Skip to content

Commit 685e56d

Browse files
authored
Support custom connect uri through annotation (#644)
- allow connection uri to be overwritten by annotation in rabbitmqcluster
1 parent a9296f0 commit 685e56d

File tree

2 files changed

+183
-8
lines changed

2 files changed

+183
-8
lines changed

rabbitmqclient/cluster_reference.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"sigs.k8s.io/controller-runtime/pkg/client"
1616
)
1717

18+
const uriAnnotationKey = "rabbitmq.com/operator-connection-uri"
19+
1820
type ClusterCredentials struct {
1921
data map[string][]byte
2022
}
@@ -90,6 +92,18 @@ func ParseReference(ctx context.Context, c client.Client, rmq topology.RabbitmqC
9092
}
9193
}
9294

95+
if uriAnnotation, ok := cluster.Annotations[uriAnnotationKey]; ok {
96+
uri, useTLSForConnection, err := extractURIandScheme(uriAnnotation)
97+
if err != nil {
98+
return nil, false, err
99+
}
100+
return map[string]string{
101+
"username": user,
102+
"password": pass,
103+
"uri": uri,
104+
}, useTLSForConnection, nil
105+
}
106+
93107
svc := &corev1.Service{}
94108
if err := c.Get(ctx, types.NamespacedName{Namespace: namespace, Name: cluster.Status.DefaultUser.ServiceReference.Name}, svc); err != nil {
95109
return nil, false, err
@@ -140,15 +154,9 @@ func readCredentialsFromKubernetesSecret(secret *corev1.Secret) (map[string]stri
140154
return nil, false, keyMissingErr("uri")
141155
}
142156

143-
uri := string(uBytes)
144-
if !strings.HasPrefix(uri, "http") {
145-
uri = "http://" + uri // set scheme to http if not provided
146-
}
147-
var tlsEnabled bool
148-
if parsed, err := url.Parse(uri); err != nil {
157+
uri, tlsEnabled, err := extractURIandScheme(string(uBytes))
158+
if err != nil {
149159
return nil, false, err
150-
} else if parsed.Scheme == "https" {
151-
tlsEnabled = true
152160
}
153161

154162
return map[string]string{
@@ -158,6 +166,19 @@ func readCredentialsFromKubernetesSecret(secret *corev1.Secret) (map[string]stri
158166
}, tlsEnabled, nil
159167
}
160168

169+
func extractURIandScheme(uri string) (string, bool, error) {
170+
if !strings.HasPrefix(uri, "http") {
171+
uri = "http://" + uri // set scheme to http if not provided
172+
}
173+
174+
if parsed, err := url.Parse(uri); err != nil {
175+
return "", false, err
176+
} else if parsed.Scheme == "https" {
177+
return uri, true, nil
178+
}
179+
return uri, false, nil
180+
}
181+
161182
func readClusterAdditionalConfig(cluster *rabbitmqv1beta1.RabbitmqCluster) (additionalConfig map[string]string, err error) {
162183
cfg, err := ini.Load([]byte(cluster.Spec.Rabbitmq.AdditionalConfig))
163184
if err != nil {

rabbitmqclient/cluster_reference_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var _ = Describe("ParseReference", func() {
2929
existingService *corev1.Service
3030
ctx = context.Background()
3131
namespace = "rabbitmq-system"
32+
uriAnnotationKey = "rabbitmq.com/operator-connection-uri"
3233
)
3334

3435
JustBeforeEach(func() {
@@ -765,6 +766,159 @@ var _ = Describe("ParseReference", func() {
765766
})
766767

767768
})
769+
770+
When("the RabbitmqCluster is annotated with connection uri override", func() {
771+
BeforeEach(func() {
772+
existingRabbitMQCluster = &rabbitmqv1beta1.RabbitmqCluster{
773+
ObjectMeta: metav1.ObjectMeta{
774+
Name: "rmq",
775+
Namespace: namespace,
776+
Annotations: map[string]string{
777+
uriAnnotationKey: "http://a-rabbitmq-test:2333",
778+
},
779+
},
780+
Status: rabbitmqv1beta1.RabbitmqClusterStatus{
781+
Binding: &corev1.LocalObjectReference{
782+
Name: "rmq-default-user-credentials",
783+
},
784+
DefaultUser: &rabbitmqv1beta1.RabbitmqClusterDefaultUser{
785+
ServiceReference: &rabbitmqv1beta1.RabbitmqClusterServiceReference{
786+
Name: "rmq",
787+
Namespace: namespace,
788+
},
789+
},
790+
},
791+
}
792+
existingCredentialSecret = &corev1.Secret{
793+
ObjectMeta: metav1.ObjectMeta{
794+
Name: "rmq-default-user-credentials",
795+
Namespace: namespace,
796+
},
797+
Data: map[string][]byte{
798+
"username": []byte(existingRabbitMQUsername),
799+
"password": []byte(existingRabbitMQPassword),
800+
},
801+
}
802+
existingService = &corev1.Service{
803+
ObjectMeta: metav1.ObjectMeta{
804+
Name: "rmq",
805+
Namespace: namespace,
806+
},
807+
Spec: corev1.ServiceSpec{
808+
ClusterIP: "1.2.3.4",
809+
Ports: []corev1.ServicePort{
810+
{
811+
Name: "management",
812+
Port: int32(15672),
813+
},
814+
},
815+
},
816+
}
817+
objs = []runtime.Object{existingRabbitMQCluster, existingCredentialSecret, existingService}
818+
})
819+
820+
It("returns correct credentials", func() {
821+
creds, tlsOn, err := rabbitmqclient.ParseReference(ctx, fakeClient,
822+
topology.RabbitmqClusterReference{Name: existingRabbitMQCluster.Name},
823+
existingRabbitMQCluster.Namespace,
824+
"",
825+
false)
826+
Expect(err).NotTo(HaveOccurred())
827+
Expect(tlsOn).To(BeFalse())
828+
829+
usernameBytes, _ := creds["username"]
830+
passwordBytes, _ := creds["password"]
831+
uriBytes, _ := creds["uri"]
832+
Expect(usernameBytes).To(Equal(existingRabbitMQUsername))
833+
Expect(passwordBytes).To(Equal(existingRabbitMQPassword))
834+
Expect(uriBytes).To(Equal("http://a-rabbitmq-test:2333"))
835+
})
836+
837+
When("annotated URI has no scheme", func() {
838+
BeforeEach(func() {
839+
*existingRabbitMQCluster = rabbitmqv1beta1.RabbitmqCluster{
840+
ObjectMeta: metav1.ObjectMeta{
841+
Name: "rmq",
842+
Namespace: namespace,
843+
Annotations: map[string]string{
844+
uriAnnotationKey: "a-rabbitmq-test:7890",
845+
},
846+
},
847+
Status: rabbitmqv1beta1.RabbitmqClusterStatus{
848+
Binding: &corev1.LocalObjectReference{
849+
Name: "rmq-default-user-credentials",
850+
},
851+
DefaultUser: &rabbitmqv1beta1.RabbitmqClusterDefaultUser{
852+
ServiceReference: &rabbitmqv1beta1.RabbitmqClusterServiceReference{
853+
Name: "rmq",
854+
Namespace: namespace,
855+
},
856+
},
857+
},
858+
}
859+
})
860+
861+
It("sets http as the scheme", func() {
862+
creds, tlsOn, err := rabbitmqclient.ParseReference(ctx, fakeClient,
863+
topology.RabbitmqClusterReference{Name: existingRabbitMQCluster.Name},
864+
existingRabbitMQCluster.Namespace,
865+
"",
866+
false)
867+
Expect(err).NotTo(HaveOccurred())
868+
Expect(tlsOn).To(BeFalse())
869+
870+
usernameBytes, _ := creds["username"]
871+
passwordBytes, _ := creds["password"]
872+
uriBytes, _ := creds["uri"]
873+
Expect(usernameBytes).To(Equal(existingRabbitMQUsername))
874+
Expect(passwordBytes).To(Equal(existingRabbitMQPassword))
875+
Expect(uriBytes).To(Equal("http://a-rabbitmq-test:7890"))
876+
})
877+
})
878+
879+
When("annotated URI has https as scheme", func() {
880+
BeforeEach(func() {
881+
*existingRabbitMQCluster = rabbitmqv1beta1.RabbitmqCluster{
882+
ObjectMeta: metav1.ObjectMeta{
883+
Name: "rmq",
884+
Namespace: namespace,
885+
Annotations: map[string]string{
886+
uriAnnotationKey: "https://a-rabbitmq-test:2333",
887+
},
888+
},
889+
Status: rabbitmqv1beta1.RabbitmqClusterStatus{
890+
Binding: &corev1.LocalObjectReference{
891+
Name: "rmq-default-user-credentials",
892+
},
893+
DefaultUser: &rabbitmqv1beta1.RabbitmqClusterDefaultUser{
894+
ServiceReference: &rabbitmqv1beta1.RabbitmqClusterServiceReference{
895+
Name: "rmq",
896+
Namespace: namespace,
897+
},
898+
},
899+
},
900+
}
901+
})
902+
903+
It("returns correct credentials", func() {
904+
creds, tlsOn, err := rabbitmqclient.ParseReference(ctx, fakeClient,
905+
topology.RabbitmqClusterReference{Name: existingRabbitMQCluster.Name},
906+
existingRabbitMQCluster.Namespace,
907+
"",
908+
false)
909+
Expect(err).NotTo(HaveOccurred())
910+
Expect(tlsOn).To(BeTrue())
911+
912+
usernameBytes, _ := creds["username"]
913+
passwordBytes, _ := creds["password"]
914+
uriBytes, _ := creds["uri"]
915+
Expect(usernameBytes).To(Equal(existingRabbitMQUsername))
916+
Expect(passwordBytes).To(Equal(existingRabbitMQPassword))
917+
Expect(uriBytes).To(Equal("https://a-rabbitmq-test:2333"))
918+
})
919+
})
920+
921+
})
768922
})
769923

770924
var _ = Describe("AllowedNamespace", func() {

0 commit comments

Comments
 (0)