diff --git a/go.mod b/go.mod index d85a28893..ad9bccce9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( github.com/aws/aws-sdk-go v1.16.26 - github.com/banzaicloud/k8s-objectmatcher v1.2.2 + github.com/banzaicloud/k8s-objectmatcher v1.1.0 github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea github.com/coreos/prometheus-operator v0.34.0 github.com/corpix/uarand v0.1.1 // indirect @@ -33,7 +33,7 @@ require ( k8s.io/kube-controller-manager v0.0.0 k8s.io/kubernetes v1.17.2 k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6 - sigs.k8s.io/controller-runtime v0.4.0 + sigs.k8s.io/controller-runtime v0.5.1 sigs.k8s.io/sig-storage-lib-external-provisioner v4.1.0+incompatible ) diff --git a/go.sum b/go.sum index cb54eadf4..d0cb5eafd 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,12 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= github.com/aws/aws-sdk-go v1.16.26 h1:GWkl3rkRO/JGRTWoLLIqwf7AWC4/W/1hMOUZqmX0js4= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/banzaicloud/k8s-objectmatcher v1.1.0 h1:KHWn9Oxh21xsaGKBHWElkaRrr4ypCDyrh15OB1zHtAw= +github.com/banzaicloud/k8s-objectmatcher v1.1.0/go.mod h1:gGaElvgkqa0Lk1khRr+jel/nsCLfzhLnD3CEWozpk9k= +github.com/banzaicloud/k8s-objectmatcher v1.1.1 h1:OWS/mUIb7HWI27pOYdxix4xu3nekNOvmS+Y3r9L5mFE= +github.com/banzaicloud/k8s-objectmatcher v1.1.1/go.mod h1:NTk6nNix5oP7/lE/5/YxFO87+241sDmTOKvoZ9E+Muw= +github.com/banzaicloud/k8s-objectmatcher v1.2.0 h1:ogya2/veg371s8jxWV2/NAtraMLnRqX+RELWJ8275JM= +github.com/banzaicloud/k8s-objectmatcher v1.2.0/go.mod h1:+kRcvF2kyA0u8k9AvTYgtt8zhv30Gi8ITKdMWqh7j+A= github.com/banzaicloud/k8s-objectmatcher v1.2.2 h1:WekhVqrRa/wUCPuESExwRjy5R+BDTf/s7DKP99y8MvY= github.com/banzaicloud/k8s-objectmatcher v1.2.2/go.mod h1:+kRcvF2kyA0u8k9AvTYgtt8zhv30Gi8ITKdMWqh7j+A= github.com/bazelbuild/bazel-gazelle v0.18.2/go.mod h1:D0ehMSbS+vesFsLGiD6JXu3mVEzOlfUl8wNnq+x/9p0= @@ -270,6 +276,7 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff h1:kOkM9whyQYodu09SJ6W3NCsHG7crFaJILQ22Gozp3lg= github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -501,6 +508,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -508,6 +517,8 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= +github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -665,6 +676,8 @@ go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= @@ -691,6 +704,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -780,6 +794,7 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -967,6 +982,8 @@ mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskX sigs.k8s.io/controller-runtime v0.2.0-beta.2/go.mod h1:TSH2R0nSz4WAlUUlNnOFcOR/VUhfwBLlmtq2X6AiQCA= sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg= sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= +sigs.k8s.io/controller-runtime v0.5.1 h1:TNidCfVoU/cs2i+9xoTcL/l7yhl0bDhYXU0NCG6wmiE= +sigs.k8s.io/controller-runtime v0.5.1/go.mod h1:Uojny7gvg55YLQnEGnPzRE3dC4ik2tRlZJgOUCWXAV4= sigs.k8s.io/controller-tools v0.2.2-0.20190919191502-76a25b63325a/go.mod h1:8SNGuj163x/sMwydREj7ld5mIMJu1cDanIfnx6xsU70= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/sig-storage-lib-external-provisioner v4.1.0+incompatible h1:pp7GUmQZKI57EjGnjkY88V4QbVuMpkw/ijKXqL67EsI= diff --git a/pkg/operator/ceph/controller/controller_utils.go b/pkg/operator/ceph/controller/controller_utils.go index 1926fcfee..35c7aa5a5 100644 --- a/pkg/operator/ceph/controller/controller_utils.go +++ b/pkg/operator/ceph/controller/controller_utils.go @@ -24,7 +24,6 @@ import ( cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" "github.com/rook/rook/pkg/clusterd" cephclient "github.com/rook/rook/pkg/daemon/ceph/client" - "github.com/rook/rook/pkg/operator/k8sutil" kerrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -44,7 +43,7 @@ var ( ) // IsReadyToReconcile determines if a controller is ready to reconcile or not -func IsReadyToReconcile(client client.Client, clustercontext *clusterd.Context, namespacedName types.NamespacedName) (cephv1.ClusterSpec, bool, bool, reconcile.Result) { +func IsReadyToReconcile(client client.Client, clustercontext *clusterd.Context, namespacedName types.NamespacedName, controllerName string) (cephv1.ClusterSpec, bool, bool, reconcile.Result) { namespacedName.Name = namespacedName.Namespace cephClusterExists := true @@ -55,34 +54,36 @@ func IsReadyToReconcile(client client.Client, clustercontext *clusterd.Context, if err != nil { if kerrors.IsNotFound(err) { cephClusterExists = false - logger.Errorf("CephCluster resource %q not found in namespace %q", namespacedName.Name, namespacedName.Namespace) - return cephv1.ClusterSpec{}, false, cephClusterExists, ImmediateRetryResult + logger.Errorf("%q: CephCluster resource %q not found in namespace %q", controllerName, namespacedName.Name, namespacedName.Namespace) + return cephv1.ClusterSpec{}, false, cephClusterExists, WaitForRequeueIfCephClusterNotReady } else if err != nil { - logger.Errorf("failed to fetch CephCluster %v", err) + logger.Errorf("%q:failed to fetch CephCluster %v", controllerName, err) return cephv1.ClusterSpec{}, false, cephClusterExists, ImmediateRetryResult } } - logger.Debugf("CephCluster resource %q found in namespace %q", namespacedName.Name, namespacedName.Namespace) + logger.Debugf("%q: CephCluster resource %q found in namespace %q", controllerName, namespacedName.Name, namespacedName.Namespace) - // If the cluster is ready - if cephCluster.Status.Phase == k8sutil.ReadyStatus { - // Test a Ceph command to verify the Operator is ready - // This is done to silence errors when the operator just started and cannot reconcile yet - _, err = cephclient.Status(clustercontext, namespacedName.Namespace) - if err != nil { - if strings.Contains(err.Error(), "error calling conf_read_file") { - logger.Info("operator is not ready to run ceph command, cannot reconcile yet.") - return cephCluster.Spec, false, cephClusterExists, WaitForRequeueIfCephClusterNotReady - } - // We should not arrive there - logger.Errorf("ceph command error %v", err) - return cephCluster.Spec, false, cephClusterExists, ImmediateRetryResult + // If the cluster is healthy + // Test a Ceph command to verify the Operator is ready + // This is done to silence errors when the operator just started and cannot reconcile yet + status, err := cephclient.Status(clustercontext, namespacedName.Namespace) + if err != nil { + if strings.Contains(err.Error(), "error calling conf_read_file") { + logger.Infof("%q: operator is not ready to run ceph command, cannot reconcile yet.", controllerName) + return cephCluster.Spec, false, cephClusterExists, WaitForRequeueIfCephClusterNotReady } - logger.Debugf("operator is ready to run ceph command, reconciling") + // We should not arrive there + logger.Errorf("%q: ceph command error %v", controllerName, err) + return cephCluster.Spec, false, cephClusterExists, ImmediateRetryResult + } + + // If Ceph status is ok we can reconcile + if status.Health.Status == "HEALTH_OK" || status.Health.Status == "HEALTH_WARN" { + logger.Debugf("%q: ceph status is %q, operator is ready to run ceph command, reconciling", controllerName, status.Health.Status) return cephCluster.Spec, true, cephClusterExists, reconcile.Result{} } - logger.Debugf("CephCluster resource %q found in namespace %q but not ready yet", namespacedName.Name, namespacedName.Namespace) - return cephCluster.Spec, false, cephClusterExists, ImmediateRetryResult + logger.Debugf("%q: CephCluster resource %q found in namespace %q but cluster state is not appropriate %q", controllerName, namespacedName.Name, namespacedName.Namespace, status.Health.Status) + return cephCluster.Spec, false, cephClusterExists, WaitForRequeueIfCephClusterNotReady } diff --git a/pkg/operator/ceph/file/controller.go b/pkg/operator/ceph/file/controller.go index d25cc6d19..3e76dfd42 100644 --- a/pkg/operator/ceph/file/controller.go +++ b/pkg/operator/ceph/file/controller.go @@ -36,6 +36,7 @@ import ( kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -54,8 +55,7 @@ var logger = capnslog.NewPackageLogger("github.com/rook/rook", controllerName) // List of object resources to watch by the controller var objectsToWatch = []runtime.Object{ &corev1.Secret{TypeMeta: metav1.TypeMeta{Kind: "Secret", APIVersion: corev1.SchemeGroupVersion.String()}}, - // Stop watching for Deployment object until https://github.com/rook/rook/issues/5047 is fully resolved - // &appsv1.Deployment{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: appsv1.SchemeGroupVersion.String()}}, + &appsv1.Deployment{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: appsv1.SchemeGroupVersion.String()}}, } var cephFilesystemKind = reflect.TypeOf(cephv1.CephFilesystem{}).Name() @@ -159,7 +159,7 @@ func (r *ReconcileCephFilesystem) reconcile(request reconcile.Request) (reconcil } // Make sure a CephCluster is present otherwise do nothing - cephClusterSpec, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName) + cephClusterSpec, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName, controllerName) if !isReadyToReconcile { // This handles the case where the Ceph Cluster is gone and we want to delete that CR // We skip the deleteFilesystem() function since everything is gone already @@ -177,8 +177,6 @@ func (r *ReconcileCephFilesystem) reconcile(request reconcile.Request) (reconcil // Return and do not requeue. Successful deletion. return reconcile.Result{}, nil } - - logger.Debugf("CephCluster resource not ready in namespace %q, retrying in %q.", request.NamespacedName.Namespace, opcontroller.WaitForRequeueIfCephClusterNotReadyAfter.String()) return reconcileResponse, nil } r.cephClusterSpec = &cephClusterSpec diff --git a/pkg/operator/ceph/file/controller_test.go b/pkg/operator/ceph/file/controller_test.go index 1a27a78f5..ac324d2a1 100644 --- a/pkg/operator/ceph/file/controller_test.go +++ b/pkg/operator/ceph/file/controller_test.go @@ -179,13 +179,7 @@ func TestCephObjectStoreController(t *testing.T) { executor := &exectest.MockExecutor{ MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { if args[0] == "status" { - return `{"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil - } - if args[0] == "fs" && args[1] == "get" { - return fsGet, nil - } - if args[0] == "auth" && args[1] == "get-or-create-key" { - return mdsCephAuthGetOrCreateKey, nil + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_ERR"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil } if args[0] == "versions" { return dummyVersionsRaw, nil @@ -193,6 +187,7 @@ func TestCephObjectStoreController(t *testing.T) { return "", nil }, } + clientset := test.New(t, 3) c := &clusterd.Context{ Executor: executor, @@ -279,6 +274,25 @@ func TestCephObjectStoreController(t *testing.T) { // Create a fake client to mock API calls. cl = fake.NewFakeClientWithScheme(s, object...) + executor = &exectest.MockExecutor{ + MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { + if args[0] == "status" { + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_OK"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil + } + if args[0] == "fs" && args[1] == "get" { + return fsGet, nil + } + if args[0] == "auth" && args[1] == "get-or-create-key" { + return mdsCephAuthGetOrCreateKey, nil + } + if args[0] == "versions" { + return dummyVersionsRaw, nil + } + return "", nil + }, + } + c.Executor = executor + // Create a ReconcileCephFilesystem object with the scheme and fake client. r = &ReconcileCephFilesystem{client: cl, scheme: s, context: c} diff --git a/pkg/operator/ceph/nfs/controller.go b/pkg/operator/ceph/nfs/controller.go index c4fa19b31..0843ab780 100644 --- a/pkg/operator/ceph/nfs/controller.go +++ b/pkg/operator/ceph/nfs/controller.go @@ -31,6 +31,7 @@ import ( opconfig "github.com/rook/rook/pkg/operator/ceph/config" opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" "github.com/rook/rook/pkg/operator/k8sutil" + appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -53,8 +54,7 @@ var logger = capnslog.NewPackageLogger("github.com/rook/rook", controllerName) var objectsToWatch = []runtime.Object{ &v1.Service{TypeMeta: metav1.TypeMeta{Kind: "Service", APIVersion: v1.SchemeGroupVersion.String()}}, &v1.ConfigMap{TypeMeta: metav1.TypeMeta{Kind: "ConfigMap", APIVersion: v1.SchemeGroupVersion.String()}}, - // Stop watching Deployments until this is resolved: https://github.com/rook/rook/issues/5047 - // &appsv1.Deployment{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: appsv1.SchemeGroupVersion.String()}}, + &appsv1.Deployment{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: appsv1.SchemeGroupVersion.String()}}, } var cephNFSKind = reflect.TypeOf(cephv1.CephNFS{}).Name() @@ -158,7 +158,7 @@ func (r *ReconcileCephNFS) reconcile(request reconcile.Request) (reconcile.Resul } // Make sure a CephCluster is present otherwise do nothing - cephClusterSpec, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName) + cephClusterSpec, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName, controllerName) if !isReadyToReconcile { // This handles the case where the Ceph Cluster is gone and we want to delete that CR // We skip the deleteStore() function since everything is gone already @@ -176,8 +176,6 @@ func (r *ReconcileCephNFS) reconcile(request reconcile.Request) (reconcile.Resul // Return and do not requeue. Successful deletion. return reconcile.Result{}, nil } - - logger.Debugf("CephCluster resource not ready in namespace %q, retrying in %q.", request.NamespacedName.Namespace, opcontroller.WaitForRequeueIfCephClusterNotReadyAfter.String()) return reconcileResponse, nil } r.cephClusterSpec = &cephClusterSpec diff --git a/pkg/operator/ceph/nfs/controller_test.go b/pkg/operator/ceph/nfs/controller_test.go index 4a6a370de..b6e309dfa 100644 --- a/pkg/operator/ceph/nfs/controller_test.go +++ b/pkg/operator/ceph/nfs/controller_test.go @@ -107,32 +107,12 @@ func TestCephNFSController(t *testing.T) { executor := &exectest.MockExecutor{ MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { if args[0] == "status" { - return `{"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_ERR"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil } if args[0] == "versions" { return dummyVersionsRaw, nil } - if args[0] == "osd" && args[1] == "pool" && args[2] == "get" { - return poolDetails, nil - } - return "", errors.New("unknown command") - }, - MockExecuteCommand: func(command string, args ...string) error { - if command == "rados" { - logger.Infof("mock execute. %s. %s", command, args) - assert.Equal(t, "stat", args[6]) - return nil - } - return errors.New("unknown command") - }, - MockExecuteCommandWithEnv: func(env []string, command string, args ...string) error { - if command == "ganesha-rados-grace" { - logger.Infof("mock execute. %s. %s", command, args) - assert.Equal(t, "add", args[4]) - assert.Len(t, env, 1) - return nil - } - return errors.New("unknown command") + return "", nil }, } clientset := test.New(t, 3) @@ -221,6 +201,39 @@ func TestCephNFSController(t *testing.T) { // Create a fake client to mock API calls. cl = fake.NewFakeClientWithScheme(s, object...) + executor = &exectest.MockExecutor{ + MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { + if args[0] == "status" { + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_OK"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil + } + if args[0] == "versions" { + return dummyVersionsRaw, nil + } + if args[0] == "osd" && args[1] == "pool" && args[2] == "get" { + return poolDetails, nil + } + return "", errors.New("unknown command") + }, + MockExecuteCommand: func(command string, args ...string) error { + if command == "rados" { + logger.Infof("mock execute. %s. %s", command, args) + assert.Equal(t, "stat", args[6]) + return nil + } + return errors.New("unknown command") + }, + MockExecuteCommandWithEnv: func(env []string, command string, args ...string) error { + if command == "ganesha-rados-grace" { + logger.Infof("mock execute. %s. %s", command, args) + assert.Equal(t, "add", args[4]) + assert.Len(t, env, 1) + return nil + } + return errors.New("unknown command") + }, + } + c.Executor = executor + // Create a ReconcileCephNFS object with the scheme and fake client. r = &ReconcileCephNFS{client: cl, scheme: s, context: c} diff --git a/pkg/operator/ceph/object/controller.go b/pkg/operator/ceph/object/controller.go index d042eed1a..8617f51a0 100644 --- a/pkg/operator/ceph/object/controller.go +++ b/pkg/operator/ceph/object/controller.go @@ -31,6 +31,7 @@ import ( opconfig "github.com/rook/rook/pkg/operator/ceph/config" opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" "github.com/rook/rook/pkg/operator/k8sutil" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" @@ -54,8 +55,7 @@ var logger = capnslog.NewPackageLogger("github.com/rook/rook", controllerName) var objectsToWatch = []runtime.Object{ &corev1.Secret{TypeMeta: metav1.TypeMeta{Kind: "Secret", APIVersion: corev1.SchemeGroupVersion.String()}}, &v1.Service{TypeMeta: metav1.TypeMeta{Kind: "Service", APIVersion: v1.SchemeGroupVersion.String()}}, - // Stop watching for Deployment object until https://github.com/rook/rook/issues/5047 is fully resolved - // &appsv1.Deployment{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: appsv1.SchemeGroupVersion.String()}}, + &appsv1.Deployment{TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: appsv1.SchemeGroupVersion.String()}}, } var cephObjectStoreKind = reflect.TypeOf(cephv1.CephObjectStore{}).Name() @@ -159,7 +159,7 @@ func (r *ReconcileCephObjectStore) reconcile(request reconcile.Request) (reconci } // Make sure a CephCluster is present otherwise do nothing - cephClusterSpec, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName) + cephClusterSpec, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName, controllerName) if !isReadyToReconcile { // This handles the case where the Ceph Cluster is gone and we want to delete that CR // We skip the deleteStore() function since everything is gone already @@ -178,7 +178,6 @@ func (r *ReconcileCephObjectStore) reconcile(request reconcile.Request) (reconci return reconcile.Result{}, nil } - logger.Debugf("CephCluster resource not ready in namespace %q, retrying in %q.", request.NamespacedName.Namespace, opcontroller.WaitForRequeueIfCephClusterNotReadyAfter.String()) return reconcileResponse, nil } r.cephClusterSpec = &cephClusterSpec diff --git a/pkg/operator/ceph/object/controller_test.go b/pkg/operator/ceph/object/controller_test.go index 292892156..b775e54cf 100644 --- a/pkg/operator/ceph/object/controller_test.go +++ b/pkg/operator/ceph/object/controller_test.go @@ -174,31 +174,13 @@ func TestCephObjectStoreController(t *testing.T) { executor := &exectest.MockExecutor{ MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { if args[0] == "status" { - return `{"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil - } - if args[0] == "auth" && args[1] == "get-or-create-key" { - return rgwCephAuthGetOrCreateKey, nil + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_ERR"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil } if args[0] == "versions" { return dummyVersionsRaw, nil } return "", nil }, - MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) { - if args[0] == "realm" && args[1] == "list" { - return realmListJSON, nil - } - if args[0] == "realm" && args[1] == "get" { - return realmGetJSON, nil - } - if args[0] == "zonegroup" && args[1] == "get" { - return zoneGroupGetJSON, nil - } - if args[0] == "zone" && args[1] == "get" { - return zoneGetJSON, nil - } - return "", nil - }, } clientset := test.New(t, 3) c := &clusterd.Context{ @@ -280,12 +262,41 @@ func TestCephObjectStoreController(t *testing.T) { _, err = c.Clientset.CoreV1().Secrets(namespace).Create(secret) assert.NoError(t, err) - // Add ready status to the CephCluster - cephCluster.Status.Phase = k8sutil.ReadyStatus - // Create a fake client to mock API calls. cl = fake.NewFakeClientWithScheme(s, object...) + // Override executor with the new ceph status and more content + executor = &exectest.MockExecutor{ + MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { + if args[0] == "status" { + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_OK"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil + } + if args[0] == "auth" && args[1] == "get-or-create-key" { + return rgwCephAuthGetOrCreateKey, nil + } + if args[0] == "versions" { + return dummyVersionsRaw, nil + } + return "", nil + }, + MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) { + if args[0] == "realm" && args[1] == "list" { + return realmListJSON, nil + } + if args[0] == "realm" && args[1] == "get" { + return realmGetJSON, nil + } + if args[0] == "zonegroup" && args[1] == "get" { + return zoneGroupGetJSON, nil + } + if args[0] == "zone" && args[1] == "get" { + return zoneGetJSON, nil + } + return "", nil + }, + } + c.Executor = executor + // Create a ReconcileCephObjectStore object with the scheme and fake client. r = &ReconcileCephObjectStore{client: cl, scheme: s, context: c} diff --git a/pkg/operator/ceph/object/user/controller.go b/pkg/operator/ceph/object/user/controller.go index 68a0d65aa..82d9134d2 100644 --- a/pkg/operator/ceph/object/user/controller.go +++ b/pkg/operator/ceph/object/user/controller.go @@ -151,7 +151,7 @@ func (r *ReconcileObjectStoreUser) reconcile(request reconcile.Request) (reconci } // Make sure a CephCluster is present otherwise do nothing - _, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName) + _, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName, controllerName) if !isReadyToReconcile { // This handles the case where the Ceph Cluster is gone and we want to delete that CR // We skip the deleteUser() function since everything is gone already @@ -169,8 +169,6 @@ func (r *ReconcileObjectStoreUser) reconcile(request reconcile.Request) (reconci // Return and do not requeue. Successful deletion. return reconcile.Result{}, nil } - - logger.Debugf("CephCluster resource not ready in namespace %q, retrying in %q.", request.NamespacedName.Namespace, opcontroller.WaitForRequeueIfCephClusterNotReadyAfter.String()) return reconcileResponse, nil } diff --git a/pkg/operator/ceph/object/user/controller_test.go b/pkg/operator/ceph/object/user/controller_test.go index 0feb70839..a0a6556e4 100644 --- a/pkg/operator/ceph/object/user/controller_test.go +++ b/pkg/operator/ceph/object/user/controller_test.go @@ -118,13 +118,7 @@ func TestCephObjectStoreUserController(t *testing.T) { executor := &exectest.MockExecutor{ MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { if args[0] == "status" { - return `{"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil - } - return "", nil - }, - MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) { - if args[0] == "user" { - return userCreateJSON, nil + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_ERR"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil } return "", nil }, @@ -190,6 +184,23 @@ func TestCephObjectStoreUserController(t *testing.T) { cephCluster.Status.Phase = k8sutil.ReadyStatus // Create a fake client to mock API calls. cl = fake.NewFakeClientWithScheme(s, object...) + + executor = &exectest.MockExecutor{ + MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { + if args[0] == "status" { + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_OK"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil + } + return "", nil + }, + MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) { + if args[0] == "user" { + return userCreateJSON, nil + } + return "", nil + }, + } + c.Executor = executor + // Create a ReconcileObjectStoreUser object with the scheme and fake client. r = &ReconcileObjectStoreUser{client: cl, scheme: s, context: c} diff --git a/pkg/operator/ceph/pool/controller.go b/pkg/operator/ceph/pool/controller.go index 0d873a377..8d29b526b 100644 --- a/pkg/operator/ceph/pool/controller.go +++ b/pkg/operator/ceph/pool/controller.go @@ -141,7 +141,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile } // Make sure a CephCluster is present otherwise do nothing - _, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName) + _, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.client, r.context, request.NamespacedName, controllerName) if !isReadyToReconcile { // This handles the case where the Ceph Cluster is gone and we want to delete that CR // We skip the deletePool() function since everything is gone already @@ -159,8 +159,6 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile // Return and do not requeue. Successful deletion. return reconcile.Result{}, nil } - - logger.Debugf("CephCluster resource not ready in namespace %q, retrying in %q.", request.NamespacedName.Namespace, opcontroller.WaitForRequeueIfCephClusterNotReadyAfter.String()) return reconcileResponse, nil } diff --git a/pkg/operator/ceph/pool/controller_test.go b/pkg/operator/ceph/pool/controller_test.go index 6c66b05d2..2df0830e4 100644 --- a/pkg/operator/ceph/pool/controller_test.go +++ b/pkg/operator/ceph/pool/controller_test.go @@ -238,7 +238,7 @@ func TestCephBlockPoolController(t *testing.T) { executor := &exectest.MockExecutor{ MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { if args[0] == "status" { - return `{"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_ERR"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil } return "", nil @@ -313,6 +313,18 @@ func TestCephBlockPoolController(t *testing.T) { } // Create a fake client to mock API calls. cl = fake.NewFakeClient(objects...) + + executor = &exectest.MockExecutor{ + MockExecuteCommandWithOutputFile: func(command, outfile string, args ...string) (string, error) { + if args[0] == "status" { + return `{"fsid":"c47cac40-9bee-4d52-823b-ccd803ba5bfe","health":{"checks":{},"status":"HEALTH_OK"},"pgmap":{"num_pgs":100,"pgs_by_state":[{"state_name":"active+clean","count":100}]}}`, nil + } + + return "", nil + }, + } + c.Executor = executor + // Create a ReconcileCephBlockPool object with the scheme and fake client. r = &ReconcileCephBlockPool{client: cl, scheme: s, context: c} diff --git a/tests/framework/utils/k8s_helper_test.go b/tests/framework/utils/k8s_helper_test.go index a56a0225c..b74969755 100644 --- a/tests/framework/utils/k8s_helper_test.go +++ b/tests/framework/utils/k8s_helper_test.go @@ -96,7 +96,7 @@ var rawContext = `{ func TestLoadMinikubeContext(t *testing.T) { executor := &exectest.MockExecutor{ - MockExecuteCommandWithOutput: func(command string, subcommand string, args ...string) (string, error) { + MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) { return fmt.Sprintf(rawContext, "minikube"), nil }} config, err := getKubeConfig(executor) @@ -111,7 +111,7 @@ func TestLoadMinikubeContext(t *testing.T) { func TestLoadDindContext(t *testing.T) { executor := &exectest.MockExecutor{ - MockExecuteCommandWithOutput: func(command string, subcommand string, args ...string) (string, error) { + MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) { return fmt.Sprintf(rawContext, "dind"), nil }} config, err := getKubeConfig(executor) @@ -126,7 +126,7 @@ func TestLoadDindContext(t *testing.T) { func TestLoadVagrantContext(t *testing.T) { executor := &exectest.MockExecutor{ - MockExecuteCommandWithOutput: func(command string, subcommand string, args ...string) (string, error) { + MockExecuteCommandWithOutput: func(command string, args ...string) (string, error) { return fmt.Sprintf(rawContext, "vagrant-single"), nil }} config, err := getKubeConfig(executor)