Skip to content

Commit

Permalink
[transporturl] Add envtest for default and tls use case
Browse files Browse the repository at this point in the history
  • Loading branch information
stuggi committed Dec 4, 2023
1 parent d112a58 commit bca900b
Show file tree
Hide file tree
Showing 5 changed files with 425 additions and 1 deletion.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/onsi/gomega v1.30.0
github.com/openstack-k8s-operators/infra-operator/apis v0.1.1-0.20230920125017-2c76cd203b44
github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231128145648-956f4d361a63
github.com/openstack-k8s-operators/lib-common/modules/test v0.3.0
github.com/rabbitmq/cluster-operator v1.14.0
go.uber.org/zap v1.26.0
golang.org/x/exp v0.0.0-20231127185646-65229373498e
Expand Down Expand Up @@ -55,6 +56,7 @@ require (
github.com/prometheus/procfs v0.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.7.0 // indirect
golang.org/x/sys v0.15.0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 h1:rncLxJBpFGqBztyxC
github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7/go.mod h1:ctXNyWanKEjGj8sss1KjjHQ3ENKFm33FFnS5BKaIPh4=
github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231128145648-956f4d361a63 h1:iA/8vt+o2bMxYvvenNB7VArBvM8UyDLw3G7S/teMLc0=
github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231128145648-956f4d361a63/go.mod h1:OYad2L+OD4j5CR49di7gu3Q1UkLBmpYwvtdoGlnasL4=
github.com/openstack-k8s-operators/lib-common/modules/test v0.3.0 h1:w2YR0OEXxmE1kQWhyyGPmQUY6s46xxnF3AnvpMpYjRU=
github.com/openstack-k8s-operators/lib-common/modules/test v0.3.0/go.mod h1:RfLOPJbmPzPZ4XHwwDc2tFbbw5zxZL15JFGwb5c6VaU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down Expand Up @@ -356,6 +358,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down
207 changes: 207 additions & 0 deletions tests/functional/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ import (
"github.com/google/uuid"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/intstr"

k8s_errors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

networkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
condition "github.com/openstack-k8s-operators/lib-common/modules/common/condition"
rabbitmqclusterv1 "github.com/rabbitmq/cluster-operator/api/v1beta1"
)

const (
Expand Down Expand Up @@ -136,6 +141,195 @@ func GetDefaultDNSDataSpec() map[string]interface{} {
return spec
}

func CreateTransportURL(name types.NamespacedName, spec map[string]interface{}) client.Object {
raw := map[string]interface{}{
"apiVersion": "rabbitmq.openstack.org/v1beta1",
"kind": "TransportURL",
"metadata": map[string]interface{}{
"name": name.Name,
"namespace": name.Namespace,
},
"spec": spec,
}

return th.CreateUnstructured(raw)
}

func CreateRabbitMQCluster(name types.NamespacedName, spec map[string]interface{}) client.Object {
raw := map[string]interface{}{
"apiVersion": "rabbitmq.com/v1beta1",
"kind": "RabbitmqCluster",
"metadata": map[string]interface{}{
"name": name.Name,
"namespace": name.Namespace,
},
"spec": spec,
}

return th.CreateUnstructured(raw)
}

func UpdateRabbitMQClusterToTLS(name types.NamespacedName) {
Eventually(func(g Gomega) {
mq := GetRabbitMQCluster(name)
g.Expect(mq).ToNot(BeNil())

_, err := controllerutil.CreateOrPatch(
th.Ctx, th.K8sClient, mq, func() error {
mq.Spec.TLS = rabbitmqclusterv1.TLSSpec{
CaSecretName: "rootca-internal",
DisableNonTLSListeners: true,
SecretName: "cert-rabbitmq-svc",
}
return nil
})
g.Expect(err).ShouldNot(HaveOccurred())
}, th.Timeout, th.Interval).Should(Succeed())
}

func GetDefaultRabbitMQClusterSpec(tlsEnabled bool) map[string]interface{} {
spec := make(map[string]interface{})
spec["delayStartSeconds"] = "30"
spec["image"] = "quay.io/podified-antelope-centos9/openstack-rabbitmq:current-podified"
if tlsEnabled {
spec["tls"] = map[string]interface{}{
"caSecretName": "rootca-internal",
"disableNonTLSListeners": true,
"secretName": "cert-rabbitmq-svc",
}
}

return spec
}

// DeleteRabbitMQCluster deletes a RabbitMQCluster instance from the Kubernetes cluster.
func DeleteRabbitMQCluster(name types.NamespacedName) {
Eventually(func(g Gomega) {
mq := &rabbitmqclusterv1.RabbitmqCluster{}
err := th.K8sClient.Get(th.Ctx, name, mq)
// if it is already gone that is OK
if k8s_errors.IsNotFound(err) {
return
}
g.Expect(err).NotTo(HaveOccurred())

g.Expect(th.K8sClient.Delete(th.Ctx, mq)).Should(Succeed())

err = th.K8sClient.Get(th.Ctx, name, mq)
g.Expect(k8s_errors.IsNotFound(err)).To(BeTrue())
}, th.Timeout, th.Interval).Should(Succeed())
}

func CreateOrUpdateRabbitMQClusterSecret(name types.NamespacedName, mq *rabbitmqclusterv1.RabbitmqCluster) {
Eventually(func(g Gomega) {
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name.Name,
Namespace: name.Namespace,
},
}

// create rabbitmq-secret secret
secretData := map[string][]byte{
"host": []byte(fmt.Sprintf("host.%s.svc", namespace)),
"password": []byte("12345678"),
"username": []byte("user"),
"port": []byte("5672"),
}

// if tls is enabled for rabbitmq cluster port will be 5671
if mq.Spec.TLS.SecretName != "" {
secretData["port"] = []byte("5671")
}

_, err := controllerutil.CreateOrPatch(
th.Ctx, th.K8sClient, secret, func() error {
secret.Data = secretData
return nil
})
g.Expect(err).ShouldNot(HaveOccurred())
}, th.Timeout, th.Interval).Should(Succeed())
}

// SimulateRabbitMQClusterReady function updates the RabbitMQCluster object
// status to have AllReplicasReady condition, statusDefaultUser reference
// and creates the secret referenced there containing host, password and user.
//
// Example usage:
//
// SimulateRabbitMQClusterReady(types.NamespacedName{Name: "test-mq", Namespace: "test-namespace"})
func SimulateRabbitMQClusterReady(name types.NamespacedName) {
Eventually(func(g Gomega) {
secretName := types.NamespacedName{Name: name.Name + "-default-user", Namespace: namespace}

mq := GetRabbitMQCluster(name)
g.Expect(mq).ToNot(BeNil())

// create/update rabbitmq secret
CreateOrUpdateRabbitMQClusterSecret(secretName, mq)

raw := map[string]interface{}{
"apiVersion": "rabbitmq.com/v1beta1",
"kind": "RabbitmqCluster",
"metadata": map[string]interface{}{
"name": name.Name,
"namespace": name.Namespace,
},
}

status := make(map[string]interface{})

// add AllReplicasReady condition
statusCondition := []map[string]interface{}{
{
"reason": "AllPodsAreReady",
"status": "True",
"type": "AllReplicasReady",
},
}

// add status.defaultUser which is used to get the
// secret holding username/password/host
statusDefaultUser := map[string]interface{}{
"secretReference": map[string]interface{}{
"keys": map[string]interface{}{
"password": "password",
"username": "username",
},
"name": secretName.Name,
"namespace": name.Namespace,
},
"serviceReference": map[string]interface{}{
"name": name.Name,
"namespace": name.Namespace,
},
}

status["conditions"] = statusCondition
status["defaultUser"] = statusDefaultUser
raw["status"] = status

un := &unstructured.Unstructured{Object: raw}
deploymentRes := schema.GroupVersionResource{
Group: "rabbitmq.com",
Version: "v1beta1",
Resource: "rabbitmqclusters",
}

// Patch status
result, err := dynClient.Resource(deploymentRes).Namespace(namespace).ApplyStatus(
th.Ctx, name.Name, un, metav1.ApplyOptions{FieldManager: "application/apply-patch"})
g.Expect(err).ToNot(HaveOccurred())
g.Expect(result).ToNot(BeNil())

mq = GetRabbitMQCluster(name)
g.Expect(mq.Status.Conditions).ToNot(BeNil())
g.Expect(mq.Status.DefaultUser).ToNot(BeNil())

}, th.Timeout, th.Interval).Should(Succeed())
th.Logger.Info("Simulated RabbitMQCluster ready", "on", name)
}

func GetDNSMasq(name types.NamespacedName) *networkv1.DNSMasq {
instance := &networkv1.DNSMasq{}
Eventually(func(g Gomega) {
Expand Down Expand Up @@ -176,6 +370,14 @@ func GetReservation(name types.NamespacedName) *networkv1.Reservation {
return instance
}

func GetRabbitMQCluster(name types.NamespacedName) *rabbitmqclusterv1.RabbitmqCluster {
mq := &rabbitmqclusterv1.RabbitmqCluster{}
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(ctx, name, mq)).Should(Succeed())
}, timeout, interval).Should(Succeed())
return mq
}

func DNSMasqConditionGetter(name types.NamespacedName) condition.Conditions {
instance := GetDNSMasq(name)
return instance.Status.Conditions
Expand All @@ -191,6 +393,11 @@ func IPSetConditionGetter(name types.NamespacedName) condition.Conditions {
return instance.Status.Conditions
}

func TransportURLConditionGetter(name types.NamespacedName) condition.Conditions {
instance := infra.GetTransportURL(name)
return instance.Status.Conditions
}

func CreateLoadBalancerService(name types.NamespacedName, addDnsAnno bool) *corev1.Service {
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Expand Down
32 changes: 31 additions & 1 deletion tests/functional/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"go.uber.org/zap/zapcore"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
Expand All @@ -36,8 +37,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap"

networkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1"
rabbitmqv1 "github.com/openstack-k8s-operators/infra-operator/apis/rabbitmq/v1beta1"
rabbitmqclusterv1 "github.com/rabbitmq/cluster-operator/api/v1beta1"

network_ctrl "github.com/openstack-k8s-operators/infra-operator/controllers/network"
rabbitmq_ctrl "github.com/openstack-k8s-operators/infra-operator/controllers/rabbitmq"

infra_test "github.com/openstack-k8s-operators/infra-operator/apis/test/helpers"
test "github.com/openstack-k8s-operators/lib-common/modules/test"

. "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"
//+kubebuilder:scaffold:imports
Expand All @@ -49,12 +56,14 @@ import (
var (
cfg *rest.Config
k8sClient client.Client // You'll be using this client in your tests.
dynClient *dynamic.DynamicClient
testEnv *envtest.Environment
ctx context.Context
cancel context.CancelFunc
logger logr.Logger
th *TestHelper
namespace string
infra *infra_test.TestHelper
)

func TestAPIs(t *testing.T) {
Expand All @@ -70,10 +79,15 @@ var _ = BeforeSuite(func() {

ctx, cancel = context.WithCancel(context.TODO())

rabbitmqv2CRDs, err := test.GetCRDDirFromModule(
"github.com/rabbitmq/cluster-operator", "../../go.mod", "config/crd/bases")
Expect(err).ShouldNot(HaveOccurred())

By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{
filepath.Join("..", "..", "config", "crd", "bases"),
rabbitmqv2CRDs,
},
ErrorIfCRDPathMissing: true,
WebhookInstallOptions: envtest.WebhookInstallOptions{
Expand All @@ -86,7 +100,6 @@ var _ = BeforeSuite(func() {
}

// cfg is defined in this file globally.
var err error
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
Expand All @@ -97,6 +110,10 @@ var _ = BeforeSuite(func() {
// in the test env.
err = networkv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = rabbitmqv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = rabbitmqclusterv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
//+kubebuilder:scaffold:scheme

logger = ctrl.Log.WithName("---Test---")
Expand All @@ -106,6 +123,8 @@ var _ = BeforeSuite(func() {
Expect(k8sClient).NotTo(BeNil())
th = NewTestHelper(ctx, k8sClient, timeout, interval, logger)
Expect(th).NotTo(BeNil())
infra = infra_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger)
Expect(infra).NotTo(BeNil())

// Start the controller-manager if goroutine
webhookInstallOptions := &testEnv.WebhookInstallOptions
Expand All @@ -125,6 +144,10 @@ var _ = BeforeSuite(func() {
kclient, err := kubernetes.NewForConfig(cfg)
Expect(err).ToNot(HaveOccurred(), "failed to create kclient")

dynClient, err = dynamic.NewForConfig(cfg)
Expect(err).NotTo(HaveOccurred())
Expect(dynClient).NotTo(BeNil())

err = (&networkv1.NetConfig{}).SetupWebhookWithManager(k8sManager)
Expect(err).NotTo(HaveOccurred())
err = (&networkv1.IPSet{}).SetupWebhookWithManager(k8sManager)
Expand Down Expand Up @@ -162,6 +185,13 @@ var _ = BeforeSuite(func() {
}).SetupWithManager(context.Background(), k8sManager)
Expect(err).ToNot(HaveOccurred())

err = (&rabbitmq_ctrl.TransportURLReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
Kclient: kclient,
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

go func() {
defer GinkgoRecover()
err = k8sManager.Start(ctx)
Expand Down
Loading

0 comments on commit bca900b

Please sign in to comment.