forked from rook/rook
Ceph mgr: Set up config in init container
Progress toward issue #2003. Includes design from design doc PR #1578 Use init containers to create configuration for Ceph mgrs. There is only 1 init container in this design: 1. Using the Rook image, call the Rook binary to create Ceph config files shared with the mgr daemgr container. Once this init is run, the main mgr daemgr is run. Leaving room to use the Ceph-versioned image in the future, call `ceph-mgr --foreground ...` to run the Ceph mgr. Signed-off-by: Blaine Gardner <blaine.gardner@suse.com>
This commit is contained in:
@@ -10,14 +10,14 @@
|
||||
- Rook Ceph block storage provisioner can now correctly create erasure coded block images. See [Advanced Example: Erasure Coded Block Storage](Documentation/block.md#advanced-example-erasure-coded-block-storage) for an example usage.
|
||||
- [Network File System (NFS)](https://github.com/nfs-ganesha/nfs-ganesha/wiki) is now supported by Rook with a new operator to deploy and manage this widely used server. NFS servers can be automatically deployed by creating an instance of the new `nfsservers.nfs.rook.io` custom resource. See the [NFS server user guide](Documentation/nfs.md) to get started with NFS.
|
||||
- The minimum version of Kubernetes supported by Rook changed from `1.7` to `1.8`.
|
||||
- `reclaimPolicy` parameter of `StorageClass` definition is now supported.
|
||||
- `reclaimPolicy` parameter of `StorageClass` definition is now supported.
|
||||
|
||||
## Breaking Changes
|
||||
- Ceph mons are [named consistently](https://github.com/rook/rook/issues/1751) with other daemons with the letters a, b, c, etc.
|
||||
- Ceph mons are now created with Deployments instead of ReplicaSets to improve the upgrade implementation.
|
||||
- Ceph mon container names in pods have changed with the
|
||||
- Ceph mon and mgr container names in pods have changed with the
|
||||
[refactor](https://github.com/rook/rook/pull/2095) to initialize the mon daemon environment via
|
||||
pod **InitContainers** and run the `ceph-mon` daemon directly from the container entrypoint.
|
||||
pod **InitContainers** and run the Ceph daemons directly from the container entrypoint.
|
||||
|
||||
- The Rook container images are no longer published to quay.io, they are published only to Docker Hub. All manifests have referenced Docker Hub for multiple releases now, so we do not expect any directly affected users from this change.
|
||||
- Rook no longer supports kubernetes `1.7`. Users running Kubernetes `1.7` on their clusters are recommended to upgrade to Kubernetes `1.8` or higher. If you are using `kubeadm`, you can follow this [guide](https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-8/) to from Kubernetes `1.7` to `1.8`. If you are using `kops` or `kubespray` for managing your Kubernetes cluster, just follow the respective projects' `upgrade` guide.
|
||||
|
||||
@@ -30,23 +30,25 @@ var (
|
||||
)
|
||||
|
||||
var mgrCmd = &cobra.Command{
|
||||
Use: "mgr",
|
||||
Short: "Generates mgr config and runs the mgr daemon",
|
||||
Use: mgrdaemon.InitCommand,
|
||||
Short: "Generates mgr config",
|
||||
Hidden: true,
|
||||
}
|
||||
|
||||
func init() {
|
||||
mgrCmd.Flags().StringVar(&mgrName, "mgr-name", "", "the mgr name")
|
||||
mgrCmd.Flags().StringVar(&mgrName, "mgr-name", "", "name of the mgr")
|
||||
mgrCmd.Flags().StringVar(&mgrKeyring, "mgr-keyring", "", "the mgr keyring")
|
||||
addCephFlags(mgrCmd)
|
||||
|
||||
flags.SetFlagsFromEnv(mgrCmd.Flags(), rook.RookEnvVarPrefix)
|
||||
|
||||
mgrCmd.RunE = startMgr
|
||||
mgrCmd.RunE = initMgr
|
||||
}
|
||||
|
||||
func startMgr(cmd *cobra.Command, args []string) error {
|
||||
required := []string{"mon-endpoints", "cluster-name", "mon-secret", "admin-secret"}
|
||||
func initMgr(cmd *cobra.Command, args []string) error {
|
||||
required := []string{
|
||||
"mgr-name", "mgr-keyring",
|
||||
"mon-endpoints", "cluster-name", "mon-secret", "admin-secret"}
|
||||
if err := flags.VerifyRequiredFlags(mgrCmd, required); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -66,7 +68,7 @@ func startMgr(cmd *cobra.Command, args []string) error {
|
||||
ClusterInfo: &clusterInfo,
|
||||
}
|
||||
|
||||
err := mgrdaemon.Run(createContext(), config)
|
||||
err := mgrdaemon.Initialize(createContext(), config)
|
||||
if err != nil {
|
||||
rook.TerminateFatal(err)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
|
||||
var monCmd = &cobra.Command{
|
||||
Use: mondaemon.InitCommand,
|
||||
Short: "Generates mon config and runs the mon daemon",
|
||||
Short: "Generates mon config",
|
||||
Hidden: true,
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
// ClusterInfo is a collection of information about a particular Ceph cluster. Rook uses information
|
||||
@@ -41,3 +44,23 @@ type MonInfo struct {
|
||||
func NewMonInfo(name, ip string, port int32) *MonInfo {
|
||||
return &MonInfo{Name: name, Endpoint: net.JoinHostPort(ip, fmt.Sprintf("%d", port))}
|
||||
}
|
||||
|
||||
// Log writes the cluster info struct to the logger
|
||||
func (c *ClusterInfo) Log(logger *capnslog.PackageLogger) {
|
||||
mons := []string{}
|
||||
for _, m := range c.Monitors {
|
||||
mons = append(mons, fmt.Sprintf("{Name: %s, Endpoint: %s}", m.Name, m.Endpoint))
|
||||
}
|
||||
monsec := ""
|
||||
if c.MonitorSecret != "" {
|
||||
monsec = "<hidden>"
|
||||
}
|
||||
admsec := ""
|
||||
if c.AdminSecret != "" {
|
||||
admsec = "<hidden>"
|
||||
}
|
||||
s := fmt.Sprintf(
|
||||
"ClusterInfo: {FSID: %s, MonitorSecret: %s, AdminSecret: %s, Name: %s, Monitors: %s}",
|
||||
c.FSID, monsec, admsec, c.Name, strings.Join(mons, " "))
|
||||
logger.Info(s)
|
||||
}
|
||||
|
||||
@@ -38,30 +38,33 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
// InitCommand is the `rook ceph` subcommand which will perform mgr initialization
|
||||
InitCommand = "mgr-init"
|
||||
|
||||
cephmgr = "ceph-mgr"
|
||||
)
|
||||
|
||||
// Config contains the necessary parameters Rook needs to know to set up a mgr for a Ceph cluster.
|
||||
type Config struct {
|
||||
ClusterInfo *cephconfig.ClusterInfo
|
||||
Name string
|
||||
Keyring string
|
||||
}
|
||||
|
||||
func Run(context *clusterd.Context, config *Config) error {
|
||||
logger.Infof("Starting MGR %s with keyring %s", config.Name, config.Keyring)
|
||||
// Initialize generates configuration files for a Ceph mgr
|
||||
func Initialize(context *clusterd.Context, config *Config) error {
|
||||
logger.Infof("Creating config for MGR %s with keyring %s", config.Name, config.Keyring)
|
||||
config.ClusterInfo.Log(logger)
|
||||
if err := generateConfigFiles(context, config); err != nil {
|
||||
return fmt.Errorf("failed to generate mgr config files. %+v", err)
|
||||
}
|
||||
|
||||
if err := startMgr(context, config); err != nil {
|
||||
return fmt.Errorf("failed to run mgr. %+v", err)
|
||||
}
|
||||
util.WriteFileToLog(logger, cephconfig.DefaultConfigFilePath())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateConfigFiles(context *clusterd.Context, config *Config) error {
|
||||
|
||||
keyringPath := getMgrKeyringPath(context.ConfigDir, config.Name)
|
||||
confDir := getMgrConfDir(context.ConfigDir, config.Name)
|
||||
username := fmt.Sprintf("mgr.%s", config.Name)
|
||||
@@ -87,30 +90,6 @@ func generateConfigFiles(context *clusterd.Context, config *Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func startMgr(context *clusterd.Context, config *Config) error {
|
||||
|
||||
// start the mgr daemon in the foreground with the given config
|
||||
logger.Infof("starting ceph-mgr")
|
||||
|
||||
confFile := getMgrConfFilePath(context.ConfigDir, config.Name, config.ClusterInfo.Name)
|
||||
util.WriteFileToLog(logger, confFile)
|
||||
|
||||
keyringPath := getMgrKeyringPath(context.ConfigDir, config.Name)
|
||||
util.WriteFileToLog(logger, keyringPath)
|
||||
args := []string{
|
||||
"--foreground",
|
||||
fmt.Sprintf("--cluster=%s", config.ClusterInfo.Name),
|
||||
fmt.Sprintf("--conf=%s", confFile),
|
||||
fmt.Sprintf("--keyring=%s", keyringPath),
|
||||
"-i", config.Name,
|
||||
}
|
||||
|
||||
if err := context.Executor.ExecuteCommand(false, cephmgr, cephmgr, args...); err != nil {
|
||||
return fmt.Errorf("failed to start mgr: %+v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMgrConfDir(dir, name string) string {
|
||||
return path.Join(dir, fmt.Sprintf("mgr-%s", name))
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
"github.com/rook/rook/pkg/clusterd"
|
||||
cephconfig "github.com/rook/rook/pkg/daemon/ceph/config"
|
||||
"github.com/rook/rook/pkg/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -44,11 +45,15 @@ type Config struct {
|
||||
|
||||
// Initialize generates configuration files for a Ceph mon
|
||||
func Initialize(context *clusterd.Context, config *Config) error {
|
||||
logger.Infof("Creating config for MON %s with port %d", config.Name, config.Port)
|
||||
config.Cluster.Log(logger)
|
||||
err := generateConfigFiles(context, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate mon config files. %+v", err)
|
||||
}
|
||||
|
||||
util.WriteFileToLog(logger, cephconfig.DefaultConfigFilePath())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -19,17 +19,14 @@ package mgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
cephv1beta1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1beta1"
|
||||
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
|
||||
"github.com/rook/rook/pkg/clusterd"
|
||||
"github.com/rook/rook/pkg/daemon/ceph/client"
|
||||
opmon "github.com/rook/rook/pkg/operator/ceph/cluster/mon"
|
||||
"github.com/rook/rook/pkg/operator/k8sutil"
|
||||
"k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
@@ -47,7 +44,7 @@ const (
|
||||
|
||||
var mgrNames = []string{"a", "b"}
|
||||
|
||||
// Cluster is the ceph mgr manager
|
||||
// Cluster represents the Rook and environment configuration settings needed to set up Ceph mgrs.
|
||||
type Cluster struct {
|
||||
Namespace string
|
||||
Version string
|
||||
@@ -61,6 +58,12 @@ type Cluster struct {
|
||||
dashboard cephv1beta1.DashboardSpec
|
||||
}
|
||||
|
||||
// mgrConfig for a single mgr
|
||||
type mgrConfig struct {
|
||||
ResourceName string // the name rook gives to mgr resources in k8s metadata
|
||||
DaemonName string // the name of the Ceph daemon ("a", "b", ...)
|
||||
}
|
||||
|
||||
// New creates an instance of the mgr
|
||||
func New(context *clusterd.Context, namespace, version string, placement rookalpha.Placement, hostNetwork bool, dashboard cephv1beta1.DashboardSpec,
|
||||
resources v1.ResourceRequirements, ownerRef metav1.OwnerReference) *Cluster {
|
||||
@@ -78,7 +81,7 @@ func New(context *clusterd.Context, namespace, version string, placement rookalp
|
||||
}
|
||||
}
|
||||
|
||||
// Start the mgr instance
|
||||
// Start begins the process of running a cluster of Ceph mgrs.
|
||||
func (c *Cluster) Start() error {
|
||||
logger.Infof("start running mgr")
|
||||
|
||||
@@ -87,21 +90,27 @@ func (c *Cluster) Start() error {
|
||||
logger.Errorf("cannot have more than %d mgrs", len(mgrNames))
|
||||
break
|
||||
}
|
||||
|
||||
daemonName := mgrNames[i]
|
||||
name := fmt.Sprintf("%s-%s", appName, daemonName)
|
||||
if err := c.createKeyring(c.Namespace, name, daemonName); err != nil {
|
||||
return fmt.Errorf("failed to create %s keyring. %+v", name, err)
|
||||
resourceName := fmt.Sprintf("%s-%s", appName, daemonName)
|
||||
if err := c.createKeyring(c.Namespace, resourceName, daemonName); err != nil {
|
||||
return fmt.Errorf("failed to create %s keyring. %+v", resourceName, err)
|
||||
}
|
||||
|
||||
mgrConfig := &mgrConfig{
|
||||
DaemonName: daemonName,
|
||||
ResourceName: resourceName,
|
||||
}
|
||||
|
||||
// start the deployment
|
||||
deployment := c.makeDeployment(name, daemonName)
|
||||
deployment := c.makeDeployment(mgrConfig)
|
||||
if _, err := c.context.Clientset.ExtensionsV1beta1().Deployments(c.Namespace).Create(deployment); err != nil {
|
||||
if !errors.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("failed to create %s deployment. %+v", name, err)
|
||||
return fmt.Errorf("failed to create %s deployment. %+v", resourceName, err)
|
||||
}
|
||||
logger.Infof("%s deployment already exists", name)
|
||||
logger.Infof("%s deployment already exists", resourceName)
|
||||
} else {
|
||||
logger.Infof("%s deployment started", name)
|
||||
logger.Infof("%s deployment started", resourceName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,101 +209,6 @@ func (c *Cluster) makeDashboardService(name string) *v1.Service {
|
||||
return svc
|
||||
}
|
||||
|
||||
func (c *Cluster) makeDeployment(name, daemonName string) *extensions.Deployment {
|
||||
|
||||
podSpec := v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: c.getDaemonLabels(daemonName),
|
||||
Annotations: map[string]string{"prometheus.io/scrape": "true",
|
||||
"prometheus.io/port": strconv.Itoa(metricsPort)},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{c.mgrContainer(name, daemonName)},
|
||||
RestartPolicy: v1.RestartPolicyAlways,
|
||||
Volumes: []v1.Volume{
|
||||
{Name: k8sutil.DataDirVolume, VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}},
|
||||
k8sutil.ConfigOverrideVolume(),
|
||||
},
|
||||
HostNetwork: c.HostNetwork,
|
||||
},
|
||||
}
|
||||
if c.HostNetwork {
|
||||
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
|
||||
}
|
||||
c.placement.ApplyToPodSpec(&podSpec.Spec)
|
||||
|
||||
replicas := int32(1)
|
||||
d := &extensions.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: c.Namespace,
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{Template: podSpec, Replicas: &replicas},
|
||||
}
|
||||
k8sutil.SetOwnerRef(c.context.Clientset, c.Namespace, &d.ObjectMeta, &c.ownerRef)
|
||||
return d
|
||||
}
|
||||
|
||||
func (c *Cluster) mgrContainer(name, daemonName string) v1.Container {
|
||||
|
||||
return v1.Container{
|
||||
Args: []string{
|
||||
"ceph",
|
||||
"mgr",
|
||||
fmt.Sprintf("--config-dir=%s", k8sutil.DataDir),
|
||||
},
|
||||
Name: name,
|
||||
Image: k8sutil.MakeRookImage(c.Version),
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{Name: k8sutil.DataDirVolume, MountPath: k8sutil.DataDir},
|
||||
k8sutil.ConfigOverrideMount(),
|
||||
},
|
||||
Env: []v1.EnvVar{
|
||||
{Name: "ROOK_MGR_NAME", Value: daemonName},
|
||||
{Name: "ROOK_MGR_KEYRING", ValueFrom: &v1.EnvVarSource{SecretKeyRef: &v1.SecretKeySelector{LocalObjectReference: v1.LocalObjectReference{Name: name}, Key: keyringName}}},
|
||||
k8sutil.PodIPEnvVar(k8sutil.PrivateIPEnvVar),
|
||||
k8sutil.PodIPEnvVar(k8sutil.PublicIPEnvVar),
|
||||
opmon.ClusterNameEnvVar(c.Namespace),
|
||||
opmon.EndpointEnvVar(),
|
||||
opmon.SecretEnvVar(),
|
||||
opmon.AdminSecretEnvVar(),
|
||||
k8sutil.ConfigOverrideEnvVar(),
|
||||
},
|
||||
Resources: c.resources,
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "mgr",
|
||||
ContainerPort: int32(6800),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
{
|
||||
Name: "http-metrics",
|
||||
ContainerPort: int32(metricsPort),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
{
|
||||
Name: "dashboard",
|
||||
ContainerPort: int32(dashboardPort),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) getLabels() map[string]string {
|
||||
return map[string]string{
|
||||
k8sutil.AppAttr: appName,
|
||||
k8sutil.ClusterAttr: c.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) getDaemonLabels(daemonName string) map[string]string {
|
||||
labels := c.getLabels()
|
||||
labels["instance"] = daemonName
|
||||
return labels
|
||||
}
|
||||
|
||||
func (c *Cluster) createKeyring(clusterName, name, daemonName string) error {
|
||||
_, err := c.context.Clientset.CoreV1().Secrets(c.Namespace).Get(name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
cephv1beta1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1beta1"
|
||||
@@ -30,7 +29,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
@@ -85,60 +83,3 @@ func validateStart(t *testing.T, c *Cluster) {
|
||||
assert.True(t, errors.IsNotFound(err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPodSpec(t *testing.T) {
|
||||
c := New(&clusterd.Context{Clientset: testop.New(1)}, "ns", "rook/rook:myversion", rookalpha.Placement{}, false, cephv1beta1.DashboardSpec{}, v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceCPU: *resource.NewQuantity(100.0, resource.BinarySI),
|
||||
},
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceMemory: *resource.NewQuantity(1337.0, resource.BinarySI),
|
||||
},
|
||||
}, metav1.OwnerReference{})
|
||||
|
||||
d := c.makeDeployment("mgr-a", "a")
|
||||
assert.NotNil(t, d)
|
||||
assert.Equal(t, "mgr-a", d.Name)
|
||||
assert.Equal(t, v1.RestartPolicyAlways, d.Spec.Template.Spec.RestartPolicy)
|
||||
assert.Equal(t, 2, len(d.Spec.Template.Spec.Volumes))
|
||||
assert.Equal(t, 3, len(d.Spec.Template.Spec.Containers[0].Ports))
|
||||
assert.Equal(t, "rook-data", d.Spec.Template.Spec.Volumes[0].Name)
|
||||
assert.Equal(t, "mgr-a", d.ObjectMeta.Name)
|
||||
assert.Equal(t, appName, d.Spec.Template.ObjectMeta.Labels["app"])
|
||||
assert.Equal(t, c.Namespace, d.Spec.Template.ObjectMeta.Labels["rook_cluster"])
|
||||
assert.Equal(t, 0, len(d.ObjectMeta.Annotations))
|
||||
|
||||
assert.Equal(t, 2, len(d.Spec.Template.ObjectMeta.Annotations))
|
||||
assert.Equal(t, "true", d.Spec.Template.ObjectMeta.Annotations["prometheus.io/scrape"])
|
||||
assert.Equal(t, strconv.Itoa(metricsPort), d.Spec.Template.ObjectMeta.Annotations["prometheus.io/port"])
|
||||
|
||||
cont := d.Spec.Template.Spec.Containers[0]
|
||||
assert.Equal(t, "rook/rook:myversion", cont.Image)
|
||||
assert.Equal(t, 2, len(cont.VolumeMounts))
|
||||
|
||||
assert.Equal(t, "ceph", cont.Args[0])
|
||||
assert.Equal(t, "mgr", cont.Args[1])
|
||||
assert.Equal(t, "--config-dir=/var/lib/rook", cont.Args[2])
|
||||
|
||||
assert.Equal(t, "100", cont.Resources.Limits.Cpu().String())
|
||||
assert.Equal(t, "1337", cont.Resources.Requests.Memory().String())
|
||||
}
|
||||
|
||||
func TestServiceSpec(t *testing.T) {
|
||||
c := New(&clusterd.Context{}, "ns", "myversion", rookalpha.Placement{}, false, cephv1beta1.DashboardSpec{}, v1.ResourceRequirements{}, metav1.OwnerReference{})
|
||||
|
||||
s := c.makeMetricsService("rook-mgr")
|
||||
assert.NotNil(t, s)
|
||||
assert.Equal(t, "rook-mgr", s.Name)
|
||||
assert.Equal(t, 1, len(s.Spec.Ports))
|
||||
}
|
||||
|
||||
func TestHostNetwork(t *testing.T) {
|
||||
c := New(&clusterd.Context{Clientset: testop.New(1)}, "ns", "myversion", rookalpha.Placement{}, true, cephv1beta1.DashboardSpec{}, v1.ResourceRequirements{}, metav1.OwnerReference{})
|
||||
|
||||
d := c.makeDeployment("mgr-a", "a")
|
||||
assert.NotNil(t, d)
|
||||
|
||||
assert.Equal(t, true, d.Spec.Template.Spec.HostNetwork)
|
||||
assert.Equal(t, v1.DNSClusterFirstWithHostNet, d.Spec.Template.Spec.DNSPolicy)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
Copyright 2018 The Rook Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package mgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
mgrdaemon "github.com/rook/rook/pkg/daemon/ceph/mgr"
|
||||
opmon "github.com/rook/rook/pkg/operator/ceph/cluster/mon"
|
||||
opspec "github.com/rook/rook/pkg/operator/ceph/spec"
|
||||
"github.com/rook/rook/pkg/operator/k8sutil"
|
||||
"k8s.io/api/core/v1"
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
mgrDaemonCommand = "ceph-mgr"
|
||||
)
|
||||
|
||||
func (c *Cluster) makeDeployment(mgrConfig *mgrConfig) *extensions.Deployment {
|
||||
podSpec := v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: mgrConfig.ResourceName,
|
||||
Labels: c.getDaemonLabels(mgrConfig.DaemonName),
|
||||
Annotations: map[string]string{"prometheus.io/scrape": "true",
|
||||
"prometheus.io/port": strconv.Itoa(metricsPort)},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
// Config file init performed by Rook
|
||||
c.makeConfigInitContainer(mgrConfig),
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
c.makeMgrDaemonContainer(mgrConfig),
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyAlways,
|
||||
Volumes: opspec.PodVolumes(""),
|
||||
HostNetwork: c.HostNetwork,
|
||||
},
|
||||
}
|
||||
if c.HostNetwork {
|
||||
podSpec.Spec.DNSPolicy = v1.DNSClusterFirstWithHostNet
|
||||
}
|
||||
c.placement.ApplyToPodSpec(&podSpec.Spec)
|
||||
|
||||
replicas := int32(1)
|
||||
d := &extensions.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: mgrConfig.ResourceName,
|
||||
Namespace: c.Namespace,
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{Template: podSpec, Replicas: &replicas},
|
||||
}
|
||||
k8sutil.SetOwnerRef(c.context.Clientset, c.Namespace, &d.ObjectMeta, &c.ownerRef)
|
||||
return d
|
||||
}
|
||||
|
||||
func (c *Cluster) makeConfigInitContainer(mgrConfig *mgrConfig) v1.Container {
|
||||
return v1.Container{
|
||||
Name: opspec.ConfigInitContainerName,
|
||||
Args: []string{
|
||||
"ceph",
|
||||
mgrdaemon.InitCommand,
|
||||
fmt.Sprintf("--config-dir=%s", k8sutil.DataDir),
|
||||
fmt.Sprintf("--mgr-name=%s", mgrConfig.DaemonName),
|
||||
},
|
||||
Image: k8sutil.MakeRookImage(c.Version),
|
||||
Env: []v1.EnvVar{
|
||||
{Name: "ROOK_MGR_KEYRING",
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
SecretKeyRef: &v1.SecretKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{Name: mgrConfig.ResourceName},
|
||||
Key: keyringName,
|
||||
}}},
|
||||
k8sutil.PodIPEnvVar(k8sutil.PrivateIPEnvVar),
|
||||
k8sutil.PodIPEnvVar(k8sutil.PublicIPEnvVar),
|
||||
opmon.ClusterNameEnvVar(c.Namespace),
|
||||
opmon.EndpointEnvVar(),
|
||||
opmon.SecretEnvVar(),
|
||||
opmon.AdminSecretEnvVar(),
|
||||
k8sutil.ConfigOverrideEnvVar(),
|
||||
},
|
||||
VolumeMounts: opspec.RookVolumeMounts(),
|
||||
// config file creation does not require ports to be open
|
||||
Resources: c.resources,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) makeMgrDaemonContainer(mgrConfig *mgrConfig) v1.Container {
|
||||
return v1.Container{
|
||||
Name: "mgr",
|
||||
Command: []string{
|
||||
mgrDaemonCommand,
|
||||
},
|
||||
Args: []string{
|
||||
"--foreground",
|
||||
"--id", mgrConfig.DaemonName,
|
||||
},
|
||||
Image: k8sutil.MakeRookImage(c.Version),
|
||||
VolumeMounts: opspec.CephVolumeMounts(),
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "mgr",
|
||||
ContainerPort: int32(6800),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
{
|
||||
Name: "http-metrics",
|
||||
ContainerPort: int32(metricsPort),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
{
|
||||
Name: "dashboard",
|
||||
ContainerPort: int32(dashboardPort),
|
||||
Protocol: v1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
Resources: c.resources,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) getLabels() map[string]string {
|
||||
return map[string]string{
|
||||
k8sutil.AppAttr: appName,
|
||||
k8sutil.ClusterAttr: c.Namespace,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) getDaemonLabels(daemonName string) map[string]string {
|
||||
labels := c.getLabels()
|
||||
labels["instance"] = daemonName
|
||||
return labels
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
Copyright 2018 The Rook Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package mgr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
cephv1beta1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1beta1"
|
||||
rookalpha "github.com/rook/rook/pkg/apis/rook.io/v1alpha2"
|
||||
"github.com/rook/rook/pkg/clusterd"
|
||||
cephconfig "github.com/rook/rook/pkg/daemon/ceph/config"
|
||||
mgrdaemon "github.com/rook/rook/pkg/daemon/ceph/mgr"
|
||||
cephtest "github.com/rook/rook/pkg/operator/ceph/test"
|
||||
"github.com/rook/rook/pkg/operator/k8sutil"
|
||||
optest "github.com/rook/rook/pkg/operator/test"
|
||||
testop "github.com/rook/rook/pkg/operator/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func TestPodSpec(t *testing.T) {
|
||||
c := New(
|
||||
&clusterd.Context{Clientset: testop.New(1)},
|
||||
"ns",
|
||||
"rook/rook:myversion",
|
||||
rookalpha.Placement{},
|
||||
false,
|
||||
cephv1beta1.DashboardSpec{},
|
||||
v1.ResourceRequirements{
|
||||
Limits: v1.ResourceList{
|
||||
v1.ResourceCPU: *resource.NewQuantity(100.0, resource.BinarySI),
|
||||
},
|
||||
Requests: v1.ResourceList{
|
||||
v1.ResourceMemory: *resource.NewQuantity(1337.0, resource.BinarySI),
|
||||
},
|
||||
},
|
||||
metav1.OwnerReference{},
|
||||
)
|
||||
|
||||
mgrTestConfig := mgrConfig{
|
||||
DaemonName: "a",
|
||||
ResourceName: "mgr-a",
|
||||
}
|
||||
|
||||
d := c.makeDeployment(&mgrTestConfig)
|
||||
|
||||
assert.NotNil(t, d)
|
||||
assert.Equal(t, "mgr-a", d.Name)
|
||||
assert.Equal(t, "mgr-a", d.ObjectMeta.Name)
|
||||
assert.Equal(t, 0, len(d.ObjectMeta.Annotations))
|
||||
|
||||
pod := d.Spec.Template
|
||||
assert.Equal(t, appName, pod.ObjectMeta.Labels["app"])
|
||||
assert.Equal(t, c.Namespace, pod.ObjectMeta.Labels["rook_cluster"])
|
||||
assert.Equal(t, 2, len(pod.ObjectMeta.Annotations))
|
||||
assert.Equal(t, "true", pod.ObjectMeta.Annotations["prometheus.io/scrape"])
|
||||
assert.Equal(t, strconv.Itoa(metricsPort), pod.ObjectMeta.Annotations["prometheus.io/port"])
|
||||
assert.Equal(t, v1.RestartPolicyAlways, pod.Spec.RestartPolicy)
|
||||
assert.Nil(t, optest.VolumeExists("rook-data", pod.Spec.Volumes))
|
||||
assert.Nil(t, optest.VolumeExists(cephconfig.DefaultConfigMountName, pod.Spec.Volumes))
|
||||
assert.Nil(t, optest.VolumeExists(k8sutil.ConfigOverrideName, pod.Spec.Volumes))
|
||||
|
||||
assert.Equal(t, 1, len(pod.Spec.InitContainers))
|
||||
assert.Equal(t, 1, len(pod.Spec.Containers))
|
||||
|
||||
configImage := "rook/rook:myversion"
|
||||
configEnvs := 8
|
||||
configContainerDefinition := cephtest.ContainerTestDefinition{
|
||||
Image: &configImage,
|
||||
Command: []string{}, // no command
|
||||
Args: [][]string{
|
||||
{"ceph"},
|
||||
{mgrdaemon.InitCommand},
|
||||
{"--config-dir=/var/lib/rook"},
|
||||
{fmt.Sprintf("--mgr-name=%s", mgrTestConfig.DaemonName)}},
|
||||
InOrderArgs: map[int]string{
|
||||
0: "ceph", // ceph must be first arg
|
||||
1: mgrdaemon.InitCommand}, // mgr init command must be second arg
|
||||
VolumeMountNames: []string{
|
||||
"rook-data",
|
||||
cephconfig.DefaultConfigMountName,
|
||||
k8sutil.ConfigOverrideName},
|
||||
EnvCount: &configEnvs,
|
||||
Ports: []v1.ContainerPort{},
|
||||
IsPrivileged: nil, // not set in spec
|
||||
}
|
||||
cont := &pod.Spec.InitContainers[0]
|
||||
configContainerDefinition.TestContainer(t, "config init", cont, logger)
|
||||
assert.Equal(t, "100", cont.Resources.Limits.Cpu().String())
|
||||
assert.Equal(t, "1337", cont.Resources.Requests.Memory().String())
|
||||
|
||||
daemonImage := "rook/rook:myversion"
|
||||
daemonEnvs := 0
|
||||
daemonContainerDefinition := cephtest.ContainerTestDefinition{
|
||||
Image: &daemonImage,
|
||||
Command: []string{
|
||||
"ceph-mgr"},
|
||||
Args: [][]string{
|
||||
{"--foreground"},
|
||||
{"--id", mgrTestConfig.DaemonName}},
|
||||
VolumeMountNames: []string{
|
||||
"rook-data",
|
||||
cephconfig.DefaultConfigMountName},
|
||||
EnvCount: &daemonEnvs,
|
||||
Ports: []v1.ContainerPort{
|
||||
{ContainerPort: int32(6800),
|
||||
Protocol: v1.ProtocolTCP},
|
||||
{ContainerPort: int32(metricsPort),
|
||||
Protocol: v1.ProtocolTCP},
|
||||
{ContainerPort: int32(dashboardPort),
|
||||
Protocol: v1.ProtocolTCP}},
|
||||
IsPrivileged: nil, // not set in spec
|
||||
}
|
||||
cont = &pod.Spec.Containers[0]
|
||||
daemonContainerDefinition.TestContainer(t, "main mon daemon", cont, logger)
|
||||
assert.Equal(t, "100", cont.Resources.Limits.Cpu().String())
|
||||
assert.Equal(t, "1337", cont.Resources.Requests.Memory().String())
|
||||
|
||||
// Verify that all the mounts have volumes and that there are no extraneous volumes
|
||||
volsMountsTestDef := optest.VolumesAndMountsTestDefinition{
|
||||
VolumesSpec: &optest.VolumesSpec{Moniker: "mon pod volumes", Volumes: pod.Spec.Volumes},
|
||||
MountsSpecItems: []*optest.MountsSpec{
|
||||
{Moniker: "mgr config init mounts", Mounts: pod.Spec.InitContainers[0].VolumeMounts},
|
||||
{Moniker: "mgr daemon mounts", Mounts: pod.Spec.Containers[0].VolumeMounts}},
|
||||
}
|
||||
volsMountsTestDef.TestMountsMatchVolumes(t)
|
||||
}
|
||||
|
||||
func TestServiceSpec(t *testing.T) {
|
||||
c := New(&clusterd.Context{}, "ns", "myversion", rookalpha.Placement{}, false, cephv1beta1.DashboardSpec{}, v1.ResourceRequirements{}, metav1.OwnerReference{})
|
||||
|
||||
s := c.makeMetricsService("rook-mgr")
|
||||
assert.NotNil(t, s)
|
||||
assert.Equal(t, "rook-mgr", s.Name)
|
||||
assert.Equal(t, 1, len(s.Spec.Ports))
|
||||
}
|
||||
|
||||
func TestHostNetwork(t *testing.T) {
|
||||
c := New(
|
||||
&clusterd.Context{Clientset: testop.New(1)},
|
||||
"ns",
|
||||
"myversion",
|
||||
rookalpha.Placement{},
|
||||
true,
|
||||
cephv1beta1.DashboardSpec{},
|
||||
v1.ResourceRequirements{},
|
||||
metav1.OwnerReference{},
|
||||
)
|
||||
|
||||
mgrTestConfig := mgrConfig{
|
||||
DaemonName: "a",
|
||||
ResourceName: "mgr-a",
|
||||
}
|
||||
|
||||
d := c.makeDeployment(&mgrTestConfig)
|
||||
assert.NotNil(t, d)
|
||||
|
||||
assert.Equal(t, true, d.Spec.Template.Spec.HostNetwork)
|
||||
assert.Equal(t, v1.DNSClusterFirstWithHostNet, d.Spec.Template.Spec.DNSPolicy)
|
||||
}
|
||||
@@ -69,7 +69,7 @@ const (
|
||||
MaxMonCount = 9
|
||||
)
|
||||
|
||||
// Cluster represents the Rook configuration settings for Ceph mons.
|
||||
// Cluster represents the Rook and environment configuration settings needed to set up Ceph mons.
|
||||
type Cluster struct {
|
||||
context *clusterd.Context
|
||||
Namespace string
|
||||
|
||||
@@ -35,7 +35,7 @@ const (
|
||||
// Full path of command used to invoke the monmap tool
|
||||
monmaptoolCommand = "/usr/bin/monmaptool"
|
||||
// Full path of the command used to invoke the Ceph mon daemon
|
||||
cephMonCommand = "/usr/bin/ceph-mon"
|
||||
cephMonCommand = "ceph-mon"
|
||||
|
||||
monmapFile = "monmap"
|
||||
)
|
||||
@@ -82,14 +82,14 @@ func (c *Cluster) makeMonPod(monConfig *monConfig, hostname string) *v1.Pod {
|
||||
podSpec := v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
// Config file init performed by Rook
|
||||
c.makeConfigInitContainer(monConfig, opspec.ConfigInitContainerName),
|
||||
c.makeConfigInitContainer(monConfig),
|
||||
// Ceph monmap init performed by 'monmaptool'
|
||||
c.makeMonmapInitContainer(monConfig, "monmap-init"),
|
||||
c.makeMonmapInitContainer(monConfig),
|
||||
// mon filesystem init performed by mon daemon
|
||||
c.makeMonFSInitContainer(monConfig, "mon-fs-init"),
|
||||
c.makeMonFSInitContainer(monConfig),
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
c.makeMonDaemonContainer(monConfig, "mon"),
|
||||
c.makeMonDaemonContainer(monConfig),
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyAlways,
|
||||
NodeSelector: map[string]string{apis.LabelHostname: hostname},
|
||||
@@ -130,9 +130,9 @@ func podSecurityContext() *v1.SecurityContext {
|
||||
return &v1.SecurityContext{Privileged: &privileged}
|
||||
}
|
||||
|
||||
func (c *Cluster) makeConfigInitContainer(monConfig *monConfig, containerName string) v1.Container {
|
||||
func (c *Cluster) makeConfigInitContainer(monConfig *monConfig) v1.Container {
|
||||
return v1.Container{
|
||||
Name: containerName,
|
||||
Name: opspec.ConfigInitContainerName,
|
||||
Args: []string{
|
||||
"ceph",
|
||||
mondaemon.InitCommand,
|
||||
@@ -164,7 +164,7 @@ func (c *Cluster) monmapFilePath(monConfig *monConfig) string {
|
||||
)
|
||||
}
|
||||
|
||||
func (c *Cluster) makeMonmapInitContainer(monConfig *monConfig, containerName string) v1.Container {
|
||||
func (c *Cluster) makeMonmapInitContainer(monConfig *monConfig) v1.Container {
|
||||
// Add mons w/ monmaptool w/ args: [--add <mon-name> <mon-endpoint>]...
|
||||
monmapAddMonArgs := []string{}
|
||||
for _, mon := range c.clusterInfo.Monitors {
|
||||
@@ -172,7 +172,7 @@ func (c *Cluster) makeMonmapInitContainer(monConfig *monConfig, containerName st
|
||||
}
|
||||
|
||||
return v1.Container{
|
||||
Name: containerName,
|
||||
Name: "monmap-init",
|
||||
Command: []string{
|
||||
monmaptoolCommand,
|
||||
},
|
||||
@@ -201,9 +201,9 @@ func (c *Cluster) cephMonCommonArgs(monConfig *monConfig) []string {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) makeMonFSInitContainer(monConfig *monConfig, containerName string) v1.Container {
|
||||
func (c *Cluster) makeMonFSInitContainer(monConfig *monConfig) v1.Container {
|
||||
return v1.Container{
|
||||
Name: containerName,
|
||||
Name: "mon-fs-init",
|
||||
Command: []string{
|
||||
cephMonCommand,
|
||||
},
|
||||
@@ -222,7 +222,7 @@ func (c *Cluster) makeMonFSInitContainer(monConfig *monConfig, containerName str
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cluster) makeMonDaemonContainer(monConfig *monConfig, containerName string) v1.Container {
|
||||
func (c *Cluster) makeMonDaemonContainer(monConfig *monConfig) v1.Container {
|
||||
return v1.Container{
|
||||
// The operator has set up the mon's service already, so the IP that the mon should
|
||||
// broadcast as its own (--public-addr) is known. But the pod's IP, which the mon should
|
||||
@@ -232,7 +232,7 @@ func (c *Cluster) makeMonDaemonContainer(monConfig *monConfig, containerName str
|
||||
// - Chosen solution, but is not as transparent to inspection as using commandline arg
|
||||
// 2. Use bash to do variable substitution with the pod IP env var; but bash is a poor PID1
|
||||
// 3. Use tini to do var substitution as above; but tini doesn't exist in the ceph images.
|
||||
Name: containerName,
|
||||
Name: "mon",
|
||||
Command: []string{
|
||||
cephMonCommand,
|
||||
},
|
||||
|
||||
@@ -153,7 +153,7 @@ func testPodSpec(t *testing.T, dataDir string) {
|
||||
monFsContDev := test_opceph.ContainerTestDefinition{
|
||||
Image: &cephImage,
|
||||
Command: []string{
|
||||
"/usr/bin/ceph-mon"},
|
||||
"ceph-mon"},
|
||||
Args: append(
|
||||
monCommonExpectedArgs(name, c),
|
||||
[]string{"--mkfs"},
|
||||
@@ -172,7 +172,7 @@ func testPodSpec(t *testing.T, dataDir string) {
|
||||
monDaemonContDev := test_opceph.ContainerTestDefinition{
|
||||
Image: &cephImage,
|
||||
Command: []string{
|
||||
"/usr/bin/ceph-mon"},
|
||||
"ceph-mon"},
|
||||
Args: append(
|
||||
monCommonExpectedArgs(name, c),
|
||||
[]string{"--foreground"},
|
||||
|
||||
@@ -24,21 +24,12 @@ import (
|
||||
)
|
||||
|
||||
func TestPodVolumes(t *testing.T) {
|
||||
type args struct {
|
||||
dataDirHostPath string
|
||||
if err := test.VolumeIsEmptyDir(k8sutil.DataDirVolume, PodVolumes("")); err != nil {
|
||||
t.Errorf("PodVolumes(\"\") - data dir source is not EmptyDir: %s", err.Error())
|
||||
}
|
||||
if err := test.VolumeIsHostPath(k8sutil.DataDirVolume, "/dev/sdb", PodVolumes("/dev/sdb")); err != nil {
|
||||
t.Errorf("PodVolumes(\"/dev/sdb\") - data dir source is not HostPath: %s", err.Error())
|
||||
}
|
||||
t.Run("Empty string dataDirHostPath is EmptyDir volume", func(t *testing.T) {
|
||||
err := test.VolumeIsEmptyDir(k8sutil.DataDirVolume, PodVolumes(""))
|
||||
if err != nil {
|
||||
t.Errorf("PodVolumes(\"\") - dataDirHostPath is not EmptyDir: %s", err.Error())
|
||||
}
|
||||
})
|
||||
t.Run("Specified dataDirHostPath is HostPath volume", func(t *testing.T) {
|
||||
err := test.VolumeIsHostPath(k8sutil.DataDirVolume, "/dev/sdb", PodVolumes("/dev/sdb"))
|
||||
if err != nil {
|
||||
t.Errorf("PodVolumes(\"/dev/sdb\") - dataDirHostPath is not HostPath: %s", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMountsMatchVolumes(t *testing.T) {
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
/*
|
||||
Copyright 2018 The Rook Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package test provides common resources useful for testing many Ceph daemons. This includes
|
||||
// functions for testing that resources match what is expected.
|
||||
package test
|
||||
|
||||
import (
|
||||
|
||||
@@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package test for the operator tests.
|
||||
package test
|
||||
|
||||
import (
|
||||
|
||||
@@ -14,7 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package test for the operator tests
|
||||
// Package test provides common resources useful for testing many operators. This includes functions
|
||||
// for creating fake/mock resources and functions for testing that resources match what is expected.
|
||||
package test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
// Package testlib provides common methods for testing code which applies to many Ceph daemons.
|
||||
//
|
||||
// Methods beginning with "TestSpec" can be used to test that Kubernetes resource specs (pods, etc.)
|
||||
// are configured correctly.
|
||||
/*
|
||||
Copyright 2016 The Rook Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
// Package testlib provides common methods for testing code which applies to many Ceph daemons.
|
||||
//
|
||||
// Methods beginning with "TestSpec" can be used to test that Kubernetes resource specs (pods, etc.)
|
||||
// are configured correctly.
|
||||
/*
|
||||
Copyright 2016 The Rook Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import "testing"
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2018 The Rook Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright 2018 The Rook Authors. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user