diff --git a/api/v1beta1/cryostat_types.go b/api/v1beta1/cryostat_types.go index 9e786a4d..5237ba1c 100644 --- a/api/v1beta1/cryostat_types.go +++ b/api/v1beta1/cryostat_types.go @@ -113,6 +113,10 @@ type CryostatStatus struct { // +optional // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Cryostat Conditions",xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} Conditions []metav1.Condition `json:"conditions,omitempty"` + // Name of the Secret containing the generated Grafana credentials + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:io.kubernetes:Secret"} + GrafanaSecret string `json:"grafanaSecret,omitempty"` // Address of the deployed Cryostat web application // +operator-sdk:csv:customresourcedefinitions:type=status,xDescriptors={"urn:alm:descriptor:org.w3:link"} ApplicationURL string `json:"applicationUrl"` @@ -355,6 +359,7 @@ type JmxCacheOptions struct { // must be created to instruct the operator to deploy the Cryostat application. //+operator-sdk:csv:customresourcedefinitions:resources={{Deployment,v1},{Ingress,v1},{PersistentVolumeClaim,v1},{Secret,v1},{Service,v1},{Route,v1},{ConsoleLink,v1}} // +kubebuilder:printcolumn:name="Application URL",type=string,JSONPath=`.status.applicationUrl` +// +kubebuilder:printcolumn:name="Grafana Secret",type=string,JSONPath=`.status.grafanaSecret` type Cryostat struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/bundle/manifests/cryostat-operator.clusterserviceversion.yaml b/bundle/manifests/cryostat-operator.clusterserviceversion.yaml index 6d0c1396..04b4d121 100644 --- a/bundle/manifests/cryostat-operator.clusterserviceversion.yaml +++ b/bundle/manifests/cryostat-operator.clusterserviceversion.yaml @@ -280,6 +280,11 @@ spec: path: conditions x-descriptors: - urn:alm:descriptor:io.kubernetes.conditions + - description: Name of the Secret containing the generated Grafana credentials + displayName: Grafana Secret + path: grafanaSecret + x-descriptors: + - urn:alm:descriptor:io.kubernetes:Secret version: v1beta1 - description: FlightRecorder represents a target Pod that is capable of creating JDK Flight Recordings using Cryostat. The Cryostat operator creates FlightRecorder objects when it finds compatible Pods. displayName: Flight Recorder diff --git a/bundle/manifests/operator.cryostat.io_cryostats.yaml b/bundle/manifests/operator.cryostat.io_cryostats.yaml index c40f5f3e..47be9889 100644 --- a/bundle/manifests/operator.cryostat.io_cryostats.yaml +++ b/bundle/manifests/operator.cryostat.io_cryostats.yaml @@ -18,6 +18,9 @@ spec: - jsonPath: .status.applicationUrl name: Application URL type: string + - jsonPath: .status.grafanaSecret + name: Grafana Secret + type: string name: v1beta1 schema: openAPIV3Schema: @@ -892,6 +895,9 @@ spec: - type type: object type: array + grafanaSecret: + description: Name of the Secret containing the generated Grafana credentials + type: string required: - applicationUrl type: object diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index 50dab83d..18020928 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -5,9 +5,9 @@ annotations: operators.operatorframework.io.bundle.metadata.v1: metadata/ operators.operatorframework.io.bundle.package.v1: cryostat-operator operators.operatorframework.io.bundle.channels.v1: alpha + operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.builder: operator-sdk-v1.4.0+git - operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 # Annotations for testing. operators.operatorframework.io.test.mediatype.v1: scorecard+v1 diff --git a/config/crd/bases/operator.cryostat.io_cryostats.yaml b/config/crd/bases/operator.cryostat.io_cryostats.yaml index 2957024c..0630f0ef 100644 --- a/config/crd/bases/operator.cryostat.io_cryostats.yaml +++ b/config/crd/bases/operator.cryostat.io_cryostats.yaml @@ -20,6 +20,9 @@ spec: - jsonPath: .status.applicationUrl name: Application URL type: string + - jsonPath: .status.grafanaSecret + name: Grafana Secret + type: string name: v1beta1 schema: openAPIV3Schema: @@ -1520,6 +1523,9 @@ spec: - type type: object type: array + grafanaSecret: + description: Name of the Secret containing the generated Grafana credentials + type: string required: - applicationUrl type: object diff --git a/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml b/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml index ac01c670..a219574c 100644 --- a/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml @@ -268,6 +268,11 @@ spec: path: conditions x-descriptors: - urn:alm:descriptor:io.kubernetes.conditions + - description: Name of the Secret containing the generated Grafana credentials + displayName: Grafana Secret + path: grafanaSecret + x-descriptors: + - urn:alm:descriptor:io.kubernetes:Secret version: v1beta1 - description: FlightRecorder represents a target Pod that is capable of creating JDK Flight Recordings using Cryostat. The Cryostat operator creates FlightRecorder objects when it finds compatible Pods. displayName: Flight Recorder diff --git a/internal/controllers/cryostat_controller.go b/internal/controllers/cryostat_controller.go index ca213685..c22e0b6d 100644 --- a/internal/controllers/cryostat_controller.go +++ b/internal/controllers/cryostat_controller.go @@ -316,6 +316,14 @@ func (r *CryostatReconciler) Reconcile(ctx context.Context, request ctrl.Request } } + if grafanaSecret != nil { + instance.Status.GrafanaSecret = grafanaSecret.Name + err = r.Client.Status().Update(ctx, instance) + if err != nil { + return reconcile.Result{}, err + } + } + // OpenShift-specific if r.IsOpenShift { err := r.createConsoleLink(ctx, instance, serviceSpecs.CoreURL.String()) diff --git a/internal/controllers/cryostat_controller_test.go b/internal/controllers/cryostat_controller_test.go index 3b8a8d65..7dd33036 100644 --- a/internal/controllers/cryostat_controller_test.go +++ b/internal/controllers/cryostat_controller_test.go @@ -166,6 +166,9 @@ var _ = Describe("CryostatController", func() { It("should set ApplicationURL in CR Status", func() { t.expectStatusApplicationURL() }) + It("should set GrafanaSecret in CR Status", func() { + t.expectStatusGrafanaSecretName() + }) It("should create deployment and set owner", func() { t.expectDeployment() }) @@ -239,6 +242,9 @@ var _ = Describe("CryostatController", func() { It("should set ApplicationURL in CR Status", func() { t.expectStatusApplicationURL() }) + It("should set GrafanaSecret in CR Status", func() { + t.expectStatusGrafanaSecretName() + }) It("should create deployment and set owner", func() { t.expectDeployment() }) @@ -1761,6 +1767,18 @@ func (t *cryostatTestInput) expectStatusApplicationURL() { Expect(instance.Status.ApplicationURL).To(Equal("https://cryostat.example.com")) } +func (t *cryostatTestInput) expectStatusGrafanaSecretName() { + instance := &operatorv1beta1.Cryostat{} + err := t.Client.Get(context.Background(), types.NamespacedName{Name: "cryostat", Namespace: "default"}, instance) + + t.reconcileCryostatFully() + + err = t.Client.Get(context.Background(), types.NamespacedName{Name: "cryostat", Namespace: "default"}, instance) + Expect(err).ToNot(HaveOccurred()) + + Expect(instance.Status.GrafanaSecret).To(Equal("cryostat-grafana-basic")) +} + func (t *cryostatTestInput) expectDeployment() { deployment := &appsv1.Deployment{} err := t.Client.Get(context.Background(), types.NamespacedName{Name: "cryostat", Namespace: "default"}, deployment)