diff --git a/api/v1alpha1/basicauthenticator_types.go b/api/v1alpha1/basicauthenticator_types.go index b0b4555..1754eae 100644 --- a/api/v1alpha1/basicauthenticator_types.go +++ b/api/v1alpha1/basicauthenticator_types.go @@ -35,6 +35,10 @@ type BasicAuthenticatorSpec struct { // +kubebuilder:validation:Optional Selector metav1.LabelSelector `json:"selector,omitempty"` + // +kubebuilder:validation:Optional + // +kubebuilder:default=ClusterIP + ServiceType string `json:"serviceType"` + // +kubebuilder:validation:Required AppPort int `json:"appPort"` diff --git a/config/crd/bases/authenticator.snappcloud.io_basicauthenticators.yaml b/config/crd/bases/authenticator.snappcloud.io_basicauthenticators.yaml index 2acfaec..30d60ef 100644 --- a/config/crd/bases/authenticator.snappcloud.io_basicauthenticators.yaml +++ b/config/crd/bases/authenticator.snappcloud.io_basicauthenticators.yaml @@ -100,6 +100,9 @@ spec: type: object type: object x-kubernetes-map-type: atomic + serviceType: + default: ClusterIP + type: string type: description: Type is used to determine that nginx should be sidercar or deployment diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index c62a758..9bf77aa 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -67,3 +67,15 @@ rules: - patch - update - watch +- apiGroups: + - "" + resources: + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch diff --git a/internal/controller/basic_authenticator/basicauthenticator_controller.go b/internal/controller/basic_authenticator/basicauthenticator_controller.go index 1a0b04c..f2413f8 100644 --- a/internal/controller/basic_authenticator/basicauthenticator_controller.go +++ b/internal/controller/basic_authenticator/basicauthenticator_controller.go @@ -23,6 +23,7 @@ import ( "github.com/snapp-incubator/simple-authenticator/internal/config" appv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" @@ -41,6 +42,7 @@ type BasicAuthenticatorReconciler struct { configMapName string credentialName string basicAuthenticatorNamespace string + deploymentLabel *v1.LabelSelector logger logr.Logger } @@ -72,6 +74,7 @@ func (r *BasicAuthenticatorReconciler) SetupWithManager(mgr ctrl.Manager) error Owns(&appv1.Deployment{}). Owns(&corev1.ConfigMap{}). Owns(&corev1.Secret{}). + Owns(&corev1.Service{}). Watches( &source.Kind{Type: &appv1.Deployment{}}, handler.EnqueueRequestsFromMapFunc(r.findExternallyManagedDeployments), diff --git a/internal/controller/basic_authenticator/provision.go b/internal/controller/basic_authenticator/provision.go index 89349b0..b1829b0 100644 --- a/internal/controller/basic_authenticator/provision.go +++ b/internal/controller/basic_authenticator/provision.go @@ -22,6 +22,7 @@ func (r *BasicAuthenticatorReconciler) Provision(ctx context.Context, req ctrl.R r.ensureSecret, r.ensureConfigmap, r.ensureDeployment, + r.ensureService, } for _, provisioner := range subProvisioner { result, err := provisioner(ctx, req) @@ -177,7 +178,45 @@ func (r *BasicAuthenticatorReconciler) ensureDeployment(ctx context.Context, req return r.createDeploymentAuthenticator(ctx, req, basicAuthenticator, r.configMapName, r.credentialName) } } +func (r *BasicAuthenticatorReconciler) ensureService(ctx context.Context, req ctrl.Request) (*ctrl.Result, error) { + basicAuthenticator := &v1alpha1.BasicAuthenticator{} + + if r, err := r.getLatestBasicAuthenticator(ctx, req, basicAuthenticator); subreconciler.ShouldHaltOrRequeue(r, err) { + return r, err + } + if r.deploymentLabel == nil { + return subreconciler.ContinueReconciling() + } + newService := createNginxService(ctx, basicAuthenticator, r.deploymentLabel) + foundService := corev1.Service{} + err := r.Get(ctx, types.NamespacedName{Name: newService.Name, Namespace: newService.Namespace}, &foundService) + if errors.IsNotFound(err) { + if err := ctrl.SetControllerReference(basicAuthenticator, newService, r.Scheme); err != nil { + r.logger.Error(err, "failed to set service owner") + return subreconciler.RequeueWithError(err) + } + err := r.Create(ctx, newService) + if err != nil { + r.logger.Error(err, "failed to create new service") + return subreconciler.RequeueWithError(err) + } + } else if err != nil { + r.logger.Error(err, "failed to fetch service") + return subreconciler.RequeueWithError(err) + } else { + if !reflect.DeepEqual(newService.Spec, foundService.Spec) { + r.logger.Info("updating service") + foundService.Spec = newService.Spec + err := r.Update(ctx, &foundService) + if err != nil { + r.logger.Error(err, "failed to update service") + return subreconciler.RequeueWithError(err) + } + } + } + return subreconciler.ContinueReconciling() +} func (r *BasicAuthenticatorReconciler) createDeploymentAuthenticator(ctx context.Context, req ctrl.Request, basicAuthenticator *v1alpha1.BasicAuthenticator, authenticatorConfigName, secretName string) (*ctrl.Result, error) { newDeployment := createNginxDeployment(basicAuthenticator, authenticatorConfigName, secretName, r.CustomConfig) @@ -203,12 +242,10 @@ func (r *BasicAuthenticatorReconciler) createDeploymentAuthenticator(ctx context return subreconciler.RequeueWithError(err) } r.logger.Info("created deployment") - + r.deploymentLabel = newDeployment.Spec.Selector } else if err != nil { - if err != nil { - r.logger.Error(err, "failed to fetch deployment") - return subreconciler.RequeueWithError(err) - } + r.logger.Error(err, "failed to fetch deployment") + return subreconciler.RequeueWithError(err) } else { //update deployment targetReplica := newDeployment.Spec.Replicas diff --git a/internal/controller/basic_authenticator/nginx.go b/internal/controller/basic_authenticator/workload.go similarity index 87% rename from internal/controller/basic_authenticator/nginx.go rename to internal/controller/basic_authenticator/workload.go index 8436911..de7ed39 100644 --- a/internal/controller/basic_authenticator/nginx.go +++ b/internal/controller/basic_authenticator/workload.go @@ -13,6 +13,7 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/controller-runtime/pkg/client" "strings" ) @@ -90,7 +91,6 @@ func createNginxDeployment(basicAuthenticator *v1alpha1.BasicAuthenticator, conf }, }, } - return deploy } @@ -153,7 +153,29 @@ func createCredentials(basicAuthenticator *v1alpha1.BasicAuthenticator) (*corev1 } return secret, nil } - +func createNginxService(ctx context.Context, basicAuthenticator *v1alpha1.BasicAuthenticator, selector *metav1.LabelSelector) *corev1.Service { + serviceName := fmt.Sprintf("%s-svc", basicAuthenticator.Name) + serviceType := getServiceType(basicAuthenticator.Spec.ServiceType) + targetPort := intstr.IntOrString{Type: intstr.Int, IntVal: int32(basicAuthenticator.Spec.AuthenticatorPort)} + svc := corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceName, + Namespace: basicAuthenticator.Namespace, + }, + Spec: corev1.ServiceSpec{ + Selector: selector.MatchLabels, + Type: serviceType, + Ports: []corev1.ServicePort{ + { + Port: int32(basicAuthenticator.Spec.AuthenticatorPort), + TargetPort: targetPort, + Name: "authenticator", + }, + }, + }, + } + return &svc +} func injector(ctx context.Context, basicAuthenticator *v1alpha1.BasicAuthenticator, configMapName string, credentialName string, customConfig *config.CustomConfig, k8Client client.Client) ([]*appsv1.Deployment, error) { nginxImageAddress := getNginxContainerImage(customConfig) nginxContainerName := getNginxContainerName(customConfig) @@ -236,3 +258,14 @@ func fillTemplate(template string, secretPath string, authenticator *v1alpha1.Ba result = strings.Replace(result, "APP_PORT", fmt.Sprintf("%d", authenticator.Spec.AppPort), 1) return result } + +func getServiceType(serviceType string) corev1.ServiceType { + switch serviceType { + case "NodePort": + return corev1.ServiceTypeNodePort + case "LoadBalancer": + return corev1.ServiceTypeLoadBalancer + default: + return corev1.ServiceTypeClusterIP + } +} diff --git a/tests/e2e/deployment/00-install.yaml b/tests/e2e/deployment/00-install.yaml index 77771bd..566a3b3 100644 --- a/tests/e2e/deployment/00-install.yaml +++ b/tests/e2e/deployment/00-install.yaml @@ -14,4 +14,4 @@ spec: appPort: 8081 appService: google.com adaptiveScale: false - authenticatorPort: 8080 + authenticatorPort: 8082 diff --git a/tests/e2e/deployment/02-assert.yaml b/tests/e2e/deployment/02-assert.yaml new file mode 100644 index 0000000..b67f4ad --- /dev/null +++ b/tests/e2e/deployment/02-assert.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Service +metadata: + name: basicauthenticator-sample-svc