Skip to content
This repository has been archived by the owner on Aug 19, 2024. It is now read-only.

Commit

Permalink
Implement routing configuration for Backstage server endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
jianrongzhang89 committed Dec 7, 2023
1 parent 29470eb commit b0d0381
Show file tree
Hide file tree
Showing 16 changed files with 203 additions and 40 deletions.
29 changes: 22 additions & 7 deletions bundle/manifests/backstage-default-config_v1_configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ data:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backstage
name: # placeholder for 'backstage-<cr-name>'
spec:
replicas: 1
selector:
Expand Down Expand Up @@ -212,7 +212,7 @@ data:
successThreshold: 1
timeoutSeconds: 2
ports:
- name: http
- name: backend
containerPort: 7007
env:
- name: APP_CONFIG_backend_listen_port
Expand All @@ -235,19 +235,34 @@ data:
includes:
- dynamic-plugins.default.yaml
plugins: []
route.yaml: |-
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: # placeholder for 'backstage-<cr-name>'
spec:
port:
targetPort: http-backend
path: /
tls:
insecureEdgeTerminationPolicy: Redirect
termination: edge
to:
kind: Service
name: # placeholder for 'backstage-<cr-name>'
service.yaml: |-
apiVersion: v1
kind: Service
metadata:
name: backstage
name: # placeholder for 'backstage-<cr-name>'
spec:
type: NodePort
type: ClusterIP
selector:
janus-idp.io/app: # placeholder for 'backstage-<cr-name>'
ports:
- name: http
port: 80
targetPort: http
- name: http-backend
port: 7007
targetPort: backend
kind: ConfigMap
metadata:
name: backstage-default-config
11 changes: 11 additions & 0 deletions bundle/manifests/backstage-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,17 @@ spec:
- get
- patch
- update
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- create
- delete
- get
- list
- update
- watch
- apiGroups:
- authentication.k8s.io
resources:
Expand Down
4 changes: 2 additions & 2 deletions config/manager/default-config/deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: backstage
name: # placeholder for 'backstage-<cr-name>'
spec:
replicas: 1
selector:
Expand Down Expand Up @@ -76,7 +76,7 @@ spec:
successThreshold: 1
timeoutSeconds: 2
ports:
- name: http
- name: backend
containerPort: 7007
env:
- name: APP_CONFIG_backend_listen_port
Expand Down
14 changes: 14 additions & 0 deletions config/manager/default-config/route.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: # placeholder for 'backstage-<cr-name>'
spec:
port:
targetPort: http-backend
path: /
tls:
insecureEdgeTerminationPolicy: Redirect
termination: edge
to:
kind: Service
name: # placeholder for 'backstage-<cr-name>'
10 changes: 5 additions & 5 deletions config/manager/default-config/service.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: backstage
name: # placeholder for 'backstage-<cr-name>'
spec:
type: NodePort
type: ClusterIP
selector:
janus-idp.io/app: # placeholder for 'backstage-<cr-name>'
ports:
- name: http
port: 80
targetPort: http
- name: http-backend
port: 7007
targetPort: backend
1 change: 1 addition & 0 deletions config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ configMapGenerator:
- files:
- default-config/deployment.yaml
- default-config/service.yaml
- default-config/route.yaml
- default-config/db-statefulset.yaml
- default-config/db-service.yaml
- default-config/db-service-hl.yaml
Expand Down
11 changes: 11 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,14 @@ rules:
- get
- patch
- update
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- create
- delete
- get
- list
- update
- watch
24 changes: 14 additions & 10 deletions controllers/backstage_backend_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,11 @@ import (
"k8s.io/utils/pointer"
)

var (
const (
_defaultBackendAuthSecretValue = "pl4s3Ch4ng3M3"
// defaultBackstageBackendAuthSecret = `
//apiVersion: v1
//kind: Secret
//metadata:
// name: # placeholder for '<cr-name>-auth'
//data:
// # A random value will be generated for the backend-secret key
//`
envPostGresHost = "POSTGRES_HOST"
envBackendSecret = "BACKEND_SECRET"
env = "APP_CONFIG_backend_auth_keys"
)

func (r *BackstageReconciler) handleBackendAuthSecret(ctx context.Context, backstage bs.Backstage, ns string) (secretName string, err error) {
Expand Down Expand Up @@ -112,9 +107,10 @@ func (r *BackstageReconciler) addBackendAuthEnvVar(ctx context.Context, backstag
//TODO(rm3l): why kubebuilder default values do not work
k = "backend-secret"
}

deployment.Spec.Template.Spec.Containers[i].Env = append(deployment.Spec.Template.Spec.Containers[i].Env,
v1.EnvVar{
Name: "BACKEND_SECRET",
Name: envBackendSecret,
ValueFrom: &v1.EnvVarSource{
SecretKeyRef: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Expand All @@ -129,6 +125,14 @@ func (r *BackstageReconciler) addBackendAuthEnvVar(ctx context.Context, backstag
Name: "APP_CONFIG_backend_auth_keys",
Value: `[{"secret": "$(BACKEND_SECRET)"}]`,
})
// If a local PostGres DB is used, set POSTGRES_HOST env variable to the local PostGres DB service.
if !backstage.Spec.SkipLocalDb {
deployment.Spec.Template.Spec.Containers[i].Env = append(deployment.Spec.Template.Spec.Containers[i].Env,
v1.EnvVar{
Name: envPostGresHost,
Value: fmt.Sprintf("backstage-psql-%s", backstage.Name),
})
}
break
}
}
Expand Down
9 changes: 9 additions & 0 deletions controllers/backstage_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type BackstageReconciler struct {
// and ignore requests from other namespaces.
// This is mostly useful for our tests, to overcome a limitation of EnvTest about namespace deletion.
Namespace string

IsOpenShift bool
}

//+kubebuilder:rbac:groups=janus-idp.io,resources=backstages,verbs=get;list;watch;create;update;patch;delete
Expand All @@ -59,6 +61,7 @@ type BackstageReconciler struct {
//+kubebuilder:rbac:groups="",resources=configmaps;secrets;persistentvolumes;persistentvolumeclaims;services,verbs=get;watch;create;update;list;delete
//+kubebuilder:rbac:groups="apps",resources=deployments,verbs=get;watch;create;update;list;delete
//+kubebuilder:rbac:groups="apps",resources=statefulsets,verbs=get;watch;create;update;list;delete
//+kubebuilder:rbac:groups="route.openshift.io",resources=routes,verbs=get;watch;create;update;list;delete

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
Expand Down Expand Up @@ -120,6 +123,12 @@ func (r *BackstageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return ctrl.Result{}, fmt.Errorf("failed to apply Backstage Service: %w", err)
}

if r.IsOpenShift {
if err := r.applyBackstageRoute(ctx, backstage, req.Namespace); err != nil {
return ctrl.Result{}, err
}
}

//TODO: it is just a placeholder for the time
r.setRunningStatus(ctx, &backstage, req.Namespace)
r.setSyncStatus(&backstage)
Expand Down
12 changes: 6 additions & 6 deletions controllers/backstage_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ var _ = Describe("Backstage controller", func() {
found := &appsv1.Deployment{}
Eventually(func() error {
// TODO to get name from default
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: "backstage"}, found)
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: fmt.Sprintf("backstage-%s", backstageName)}, found)
}, time.Minute, time.Second).Should(Succeed())

By("Checking that the Deployment is configured with a random backend auth secret")
Expand Down Expand Up @@ -338,7 +338,7 @@ spec:
By("Checking if Deployment was successfully created in the reconciliation")
Eventually(func() error {
found := &appsv1.Deployment{}
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: "bs1-deployment"}, found)
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: fmt.Sprintf("backstage-%s", backstageName)}, found)
}, time.Minute, time.Second).Should(Succeed())

By("Checking the latest Status added to the Backstage instance")
Expand Down Expand Up @@ -457,7 +457,7 @@ spec:
By("Not creating a Backstage Deployment")
Consistently(func() error {
// TODO to get name from default
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: "backstage"}, &appsv1.Deployment{})
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: fmt.Sprintf("backstage-%s", backstageName)}, &appsv1.Deployment{})
}, 5*time.Second, time.Second).Should(Not(Succeed()))
})
})
Expand Down Expand Up @@ -558,7 +558,7 @@ plugins: []
found := &appsv1.Deployment{}
Eventually(func(g Gomega) {
// TODO to get name from default
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: "backstage"}, found)
err := k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: fmt.Sprintf("backstage-%s", backstageName)}, found)
g.Expect(err).To(Not(HaveOccurred()))
}, time.Minute, time.Second).Should(Succeed())

Expand Down Expand Up @@ -733,7 +733,7 @@ plugins: []
found := &appsv1.Deployment{}
Eventually(func() error {
// TODO to get name from default
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: "backstage"}, found)
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: fmt.Sprintf("backstage-%s", backstageName)}, found)
}, time.Minute, time.Second).Should(Succeed())

By("Checking that the Deployment is configured with the specified secret", func() {
Expand Down Expand Up @@ -808,7 +808,7 @@ plugins: []
found := &appsv1.Deployment{}
Eventually(func() error {
// TODO to get name from default
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: "backstage"}, found)
return k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: fmt.Sprintf("backstage-%s", backstageName)}, found)
}, time.Minute, time.Second).Should(Succeed())

By("Checking that the Deployment is configured with the specified secret", func() {
Expand Down
4 changes: 3 additions & 1 deletion controllers/backstage_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ func (r *BackstageReconciler) applyBackstageDeployment(ctx context.Context, back
}

foundDeployment := &appsv1.Deployment{}
err = r.Get(ctx, types.NamespacedName{Name: deployment.Name, Namespace: ns}, foundDeployment)
name := fmt.Sprintf("backstage-%s", backstage.Name)
deployment.Name = name
err = r.Get(ctx, types.NamespacedName{Name: name, Namespace: ns}, foundDeployment)
if err != nil {
if errors.IsNotFound(err) {

Expand Down
64 changes: 64 additions & 0 deletions controllers/backstage_route.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// Copyright (c) 2023 Red Hat, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package controller

import (
"context"
"fmt"

"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

openshift "github.com/openshift/api/route/v1"
bs "janus-idp.io/backstage-operator/api/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
)

func (r *BackstageReconciler) applyBackstageRoute(ctx context.Context, backstage bs.Backstage, ns string) error {
route := &openshift.Route{}
err := r.readConfigMapOrDefault(ctx, backstage.Spec.RawRuntimeConfig.BackstageConfigName, "route.yaml", ns, route)
if err != nil {
return err
}

// Override the route and service names
name := fmt.Sprintf("backstage-%s", backstage.Name)
route.Name = name
route.Spec.To.Name = name

err = r.Get(ctx, types.NamespacedName{Name: route.Name, Namespace: ns}, route)
if err != nil {
if !errors.IsNotFound(err) {
return fmt.Errorf("failed to get backstage route, reason: %s", err)
}
} else {
//lg.Info("CR update is ignored for the time")
return nil
}

r.labels(&route.ObjectMeta, backstage)

if r.OwnsRuntime {
if err := controllerutil.SetControllerReference(&backstage, route, r.Scheme); err != nil {
return fmt.Errorf("failed to set owner reference: %s", err)
}
}

err = r.Create(ctx, route)
if err != nil {
return fmt.Errorf("failed to create backstage route, reason: %s", err)
}
return nil
}
2 changes: 2 additions & 0 deletions controllers/backstage_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ func (r *BackstageReconciler) applyBackstageService(ctx context.Context, backsta
if err != nil {
return err
}
name := fmt.Sprintf("backstage-%s", backstage.Name)
service.Name = name

setBackstageAppLabel(&service.Spec.Selector, backstage)

Expand Down
Loading

0 comments on commit b0d0381

Please sign in to comment.