diff --git a/.github/workflows/build-test-dev.yml b/.github/workflows/build-test-dev.yml index 965bbe2..8294510 100644 --- a/.github/workflows/build-test-dev.yml +++ b/.github/workflows/build-test-dev.yml @@ -6,7 +6,7 @@ on: - main env: - VERSION: 1.0.3 + VERSION: 1.1.0 IMAGE_NAME: pubsubplus-eventbroker-operator VAULT_ADDR: ${{ secrets.VAULT_ADDR }} GCLOUD_PROJECT_ID_DEV: ${{ secrets.GCLOUD_PROJECT_ID }} @@ -121,6 +121,11 @@ jobs: exportToken: true secrets: | secret/data/development/gcp-gcr GCP_SERVICE_ACCOUNT | GCP_DEV_SERVICE_ACCOUNT + env: + VERSION: 1.1.0 + IMAGE_NAME: pubsubplus-eventbroker-operator + VAULT_ADDR: ${{ secrets.VAULT_ADDR }} + GCLOUD_PROJECT_ID_DEV: ${{ secrets.GCLOUD_PROJECT_ID }} - name: Log in to gcr development docker registry uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 @@ -138,6 +143,12 @@ jobs: tags: | gcr.io/${{ env.GCLOUD_PROJECT_ID_DEV }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} push: true + env: + VERSION: 1.1.0 + IMAGE_NAME: pubsubplus-eventbroker-operator + VAULT_ADDR: ${{ secrets.VAULT_ADDR }} + GCLOUD_PROJECT_ID_DEV: ${{ secrets.GCLOUD_PROJECT_ID }} + - name: Run Vulnerability PreCheck for Prisma uses: ./maas-build-actions/.github/actions/prisma-vulnerability-checker diff --git a/.github/workflows/prep-release.yml b/.github/workflows/prep-release.yml index 388ebd2..819c2c6 100644 --- a/.github/workflows/prep-release.yml +++ b/.github/workflows/prep-release.yml @@ -4,7 +4,7 @@ on: release_tag: description: 'Release tag' required: true - default: '1.0.3-dev' + default: '1.1.0' prep_internal_release: # Need to distinguish between internal and external releases # Internal release: Will use default internal location for created images (ghcr.io) and will tag and push operator candidate there diff --git a/.github/workflows/test-broker-chaos-situation.yml b/.github/workflows/test-broker-chaos-situation.yml index 831e8a3..47ffe72 100644 --- a/.github/workflows/test-broker-chaos-situation.yml +++ b/.github/workflows/test-broker-chaos-situation.yml @@ -72,7 +72,7 @@ jobs: kubectl create secret tls monitoring-tls --key="tls.private.pem" --cert="tls.public.pem" kubectl apply -f ci/manifests/eventbroker-ha.yaml | grep "test-ha created" sleep 10 ; kubectl get all - kubectl wait pods --selector app.kubernetes.io/instance=test-ha --for condition=Ready --timeout=300s + kubectl wait pods --selector app.kubernetes.io/instance=test-ha --for condition=Ready --timeout=500s kubectl get po --show-labels -n $TESTNAMESPACE | grep test-ha | grep "1/1" kubectl get po --show-labels -n $TESTNAMESPACE | grep test-ha | grep active=true kubectl get sts -n $TESTNAMESPACE | grep test-ha @@ -99,7 +99,7 @@ jobs: run: | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tlsupdated.key -out tlsupdated.crt -subj "/CN=*" kubectl create secret tls test-tlsupdated --key="tlsupdated.key" --cert="tlsupdated.crt" - kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=300s + kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=400s kubectl get all kubectl apply -f ci/manifests/chaos-manifests/admin-secret-update.yaml | grep "configured" kubectl get all @@ -113,11 +113,11 @@ jobs: - name: Testing the Operator - HA - Chaos Scenario 3 - Update Scaling Parameters and confirm recovery for message delivery run: | - kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=300s + kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=400s kubectl get all kubectl apply -f ci/manifests/chaos-manifests/scaling-parameter-update.yaml | grep "configured" kubectl get all - kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=300s + kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=400s kubectl get all kubectl port-forward svc/test-ha-pubsubplus -n $TESTNAMESPACE 55558:55555 & sleep 5 @@ -127,7 +127,7 @@ jobs: - name: Testing the Operator - HA - Chaos Scenario 4 - Kill 2 Nodes and confirm recovery for message delivery run: | - kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=300s + kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=400s kubectl get all kubectl get pods -n $TESTNAMESPACE --selector node-type=message-routing-primary | grep Running | awk '{print $1}' | xargs kubectl delete pod kubectl get pods -n $TESTNAMESPACE --selector node-type=message-routing-backup | grep Running | awk '{print $1}' | xargs kubectl delete pod @@ -143,7 +143,7 @@ jobs: run: | kubectl get sts -n $TESTNAMESPACE | grep 1/1 | awk '{print $1}' | xargs kubectl delete sts kubectl get all - kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=300s + kubectl wait pods --selector node-type=message-routing-primary --for condition=Ready --timeout=400s sleep 120 kubectl get all kubectl port-forward svc/test-ha-pubsubplus -n $TESTNAMESPACE 55552:55555 & diff --git a/.github/workflows/vulncheck_periodic.yml b/.github/workflows/vulncheck_periodic.yml index 7b9185e..4c41302 100644 --- a/.github/workflows/vulncheck_periodic.yml +++ b/.github/workflows/vulncheck_periodic.yml @@ -1,7 +1,14 @@ name: Vuln check on: schedule: - - cron: '0 */6 * * *' + - cron: '0 */ * * *' + +env: + VERSION: 1.1.0 + IMAGE_NAME: pubsubplus-eventbroker-operator + VAULT_ADDR: ${{ secrets.VAULT_ADDR }} + GCLOUD_PROJECT_ID_DEV: ${{ secrets.GCLOUD_PROJECT_ID }} + permissions: contents: read @@ -57,6 +64,11 @@ jobs: exportToken: true secrets: | secret/data/development/gcp-gcr GCP_SERVICE_ACCOUNT | GCP_DEV_SERVICE_ACCOUNT + env: + VERSION: 1.1.0 + IMAGE_NAME: pubsubplus-eventbroker-operator + VAULT_ADDR: ${{ secrets.VAULT_ADDR }} + GCLOUD_PROJECT_ID_DEV: ${{ secrets.GCLOUD_PROJECT_ID }} - name: Log in to gcr development docker registry uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 @@ -72,6 +84,12 @@ jobs: tags: | gcr.io/${{ env.GCLOUD_PROJECT_ID_DEV }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} push: true + env: + VERSION: 1.1.0 + IMAGE_NAME: pubsubplus-eventbroker-operator + VAULT_ADDR: ${{ secrets.VAULT_ADDR }} + GCLOUD_PROJECT_ID_DEV: ${{ secrets.GCLOUD_PROJECT_ID }} + - name: Run Vulnerability PreCheck for Prisma uses: ./maas-build-actions/.github/actions/prisma-vulnerability-checker diff --git a/Dockerfile b/Dockerfile index bc91d5c..ec1cee5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,12 +19,12 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM registry.access.redhat.com/ubi9/ubi-minimal:latest +FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4-1134 LABEL name="solace/pubsubplus-eventbroker-operator" LABEL vendor="Solace Corporation" -LABEL version="1.0.3" -LABEL release="1.0.3" +LABEL version="1.1.0" +LABEL release="1.1.0" LABEL summary="Solace PubSub+ Event Broker Kubernetes Operator" LABEL description="The Solace PubSub+ Event Broker Kubernetes Operator deploys and manages the lifecycle of PubSub+ Event Brokers" diff --git a/Makefile b/Makefile index 3a175a6..3ddfe4a 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # To re-generate a bundle for another specific version without changing the standard setup, you can: # - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2) # - use environment variables to overwrite this value (e.g export VERSION=0.0.2) -VERSION ?= 1.0.3 +VERSION ?= 1.1.0 # API_VERSION defines the API version for the PubSubPlusEventBroker CRD API_VERSION ?= v1beta1 diff --git a/README.md b/README.md index bcb91cd..4c1a48e 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,9 @@ kubectl get pods --show-labels --watch kubectl wait --for=condition=ServiceReady eventbroker non-ha-monitoring-enabled-example kubectl wait --for=condition=MonitoringReady eventbroker non-ha-monitoring-enabled-example ``` -For more information about Prometheus monitoring, see [Exposing Metrics to Prometheus](/docs/EventBrokerOperatorUserGuide.md#exposing-metrics-to-prometheus) in the detailed PubSub+ Operator documentation. +For more information about Prometheus monitoring, see [Exposing Metrics to Prometheus](/docs/EventBrokerOperatorUserGuide.md#exposing-metrics-to-prometheus) in the detailed PubSub+ Operator documentation. + +> Solace Pubsub+ Prometheus Exporter End of Life Notice : Please note that Solace will end of life Pubsub+ Prometheus Exporter version 1.0.1 as of June ,2024. This means there will be no releases for Pubsub+ Prometheus Exporter after June ,2024, however, Solace will continue to provide technical support for it until June, 2025. Refer https://solace.com/legal/technical-product-support/ for support terminologies. If you have monitoring enabled, the operator will default to downloading the Solace version of Pubsub+ Prometheus Exporter 1.0.1. The community version of the Prometheus Exporter available at https://github.com/solacecommunity/solace-prometheus-exporter can be deployed with Pubsub+ Event Broker Operator. Note that Solace does not officially support the community version of the Prometheus Exporter. ### 4. Test the deployment diff --git a/api/v1beta1/eventbroker_types.go b/api/v1beta1/eventbroker_types.go index 4da864b..789a531 100644 --- a/api/v1beta1/eventbroker_types.go +++ b/api/v1beta1/eventbroker_types.go @@ -20,6 +20,7 @@ import ( "encoding/json" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" ) // EventBrokerSpec defines the desired state of PubSubPlusEventBroker @@ -39,6 +40,8 @@ type EventBrokerSpec struct { Developer bool `json:"developer"` //+optional //+kubebuilder:validation:Type:=object + //+kubebuilder:pruning:PreserveUnknownFields + //+kubebuilder:validation:Schemaless //+operator-sdk:csv:customresourcedefinitions:type=spec,order=3 // SystemScaling provides exact fine-grained specification of the event broker scaling parameters // and the assigned CPU / memory resources to the Pod. @@ -110,6 +113,15 @@ type EventBrokerSpec struct { // SecurityContext defines the pod security context for the event broker. SecurityContext SecurityContext `json:"securityContext,omitempty"` //+kubebuilder:validation:Type:=object + // ContainerSecurityContext defines the container security context for the PubSubPlusEventBroker. + BrokerSecurityContext ContainerSecurityContext `json:"brokerContainerSecurity,omitempty"` + //+optional + //+kubebuilder:validation:Type:=boolean + //+kubebuilder:default:=false + // EnableServiceLinks indicates whether information about services should be injected into pod's environment + // variables, matching the syntax of Docker links. Optional: Defaults to false. + EnableServiceLinks bool `json:"enableServiceLinks,omitempty"` + //+kubebuilder:validation:Type:=object // ServiceAccount defines a ServiceAccount dedicated to the PubSubPlusEventBroker ServiceAccount BrokerServiceAccount `json:"serviceAccount,omitempty"` //+kubebuilder:validation:Type:=object @@ -214,6 +226,7 @@ type BrokerPersistentVolumeClaim struct { ClaimName string `json:"claimName"` } +// +kubebuilder:pruning:PreserveUnknownFields type SystemScaling struct { // +kubebuilder:default:=100 MaxConnections int `json:"maxConnections,omitempty"` @@ -225,6 +238,8 @@ type SystemScaling struct { MessagingNodeCpu string `json:"messagingNodeCpu,omitempty"` // +kubebuilder:default:="4025Mi" MessagingNodeMemory string `json:"messagingNodeMemory,omitempty"` + //+kubebuilder:pruning:PreserveUnknownFields + runtime.RawExtension `json:"-"` } // BrokerTLS defines TLS configuration for the PubSubPlusEventBroker @@ -269,6 +284,16 @@ type ExtraEnvVar struct { Value string `json:"value"` } +// MonitoringExtraEnvVar defines environment variables to be added to the Prometheus Exporter container for Monitoring +type MonitoringExtraEnvVar struct { + //+kubebuilder:validation:Type:=string + // Specifies the Name of an environment variable to be added to the Prometheus Exporter container for Monitoring + Name string `json:"name"` + //+kubebuilder:validation:Type:=string + // Specifies the Value of an environment variable to be added to the Prometheus Exporter container for Monitoring + Value string `json:"value"` +} + // BrokerImage defines Image details and pulling configurations type BrokerImage struct { //+optional @@ -333,6 +358,18 @@ type SecurityContext struct { RunAsUser int64 `json:"runAsUser"` } +// ContainerSecurityContext defines the container security context for the PubSubPlusEventBroker +type ContainerSecurityContext struct { + //+optional + //+kubebuilder:validation:Type:=number + // Specifies runAsGroup in container security context. 0 or unset defaults either to 1000002, or if OpenShift detected to unspecified (see documentation) + RunAsGroup int64 `json:"runAsGroup"` + //+optional + //+kubebuilder:validation:Type:=number + // Specifies runAsUser in container security context. 0 or unset defaults either to 1000001, or if OpenShift detected to unspecified (see documentation) + RunAsUser int64 `json:"runAsUser"` +} + // MonitoringImage defines Image details and pulling configurations for the Prometheus Exporter for Monitoring type MonitoringImage struct { //+kubebuilder:validation:Type:=string @@ -360,6 +397,10 @@ type Monitoring struct { // Enabled true enables the setup of the Prometheus Exporter. Enabled bool `json:"enabled"` //+optional + //+kubebuilder:validation:Type:=array + // List of extra environment variables to be added to the Prometheus Exporter container. + ExtraEnvVars []*MonitoringExtraEnvVar `json:"extraEnvVars"` + //+optional //+kubebuilder:validation:Type:=object // Image defines container image parameters for the Prometheus Exporter. MonitoringImage *MonitoringImage `json:"image,omitempty"` diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 0460f89..38a5445 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -23,7 +23,7 @@ package v1beta1 import ( "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -126,13 +126,28 @@ func (in *BrokerTLS) DeepCopy() *BrokerTLS { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ContainerSecurityContext) DeepCopyInto(out *ContainerSecurityContext) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerSecurityContext. +func (in *ContainerSecurityContext) DeepCopy() *ContainerSecurityContext { + if in == nil { + return nil + } + out := new(ContainerSecurityContext) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EventBrokerSpec) DeepCopyInto(out *EventBrokerSpec) { *out = *in if in.SystemScaling != nil { in, out := &in.SystemScaling, &out.SystemScaling *out = new(SystemScaling) - **out = **in + (*in).DeepCopyInto(*out) } if in.ExtraEnvVars != nil { in, out := &in.ExtraEnvVars, &out.ExtraEnvVars @@ -168,6 +183,7 @@ func (in *EventBrokerSpec) DeepCopyInto(out *EventBrokerSpec) { } } out.SecurityContext = in.SecurityContext + out.BrokerSecurityContext = in.BrokerSecurityContext out.ServiceAccount = in.ServiceAccount out.BrokerTLS = in.BrokerTLS in.Service.DeepCopyInto(&out.Service) @@ -232,6 +248,17 @@ func (in *ExtraEnvVar) DeepCopy() *ExtraEnvVar { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Monitoring) DeepCopyInto(out *Monitoring) { *out = *in + if in.ExtraEnvVars != nil { + in, out := &in.ExtraEnvVars, &out.ExtraEnvVars + *out = make([]*MonitoringExtraEnvVar, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(MonitoringExtraEnvVar) + **out = **in + } + } + } if in.MonitoringImage != nil { in, out := &in.MonitoringImage, &out.MonitoringImage *out = new(MonitoringImage) @@ -254,6 +281,21 @@ func (in *Monitoring) DeepCopy() *Monitoring { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MonitoringExtraEnvVar) DeepCopyInto(out *MonitoringExtraEnvVar) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MonitoringExtraEnvVar. +func (in *MonitoringExtraEnvVar) DeepCopy() *MonitoringExtraEnvVar { + if in == nil { + return nil + } + out := new(MonitoringExtraEnvVar) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MonitoringImage) DeepCopyInto(out *MonitoringImage) { *out = *in @@ -496,6 +538,7 @@ func (in *StorageCustomVolumeMount) DeepCopy() *StorageCustomVolumeMount { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SystemScaling) DeepCopyInto(out *SystemScaling) { *out = *in + in.RawExtension.DeepCopyInto(&out.RawExtension) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SystemScaling. diff --git a/bundle/manifests/pubsubplus-eventbroker-operator.clusterserviceversion.yaml b/bundle/manifests/pubsubplus-eventbroker-operator.clusterserviceversion.yaml index 8af0360..521715f 100644 --- a/bundle/manifests/pubsubplus-eventbroker-operator.clusterserviceversion.yaml +++ b/bundle/manifests/pubsubplus-eventbroker-operator.clusterserviceversion.yaml @@ -20,16 +20,16 @@ metadata: certified: "true" com.redhat.delivery.operator.bundle: "true" com.redhat.openshift.versions: v4.10 - containerImage: docker.io/solace/pubsubplus-eventbroker-operator:1.0.3 - createdAt: "2024-04-23T16:09:41Z" + containerImage: docker.io/solace/pubsubplus-eventbroker-operator:1.1.0 + createdAt: "2024-07-01T12:25:04Z" description: The Solace PubSub+ Event Broker Operator deploys and manages the lifecycle of PubSub+ Event Brokers operators.openshift.io/valid-subscription: '[]' - operators.operatorframework.io/builder: operator-sdk-v1.27.0 + operators.operatorframework.io/builder: operator-sdk-v1.34.1 operators.operatorframework.io/project_layout: go.kubebuilder.io/v3 repository: https://github.com/SolaceProducts/pubsubplus-kubernetes-quickstart support: Solace Products - name: pubsubplus-eventbroker-operator.v1.0.3 + name: pubsubplus-eventbroker-operator.v1.1.0 namespace: placeholder spec: apiservicedefinitions: {} @@ -296,7 +296,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.annotations['olm.targetNamespaces'] - image: docker.io/solace/pubsubplus-eventbroker-operator:1.0.3 + image: docker.io/solace/pubsubplus-eventbroker-operator:1.1.0 imagePullPolicy: Always livenessProbe: httpGet: @@ -411,4 +411,4 @@ spec: provider: name: Solace Corporation url: www.solace.com - version: 1.0.3 + version: 1.1.0 diff --git a/bundle/manifests/pubsubplus.solace.com_pubsubpluseventbrokers.yaml b/bundle/manifests/pubsubplus.solace.com_pubsubpluseventbrokers.yaml index 59909dc..70b6fe3 100644 --- a/bundle/manifests/pubsubplus.solace.com_pubsubpluseventbrokers.yaml +++ b/bundle/manifests/pubsubplus.solace.com_pubsubpluseventbrokers.yaml @@ -3,8 +3,7 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - labels: - app.kubernetes.io/version: v1.0.3 + creationTimestamp: null name: pubsubpluseventbrokers.pubsubplus.solace.com spec: group: pubsubplus.solace.com @@ -49,12 +48,35 @@ spec: When provided, ensure the secret key name is `username_admin_password`. For valid values refer to the Solace documentation https://docs.solace.com/Admin/Configuring-Internal-CLI-User-Accounts.htm. nullable: true type: string + brokerContainerSecurity: + description: ContainerSecurityContext defines the container security + context for the PubSubPlusEventBroker. + properties: + runAsGroup: + description: Specifies runAsGroup in container security context. + 0 or unset defaults either to 1000002, or if OpenShift detected + to unspecified (see documentation) + format: int64 + type: number + runAsUser: + description: Specifies runAsUser in container security context. + 0 or unset defaults either to 1000001, or if OpenShift detected + to unspecified (see documentation) + format: int64 + type: number + type: object developer: default: false description: |- Developer true specifies a minimum footprint scaled-down deployment, not for production use. If set to true it overrides SystemScaling parameters. type: boolean + enableServiceLinks: + default: false + description: |- + EnableServiceLinks indicates whether information about services should be injected into pod's environment + variables, matching the syntax of Docker links. Optional: Defaults to false. + type: boolean extraEnvVars: description: |- List of extra environment variables to be added to the PubSubPlusEventBroker container. Note: Do not configure Timezone or SystemScaling parameters here as it could cause unintended consequences. @@ -132,6 +154,26 @@ spec: description: Enabled true enables the setup of the Prometheus Exporter. type: boolean + extraEnvVars: + description: List of extra environment variables to be added to + the Prometheus Exporter container. + items: + description: MonitoringExtraEnvVar defines environment variables + to be added to the Prometheus Exporter container for Monitoring + properties: + name: + description: Specifies the Name of an environment variable + to be added to the Prometheus Exporter container for Monitoring + type: string + value: + description: Specifies the Value of an environment variable + to be added to the Prometheus Exporter container for Monitoring + type: string + required: + - name + - value + type: object + type: array image: description: Image defines container image parameters for the Prometheus Exporter. @@ -1454,23 +1496,8 @@ spec: description: |- SystemScaling provides exact fine-grained specification of the event broker scaling parameters and the assigned CPU / memory resources to the Pod. - properties: - maxConnections: - default: 100 - type: integer - maxQueueMessages: - default: 100 - type: integer - maxSpoolUsage: - default: 1000 - type: integer - messagingNodeCpu: - default: "2" - type: string - messagingNodeMemory: - default: 4025Mi - type: string type: object + x-kubernetes-preserve-unknown-fields: true timezone: default: UTC description: Defines the timezone for the event broker container, diff --git a/bundle/metadata/annotations.yaml b/bundle/metadata/annotations.yaml index fb59147..b1053cc 100644 --- a/bundle/metadata/annotations.yaml +++ b/bundle/metadata/annotations.yaml @@ -6,13 +6,10 @@ annotations: operators.operatorframework.io.bundle.package.v1: pubsubplus-eventbroker-operator operators.operatorframework.io.bundle.channels.v1: stable operators.operatorframework.io.bundle.channel.default.v1: stable - operators.operatorframework.io.metrics.builder: operator-sdk-v1.26.0 + operators.operatorframework.io.metrics.builder: operator-sdk-v1.34.1 operators.operatorframework.io.metrics.mediatype.v1: metrics+v1 operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v3 # Annotations for testing. operators.operatorframework.io.test.mediatype.v1: scorecard+v1 operators.operatorframework.io.test.config.v1: tests/scorecard/ - - # Required by RedHat certification - com.redhat.openshift.versions: "v4.11" diff --git a/ci/whitesource/whitesource-agent.config b/ci/whitesource/whitesource-agent.config index 075093e..2941dfd 100644 --- a/ci/whitesource/whitesource-agent.config +++ b/ci/whitesource/whitesource-agent.config @@ -41,11 +41,11 @@ go.modules.includeTestDependencies=true #userKey= projectName=pubsubplus-kubernetes-operator -projectVersion=v1.0.3 +projectVersion=v1.1.0 projectToken= productName=pubsubplus-kubernetes-operator -productVersion=v1.0.3 +productVersion=v1.1.0 productToken= updateType=OVERRIDE #requesterEmail=user@provider.com diff --git a/config/crd/bases/pubsubplus.solace.com_pubsubpluseventbrokers.yaml b/config/crd/bases/pubsubplus.solace.com_pubsubpluseventbrokers.yaml index 419aa5a..3e9c1d9 100644 --- a/config/crd/bases/pubsubplus.solace.com_pubsubpluseventbrokers.yaml +++ b/config/crd/bases/pubsubplus.solace.com_pubsubpluseventbrokers.yaml @@ -48,12 +48,35 @@ spec: When provided, ensure the secret key name is `username_admin_password`. For valid values refer to the Solace documentation https://docs.solace.com/Admin/Configuring-Internal-CLI-User-Accounts.htm. nullable: true type: string + brokerContainerSecurity: + description: ContainerSecurityContext defines the container security + context for the PubSubPlusEventBroker. + properties: + runAsGroup: + description: Specifies runAsGroup in container security context. + 0 or unset defaults either to 1000002, or if OpenShift detected + to unspecified (see documentation) + format: int64 + type: number + runAsUser: + description: Specifies runAsUser in container security context. + 0 or unset defaults either to 1000001, or if OpenShift detected + to unspecified (see documentation) + format: int64 + type: number + type: object developer: default: false description: |- Developer true specifies a minimum footprint scaled-down deployment, not for production use. If set to true it overrides SystemScaling parameters. type: boolean + enableServiceLinks: + default: false + description: |- + EnableServiceLinks indicates whether information about services should be injected into pod's environment + variables, matching the syntax of Docker links. Optional: Defaults to false. + type: boolean extraEnvVars: description: |- List of extra environment variables to be added to the PubSubPlusEventBroker container. Note: Do not configure Timezone or SystemScaling parameters here as it could cause unintended consequences. @@ -131,6 +154,26 @@ spec: description: Enabled true enables the setup of the Prometheus Exporter. type: boolean + extraEnvVars: + description: List of extra environment variables to be added to + the Prometheus Exporter container. + items: + description: MonitoringExtraEnvVar defines environment variables + to be added to the Prometheus Exporter container for Monitoring + properties: + name: + description: Specifies the Name of an environment variable + to be added to the Prometheus Exporter container for Monitoring + type: string + value: + description: Specifies the Value of an environment variable + to be added to the Prometheus Exporter container for Monitoring + type: string + required: + - name + - value + type: object + type: array image: description: Image defines container image parameters for the Prometheus Exporter. @@ -1453,23 +1496,8 @@ spec: description: |- SystemScaling provides exact fine-grained specification of the event broker scaling parameters and the assigned CPU / memory resources to the Pod. - properties: - maxConnections: - default: 100 - type: integer - maxQueueMessages: - default: 100 - type: integer - maxSpoolUsage: - default: 1000 - type: integer - messagingNodeCpu: - default: "2" - type: string - messagingNodeMemory: - default: 4025Mi - type: string type: object + x-kubernetes-preserve-unknown-fields: true timezone: default: UTC description: Defines the timezone for the event broker container, diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index be8e377..aba9d59 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -11,4 +11,4 @@ kind: Kustomization images: - name: controller newName: ghcr.io/solacedev/pubsubplus-eventbroker-operator - newTag: 1.0.3 + newTag: 1.1.0 diff --git a/config/samples/pubsubpluseventbroker_scaling_parameters_loosely_coupled.yaml b/config/samples/pubsubpluseventbroker_scaling_parameters_loosely_coupled.yaml new file mode 100644 index 0000000..4f8e9c5 --- /dev/null +++ b/config/samples/pubsubpluseventbroker_scaling_parameters_loosely_coupled.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: ha-scaling-parameters-tls +type: kubernetes.io/tls +data: + # values are base64 encoded, which obscures them but does NOT provide + # any useful level of confidentiality. + tls.crt: | + LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMrVENDQWVHZ0F3SUJBZ0lVZUQ5OEZUakloV0tGVUs0VWgzbWpMRDJUOGlrd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0RERUtNQWdHQTFVRUF3d0JLakFlRncweU5EQXpNVEF4TmpJeE1UbGFGdzB5TlRBek1UQXhOakl4TVRsYQpNQXd4Q2pBSUJnTlZCQU1NQVNvd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURCClpiRElyUEt2STJsN3Z6QXFWQXlLTjJybFVSOHd6cG11cHdrWFdZNHRTS1hRK2VPMHBaYnBMY0N3WDRRZlRuZlcKVkxlUElJbnBOcVIzbGxNSloxNmdZbXVrbUdMeTJ0MnpQS1JOM1U2eWNQSHRCM2NVUkZEbjZ1YTlxOGRxcXN6SQpyMmdDaDM0UTlwM1lxeVA0T2FWQVI2b3FaVCszNnA3VGZSUlFTUWdYRDI5RWJyZnI5SUd6M0dTSmtFTjhsNExVCmQ0Ym5ZdGhjNGhvVytsQ0l1TUJpNlRxRitGZ2g5Z3VoNTJVSjFVLy80YkcvN0Y1dDFMZklON21mUnBTQXRSUlcKbHp2TWZMOW4wVyttNHlXQy9EeExnVjkvUXRhQUxnR1ZaVmpYRUF2VkprQk9kUS8yMUNSMDZSZXVaSjcrVExXSgpPS01INVdpQ0c5Z3F1d0lRaGY5akFnTUJBQUdqVXpCUk1CMEdBMVVkRGdRV0JCVEkyN3VJVndkTzVUQnFVNTBMClNyUmM2T291QnpBZkJnTlZIU01FR0RBV2dCVEkyN3VJVndkTzVUQnFVNTBMU3JSYzZPb3VCekFQQmdOVkhSTUIKQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCTXN0Y0xCL2Q2dXI4U3pTL0xCTWMxTDdoKwpZOURvK25ialh0dTIwZkxBK2FCVVhFSFAyVytBalYyZG1jaFA3d2MrQVZYYWxLLy9EaTBrSGhSdWNIRXBSVXJPCm1iTWNtcDRZK1VRUS9jTTJUVGZKZ1E3MTBDRjlhdTBZeW8weWxuMzNiRE5jWDZjSnJKZUxaWEd6TmxIb2R4WVcKWHlMUTFHSTlDZVJCYjVMYVJQQ0IyZFpkU1N6Sko1MWJYR3VKdXpFWHFKM1pUWkN6ZVo3Q0dsanZUd1d0OGlnSwpZd0Y5NHlyYzEzYkNmK2ZZOEdDbloybG1pOThueVd6WDE0eXNETDhuQUVVano0ZE5pUDdsNUx4R1JVTDNjb2RjCjk1a0MyRGd3SEIxVE5tRW5JMFNWUGk0N21RRk5PZ0JNZFdPVnQ5Z2ZXRDRyODA4K0YvMGxmUXNndTExMgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + # This is an example, remember to not use in production + tls.key: | + LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRREJaYkRJclBLdkkybDcKdnpBcVZBeUtOMnJsVVI4d3pwbXVwd2tYV1k0dFNLWFErZU8wcFpicExjQ3dYNFFmVG5mV1ZMZVBJSW5wTnFSMwpsbE1KWjE2Z1ltdWttR0x5MnQyelBLUk4zVTZ5Y1BIdEIzY1VSRkRuNnVhOXE4ZHFxc3pJcjJnQ2gzNFE5cDNZCnF5UDRPYVZBUjZvcVpUKzM2cDdUZlJSUVNRZ1hEMjlFYnJmcjlJR3ozR1NKa0VOOGw0TFVkNGJuWXRoYzRob1cKK2xDSXVNQmk2VHFGK0ZnaDlndWg1MlVKMVUvLzRiRy83RjV0MUxmSU43bWZScFNBdFJSV2x6dk1mTDluMFcrbQo0eVdDL0R4TGdWOS9RdGFBTGdHVlpWalhFQXZWSmtCT2RRLzIxQ1IwNlJldVpKNytUTFdKT0tNSDVXaUNHOWdxCnV3SVFoZjlqQWdNQkFBRUNnZ0VBUnF0dUtpWm9sKzhNd0pkZ2RsYzRMZG1LU2ptV2VETkduVGVVYnQvZXdGVm4Kb2pGdUw3akNxSHA3aXZlY1JBUmNiZ21PK2RJZUV3WlFteEpuVFd4a2U1NzdUcTRRbWtXMzlhTVhOd3pEa1JrTQpqbHpIK3JQc0RKTWR0ZmxyYVdMNGFlME95TDNTSjBpMjdWRzhWeHhaY2wrOW9yaFV6RlFEcmF4ckc5dFVCWGlQCkI5QkovTjV1d3VvODFHbytoOXNlUVVaOE0xS1c4cCtKb2U4Yk5Vb2lOaEJZSGd5VFZPeVVRd2MwazQ5ZTU2elgKZjFHY0Q2SzNhNmNKdktRVjBVRUJpR2tPOFFPbVV1MWRVSWNHOXUyNVkyMUkydUovQzB2aWg4YWF1Y3dObzR2Uwo2WkFWZjBhNG5WdGNiYW1YRXg1Wnl3QVQyTXhQQ0ltTUVXWnROYklXWVFLQmdRRDAxcmlzNm5TVDZtUEZuKy82CjdZcEdZc1pYbUNlQWR0WXQxbnAydkg1cjVzR1ROY0JnM1d0aHMyanI0QXlweGlLWGo2UmpYb1ExTUdIc0l4VW0KY0xtK01LYmxvSm52SEphaHE3dXZhZGdla3dsamF2UjRnQmF3WTdNMjF4bUJaa0N3QUVFR0lhSnNVOVVBNHVXSQp3N3RONWVhaHNKT0JaNUtMaE1BV05nWlNYd0tCZ1FES05xVDJlQkVaeFp5MlcrNkFZVWdYMW9LN2Yzb3MzcXBYCjUzZDFMazJwbmQxYmVic0NKOFA5eVcxcW8yUlBRMm10bEFiZGFoQVUrY1U5YnJSVktZV01Ma3E4bWIvdDJ4TksKM0YwaE16ZUdndWZNR2dBQzhsV0RMdkoxZGpTaUlFb2JlT05HcjZZeVlKT0pGR0VsdmlwNU1wWTMrbWI4SWRlSwozOWwvbGV1WmZRS0JnQmNWZzVYeUNRbkZLS0VDWWxyek9IMUlaTkR2YkpJRklrNXlFVnZPaTlEYWtkZXlVckFQClVFZUc1ZGFQYWtJN2h4bHBGcU96enAxQk1ZcFZDSEoyWUZ6Wk0zTWxBRDUySUpHZm9uTjRkRUwxdEFYbW1LUWYKMTRQTDhxS3lCeHFYTEhRcm9mWFZCLzVVclJtSFN3THBDV2pmeXkzbGV4TFJWQlRKY0Y3bnV4TGJBb0dBVlNRUQo3UjI4eFljbzVyZHFnbTl6ZFdZQ2dZTzVJMjlWZGRHbHdKY1FhQnhwK1h3VnUyQ1c2eUtHaVdIbWVHRS8rNi9aCi9Cd09UV2FsSDZxZkQwUitVSG1sU2lmS1loSGQyNlZSS1F0eGs1ZEdsZTlVbGVrSERFY1dHMUw3OGs5NkpIc1AKNXRGS1B1ZmU5dGEzMkxackY4Q3U4ejdoWWNPMkIya2RJTlUwNzlrQ2dZQVVlTGVpWXNrdnJpSWlpVUd1d1JGawp0OGI1V0JVYmxxdXBPT080SGcxNEIyS3piVUkrRUJxZDFQWDVSQWxjYUFhYnNuVUhha1hpNCtvc0w5VkFzRkU1CjJZMG9RdzRWeHBZMy8zcVN6cTk2WHRiWWk4YXZJOTUxRWNtNUpHVjRkQUp1ZWxVN1NqY0cvQVB5dWFCLzM4OG0KSTdRbWVIaU5LcTJEdXZvejlleUVkUT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K +--- +apiVersion: pubsubplus.solace.com/v1beta1 +kind: PubSubPlusEventBroker +metadata: + name: loose-ha-scaling-parameters +spec: + timezone: UTC + systemScaling: + system_scaling_maxconnectioncount: 100 + system_scaling_maxqueuemessagecount: 240 + system_scaling_maxkafkabridgecount: 10 + system_scaling_maxkafkabrokerconnectioncount: 300 + system_scaling_maxbridgecount: 25 + system_scaling_maxsubscriptioncount: 90 + messagingNodeCpu: "2" + messagingNodeMemory: "535Mi" + storage: + messagingNodeStorageSize: "700MB" + redundancy: false + podDisruptionBudgetForHA: true + podLabels: + "DeploymentType": "HA" + "DeploymentTestMode": "ScalingParameters" + podAnnotations: + "DeploymentType": "HA" + "DeploymentTestMode": "ScalingParameters" + tls: + enabled: true + serverTlsConfigSecret: ha-scaling-parameters-tls + service: + type: LoadBalancer + monitoring: + enabled: true + image: + repository: ghcr.io/solacedev/pubsubplus-prometheus-exporter + pullPolicy: Always diff --git a/controllers/conditions.go b/controllers/conditions.go index 280c203..3657c5c 100644 --- a/controllers/conditions.go +++ b/controllers/conditions.go @@ -47,6 +47,7 @@ const ( ActivePodAndServiceExistsReason = "ActivePodAndServiceExists" MissingReadyPodReason = "MissingReadyPod" AtLeastOnePodPendingReason = "AtLeastOnePodPending" + ScalingParameterMisConfigurationReason = "ScalingParameterMisconfigured" ) // sets or updates a status condition using helper from meta diff --git a/controllers/controller_utils.go b/controllers/controller_utils.go index b2b6c11..fd05712 100644 --- a/controllers/controller_utils.go +++ b/controllers/controller_utils.go @@ -22,14 +22,13 @@ import ( "embed" "encoding/gob" "fmt" - "hash/crc64" - "strconv" - eventbrokerv1beta1 "github.com/SolaceProducts/pubsubplus-operator/api/v1beta1" + "hash/crc64" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "strconv" ) var ( @@ -82,6 +81,11 @@ func brokerSpecHash(s eventbrokerv1beta1.EventBrokerSpec) string { return hash(brokerSpecSubset.String()) } +func monitoringSpecHash(s eventbrokerv1beta1.EventBrokerSpec) string { + brokerSpecSubset := s.DeepCopy() + return hash(brokerSpecSubset.Monitoring.String()) +} + func brokerServiceHash(s eventbrokerv1beta1.EventBrokerSpec) string { brokerServiceSubset := s.Service.DeepCopy() return hash(brokerServiceSubset.String()) @@ -110,6 +114,10 @@ func brokerPodOutdated(pod *corev1.Pod, expectedBrokerSpecHash string, expectedT return result } +func brokerMonitoringOutdated(monitoring *appsv1.Deployment, expectedMonitoringSpecHash string) bool { + return monitoring.ObjectMeta.Annotations[monitoringSpecSignatureAnnotationName] != expectedMonitoringSpecHash +} + func convertToByteArray(e any) []byte { var network bytes.Buffer // Stand-in for a network connection enc := gob.NewEncoder(&network) // Will write to network. diff --git a/controllers/defaults.go b/controllers/defaults.go index 36a5173..721c5c8 100644 --- a/controllers/defaults.go +++ b/controllers/defaults.go @@ -26,6 +26,30 @@ const ( DefaultBrokerImageRepoOpenShift = "registry.connect.redhat.com/solace/pubsubplus-standard" DefaultBrokerImageTagOpenShift = "latest" - DefaultExporterImageRepoOpenShift = "registry.connect.redhat.com/solace/pubsubplus-prometheus-exporter" // TODO: update once published to public + DefaultExporterImageRepoOpenShift = "registry.connect.redhat.com/solace/pubsubplus-prometheus-exporter" DefaultExporterImageTagOpenShift = "latest" + + DefaultMonitorNodeCPURequests = "1" + DefaultMonitorNodeCPULimits = "1" + DefaultMonitorNodeMemoryRequests = "2Gi" + DefaultMonitorNodeMemoryLimits = "2Gi" + DefaultMonitorNodeMaxConnections = 100 + DefaultMonitorNodeMaxQueueMessages = 100 + DefaultMonitorNodeMaxSpoolUsage = 1000 + + DefaultMessagingNodeCPURequests = "2" + DefaultMessagingNodeCPULimits = "2" + DefaultMessagingNodeMemoryRequests = "4025Mi" + DefaultMessagingNodeMemoryLimits = "4025Mi" + DefaultMessagingNodeMaxConnections = 100 + DefaultMessagingNodeMaxQueueMessages = 100 + DefaultMessagingNodeMaxSpoolUsage = 10000 + + DefaultDeveloperModeCPURequests = "1" + DefaultDeveloperModeCPULimits = "2" + DefaultDeveloperModeMemoryRequests = "3410Mi" + DefaultDeveloperModeMemoryLimits = "3410Mi" + DefaultDeveloperModeMaxConnections = 100 + DefaultDeveloperModeMaxQueueMessages = 100 + DefaultDeveloperModeMaxSpoolUsage = 1000 ) diff --git a/controllers/eventbroker_controller.go b/controllers/eventbroker_controller.go index f6c2b19..3cd5a84 100644 --- a/controllers/eventbroker_controller.go +++ b/controllers/eventbroker_controller.go @@ -658,6 +658,7 @@ func (r *PubSubPlusEventBrokerReconciler) Reconcile(ctx context.Context, req ctr // Check and ensure setup if Prometheus Exporter is enabled prometheusExporterEnabled := pubsubpluseventbroker.Spec.Monitoring.Enabled + monitoringSpecHash := monitoringSpecHash(pubsubpluseventbroker.Spec) prometheusExporterSvc := &corev1.Service{} prometheusExporterDeployment := &appsv1.Deployment{} if prometheusExporterEnabled { @@ -709,6 +710,29 @@ func (r *PubSubPlusEventBrokerReconciler) Reconcile(ctx context.Context, req ctr r.SetCondition(ctx, log, pubsubpluseventbroker, MonitoringReadyCondition, metav1.ConditionTrue, MonitoringReadyReason, "All checks passed") } + // Check and address if monitoring require update + if brokerMonitoringOutdated(prometheusExporterDeployment, monitoringSpecHash) { + log.Info("Updating existing Prometheus Exporter Deployment", "Deployment.Namespace", prometheusExporterDeployment.Namespace, "Deployment.Name", prometheusExporterDeployment.Name) + prometheusExporterDeploymentName := getObjectName("PrometheusExporterDeployment", pubsubpluseventbroker.Name) + err := r.Get(ctx, types.NamespacedName{Name: prometheusExporterDeploymentName, Namespace: pubsubpluseventbroker.Namespace}, prometheusExporterDeployment) + if err != nil { + log.Info("Prometheus Exporter Deployment resource not found. Ignoring since object must be deleted") + } else { + if prometheusExporterDeployment.ObjectMeta.DeletionTimestamp == nil { + log.Info("Deleting outdated Prometheus Exporter Deployment", "Deployment.Namespace", prometheusExporterDeployment.Namespace, "Deployment.Name", prometheusExporterDeployment.Name) + + err := r.Delete(ctx, prometheusExporterDeployment, client.PropagationPolicy(metav1.DeletePropagationForeground)) + if err != nil { + r.recordErrorState(ctx, log, pubsubpluseventbroker, err, ResourceErrorReason, "Failed to delete outdated Prometheus Exporter Deployment", "Deployment.Namespace", prometheusExporterDeployment.Namespace, "Deployment.Name", prometheusExporterDeployment.Name) + return ctrl.Result{}, err + } + // Prometheus Exporter Deployment deleted successfully - return and requeue + r.emitResourceRestartEvent(pubsubpluseventbroker, "Prometheus Exporter Deployment", prometheusExporterDeployment.Name) + return ctrl.Result{RequeueAfter: time.Duration(3) * time.Second}, nil + } + } + } + // Now update elements of the PubSubPlusEventBroker deployment status; fetch the latest as needed err = r.Get(ctx, req.NamespacedName, pubsubpluseventbroker) if err != nil { diff --git a/controllers/namings.go b/controllers/namings.go index 835e61a..6c70bcd 100644 --- a/controllers/namings.go +++ b/controllers/namings.go @@ -24,19 +24,35 @@ import ( ) const ( - brokerSpecSignatureAnnotationName = "lastAppliedConfig/brokerSpec" - brokerServiceSignatureAnnotationName = "lastAppliedConfig/brokerService" - tlsSecretSignatureAnnotationName = "lastAppliedConfig/tlsSecret" - appKubernetesIoNameLabel = "pubsubpluseventbroker" - appKubernetesIoManagedByLabel = "solace-pubsubplus-operator" - maintenanceLabel = "solace.com/pauseReconcile" - secretKeyName = "username_admin_password" - monitorSecretKeyName = "username_monitor_password" - preSharedAuthKeyName = "preshared_auth_key" - tcpSempPortName = "tcp-semp" - tlsSempPortName = "tls-semp" - brokerNodeComponent = "brokernode" - metricsExporterComponent = "metricsexporter" + brokerSpecSignatureAnnotationName = "lastAppliedConfig/brokerSpec" + brokerServiceSignatureAnnotationName = "lastAppliedConfig/brokerService" + tlsSecretSignatureAnnotationName = "lastAppliedConfig/tlsSecret" + monitoringSpecSignatureAnnotationName = "lastAppliedConfig/monitoringSpec" + appKubernetesIoNameLabel = "pubsubpluseventbroker" + appKubernetesIoManagedByLabel = "solace-pubsubplus-operator" + maintenanceLabel = "solace.com/pauseReconcile" + secretKeyName = "username_admin_password" + monitorSecretKeyName = "username_monitor_password" + preSharedAuthKeyName = "preshared_auth_key" + tcpSempPortName = "tcp-semp" + tlsSempPortName = "tls-semp" + brokerNodeComponent = "brokernode" + metricsExporterComponent = "metricsexporter" + scalingParameterPrefix = "system_scaling_" + scalingParameterSpoolPrefix = "messagespool_" + scalingParameterMaxConnectionCount = "system_scaling_maxconnectioncount" + scalingParameterMaxQueueCount = "system_scaling_maxqueuemessagecount" + scalingParameterMaxSpoolUsage = "messagespool_maxspoolusage" + monitoringExporterIncludeRates = "SOLACE_INCLUDE_RATES" + monitoringExporterListenTLS = "SOLACE_LISTEN_TLS" + monitoringExporterBrokerUsername = "SOLACE_USERNAME" + monitoringExporterBrokerPassword = "SOLACE_PASSWORD" + monitoringExporterScrapeURI = "SOLACE_SCRAPE_URI" + monitoringExporterScrapeTimeout = "SOLACE_SCRAPE_TIMEOUT" + monitoringExporterPrivateKey = "SOLACE_PRIVATE_KEY" + monitoringExporterServerCert = "SOLACE_SERVER_CERT" + monitoringExporterSSLVerify = "SOLACE_SSL_VERIFY" + monitoringExporterListenAddress = "SOLACE_WEB_LISTEN_ADDRESS" ) type BrokerRole int // Notice that this is about the current role, not the broker node designation diff --git a/controllers/prometheus_exporter.go b/controllers/prometheus_exporter.go index e27c322..e9ebc3c 100644 --- a/controllers/prometheus_exporter.go +++ b/controllers/prometheus_exporter.go @@ -29,99 +29,113 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ) -func (r *PubSubPlusEventBrokerReconciler) newDeploymentForPrometheusExporter(name string, monitoringSecret *corev1.Secret, m *eventbrokerv1beta1.PubSubPlusEventBroker) *appsv1.Deployment { - dep := &appsv1.Deployment{ +func (r *PubSubPlusEventBrokerReconciler) newDeploymentForPrometheusExporter(monitoringDeploymentName string, monitoringSecret *corev1.Secret, m *eventbrokerv1beta1.PubSubPlusEventBroker) *appsv1.Deployment { + monitoringDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: name, + Name: monitoringDeploymentName, Namespace: m.Namespace, Labels: getObjectLabels(m.Name), }, - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: getMonitoringDeploymentSelector(m.Name), + } + r.updateDeploymentForPrometheusExporter(monitoringDeployment, monitoringSecret, m) + // Set PubSubPlusEventBroker instance as the owner and controller + ctrl.SetControllerReference(m, monitoringDeployment, r.Scheme) + return monitoringDeployment +} + +func (r *PubSubPlusEventBrokerReconciler) updateDeploymentForPrometheusExporter(monitoringDeployment *appsv1.Deployment, monitoringSecret *corev1.Secret, eventBroker *eventbrokerv1beta1.PubSubPlusEventBroker) *appsv1.Deployment { + if monitoringDeployment.Annotations == nil { + monitoringDeployment.Annotations = map[string]string{} + } + monitoringDeployment.Annotations[monitoringSpecSignatureAnnotationName] = monitoringSpecHash(eventBroker.Spec) + monitoringDeployment.Spec = appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: getMonitoringDeploymentSelector(eventBroker.Name), + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: getMonitoringDeploymentSelector(eventBroker.Name), }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: getMonitoringDeploymentSelector(m.Name), - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "exporter", - Image: r.getExporterImageDetails(m.Spec.Monitoring.MonitoringImage), - ImagePullPolicy: getExporterImagePullPolicy(m.Spec.Monitoring.MonitoringImage), - Ports: []corev1.ContainerPort{{ - Name: getExporterHttpProtocolType(&m.Spec.Monitoring), - ContainerPort: getExporterContainerPort(&m.Spec.Monitoring), - }}, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "exporter", + Image: r.getExporterImageDetails(eventBroker.Spec.Monitoring.MonitoringImage), + ImagePullPolicy: getExporterImagePullPolicy(eventBroker.Spec.Monitoring.MonitoringImage), + Ports: []corev1.ContainerPort{{ + Name: getExporterHttpProtocolType(&eventBroker.Spec.Monitoring), + ContainerPort: getExporterContainerPort(&eventBroker.Spec.Monitoring), + }}, - Env: []corev1.EnvVar{ - { - Name: "SOLACE_WEB_LISTEN_ADDRESS", - Value: fmt.Sprintf("%s://%s.%s.svc.cluster.local:%d", getExporterHttpProtocolType(&m.Spec.Monitoring), getObjectName("PrometheusExporterService", m.Name), m.Namespace, getExporterContainerPort(&m.Spec.Monitoring)), - }, - { - Name: "SOLACE_SCRAPE_URI", - Value: fmt.Sprintf("%s://%s.%s.svc.cluster.local:%d", getPubSubPlusEventBrokerProtocol(&m.Spec), getObjectName("BrokerService", m.Name), m.Namespace, getPubSubPlusEventBrokerPort(&m.Spec.Service, &m.Spec.BrokerTLS)), - }, - { - Name: "SOLACE_LISTEN_TLS", - Value: getExporterTLSConfiguration(&m.Spec.Monitoring), - }, - { - Name: "SOLACE_USERNAME", - Value: "monitor", - }, - { - Name: "SOLACE_PASSWORD", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: monitoringSecret.Name, - }, - Key: monitorSecretKeyName, + Env: []corev1.EnvVar{ + { + Name: monitoringExporterListenAddress, + Value: fmt.Sprintf("%s://%s.%s.svc.cluster.local:%d", getExporterHttpProtocolType(&eventBroker.Spec.Monitoring), getObjectName("PrometheusExporterService", eventBroker.Name), eventBroker.Namespace, getExporterContainerPort(&eventBroker.Spec.Monitoring)), + }, + { + Name: monitoringExporterScrapeURI, + Value: fmt.Sprintf("%s://%s.%s.svc.cluster.local:%d", getPubSubPlusEventBrokerProtocol(&eventBroker.Spec), getObjectName("BrokerService", eventBroker.Name), eventBroker.Namespace, getPubSubPlusEventBrokerPort(&eventBroker.Spec.Service, &eventBroker.Spec.BrokerTLS)), + }, + { + Name: monitoringExporterListenTLS, + Value: getExporterTLSConfiguration(&eventBroker.Spec.Monitoring), + }, + { + Name: monitoringExporterBrokerUsername, + Value: "monitor", + }, + { + Name: monitoringExporterBrokerPassword, + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: monitoringSecret.Name, }, + Key: monitorSecretKeyName, }, }, - { - Name: "SOLACE_SCRAPE_TIMEOUT", - Value: fmt.Sprint(m.Spec.Monitoring.TimeOut) + "s", - }, - { - Name: "SOLACE_SSL_VERIFY", - Value: strconv.FormatBool(m.Spec.Monitoring.SSLVerify), - }, - { - Name: "SOLACE_INCLUDE_RATES", - Value: strconv.FormatBool(m.Spec.Monitoring.IncludeRates), - }, }, - SecurityContext: &corev1.SecurityContext{ - Privileged: &[]bool{false}[0], // Set to false - Capabilities: &corev1.Capabilities{ - Drop: []corev1.Capability{ - corev1.Capability("ALL"), - }, - }, - RunAsNonRoot: &[]bool{true}[0], // Set to true - AllowPrivilegeEscalation: &[]bool{false}[0], // Set to false - SeccompProfile: &corev1.SeccompProfile{ - Type: corev1.SeccompProfileTypeRuntimeDefault, + { + Name: monitoringExporterScrapeTimeout, + Value: fmt.Sprint(eventBroker.Spec.Monitoring.TimeOut) + "s", + }, + { + Name: monitoringExporterSSLVerify, + Value: strconv.FormatBool(eventBroker.Spec.Monitoring.SSLVerify), + }, + { + Name: monitoringExporterIncludeRates, + Value: strconv.FormatBool(eventBroker.Spec.Monitoring.IncludeRates), + }, + }, + SecurityContext: &corev1.SecurityContext{ + Privileged: &[]bool{false}[0], // Set to false + Capabilities: &corev1.Capabilities{ + Drop: []corev1.Capability{ + corev1.Capability("ALL"), }, }, + RunAsNonRoot: &[]bool{true}[0], // Set to true + AllowPrivilegeEscalation: &[]bool{false}[0], // Set to false + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + }, }, }, - ImagePullSecrets: getExporterImagePullSecrets(m.Spec.Monitoring.MonitoringImage), }, + ImagePullSecrets: getExporterImagePullSecrets(eventBroker.Spec.Monitoring.MonitoringImage), }, }, + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + }, } // OpenShift and namespace must be considered for RunAsUser // Only set it if not on OpenShift or using the "default" namespace // otherwise leave it undefined - if !r.IsOpenShift || m.Namespace == corev1.NamespaceDefault { - dep.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{ + if !r.IsOpenShift || eventBroker.Namespace == corev1.NamespaceDefault { + monitoringDeployment.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{ RunAsUser: &[]int64{10001}[0], RunAsGroup: &[]int64{10001}[0], FSGroup: &[]int64{10002}[0], @@ -129,53 +143,74 @@ func (r *PubSubPlusEventBrokerReconciler) newDeploymentForPrometheusExporter(nam } //Set TLS configuration - if m.Spec.Monitoring.MonitoringMetricsEndpoint != nil && len(strings.TrimSpace(m.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTLSConfigSecret)) > 0 { - allVolumes := dep.Spec.Template.Spec.Volumes + if eventBroker.Spec.Monitoring.MonitoringMetricsEndpoint != nil && len(strings.TrimSpace(eventBroker.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTLSConfigSecret)) > 0 { + allVolumes := monitoringDeployment.Spec.Template.Spec.Volumes allVolumes = append(allVolumes, corev1.Volume{ Name: "server-certs", VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: m.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTLSConfigSecret, + SecretName: eventBroker.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTLSConfigSecret, DefaultMode: &[]int32{0400}[0], }, }, }) - allContainerVolumeMounts := dep.Spec.Template.Spec.Containers[0].VolumeMounts + allContainerVolumeMounts := monitoringDeployment.Spec.Template.Spec.Containers[0].VolumeMounts allContainerVolumeMounts = append(allContainerVolumeMounts, corev1.VolumeMount{ Name: "server-certs", MountPath: "/mnt/disks/solace", ReadOnly: true, }) - allEnv := dep.Spec.Template.Spec.Containers[0].Env + allEnv := monitoringDeployment.Spec.Template.Spec.Containers[0].Env allEnv = append(allEnv, corev1.EnvVar{ - Name: "SOLACE_SERVER_CERT", - Value: "/mnt/disks/solace/" + m.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTlsConfigServerCertName, + Name: monitoringExporterServerCert, + Value: "/mnt/disks/solace/" + eventBroker.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTlsConfigServerCertName, }) allEnv = append(allEnv, corev1.EnvVar{ - Name: "SOLACE_PRIVATE_KEY", - Value: "/mnt/disks/solace/" + m.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTlsConfigPrivateKeyName, + Name: monitoringExporterPrivateKey, + Value: "/mnt/disks/solace/" + eventBroker.Spec.Monitoring.MonitoringMetricsEndpoint.EndpointTlsConfigPrivateKeyName, }) - dep.Spec.Template.Spec.Containers[0].Env = allEnv - dep.Spec.Template.Spec.Volumes = allVolumes - dep.Spec.Template.Spec.Containers[0].VolumeMounts = allContainerVolumeMounts + monitoringDeployment.Spec.Template.Spec.Containers[0].Env = allEnv + monitoringDeployment.Spec.Template.Spec.Volumes = allVolumes + monitoringDeployment.Spec.Template.Spec.Containers[0].VolumeMounts = allContainerVolumeMounts } else { - allEnv := dep.Spec.Template.Spec.Containers[0].Env + allEnv := monitoringDeployment.Spec.Template.Spec.Containers[0].Env allEnv = append(allEnv, corev1.EnvVar{ - Name: "SOLACE_SERVER_CERT", - Value: ".", //This is a mandatory parameter. + Name: monitoringExporterServerCert, + Value: ".", //This is a mandatory parameter for older versions of the exporter. }) allEnv = append(allEnv, corev1.EnvVar{ - Name: "SOLACE_PRIVATE_KEY", - Value: ".", //This is a mandatory parameter. + Name: monitoringExporterPrivateKey, + Value: ".", //This is a mandatory parameter for older versions of the exporter. }) - dep.Spec.Template.Spec.Containers[0].Env = allEnv + monitoringDeployment.Spec.Template.Spec.Containers[0].Env = allEnv } - // Set PubSubPlusEventBroker instance as the owner and controller - ctrl.SetControllerReference(m, dep, r.Scheme) - return dep + //Set Extra environment variables + if len(eventBroker.Spec.Monitoring.ExtraEnvVars) > 0 { + allEnv := monitoringDeployment.Spec.Template.Spec.Containers[0].Env + for _, envV := range eventBroker.Spec.Monitoring.ExtraEnvVars { + if strings.ToUpper(envV.Name) != monitoringExporterIncludeRates && + strings.ToUpper(envV.Name) != monitoringExporterPrivateKey && + strings.ToUpper(envV.Name) != monitoringExporterServerCert && + strings.ToUpper(envV.Name) != monitoringExporterBrokerUsername && + strings.ToUpper(envV.Name) != monitoringExporterBrokerPassword && + strings.ToUpper(envV.Name) != monitoringExporterListenAddress && + strings.ToUpper(envV.Name) != monitoringExporterListenTLS && + strings.ToUpper(envV.Name) != monitoringExporterScrapeTimeout && + strings.ToUpper(envV.Name) != monitoringExporterScrapeURI && + strings.ToUpper(envV.Name) != monitoringExporterSSLVerify { + allEnv = append(allEnv, corev1.EnvVar{ + Name: envV.Name, + Value: envV.Value, + }) + } + } + monitoringDeployment.Spec.Template.Spec.Containers[0].Env = allEnv + } + + return monitoringDeployment } func (r *PubSubPlusEventBrokerReconciler) newServiceForPrometheusExporter(exporter *eventbrokerv1beta1.Monitoring, svcName string, m *eventbrokerv1beta1.PubSubPlusEventBroker) *corev1.Service { diff --git a/controllers/statefulset.go b/controllers/statefulset.go index e87020a..f76259f 100644 --- a/controllers/statefulset.go +++ b/controllers/statefulset.go @@ -19,6 +19,8 @@ package controllers import ( "context" "encoding/json" + "fmt" + ctrllog "sigs.k8s.io/controller-runtime/pkg/log" "strconv" "strings" @@ -40,7 +42,8 @@ func (r *PubSubPlusEventBrokerReconciler) createStatefulsetForEventBroker(stsNam // Determine broker sizing var storageSize string if nodeType == "monitor" { - if len(strings.TrimSpace(m.Spec.Storage.MonitorNodeStorageSize)) == 0 || m.Spec.Storage.MonitorNodeStorageSize == "0" { + monitorNodeSize := strings.TrimSpace(m.Spec.Storage.MonitorNodeStorageSize) + if len(strings.TrimSpace(monitorNodeSize)) == 0 || monitorNodeSize == "0" { storageSize = "3Gi" } else { storageSize = m.Spec.Storage.MonitorNodeStorageSize @@ -70,6 +73,9 @@ func (r *PubSubPlusEventBrokerReconciler) createStatefulsetForEventBroker(stsNam } if len(m.Spec.Storage.CustomVolumeMount) == 0 && !usesEphemeralStorageForMonitoringNode(&m.Spec.Storage, nodeType) && !usesEphemeralStorageForMessageNode(&m.Spec.Storage, nodeType) { + if strings.Contains(storageSize, "B") { + storageSize = strings.Replace(storageSize, "B", "", -1) + } dep.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{ { ObjectMeta: metav1.ObjectMeta{ @@ -107,31 +113,30 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a haDeployment := m.Spec.Redundancy stsName := sts.ObjectMeta.Name nodeType := getBrokerNodeType(stsName) + log := ctrllog.FromContext(ctx) // Determine broker sizing var cpuRequests, cpuLimits string var memRequests, memLimits string var maxConnections, maxQueueMessages, maxSpoolUsage int - // TODO: _types.go has already defaults. Review if those indeed need to be duplicated here. - // TODO: remove any hardcoded values - at a minimum move it to the beginning of this code file if nodeType == "monitor" { - cpuRequests = "1" - cpuLimits = "1" - memRequests = "2Gi" - memLimits = "2Gi" - maxConnections = 100 - maxQueueMessages = 100 - maxSpoolUsage = 1000 + cpuRequests = DefaultMonitorNodeCPURequests + cpuLimits = DefaultMonitorNodeCPULimits + memRequests = DefaultMonitorNodeMemoryRequests + memLimits = DefaultMonitorNodeMemoryLimits + maxConnections = DefaultMonitorNodeMaxConnections + maxQueueMessages = DefaultMonitorNodeMaxQueueMessages + maxSpoolUsage = DefaultMonitorNodeMaxSpoolUsage } else { // First determine default settings for the message routing broker nodes, depending on developer mode set // refer to https://docs.solace.com/Admin-Ref/Resource-Calculator/pubsubplus-resource-calculator.html - cpuRequests = (map[bool]string{true: "1", false: "2"})[m.Spec.Developer] - cpuLimits = (map[bool]string{true: "2", false: "2"})[m.Spec.Developer] - memRequests = (map[bool]string{true: "3410Mi", false: "4025Mi"})[m.Spec.Developer] - memLimits = (map[bool]string{true: "3410Mi", false: "4025Mi"})[m.Spec.Developer] - maxConnections = (map[bool]int{true: 100, false: 100})[m.Spec.Developer] - maxQueueMessages = (map[bool]int{true: 100, false: 100})[m.Spec.Developer] - maxSpoolUsage = (map[bool]int{true: 1000, false: 10000})[m.Spec.Developer] + cpuRequests = (map[bool]string{true: DefaultDeveloperModeCPURequests, false: DefaultMessagingNodeCPURequests})[m.Spec.Developer] + cpuLimits = (map[bool]string{true: DefaultDeveloperModeCPULimits, false: DefaultMessagingNodeCPULimits})[m.Spec.Developer] + memRequests = (map[bool]string{true: DefaultDeveloperModeMemoryRequests, false: DefaultMessagingNodeMemoryRequests})[m.Spec.Developer] + memLimits = (map[bool]string{true: DefaultDeveloperModeMemoryLimits, false: DefaultMessagingNodeMemoryLimits})[m.Spec.Developer] + maxConnections = (map[bool]int{true: DefaultDeveloperModeMaxConnections, false: DefaultMessagingNodeMaxConnections})[m.Spec.Developer] + maxQueueMessages = (map[bool]int{true: DefaultDeveloperModeMaxQueueMessages, false: DefaultMessagingNodeMaxQueueMessages})[m.Spec.Developer] + maxSpoolUsage = (map[bool]int{true: DefaultDeveloperModeMaxSpoolUsage, false: DefaultMessagingNodeMaxSpoolUsage})[m.Spec.Developer] // Overwrite for any values defined in spec.systemScaling if m.Spec.SystemScaling != nil && !m.Spec.Developer { if m.Spec.SystemScaling.MessagingNodeCpu != "" { @@ -190,6 +195,7 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a Annotations: podAnnotations, }, Spec: corev1.PodSpec{ + EnableServiceLinks: &m.Spec.EnableServiceLinks, Containers: []corev1.Container{ { Name: "pubsubplus", @@ -227,18 +233,6 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a Name: "BROKERSERVICES_NAME", Value: brokerServicesName, }, - { - Name: "BROKER_MAXCONNECTIONCOUNT", - Value: strconv.Itoa(maxConnections), - }, - { - Name: "BROKER_MAXQUEUEMESSAGECOUNT", - Value: strconv.Itoa(maxQueueMessages), - }, - { - Name: "BROKER_MAXSPOOLUSAGE", - Value: strconv.Itoa(maxSpoolUsage), - }, { Name: "BROKER_TLS_ENABLED", Value: strconv.FormatBool(m.Spec.BrokerTLS.Enabled), @@ -305,7 +299,7 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a Privileged: &[]bool{false}[0], // Set to false Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{ - corev1.Capability("ALL"), + "ALL", }, }, RunAsNonRoot: &[]bool{true}[0], // Set to true @@ -347,7 +341,6 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a RestartPolicy: corev1.RestartPolicyAlways, TerminationGracePeriodSeconds: &[]int64{1200}[0], // 1200 ServiceAccountName: sa.Name, - // NodeName: "", Volumes: []corev1.Volume{ { Name: "podinfo", @@ -403,10 +396,13 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a }, }, }, + SecurityContext: &corev1.PodSecurityContext{ + RunAsNonRoot: &[]bool{true}[0], // Set to true + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + }, + }, ImagePullSecrets: m.Spec.BrokerImage.ImagePullSecrets, - // SchedulerName: "", - // Tolerations: []corev1.Toleration{}, - // TopologySpreadConstraints: []corev1.TopologySpreadConstraint{}, }, } @@ -435,7 +431,6 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a // Set pod security context // Following cases are distinguished for RunAsUser and FSGroup: 1) if value not specified AND in OpenShift env AND using non-default namespace, then leave it to unspecified // 2) value not specified or using default namespace: set to default 3) value specified, then set to value. - sts.Spec.Template.Spec.SecurityContext = &corev1.PodSecurityContext{} // Set RunAsUser if m.Spec.SecurityContext.RunAsUser == 0 { // not specified case @@ -455,6 +450,28 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a sts.Spec.Template.Spec.SecurityContext.FSGroup = &m.Spec.SecurityContext.FSGroup } + // Set container security context + // Following cases are distinguished for RunAsUser and RunAsGroup: 1) if value not specified AND in OpenShift env AND using non-default namespace, then leave it to unspecified + // 2) value not specified or using default namespace: set to default 3) value specified, then set to value. + // Set containerSecurityRunAsUser + if m.Spec.BrokerSecurityContext.RunAsUser == 0 { + // not specified case + if !r.IsOpenShift || sts.ObjectMeta.Namespace == corev1.NamespaceDefault { + sts.Spec.Template.Spec.Containers[0].SecurityContext.RunAsUser = &[]int64{1000001}[0] + } // else in OpenShift env AND using non-default namespace so leave it undefined + } else { + sts.Spec.Template.Spec.Containers[0].SecurityContext.RunAsUser = &m.Spec.BrokerSecurityContext.RunAsUser + } + // Set containerSecurityRunAsGroup + if m.Spec.BrokerSecurityContext.RunAsGroup == 0 { + // not specified case + if !r.IsOpenShift || sts.ObjectMeta.Namespace == corev1.NamespaceDefault { + sts.Spec.Template.Spec.Containers[0].SecurityContext.RunAsGroup = &[]int64{1000002}[0] + } // else in OpenShift env AND using non-default namespace so leave it undefined + } else { + sts.Spec.Template.Spec.Containers[0].SecurityContext.RunAsGroup = &m.Spec.BrokerSecurityContext.RunAsGroup + } + //Set TLS configuration if m.Spec.BrokerTLS.Enabled { allVolumes := sts.Spec.Template.Spec.Volumes @@ -619,6 +636,84 @@ func (r *PubSubPlusEventBrokerReconciler) updateStatefulsetForEventBroker(sts *a sts.Spec.Template.Spec.Tolerations = tolerationConfiguration } + //Set unknown scaling parameter values + if m.Spec.SystemScaling != nil { + var err error + var scalingParamMap map[string]interface{} + inrec, _ := json.Marshal(m.Spec.SystemScaling) + json.Unmarshal(inrec, &scalingParamMap) + allEnv := sts.Spec.Template.Spec.Containers[0].Env + for key, val := range scalingParamMap { + if strings.HasPrefix(strings.ToLower(key), scalingParameterPrefix) || strings.HasPrefix(strings.ToLower(key), scalingParameterSpoolPrefix) { + log.V(1).Info("Detected Scaling Parameter ", " pubsubpluseventbroker.scalingParameter", key) + value := fmt.Sprint(val) + if strings.ToLower(scalingParameterMaxConnectionCount) == strings.ToLower(key) { + maxConnections, err = strconv.Atoi(value) + if maxConnections == 0 || err != nil { + maxConnections = DefaultMessagingNodeMaxConnections + r.recordErrorState(ctx, log, m, err, ScalingParameterMisConfigurationReason, "Failed to read Scaling Parameter '"+key+"'. Using default", "Namespace", m.Namespace, "Name", m.Name) + } + } else if strings.ToLower(scalingParameterMaxQueueCount) == strings.ToLower(key) { + maxQueueMessages, err = strconv.Atoi(value) + if maxQueueMessages == 0 || err != nil { + maxQueueMessages = DefaultMessagingNodeMaxQueueMessages + r.recordErrorState(ctx, log, m, err, ScalingParameterMisConfigurationReason, "Failed to read Scaling Parameter '"+key+"'. Using default", "Namespace", m.Namespace, "Name", m.Name) + } + } else if strings.ToLower(scalingParameterMaxSpoolUsage) == strings.ToLower(key) { + maxSpoolUsage, err = strconv.Atoi(value) + if maxSpoolUsage == 0 || err != nil { + maxSpoolUsage = DefaultMessagingNodeMaxSpoolUsage + r.recordErrorState(ctx, log, m, err, ScalingParameterMisConfigurationReason, "Failed to read Scaling Parameter '"+key+"'. Using default", "Namespace", m.Namespace, "Name", m.Name) + } + } else { + allEnv = append(allEnv, corev1.EnvVar{ + Name: strings.ToUpper(key), + Value: value, + }) + } + } + } + sts.Spec.Template.Spec.Containers[0].Env = allEnv + } + + //set init scaling parameters + allEnv := sts.Spec.Template.Spec.Containers[0].Env + + envMap := make(map[string]corev1.EnvVar) + for _, envVar := range allEnv { + envMap[strings.ToUpper(envVar.Name)] = envVar + } + + uniqueEnvVars := make([]corev1.EnvVar, 0, len(envMap)) + for _, envVar := range envMap { + uniqueEnvVars = append(uniqueEnvVars, envVar) + } + + filteredEnv := []corev1.EnvVar{} + for _, envVar := range uniqueEnvVars { + envVarNameLower := strings.ToLower(envVar.Name) + if envVarNameLower != scalingParameterMaxSpoolUsage && + envVarNameLower != scalingParameterMaxConnectionCount && + envVarNameLower != scalingParameterMaxQueueCount { + filteredEnv = append(filteredEnv, envVar) + } + } + allEnv = filteredEnv + + allEnv = append(allEnv, + corev1.EnvVar{ + Name: "BROKER_MAXCONNECTIONCOUNT", + Value: strconv.Itoa(maxConnections), + }, + corev1.EnvVar{ + Name: "BROKER_MAXQUEUEMESSAGECOUNT", + Value: strconv.Itoa(maxQueueMessages), + }, + corev1.EnvVar{ + Name: "BROKER_MAXSPOOLUSAGE", + Value: strconv.Itoa(maxSpoolUsage), + }) + sts.Spec.Template.Spec.Containers[0].Env = allEnv } func (r *PubSubPlusEventBrokerReconciler) getBrokerImageDetails(bm *eventbrokerv1beta1.BrokerImage) string { @@ -641,10 +736,11 @@ func getTimezone(tz string) string { } func getBrokerMessageNodeStorageSize(st *eventbrokerv1beta1.Storage) string { - if st == nil || len(strings.TrimSpace(st.MessagingNodeStorageSize)) == 0 || st.MessagingNodeStorageSize == "0" { + messagingNodeSize := strings.TrimSpace(st.MessagingNodeStorageSize) + if st == nil || len(messagingNodeSize) == 0 || messagingNodeSize == "0" { return "30Gi" } - return st.MessagingNodeStorageSize + return messagingNodeSize } func getNodeAffinityDetails(na []eventbrokerv1beta1.NodeAssignment, nodeType string) *corev1.Affinity { diff --git a/deploy/deploy.yaml b/deploy/deploy.yaml index 974c4f0..6fe71fb 100644 --- a/deploy/deploy.yaml +++ b/deploy/deploy.yaml @@ -54,12 +54,35 @@ spec: When provided, ensure the secret key name is `username_admin_password`. For valid values refer to the Solace documentation https://docs.solace.com/Admin/Configuring-Internal-CLI-User-Accounts.htm. nullable: true type: string + brokerContainerSecurity: + description: ContainerSecurityContext defines the container security + context for the PubSubPlusEventBroker. + properties: + runAsGroup: + description: Specifies runAsGroup in container security context. + 0 or unset defaults either to 1000002, or if OpenShift detected + to unspecified (see documentation) + format: int64 + type: number + runAsUser: + description: Specifies runAsUser in container security context. + 0 or unset defaults either to 1000001, or if OpenShift detected + to unspecified (see documentation) + format: int64 + type: number + type: object developer: default: false description: |- Developer true specifies a minimum footprint scaled-down deployment, not for production use. If set to true it overrides SystemScaling parameters. type: boolean + enableServiceLinks: + default: false + description: |- + EnableServiceLinks indicates whether information about services should be injected into pod's environment + variables, matching the syntax of Docker links. Optional: Defaults to false. + type: boolean extraEnvVars: description: |- List of extra environment variables to be added to the PubSubPlusEventBroker container. Note: Do not configure Timezone or SystemScaling parameters here as it could cause unintended consequences. @@ -137,6 +160,26 @@ spec: description: Enabled true enables the setup of the Prometheus Exporter. type: boolean + extraEnvVars: + description: List of extra environment variables to be added to + the Prometheus Exporter container. + items: + description: MonitoringExtraEnvVar defines environment variables + to be added to the Prometheus Exporter container for Monitoring + properties: + name: + description: Specifies the Name of an environment variable + to be added to the Prometheus Exporter container for Monitoring + type: string + value: + description: Specifies the Value of an environment variable + to be added to the Prometheus Exporter container for Monitoring + type: string + required: + - name + - value + type: object + type: array image: description: Image defines container image parameters for the Prometheus Exporter. @@ -1459,23 +1502,8 @@ spec: description: |- SystemScaling provides exact fine-grained specification of the event broker scaling parameters and the assigned CPU / memory resources to the Pod. - properties: - maxConnections: - default: 100 - type: integer - maxQueueMessages: - default: 100 - type: integer - maxSpoolUsage: - default: 1000 - type: integer - messagingNodeCpu: - default: "2" - type: string - messagingNodeMemory: - default: 4025Mi - type: string type: object + x-kubernetes-preserve-unknown-fields: true timezone: default: UTC description: Defines the timezone for the event broker container, @@ -1903,7 +1931,7 @@ spec: env: - name: WATCH_NAMESPACE value: "" - image: docker.io/solace/pubsubplus-eventbroker-operator:1.0.3 + image: docker.io/solace/pubsubplus-eventbroker-operator:1.1.0 imagePullPolicy: Always livenessProbe: httpGet: diff --git a/docs/EventBrokerOperatorParametersReference.md b/docs/EventBrokerOperatorParametersReference.md index 4de2327..bca81a6 100644 --- a/docs/EventBrokerOperatorParametersReference.md +++ b/docs/EventBrokerOperatorParametersReference.md @@ -91,6 +91,13 @@ EventBrokerSpec defines the desired state of PubSubPlusEventBroker When provided, ensure the secret key name is `username_admin_password`. For valid values refer to the Solace documentation https://docs.solace.com/Admin/Configuring-Internal-CLI-User-Accounts.htm.
false + + brokerContainerSecurity + object + + ContainerSecurityContext defines the container security context for the PubSubPlusEventBroker.
+ + false developer boolean @@ -101,6 +108,16 @@ If set to true it overrides SystemScaling parameters.
Default: false
false + + enableServiceLinks + boolean + + EnableServiceLinks indicates whether information about services should be injected into pod's environment +variables, matching the syntax of Docker links. Optional: Defaults to false.
+
+ Default: false
+ + false extraEnvVars []object @@ -263,6 +280,44 @@ and the assigned CPU / memory resources to the Pod.
+### PubSubPlusEventBroker.spec.brokerContainerSecurity +[↩ Parent](#pubsubpluseventbrokerspec) + + + +ContainerSecurityContext defines the container security context for the PubSubPlusEventBroker. + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
runAsGroupnumber + Specifies runAsGroup in container security context. 0 or unset defaults either to 1000002, or if OpenShift detected to unspecified (see documentation)
+
+ Format: int64
+
false
runAsUsernumber + Specifies runAsUser in container security context. 0 or unset defaults either to 1000001, or if OpenShift detected to unspecified (see documentation)
+
+ Format: int64
+
false
+ + ### PubSubPlusEventBroker.spec.extraEnvVars[index] [↩ Parent](#pubsubpluseventbrokerspec) diff --git a/docs/EventBrokerOperatorUserGuide.md b/docs/EventBrokerOperatorUserGuide.md index 84ee584..7c53389 100644 --- a/docs/EventBrokerOperatorUserGuide.md +++ b/docs/EventBrokerOperatorUserGuide.md @@ -31,8 +31,7 @@ __Contents:__ - [Pulling images from a private registry](#pulling-images-from-a-private-registry) - [Broker Scaling](#broker-scaling) - [Vertical Scaling](#vertical-scaling) - - [Minimum footprint deployment for Developers](#minimum-footprint-deployment-for-developers) - - [Forward Compatibility for Vertical Scaling](#forward-compatibility-for-vertical-scaling) + - [Minimum footprint deployment for Developers](#minimum-footprint-deployment-for-developers) - [Storage](#storage) - [Dynamically allocated storage from a Storage Class](#dynamically-allocated-storage-from-a-storage-class) - [Using an existing Storage Class](#using-an-existing-storage-class) @@ -305,7 +304,10 @@ spec: >Note: Beyond CPU and memory requirements, broker storage size (see [Storage](#storage) section) must also support the provided scaling. The calculator can be used to determine that as well. -Also note, that specifying maxConnections, maxQueueMessages, and maxSpoolUsage on initial deployment overwrites the broker’s default values. On the other hand, doing the same using upgrade on an existing deployment does not overwrite these values on brokers configuration, but it can be used to prepare (first step) for a manual scale up using CLI where these parameter changes would actually become effective (second step). +Also note, that specifying `maxConnections`, `maxQueueMessages`, and `maxSpoolUsage` on initial deployment overwrites the broker’s default values. On the other hand, doing the same using upgrade on an existing deployment does not overwrite these values on brokers configuration, but it can be used to prepare (first step) for a manual scale up using CLI where these parameter changes would actually become effective (second step). + +>Note: The scaling parameters intentionally use a mix of *camelCase* and *snake_case* to maintain backward and forward compatibility with Solace PubSub+ Software Event Broker configurations. Make sure values are not duplicated for consistency. When using the [resource calculator](https://docs.solace.com/Admin-Ref/Resource-Calculator/pubsubplus-resource-calculator.html), ensure that the scaling parameters are in the correct format to match what the Solace PubSub+ Software Event Broker expects. If invalid scaling parameters are provided, the Operator will revert to default values. For the list of default values, please refer to this [link](/docs/EventBrokerOperatorParametersReference.md). + ##### Minimum footprint deployment for Developers @@ -315,63 +317,11 @@ To activate, set `spec.developer` to `true`. >Important: If set to `true`, `spec.developer` has precedence over any `spec.systemScaling` vertical scaling settings. -##### Forward Compatibility for Vertical Scaling - -Use `extraEnvVars`, which allows configuration of [additional properties for broker pods](#broker-pod-additional-properties) to ensure forward compatibility of `scalingParameters`. - -For example from 10.7.x of Solace PubSub+ Software Event Broker, new scaling parameters have been added. - -* [Maximum Number of Kafka Bridges](https://docs.solace.com/Software-Broker/System-Scaling-Parameters.htm#max-kafka-bridges) -* [Maximum Number of Kafka Broker Connections](https://docs.solace.com/Software-Broker/System-Scaling-Parameters.htm#max-kafka-broker-connections) - -Configure these parameters outside of `systemScaling` using `extraEnvVars`, as shown below: - -```yaml -apiVersion: pubsubplus.solace.com/v1beta1 -kind: PubSubPlusEventBroker -metadata: - name: ha-scaling-param-extra -spec: - extraEnvVars: - - name: system_scaling_maxkafkabrokerconnectioncount - value: "300" - - name: system_scaling_maxkafkabridgecount - value: "10" - systemScaling: - messagingNodeMemory: "8025Mi" - messagingNodeCpu: "2" - maxSpoolUsage: 500 - maxQueueMessages: 100 - maxConnections: 1000 - redundancy: false -``` - -When the broker pod has started, confirm consistency of values with the command `show system` after having [CLI access to individual event broker](#cli-access-to-individual-event-brokers). - -``` -ha-scaling-param-extra-pubsubplus-p-0> show system - -System Uptime: 0d 0h 1m 13s -Last Restart Reason: Unknown reason - -Scaling: -Max Connections: 1000 -Max Queue Messages: 100M -Max Kafka Bridges: 10 -Max Kafka Broker Connections: 300 - -Topic Routing: -Subscription Exceptions: Enabled -Subscription Exceptions Defer: Enabled -``` - ->Note: Please verify that the value aligns with the `scalingParameter` values. This custom method of configuring `scalingParameters` is only effective if it's supported as environment variables and values consistent with what the Solace PubSub+ Software Event Broker expects. Use the [Resource-Calculator](https://docs.solace.com/Admin-Ref/Resource-Calculator/pubsubplus-resource-calculator.html) as guide. - ### Storage The [PubSub+ deployment uses disk storage](https://docs.solace.com/Software-Broker/Configuring-Storage.htm) for logging, configuration, guaranteed messaging, and storing diagnostic and other information, allocated from Kubernetes volumes. -For a given set of [scaling](#vertical-scaling), use the [Solace online System Resource Calculator](https://docs.solace.com/Admin-Ref/Resource-Calculator/pubsubplus-resource-calculator.html) to determine the required storage size. +For a given set of [scaling](#vertical-scaling), use the [Solace online System Resource Calculator](https://docs.solace.com/Admin-Ref/Resource-Calculator/pubsubplus-resource-calculator.html) to determine the required storage size. The broker pods can use following storage options: * Dynamically allocated storage from a Kubernetes Storage Class (default) @@ -513,6 +463,8 @@ In summary, a deployment is ready for service requests when there is a broker po kubectl get pods --show-labels ``` +> Note: The Operator uses SEMP to determine the active PubSub+ Event Broker. Restarting SEMP will affect the active broker selection. + #### Using a Service Type [PubSub+ services](https://docs.solace.com/Configuring-and-Managing/Default-Port-Numbers.htm#Software) can be exposed using one of the following [Kubernetes service types](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) by specifying the `spec.service.type` parameter: @@ -826,7 +778,7 @@ In a Production environment additional steps are required to ensure there is onl #### Broker Security Context -The following container-level security context configuration is automatically set by the operator: +The following container-level security context configuration is automatically set by the operator for the PubSub+ broker container ``` capabilities: diff --git a/version.go b/version.go index b5b3628..6aeb0eb 100644 --- a/version.go +++ b/version.go @@ -15,4 +15,4 @@ // limitations under the License. package main -const version = "1.0.3" +const version = "1.1.0"