Merge pull request #2468 from noahdesu/ceph-dashboard-port-ssl
add ceph dashboard port/ssl options
This commit is contained in:
11 files changed
+129
-21
No files matched your search
@@ -51,14 +51,29 @@ kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o yaml | grep "pas
|
||||
|
||||
## Configure the Dashboard
|
||||
|
||||
If you are accessing the dashboard via a reverse proxy, you may wish to serve it under a URL prefix.
|
||||
To get the dashboard to use hyperlinks that include your prefix, you can set the `urlPrefix` setting:
|
||||
The following dashboard configuration settings are supported:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
dashboard:
|
||||
urlPrefix: /ceph-dashboard
|
||||
port: 8443
|
||||
ssl: true
|
||||
```
|
||||
|
||||
* `urlPrefix` If you are accessing the dashboard via a reverse proxy, you may
|
||||
wish to serve it under a URL prefix. To get the dashboard to use hyperlinks
|
||||
that include your prefix, you can set the `urlPrefix` setting.
|
||||
|
||||
* `port` The port that the dashboard is served on may be changed from the
|
||||
default using the `port` setting. The corresponding K8s service exposing the
|
||||
port will automatically be updated.
|
||||
|
||||
* `ssl` The dashboard may be served without SSL (useful for when you deploy the
|
||||
dashboard behind a proxy already served using SSL) by setting the `ssl` option
|
||||
to be false. Note that the ssl setting will be ignored in Luminous as well as
|
||||
Mimic 13.2.2 or older where it is not supported
|
||||
|
||||
## Viewing the Dashboard External to the Cluster
|
||||
|
||||
Commonly you will want to view the dashboard from outside the cluster. For example, on a development machine with the
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
- Use `Readiness` and `Liveness` probes.
|
||||
- Updated automatically on Object Store CRD changes.
|
||||
|
||||
- Added the dashboard `port` configuration setting.
|
||||
- Added the dashboard `ssl` configuration setting.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
- Rook no longer supports Kubernetes `1.8` and `1.9`.
|
||||
|
||||
@@ -32,6 +32,10 @@ spec:
|
||||
type: boolean
|
||||
urlPrefix:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 65535
|
||||
dataDirHostPath:
|
||||
pattern: ^/(\S+)
|
||||
type: string
|
||||
|
||||
@@ -179,6 +179,10 @@ spec:
|
||||
enabled: true
|
||||
# serve the dashboard under a subpath (useful when you are accessing the dashboard via a reverse proxy)
|
||||
# urlPrefix: /ceph-dashboard
|
||||
# serve the dashboard at the given port.
|
||||
# port: 8443
|
||||
# serve the dashboard using SSL
|
||||
# ssl: true
|
||||
network:
|
||||
# toggle to use hostNetwork
|
||||
hostNetwork: false
|
||||
|
||||
@@ -36,6 +36,8 @@ spec:
|
||||
type: boolean
|
||||
urlPrefix:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
dataDirHostPath:
|
||||
pattern: ^/(\S+)
|
||||
type: string
|
||||
|
||||
@@ -94,6 +94,10 @@ type DashboardSpec struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
// A prefix for all URLs to use the dashboard with a reverse proxy
|
||||
UrlPrefix string `json:"urlPrefix,omitempty"`
|
||||
// The dashboard webserver port
|
||||
Port int `json:"port,omitempty"`
|
||||
// Whether SSL should be used
|
||||
SSL *bool `json:"ssl,omitempty"`
|
||||
}
|
||||
|
||||
type ClusterStatus struct {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -262,6 +263,27 @@ func clusterChanged(oldCluster, newCluster cephv1.ClusterSpec, clusterRef *clust
|
||||
changeFound = true
|
||||
}
|
||||
|
||||
if oldCluster.Dashboard.Port != newCluster.Dashboard.Port {
|
||||
logger.Infof("dashboard port has changed from \"%d\" to \"%d\"", oldCluster.Dashboard.Port, newCluster.Dashboard.Port)
|
||||
changeFound = true
|
||||
}
|
||||
|
||||
if (oldCluster.Dashboard.SSL == nil && newCluster.Dashboard.SSL != nil) ||
|
||||
(oldCluster.Dashboard.SSL != nil && newCluster.Dashboard.SSL == nil) ||
|
||||
(oldCluster.Dashboard.SSL != nil && newCluster.Dashboard.SSL != nil &&
|
||||
*oldCluster.Dashboard.SSL != *newCluster.Dashboard.SSL) {
|
||||
oldSSL := "<default>"
|
||||
if oldCluster.Dashboard.SSL != nil {
|
||||
oldSSL = strconv.FormatBool(*oldCluster.Dashboard.SSL)
|
||||
}
|
||||
newSSL := "<default>"
|
||||
if newCluster.Dashboard.SSL != nil {
|
||||
newSSL = strconv.FormatBool(*newCluster.Dashboard.SSL)
|
||||
}
|
||||
logger.Infof("dashboard ssl option has changed from \"%s\" to \"%s\"", oldSSL, newSSL)
|
||||
changeFound = true
|
||||
}
|
||||
|
||||
if oldCluster.Mon.Count != newCluster.Mon.Count {
|
||||
logger.Infof("number of mons have changed from %d to %d. The health check will update the mons...", oldCluster.Mon.Count, newCluster.Mon.Count)
|
||||
clusterRef.mons.MonCountMutex.Lock()
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -54,7 +55,7 @@ func init() {
|
||||
|
||||
func (c *Cluster) configureDashboard(port int) error {
|
||||
// enable or disable the dashboard module
|
||||
if err := c.toggleDashboardModule(); err != nil {
|
||||
if err := c.toggleDashboardModule(port); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -66,6 +67,17 @@ func (c *Cluster) configureDashboard(port int) error {
|
||||
return fmt.Errorf("failed to create dashboard mgr service. %+v", err)
|
||||
}
|
||||
logger.Infof("dashboard service already exists")
|
||||
original, err := c.context.Clientset.CoreV1().Services(c.Namespace).Get(dashboardService.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get dashboard service. %+v", err)
|
||||
}
|
||||
if original.Spec.Ports[0].Port != int32(port) {
|
||||
logger.Infof("dashboard port changed. updating service")
|
||||
original.Spec.Ports[0].Port = int32(port)
|
||||
if _, err := c.context.Clientset.CoreV1().Services(c.Namespace).Update(original); err != nil {
|
||||
return fmt.Errorf("failed to update dashboard mgr service. %+v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.Infof("dashboard service started")
|
||||
}
|
||||
@@ -81,7 +93,7 @@ func (c *Cluster) configureDashboard(port int) error {
|
||||
}
|
||||
|
||||
// Ceph docs about the dashboard module: http://docs.ceph.com/docs/luminous/mgr/dashboard/
|
||||
func (c *Cluster) toggleDashboardModule() error {
|
||||
func (c *Cluster) toggleDashboardModule(dashboardPort int) error {
|
||||
if c.dashboard.Enabled {
|
||||
if err := client.MgrEnableModule(c.context, c.Namespace, dashboardModuleName, true); err != nil {
|
||||
return fmt.Errorf("failed to enable mgr dashboard module. %+v", err)
|
||||
@@ -91,7 +103,7 @@ func (c *Cluster) toggleDashboardModule() error {
|
||||
return fmt.Errorf("failed to initialize dashboard. %+v", err)
|
||||
}
|
||||
|
||||
if err := c.configureDashboardModule(); err != nil {
|
||||
if err := c.configureDashboardModule(dashboardPort); err != nil {
|
||||
return fmt.Errorf("failed to configure mgr dashboard module. %+v", err)
|
||||
}
|
||||
} else {
|
||||
@@ -102,11 +114,34 @@ func (c *Cluster) toggleDashboardModule() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cluster) configureDashboardModule() error {
|
||||
func (c *Cluster) configureDashboardModule(dashboardPort int) error {
|
||||
// url prefix
|
||||
hasChanged, err := client.MgrSetAllConfig(c.context, c.Namespace, c.cephVersion.Name, "mgr/dashboard/url_prefix", c.dashboard.UrlPrefix)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// server port
|
||||
port := strconv.Itoa(dashboardPort)
|
||||
changed, err := client.MgrSetAllConfig(c.context, c.Namespace, c.cephVersion.Name, "mgr/dashboard/server_port", port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hasChanged = hasChanged || changed
|
||||
|
||||
// ssl support
|
||||
var ssl string
|
||||
if c.dashboard.SSL == nil {
|
||||
ssl = ""
|
||||
} else {
|
||||
ssl = strconv.FormatBool(*c.dashboard.SSL)
|
||||
}
|
||||
changed, err = client.MgrSetAllConfig(c.context, c.Namespace, c.cephVersion.Name, "mgr/dashboard/ssl", ssl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hasChanged = hasChanged || changed
|
||||
|
||||
if hasChanged {
|
||||
logger.Infof("dashboard config has changed")
|
||||
return c.restartDashboard()
|
||||
@@ -128,12 +163,14 @@ func (c *Cluster) initializeSecureDashboard() error {
|
||||
return fmt.Errorf("failed to generate a password. %+v", err)
|
||||
}
|
||||
|
||||
alreadyCreated, err := c.createSelfSignedCert()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create a self signed cert. %+v", err)
|
||||
}
|
||||
if alreadyCreated {
|
||||
return nil
|
||||
if c.dashboard.SSL == nil || *c.dashboard.SSL {
|
||||
alreadyCreated, err := c.createSelfSignedCert()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create a self signed cert. %+v", err)
|
||||
}
|
||||
if alreadyCreated {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.setLoginCredentials(password); err != nil {
|
||||
|
||||
@@ -103,9 +103,10 @@ func TestStartSecureDashboard(t *testing.T) {
|
||||
dashboardInitWaitTime = 0
|
||||
err := c.configureDashboard(dashboardPortHttp)
|
||||
assert.Nil(t, err)
|
||||
// the dashboard is enabled, then disabled and enabled again to restart it with the cert
|
||||
assert.Equal(t, 2, enables)
|
||||
assert.Equal(t, 1, disables)
|
||||
// the dashboard is enabled, then disabled and enabled again to restart
|
||||
// it with the cert, and another restart when setting the dashboard port
|
||||
assert.Equal(t, 3, enables)
|
||||
assert.Equal(t, 2, disables)
|
||||
assert.Equal(t, 2, moduleRetries)
|
||||
|
||||
svc, err := c.context.Clientset.CoreV1().Services(c.Namespace).Get("rook-ceph-mgr-dashboard", metav1.GetOptions{})
|
||||
@@ -116,8 +117,8 @@ func TestStartSecureDashboard(t *testing.T) {
|
||||
c.dashboard.Enabled = false
|
||||
err = c.configureDashboard(dashboardPortHttp)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, enables)
|
||||
assert.Equal(t, 2, disables)
|
||||
assert.Equal(t, 3, enables)
|
||||
assert.Equal(t, 3, disables)
|
||||
|
||||
svc, err = c.context.Clientset.CoreV1().Services(c.Namespace).Get("rook-ceph-mgr-dashboard", metav1.GetOptions{})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
@@ -90,9 +90,17 @@ var updateDeploymentAndWait = k8sutil.UpdateDeploymentAndWait
|
||||
func (c *Cluster) Start() error {
|
||||
logger.Infof("start running mgr")
|
||||
|
||||
dashboardPort := dashboardPortHttps
|
||||
if c.cephVersion.Name == cephv1.Luminous {
|
||||
dashboardPort = dashboardPortHttp
|
||||
var dashboardPort int
|
||||
if c.dashboard.Port == 0 {
|
||||
// select default ports
|
||||
if c.cephVersion.Name == cephv1.Luminous {
|
||||
dashboardPort = dashboardPortHttp
|
||||
} else {
|
||||
dashboardPort = dashboardPortHttps
|
||||
}
|
||||
} else {
|
||||
// crd validates port >= 0
|
||||
dashboardPort = c.dashboard.Port
|
||||
}
|
||||
|
||||
for i := 0; i < c.Replicas; i++ {
|
||||
|
||||
@@ -61,6 +61,7 @@ func TestStartMGR(t *testing.T) {
|
||||
testopk8s.ClearDeploymentsUpdated(deploymentsUpdated)
|
||||
|
||||
c.dashboard.UrlPrefix = "/test"
|
||||
c.dashboard.Port = 12345
|
||||
err = c.Start()
|
||||
assert.Nil(t, err)
|
||||
validateStart(t, c)
|
||||
@@ -92,9 +93,16 @@ func validateStart(t *testing.T, c *Cluster) {
|
||||
_, err := c.context.Clientset.CoreV1().Services(c.Namespace).Get("rook-ceph-mgr", metav1.GetOptions{})
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = c.context.Clientset.CoreV1().Services(c.Namespace).Get("rook-ceph-mgr-dashboard", metav1.GetOptions{})
|
||||
ds, err := c.context.Clientset.CoreV1().Services(c.Namespace).Get("rook-ceph-mgr-dashboard", metav1.GetOptions{})
|
||||
if c.dashboard.Enabled {
|
||||
assert.Nil(t, err)
|
||||
if c.dashboard.Port == 0 {
|
||||
// port=0 -> default port
|
||||
assert.Equal(t, ds.Spec.Ports[0].Port, int32(dashboardPortHttps))
|
||||
} else {
|
||||
// non-zero ports are configured as-is
|
||||
assert.Equal(t, ds.Spec.Ports[0].Port, int32(c.dashboard.Port))
|
||||
}
|
||||
} else {
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user