internal/resource/testutils.go (317 lines of code) (raw):

package resource import ( . "git.jetbrains.team/tch/teamcity-operator/api/v1beta1" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" defaultscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client" ) const ( TeamCityName = "test" TeamCityNamespace = "default" TeamCityImage = "jetbrains/teamcity-server:latest" ) type ResourceModifier func(*TeamCity) var ( Instance TeamCity DefaultClient client.Client DefaultStatefulSetBuilder *StatefulSetBuilder DefaultServiceBuilder *ServiceBuilder DefaultIngressBuilder *IngressBuilder DefaultPersistentVolumeClaimBuilder *PersistentVolumeClaimBuilder DefaultSecondaryStatefulSetBuilder *SecondaryStatefulSetBuilder DefaultServiceAccountBuilder *ServiceAccountBuilder StaleStatefulSetName = "StaleSTS" StaleServiceAccountName = "StaleServiceAccount" StaleIngressName = "StaleIngress" StalePvcName = "StalePvc" StaleServiceName = "StaleService" scheme *runtime.Scheme builder *TeamCityResourceBuilder teamCityReplicas = int32(0) dataDirPVCAccessMode = []corev1.PersistentVolumeAccessMode{"ReadWriteMany"} dataDirPVCStorageClassName = "standard" dataDirPVCVolumeMode = corev1.PersistentVolumeFilesystem dataDirPVCResources = corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceStorage: resource.MustParse("1Gi"), }, } dataDirPVCName = "data-dir" dataDirPVCSpec = corev1.PersistentVolumeClaimSpec{ AccessModes: dataDirPVCAccessMode, StorageClassName: &dataDirPVCStorageClassName, VolumeMode: &dataDirPVCVolumeMode, Resources: dataDirPVCResources, } dataDirPVC = CustomPersistentVolumeClaim{ Name: dataDirPVCName, Spec: dataDirPVCSpec, VolumeMount: corev1.VolumeMount{ Name: "default-storage", MountPath: "/storage", }, } requests = corev1.ResourceList{ "cpu": resource.MustParse("900m"), "memory": resource.MustParse("1512Mi"), } mainNodeName = "main-node" xmxPercentage = int64(95) serviceNameMain = TeamCityName + "-service-main" serviceNameSecondary = TeamCityName + "-service-secondary" servicePort = int32(8111) ingressNameFirst = TeamCityName + "-ingress-first" ingressNameSecondary = TeamCityName + "-ingress-secondary" ) func BeforeEachBuild(modify ResourceModifier) { Instance = getBaseTcInstance() scheme = runtime.NewScheme() Expect(AddToScheme(scheme)).To(Succeed()) Expect(defaultscheme.AddToScheme(scheme)).To(Succeed()) modify(&Instance) builder = &TeamCityResourceBuilder{ Instance: &Instance, Scheme: scheme, Client: DefaultClient, } DefaultStatefulSetBuilder = builder.StatefulSet() DefaultServiceBuilder = builder.Service() DefaultIngressBuilder = builder.Ingress() DefaultPersistentVolumeClaimBuilder = builder.PersistentVolumeClaim() DefaultSecondaryStatefulSetBuilder = builder.SecondaryStatefulSet() DefaultServiceAccountBuilder = builder.ServiceAccount() } func getBaseTcInstance() TeamCity { return TeamCity{ ObjectMeta: metav1.ObjectMeta{ Name: TeamCityName, Namespace: TeamCityNamespace, }, Spec: TeamCitySpec{ Image: TeamCityImage, DataDirVolumeClaim: dataDirPVC, XmxPercentage: xmxPercentage, MainNode: Node{ Name: mainNodeName, Spec: NodeSpec{ Requests: requests, }, }, }, } } func getStartupConfigurations() map[string]string { return map[string]string{ "foo": "bar", "hello": "world", } } func getDatabaseSecret() DatabaseSecret { return DatabaseSecret{ Secret: "database-secret", } } func getNodeSelector() map[string]string { return map[string]string{ "hello": "world", "foo": "bar", } } func getAffinity() corev1.Affinity { return corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ NodeSelectorTerms: []corev1.NodeSelectorTerm{ { MatchExpressions: []corev1.NodeSelectorRequirement{ { Key: "some-key", Operator: "In", Values: []string{"some-value"}, }, }, }, }, }, PreferredDuringSchedulingIgnoredDuringExecution: []corev1.PreferredSchedulingTerm{ { Weight: 5, Preference: corev1.NodeSelectorTerm{ MatchExpressions: []corev1.NodeSelectorRequirement{ { Key: "some-key", Operator: "In", Values: []string{"some-value"}, }, }, }, }, }, }, } } func getInitContainers() []corev1.Container { return []corev1.Container{ { Name: "volume-permissions", Image: "busybox", Command: []string{ "sh", "-c", "chown -R 1000:1000 /storage", }, SecurityContext: &corev1.SecurityContext{ RunAsNonRoot: pointer.Bool(false), RunAsUser: pointer.Int64(0), }, VolumeMounts: []corev1.VolumeMount{ { Name: "teamcity-node-volume1", MountPath: "/storage", }, }, }, } } func getAdditionalPVC() CustomPersistentVolumeClaim { return CustomPersistentVolumeClaim{ Name: "some-additional-data", VolumeMount: corev1.VolumeMount{ Name: "plugin-data", MountPath: "/storage/plugins", }, Spec: corev1.PersistentVolumeClaimSpec{ AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteMany"}, Resources: corev1.ResourceRequirements{}, StorageClassName: pointer.String("standard"), VolumeMode: &dataDirPVCVolumeMode, }, } } func getServiceList() []Service { return []Service{ { Name: serviceNameMain, Annotations: map[string]string{ "role": "tc-main", }, ServiceSpec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{ {Port: servicePort, TargetPort: intstr.FromInt32(8111)}, }, Selector: map[string]string{ "app.kubernetes.io/name": TeamCityName, }, }, }, { Name: serviceNameSecondary, Annotations: map[string]string{ "role": "tc-secondary", }, ServiceSpec: corev1.ServiceSpec{ Ports: []corev1.ServicePort{ {Port: servicePort, TargetPort: intstr.FromInt32(8111)}, }, Selector: map[string]string{ "app.kubernetes.io/name": TeamCityName, }, }, }, } } func getLabels() map[string]string { return map[string]string{ "foo": "bar", "teamcity": "the best", "app.kubernetes.io/name": "label-override-test", } } func getIngressList() []Ingress { ingressClassName := "nginx" ingressServiceBackend := netv1.IngressServiceBackend{ Name: serviceNameMain, Port: netv1.ServiceBackendPort{ Number: servicePort, }, } ingressHttpRuleValue := netv1.HTTPIngressRuleValue{ Paths: []netv1.HTTPIngressPath{ { Backend: netv1.IngressBackend{Service: &ingressServiceBackend}, }, }, } ingressRuleValue := netv1.IngressRuleValue{ HTTP: &ingressHttpRuleValue, } return []Ingress{ { Name: ingressNameFirst, Annotations: map[string]string{ "role": "tc-main", }, IngressSpec: netv1.IngressSpec{ IngressClassName: &ingressClassName, Rules: []netv1.IngressRule{ { Host: TeamCityName + ".myteamcity.com", IngressRuleValue: ingressRuleValue, }, }, }, }, { Name: ingressNameSecondary, Annotations: map[string]string{ "role": "tc-secondary", }, IngressSpec: netv1.IngressSpec{ IngressClassName: &ingressClassName, Rules: []netv1.IngressRule{ { Host: TeamCityName + "-secondary.myteamcity.com", IngressRuleValue: ingressRuleValue, }, }, }, }, } } func getSecondaryNodes() []Node { return []Node{ getNode("secondary-0", make(map[string]string), requests, []string{"foo"}), getNode("secondary-1", make(map[string]string), requests, []string{"bar"}), } } func getNode(nodeName string, annotations map[string]string, requests corev1.ResourceList, responsibilities []string) Node { return Node{ Name: nodeName, Annotations: annotations, Spec: NodeSpec{ Requests: requests, Responsibilities: responsibilities, }, } } func getServiceAccount() ServiceAccount { return ServiceAccount{ Name: "test-service-account", Annotations: map[string]string{ "eks.amazonaws.com/role-arn": "some-role", }, } } func getExtraNodeEnvVars() map[string]string { return map[string]string{ "AWS_DEFAULT_REGION": "eu-west-1", "HELLO": "WORLD", } }