diff --git a/.gitignore b/.gitignore index a29049d7..a7757c89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -./scripts - # Binaries for programs and plugins *.exe *.exe~ @@ -28,4 +26,5 @@ __debug_bin* *.swo *~ .vscode/ +.scripts/ .DS_Store diff --git a/Makefile b/Makefile index 494a24a6..a0726480 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,13 @@ IMG ?= $(IMAGE_TAG_BASE):v$(VERSION) # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.25.0 +# Default Backstage config directory to use +# it has to be defined as a set of YAML files inside ./config/manager/${CONF_DIR} directory +# to use other config - add a directory with config and run 'CONF_DIR= make ...' +# TODO find better place than ./config/manager (but not ./config/overlays) ? +# TODO it works only for make run, needs supporting make deploy as well https://github.com/janus-idp/operator/issues/47 +CONF_DIR ?= default-config + # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) GOBIN=$(shell go env GOPATH)/bin @@ -111,8 +118,9 @@ vet: ## Run go vet against code. go vet ./... .PHONY: test -test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out +test: manifests generate fmt vet envtest ## Run tests. We need LOCALBIN=$(LOCALBIN) to get correct default-config path + mkdir -p $(LOCALBIN)/default-config && cp config/manager/${CONF_DIR}/* $(LOCALBIN)/default-config + LOCALBIN=$(LOCALBIN) KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out ##@ Build @@ -121,8 +129,8 @@ build: generate fmt vet ## Build manager binary. go build -o bin/manager main.go .PHONY: run -run: manifests generate fmt vet ## Run a controller from your host. - go run ./main.go +run: manifests generate fmt vet build ## Run a controller from your host. + cd $(LOCALBIN) && mkdir -p default-config && cp ../config/manager/${CONF_DIR}/* default-config && ./manager PLATFORM ?= linux/amd64 # If you wish built the manager image targeting other platforms you can use the --platform flag. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 9126a8bc..891bee7f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/bundle/manifests/backstage-operator.clusterserviceversion.yaml b/bundle/manifests/backstage-operator.clusterserviceversion.yaml index e670b1e0..d8d91cb4 100644 --- a/bundle/manifests/backstage-operator.clusterserviceversion.yaml +++ b/bundle/manifests/backstage-operator.clusterserviceversion.yaml @@ -124,7 +124,7 @@ spec: app.kubernetes.io/created-by: backstage-operator app.kubernetes.io/instance: controller-manager app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: deployment + app.kubernetes.io/name: deployment.yaml app.kubernetes.io/part-of: backstage-operator control-plane: controller-manager name: backstage-operator-controller-manager diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 3684a51a..4bdce607 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -1,12 +1,12 @@ # Adds namespace to all resources. -namespace: backstage-operator-system +namespace: backstage-system # Value of this field is prepended to the # names of all resources, e.g. a deployment named # "wordpress" becomes "alices-wordpress". # Note that it should also match with the prefix (text before '-') of the namespace # field above. -namePrefix: backstage-operator- +namePrefix: backstage- # Labels to add to all resources and selectors. #commonLabels: diff --git a/config/manager/default-config/backend-auth-secret.yaml b/config/manager/default-config/backend-auth-secret.yaml new file mode 100644 index 00000000..34e04f9a --- /dev/null +++ b/config/manager/default-config/backend-auth-secret.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Secret +metadata: + name: # placeholder for '-auth' +data: +# A random value will be generated for the backend-secret key diff --git a/config/manager/default-config/db-service-hl.yaml b/config/manager/default-config/db-service-hl.yaml new file mode 100644 index 00000000..444fe0ca --- /dev/null +++ b/config/manager/default-config/db-service-hl.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Service +metadata: + name: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' +spec: + selector: + backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + clusterIP: None + ports: + - port: 5432 \ No newline at end of file diff --git a/config/manager/default-config/db-service.yaml b/config/manager/default-config/db-service.yaml new file mode 100644 index 00000000..93e5c48a --- /dev/null +++ b/config/manager/default-config/db-service.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Service +metadata: + name: backstage-psql # placeholder for 'backstage-psql-' .NOTE: For the time it is static and linked to Secret-> postgres-secrets -> OSTGRES_HOST +spec: + selector: + backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + ports: + - port: 5432 diff --git a/config/manager/default-config/db-statefulset.yaml b/config/manager/default-config/db-statefulset.yaml new file mode 100644 index 00000000..5a208edf --- /dev/null +++ b/config/manager/default-config/db-statefulset.yaml @@ -0,0 +1,101 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: backstage-psql-cr1 # placeholder for 'backstage-psql-' +spec: + podManagementPolicy: OrderedReady + replicas: 1 + selector: + matchLabels: + backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + serviceName: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' + template: + metadata: + labels: + backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + name: backstage-db-cr1 # placeholder for 'backstage-psql-' + spec: + containers: + - env: + - name: POSTGRESQL_PORT_NUMBER + value: "5432" + - name: POSTGRESQL_VOLUME_DIR + value: /var/lib/pgsql/data + - name: PGDATA + value: /var/lib/pgsql/data/userdata + envFrom: + - secretRef: + name: postgres-secrets + image: quay.io/fedora/postgresql-15:latest + imagePullPolicy: IfNotPresent + securityContext: + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + livenessProbe: + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: postgresql + ports: + - containerPort: 5432 + name: tcp-postgresql + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + - | + exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + memory: 1024Mi + volumeMounts: + - mountPath: /dev/shm + name: dshm + - mountPath: /var/lib/pgsql/data + name: data + restartPolicy: Always + securityContext: {} + serviceAccount: default + serviceAccountName: default + volumes: + - emptyDir: + medium: Memory + name: dshm + updateStrategy: + rollingUpdate: + partition: 0 + type: RollingUpdate + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi \ No newline at end of file diff --git a/config/manager/default-config/deployment.yaml b/config/manager/default-config/deployment.yaml new file mode 100644 index 00000000..d2af0b50 --- /dev/null +++ b/config/manager/default-config/deployment.yaml @@ -0,0 +1,91 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backstage +spec: + replicas: 1 + selector: + matchLabels: + backstage.io/app: # placeholder for 'backstage-' + template: + metadata: + labels: + backstage.io/app: # placeholder for 'backstage-' + spec: + # serviceAccountName: default + volumes: + - ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + name: dynamic-plugins-root + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: dynamic-plugins-npmrc + + initContainers: + - command: + - ./install-dynamic-plugins.sh + - /dynamic-plugins-root + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + image: 'quay.io/janus-idp/backstage-showcase:next' + imagePullPolicy: IfNotPresent + name: install-dynamic-plugins + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + workingDir: /opt/app-root/src + + containers: + - name: backstage-backend + image: quay.io/janus-idp/backstage-showcase:next + imagePullPolicy: IfNotPresent + args: + - "--config" + - "dynamic-plugins-root/app-config.dynamic-plugins.yaml" + readinessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 7007 + scheme: HTTP + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 2 + timeoutSeconds: 2 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthcheck + port: 7007 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 2 + ports: + - name: http + containerPort: 7007 + env: + - name: APP_CONFIG_backend_listen_port + value: "7007" + envFrom: + - secretRef: + name: postgres-secrets + # - secretRef: + # name: backstage-secrets + volumeMounts: + - mountPath: /opt/app-root/src/dynamic-plugins-root + name: dynamic-plugins-root \ No newline at end of file diff --git a/config/manager/default-config/dynamic-plugins-configmap.yaml b/config/manager/default-config/dynamic-plugins-configmap.yaml new file mode 100644 index 00000000..492543c6 --- /dev/null +++ b/config/manager/default-config/dynamic-plugins-configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: # placeholder for '-dynamic-plugins' +data: + "dynamic-plugins.yaml": | + includes: + - dynamic-plugins.default.yaml + plugins: [] \ No newline at end of file diff --git a/config/manager/default-config/service.yaml b/config/manager/default-config/service.yaml new file mode 100644 index 00000000..e2c04838 --- /dev/null +++ b/config/manager/default-config/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: backstage +spec: + type: NodePort + selector: + backstage.io/app: # placeholder for 'backstage-' + ports: + - name: http + port: 80 + targetPort: http \ No newline at end of file diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 3542d6ae..a6046f3d 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -5,4 +5,17 @@ kind: Kustomization images: - name: controller newName: quay.io/rhdh/backstage-operator - newTag: v0.0.1 + +generatorOptions: + disableNameSuffixHash: true + +configMapGenerator: +- files: + - default-config/deployment.yaml + - default-config/service.yaml + - default-config/db-statefulset.yaml + - default-config/db-service.yaml + - default-config/db-service-hl.yaml + - default-config/backend-auth-secret.yaml + - default-config/dynamic-plugins-configmap.yaml + name: default-config diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 541a1601..fcedb7bb 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -98,5 +98,13 @@ spec: requests: cpu: 10m memory: 64Mi + volumeMounts: + - mountPath: /default-config + name: default-config serviceAccountName: controller-manager terminationGracePeriodSeconds: 10 + volumes: + - name: default-config + configMap: + name: default-config + diff --git a/controllers/backstage_backend_auth.go b/controllers/backstage_backend_auth.go index 1fef7cf5..73a7afee 100644 --- a/controllers/backstage_backend_auth.go +++ b/controllers/backstage_backend_auth.go @@ -29,15 +29,15 @@ import ( ) var ( - _defaultBackendAuthSecretValue = "pl4s3Ch4ng3M3" - defaultBackstageBackendAuthSecret = ` -apiVersion: v1 -kind: Secret -metadata: - name: # placeholder for '-auth' -data: - # A random value will be generated for the backend-secret key -` + _defaultBackendAuthSecretValue = "pl4s3Ch4ng3M3" + // defaultBackstageBackendAuthSecret = ` + //apiVersion: v1 + //kind: Secret + //metadata: + // name: # placeholder for '-auth' + //data: + // # A random value will be generated for the backend-secret key + //` ) func (r *BackstageReconciler) handleBackendAuthSecret(ctx context.Context, backstage bs.Backstage, ns string) (secretName string, err error) { @@ -47,8 +47,8 @@ func (r *BackstageReconciler) handleBackendAuthSecret(ctx context.Context, backs //Create default Secret for backend auth var sec v1.Secret - var isDefault bool - isDefault, err = r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "backend-auth-secret", ns, defaultBackstageBackendAuthSecret, &sec) + //var isDefault bool + err = r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "backend-auth-secret.yaml", ns, &sec) if err != nil { return "", fmt.Errorf("failed to read config: %s", err) } @@ -68,20 +68,22 @@ func (r *BackstageReconciler) handleBackendAuthSecret(ctx context.Context, backs //TODO(rm3l): why kubebuilder default values do not work k = "backend-secret" } - if isDefault { - // Create a secret with a random value - authVal := func(length int) string { - bytes := make([]byte, length) - if _, randErr := rand.Read(bytes); randErr != nil { - // Do not fail, but use a fallback value - return _defaultBackendAuthSecretValue - } - return base64.StdEncoding.EncodeToString(bytes) - }(24) - sec.Data = map[string][]byte{ - k: []byte(authVal), + + // there should not be any difference between default and not default + // if isDefault { + // Create a secret with a random value + authVal := func(length int) string { + bytes := make([]byte, length) + if _, randErr := rand.Read(bytes); randErr != nil { + // Do not fail, but use a fallback value + return _defaultBackendAuthSecretValue } + return base64.StdEncoding.EncodeToString(bytes) + }(24) + sec.Data = map[string][]byte{ + k: []byte(authVal), } + // } err = r.Create(ctx, &sec) if err != nil { return "", fmt.Errorf("failed to create secret for backend auth, reason: %s", err) diff --git a/controllers/backstage_controller.go b/controllers/backstage_controller.go index 131bbe43..7714d884 100644 --- a/controllers/backstage_controller.go +++ b/controllers/backstage_controller.go @@ -18,6 +18,8 @@ import ( "bytes" "context" "fmt" + "os" + "path/filepath" bs "backstage.io/backstage-operator/api/v1alpha1" appsv1 "k8s.io/api/apps/v1" @@ -42,7 +44,7 @@ type BackstageReconciler struct { client.Client Scheme *runtime.Scheme // If true, Backstage Controller always sync the state of runtime objects created - // otherwise, the can be re-configured independently + // otherwise, runtime objects can be re-configured independently OwnsRuntime bool // Namespace allows to restrict the reconciliation to this particular namespace, @@ -99,27 +101,23 @@ func (r *BackstageReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( err := r.applyLocalDbStatefulSet(ctx, backstage, req.Namespace) if err != nil { - //backstage.Status.PostgreState = err.Error() - return ctrl.Result{}, err + return ctrl.Result{}, fmt.Errorf("failed to apply Database Deployment: %w", err) } err = r.applyLocalDbServices(ctx, backstage, req.Namespace) if err != nil { - //backstage.Status.PostgreState = err.Error() - return ctrl.Result{}, err + return ctrl.Result{}, fmt.Errorf("failed to apply Database Service: %w", err) } } err := r.applyBackstageDeployment(ctx, backstage, req.Namespace) if err != nil { - return ctrl.Result{}, err + return ctrl.Result{}, fmt.Errorf("failed to apply Backstage Deployment: %w", err) } if err := r.applyBackstageService(ctx, backstage, req.Namespace); err != nil { - // TODO BackstageDepState state - //backstage.Status.BackstageState = err.Error() - return ctrl.Result{}, err + return ctrl.Result{}, fmt.Errorf("failed to apply Backstage Service: %w", err) } //TODO: it is just a placeholder for the time @@ -127,61 +125,74 @@ func (r *BackstageReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( r.setSyncStatus(&backstage) err = r.Status().Update(ctx, &backstage) if err != nil { - return ctrl.Result{}, err + return ctrl.Result{}, fmt.Errorf("failed to set status: %w", err) //log.FromContext(ctx).Error(err, "unable to update backstage.status") } return ctrl.Result{}, nil } -func (r *BackstageReconciler) readConfigMapOrDefault(ctx context.Context, name string, key string, ns string, def string, object v1.Object) (isDefault bool, err error) { +func (r *BackstageReconciler) readConfigMapOrDefault(ctx context.Context, name string, key string, ns string, object v1.Object) error { - // ConfigMap name not set, default - //lg := log.FromContext(ctx) - - //lg.V(1).Info("readConfigMapOrDefault CM: ", "name", name) + lg := log.FromContext(ctx) if name == "" { - err = readYaml(def, object) + err := readYamlFile(defFile(key), object) if err != nil { - return true, err + return fmt.Errorf("failed to read YAML file: %w", err) } object.SetNamespace(ns) - return true, nil + return nil } cm := corev1.ConfigMap{} - if err = r.Get(ctx, types.NamespacedName{Name: name, Namespace: ns}, &cm); err != nil { - return false, err + if err := r.Get(ctx, types.NamespacedName{Name: name, Namespace: ns}, &cm); err != nil { + return err } - //lg.V(1).Info("readConfigMapOrDefault CM name found: ", "ConfigMap:", cm) + val, ok := cm.Data[key] if !ok { // key not found, default - err = readYaml(def, object) + lg.V(1).Info("custom configuration configMap and data exists, trying to apply it", "configMap", cm.Name, "key", key) + err := readYamlFile(defFile(key), object) if err != nil { - return true, err + return fmt.Errorf("failed to read YAML file: %w", err) } } else { - err = readYaml(val, object) + lg.V(1).Info("custom configuration configMap exists but no such key, applying default config", "configMap", cm.Name, "key", key) + err := readYaml([]byte(val), object) if err != nil { - return false, err + return fmt.Errorf("failed to read YAML: %w", err) } } object.SetNamespace(ns) - return !ok, nil + return nil } -func readYaml(manifest string, object interface{}) error { - dec := yaml.NewYAMLOrJSONDecoder(bytes.NewReader([]byte(manifest)), 1000) +func readYaml(manifest []byte, object interface{}) error { + dec := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(manifest), 1000) if err := dec.Decode(object); err != nil { - return err + return fmt.Errorf("failed to decode YAML: %w", err) } return nil } +func readYamlFile(path string, object interface{}) error { + + b, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read YAML file: %w", err) + } + return readYaml(b, object) +} + +func defFile(key string) string { + return filepath.Join(os.Getenv("LOCALBIN"), "default-config", key) +} + // sets the RuntimeRunning condition func (r *BackstageReconciler) setRunningStatus(ctx context.Context, backstage *bs.Backstage, ns string) { + meta.SetStatusCondition(&backstage.Status.Conditions, v1.Condition{ Type: bs.RuntimeConditionRunning, Status: "Unknown", diff --git a/controllers/backstage_controller_test.go b/controllers/backstage_controller_test.go index 3cb12734..6f2051bf 100644 --- a/controllers/backstage_controller_test.go +++ b/controllers/backstage_controller_test.go @@ -285,7 +285,7 @@ var _ = Describe("Backstage controller", func() { BeforeEach(func() { backstageConfigMap := buildConfigMap("my-bs-config", map[string]string{ - "deploy": ` + "deployment.yaml": ` apiVersion: apps/v1 kind: Deployment metadata: @@ -349,7 +349,7 @@ spec: BeforeEach(func() { localDbConfigMap := buildConfigMap("my-db-config", map[string]string{ - "statefulset": ` + "db-statefulset.yaml": ` apiVersion: apps/v1 kind: StatefulSet metadata: diff --git a/controllers/backstage_deployment.go b/controllers/backstage_deployment.go index 869a5a57..f9bd6df0 100644 --- a/controllers/backstage_deployment.go +++ b/controllers/backstage_deployment.go @@ -31,109 +31,109 @@ const ( _containersWorkingDir = "/opt/app-root/src" ) -var ( - DefaultBackstageDeployment = fmt.Sprintf(` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: backstage -spec: - replicas: 1 - selector: - matchLabels: - backstage.io/app: # placeholder for 'backstage-' - template: - metadata: - labels: - backstage.io/app: # placeholder for 'backstage-' - spec: -# serviceAccountName: default - - volumes: - - ephemeral: - volumeClaimTemplate: - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - name: dynamic-plugins-root - - name: dynamic-plugins-npmrc - secret: - defaultMode: 420 - optional: true - secretName: dynamic-plugins-npmrc - - initContainers: - - command: - - ./install-dynamic-plugins.sh - - /dynamic-plugins-root - env: - - name: NPM_CONFIG_USERCONFIG - value: %[3]s/.npmrc.dynamic-plugins - image: 'quay.io/janus-idp/backstage-showcase:next' - imagePullPolicy: IfNotPresent - name: %[1]s - volumeMounts: - - mountPath: /dynamic-plugins-root - name: dynamic-plugins-root - - mountPath: %[3]s/.npmrc.dynamic-plugins - name: dynamic-plugins-npmrc - readOnly: true - subPath: .npmrc - workingDir: %[3]s - - containers: - - name: %[2]s - image: quay.io/janus-idp/backstage-showcase:next - imagePullPolicy: IfNotPresent - args: - - "--config" - - "dynamic-plugins-root/app-config.dynamic-plugins.yaml" - readinessProbe: - failureThreshold: 3 - httpGet: - path: /healthcheck - port: 7007 - scheme: HTTP - initialDelaySeconds: 30 - periodSeconds: 10 - successThreshold: 2 - timeoutSeconds: 2 - livenessProbe: - failureThreshold: 3 - httpGet: - path: /healthcheck - port: 7007 - scheme: HTTP - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 2 - ports: - - name: http - containerPort: 7007 - env: - - name: APP_CONFIG_backend_listen_port - value: "7007" - envFrom: - - secretRef: - name: postgres-secrets -# - secretRef: -# name: backstage-secrets - volumeMounts: - - mountPath: %[3]s/dynamic-plugins-root - name: dynamic-plugins-root -`, _defaultBackstageInitContainerName, _defaultBackstageMainContainerName, _containersWorkingDir) -) +//var ( +// DefaultBackstageDeployment = fmt.Sprintf(` +//apiVersion: apps/v1 +//kind: Deployment +//metadata: +// name: backstage +//spec: +// replicas: 1 +// selector: +// matchLabels: +// backstage.io/app: # placeholder for 'backstage-' +// template: +// metadata: +// labels: +// backstage.io/app: # placeholder for 'backstage-' +// spec: +//# serviceAccountName: default +// +// volumes: +// - ephemeral: +// volumeClaimTemplate: +// spec: +// accessModes: +// - ReadWriteOnce +// resources: +// requests: +// storage: 1Gi +// name: dynamic-plugins-root +// - name: dynamic-plugins-npmrc +// secret: +// defaultMode: 420 +// optional: true +// secretName: dynamic-plugins-npmrc +// +// initContainers: +// - command: +// - ./install-dynamic-plugins.sh +// - /dynamic-plugins-root +// env: +// - name: NPM_CONFIG_USERCONFIG +// value: %[3]s/.npmrc.dynamic-plugins +// image: 'quay.io/janus-idp/backstage-showcase:next' +// imagePullPolicy: IfNotPresent +// name: %[1]s +// volumeMounts: +// - mountPath: /dynamic-plugins-root +// name: dynamic-plugins-root +// - mountPath: %[3]s/.npmrc.dynamic-plugins +// name: dynamic-plugins-npmrc +// readOnly: true +// subPath: .npmrc +// workingDir: %[3]s +// +// containers: +// - name: %[2]s +// image: quay.io/janus-idp/backstage-showcase:next +// imagePullPolicy: IfNotPresent +// args: +// - "--config" +// - "dynamic-plugins-root/app-config.dynamic-plugins.yaml" +// readinessProbe: +// failureThreshold: 3 +// httpGet: +// path: /healthcheck +// port: 7007 +// scheme: HTTP +// initialDelaySeconds: 30 +// periodSeconds: 10 +// successThreshold: 2 +// timeoutSeconds: 2 +// livenessProbe: +// failureThreshold: 3 +// httpGet: +// path: /healthcheck +// port: 7007 +// scheme: HTTP +// initialDelaySeconds: 60 +// periodSeconds: 10 +// successThreshold: 1 +// timeoutSeconds: 2 +// ports: +// - name: http +// containerPort: 7007 +// env: +// - name: APP_CONFIG_backend_listen_port +// value: "7007" +// envFrom: +// - secretRef: +// name: postgres-secrets +//# - secretRef: +//# name: backstage-secrets +// volumeMounts: +// - mountPath: %[3]s/dynamic-plugins-root +// name: dynamic-plugins-root +//`, _defaultBackstageInitContainerName, _defaultBackstageMainContainerName, _containersWorkingDir) +//) func (r *BackstageReconciler) applyBackstageDeployment(ctx context.Context, backstage bs.Backstage, ns string) error { //lg := log.FromContext(ctx) deployment := &appsv1.Deployment{} - _, err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "deploy", ns, DefaultBackstageDeployment, deployment) + err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "deployment.yaml", ns, deployment) if err != nil { return fmt.Errorf("failed to read config: %s", err) } @@ -179,7 +179,7 @@ func (r *BackstageReconciler) applyBackstageDeployment(ctx context.Context, back } } else { - return fmt.Errorf("failed to get backstage deployment, reason: %s", err) + return fmt.Errorf("failed to get backstage deployment.yaml, reason: %s", err) } } else { //lg.Info("CR update is ignored for the time") diff --git a/controllers/backstage_dynamic_plugins.go b/controllers/backstage_dynamic_plugins.go index 3a90c782..a37d8155 100644 --- a/controllers/backstage_dynamic_plugins.go +++ b/controllers/backstage_dynamic_plugins.go @@ -26,19 +26,19 @@ import ( "k8s.io/utils/pointer" ) -var ( - defaultDynamicPluginsConfigMap = ` -apiVersion: v1 -kind: ConfigMap -metadata: - name: # placeholder for '-dynamic-plugins' -data: - "dynamic-plugins.yaml": | - includes: - - dynamic-plugins.default.yaml - plugins: [] -` -) +//var ( +// defaultDynamicPluginsConfigMap = ` +//apiVersion: v1 +//kind: ConfigMap +//metadata: +// name: # placeholder for '-dynamic-plugins' +//data: +// "dynamic-plugins.yaml": | +// includes: +// - dynamic-plugins.default.yaml +// plugins: [] +//` +//) func (r *BackstageReconciler) getOrGenerateDynamicPluginsConf(ctx context.Context, backstage bs.Backstage, ns string) (config bs.DynamicPluginsConfigRef, err error) { if backstage.Spec.DynamicPluginsConfig != nil { @@ -47,7 +47,7 @@ func (r *BackstageReconciler) getOrGenerateDynamicPluginsConf(ctx context.Contex //Create default ConfigMap for dynamic plugins var cm v1.ConfigMap - _, err = r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "dynamic-plugins-configmap", ns, defaultDynamicPluginsConfigMap, &cm) + err = r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "dynamic-plugins-configmap.yaml", ns, &cm) if err != nil { return bs.DynamicPluginsConfigRef{}, fmt.Errorf("failed to read config: %s", err) } diff --git a/controllers/backstage_service.go b/controllers/backstage_service.go index cd552861..c019fc4f 100644 --- a/controllers/backstage_service.go +++ b/controllers/backstage_service.go @@ -26,23 +26,6 @@ import ( "k8s.io/apimachinery/pkg/types" ) -var ( - DefaultBackstageService = ` -apiVersion: v1 -kind: Service -metadata: - name: backstage -spec: - type: NodePort - selector: - backstage.io/app: # placeholder for 'backstage-' - ports: - - name: http - port: 80 - targetPort: http -` -) - // selector for deploy.spec.template.spec.meta.label // targetPort: http for deploy.spec.template.spec.containers.ports.name=http func (r *BackstageReconciler) applyBackstageService(ctx context.Context, backstage bs.Backstage, ns string) error { @@ -50,7 +33,7 @@ func (r *BackstageReconciler) applyBackstageService(ctx context.Context, backsta //lg := log.FromContext(ctx) service := &corev1.Service{} - _, err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "service", ns, DefaultBackstageService, service) + err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "service.yaml", ns, service) if err != nil { return err } diff --git a/controllers/local_db_statefulset.go b/controllers/local_db_statefulset.go index a1bb8fe0..b1d900d2 100644 --- a/controllers/local_db_statefulset.go +++ b/controllers/local_db_statefulset.go @@ -27,138 +27,138 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log" ) -var ( - DefaultLocalDbDeployment = `apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: backstage-psql-cr1 # placeholder for 'backstage-psql-' -spec: - podManagementPolicy: OrderedReady - replicas: 1 - selector: - matchLabels: - backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' - serviceName: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' - template: - metadata: - labels: - backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' - name: backstage-db-cr1 # placeholder for 'backstage-psql-' - spec: - containers: - - env: - - name: POSTGRESQL_PORT_NUMBER - value: "5432" - - name: POSTGRESQL_VOLUME_DIR - value: /var/lib/pgsql/data - - name: PGDATA - value: /var/lib/pgsql/data/userdata - envFrom: - - secretRef: - name: postgres-secrets - image: quay.io/fedora/postgresql-15:latest - imagePullPolicy: IfNotPresent - securityContext: - runAsNonRoot: true - allowPrivilegeEscalation: false - seccompProfile: - type: RuntimeDefault - capabilities: - drop: - - ALL - livenessProbe: - exec: - command: - - /bin/sh - - -c - - exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 - failureThreshold: 6 - initialDelaySeconds: 30 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - name: postgresql - ports: - - containerPort: 5432 - name: tcp-postgresql - protocol: TCP - readinessProbe: - exec: - command: - - /bin/sh - - -c - - -e - - | - exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 - failureThreshold: 6 - initialDelaySeconds: 5 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: - requests: - cpu: 250m - memory: 256Mi - limits: - memory: 1024Mi - volumeMounts: - - mountPath: /dev/shm - name: dshm - - mountPath: /var/lib/pgsql/data - name: data - restartPolicy: Always - securityContext: {} - serviceAccount: default - serviceAccountName: default - volumes: - - emptyDir: - medium: Memory - name: dshm - updateStrategy: - rollingUpdate: - partition: 0 - type: RollingUpdate - volumeClaimTemplates: - - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: data - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi -` - DefaultLocalDbService = `apiVersion: v1 -kind: Service -metadata: - name: backstage-psql-cr1 # placeholder for 'backstage-psql-' -spec: - selector: - backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' - ports: - - port: 5432 -` - DefaultLocalDbServiceHL = `apiVersion: v1 -kind: Service -metadata: - name: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' -spec: - selector: - backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' - clusterIP: None - ports: - - port: 5432 -` -) +//var ( +// DefaultLocalDbDeployment = `apiVersion: apps/v1 +//kind: StatefulSet +//metadata: +// name: backstage-psql-cr1 # placeholder for 'backstage-psql-' +//spec: +// podManagementPolicy: OrderedReady +// replicas: 1 +// selector: +// matchLabels: +// backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' +// serviceName: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' +// template: +// metadata: +// labels: +// backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' +// name: backstage-db-cr1 # placeholder for 'backstage-psql-' +// spec: +// containers: +// - env: +// - name: POSTGRESQL_PORT_NUMBER +// value: "5432" +// - name: POSTGRESQL_VOLUME_DIR +// value: /var/lib/pgsql/data +// - name: PGDATA +// value: /var/lib/pgsql/data/userdata +// envFrom: +// - secretRef: +// name: postgres-secrets +// image: quay.io/fedora/postgresql-15:latest +// imagePullPolicy: IfNotPresent +// securityContext: +// runAsNonRoot: true +// allowPrivilegeEscalation: false +// seccompProfile: +// type: RuntimeDefault +// capabilities: +// drop: +// - ALL +// livenessProbe: +// exec: +// command: +// - /bin/sh +// - -c +// - exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 +// failureThreshold: 6 +// initialDelaySeconds: 30 +// periodSeconds: 10 +// successThreshold: 1 +// timeoutSeconds: 5 +// name: postgresql +// ports: +// - containerPort: 5432 +// name: tcp-postgresql +// protocol: TCP +// readinessProbe: +// exec: +// command: +// - /bin/sh +// - -c +// - -e +// - | +// exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 +// failureThreshold: 6 +// initialDelaySeconds: 5 +// periodSeconds: 10 +// successThreshold: 1 +// timeoutSeconds: 5 +// resources: +// requests: +// cpu: 250m +// memory: 256Mi +// limits: +// memory: 1024Mi +// volumeMounts: +// - mountPath: /dev/shm +// name: dshm +// - mountPath: /var/lib/pgsql/data +// name: data +// restartPolicy: Always +// securityContext: {} +// serviceAccount: default +// serviceAccountName: default +// volumes: +// - emptyDir: +// medium: Memory +// name: dshm +// updateStrategy: +// rollingUpdate: +// partition: 0 +// type: RollingUpdate +// volumeClaimTemplates: +// - apiVersion: v1 +// kind: PersistentVolumeClaim +// metadata: +// name: data +// spec: +// accessModes: +// - ReadWriteOnce +// resources: +// requests: +// storage: 1Gi +//` +// DefaultLocalDbService = `apiVersion: v1 +//kind: Service +//metadata: +// name: backstage-psql-cr1 # placeholder for 'backstage-psql-' +//spec: +// selector: +// backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' +// ports: +// - port: 5432 +//` +// DefaultLocalDbServiceHL = `apiVersion: v1 +//kind: Service +//metadata: +// name: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' +//spec: +// selector: +// backstage.io/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' +// clusterIP: None +// ports: +// - port: 5432 +//` +//) func (r *BackstageReconciler) applyLocalDbStatefulSet(ctx context.Context, backstage bs.Backstage, ns string) error { lg := log.FromContext(ctx) statefulSet := &appsv1.StatefulSet{} - _, err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.LocalDbConfigName, "statefulset", ns, DefaultLocalDbDeployment, statefulSet) + err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.LocalDbConfigName, "db-statefulset.yaml", ns, statefulSet) if err != nil { return err } @@ -190,22 +190,23 @@ func (r *BackstageReconciler) applyLocalDbStatefulSet(ctx context.Context, backs } func (r *BackstageReconciler) applyLocalDbServices(ctx context.Context, backstage bs.Backstage, ns string) error { - name := fmt.Sprintf("backstage-psql-%s", backstage.Name) - err := r.applyPsqlService(ctx, backstage, name, name, DefaultLocalDbService, ns) + // TODO static for the time and bound to Secret: postgres-secret + label := fmt.Sprintf("backstage-psql-%s", backstage.Name) + err := r.applyPsqlService(ctx, backstage, "backstage-psql", label, ns, "db-service.yaml") if err != nil { return err } nameHL := fmt.Sprintf("backstage-psql-%s-hl", backstage.Name) - return r.applyPsqlService(ctx, backstage, nameHL, name, DefaultLocalDbServiceHL, ns) + return r.applyPsqlService(ctx, backstage, nameHL, label, ns, "db-service-hl.yaml") } -func (r *BackstageReconciler) applyPsqlService(ctx context.Context, backstage bs.Backstage, name, label, defaultData, ns string) error { +func (r *BackstageReconciler) applyPsqlService(ctx context.Context, backstage bs.Backstage, name, label, ns string, key string) error { lg := log.FromContext(ctx) service := &corev1.Service{} - _, err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.LocalDbConfigName, "service", ns, defaultData, service) + err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.LocalDbConfigName, key, ns, service) if err != nil { return err } diff --git a/controllers/local_db_storage.go b/controllers/local_db_storage.go index beae53e9..6c9d45a6 100644 --- a/controllers/local_db_storage.go +++ b/controllers/local_db_storage.go @@ -26,32 +26,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) -var ( - DefaultLocalDbPV = ` -apiVersion: v1 -kind: PersistentVolume -metadata: - name: postgres-storage - namespace: backstage - labels: - type: local -spec: - capacity: - storage: 2Gi - accessModes: - - ReadWriteOnce - persistentVolumeReclaimPolicy: Retain - hostPath: - path: '/mnt/data' -` -) - func (r *BackstageReconciler) applyPV(ctx context.Context, backstage bs.Backstage, ns string) error { // Postgre PersistentVolume //lg := log.FromContext(ctx) pv := &corev1.PersistentVolume{} - err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.LocalDbConfigName, "persistentVolume", ns, DefaultLocalDbPV, pv) + err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.LocalDbConfigName, "db-pv.yaml", ns, pv) if err != nil { return err } diff --git a/docker/Dockerfile b/docker/Dockerfile index 7428e66e..0b58d584 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -62,8 +62,8 @@ ENV EXTERNAL_SOURCE=. # ENV EXTERNAL_SOURCE=$REMOTE_SOURCES/upstream1/app/distgit/containers/rhdh-operator #/ Downstream uncomment -ENV HOME=/opt/helm \ - USER_NAME=helm \ +ENV HOME=/ \ + USER_NAME=backstage \ USER_UID=1001 RUN echo "${USER_NAME}:x:${USER_UID}:0:${USER_NAME} user:${HOME}:/sbin/nologin" >> /etc/passwd diff --git a/examples/postgres-secret.yaml b/examples/postgres-secret.yaml index d256eb1f..5ba67ed9 100644 --- a/examples/postgres-secret.yaml +++ b/examples/postgres-secret.yaml @@ -8,4 +8,5 @@ stringData: POSTGRES_PASSWORD: admin123 POSTGRES_PORT: "5432" POSTGRES_USER: postgres - POSTGRESQL_ADMIN_PASSWORD: admin123 \ No newline at end of file + POSTGRESQL_ADMIN_PASSWORD: admin123 + POSTGRES_HOST: backstage-psql \ No newline at end of file diff --git a/main.go b/main.go index fd9ad25f..1adb2c75 100644 --- a/main.go +++ b/main.go @@ -115,7 +115,7 @@ func main() { os.Exit(1) } - setupLog.Info("starting manager") + setupLog.Info("starting manager with parameters: ", "own-runtime", ownRuntime, "env.LOCALBIN", os.Getenv("LOCALBIN")) if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { setupLog.Error(err, "problem running manager") os.Exit(1)