diff --git a/api/v1beta1/rabbitmqcluster_types.go b/api/v1beta1/rabbitmqcluster_types.go index f7802343b..5da33b1af 100644 --- a/api/v1beta1/rabbitmqcluster_types.go +++ b/api/v1beta1/rabbitmqcluster_types.go @@ -286,10 +286,10 @@ type RabbitmqClusterStatus struct { Conditions []status.RabbitmqClusterCondition `json:"conditions"` // Identifying information on internal resources - Admin *RabbitmqClusterAdmin `json:"admin,omitempty"` + DefaultUser *RabbitmqClusterDefaultUser `json:"defaultUser,omitempty"` } -type RabbitmqClusterAdmin struct { +type RabbitmqClusterDefaultUser struct { SecretReference *RabbitmqClusterSecretReference `json:"secretReference,omitempty"` ServiceReference *RabbitmqClusterServiceReference `json:"serviceReference,omitempty"` } diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 7cba5a0b4..cbbd2b9d0 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -176,46 +176,46 @@ func (in *RabbitmqCluster) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RabbitmqClusterAdmin) DeepCopyInto(out *RabbitmqClusterAdmin) { +func (in *RabbitmqClusterConfigurationSpec) DeepCopyInto(out *RabbitmqClusterConfigurationSpec) { *out = *in - if in.SecretReference != nil { - in, out := &in.SecretReference, &out.SecretReference - *out = new(RabbitmqClusterSecretReference) - (*in).DeepCopyInto(*out) - } - if in.ServiceReference != nil { - in, out := &in.ServiceReference, &out.ServiceReference - *out = new(RabbitmqClusterServiceReference) - **out = **in + if in.AdditionalPlugins != nil { + in, out := &in.AdditionalPlugins, &out.AdditionalPlugins + *out = make([]Plugin, len(*in)) + copy(*out, *in) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitmqClusterAdmin. -func (in *RabbitmqClusterAdmin) DeepCopy() *RabbitmqClusterAdmin { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitmqClusterConfigurationSpec. +func (in *RabbitmqClusterConfigurationSpec) DeepCopy() *RabbitmqClusterConfigurationSpec { if in == nil { return nil } - out := new(RabbitmqClusterAdmin) + out := new(RabbitmqClusterConfigurationSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *RabbitmqClusterConfigurationSpec) DeepCopyInto(out *RabbitmqClusterConfigurationSpec) { +func (in *RabbitmqClusterDefaultUser) DeepCopyInto(out *RabbitmqClusterDefaultUser) { *out = *in - if in.AdditionalPlugins != nil { - in, out := &in.AdditionalPlugins, &out.AdditionalPlugins - *out = make([]Plugin, len(*in)) - copy(*out, *in) + if in.SecretReference != nil { + in, out := &in.SecretReference, &out.SecretReference + *out = new(RabbitmqClusterSecretReference) + (*in).DeepCopyInto(*out) + } + if in.ServiceReference != nil { + in, out := &in.ServiceReference, &out.ServiceReference + *out = new(RabbitmqClusterServiceReference) + **out = **in } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitmqClusterConfigurationSpec. -func (in *RabbitmqClusterConfigurationSpec) DeepCopy() *RabbitmqClusterConfigurationSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RabbitmqClusterDefaultUser. +func (in *RabbitmqClusterDefaultUser) DeepCopy() *RabbitmqClusterDefaultUser { if in == nil { return nil } - out := new(RabbitmqClusterConfigurationSpec) + out := new(RabbitmqClusterDefaultUser) in.DeepCopyInto(out) return out } @@ -413,9 +413,9 @@ func (in *RabbitmqClusterStatus) DeepCopyInto(out *RabbitmqClusterStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - if in.Admin != nil { - in, out := &in.Admin, &out.Admin - *out = new(RabbitmqClusterAdmin) + if in.DefaultUser != nil { + in, out := &in.DefaultUser, &out.DefaultUser + *out = new(RabbitmqClusterDefaultUser) (*in).DeepCopyInto(*out) } } diff --git a/bin/kubectl-rabbitmq b/bin/kubectl-rabbitmq index 7fb35bff6..65fdb215b 100755 --- a/bin/kubectl-rabbitmq +++ b/bin/kubectl-rabbitmq @@ -23,7 +23,7 @@ usage() { echo " Open Management UI for an instance" echo " kubectl rabbitmq manage INSTANCE" echo - echo " Print admin secrets for an instance" + echo " Print default-user secrets for an instance" echo " kubectl rabbitmq secrets INSTANCE" echo echo " List all RabbitMQ clusters" @@ -67,8 +67,8 @@ usage() { get_instance_details() { instance=${1} - username=$(kubectl get secret "${instance}-rabbitmq-admin" -o jsonpath="{.data.username}" | base64 --decode) - password=$(kubectl get secret "${instance}-rabbitmq-admin" -o jsonpath="{.data.password}" | base64 --decode) + username=$(kubectl get secret "${instance}-rabbitmq-default-user" -o jsonpath="{.data.username}" | base64 --decode) + password=$(kubectl get secret "${instance}-rabbitmq-default-user" -o jsonpath="{.data.password}" | base64 --decode) service=${instance}-rabbitmq-client } diff --git a/charts/tsmgr/bind.yaml b/charts/tsmgr/bind.yaml index 8ca1c0589..c6a5c4786 100644 --- a/charts/tsmgr/bind.yaml +++ b/charts/tsmgr/bind.yaml @@ -9,8 +9,8 @@ template: | local clientFilterFunc(j) = std.length(std.findSubstr("rabbitmq-client", j.name)) > 0; local clientService = std.filter(clientFilterFunc, $.services)[0]; - local secretFilterFunc(j) = std.length(std.findSubstr("rabbitmq-admin", j.name)) > 0; - local admin = std.filter(secretFilterFunc, $.secrets); + local secretFilterFunc(j) = std.length(std.findSubstr("rabbitmq-default-user", j.name)) > 0; + local defaultUser = std.filter(secretFilterFunc, $.secrets); local vhost = "%2F"; local ingress = if clientService.spec.type == "LoadBalancer" then @@ -20,15 +20,15 @@ template: | clientService.status.loadBalancer.ingress[0].ip else clientService.spec.clusterIP; - local adminUsername = admin[0].data['username']; - local adminPassword = admin[0].data['password']; - local mgmtURI = "http://" + ingress + ":15672/#/login/" + adminUsername + "/" + adminPassword; - local apiURI = "http://" + adminUsername + ":" + adminPassword + "@" + ingress + ":15672/api/"; - local amqpURI = "amqp://" + adminUsername + ":" + adminPassword + "@" + ingress + "/" + vhost; + local defaultUserUsername = defaultUser[0].data['username']; + local defaultUserPassword = defaultUser[0].data['password']; + local mgmtURI = "http://" + ingress + ":15672"; + local apiURI = "http://" + defaultUserUsername + ":" + defaultUserPassword + "@" + ingress + ":15672/api/"; + local amqpURI = "amqp://" + defaultUserUsername + ":" + defaultUserPassword + "@" + ingress + "/" + vhost; { "hostname": ingress, - "username": adminUsername, - "password": adminPassword, + "username": defaultUserUsername, + "password": defaultUserPassword, "dashboard_url": mgmtURI, "hostnames": [ ingress @@ -49,14 +49,14 @@ template: | "hosts": [ ingress ], - "password": adminPassword, + "password": defaultUserPassword, "port": 5672, "ssl": false, "uri": amqpURI, "uris": [ amqpURI ], - "username": adminUsername, + "username": defaultUserUsername, "vhost": vhost }, "management": { @@ -64,7 +64,7 @@ template: | "hosts": [ ingress ], - "password": adminPassword, + "password": defaultUserPassword, "path": "/api/", "port": 15672, "ssl": false, @@ -72,7 +72,7 @@ template: | "uris": [ apiURI ], - "username": adminUsername + "username": defaultUserUsername } }, } diff --git a/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml b/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml index 9da12f46f..04a471bf9 100644 --- a/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml +++ b/config/crd/bases/rabbitmq.com_rabbitmqclusters.yaml @@ -3758,35 +3758,6 @@ spec: status: description: Status presents the observed state of RabbitmqCluster properties: - admin: - description: Identifying information on internal resources - properties: - secretReference: - properties: - keys: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - required: - - keys - - name - - namespace - type: object - serviceReference: - properties: - name: - type: string - namespace: - type: string - required: - - name - - namespace - type: object - type: object clusterStatus: type: string conditions: @@ -3817,6 +3788,35 @@ spec: - type type: object type: array + defaultUser: + description: Identifying information on internal resources + properties: + secretReference: + properties: + keys: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + required: + - keys + - name + - namespace + type: object + serviceReference: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: object required: - conditions type: object diff --git a/controllers/rabbitmqcluster_controller.go b/controllers/rabbitmqcluster_controller.go index b2357692a..3656939a3 100644 --- a/controllers/rabbitmqcluster_controller.go +++ b/controllers/rabbitmqcluster_controller.go @@ -205,7 +205,7 @@ func (r *RabbitmqClusterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, er "name", rabbitmqCluster.Name) } - if err := r.setAdminStatus(ctx, rabbitmqCluster); err != nil { + if err := r.setDefaultUserStatus(ctx, rabbitmqCluster); err != nil { return ctrl.Result{}, err } @@ -272,28 +272,28 @@ func (r *RabbitmqClusterReconciler) checkTLSSecrets(ctx context.Context, rabbitm return ctrl.Result{}, nil } -func (r *RabbitmqClusterReconciler) setAdminStatus(ctx context.Context, rmq *rabbitmqv1beta1.RabbitmqCluster) error { +func (r *RabbitmqClusterReconciler) setDefaultUserStatus(ctx context.Context, rmq *rabbitmqv1beta1.RabbitmqCluster) error { - adminStatus := &rabbitmqv1beta1.RabbitmqClusterAdmin{} + defaultUserStatus := &rabbitmqv1beta1.RabbitmqClusterDefaultUser{} serviceRef := &rabbitmqv1beta1.RabbitmqClusterServiceReference{ Name: rmq.ChildResourceName("client"), Namespace: rmq.Namespace, } - adminStatus.ServiceReference = serviceRef + defaultUserStatus.ServiceReference = serviceRef secretRef := &rabbitmqv1beta1.RabbitmqClusterSecretReference{ - Name: rmq.ChildResourceName(resource.AdminSecretName), + Name: rmq.ChildResourceName(resource.DefaultUserSecretName), Namespace: rmq.Namespace, Keys: map[string]string{ "username": "username", "password": "password", }, } - adminStatus.SecretReference = secretRef + defaultUserStatus.SecretReference = secretRef - if !reflect.DeepEqual(rmq.Status.Admin, adminStatus) { - rmq.Status.Admin = adminStatus + if !reflect.DeepEqual(rmq.Status.DefaultUser, defaultUserStatus) { + rmq.Status.DefaultUser = defaultUserStatus if err := r.Status().Update(ctx, rmq); err != nil { return err } diff --git a/controllers/rabbitmqcluster_controller_test.go b/controllers/rabbitmqcluster_controller_test.go index d494108a9..98902ad55 100644 --- a/controllers/rabbitmqcluster_controller_test.go +++ b/controllers/rabbitmqcluster_controller_test.go @@ -113,8 +113,8 @@ var _ = Describe("RabbitmqClusterController", func() { Expect(configMap.OwnerReferences[0].Name).To(Equal(cluster.Name)) }) - By("creating a rabbitmq admin secret", func() { - secretName := cluster.ChildResourceName("admin") + By("creating a rabbitmq default-user secret", func() { + secretName := cluster.ChildResourceName("default-user") secret, err := clientSet.CoreV1().Secrets(cluster.Namespace).Get(ctx, secretName, metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) Expect(secret.Name).To(Equal(secretName)) @@ -173,7 +173,7 @@ var _ = Describe("RabbitmqClusterController", func() { Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.ConfigMap", cluster.ChildResourceName("plugins-conf"))) Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.ConfigMap", cluster.ChildResourceName("server-conf"))) Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.Secret", cluster.ChildResourceName("erlang-cookie"))) - Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.Secret", cluster.ChildResourceName("admin"))) + Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.Secret", cluster.ChildResourceName("default-user"))) Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.ServiceAccount", cluster.ChildResourceName("server"))) Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.Role", cluster.ChildResourceName("peer-discovery"))) Expect(allEventMsgs).To(ContainSubstring("created resource %s of Type *v1.RoleBinding", cluster.ChildResourceName("server"))) @@ -194,7 +194,7 @@ var _ = Describe("RabbitmqClusterController", func() { }, 5).Should(Equal("deletion.finalizers.rabbitmqclusters.rabbitmq.com")) }) - By("setting the admin secret details in the custom resource status", func() { + By("setting the default-user secret details in the custom resource status", func() { rmq := &rabbitmqv1beta1.RabbitmqCluster{} secretRef := &rabbitmqv1beta1.RabbitmqClusterSecretReference{} Eventually(func() *rabbitmqv1beta1.RabbitmqClusterSecretReference { @@ -203,15 +203,15 @@ var _ = Describe("RabbitmqClusterController", func() { return nil } - if rmq.Status.Admin != nil && rmq.Status.Admin.SecretReference != nil { - secretRef = rmq.Status.Admin.SecretReference + if rmq.Status.DefaultUser != nil && rmq.Status.DefaultUser.SecretReference != nil { + secretRef = rmq.Status.DefaultUser.SecretReference return secretRef } return nil }, 5).ShouldNot(BeNil()) - Expect(secretRef.Name).To(Equal(rmq.ChildResourceName(resource.AdminSecretName))) + Expect(secretRef.Name).To(Equal(rmq.ChildResourceName(resource.DefaultUserSecretName))) Expect(secretRef.Namespace).To(Equal(rmq.Namespace)) Expect(secretRef.Keys).To(HaveKeyWithValue("username", "username")) Expect(secretRef.Keys).To(HaveKeyWithValue("password", "password")) @@ -226,8 +226,8 @@ var _ = Describe("RabbitmqClusterController", func() { return nil } - if rmq.Status.Admin != nil && rmq.Status.Admin.ServiceReference != nil { - serviceRef = rmq.Status.Admin.ServiceReference + if rmq.Status.DefaultUser != nil && rmq.Status.DefaultUser.ServiceReference != nil { + serviceRef = rmq.Status.DefaultUser.ServiceReference return serviceRef } @@ -803,7 +803,7 @@ var _ = Describe("RabbitmqClusterController", func() { It("updates annotations for secrets", func() { Eventually(func() map[string]string { - roleBinding, err := clientSet.CoreV1().Secrets(cluster.Namespace).Get(ctx, cluster.ChildResourceName("admin"), metav1.GetOptions{}) + roleBinding, err := clientSet.CoreV1().Secrets(cluster.Namespace).Get(ctx, cluster.ChildResourceName("default-user"), metav1.GetOptions{}) Expect(err).NotTo(HaveOccurred()) return roleBinding.Annotations }, 3).Should(HaveKeyWithValue(annotationKey, annotationValue)) @@ -1220,7 +1220,7 @@ var _ = Describe("RabbitmqClusterController", func() { { Secret: &corev1.SecretProjection{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "rabbitmq-sts-override-rabbitmq-admin", + Name: "rabbitmq-sts-override-rabbitmq-default-user", }, Items: []corev1.KeyToPath{ { diff --git a/docs/examples/federation-over-tls/setup.sh b/docs/examples/federation-over-tls/setup.sh index e09f31986..2cfd31c12 100755 --- a/docs/examples/federation-over-tls/setup.sh +++ b/docs/examples/federation-over-tls/setup.sh @@ -8,10 +8,10 @@ sleep 2 kubectl wait --for=condition=Ready pod/upstream-rabbitmq-server-0 kubectl wait --for=condition=Ready pod/downstream-rabbitmq-server-0 -UPSTREAM_USERNAME=$(kubectl get secret upstream-rabbitmq-admin -o jsonpath="{.data.username}" | base64 --decode) -UPSTREAM_PASSWORD=$(kubectl get secret upstream-rabbitmq-admin -o jsonpath="{.data.password}" | base64 --decode) -DOWNSTREAM_USERNAME=$(kubectl get secret downstream-rabbitmq-admin -o jsonpath="{.data.username}" | base64 --decode) -DOWNSTREAM_PASSWORD=$(kubectl get secret downstream-rabbitmq-admin -o jsonpath="{.data.password}" | base64 --decode) +UPSTREAM_USERNAME=$(kubectl get secret upstream-rabbitmq-default-user -o jsonpath="{.data.username}" | base64 --decode) +UPSTREAM_PASSWORD=$(kubectl get secret upstream-rabbitmq-default-user -o jsonpath="{.data.password}" | base64 --decode) +DOWNSTREAM_USERNAME=$(kubectl get secret downstream-rabbitmq-default-user -o jsonpath="{.data.username}" | base64 --decode) +DOWNSTREAM_PASSWORD=$(kubectl get secret downstream-rabbitmq-default-user -o jsonpath="{.data.password}" | base64 --decode) kubectl exec downstream-rabbitmq-server-0 -- rabbitmqctl set_parameter federation-upstream my-upstream "{\"uri\":\"amqps://${UPSTREAM_USERNAME}:${UPSTREAM_PASSWORD}@upstream-rabbitmq-client\",\"expires\":3600001}" @@ -26,8 +26,8 @@ read UPSTREAM_RABBITMQADMIN="rabbitmqadmin -U http://upstream-rabbitmq-client/ -u ${UPSTREAM_USERNAME} -p ${UPSTREAM_PASSWORD} -V /" DOWNSTREAM_RABBITMQADMIN="rabbitmqadmin -U http://downstream-rabbitmq-client/ -u ${DOWNSTREAM_USERNAME} -p ${DOWNSTREAM_PASSWORD} -V /" -$RABBITMQADMIN_UPSTREAM declare queue name=test.queue queue_type=quorum -$RABBITMQADMIN_UPSTREAM declare binding source=amq.fanout destination=test.queue +$UPSTREAM_RABBITMQADMIN declare queue name=test.queue queue_type=quorum +$UPSTREAM_RABBITMQADMIN declare binding source=amq.fanout destination=test.queue $DOWNSTREAM_RABBITMQADMIN declare queue name=test.queue queue_type=quorum $DOWNSTREAM_RABBITMQADMIN declare binding source=amq.fanout destination=test.queue diff --git a/docs/examples/import-definitions/README.md b/docs/examples/import-definitions/README.md index 7b0106bb2..8690f7174 100644 --- a/docs/examples/import-definitions/README.md +++ b/docs/examples/import-definitions/README.md @@ -21,4 +21,4 @@ kubectl create configmap definitions --from-file='def.json=/my/path/to/definitio Then, leverage the StatefulSet Override to mount this additional ConfigMap `definitions` to your rabbitmqcluster instance. Check out `rabbitmq.yaml` as an example. -Keep in mind that exported definitions contain all broker objects, including users. This means that the admin user credentials will be imported from the definitions, and will not be the one which is generated at the creation of the deployment as a kubernetes secret object. +Keep in mind that exported definitions contain all broker objects, including users. This means that the default-user credentials will be imported from the definitions, and will not be the one which is generated at the creation of the deployment as a kubernetes secret object. diff --git a/docs/proposals/implemented/20200310-crd-spec-configurability.md b/docs/proposals/implemented/20200310-crd-spec-configurability.md index dcf71f8a1..b74d9daa0 100644 --- a/docs/proposals/implemented/20200310-crd-spec-configurability.md +++ b/docs/proposals/implemented/20200310-crd-spec-configurability.md @@ -58,7 +58,7 @@ In our team roadmap we decided to coup the lack of user feedbacks by offering [d ## Proposal -This proposal adds the ability to override statefulSet and client service template directly through the CRD spec. Our operator creates 9 kubernetes child recourses directly for each `RabbitmqCluster`: client Service, headless Service, StatefulSet, ConfigMap, erlang cookie secret, admin secret, rbac role, role binding, service account. Among these resources, we allow users to partially configure the StatefulSet, the client Service, and the pods that StatefulSet creates. The proposal focuses on 2 child recourses: client Service and StatefulSet to increase configurability, since there is no obvious use case for now that involves configuring any of the other child resources. We can add overrides for other resources when we see fit in the future. +This proposal adds the ability to override statefulSet and client service template directly through the CRD spec. Our operator creates 9 kubernetes child recourses directly for each `RabbitmqCluster`: client Service, headless Service, StatefulSet, ConfigMap, erlang cookie secret, default user secret, rbac role, role binding, service account. Among these resources, we allow users to partially configure the StatefulSet, the client Service, and the pods that StatefulSet creates. The proposal focuses on 2 child recourses: client Service and StatefulSet to increase configurability, since there is no obvious use case for now that involves configuring any of the other child resources. We can add overrides for other resources when we see fit in the future. A brief summary of the proposed plan: * Add an override section to CRD spec which supports statefulSetOverride and clientServiceOverride diff --git a/internal/resource/admin_secret.go b/internal/resource/default_user_secret.go similarity index 84% rename from internal/resource/admin_secret.go rename to internal/resource/default_user_secret.go index b80d111b7..27306947d 100644 --- a/internal/resource/admin_secret.go +++ b/internal/resource/default_user_secret.go @@ -12,6 +12,7 @@ package resource import ( "bytes" "fmt" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" rabbitmqv1beta1 "github.com/rabbitmq/cluster-operator/api/v1beta1" @@ -23,51 +24,52 @@ import ( ) const ( - AdminSecretName = "admin" + DefaultUserSecretName = "default-user" ) -type AdminSecretBuilder struct { +type DefaultUserSecretBuilder struct { Instance *rabbitmqv1beta1.RabbitmqCluster Scheme *runtime.Scheme } -func (builder *RabbitmqResourceBuilder) AdminSecret() *AdminSecretBuilder { - return &AdminSecretBuilder{ +func (builder *RabbitmqResourceBuilder) DefaultUserSecret() *DefaultUserSecretBuilder { + return &DefaultUserSecretBuilder{ Instance: builder.Instance, Scheme: builder.Scheme, } } -func generateDefaultUserConf(username, password string) ([]byte, error) { - - ini.PrettySection = false // Remove trailing new line because default_user.conf has only a default section. - cfg, err := ini.Load([]byte{}) +func (builder *DefaultUserSecretBuilder) Build() (runtime.Object, error) { + username, err := randomEncodedString(24) if err != nil { return nil, err } - defaultSection := cfg.Section("") - - if _, err := defaultSection.NewKey("default_user", username); err != nil { - return nil, err - } - if _, err := defaultSection.NewKey("default_pass", password); err != nil { + password, err := randomEncodedString(24) + if err != nil { return nil, err } - var userConfBuffer bytes.Buffer - if _, err := cfg.WriteTo(&userConfBuffer); err != nil { + defaultUserConf, err := generateDefaultUserConf(username, password) + if err != nil { return nil, err } - return userConfBuffer.Bytes(), nil -} - -func (builder *AdminSecretBuilder) UpdateRequiresStsRestart() bool { - return false + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: builder.Instance.ChildResourceName(DefaultUserSecretName), + Namespace: builder.Instance.Namespace, + }, + Type: corev1.SecretTypeOpaque, + Data: map[string][]byte{ + "username": []byte(username), + "password": []byte(password), + "default_user.conf": defaultUserConf, + }, + }, nil } -func (builder *AdminSecretBuilder) Update(object runtime.Object) error { +func (builder *DefaultUserSecretBuilder) Update(object runtime.Object) error { secret := object.(*corev1.Secret) secret.Labels = metadata.GetLabels(builder.Instance.Name, builder.Instance.Labels) secret.Annotations = metadata.ReconcileAndFilterAnnotations(secret.GetAnnotations(), builder.Instance.Annotations) @@ -79,32 +81,30 @@ func (builder *AdminSecretBuilder) Update(object runtime.Object) error { return nil } -func (builder *AdminSecretBuilder) Build() (runtime.Object, error) { - username, err := randomEncodedString(24) +func (builder *DefaultUserSecretBuilder) UpdateRequiresStsRestart() bool { + return false +} + +func generateDefaultUserConf(username, password string) ([]byte, error) { + ini.PrettySection = false // Remove trailing new line because default_user.conf has only a default section. + cfg, err := ini.Load([]byte{}) if err != nil { return nil, err } + defaultSection := cfg.Section("") - password, err := randomEncodedString(24) - if err != nil { + if _, err := defaultSection.NewKey("default_user", username); err != nil { return nil, err } - defaultUserConf, err := generateDefaultUserConf(username, password) - if err != nil { + if _, err := defaultSection.NewKey("default_pass", password); err != nil { return nil, err } - return &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: builder.Instance.ChildResourceName(AdminSecretName), - Namespace: builder.Instance.Namespace, - }, - Type: corev1.SecretTypeOpaque, - Data: map[string][]byte{ - "username": []byte(username), - "password": []byte(password), - "default_user.conf": defaultUserConf, - }, - }, nil + var userConfBuffer bytes.Buffer + if _, err := cfg.WriteTo(&userConfBuffer); err != nil { + return nil, err + } + + return userConfBuffer.Bytes(), nil } diff --git a/internal/resource/admin_secret_test.go b/internal/resource/default_user_secret_test.go similarity index 88% rename from internal/resource/admin_secret_test.go rename to internal/resource/default_user_secret_test.go index f9278e9e1..aaaacdf7e 100644 --- a/internal/resource/admin_secret_test.go +++ b/internal/resource/default_user_secret_test.go @@ -11,6 +11,7 @@ package resource_test import ( b64 "encoding/base64" + "gopkg.in/ini.v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -24,13 +25,13 @@ import ( corev1 "k8s.io/api/core/v1" ) -var _ = Describe("AdminSecret", func() { +var _ = Describe("DefaultUserSecret", func() { var ( - secret *corev1.Secret - instance rabbitmqv1beta1.RabbitmqCluster - builder *resource.RabbitmqResourceBuilder - adminSecretBuilder *resource.AdminSecretBuilder - scheme *runtime.Scheme + secret *corev1.Secret + instance rabbitmqv1beta1.RabbitmqCluster + builder *resource.RabbitmqResourceBuilder + defaultUserSecretBuilder *resource.DefaultUserSecretBuilder + scheme *runtime.Scheme ) BeforeEach(func() { @@ -47,21 +48,21 @@ var _ = Describe("AdminSecret", func() { Instance: &instance, Scheme: scheme, } - adminSecretBuilder = builder.AdminSecret() + defaultUserSecretBuilder = builder.DefaultUserSecret() }) Context("Build with defaults", func() { - It("creates the necessary admin secret", func() { + It("creates the necessary default-user secret", func() { var username []byte var password []byte var ok bool - obj, err := adminSecretBuilder.Build() + obj, err := defaultUserSecretBuilder.Build() Expect(err).NotTo(HaveOccurred()) secret = obj.(*corev1.Secret) By("creating the secret with correct name and namespace", func() { - Expect(secret.Name).To(Equal(instance.ChildResourceName("admin"))) + Expect(secret.Name).To(Equal(instance.ChildResourceName("default-user"))) Expect(secret.Namespace).To(Equal("a namespace")) }) @@ -124,7 +125,7 @@ var _ = Describe("AdminSecret", func() { }, }, } - err := adminSecretBuilder.Update(secret) + err := defaultUserSecretBuilder.Update(secret) Expect(err).NotTo(HaveOccurred()) By("adding new labels from the CR", func() { @@ -172,10 +173,10 @@ var _ = Describe("AdminSecret", func() { }, }, } - err := adminSecretBuilder.Update(secret) + err := defaultUserSecretBuilder.Update(secret) Expect(err).NotTo(HaveOccurred()) - By("updating secret annotations on admin secret", func() { + By("updating secret annotations on default-user secret", func() { expectedAnnotations := map[string]string{ "my-annotation": "i-like-this", "i-was-here-already": "please-dont-delete-me", @@ -197,7 +198,7 @@ var _ = Describe("AdminSecret", func() { Name: "rabbit1", }, } - Expect(adminSecretBuilder.Update(secret)).NotTo(HaveOccurred()) + Expect(defaultUserSecretBuilder.Update(secret)).NotTo(HaveOccurred()) Expect(secret.OwnerReferences[0].Name).To(Equal(instance.Name)) }) }) diff --git a/internal/resource/erlang_cookie_test.go b/internal/resource/erlang_cookie_test.go index 545836798..708189611 100644 --- a/internal/resource/erlang_cookie_test.go +++ b/internal/resource/erlang_cookie_test.go @@ -11,6 +11,7 @@ package resource_test import ( b64 "encoding/base64" + "k8s.io/apimachinery/pkg/runtime" defaultscheme "k8s.io/client-go/kubernetes/scheme" @@ -102,7 +103,7 @@ var _ = Describe("ErlangCookie", func() { Expect(err).NotTo(HaveOccurred()) }) - It("adds labels from the CRD on the admin secret", func() { + It("adds labels from the CRD on the default-user secret", func() { testLabels(secret.Labels) }) diff --git a/internal/resource/rabbitmq_resource_builder.go b/internal/resource/rabbitmq_resource_builder.go index a93c143cb..aca507eeb 100644 --- a/internal/resource/rabbitmq_resource_builder.go +++ b/internal/resource/rabbitmq_resource_builder.go @@ -30,7 +30,7 @@ func (builder *RabbitmqResourceBuilder) ResourceBuilders() ([]ResourceBuilder, e builder.HeadlessService(), builder.ClientService(), builder.ErlangCookie(), - builder.AdminSecret(), + builder.DefaultUserSecret(), builder.RabbitmqPluginsConfigMap(), builder.ServerConfigMap(), builder.ServiceAccount(), diff --git a/internal/resource/rabbitmq_resource_builder_test.go b/internal/resource/rabbitmq_resource_builder_test.go index 2d8757f3e..15b3febd7 100644 --- a/internal/resource/rabbitmq_resource_builder_test.go +++ b/internal/resource/rabbitmq_resource_builder_test.go @@ -55,7 +55,7 @@ var _ = Describe("RabbitmqResourceBuilder", func() { &HeadlessServiceBuilder{}, &ClientServiceBuilder{}, &ErlangCookieBuilder{}, - &AdminSecretBuilder{}, + &DefaultUserSecretBuilder{}, &RabbitmqPluginsConfigMapBuilder{}, &ServerConfigMapBuilder{}, &ServiceAccountBuilder{}, diff --git a/internal/resource/statefulset.go b/internal/resource/statefulset.go index 3a1b4bbfd..bf8c3f824 100644 --- a/internal/resource/statefulset.go +++ b/internal/resource/statefulset.go @@ -286,7 +286,7 @@ func (builder *StatefulSetBuilder) podTemplateSpec(annotations, labels map[strin { Secret: &corev1.SecretProjection{ LocalObjectReference: corev1.LocalObjectReference{ - Name: builder.Instance.ChildResourceName(AdminSecretName), + Name: builder.Instance.ChildResourceName(DefaultUserSecretName), }, Items: []corev1.KeyToPath{ { diff --git a/internal/resource/statefulset_test.go b/internal/resource/statefulset_test.go index 481188991..0586d4310 100644 --- a/internal/resource/statefulset_test.go +++ b/internal/resource/statefulset_test.go @@ -855,7 +855,7 @@ var _ = Describe("StatefulSet", func() { { Secret: &corev1.SecretProjection{ LocalObjectReference: corev1.LocalObjectReference{ - Name: builder.Instance.ChildResourceName("admin"), + Name: builder.Instance.ChildResourceName("default-user"), }, Items: []corev1.KeyToPath{ { diff --git a/system_tests/utils.go b/system_tests/utils.go index 629332471..c95e99c7d 100644 --- a/system_tests/utils.go +++ b/system_tests/utils.go @@ -18,7 +18,6 @@ import ( "fmt" "io" "io/ioutil" - k8sresource "k8s.io/apimachinery/pkg/api/resource" "log" "net/http" "os" @@ -28,6 +27,8 @@ import ( "strings" "time" + k8sresource "k8s.io/apimachinery/pkg/api/resource" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/cloudflare/cfssl/csr" @@ -357,19 +358,19 @@ type HealthcheckResponse struct { } func getUsernameAndPassword(ctx context.Context, clientset *kubernetes.Clientset, namespace, instanceName string) (string, string, error) { - secret, err := clientset.CoreV1().Secrets(namespace).Get(ctx, fmt.Sprintf("%s-rabbitmq-admin", instanceName), metav1.GetOptions{}) + secret, err := clientset.CoreV1().Secrets(namespace).Get(ctx, fmt.Sprintf("%s-rabbitmq-default-user", instanceName), metav1.GetOptions{}) if err != nil { return "", "", err } username, ok := secret.Data["username"] if !ok { - return "", "", fmt.Errorf("cannot find 'username' in %s-rabbitmq-admin", instanceName) + return "", "", fmt.Errorf("cannot find 'username' in %s-rabbitmq-default-user", instanceName) } password, ok := secret.Data["password"] if !ok { - return "", "", fmt.Errorf("cannot find 'password' in %s-rabbitmq-admin", instanceName) + return "", "", fmt.Errorf("cannot find 'password' in %s-rabbitmq-default-user", instanceName) } return string(username), string(password), nil }