diff --git a/Makefile b/Makefile index 51bb6fa1..8748542c 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ test: install-gotestsum spin-postgres-db spin-rabbitmq build_test_plugins --rerun-fails-max-failures=1550 \ --format testname \ --junitfile junit.xml \ - --packages="./internal/... ./providers/... ./utils... ./cmd/... ./tenant-manager/..." \ + --packages="./internal/... ./providers/... ./utils... ./cmd/..." \ -- -count=1 -covermode=atomic -coverpkg=./... -parallel=$$PARALLEL \ -args -test.gocoverdir=$$(pwd)/cover; \ } || status=$$?; \ diff --git a/Taskfile.yaml b/Taskfile.yaml index c50074b4..1f783b6b 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -6,7 +6,7 @@ includes: flatten: true excludes: [] # put task names in here which are overwritten in this file vars: - CODE_DIRS: '{{.ROOT_DIR}}/cmd/... {{.ROOT_DIR}}/internal/... {{.ROOT_DIR}}/apis/... {{.ROOT_DIR}}/providers/... {{.ROOT_DIR}}/tenant-manager/... {{.ROOT_DIR}}/test/... {{.ROOT_DIR}}/utils/...' - COMPONENTS: 'api-server task-scheduler task-worker tenant-manager tenant-manager-cli' + CODE_DIRS: '{{.ROOT_DIR}}/cmd/... {{.ROOT_DIR}}/internal/... {{.ROOT_DIR}}/apis/... {{.ROOT_DIR}}/providers/... {{.ROOT_DIR}}/test/... {{.ROOT_DIR}}/utils/...' + COMPONENTS: 'cmk-core tenant-manager tenant-manager-cli' REPO_URL: 'https://github.com/openkcm/cmk' diff --git a/charts/.helmignore b/charts/cmk-core/.helmignore similarity index 100% rename from charts/.helmignore rename to charts/cmk-core/.helmignore diff --git a/charts/Chart.yaml b/charts/cmk-core/Chart.yaml similarity index 100% rename from charts/Chart.yaml rename to charts/cmk-core/Chart.yaml diff --git a/charts/README.md b/charts/cmk-core/README.md similarity index 100% rename from charts/README.md rename to charts/cmk-core/README.md diff --git a/charts/templates/NOTES.txt b/charts/cmk-core/templates/NOTES.txt similarity index 100% rename from charts/templates/NOTES.txt rename to charts/cmk-core/templates/NOTES.txt diff --git a/charts/templates/_helpers.tpl b/charts/cmk-core/templates/_helpers.tpl similarity index 100% rename from charts/templates/_helpers.tpl rename to charts/cmk-core/templates/_helpers.tpl diff --git a/charts/cmk-core/templates/configmap.yaml b/charts/cmk-core/templates/configmap.yaml new file mode 100644 index 00000000..d8339fe6 --- /dev/null +++ b/charts/cmk-core/templates/configmap.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "cmk.name" . }}-config + labels: + {{- include "cmk.labels" . | nindent 4 }} +immutable: {{ .Values.application.isImmutable | default false }} +data: + config.yaml: |- + application: + name: {{ .Chart.Name }} + {{- with .Values.application }} + environment: {{ .environment }} + {{- with .labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end}} + {{- end}} + + {{- with .Values.config }} + {{- toYaml . | nindent 4 }} + {{- end}} \ No newline at end of file diff --git a/charts/templates/api-server/deployment.yaml b/charts/cmk-core/templates/deployment.yaml similarity index 85% rename from charts/templates/api-server/deployment.yaml rename to charts/cmk-core/templates/deployment.yaml index bb70e142..0a436228 100644 --- a/charts/templates/api-server/deployment.yaml +++ b/charts/cmk-core/templates/deployment.yaml @@ -1,4 +1,3 @@ -{{- if .Values.apiServer.deploy }} --- apiVersion: apps/v1 kind: Deployment @@ -7,7 +6,7 @@ metadata: labels: {{- include "cmk.labels" . | nindent 4 }} spec: - {{- if not .Values.autoscaling.enabled }} + {{- if not .Values.hpa.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: @@ -15,13 +14,13 @@ spec: {{- include "cmk.selectorLabels" . | nindent 6 }} template: metadata: - {{- with .Values.podAnnotations }} + {{- with .Values.pod.annotations }} annotations: {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "cmk.labels" . | nindent 8 }} - {{- with .Values.podLabels }} + {{- with .Values.pod.labels }} {{- toYaml . | nindent 8 }} {{- end }} spec: @@ -30,7 +29,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "cmk.serviceAccountName" . }} - {{- with .Values.podSecurityContext }} + {{- with .Values.pod.securityContext }} securityContext: {{- toYaml . | nindent 8 }} {{- end }} @@ -49,10 +48,10 @@ spec: {{- end }} image: "{{ template "cmk.image" (tuple .Values.image $.Chart.AppVersion) }}" imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- with .Values.apiServer.image.command }} + {{- with .Values.image.command }} command: [ "{{- toYaml . }}" ] {{- end }} - {{- with .Values.apiServer.image.args }} + {{- with .Values.image.args }} args: {{- toYaml . | nindent 12 }} {{- end }} @@ -109,16 +108,19 @@ spec: {{- with .Values.extraVolumes }} {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.nodeSelector }} + {{- with .Values.pod.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- with .Values.pod.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.tolerations }} + {{- with .Values.pod.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.pod.tolerations }} tolerations: - {{- toYaml . | nindent 8 }} + {{- toYaml . | nindent 6 }} {{- end }} -{{- end }} diff --git a/charts/cmk-core/templates/hpa.yaml b/charts/cmk-core/templates/hpa.yaml new file mode 100644 index 00000000..cb351f2a --- /dev/null +++ b/charts/cmk-core/templates/hpa.yaml @@ -0,0 +1,36 @@ +{{- if .Values.hpa.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "cmk.fullname" . }} + labels: + {{- include "cmk.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "cmk.fullname" . }} + minReplicas: {{ .Values.hpa.minReplicas }} + maxReplicas: {{ .Values.hpa.maxReplicas }} + metrics: + {{- if or .Values.hpa.targetCPUUtilizationPercentage .Values.hpa.targetMemoryUtilizationPercentage }} + {{- if .Values.hpa.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.hpa.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetMemoryUtilizationPercentage }} + {{- end }} + {{- else }} + [] + {{- end }} +{{- end }} diff --git a/charts/cmk-core/templates/pdb.yaml b/charts/cmk-core/templates/pdb.yaml new file mode 100644 index 00000000..078b8f0d --- /dev/null +++ b/charts/cmk-core/templates/pdb.yaml @@ -0,0 +1,23 @@ +{{- if .Values.pod.disruptionBudget.enabled }} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "cmk.fullname" . }} + namespace: {{ include "cmk.namespace" . }} + labels: + {{- include "cmk.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "cmk.selectorLabels" . | nindent 6 }} + {{- if not (or (hasKey .Values.pod.disruptionBudget "minAvailable") (hasKey .Values.pod.disruptionBudget "maxUnavailable")) }} + minAvailable: 1 # Default value because minAvailable and maxUnavailable are not set + {{- end }} + {{- if hasKey .Values.pod.disruptionBudget "minAvailable" }} + minAvailable: {{ .Values.pod.disruptionBudget.minAvailable }} + {{- end }} + {{- if hasKey .Values.pod.disruptionBudget "maxUnavailable" }} + maxUnavailable: {{ .Values.pod.disruptionBudget.maxUnavailable }} + {{- end }} +{{- end }} diff --git a/charts/templates/api-server/service.yaml b/charts/cmk-core/templates/service.yaml similarity index 82% rename from charts/templates/api-server/service.yaml rename to charts/cmk-core/templates/service.yaml index a146d0b0..c07683df 100644 --- a/charts/templates/api-server/service.yaml +++ b/charts/cmk-core/templates/service.yaml @@ -1,4 +1,3 @@ -{{- if .Values.apiServer.deploy }} --- apiVersion: v1 kind: Service @@ -20,5 +19,4 @@ spec: {{- toYaml . | nindent 4 }} {{- end }} selector: - {{- include "cmk.selectorLabels" . | nindent 4 }} -{{- end }} \ No newline at end of file + {{- include "cmk.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/templates/api-server/serviceaccount.yaml b/charts/cmk-core/templates/serviceaccount.yaml similarity index 80% rename from charts/templates/api-server/serviceaccount.yaml rename to charts/cmk-core/templates/serviceaccount.yaml index 18b5ade4..75c08732 100644 --- a/charts/templates/api-server/serviceaccount.yaml +++ b/charts/cmk-core/templates/serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.apiServer.deploy .Values.serviceAccount.create -}} +{{- if .Values.serviceAccount.create -}} apiVersion: v1 kind: ServiceAccount metadata: @@ -10,4 +10,3 @@ metadata: {{- toYaml . | nindent 4 }} {{- end }} automountServiceAccountToken: {{ .Values.serviceAccount.automount }} -{{- end }} diff --git a/charts/values.yaml b/charts/cmk-core/values.yaml similarity index 80% rename from charts/values.yaml rename to charts/cmk-core/values.yaml index 6e8ec725..9953b68b 100644 --- a/charts/values.yaml +++ b/charts/cmk-core/values.yaml @@ -2,118 +2,6 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# Component-specific values - -# api-server configuration -apiServer: - # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ - image: - # Setting the command - # +docs:property - command: "" - - # Setting the arguments for the container - # +docs:property - args: [] - # - --graceful-shutdown=2 - # - --graceful-shutdown-message="Graceful shutdown in %d seconds" - - # Enable the API-server deployment. - deploy: true - -# tenant-manager configuration -tenantManager: - # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ - image: - # Setting the command - # +docs:property - command: "" - - # Setting the arguments for the container - # +docs:property - args: [] - # - --graceful-shutdown=2 - # - --graceful-shutdown-message="Graceful shutdown in %d seconds" - - # Enable the tenant-manager deployment. - deploy: true - - # tenant-manager service configuration - service: - # Enable the tenant-manager service - enabled: false - - # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types - type: ClusterIP - # This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports - ports: - - port: 5672 # must match .Values.cmk.port - protocol: TCP - targetPort: http - name: http - -# tenant-manager-cli configuration -tenantManagerCLI: - # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ - image: - # Setting the command - # +docs:property - command: "" - - # Setting the arguments for the container - # +docs:property - args: [] - # - --graceful-shutdown=2 - # - --graceful-shutdown-message="Graceful shutdown in %d seconds" - - # Enable the tenant-manager-cli deployment. - deploy: false - - # tenant-manager-cli service configuration - service: - # Enable the tenant-manager-cli service - enabled: false - - # Additional containers on the output Deployment definition. - extraContainers: [] - - # Additional init containers on the output Deployment definition. - extraInitContainers: [] - -# task scheduler configuration -taskScheduler: - # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ - image: - # Setting the command - # +docs:property - command: "" - - # Setting the arguments for the container - # +docs:property - args: [] - # - --graceful-shutdown=2 - # - --graceful-shutdown-message="Graceful shutdown in %d seconds" - - # Enable the task scheduler deployment. - deploy: false - -# task worker configuration -taskWorker: - # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ - image: - # Setting the command - # +docs:property - command: "" - - # Setting the arguments for the container - # +docs:property - args: [] - # - --graceful-shutdown=2 - # - --graceful-shutdown-message="Graceful shutdown in %d seconds" - - # Enable the task worker deployment. - deploy: false - # Override the "name" value, which is used to annotate some of # the resources that are created by this Chart (using "app.kubernetes.io/name"). # +docs:property @@ -136,19 +24,19 @@ replicaCount: 1 image: # The container registry to pull the image from. # For example: - # registry: kms.common.repositories.cloud.sap - # repository: cmk + # registry: ghcr.io/openkcm + # repository: images/checker # +docs:property - registry: "" + registry: ghcr.io/openkcm # The container image # +docs:property - repository: cmk-api-server-dev + repository: images/cmk # Override the image tag to deploy by setting this variable. # If no value is set, the chart's appVersion is used. # +docs:property - tag: "latest" + tag: "" # Setting a digest will override any tag. # +docs:property @@ -157,11 +45,16 @@ image: # Kubernetes imagePullPolicy. pullPolicy: IfNotPresent - # Setting the arguments for the container - # +docs:property - #args: - # - --graceful-shutdown=2 - # - --graceful-shutdown-message="Graceful shutdown in %d seconds" + # # Setting the arguments for the container + # # +docs:property + args: + - api-server +# - task-scheduler +# - task-worker +# - task-manager +# - task-manager-cli + # - --graceful-shutdown 2 + # - --graceful-message 'Graceful shutdown in %d seconds' # Setting the command # +docs:property @@ -183,15 +76,46 @@ serviceAccount: # If not set and create is true, a name is generated using the fullname template name: "" -# This is for setting Kubernetes Annotations to a Pod. -# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ -podAnnotations: {} -# This is for setting Kubernetes Labels to a Pod. -# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ -podLabels: {} +pod: + # This is for setting Kubernetes Annotations to a Pod. + # For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + annotations: { } + + # This is for setting Kubernetes Labels to a Pod. + # For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + labels: {} + + securityContext: {} + # fsGroup: 2000 + + disruptionBudget: + # Enable or disable the PodDisruptionBudget resource. + # + # This prevents downtime during voluntary disruptions such as during a Node upgrade. + # For example, the PodDisruptionBudget will block `kubectl drain` + # Pod is currently running. + enabled: false + + # This configures the minimum available pods for disruptions. It can either be set to + # an integer (e.g. 1) or a percentage value (e.g. 25%). + # It cannot be used if `maxUnavailable` is set. + # +docs:property + # +docs:type=unknown + # minAvailable: 1 + + # This configures the maximum unavailable pods for disruptions. It can either be set to + # an integer (e.g. 1) or a percentage value (e.g. 25%). + # it cannot be used if `minAvailable` is set. + # +docs:property + # +docs:type=unknown + # maxUnavailable: 1 + nodeSelector: { } + tolerations: [ ] + affinity: { } + topologySpreadConstraints: [] + + -podSecurityContext: {} -# fsGroup: 2000 securityContext: {} # capabilities: @@ -201,27 +125,6 @@ securityContext: {} # runAsNonRoot: true # runAsUser: 1000 -podDisruptionBudget: - # Enable or disable the PodDisruptionBudget resource. - # - # This prevents downtime during voluntary disruptions such as during a Node upgrade. - # For example, the PodDisruptionBudget will block `kubectl drain` - # Pod is currently running. - enabled: false - - # This configures the minimum available pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # It cannot be used if `maxUnavailable` is set. - # +docs:property - # +docs:type=unknown - # minAvailable: 1 - - # This configures the maximum unavailable pods for disruptions. It can either be set to - # an integer (e.g. 1) or a percentage value (e.g. 25%). - # it cannot be used if `minAvailable` is set. - # +docs:property - # +docs:type=unknown - # maxUnavailable: 1 # This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ service: @@ -267,7 +170,7 @@ readinessProbe: periodSeconds: 10 # This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/ -autoscaling: +hpa: enabled: false minReplicas: 1 maxReplicas: 1 @@ -292,9 +195,6 @@ extraEnvs: [] # Additional envsFrom on the output Deployment definition. extraEnvsFrom: [] -nodeSelector: {} - -tolerations: [] ports: - name: http-status @@ -304,16 +204,14 @@ ports: containerPort: 8081 protocol: TCP -affinity: {} - -config: +application: isImmutable: false - # Environment where the application is running environment: local # Labels associated to metrics, traces and logs - labels: {} + labels: { } +config: # Feature gates featureGates: enrich-header-with-client-type: true diff --git a/charts/templates/api-server/configmap.yaml b/charts/templates/api-server/configmap.yaml deleted file mode 100644 index 6b1efcb9..00000000 --- a/charts/templates/api-server/configmap.yaml +++ /dev/null @@ -1,71 +0,0 @@ -{{- if .Values.apiServer.deploy }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "cmk.name" . }}-config - labels: - {{- include "cmk.labels" . | nindent 4 }} -immutable: {{ .Values.config.isImmutable | default false }} -data: - config.yaml: |- - application: - name: {{ .Chart.Name }} - {{- with .Values.config }} - environment: {{ .environment }} - {{- with .labels }} - labels: - {{- toYaml . | nindent 8 }} - {{- end}} - - featureGates: - {{- toYaml .featureGates | nindent 6 }} - - http: - address: :{{ .http.port }} - - logger: - {{- toYaml .logger | nindent 6 }} - - status: - {{- toYaml .status | nindent 6 }} - - certificates: - {{- toYaml .certificates | nindent 6 }} - - cryptoLayer: - {{- toYaml .cryptoLayer | nindent 6 }} - - # Telemetry configuration - telemetry: - {{- toYaml .telemetry | nindent 6 }} - - # Scheduler configuration - scheduler: - {{- toYaml .scheduler | nindent 6 }} - - # Database configuration - database: - {{- toYaml .database | nindent 6 }} - - # Services configuration - services: - {{- toYaml .services | nindent 6 }} - - # Plugins configuration - plugins: - {{ include "cmk.plugins" . | nindent 6 }} - - eventProcessor: - {{- toYaml .eventProcessor | nindent 6 }} - system: - {{- toYaml .system | nindent 6 }} - - provisioning: - {{- toYaml .provisioning | nindent 6 }} - - audit: - {{- toYaml .audit | nindent 6 }} - - {{- end }} -{{- end }} diff --git a/charts/templates/api-server/hpa.yaml b/charts/templates/api-server/hpa.yaml deleted file mode 100644 index 0161e9e0..00000000 --- a/charts/templates/api-server/hpa.yaml +++ /dev/null @@ -1,36 +0,0 @@ -{{- if and .Values.apiServer.deploy .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "cmk.fullname" . }} - labels: - {{- include "cmk.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "cmk.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if or .Values.autoscaling.targetCPUUtilizationPercentage .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} - {{- else }} - [] - {{- end }} -{{- end }} diff --git a/charts/templates/api-server/pdb.yaml b/charts/templates/api-server/pdb.yaml deleted file mode 100644 index 57732a3e..00000000 --- a/charts/templates/api-server/pdb.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- if and .Values.apiServer.deploy .Values.podDisruptionBudget.enabled }} ---- -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: {{ include "cmk.fullname" . }} - namespace: {{ include "cmk.namespace" . }} - labels: - {{- include "cmk.labels" . | nindent 4 }} -spec: - selector: - matchLabels: - {{- include "cmk.selectorLabels" . | nindent 6 }} - {{- if not (or (hasKey .Values.podDisruptionBudget "minAvailable") (hasKey .Values.podDisruptionBudget "maxUnavailable")) }} - minAvailable: 1 # Default value because minAvailable and maxUnavailable are not set - {{- end }} - {{- if hasKey .Values.podDisruptionBudget "minAvailable" }} - minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} - {{- end }} - {{- if hasKey .Values.podDisruptionBudget "maxUnavailable" }} - maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} - {{- end }} -{{- end }} diff --git a/charts/templates/task-scheduler/configmap.yaml b/charts/templates/task-scheduler/configmap.yaml deleted file mode 100644 index dddeafac..00000000 --- a/charts/templates/task-scheduler/configmap.yaml +++ /dev/null @@ -1,42 +0,0 @@ -{{- if .Values.taskScheduler.deploy }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "cmk.name" . }}-task-scheduler-config - labels: - {{- include "cmk.task-scheduler.labels" . | nindent 4 }} -immutable: {{ .Values.config.isImmutable | default false }} -data: - config.yaml: |- - application: - name: task-scheduler - {{- with .Values.config }} - environment: {{ .environment }} - {{- with .labels }} - labels: - {{- toYaml . | nindent 8 }} - {{- end }} - - status: - {{- toYaml .status | nindent 6 }} - - logger: - {{- toYaml .logger | nindent 6 }} - - telemetry: - {{- toYaml .telemetry | nindent 6 }} - - # Database configuration - database: - {{- toYaml .database | nindent 6 }} - - # Scheduler configuration - scheduler: - {{- toYaml .scheduler | nindent 6 }} - - certificates: - {{- toYaml .certificates | nindent 6 }} - - {{- end }} -{{- end }} diff --git a/charts/templates/task-scheduler/serviceaccount.yaml b/charts/templates/task-scheduler/serviceaccount.yaml deleted file mode 100644 index bd0eed75..00000000 --- a/charts/templates/task-scheduler/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if and .Values.taskScheduler.deploy .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "cmk.serviceAccountName" . }}-task-scheduler - labels: - {{- include "cmk.task-scheduler.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -automountServiceAccountToken: {{ .Values.serviceAccount.automount }} -{{- end }} diff --git a/charts/templates/task-worker/configmap.yaml b/charts/templates/task-worker/configmap.yaml deleted file mode 100644 index 5e52da65..00000000 --- a/charts/templates/task-worker/configmap.yaml +++ /dev/null @@ -1,49 +0,0 @@ -{{- if .Values.taskWorker.deploy }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "cmk.name" . }}-task-worker-config - labels: - {{- include "cmk.task-worker.labels" . | nindent 4 }} -immutable: {{ .Values.config.isImmutable | default false }} -data: - config.yaml: |- - application: - name: task-worker - {{- with .Values.config }} - environment: {{ .environment }} - {{- with .labels }} - labels: - {{- toYaml . | nindent 8 }} - {{- end}} - - status: - {{- toYaml .status | nindent 6 }} - - logger: - {{- toYaml .logger | nindent 6 }} - - telemetry: - {{- toYaml .telemetry | nindent 6 }} - - # Database configuration - database: - {{- toYaml .database | nindent 6 }} - - # Scheduler configuration - scheduler: - {{- toYaml .scheduler | nindent 6 }} - - certificates: - {{- toYaml .certificates | nindent 6 }} - - # Plugins configuration - plugins: - {{- include "cmk.plugins" . | nindent 6 }} - - # Keystore pool configuration - keystorePool: - {{- toYaml .keystorePool | nindent 6 }} - {{- end }} -{{- end }} diff --git a/charts/templates/tenant-manager-cli/configmap.yaml b/charts/templates/tenant-manager-cli/configmap.yaml deleted file mode 100644 index e8273733..00000000 --- a/charts/templates/tenant-manager-cli/configmap.yaml +++ /dev/null @@ -1,37 +0,0 @@ -{{- if .Values.tenantManagerCLI.deploy }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "cmk.name" . }}-tenant-manager-cli-config - labels: - {{- include "cmk.tenant-manager-cli.labels" . | nindent 4 }} -immutable: {{ .Values.config.isImmutable | default false }} -data: - config.yaml: |- - application: - name: tenant-manager-cli - {{- with .Values.config }} - environment: {{ .environment }} - {{- with .labels }} - labels: - {{- toYaml . | nindent 8 }} - {{- end}} - - status: - {{- toYaml .status | nindent 6 }} - - logger: - {{- toYaml .logger | nindent 6 }} - - telemetry: - {{- toYaml .telemetry | nindent 6 }} - - database: - {{- toYaml .database | nindent 6 }} - - tenantManager: - {{- toYaml .tenantManager | nindent 6 }} - - {{- end }} -{{- end }} diff --git a/charts/templates/tenant-manager-cli/deployment.yaml b/charts/templates/tenant-manager-cli/deployment.yaml deleted file mode 100644 index abad9d36..00000000 --- a/charts/templates/tenant-manager-cli/deployment.yaml +++ /dev/null @@ -1,105 +0,0 @@ -{{- if .Values.tenantManagerCLI.deploy }} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "cmk.fullname" . }}-tenant-manager-cli - labels: - {{- include "cmk.tenant-manager-cli.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "cmk.tenant-manager-cli.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "cmk.tenant-manager-cli.labels" . | nindent 8 }} - {{- with .Values.podLabels }} - {{- toYaml . | nindent 8 }} - {{- end }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "cmk.serviceAccountName" . }}-tenant-manager-cli - {{- with .Values.podSecurityContext }} - securityContext: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tenantManagerCLI.extraInitContainers }} - initContainers: - {{- toYaml . | nindent 8 }} - {{- end }} - containers: - {{- with .Values.tenantManagerCLI.extraContainers }} - {{- toYaml . | nindent 8 }} - {{- end }} - - name: {{ include "cmk.name" . }}-tenant-manager-cli - {{- with .Values.securityContext }} - securityContext: - {{- toYaml . | nindent 12 }} - {{- end }} - image: "{{ template "cmk.image" (tuple .Values.image $.Chart.AppVersion) }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- with .Values.tenantManagerCLI.image.command }} - command: [ "{{- toYaml . }}" ] - {{- end }} - {{- with .Values.tenantManagerCLI.image.args }} - args: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.ports }} - ports: - {{- toYaml . | nindent 12 }} - {{- end }} - env: - - name: MY_POD_IP - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: status.podIP - - name: K8S_NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: K8S_NODE_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - volumeMounts: - - name: {{ include "cmk.name" . }}-tenant-manager-cli-config-volume - mountPath: /etc/tenant-manager-cli - readOnly: true - {{- with .Values.extraVolumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} - volumes: - - name: {{ include "cmk.name" . }}-tenant-manager-cli-config-volume - projected: - sources: - - configMap: - name: {{ include "cmk.name" . }}-tenant-manager-cli-config - {{- with .Values.extraVolumes }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} -{{- end}} diff --git a/charts/templates/tenant-manager-cli/serviceaccount.yaml b/charts/templates/tenant-manager-cli/serviceaccount.yaml deleted file mode 100644 index 3e767469..00000000 --- a/charts/templates/tenant-manager-cli/serviceaccount.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if and .Values.tenantManagerCLI.deploy .Values.serviceAccount.create -}} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "cmk.serviceAccountName" . }}-tenant-manager-cli - labels: - {{- include "cmk.tenant-manager-cli.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -automountServiceAccountToken: {{ .Values.serviceAccount.automount }} -{{- end }} diff --git a/charts/templates/tenant-manager/configmap.yaml b/charts/templates/tenant-manager/configmap.yaml deleted file mode 100644 index fa6203f0..00000000 --- a/charts/templates/tenant-manager/configmap.yaml +++ /dev/null @@ -1,42 +0,0 @@ -{{- if .Values.tenantManager.deploy }} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "cmk.name" . }}-tenant-manager-config - labels: - {{- include "cmk.tenant-manager.labels" . | nindent 4 }} -immutable: {{ .Values.config.isImmutable | default false }} -data: - config.yaml: |- - application: - name: tenant-manager - {{- with .Values.config }} - environment: {{ .environment }} - {{- with .labels }} - labels: - {{- toYaml . | nindent 8 }} - {{- end}} - - status: - {{- toYaml .status | nindent 6 }} - - logger: - {{- toYaml .logger | nindent 6 }} - - telemetry: - {{- toYaml .telemetry | nindent 6 }} - - # Database configuration - database: - {{- toYaml .database | nindent 6 }} - - # Services configuration - services: - {{- toYaml .services | nindent 6 }} - - tenantManager: - {{- toYaml .tenantManager | nindent 6 }} - - {{- end }} -{{- end }} diff --git a/charts/templates/tenant-manager/deployment.yaml b/charts/templates/tenant-manager/deployment.yaml deleted file mode 100644 index f7097a72..00000000 --- a/charts/templates/tenant-manager/deployment.yaml +++ /dev/null @@ -1,105 +0,0 @@ -{{- if .Values.tenantManager.deploy }} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "cmk.fullname" . }}-tenant-manager - labels: - {{- include "cmk.tenant-manager.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "cmk.tenant-manager.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "cmk.tenant-manager.labels" . | nindent 8 }} - {{- with .Values.podLabels }} - {{- toYaml . | nindent 8 }} - {{- end }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "cmk.serviceAccountName" . }}-tenant-manager - {{- with .Values.podSecurityContext }} - securityContext: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.extraInitContainers }} - initContainers: - {{- toYaml . | nindent 8 }} - {{- end }} - containers: - {{- with .Values.extraContainers }} - {{- toYaml . | nindent 8 }} - {{- end }} - - name: {{ include "cmk.name" . }}-tenant-manager - {{- with .Values.securityContext }} - securityContext: - {{- toYaml . | nindent 12 }} - {{- end }} - image: "{{ template "cmk.image" (tuple .Values.image $.Chart.AppVersion) }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- with .Values.tenantManager.image.command }} - command: [ "{{- toYaml . }}" ] - {{- end }} - {{- with .Values.tenantManager.image.args }} - args: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.ports }} - ports: - {{- toYaml . | nindent 12 }} - {{- end }} - env: - - name: MY_POD_IP - valueFrom: - fieldRef: - apiVersion: v1 - fieldPath: status.podIP - - name: K8S_NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: K8S_NODE_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - volumeMounts: - - name: {{ include "cmk.name" . }}-tenant-manager-config-volume - mountPath: /etc/tenant-manager - readOnly: true - {{- with .Values.extraVolumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} - volumes: - - name: {{ include "cmk.name" . }}-tenant-manager-config-volume - projected: - sources: - - configMap: - name: {{ include "cmk.name" . }}-tenant-manager-config - {{- with .Values.extraVolumes }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} -{{- end}} diff --git a/charts/templates/tenant-manager/hpa.yaml b/charts/templates/tenant-manager/hpa.yaml deleted file mode 100644 index 402aead2..00000000 --- a/charts/templates/tenant-manager/hpa.yaml +++ /dev/null @@ -1,36 +0,0 @@ -{{- if and .Values.tenantManager.deploy .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "cmk.fullname" . }} - labels: - {{- include "cmk.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "cmk.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if or .Values.autoscaling.targetCPUUtilizationPercentage .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} - {{- else }} - [] - {{- end }} -{{- end }} diff --git a/charts/templates/tenant-manager/pdb.yaml b/charts/templates/tenant-manager/pdb.yaml deleted file mode 100644 index 479265d8..00000000 --- a/charts/templates/tenant-manager/pdb.yaml +++ /dev/null @@ -1,23 +0,0 @@ -{{- if and .Values.tenantManager.deploy .Values.podDisruptionBudget.enabled }} ---- -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: {{ include "cmk.fullname" . }} - namespace: {{ include "cmk.namespace" . }} - labels: - {{- include "cmk.labels" . | nindent 4 }} -spec: - selector: - matchLabels: - {{- include "cmk.selectorLabels" . | nindent 6 }} - {{- if not (or (hasKey .Values.podDisruptionBudget "minAvailable") (hasKey .Values.podDisruptionBudget "maxUnavailable")) }} - minAvailable: 1 # Default value because minAvailable and maxUnavailable are not set - {{- end }} - {{- if hasKey .Values.podDisruptionBudget "minAvailable" }} - minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} - {{- end }} - {{- if hasKey .Values.podDisruptionBudget "maxUnavailable" }} - maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} - {{- end }} -{{- end }} diff --git a/charts/templates/tests/test-connection.yaml b/charts/templates/tests/test-connection.yaml deleted file mode 100644 index 24a69407..00000000 --- a/charts/templates/tests/test-connection.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: "{{ include "cmk.fullname" . }}-test-connection" - labels: - {{- include "cmk.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": test -spec: - containers: - - name: wget - image: busybox - command: ['wget'] - args: ['{{ include "cmk.fullname" . }}:{{ "8081" }}'] - restartPolicy: Never diff --git a/charts/tenant-manager/.helmignore b/charts/tenant-manager/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/tenant-manager/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/tenant-manager/Chart.yaml b/charts/tenant-manager/Chart.yaml new file mode 100644 index 00000000..659e2352 --- /dev/null +++ b/charts/tenant-manager/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: tenant-manager +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.0" diff --git a/charts/tenant-manager/README.md b/charts/tenant-manager/README.md new file mode 100644 index 00000000..6b57d104 --- /dev/null +++ b/charts/tenant-manager/README.md @@ -0,0 +1,39 @@ +# CMK Helm Chart +KMS2.0 helm charts + +## How To + +Download all dependencies as defined in the parent chart and sub charts. + +```bash +helm dependency build ./charts +``` + +Update the dependencies after making changes to the chart. + +```bash +helm dependency update ./charts +``` + +After changing dependencies in a sub chart, update the sub charts dependencies first +and then update the parent chart dependencies. + +```bash +helm dependency update ./charts/ +helm dependency update ./charts +``` + +Render chart templates locally and display the output. +```bash +helm template kms2x ./charts +``` + +Install entire kms2x charts +```bash +helm install kms2x ./charts +``` + +UnInstall kms2x entire deployment +```bash +helm uninstall kms2x +``` \ No newline at end of file diff --git a/charts/tenant-manager/templates/NOTES.txt b/charts/tenant-manager/templates/NOTES.txt new file mode 100644 index 00000000..b9ad25fc --- /dev/null +++ b/charts/tenant-manager/templates/NOTES.txt @@ -0,0 +1,16 @@ +1. Get the application URL by running these commands: +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "tenant-manager.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "tenant-manager.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "tenant-manager.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "tenant-manager.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/tenant-manager/templates/_helpers.tpl b/charts/tenant-manager/templates/_helpers.tpl new file mode 100644 index 00000000..bdfd3144 --- /dev/null +++ b/charts/tenant-manager/templates/_helpers.tpl @@ -0,0 +1,194 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "tenant-manager.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Namespace for all resources to be installed into +If not defined in values file then the helm release namespace is used +By default this is not set so the helm release namespace will be used + +This gets around an problem within helm discussed here +https://github.com/helm/helm/issues/5358 +*/}} +{{- define "tenant-manager.namespace" -}} + {{ .Values.namespace | default .Release.Namespace }} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "tenant-manager.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "tenant-manager.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "tenant-manager.labels" -}} +helm.sh/chart: {{ include "tenant-manager.chart" . }} +{{ include "tenant-manager.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Task Scheduler labels +*/}} +{{- define "tenant-manager.task-scheduler.labels" -}} +helm.sh/chart: {{ include "tenant-manager.chart" . }} +{{ include "tenant-manager.task-scheduler.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Task Worker labels +*/}} +{{- define "tenant-manager.task-worker.labels" -}} +helm.sh/chart: {{ include "tenant-manager.chart" . }} +{{ include "tenant-manager.task-worker.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Tenant Manager labels +*/}} +{{- define "tenant-manager.tenant-manager.labels" -}} +helm.sh/chart: {{ include "tenant-manager.chart" . }} +{{ include "tenant-manager.tenant-manager.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Tenant Manager CLI labels +*/}} +{{- define "tenant-manager.tenant-manager-cli.labels" -}} +helm.sh/chart: {{ include "tenant-manager.chart" . }} +{{ include "tenant-manager.tenant-manager-cli.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "tenant-manager.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/component: {{ .Chart.Name }} +{{- end }} + +{{/* +task-scheduler Selector Labels +*/}} +{{- define "tenant-manager.task-scheduler.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }}-task-scheduler +app.kubernetes.io/component: {{ .Chart.Name }}-task-scheduler +{{- end }} + +{{/* +task-worker Selector Labels +*/}} +{{- define "tenant-manager.task-worker.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }}-task-worker +app.kubernetes.io/component: {{ .Chart.Name }}-task-worker +{{- end }} + +{{/* +Tenant Manager Selector labels +*/}} +{{- define "tenant-manager.tenant-manager.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager.name" . }}-tenant-manager +app.kubernetes.io/instance: {{ .Release.Name }}-tenant-manager +app.kubernetes.io/component: {{ .Chart.Name }}-tenant-manager +{{- end }} + +{{/* +Tenant Manager CLI Selector labels +*/}} +{{- define "tenant-manager.tenant-manager-cli.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager.name" . }}-tenant-manager-cli +app.kubernetes.io/instance: {{ .Release.Name }}-tenant-manager-cli +app.kubernetes.io/component: {{ .Chart.Name }}-tenant-manager-cli +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "tenant-manager.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "tenant-manager.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "tenant-manager.postgresqlName" -}} +{{- printf "%s-postgresql" .Release.Name -}} +{{- end }} + +{{/* +Util function for generating the image URL based on the provided options. +*/}} +{{- define "tenant-manager.image" -}} +{{- $defaultTag := index . 1 -}} +{{- with index . 0 -}} +{{- if .registry -}}{{ printf "%s/%s" .registry .repository }}{{- else -}}{{- .repository -}}{{- end -}} +{{- if .digest -}}{{ printf "@%s" .digest }}{{- else -}}{{ printf ":%s" (default $defaultTag .tag) }}{{- end -}} +{{- end }} +{{- end }} + +{{/* +Active plugins +*/}} +{{- define "tenant-manager.plugins" -}} +{{- $ := . }} +{{- $plugins := list -}} +{{- range .plugins -}} +{{- $plugin := . -}} +{{- range .tags -}} +{{- if has . $.activePlugins -}} + +{{- $plugins = append $plugins $plugin -}} +{{- break -}} + +{{- end -}} +{{- end -}} +{{- end -}} +{{- toYaml $plugins -}} +{{- end -}} diff --git a/charts/tenant-manager/templates/configmap.yaml b/charts/tenant-manager/templates/configmap.yaml new file mode 100644 index 00000000..5a41bd54 --- /dev/null +++ b/charts/tenant-manager/templates/configmap.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "tenant-manager.name" . }}-config + labels: + {{- include "tenant-manager.labels" . | nindent 4 }} +immutable: {{ .Values.application.isImmutable | default false }} +data: + config.yaml: |- + application: + name: {{ .Chart.Name }} + {{- with .Values.application }} + environment: {{ .environment }} + {{- with .labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end}} + {{- end}} + + {{- with .Values.config }} + {{- toYaml . | nindent 4 }} + {{- end}} \ No newline at end of file diff --git a/charts/templates/task-worker/deployment.yaml b/charts/tenant-manager/templates/deployment.yaml similarity index 58% rename from charts/templates/task-worker/deployment.yaml rename to charts/tenant-manager/templates/deployment.yaml index 66309100..f149847b 100644 --- a/charts/templates/task-worker/deployment.yaml +++ b/charts/tenant-manager/templates/deployment.yaml @@ -1,27 +1,26 @@ -{{- if .Values.taskWorker.deploy }} --- apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "cmk.fullname" . }}-task-worker + name: {{ include "tenant-manager.fullname" . }} labels: - {{- include "cmk.task-worker.labels" . | nindent 4 }} + {{- include "tenant-manager.labels" . | nindent 4 }} spec: - {{- if not .Values.autoscaling.enabled }} + {{- if not .Values.hpa.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: - {{- include "cmk.task-worker.selectorLabels" . | nindent 6 }} + {{- include "tenant-manager.selectorLabels" . | nindent 6 }} template: metadata: - {{- with .Values.podAnnotations }} + {{- with .Values.pod.annotations }} annotations: {{- toYaml . | nindent 8 }} {{- end }} labels: - {{- include "cmk.task-worker.labels" . | nindent 8 }} - {{- with .Values.podLabels }} + {{- include "tenant-manager.labels" . | nindent 8 }} + {{- with .Values.pod.labels }} {{- toYaml . | nindent 8 }} {{- end }} spec: @@ -29,8 +28,8 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: {{ include "cmk.serviceAccountName" . }}-task-worker - {{- with .Values.podSecurityContext }} + serviceAccountName: {{ include "tenant-manager.serviceAccountName" . }} + {{- with .Values.pod.securityContext }} securityContext: {{- toYaml . | nindent 8 }} {{- end }} @@ -42,17 +41,17 @@ spec: {{- with .Values.extraContainers }} {{- toYaml . | nindent 8 }} {{- end }} - - name: {{ include "cmk.name" . }}-task-worker + - name: {{ include "tenant-manager.name" . }} {{- with .Values.securityContext }} securityContext: {{- toYaml . | nindent 12 }} {{- end }} - image: "{{ template "cmk.image" (tuple .Values.image $.Chart.AppVersion) }}" + image: "{{ template "tenant-manager.image" (tuple .Values.image $.Chart.AppVersion) }}" imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- with .Values.taskWorker.image.command }} + {{- with .Values.image.command }} command: [ "{{- toYaml . }}" ] {{- end }} - {{- with .Values.taskWorker.image.args }} + {{- with .Values.image.args }} args: {{- toYaml . | nindent 12 }} {{- end }} @@ -81,32 +80,47 @@ spec: envFrom: {{- . | toYaml | nindent 12 }} {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} volumeMounts: - - name: {{ include "cmk.name" . }}-task-worker-config-volume - mountPath: /etc/cmk + - name: {{ include "tenant-manager.name" . }}-config-volume + mountPath: /etc/tenant-manager readOnly: true {{- with .Values.extraVolumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} volumes: - - name: {{ include "cmk.name" . }}-task-worker-config-volume + - name: {{ include "tenant-manager.name" . }}-config-volume projected: sources: - configMap: - name: {{ include "cmk.name" . }}-task-worker-config + name: {{ include "tenant-manager.name" . }}-config {{- with .Values.extraVolumes }} {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.nodeSelector }} + {{- with .Values.pod.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- with .Values.pod.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.tolerations }} + {{- with .Values.pod.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.pod.tolerations }} tolerations: - {{- toYaml . | nindent 8 }} + {{- toYaml . | nindent 6 }} {{- end }} -{{- end}} diff --git a/charts/tenant-manager/templates/hpa.yaml b/charts/tenant-manager/templates/hpa.yaml new file mode 100644 index 00000000..e30ed78e --- /dev/null +++ b/charts/tenant-manager/templates/hpa.yaml @@ -0,0 +1,36 @@ +{{- if .Values.hpa.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "tenant-manager.fullname" . }} + labels: + {{- include "tenant-manager.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "tenant-manager.fullname" . }} + minReplicas: {{ .Values.hpa.minReplicas }} + maxReplicas: {{ .Values.hpa.maxReplicas }} + metrics: + {{- if or .Values.hpa.targetCPUUtilizationPercentage .Values.hpa.targetMemoryUtilizationPercentage }} + {{- if .Values.hpa.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.hpa.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetMemoryUtilizationPercentage }} + {{- end }} + {{- else }} + [] + {{- end }} +{{- end }} diff --git a/charts/tenant-manager/templates/pdb.yaml b/charts/tenant-manager/templates/pdb.yaml new file mode 100644 index 00000000..1447455e --- /dev/null +++ b/charts/tenant-manager/templates/pdb.yaml @@ -0,0 +1,23 @@ +{{- if .Values.pod.disruptionBudget.enabled }} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "tenant-manager.fullname" . }} + namespace: {{ include "tenant-manager.namespace" . }} + labels: + {{- include "tenant-manager.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "tenant-manager.selectorLabels" . | nindent 6 }} + {{- if not (or (hasKey .Values.pod.disruptionBudget "minAvailable") (hasKey .Values.pod.disruptionBudget "maxUnavailable")) }} + minAvailable: 1 # Default value because minAvailable and maxUnavailable are not set + {{- end }} + {{- if hasKey .Values.pod.disruptionBudget "minAvailable" }} + minAvailable: {{ .Values.pod.disruptionBudget.minAvailable }} + {{- end }} + {{- if hasKey .Values.pod.disruptionBudget "maxUnavailable" }} + maxUnavailable: {{ .Values.pod.disruptionBudget.maxUnavailable }} + {{- end }} +{{- end }} diff --git a/charts/tenant-manager/templates/service.yaml b/charts/tenant-manager/templates/service.yaml new file mode 100644 index 00000000..b02b1a04 --- /dev/null +++ b/charts/tenant-manager/templates/service.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "tenant-manager.fullname" . }} + labels: + {{- include "tenant-manager.labels" . | nindent 4 }} + {{- with .Values.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type }} +{{- with .Values.service.ports }} + ports: + {{- toYaml . | nindent 4 }} +{{- end }} + selector: + {{- include "tenant-manager.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/templates/task-worker/serviceaccount.yaml b/charts/tenant-manager/templates/serviceaccount.yaml similarity index 53% rename from charts/templates/task-worker/serviceaccount.yaml rename to charts/tenant-manager/templates/serviceaccount.yaml index afd9cbba..fcb42797 100644 --- a/charts/templates/task-worker/serviceaccount.yaml +++ b/charts/tenant-manager/templates/serviceaccount.yaml @@ -1,13 +1,12 @@ -{{- if and .Values.taskWorker.deploy .Values.serviceAccount.create -}} +{{- if .Values.serviceAccount.create -}} apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "cmk.serviceAccountName" . }}-task-worker + name: {{ include "tenant-manager.serviceAccountName" . }} labels: - {{- include "cmk.task-worker.labels" . | nindent 4 }} + {{- include "tenant-manager.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} automountServiceAccountToken: {{ .Values.serviceAccount.automount }} -{{- end }} diff --git a/charts/tenant-manager/values.yaml b/charts/tenant-manager/values.yaml new file mode 100644 index 00000000..a9be6002 --- /dev/null +++ b/charts/tenant-manager/values.yaml @@ -0,0 +1,669 @@ +# Default values for cmk. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Override the "name" value, which is used to annotate some of +# the resources that are created by this Chart (using "app.kubernetes.io/name"). +# +docs:property +nameOverride: "" + +# Override the "fullname" value. This value is used as part of +# most of the names of the resources created by this Helm chart. +# +docs:property +fullnameOverride: "" + +# This namespace allows you to define where the services are installed into. +# If not set then they use the namespace of the release. +# This is helpful when installing a chart dependency (sub chart). +namespace: "" + +# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ +replicaCount: 1 + +# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ +image: + # The container registry to pull the image from. + # For example: + # registry: ghcr.io/openkcm + # repository: images/checker + # +docs:property + registry: ghcr.io/openkcm + + # The container image + # +docs:property + repository: images/tenant-manager + + # Override the image tag to deploy by setting this variable. + # If no value is set, the chart's appVersion is used. + # +docs:property + tag: "" + + # Setting a digest will override any tag. + # +docs:property + # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 + + # Kubernetes imagePullPolicy. + pullPolicy: IfNotPresent + + # # Setting the arguments for the container + # # +docs:property + args: + - api-server +# - task-scheduler +# - task-worker +# - task-manager +# - task-manager-cli + # - --graceful-shutdown 2 + # - --graceful-message 'Graceful shutdown in %d seconds' + + # Setting the command + # +docs:property + #command: "./extension-server" + +# This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: +# - name: "" + +# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +pod: + # This is for setting Kubernetes Annotations to a Pod. + # For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + annotations: { } + + # This is for setting Kubernetes Labels to a Pod. + # For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + labels: {} + + securityContext: {} + # fsGroup: 2000 + + disruptionBudget: + # Enable or disable the PodDisruptionBudget resource. + # + # This prevents downtime during voluntary disruptions such as during a Node upgrade. + # For example, the PodDisruptionBudget will block `kubectl drain` + # Pod is currently running. + enabled: false + + # This configures the minimum available pods for disruptions. It can either be set to + # an integer (e.g. 1) or a percentage value (e.g. 25%). + # It cannot be used if `maxUnavailable` is set. + # +docs:property + # +docs:type=unknown + # minAvailable: 1 + + # This configures the maximum unavailable pods for disruptions. It can either be set to + # an integer (e.g. 1) or a percentage value (e.g. 25%). + # it cannot be used if `minAvailable` is set. + # +docs:property + # +docs:type=unknown + # maxUnavailable: 1 + nodeSelector: { } + tolerations: [ ] + affinity: { } + topologySpreadConstraints: [] + + + + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + +# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ +service: + # Labels to add to the service + labels: {} + # Annotations to add to the service + annotations: {} + # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + type: ClusterIP + # This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports + ports: + - port: 8081 # must match .Values.cmk.port + protocol: TCP + targetPort: http + name: http + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +livenessProbe: + httpGet: + path: /probe/liveness + port: http-status + scheme: HTTP + failureThreshold: 1 + periodSeconds: 10 +readinessProbe: + httpGet: + path: /probe/readiness + port: http-status + scheme: HTTP + failureThreshold: 1 + periodSeconds: 10 + +# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/ +hpa: + enabled: false + minReplicas: 1 + maxReplicas: 1 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + +# Additional init containers on the output Deployment definition. +extraInitContainers: [] + +# Additional containers on the output Deployment definition. +extraContainers: [] + +# Additional volumes on the output Deployment definition. +extraVolumes: [] + +# Additional volumeMounts on the output Deployment definition. +extraVolumeMounts: [] + +# Additional ens on the output Deployment definition. +extraEnvs: [] + +# Additional envsFrom on the output Deployment definition. +extraEnvsFrom: [] + + +ports: + - name: http-status + containerPort: 8888 + protocol: TCP + - name: http + containerPort: 8081 + protocol: TCP + +application: + isImmutable: false + # Environment where the application is running + environment: local + # Labels associated to metrics, traces and logs + labels: { } + +config: + # Feature gates + featureGates: + enrich-header-with-client-type: true + enrich-header-with-client-region: true + disable-client-certificate-computation: false + disable-jwt-token-computation: false + + http: + port: 8081 + + # Expose the status port + status: + enabled: true + address: ":8888" + profiling: false + + # Certificates configuration + certificates: + # rootCertURL + rootCertURL: https://aia.pki.co.example.com/aia/EXAMPLE%20Cloud%20Root%20CA.crt + # Validity of the certificates in days; Must be between 7 and 30 days + validityDays: 30 + # Threshold in days to rotate the certificates; Must be between 1 and 30 days + rotationThresholdDays: 7 + + ## Crypto layer configuration + cryptoLayer: + certX509Trusts: + source: embedded + value: | + { + "crypto-1": { + "Subject": "FakeCert", + "RootCA": "https://aia.pki.co.example.com/aia/EXAMPLE%20Cloud%20Root%20CA.crt" + } + } + # This does set the logger configuration + # +docs:property + logger: + level: debug # one of: debug, info, warn, error + # Format of the logs + format: json # one of: json, text + formatter: + time: + type: pattern # one of: pattern, unix + # Used only when the property type: pattern + # Should follow golang time pattern + # Default value time.RFC3339. + pattern: "Mon Jan 02 15:04:05 -0700 2006" + # Used only when the property type: unix + # Time units are "1ns", "1us" (or "1µs"), "1ms", "1s" + # Default value 1s. + precision: 1s + fields: + # Field names (this way the field name can be changed) to be used on log records; These are their defaults. + error: "error" + message: "msg" + level: "level" + time: "time" + # Fields names used by OTEL to track the Trace and Span ID + otel: + traceID: "trace.id" # Default is TraceID + spanID: "span.id" # Default is SpanID + masking: + # All fields under PII, the formatters will mask the value and keeping first 4 original characters + pii: + - email + - ip-address + # All fields under other, the formatters will mask the value, using given mask. + other: + jwt-token: "*****" + telemetry: + logs: + enabled: false + protocol: http # one of: http, grpc; Default is http + # Host configuration example set as a value: + # host: + # source: embedded + # value: localhost:4317 + # Host configuration example load value from an environment variable: + # host: + # source: env + # env: OTEL_LOGS_HOST + # Host configuration example load value from a JSON file: + # host: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json + # jsonPath: "$.credentials.ingest-otlp-endpoint" # Syntax JSONPath Query Expression + host: + source: embedded + value: localhost:4317 + url: /api/v2/otlp/v1/logs + # OpenTelemetry secret connections; Applicable in the same way for logs, traces and metrics + # Insecure configuration example: + # secretRef: + # type: insecure # one of: insecure, mtls, api-token + # APIToken configuration example loading value from environment variable: + # secretRef: + # type: api-token # one of: insecure, mtls, api-token + # apiToken: + # source: env + # env: OTEL_LOS_API_TOKEN + # APIToken configuration example loading value from binary file as is: + # secretRef: + # type: api-token # one of: insecure, mtls, api-token + # apiToken: + # source: file + # path: /etc/credentials/api-token + # format: binary # one of: json, binary + # APIToken configuration example loading value from JSON file, extracting a specific field: + # secretRef: + # type: api-token # one of: insecure, mtls, api-token + # apiToken: + # source: file + # path: /etc/credentials/api-token.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.api-token" # Syntax JSONPath Query Expression + # mTLS configuration example loading value from environment variables: + # secretRef: + # type: mtls # one of: insecure, mtls, api-token + # mtls: + # cert: + # source: env + # env: OTEL_LOGS_X509_CERT + # certKey: + # source: env + # env: OTEL_LOGS_X509_CERT_KEY + # serverCA: + # source: env + # env: OTEL_LOGS_X509_SERVER_CA + # mTLS configuration example loading value from binary file as is: + # secretRef: + # type: mtls # one of: insecure, mtls, api-token + # mtls: + # cert: + # source: file + # file: + # path: /etc/credentials/cert.pem + # format: binary # one of: json, binary + # certKey: + # source: file + # file: + # path: /etc/credentials/cert-key.pem + # format: binary # one of: json, binary + # serverCA: + # source: file + # file: + # path: /etc/credentials/server-ca.pem + # format: binary # one of: json, binary + # mTLS configuration example loading value from JSON file, extracting a specific field: + # secretRef: + # type: mtls # one of: insecure, mtls, api-token + # mtls: + # cert: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.ingest-otlp-cert" # Syntax JSONPath Query Expression + # certKey: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.ingest-otlp-key" # Syntax JSONPath Query Expression + # serverCA: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.server-ca" # Syntax JSONPath Query Expression + secretRef: + type: api-token # one of: insecure, mtls, api-token + apiToken: + source: embedded + value: "unknown" + traces: + enabled: false + protocol: http # one of: http, grpc; Default is http + # Host configuration example set as a value: + # host: + # source: embedded + # value: localhost:4317 + # Host configuration example load value from an environment variable: + # host: + # source: env + # env: OTEL_LOGS_HOST + # Host configuration example load value from a JSON file: + # host: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json + # jsonPath: "$.credentials.ingest-otlp-endpoint" # Syntax JSONPath Query Expression + host: + source: embedded + value: localhost:4317 + url: /api/v2/otlp/v1/traces + # OpenTelemetry traces secret; See examples from logs. + secretRef: + type: api-token # insecure, mtls, api-token + apiToken: + source: embedded + value: "unknown" + metrics: + enabled: false + protocol: http # one of: http, grpc; Default is http + # Host configuration example set as a value: + # host: + # value: localhost:4317 + # Host configuration example load value from an environment variable: + # host: + # source: env + # env: OTEL_LOGS_HOST + # Host configuration example load value from a JSON file: + # host: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json + # jsonPath: "$.credentials.ingest-otlp-endpoint" # Syntax JSONPath Query Expression + host: + source: embedded + value: localhost:4317 + url: /api/v2/otlp/v1/metrics + # OpenTelemetry traces secret; See examples from logs. + secretRef: + type: api-token # insecure, mtls, api-token + apiToken: + source: embedded + value: "unknown" + # Metrics exposed through /metrics endpoint for prometheus + prometheus: + enabled: false + + # Database configuration + database: + host: + source: embedded + value: host.ns.svc.cluster.local + user: + source: embedded + value: user + secret: + source: embedded + value: secret + name: name + port: 1234 + + # Scheduler configuration + scheduler: + # Scheduler taskQueue configuration + taskQueue: + host: + source: embedded + value: host.ns.svc.cluster.local + port: 1234 + acl: + username: + source: embedded + value: default + password: + source: embedded + value: secret + enabled: true + secretRef: + type: insecure + # ServerCA is an optional field, if not provided, the default CA will be used. + # See secretRef -> see registry for spcific examples + # Scheduler tasks configuration + # Contains a list of configured tasks + # Each task consists of type name, retries count and cron expression + # Empty by default - uncomment and update example value(s) + tasks: [] +# - cronspec: "@every 1h" +# taskType: taskType1 +# retries: 1 +# - cronspec: "@every 2h" +# taskType: taskType2 +# retries: 2 +# - cronspec: "@every 3h" +# taskType: taskType3 +# retries: 3 + + # Services that CMK depends on configuration + services: + # Registry configuration + registry: + enabled: false + address: host.ns.svc.cluster.local:1234 + secretRef: + type: insecure + #secretRef: + # type: mtls + # mTLS: + # serverCA: + # source: file + # file: + # path: /etc/registry/ca + # format: binary + # cert: + # source: file + # file: + # path: /etc/registry/cert + # format: binary + # certKey: + # source: file + # file: + # path: /etc/registry/key + # format: binary + # AWS KMS configuration + aws: + kms: + port: 1234 + host: host.ns.svc.cluster.local + accessKeyId: + name: name + key: KEY + secretAccessKey: + name: name + key: KEY + + # Plugins configuration + # Contains a list of configured plugins + # Note: CMK API-server will not start without any plugin provided + # Empty by default - uncomment and update example value(s) + plugins: [] + # - name: plugin1 + # path: ./path/to/plugin1 + # type: Type1 + # logLevel: debug + # tags: ['tag1', 'tag2'] + # yamlConfiguration: | + # key1: value1 + # key2: value2 + # - name: plugin2 + # path: ./path/to/plugin2 + # type: Type2 + # logLevel: debug + # tags: ['tag1', 'tag2'] + # yamlConfiguration: | + # key1: value1 + # key2: value2 + + # Active plugins are controlled through Makefile. + # See k3d-apply-helm-chart target definition and ACTIVE_PLUGINS variable in the Makefile. + activePlugins: + # - plugin1 + # - plugin2 + # - plugin3 + + # Contains a list of System properties + # Properties set with optional are added to the system_properties table + # Properties set with internal are added to the systems table + # Can be set a displayName and default value for each property + system: + identifier: + displayName: "GTID" + internal: true + region: + displayName: "Region" + internal: true + type: + displayName: "Type" + internal: true + name: + displayName: "Name" + default: "n/a" + optional: true + systemrole: + displayName: "Role" + optional: true + systemroleid: + displayName: "RoleID" + optional: true + + # Event configuration + eventProcessor: + #secretRef: + # type: mtls + # mTLS: + # serverCA: + # source: file + # file: + # path: /etc/event-processor/secrets.json + # format: json + # jsonPath: "$.serverCA" # Syntax JSONPath Query Expression + # cert: + # source: file + # file: + # path: /etc/event-processor/secrets.json + # format: json + # jsonPath: "$.cert" # Syntax JSONPath Query Expression + # certKey: + # source: file + # file: + # path: /etc/event-processor/secrets.json + # format: json + # jsonPath: "$.certKey" # Syntax JSONPath Query Expression + # targets: + # Example of event targets: + #- region: eu10 + # amqp: + # url: "amqps://messaging.example.com:5671" + # target: "ks/eu10" + # source: "cmk/emea/keys" + #maxReconcileCount: 18 + # If want to limit the reconcile period for one task to one day, + # need maxReconcileCount = 18, as there is an exponential backoff for retries, + # starting with 10s and limiting at 10240s. + + audit: + #endpoint: http://localhost:4043/logs + #mtls: + # cert: + # source: file + # file: + # path: /etc/audit-logger/secrets.json + # format: json + # jsonPath: "$.ingest-otlp-cert" + # certKey: + # source: file + # file: + # path: /etc/audit-logger/secrets.json + # format: json + # jsonPath: "$.ingest-otlp-key" + # serverCa: + # source: file + # file: + # path: /etc/audit-logger/secrets.json + # format: json + # jsonPath: "$.server-ca" + #additionalProperties: | + # specVersion: "v1" + # appID: "cmk" + # folderPath: "/var/log/cmk" + # accountID: "123456789012" + # resourceGroupPath: "/cmk" + # region: "eu10" + # appImage: "cmk:latest" + # appVersion: "1.0.0" + + # Signed client data + clientData: + # This path is used to verify the signature of the client data + #signingKeysPath: /etc/signing-keys + + # Keystore pool configuration + # keystorePool: + # Target number of keystores to keep in the pool + # size: 5 + # Interval to report the size of the keystore pool + # interval: 10m diff --git a/charts/tenantmanager-cli/.helmignore b/charts/tenantmanager-cli/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/charts/tenantmanager-cli/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/tenantmanager-cli/Chart.yaml b/charts/tenantmanager-cli/Chart.yaml new file mode 100644 index 00000000..3566b859 --- /dev/null +++ b/charts/tenantmanager-cli/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: tenant-manager-cli +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.1.0" diff --git a/charts/tenantmanager-cli/README.md b/charts/tenantmanager-cli/README.md new file mode 100644 index 00000000..6b57d104 --- /dev/null +++ b/charts/tenantmanager-cli/README.md @@ -0,0 +1,39 @@ +# CMK Helm Chart +KMS2.0 helm charts + +## How To + +Download all dependencies as defined in the parent chart and sub charts. + +```bash +helm dependency build ./charts +``` + +Update the dependencies after making changes to the chart. + +```bash +helm dependency update ./charts +``` + +After changing dependencies in a sub chart, update the sub charts dependencies first +and then update the parent chart dependencies. + +```bash +helm dependency update ./charts/ +helm dependency update ./charts +``` + +Render chart templates locally and display the output. +```bash +helm template kms2x ./charts +``` + +Install entire kms2x charts +```bash +helm install kms2x ./charts +``` + +UnInstall kms2x entire deployment +```bash +helm uninstall kms2x +``` \ No newline at end of file diff --git a/charts/tenantmanager-cli/templates/NOTES.txt b/charts/tenantmanager-cli/templates/NOTES.txt new file mode 100644 index 00000000..26443dee --- /dev/null +++ b/charts/tenantmanager-cli/templates/NOTES.txt @@ -0,0 +1,16 @@ +1. Get the application URL by running these commands: +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "tenant-manager-cli.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "tenant-manager-cli.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "tenant-manager-cli.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "tenant-manager-cli.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/tenantmanager-cli/templates/_helpers.tpl b/charts/tenantmanager-cli/templates/_helpers.tpl new file mode 100644 index 00000000..35f552cb --- /dev/null +++ b/charts/tenantmanager-cli/templates/_helpers.tpl @@ -0,0 +1,194 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "tenant-manager-cli.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Namespace for all resources to be installed into +If not defined in values file then the helm release namespace is used +By default this is not set so the helm release namespace will be used + +This gets around an problem within helm discussed here +https://github.com/helm/helm/issues/5358 +*/}} +{{- define "tenant-manager-cli.namespace" -}} + {{ .Values.namespace | default .Release.Namespace }} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "tenant-manager-cli.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "tenant-manager-cli.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "tenant-manager-cli.labels" -}} +helm.sh/chart: {{ include "tenant-manager-cli.chart" . }} +{{ include "tenant-manager-cli.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Task Scheduler labels +*/}} +{{- define "tenant-manager-cli.task-scheduler.labels" -}} +helm.sh/chart: {{ include "tenant-manager-cli.chart" . }} +{{ include "tenant-manager-cli.task-scheduler.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Task Worker labels +*/}} +{{- define "tenant-manager-cli.task-worker.labels" -}} +helm.sh/chart: {{ include "tenant-manager-cli.chart" . }} +{{ include "tenant-manager-cli.task-worker.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Tenant Manager labels +*/}} +{{- define "tenant-manager-cli.tenant-manager.labels" -}} +helm.sh/chart: {{ include "tenant-manager-cli.chart" . }} +{{ include "tenant-manager-cli.tenant-manager.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Tenant Manager CLI labels +*/}} +{{- define "tenant-manager-cli.tenant-manager-cli.labels" -}} +helm.sh/chart: {{ include "tenant-manager-cli.chart" . }} +{{ include "tenant-manager-cli.tenant-manager-cli.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "tenant-manager-cli.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager-cli.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/component: {{ .Chart.Name }} +{{- end }} + +{{/* +task-scheduler Selector Labels +*/}} +{{- define "tenant-manager-cli.task-scheduler.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager-cli.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }}-task-scheduler +app.kubernetes.io/component: {{ .Chart.Name }}-task-scheduler +{{- end }} + +{{/* +task-worker Selector Labels +*/}} +{{- define "tenant-manager-cli.task-worker.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager-cli.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }}-task-worker +app.kubernetes.io/component: {{ .Chart.Name }}-task-worker +{{- end }} + +{{/* +Tenant Manager Selector labels +*/}} +{{- define "tenant-manager-cli.tenant-manager.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager-cli.name" . }}-tenant-manager +app.kubernetes.io/instance: {{ .Release.Name }}-tenant-manager +app.kubernetes.io/component: {{ .Chart.Name }}-tenant-manager +{{- end }} + +{{/* +Tenant Manager CLI Selector labels +*/}} +{{- define "tenant-manager-cli.tenant-manager-cli.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tenant-manager-cli.name" . }}-tenant-manager-cli +app.kubernetes.io/instance: {{ .Release.Name }}-tenant-manager-cli +app.kubernetes.io/component: {{ .Chart.Name }}-tenant-manager-cli +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "tenant-manager-cli.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "tenant-manager-cli.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "tenant-manager-cli.postgresqlName" -}} +{{- printf "%s-postgresql" .Release.Name -}} +{{- end }} + +{{/* +Util function for generating the image URL based on the provided options. +*/}} +{{- define "tenant-manager-cli.image" -}} +{{- $defaultTag := index . 1 -}} +{{- with index . 0 -}} +{{- if .registry -}}{{ printf "%s/%s" .registry .repository }}{{- else -}}{{- .repository -}}{{- end -}} +{{- if .digest -}}{{ printf "@%s" .digest }}{{- else -}}{{ printf ":%s" (default $defaultTag .tag) }}{{- end -}} +{{- end }} +{{- end }} + +{{/* +Active plugins +*/}} +{{- define "tenant-manager-cli.plugins" -}} +{{- $ := . }} +{{- $plugins := list -}} +{{- range .plugins -}} +{{- $plugin := . -}} +{{- range .tags -}} +{{- if has . $.activePlugins -}} + +{{- $plugins = append $plugins $plugin -}} +{{- break -}} + +{{- end -}} +{{- end -}} +{{- end -}} +{{- toYaml $plugins -}} +{{- end -}} diff --git a/charts/tenantmanager-cli/templates/configmap.yaml b/charts/tenantmanager-cli/templates/configmap.yaml new file mode 100644 index 00000000..db9462b9 --- /dev/null +++ b/charts/tenantmanager-cli/templates/configmap.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "tenant-manager-cli.name" . }}-config + labels: + {{- include "tenant-manager-cli.labels" . | nindent 4 }} +immutable: {{ .Values.application.isImmutable | default false }} +data: + config.yaml: |- + application: + name: {{ .Chart.Name }} + {{- with .Values.application }} + environment: {{ .environment }} + {{- with .labels }} + labels: + {{- toYaml . | nindent 8 }} + {{- end}} + {{- end}} + + {{- with .Values.config }} + {{- toYaml . | nindent 4 }} + {{- end}} \ No newline at end of file diff --git a/charts/templates/task-scheduler/deployment.yaml b/charts/tenantmanager-cli/templates/deployment.yaml similarity index 58% rename from charts/templates/task-scheduler/deployment.yaml rename to charts/tenantmanager-cli/templates/deployment.yaml index 4f2390f9..19dca249 100644 --- a/charts/templates/task-scheduler/deployment.yaml +++ b/charts/tenantmanager-cli/templates/deployment.yaml @@ -1,27 +1,26 @@ -{{- if .Values.taskScheduler.deploy }} --- apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "cmk.fullname" . }}-task-scheduler + name: {{ include "tenant-manager-cli.fullname" . }} labels: - {{- include "cmk.task-scheduler.labels" . | nindent 4 }} + {{- include "tenant-manager-cli.labels" . | nindent 4 }} spec: - {{- if not .Values.autoscaling.enabled }} + {{- if not .Values.hpa.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: - {{- include "cmk.task-scheduler.selectorLabels" . | nindent 6 }} + {{- include "tenant-manager-cli.selectorLabels" . | nindent 6 }} template: metadata: - {{- with .Values.podAnnotations }} + {{- with .Values.pod.annotations }} annotations: {{- toYaml . | nindent 8 }} {{- end }} labels: - {{- include "cmk.task-scheduler.labels" . | nindent 8 }} - {{- with .Values.podLabels }} + {{- include "tenant-manager-cli.labels" . | nindent 8 }} + {{- with .Values.pod.labels }} {{- toYaml . | nindent 8 }} {{- end }} spec: @@ -29,8 +28,8 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: {{ include "cmk.serviceAccountName" . }}-task-scheduler - {{- with .Values.podSecurityContext }} + serviceAccountName: {{ include "tenant-manager-cli.serviceAccountName" . }} + {{- with .Values.pod.securityContext }} securityContext: {{- toYaml . | nindent 8 }} {{- end }} @@ -42,17 +41,17 @@ spec: {{- with .Values.extraContainers }} {{- toYaml . | nindent 8 }} {{- end }} - - name: {{ include "cmk.name" . }}-task-scheduler + - name: {{ include "tenant-manager-cli.name" . }} {{- with .Values.securityContext }} securityContext: {{- toYaml . | nindent 12 }} {{- end }} - image: "{{ template "cmk.image" (tuple .Values.image $.Chart.AppVersion) }}" + image: "{{ template "tenant-manager-cli.image" (tuple .Values.image $.Chart.AppVersion) }}" imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- with .Values.taskScheduler.image.command }} + {{- with .Values.image.command }} command: [ "{{- toYaml . }}" ] {{- end }} - {{- with .Values.taskScheduler.image.args }} + {{- with .Values.image.args }} args: {{- toYaml . | nindent 12 }} {{- end }} @@ -80,33 +79,48 @@ spec: {{- with .Values.extraEnvsFrom }} envFrom: {{- . | toYaml | nindent 12 }} - {{- end}} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} volumeMounts: - - name: {{ include "cmk.name" . }}-task-scheduler-config-volume - mountPath: /etc/cmk + - name: {{ include "tenant-manager-cli.name" . }}-config-volume + mountPath: /etc/tenant-manager-cli readOnly: true {{- with .Values.extraVolumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} volumes: - - name: {{ include "cmk.name" . }}-task-scheduler-config-volume + - name: {{ include "tenant-manager-cli.name" . }}-config-volume projected: sources: - configMap: - name: {{ include "cmk.name" . }}-task-scheduler-config + name: {{ include "tenant-manager-cli.name" . }}-config {{- with .Values.extraVolumes }} {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.nodeSelector }} + {{- with .Values.pod.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.affinity }} + {{- with .Values.pod.affinity }} affinity: {{- toYaml . | nindent 8 }} {{- end }} - {{- with .Values.tolerations }} + {{- with .Values.pod.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.pod.tolerations }} tolerations: - {{- toYaml . | nindent 8 }} + {{- toYaml . | nindent 6 }} {{- end }} -{{- end }} diff --git a/charts/tenantmanager-cli/templates/hpa.yaml b/charts/tenantmanager-cli/templates/hpa.yaml new file mode 100644 index 00000000..960e7498 --- /dev/null +++ b/charts/tenantmanager-cli/templates/hpa.yaml @@ -0,0 +1,36 @@ +{{- if .Values.hpa.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "tenant-manager-cli.fullname" . }} + labels: + {{- include "tenant-manager-cli.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "tenant-manager-cli.fullname" . }} + minReplicas: {{ .Values.hpa.minReplicas }} + maxReplicas: {{ .Values.hpa.maxReplicas }} + metrics: + {{- if or .Values.hpa.targetCPUUtilizationPercentage .Values.hpa.targetMemoryUtilizationPercentage }} + {{- if .Values.hpa.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.hpa.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.hpa.targetMemoryUtilizationPercentage }} + {{- end }} + {{- else }} + [] + {{- end }} +{{- end }} diff --git a/charts/tenantmanager-cli/templates/pdb.yaml b/charts/tenantmanager-cli/templates/pdb.yaml new file mode 100644 index 00000000..038b80cd --- /dev/null +++ b/charts/tenantmanager-cli/templates/pdb.yaml @@ -0,0 +1,23 @@ +{{- if .Values.pod.disruptionBudget.enabled }} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "tenant-manager-cli.fullname" . }} + namespace: {{ include "tenant-manager-cli.namespace" . }} + labels: + {{- include "tenant-manager-cli.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "tenant-manager-cli.selectorLabels" . | nindent 6 }} + {{- if not (or (hasKey .Values.pod.disruptionBudget "minAvailable") (hasKey .Values.pod.disruptionBudget "maxUnavailable")) }} + minAvailable: 1 # Default value because minAvailable and maxUnavailable are not set + {{- end }} + {{- if hasKey .Values.pod.disruptionBudget "minAvailable" }} + minAvailable: {{ .Values.pod.disruptionBudget.minAvailable }} + {{- end }} + {{- if hasKey .Values.pod.disruptionBudget "maxUnavailable" }} + maxUnavailable: {{ .Values.pod.disruptionBudget.maxUnavailable }} + {{- end }} +{{- end }} diff --git a/charts/tenantmanager-cli/templates/service.yaml b/charts/tenantmanager-cli/templates/service.yaml new file mode 100644 index 00000000..55b2d826 --- /dev/null +++ b/charts/tenantmanager-cli/templates/service.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "tenant-manager-cli.fullname" . }} + labels: + {{- include "tenant-manager-cli.labels" . | nindent 4 }} + {{- with .Values.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type }} +{{- with .Values.service.ports }} + ports: + {{- toYaml . | nindent 4 }} +{{- end }} + selector: + {{- include "tenant-manager-cli.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/charts/templates/tenant-manager/serviceaccount.yaml b/charts/tenantmanager-cli/templates/serviceaccount.yaml similarity index 52% rename from charts/templates/tenant-manager/serviceaccount.yaml rename to charts/tenantmanager-cli/templates/serviceaccount.yaml index 040dd4cf..7970c0fb 100644 --- a/charts/templates/tenant-manager/serviceaccount.yaml +++ b/charts/tenantmanager-cli/templates/serviceaccount.yaml @@ -1,13 +1,12 @@ -{{- if and .Values.tenantManager.deploy .Values.serviceAccount.create -}} +{{- if .Values.serviceAccount.create -}} apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "cmk.serviceAccountName" . }}-tenant-manager + name: {{ include "tenant-manager-cli.serviceAccountName" . }} labels: - {{- include "cmk.tenant-manager.labels" . | nindent 4 }} + {{- include "tenant-manager-cli.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} automountServiceAccountToken: {{ .Values.serviceAccount.automount }} -{{- end }} diff --git a/charts/tenantmanager-cli/values.yaml b/charts/tenantmanager-cli/values.yaml new file mode 100644 index 00000000..9953b68b --- /dev/null +++ b/charts/tenantmanager-cli/values.yaml @@ -0,0 +1,669 @@ +# Default values for cmk. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Override the "name" value, which is used to annotate some of +# the resources that are created by this Chart (using "app.kubernetes.io/name"). +# +docs:property +nameOverride: "" + +# Override the "fullname" value. This value is used as part of +# most of the names of the resources created by this Helm chart. +# +docs:property +fullnameOverride: "" + +# This namespace allows you to define where the services are installed into. +# If not set then they use the namespace of the release. +# This is helpful when installing a chart dependency (sub chart). +namespace: "" + +# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ +replicaCount: 1 + +# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ +image: + # The container registry to pull the image from. + # For example: + # registry: ghcr.io/openkcm + # repository: images/checker + # +docs:property + registry: ghcr.io/openkcm + + # The container image + # +docs:property + repository: images/cmk + + # Override the image tag to deploy by setting this variable. + # If no value is set, the chart's appVersion is used. + # +docs:property + tag: "" + + # Setting a digest will override any tag. + # +docs:property + # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 + + # Kubernetes imagePullPolicy. + pullPolicy: IfNotPresent + + # # Setting the arguments for the container + # # +docs:property + args: + - api-server +# - task-scheduler +# - task-worker +# - task-manager +# - task-manager-cli + # - --graceful-shutdown 2 + # - --graceful-message 'Graceful shutdown in %d seconds' + + # Setting the command + # +docs:property + #command: "./extension-server" + +# This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: +# - name: "" + +# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +pod: + # This is for setting Kubernetes Annotations to a Pod. + # For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + annotations: { } + + # This is for setting Kubernetes Labels to a Pod. + # For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + labels: {} + + securityContext: {} + # fsGroup: 2000 + + disruptionBudget: + # Enable or disable the PodDisruptionBudget resource. + # + # This prevents downtime during voluntary disruptions such as during a Node upgrade. + # For example, the PodDisruptionBudget will block `kubectl drain` + # Pod is currently running. + enabled: false + + # This configures the minimum available pods for disruptions. It can either be set to + # an integer (e.g. 1) or a percentage value (e.g. 25%). + # It cannot be used if `maxUnavailable` is set. + # +docs:property + # +docs:type=unknown + # minAvailable: 1 + + # This configures the maximum unavailable pods for disruptions. It can either be set to + # an integer (e.g. 1) or a percentage value (e.g. 25%). + # it cannot be used if `minAvailable` is set. + # +docs:property + # +docs:type=unknown + # maxUnavailable: 1 + nodeSelector: { } + tolerations: [ ] + affinity: { } + topologySpreadConstraints: [] + + + + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + +# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ +service: + # Labels to add to the service + labels: {} + # Annotations to add to the service + annotations: {} + # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + type: ClusterIP + # This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports + ports: + - port: 8081 # must match .Values.cmk.port + protocol: TCP + targetPort: http + name: http + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +livenessProbe: + httpGet: + path: /probe/liveness + port: http-status + scheme: HTTP + failureThreshold: 1 + periodSeconds: 10 +readinessProbe: + httpGet: + path: /probe/readiness + port: http-status + scheme: HTTP + failureThreshold: 1 + periodSeconds: 10 + +# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/ +hpa: + enabled: false + minReplicas: 1 + maxReplicas: 1 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + +# Additional init containers on the output Deployment definition. +extraInitContainers: [] + +# Additional containers on the output Deployment definition. +extraContainers: [] + +# Additional volumes on the output Deployment definition. +extraVolumes: [] + +# Additional volumeMounts on the output Deployment definition. +extraVolumeMounts: [] + +# Additional ens on the output Deployment definition. +extraEnvs: [] + +# Additional envsFrom on the output Deployment definition. +extraEnvsFrom: [] + + +ports: + - name: http-status + containerPort: 8888 + protocol: TCP + - name: http + containerPort: 8081 + protocol: TCP + +application: + isImmutable: false + # Environment where the application is running + environment: local + # Labels associated to metrics, traces and logs + labels: { } + +config: + # Feature gates + featureGates: + enrich-header-with-client-type: true + enrich-header-with-client-region: true + disable-client-certificate-computation: false + disable-jwt-token-computation: false + + http: + port: 8081 + + # Expose the status port + status: + enabled: true + address: ":8888" + profiling: false + + # Certificates configuration + certificates: + # rootCertURL + rootCertURL: https://aia.pki.co.example.com/aia/EXAMPLE%20Cloud%20Root%20CA.crt + # Validity of the certificates in days; Must be between 7 and 30 days + validityDays: 30 + # Threshold in days to rotate the certificates; Must be between 1 and 30 days + rotationThresholdDays: 7 + + ## Crypto layer configuration + cryptoLayer: + certX509Trusts: + source: embedded + value: | + { + "crypto-1": { + "Subject": "FakeCert", + "RootCA": "https://aia.pki.co.example.com/aia/EXAMPLE%20Cloud%20Root%20CA.crt" + } + } + # This does set the logger configuration + # +docs:property + logger: + level: debug # one of: debug, info, warn, error + # Format of the logs + format: json # one of: json, text + formatter: + time: + type: pattern # one of: pattern, unix + # Used only when the property type: pattern + # Should follow golang time pattern + # Default value time.RFC3339. + pattern: "Mon Jan 02 15:04:05 -0700 2006" + # Used only when the property type: unix + # Time units are "1ns", "1us" (or "1µs"), "1ms", "1s" + # Default value 1s. + precision: 1s + fields: + # Field names (this way the field name can be changed) to be used on log records; These are their defaults. + error: "error" + message: "msg" + level: "level" + time: "time" + # Fields names used by OTEL to track the Trace and Span ID + otel: + traceID: "trace.id" # Default is TraceID + spanID: "span.id" # Default is SpanID + masking: + # All fields under PII, the formatters will mask the value and keeping first 4 original characters + pii: + - email + - ip-address + # All fields under other, the formatters will mask the value, using given mask. + other: + jwt-token: "*****" + telemetry: + logs: + enabled: false + protocol: http # one of: http, grpc; Default is http + # Host configuration example set as a value: + # host: + # source: embedded + # value: localhost:4317 + # Host configuration example load value from an environment variable: + # host: + # source: env + # env: OTEL_LOGS_HOST + # Host configuration example load value from a JSON file: + # host: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json + # jsonPath: "$.credentials.ingest-otlp-endpoint" # Syntax JSONPath Query Expression + host: + source: embedded + value: localhost:4317 + url: /api/v2/otlp/v1/logs + # OpenTelemetry secret connections; Applicable in the same way for logs, traces and metrics + # Insecure configuration example: + # secretRef: + # type: insecure # one of: insecure, mtls, api-token + # APIToken configuration example loading value from environment variable: + # secretRef: + # type: api-token # one of: insecure, mtls, api-token + # apiToken: + # source: env + # env: OTEL_LOS_API_TOKEN + # APIToken configuration example loading value from binary file as is: + # secretRef: + # type: api-token # one of: insecure, mtls, api-token + # apiToken: + # source: file + # path: /etc/credentials/api-token + # format: binary # one of: json, binary + # APIToken configuration example loading value from JSON file, extracting a specific field: + # secretRef: + # type: api-token # one of: insecure, mtls, api-token + # apiToken: + # source: file + # path: /etc/credentials/api-token.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.api-token" # Syntax JSONPath Query Expression + # mTLS configuration example loading value from environment variables: + # secretRef: + # type: mtls # one of: insecure, mtls, api-token + # mtls: + # cert: + # source: env + # env: OTEL_LOGS_X509_CERT + # certKey: + # source: env + # env: OTEL_LOGS_X509_CERT_KEY + # serverCA: + # source: env + # env: OTEL_LOGS_X509_SERVER_CA + # mTLS configuration example loading value from binary file as is: + # secretRef: + # type: mtls # one of: insecure, mtls, api-token + # mtls: + # cert: + # source: file + # file: + # path: /etc/credentials/cert.pem + # format: binary # one of: json, binary + # certKey: + # source: file + # file: + # path: /etc/credentials/cert-key.pem + # format: binary # one of: json, binary + # serverCA: + # source: file + # file: + # path: /etc/credentials/server-ca.pem + # format: binary # one of: json, binary + # mTLS configuration example loading value from JSON file, extracting a specific field: + # secretRef: + # type: mtls # one of: insecure, mtls, api-token + # mtls: + # cert: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.ingest-otlp-cert" # Syntax JSONPath Query Expression + # certKey: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.ingest-otlp-key" # Syntax JSONPath Query Expression + # serverCA: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json, binary + # jsonPath: "$.credentials.server-ca" # Syntax JSONPath Query Expression + secretRef: + type: api-token # one of: insecure, mtls, api-token + apiToken: + source: embedded + value: "unknown" + traces: + enabled: false + protocol: http # one of: http, grpc; Default is http + # Host configuration example set as a value: + # host: + # source: embedded + # value: localhost:4317 + # Host configuration example load value from an environment variable: + # host: + # source: env + # env: OTEL_LOGS_HOST + # Host configuration example load value from a JSON file: + # host: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json + # jsonPath: "$.credentials.ingest-otlp-endpoint" # Syntax JSONPath Query Expression + host: + source: embedded + value: localhost:4317 + url: /api/v2/otlp/v1/traces + # OpenTelemetry traces secret; See examples from logs. + secretRef: + type: api-token # insecure, mtls, api-token + apiToken: + source: embedded + value: "unknown" + metrics: + enabled: false + protocol: http # one of: http, grpc; Default is http + # Host configuration example set as a value: + # host: + # value: localhost:4317 + # Host configuration example load value from an environment variable: + # host: + # source: env + # env: OTEL_LOGS_HOST + # Host configuration example load value from a JSON file: + # host: + # source: file + # file: + # path: /etc/credentials/config.json + # format: json # one of: json + # jsonPath: "$.credentials.ingest-otlp-endpoint" # Syntax JSONPath Query Expression + host: + source: embedded + value: localhost:4317 + url: /api/v2/otlp/v1/metrics + # OpenTelemetry traces secret; See examples from logs. + secretRef: + type: api-token # insecure, mtls, api-token + apiToken: + source: embedded + value: "unknown" + # Metrics exposed through /metrics endpoint for prometheus + prometheus: + enabled: false + + # Database configuration + database: + host: + source: embedded + value: host.ns.svc.cluster.local + user: + source: embedded + value: user + secret: + source: embedded + value: secret + name: name + port: 1234 + + # Scheduler configuration + scheduler: + # Scheduler taskQueue configuration + taskQueue: + host: + source: embedded + value: host.ns.svc.cluster.local + port: 1234 + acl: + username: + source: embedded + value: default + password: + source: embedded + value: secret + enabled: true + secretRef: + type: insecure + # ServerCA is an optional field, if not provided, the default CA will be used. + # See secretRef -> see registry for spcific examples + # Scheduler tasks configuration + # Contains a list of configured tasks + # Each task consists of type name, retries count and cron expression + # Empty by default - uncomment and update example value(s) + tasks: [] +# - cronspec: "@every 1h" +# taskType: taskType1 +# retries: 1 +# - cronspec: "@every 2h" +# taskType: taskType2 +# retries: 2 +# - cronspec: "@every 3h" +# taskType: taskType3 +# retries: 3 + + # Services that CMK depends on configuration + services: + # Registry configuration + registry: + enabled: false + address: host.ns.svc.cluster.local:1234 + secretRef: + type: insecure + #secretRef: + # type: mtls + # mTLS: + # serverCA: + # source: file + # file: + # path: /etc/registry/ca + # format: binary + # cert: + # source: file + # file: + # path: /etc/registry/cert + # format: binary + # certKey: + # source: file + # file: + # path: /etc/registry/key + # format: binary + # AWS KMS configuration + aws: + kms: + port: 1234 + host: host.ns.svc.cluster.local + accessKeyId: + name: name + key: KEY + secretAccessKey: + name: name + key: KEY + + # Plugins configuration + # Contains a list of configured plugins + # Note: CMK API-server will not start without any plugin provided + # Empty by default - uncomment and update example value(s) + plugins: [] + # - name: plugin1 + # path: ./path/to/plugin1 + # type: Type1 + # logLevel: debug + # tags: ['tag1', 'tag2'] + # yamlConfiguration: | + # key1: value1 + # key2: value2 + # - name: plugin2 + # path: ./path/to/plugin2 + # type: Type2 + # logLevel: debug + # tags: ['tag1', 'tag2'] + # yamlConfiguration: | + # key1: value1 + # key2: value2 + + # Active plugins are controlled through Makefile. + # See k3d-apply-helm-chart target definition and ACTIVE_PLUGINS variable in the Makefile. + activePlugins: + # - plugin1 + # - plugin2 + # - plugin3 + + # Contains a list of System properties + # Properties set with optional are added to the system_properties table + # Properties set with internal are added to the systems table + # Can be set a displayName and default value for each property + system: + identifier: + displayName: "GTID" + internal: true + region: + displayName: "Region" + internal: true + type: + displayName: "Type" + internal: true + name: + displayName: "Name" + default: "n/a" + optional: true + systemrole: + displayName: "Role" + optional: true + systemroleid: + displayName: "RoleID" + optional: true + + # Event configuration + eventProcessor: + #secretRef: + # type: mtls + # mTLS: + # serverCA: + # source: file + # file: + # path: /etc/event-processor/secrets.json + # format: json + # jsonPath: "$.serverCA" # Syntax JSONPath Query Expression + # cert: + # source: file + # file: + # path: /etc/event-processor/secrets.json + # format: json + # jsonPath: "$.cert" # Syntax JSONPath Query Expression + # certKey: + # source: file + # file: + # path: /etc/event-processor/secrets.json + # format: json + # jsonPath: "$.certKey" # Syntax JSONPath Query Expression + # targets: + # Example of event targets: + #- region: eu10 + # amqp: + # url: "amqps://messaging.example.com:5671" + # target: "ks/eu10" + # source: "cmk/emea/keys" + #maxReconcileCount: 18 + # If want to limit the reconcile period for one task to one day, + # need maxReconcileCount = 18, as there is an exponential backoff for retries, + # starting with 10s and limiting at 10240s. + + audit: + #endpoint: http://localhost:4043/logs + #mtls: + # cert: + # source: file + # file: + # path: /etc/audit-logger/secrets.json + # format: json + # jsonPath: "$.ingest-otlp-cert" + # certKey: + # source: file + # file: + # path: /etc/audit-logger/secrets.json + # format: json + # jsonPath: "$.ingest-otlp-key" + # serverCa: + # source: file + # file: + # path: /etc/audit-logger/secrets.json + # format: json + # jsonPath: "$.server-ca" + #additionalProperties: | + # specVersion: "v1" + # appID: "cmk" + # folderPath: "/var/log/cmk" + # accountID: "123456789012" + # resourceGroupPath: "/cmk" + # region: "eu10" + # appImage: "cmk:latest" + # appVersion: "1.0.0" + + # Signed client data + clientData: + # This path is used to verify the signature of the client data + #signingKeysPath: /etc/signing-keys + + # Keystore pool configuration + # keystorePool: + # Target number of keystores to keep in the pool + # size: 5 + # Interval to report the size of the keystore pool + # interval: 10m diff --git a/cmd/api-server/export_test.go b/cmd/api-server/export_test.go deleted file mode 100644 index 3684a700..00000000 --- a/cmd/api-server/export_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -var ( - Run = run - RunFunctionWithSigHandling = runFuncWithSignalHandling - MonitorKeystorePoolSize = monitorKeystorePoolSize -) diff --git a/cmd/api-server/main_test.go b/cmd/api-server/main_test.go deleted file mode 100644 index c196ffaa..00000000 --- a/cmd/api-server/main_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package main_test - -import ( - "context" - "net/http" - "os" - "testing" - "time" - - "github.com/openkcm/common-sdk/pkg/commoncfg" - "github.com/stretchr/testify/require" - - apiServer "github.com/openkcm/cmk/cmd/api-server" - "github.com/openkcm/cmk/internal/config" - "github.com/openkcm/cmk/internal/testutils" -) - -func TestServerRunningAndShutdown(t *testing.T) { - _, _ = testutils.NewTestDB(t, testutils.TestDBConfig{}) - - cfg := &config.Config{ - HTTP: config.HTTPServer{ - Address: "localhost:8082", - }, - - Database: config.Database{ - Host: commoncfg.SourceRef{ - Source: commoncfg.EmbeddedSourceValue, - Value: "localhost", - }, - User: commoncfg.SourceRef{ - Source: commoncfg.EmbeddedSourceValue, - Value: "postgres", - }, - Secret: commoncfg.SourceRef{ - Source: commoncfg.EmbeddedSourceValue, - Value: "secret", - }, - Name: "cmk", - Port: "5433", - }, - BaseConfig: commoncfg.BaseConfig{ - Logger: commoncfg.Logger{ - Format: "json", - Level: "info", - }, - }, - } - - ctx := t.Context() - - go func() { - err := apiServer.Run(ctx, cfg) - //nolint:testifylint - require.NoError(t, err) - }() - - url := "http://" + cfg.HTTP.Address + "/keys" - - // Wait until server has started - for { - req, _ := http.NewRequestWithContext(t.Context(), http.MethodGet, url, nil) - - r, err := http.DefaultClient.Do(req) - if err == nil { - defer r.Body.Close() - break - } - - time.Sleep(100 * time.Millisecond) - } - - // Send shutdown to the server - ctx.Done() - - // Wait until cant connect to the server - for { - req, _ := http.NewRequestWithContext(t.Context(), http.MethodGet, url, nil) - - r, err := http.DefaultClient.Do(req) - if err == nil { - defer r.Body.Close() - break - } - - time.Sleep(100 * time.Millisecond) - } -} - -func TestRun(t *testing.T) { - t.Run("Should error on not possible database connection", func(t *testing.T) { - err := apiServer.Run(t.Context(), &config.Config{ - HTTP: config.HTTPServer{ - Address: "localhost:8082", - }, - Database: config.Database{ - Host: commoncfg.SourceRef{ - Value: "error", - }, - User: commoncfg.SourceRef{ - Value: "error", - }, - Secret: commoncfg.SourceRef{ - Value: "error", - }, - Name: "error", - Port: "5433", - }, - BaseConfig: commoncfg.BaseConfig{ - Logger: commoncfg.Logger{ - Format: "json", - Level: "info", - }, - }, - }) - require.Error(t, err) - }) -} - -func TestRunFunctionWithSigHandling(t *testing.T) { - t.Run("Should exitCode 1 on config not found", func(t *testing.T) { - exitCode := apiServer.RunFunctionWithSigHandling(func(_ context.Context, _ *config.Config) error { - return nil - }) - require.Equal(t, 1, exitCode) - }) - - t.Run("Should exitCode 0 on run", func(t *testing.T) { - filename := "config.yaml" - f, err := os.Create(filename) - require.NoError(t, err) - - defer f.Close() - defer os.Remove(filename) - - exitCode := apiServer.RunFunctionWithSigHandling(func(_ context.Context, _ *config.Config) error { - return nil - }) - require.Equal(t, 0, exitCode) - }) -} - -func TestMonitorKeystorePoolSize(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) - defer cancel() - - cfg := config.Config{ - KeystorePool: config.KeystorePool{ - Interval: 100 * time.Millisecond, - }, - Database: config.Database{ - Host: commoncfg.SourceRef{Source: "embedded", Value: "localhost"}, - User: commoncfg.SourceRef{Source: "embedded", Value: "postgres"}, - Secret: commoncfg.SourceRef{Source: "embedded", Value: "secret"}, - Name: "cmk", - Port: "5433", - }, - } - - // Run in goroutine, should exit after context timeout - go func() { - apiServer.MonitorKeystorePoolSize(ctx, cfg) - }() - - <-ctx.Done() - // Check if the error is due to context deadline exceeded, not due to other reasons - require.Error(t, ctx.Err(), &context.DeadlineExceeded) -} diff --git a/cmd/api-server/main.go b/cmd/cmk-core/apiserver/command.go similarity index 71% rename from cmd/api-server/main.go rename to cmd/cmk-core/apiserver/command.go index 8b3f7ec6..c02ba682 100644 --- a/cmd/api-server/main.go +++ b/cmd/cmk-core/apiserver/command.go @@ -1,12 +1,8 @@ -package main +package apiserver import ( "context" - "flag" - "fmt" "log/slog" - "os" - "os/signal" "syscall" "time" @@ -17,6 +13,7 @@ import ( "github.com/openkcm/common-sdk/pkg/status" "github.com/prometheus/client_golang/prometheus" "github.com/samber/oops" + "github.com/spf13/cobra" "github.com/openkcm/cmk/internal/config" "github.com/openkcm/cmk/internal/constants" @@ -28,13 +25,6 @@ import ( "github.com/openkcm/cmk/internal/repo/sql" ) -var ( - BuildInfo = "{}" - gracefulShutdownSec = flag.Int64("graceful-shutdown", 1, "graceful shutdown seconds") - gracefulShutdownMessage = flag.String("graceful-shutdown-message", "Graceful shutdown in %d seconds", - "graceful shutdown message") -) - const ( healthStatusTimeoutS = 5 * time.Second postgresDriverName = "pgx" @@ -44,54 +34,11 @@ const ( //nolint:mnd var defaultConfig = map[string]any{"Certificates": map[string]int{"ValidityDays": 30}} -// runFuncWithSignalHandling runs the given function with signal handling. When -// a CTRL-C is received, the context will be cancelled on which the function can -// act upon. -// It returns the exitCode -func runFuncWithSignalHandling(f func(context.Context, *config.Config) error) int { - ctx, cancelOnSignal := signal.NotifyContext( - context.Background(), - os.Interrupt, syscall.SIGTERM, - ) - defer cancelOnSignal() - - cfg, err := loadConfig() - if err != nil { - log.Error(ctx, "Failed to load the configuration", err) - _, _ = fmt.Fprintln(os.Stderr, err) - - return 1 - } - - log.Debug(ctx, "Starting the application", slog.Any("config", *cfg)) - - err = f(ctx, cfg) - if err != nil { - log.Error(ctx, "Failed to start the application", err) - _, _ = fmt.Fprintln(os.Stderr, err) - - return 1 - } - - // graceful shutdown so running goroutines may finish - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(*gracefulShutdownMessage, *gracefulShutdownSec)) - time.Sleep(time.Duration(*gracefulShutdownSec) * time.Second) - - return 0 -} - // - Starts the status server // - Starts the CMK API Server func run(ctx context.Context, cfg *config.Config) error { - // Update Version - err := commoncfg.UpdateConfigVersion(&cfg.BaseConfig, BuildInfo) - if err != nil { - return oops.In("main"). - Wrapf(err, "Failed to update the version configuration") - } - // LoggerConfig initialisation - err = logger.InitAsDefault(cfg.Logger, cfg.Application) + err := logger.InitAsDefault(cfg.Logger, cfg.Application) if err != nil { return oops.In("main"). Wrapf(err, "Failed to initialise the logger") @@ -148,7 +95,7 @@ func monitorKeystorePoolSize( dbCon, err := db.StartDBConnection(cfg.Database, cfg.DatabaseReplicas) if err != nil { - log.Error(ctx, "failed to initialize DB Connection", err) + log.Error(ctx, "failed to initialize db Connection", err) } pool := manager.NewPool(sql.NewRepository(dbCon)) @@ -221,7 +168,7 @@ func startStatusServer(ctx context.Context, cfg *config.Config) { }() } -func loadConfig() (*config.Config, error) { +func loadConfig(buildInfo string) (*config.Config, error) { cfg := &config.Config{} loader := commoncfg.NewLoader( @@ -240,6 +187,13 @@ func loadConfig() (*config.Config, error) { return nil, oops.In("main").Wrapf(err, "failed to load config") } + // Update Version + err = commoncfg.UpdateConfigVersion(&cfg.BaseConfig, buildInfo) + if err != nil { + return nil, oops.In("main"). + Wrapf(err, "Failed to update the version configuration") + } + err = cfg.Validate() if err != nil { return nil, oops.In("main").Wrapf(err, "failed to validate config") @@ -248,11 +202,25 @@ func loadConfig() (*config.Config, error) { return cfg, nil } -// main is the entry point for the application. It is intentionally kept small -// because it is hard to test, which would lower test coverage. -func main() { - flag.Parse() +func Cmd(buildInfo string) *cobra.Command { + var cmd = &cobra.Command{ + Use: "api-server", + Short: "CMK API Server", + Long: "CMK API Server is a component of the Cloud Key Management system that provides ", + RunE: func(cmd *cobra.Command, _ []string) error { + cfg, err := loadConfig(buildInfo) + if err != nil { + return oops.In("main").Wrapf(err, "failed to load config") + } + + err = run(cmd.Context(), cfg) + if err != nil { + return oops.In("main").Wrapf(err, "failed to run the api server") + } + + return err + }, + } - exitCode := runFuncWithSignalHandling(run) - os.Exit(exitCode) + return cmd } diff --git a/cmd/cmk-core/apiserver/command_test.go b/cmd/cmk-core/apiserver/command_test.go new file mode 100644 index 00000000..7fb81aba --- /dev/null +++ b/cmd/cmk-core/apiserver/command_test.go @@ -0,0 +1,70 @@ +package apiserver_test + +import ( + "context" + "testing" + "time" + + "github.com/openkcm/common-sdk/pkg/commoncfg" + "github.com/stretchr/testify/require" + + "github.com/openkcm/cmk/cmd/core/apiserver" + "github.com/openkcm/cmk/internal/config" +) + +func TestRun(t *testing.T) { + t.Run("Should error on not possible database connection", func(t *testing.T) { + err := apiserver.Run(t.Context(), &config.Config{ + HTTP: config.HTTPServer{ + Address: "localhost:8082", + }, + Database: config.Database{ + Host: commoncfg.SourceRef{ + Value: "error", + }, + User: commoncfg.SourceRef{ + Value: "error", + }, + Secret: commoncfg.SourceRef{ + Value: "error", + }, + Name: "error", + Port: "5433", + }, + BaseConfig: commoncfg.BaseConfig{ + Logger: commoncfg.Logger{ + Format: "json", + Level: "info", + }, + }, + }) + require.Error(t, err) + }) +} + +func TestMonitorKeystorePoolSize(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer cancel() + + cfg := config.Config{ + KeystorePool: config.KeystorePool{ + Interval: 100 * time.Millisecond, + }, + Database: config.Database{ + Host: commoncfg.SourceRef{Source: "embedded", Value: "localhost"}, + User: commoncfg.SourceRef{Source: "embedded", Value: "postgres"}, + Secret: commoncfg.SourceRef{Source: "embedded", Value: "secret"}, + Name: "cmk", + Port: "5433", + }, + } + + // Run in goroutine, should exit after context timeout + go func() { + apiserver.MonitorKeystorePoolSize(ctx, cfg) + }() + + <-ctx.Done() + // Check if the error is due to context deadline exceeded, not due to other reasons + require.Error(t, ctx.Err(), &context.DeadlineExceeded) +} diff --git a/cmd/cmk-core/apiserver/export_test.go b/cmd/cmk-core/apiserver/export_test.go new file mode 100644 index 00000000..82accbc0 --- /dev/null +++ b/cmd/cmk-core/apiserver/export_test.go @@ -0,0 +1,6 @@ +package apiserver + +var ( + Run = run + MonitorKeystorePoolSize = monitorKeystorePoolSize +) diff --git a/cmd/cmk-core/main.go b/cmd/cmk-core/main.go new file mode 100644 index 00000000..12aee006 --- /dev/null +++ b/cmd/cmk-core/main.go @@ -0,0 +1,104 @@ +package main + +import ( + "context" + "fmt" + "log/slog" + "os" + "os/signal" + "syscall" + "time" + + "github.com/openkcm/common-sdk/pkg/utils" + "github.com/spf13/cobra" + + slogctx "github.com/veqryn/slog-context" + + "github.com/openkcm/cmk/cmd/core/apiserver" + "github.com/openkcm/cmk/cmd/core/taskscheduler" + "github.com/openkcm/cmk/cmd/core/taskworker" +) + +var ( + // BuildInfo will be set by the build system + BuildInfo = "{}" + + isVersionCmd bool + gracefulShutdownSec int64 + gracefulShutdownMessage string +) + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "CMK Version", + RunE: func(cmd *cobra.Command, _ []string) error { + isVersionCmd = true + + value, err := utils.ExtractFromComplexValue(BuildInfo) + if err != nil { + return err + } + + slog.InfoContext(cmd.Context(), value) + + return nil + }, +} + +func rootCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "cmk", + Short: "OpenKCM CMK - Customer Manager Keys", + Long: "OpenKCM Customer Manager Keys(CMK) is a key management service to manage " + + "encryption keys for applications and services.", + } + + cmd.PersistentFlags().Int64Var(&gracefulShutdownSec, "graceful-shutdown", + 1, + "graceful shutdown seconds", + ) + cmd.PersistentFlags().StringVar(&gracefulShutdownMessage, "graceful-shutdown-message", + "Graceful shutdown in %d seconds", + "graceful shutdown message", + ) + + cmd.AddCommand( + versionCmd, + apiserver.Cmd(BuildInfo), + taskscheduler.Cmd(BuildInfo), + taskworker.Cmd(BuildInfo), + ) + + return cmd +} + +func execute() error { + ctx, cancelOnSignal := signal.NotifyContext( + context.Background(), + os.Interrupt, syscall.SIGTERM, + ) + defer cancelOnSignal() + + err := rootCmd().ExecuteContext(ctx) + if err != nil { + slogctx.Error(ctx, "Failed to start the application", "error", err) + _, _ = fmt.Fprintln(os.Stderr, err) + + return err + } + + // graceful shutdown so running goroutines may finish + if !isVersionCmd { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(gracefulShutdownMessage, gracefulShutdownSec)) + time.Sleep(time.Duration(gracefulShutdownSec) * time.Second) + } + + return nil +} + +func main() { + err := execute() + if err != nil { + os.Exit(1) + } +} diff --git a/cmd/cmk-core/taskscheduler/command.go b/cmd/cmk-core/taskscheduler/command.go new file mode 100644 index 00000000..474107b6 --- /dev/null +++ b/cmd/cmk-core/taskscheduler/command.go @@ -0,0 +1,75 @@ +package taskscheduler + +import ( + "github.com/openkcm/common-sdk/pkg/commoncfg" + "github.com/openkcm/common-sdk/pkg/logger" + "github.com/samber/oops" + "github.com/spf13/cobra" + + "github.com/openkcm/cmk/internal/async" + "github.com/openkcm/cmk/internal/config" + "github.com/openkcm/cmk/internal/constants" + cmklog "github.com/openkcm/cmk/internal/log" +) + +func Cmd(buildInfo string) *cobra.Command { + var cmd = &cobra.Command{ + Use: "task-scheduler", + Short: "CMK Task Scheduler", + Long: "CMK Task Scheduler - Customizable and efficient task scheduling solution.", + RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + + defaultValues := map[string]any{} + cfg := &config.Config{} + + err := commoncfg.LoadConfig( + cfg, + defaultValues, + constants.DefaultConfigPath1, + constants.DefaultConfigPath2, + ".", + ) + if err != nil { + return oops.In("main").Wrapf(err, "failed to load the config") + } + + // Update Version + err = commoncfg.UpdateConfigVersion(&cfg.BaseConfig, buildInfo) + if err != nil { + return oops.In("main"). + Wrapf(err, "Failed to update the version configuration") + } + + // LoggerConfig initialisation + err = logger.InitAsDefault(cfg.Logger, cfg.Application) + if err != nil { + return oops.In("main"). + Wrapf(err, "Failed to initialise the logger") + } + + cronJob, err := async.New(cfg) + if err != nil { + return oops.In("main").Wrapf(err, "failed to create the scheduler") + } + + err = cronJob.RunScheduler() + if err != nil { + return oops.In("main").Wrapf(err, "failed to start the scheduler job") + } + + <-ctx.Done() + + err = cronJob.Shutdown(ctx) + if err != nil { + return oops.In("main").Wrapf(err, "failed to shutdown the scheduler") + } + + cmklog.Info(ctx, "shutting down scheduler") + + return err + }, + } + + return cmd +} diff --git a/cmd/cmk-core/taskworker/command.go b/cmd/cmk-core/taskworker/command.go new file mode 100644 index 00000000..5da82f4e --- /dev/null +++ b/cmd/cmk-core/taskworker/command.go @@ -0,0 +1,75 @@ +package taskworker + +import ( + "github.com/openkcm/common-sdk/pkg/commoncfg" + "github.com/openkcm/common-sdk/pkg/logger" + "github.com/samber/oops" + "github.com/spf13/cobra" + + "github.com/openkcm/cmk/internal/async" + "github.com/openkcm/cmk/internal/config" + "github.com/openkcm/cmk/internal/constants" + cmklog "github.com/openkcm/cmk/internal/log" +) + +func Cmd(buildInfo string) *cobra.Command { + var cmd = &cobra.Command{ + Use: "task-worker", + Short: "CMK Task Worker", + Long: "CMK Task Worker - A background service that processes tasks asynchronously.", + RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + + defaultValues := map[string]any{} + cfg := &config.Config{} + + err := commoncfg.LoadConfig( + cfg, + defaultValues, + constants.DefaultConfigPath1, + constants.DefaultConfigPath2, + ".", + ) + if err != nil { + return oops.In("main").Wrapf(err, "failed to load the config") + } + + // Update Version + err = commoncfg.UpdateConfigVersion(&cfg.BaseConfig, buildInfo) + if err != nil { + return oops.In("main"). + Wrapf(err, "Failed to update the version configuration") + } + + // LoggerConfig initialisation + err = logger.InitAsDefault(cfg.Logger, cfg.Application) + if err != nil { + return oops.In("main"). + Wrapf(err, "Failed to initialise the logger") + } + + cronJob, err := async.New(cfg) + if err != nil { + return oops.In("main").Wrapf(err, "failed to create the worker") + } + + err = cronJob.RunWorker(ctx, cfg) + if err != nil { + return oops.In("main").Wrapf(err, "failed to start the worker") + } + + <-ctx.Done() + + err = cronJob.Shutdown(ctx) + if err != nil { + return oops.In("main").Wrapf(err, "%s", async.ErrClientShutdown.Error()) + } + + cmklog.Info(ctx, "shutting down worker") + + return nil + }, + } + + return cmd +} diff --git a/cmd/task-scheduler/main.go b/cmd/task-scheduler/main.go deleted file mode 100644 index 613429f8..00000000 --- a/cmd/task-scheduler/main.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "context" - "log" - "os" - "os/signal" - "syscall" - - "github.com/openkcm/common-sdk/pkg/commoncfg" - "github.com/openkcm/common-sdk/pkg/logger" - "github.com/samber/oops" - - "github.com/openkcm/cmk/internal/async" - "github.com/openkcm/cmk/internal/config" - "github.com/openkcm/cmk/internal/constants" - cmklog "github.com/openkcm/cmk/internal/log" -) - -const AppName = "scheduler" - -func start() error { - ctx, cancelOnSignal := signal.NotifyContext( - context.Background(), - os.Interrupt, syscall.SIGTERM, - ) - - defer cancelOnSignal() - - defaultValues := map[string]any{} - cfg := &config.Config{} - - err := commoncfg.LoadConfig( - cfg, - defaultValues, - constants.DefaultConfigPath1, - constants.DefaultConfigPath2, - ".", - ) - if err != nil { - return oops.In("main").Wrapf(err, "failed to load the config") - } - - // LoggerConfig initialisation - err = logger.InitAsDefault(cfg.Logger, cfg.Application) - if err != nil { - return oops.In("main"). - Wrapf(err, "Failed to initialise the logger") - } - - cronJob, err := async.New(cfg) - if err != nil { - return oops.In("main").Wrapf(err, "failed to create the scheduler") - } - - err = cronJob.RunScheduler() - if err != nil { - return oops.In("main").Wrapf(err, "failed to start the scheduler job") - } - - <-ctx.Done() - - err = cronJob.Shutdown(ctx) - if err != nil { - return oops.In("main").Wrapf(err, "failed to shutdown the scheduler") - } - - cmklog.Info(ctx, "shutting down scheduler") - - return nil -} - -func main() { - err := start() - if err != nil { - log.Fatal(err) - } -} diff --git a/cmd/task-worker/main.go b/cmd/task-worker/main.go deleted file mode 100644 index 7dc1a404..00000000 --- a/cmd/task-worker/main.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "context" - "log" - "os" - "os/signal" - "syscall" - - "github.com/openkcm/common-sdk/pkg/commoncfg" - "github.com/openkcm/common-sdk/pkg/logger" - "github.com/samber/oops" - - "github.com/openkcm/cmk/internal/async" - "github.com/openkcm/cmk/internal/config" - "github.com/openkcm/cmk/internal/constants" - cmklog "github.com/openkcm/cmk/internal/log" -) - -const AppName = "worker" - -func start() error { - ctx, cancelOnSignal := signal.NotifyContext( - context.Background(), - os.Interrupt, syscall.SIGTERM, - ) - - defer cancelOnSignal() - - defaultValues := map[string]any{} - cfg := &config.Config{} - - err := commoncfg.LoadConfig( - cfg, - defaultValues, - constants.DefaultConfigPath1, - constants.DefaultConfigPath2, - ".", - ) - if err != nil { - return oops.In("main").Wrapf(err, "failed to load the config") - } - - // LoggerConfig initialisation - err = logger.InitAsDefault(cfg.Logger, cfg.Application) - if err != nil { - return oops.In("main"). - Wrapf(err, "Failed to initialise the logger") - } - - cronJob, err := async.New(cfg) - if err != nil { - return oops.In("main").Wrapf(err, "failed to create the worker") - } - - err = cronJob.RunWorker(ctx, cfg) - if err != nil { - return oops.In("main").Wrapf(err, "failed to start the worker") - } - - <-ctx.Done() - - err = cronJob.Shutdown(ctx) - if err != nil { - return oops.In("main").Wrapf(err, "%s", async.ErrClientShutdown.Error()) - } - - cmklog.Info(ctx, "shutting down worker") - - return nil -} - -func main() { - err := start() - if err != nil { - log.Fatal(err) - } -} diff --git a/cmd/tenant-manager-cli/command.go b/cmd/tenant-manager-cli/command.go new file mode 100644 index 00000000..9c455a6d --- /dev/null +++ b/cmd/tenant-manager-cli/command.go @@ -0,0 +1,88 @@ +package main + +import ( + "context" + "fmt" + "log/slog" + "os" + "os/signal" + "syscall" + "time" + + "github.com/openkcm/common-sdk/pkg/utils" + "github.com/spf13/cobra" + + slogctx "github.com/veqryn/slog-context" + + "github.com/openkcm/cmk/internal/tenant-manager/cli" +) + +var ( + // BuildInfo will be set by the build system + BuildInfo = "{}" + + isVersionCmd bool + gracefulShutdownSec int64 + gracefulShutdownMessage string +) +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Tenant Manager CLI Version", + RunE: func(cmd *cobra.Command, _ []string) error { + isVersionCmd = true + + value, err := utils.ExtractFromComplexValue(BuildInfo) + if err != nil { + return err + } + + slog.InfoContext(cmd.Context(), value) + + return nil + }, +} + +func rootCmd() *cobra.Command { + factory := cli.NewCommandFactory() + + return cli.InitWithCommandFactory( + factory.NewCreateGroupsCmd(), + factory.NewCreateTenantCmd(), + factory.NewDeleteTenantCmd(), + factory.NewGetTenantCmd(), + factory.NewListTenantsCmd(), + factory.NewUpdateTenantCmd(), + versionCmd, + ) +} + +func execute() error { + ctx, cancelOnSignal := signal.NotifyContext( + context.Background(), + os.Interrupt, syscall.SIGTERM, + ) + defer cancelOnSignal() + + err := rootCmd().ExecuteContext(ctx) + if err != nil { + slogctx.Error(ctx, "Failed to start the application", "error", err) + _, _ = fmt.Fprintln(os.Stderr, err) + + return err + } + + // graceful shutdown so running goroutines may finish + if !isVersionCmd { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(gracefulShutdownMessage, gracefulShutdownSec)) + time.Sleep(time.Duration(gracefulShutdownSec) * time.Second) + } + + return nil +} + +func main() { + err := execute() + if err != nil { + os.Exit(1) + } +} diff --git a/cmd/tenant-manager-cli/export_test.go b/cmd/tenant-manager-cli/export_test.go deleted file mode 100644 index f487b801..00000000 --- a/cmd/tenant-manager-cli/export_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -var ( - Run = run - RunFunctionWithSigHandling = runFuncWithSignalHandling - SetupCommands = setupCommands -) diff --git a/cmd/tenant-manager-cli/main.go b/cmd/tenant-manager-cli/main.go deleted file mode 100644 index 36f5b34c..00000000 --- a/cmd/tenant-manager-cli/main.go +++ /dev/null @@ -1,142 +0,0 @@ -package main - -import ( - "context" - "log/slog" - "os" - "os/signal" - "syscall" - - "github.com/openkcm/common-sdk/pkg/commoncfg" - "github.com/openkcm/common-sdk/pkg/logger" - "github.com/samber/oops" - "github.com/spf13/cobra" - - multitenancy "github.com/bartventer/gorm-multitenancy/v8" - - "github.com/openkcm/cmk/internal/config" - "github.com/openkcm/cmk/internal/constants" - "github.com/openkcm/cmk/internal/db" - "github.com/openkcm/cmk/internal/log" - "github.com/openkcm/cmk/tenant-manager/tenant-cli/cmd" -) - -func runFuncWithSignalHandling(f func(context.Context, *config.Config) error) int { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // Create signal channel - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) - - // Handle signals in a separate goroutine - go func() { - <-sigChan - log.Info(ctx, "Interrupt signal received, shutting down...") - cancel() - }() - - cfg, err := loadConfig() - if err != nil { - log.Error(ctx, "Failed to load config:", err) - - return 1 - } - - log.Debug(ctx, "Starting the application", slog.Any("config", cfg)) - - err = f(ctx, cfg) - if err != nil { - log.Error(ctx, "Falied running tenant-manager-cli", err) - return 1 - } - - return 0 -} - -func run(ctx context.Context, cfg *config.Config) error { - err := logger.InitAsDefault(cfg.Logger, cfg.Application) - if err != nil { - return oops.In("main").Wrapf(err, "Failed to initialise the logger") - } - - dbCon, err := db.StartDB(ctx, cfg.Database, cfg.Provisioning, cfg.DatabaseReplicas) - if err != nil { - return oops.In("main").Wrapf(err, "Failed to initialise db connection") - } - - rootCmd := setupCommands(ctx, dbCon) - - err = rootCmd.ExecuteContext(ctx) - if err != nil { - return oops.In("main").Wrapf(err, "error executing command") - } - - return nil -} - -// setupCommands creates and configures all CLI commands and flags -func setupCommands(ctx context.Context, dbCon *multitenancy.DB) *cobra.Command { - var ( - id, region, status string - sleep bool - ) - - factory := cmd.NewCommandFactory(dbCon) - rootCmd := factory.NewRootCmd(ctx) - rootCmd.PersistentFlags().BoolVar(&sleep, "sleep", false, "Enable sleep mode") - - createGroupsCmd := factory.NewCreateGroupsCmd(ctx) - createGroupsCmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") - rootCmd.AddCommand(createGroupsCmd) - - createCmd := factory.NewCreateTenantCmd(ctx) - createCmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") - createCmd.Flags().StringVarP(®ion, "region", "r", "", "Tenant region") - createCmd.Flags().StringVarP(&status, "status", "s", "", "Tenant status") - rootCmd.AddCommand(createCmd) - - deleteTenantCmd := factory.NewDeleteTenantCmd(ctx) - deleteTenantCmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") - rootCmd.AddCommand(deleteTenantCmd) - - getTenantCmd := factory.NewGetTenantCmd(ctx) - getTenantCmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") - rootCmd.AddCommand(getTenantCmd) - - listTenantsCmd := factory.NewListTenantsCmd(ctx) - rootCmd.AddCommand(listTenantsCmd) - - updateTenantCmd := factory.NewUpdateTenantCmd(ctx) - updateTenantCmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") - updateTenantCmd.Flags().StringVarP(®ion, "region", "r", "", "Tenant region") - updateTenantCmd.Flags().StringVarP(&status, "status", "s", "", "Tenant status") - rootCmd.AddCommand(updateTenantCmd) - - return rootCmd -} - -func loadConfig() (*config.Config, error) { - cfg := &config.Config{} - - loader := commoncfg.NewLoader( - cfg, - commoncfg.WithPaths( - ".", - "/etc/tenant-manager-cli", - ), - commoncfg.WithEnvOverride(constants.APIName), - ) - - err := loader.LoadConfig() - if err != nil { - return nil, oops.In("main").Wrapf(err, "failed to load config") - } - - return cfg, nil -} - -func main() { - exitCode := runFuncWithSignalHandling(run) - os.Exit(exitCode) -} diff --git a/cmd/tenant-manager-cli/main_test.go b/cmd/tenant-manager-cli/main_test.go deleted file mode 100644 index 677fe1db..00000000 --- a/cmd/tenant-manager-cli/main_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package main_test - -import ( - "context" - "errors" - "os" - "testing" - - "github.com/openkcm/common-sdk/pkg/commoncfg" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - tmCLI "github.com/openkcm/cmk/cmd/tenant-manager-cli" - "github.com/openkcm/cmk/internal/config" -) - -var errTest = errors.New("test error") - -const ( - validConfigContent = `application: - name: test-app -logger: - level: info` - - invalidConfigContent = `invalid: yaml: content: [ - malformed: yaml` -) - -func TestSetupCommands(t *testing.T) { - t.Run("Should create root command with all subcommands", func(t *testing.T) { - ctx := t.Context() - - rootCmd := tmCLI.SetupCommands(ctx, nil) - - assert.NotNil(t, rootCmd) - assert.NotEmpty(t, rootCmd.Use) - assert.NotNil(t, rootCmd.PersistentFlags().Lookup("sleep")) - - commands := rootCmd.Commands() - t.Logf("Found %d commands", len(commands)) - - for _, cmd := range commands { - t.Logf("Command: %s", cmd.Name()) - } - - assert.GreaterOrEqual(t, len(commands), 1, "Root command should be created") - }) -} - -func TestRunFunctionWithSigHandling(t *testing.T) { - t.Run("Should return exit code 1 when config loading fails", func(t *testing.T) { - // Setup environment with invalid config to force loading failure - setupTestEnvironment(t, invalidConfigContent) - - testFunc := func(_ context.Context, _ *config.Config) error { - t.Error("Should not reach this point when config loading fails") - return nil - } - - exitCode := tmCLI.RunFunctionWithSigHandling(testFunc) - assert.Equal(t, 1, exitCode) - }) - - t.Run("Should return exit code 1 when run function returns error", func(t *testing.T) { - setupTestEnvironment(t, validConfigContent) - - testFunc := func(_ context.Context, _ *config.Config) error { - return errTest - } - - exitCode := tmCLI.RunFunctionWithSigHandling(testFunc) - assert.Equal(t, 1, exitCode) - }) - - t.Run("Should return exit code 0 when run function succeeds", func(t *testing.T) { - setupTestEnvironment(t, validConfigContent) - - executed := false - testFunc := func(_ context.Context, cfg *config.Config) error { - executed = true - - assert.Equal(t, "test-app", cfg.Application.Name) - - return nil - } - - exitCode := tmCLI.RunFunctionWithSigHandling(testFunc) - assert.Equal(t, 0, exitCode) - assert.True(t, executed) - }) -} - -func TestRun(t *testing.T) { - t.Run("Should error on invalid logger config", func(t *testing.T) { - ctx := t.Context() - - cfg := &config.Config{ - BaseConfig: commoncfg.BaseConfig{ - Logger: commoncfg.Logger{ - Level: "invalid-level", - Format: "invalid-format", - Formatter: commoncfg.LoggerFormatter{ - Time: commoncfg.LoggerTime{ - Type: "unix", - Precision: "*#md1", - }, - }, - }, - }, - } - - err := tmCLI.Run(ctx, cfg) - - require.Error(t, err) - assert.Contains(t, err.Error(), "Failed to initialise the logger") - }) - - t.Run("Should error on invalid database config", func(t *testing.T) { - ctx := t.Context() - - cfg := &config.Config{ - BaseConfig: commoncfg.BaseConfig{ - Logger: commoncfg.Logger{ - Level: "info", - Format: "json", - }, - }, - Database: config.Database{}, - } - - err := tmCLI.Run(ctx, cfg) - require.Error(t, err) - assert.Contains(t, err.Error(), "Failed to initialise db connection") - }) -} - -// Helper function to create a temporary test environment with config file -func setupTestEnvironment(t *testing.T, configContent string) { - t.Helper() - - tempDir := t.TempDir() - t.Chdir(tempDir) - - if configContent != "" { - writeConfigFile(t, configContent) - } -} - -// Helper function to write config file -func writeConfigFile(t *testing.T, content string) { - t.Helper() - - err := os.WriteFile("config.yaml", []byte(content), 0600) - require.NoError(t, err) -} diff --git a/cmd/tenant-manager/main.go b/cmd/tenant-manager/command.go similarity index 50% rename from cmd/tenant-manager/main.go rename to cmd/tenant-manager/command.go index 6d896290..61a1fe66 100644 --- a/cmd/tenant-manager/main.go +++ b/cmd/tenant-manager/command.go @@ -2,7 +2,6 @@ package main import ( "context" - "flag" "fmt" "log/slog" "os" @@ -15,72 +14,31 @@ import ( "github.com/openkcm/common-sdk/pkg/logger" "github.com/openkcm/common-sdk/pkg/otlp" "github.com/openkcm/common-sdk/pkg/status" + "github.com/openkcm/common-sdk/pkg/utils" "github.com/samber/oops" + "github.com/spf13/cobra" + + slogctx "github.com/veqryn/slog-context" "github.com/openkcm/cmk/internal/config" "github.com/openkcm/cmk/internal/db/dsn" "github.com/openkcm/cmk/internal/log" - "github.com/openkcm/cmk/tenant-manager/business" + "github.com/openkcm/cmk/internal/tenant-manager/business" ) const ( + DefaultConfigPath1 = "/etc/tenant-manager" + DefaultConfigPath2 = "$HOME/.tenant-manager" + defaultTimeout = 5 errMsgLoadConfig = "Failed to load the configuration" errMsgLoggerInit = "Failed to initialise the logger" errMsgLoadTelemetry = "Failed to load the telemetry" errMsgStartTheBusinessApp = "Failed to start the main business application" errMsgStatusServer = "Failure on the status server" - errMsgStartApp = "Failed to start the application" postgresDriverName = "pgx" ) -var ( - gracefulShutdownSec = flag.Int64("graceful-shutdown", 1, "graceful shutdown seconds") - gracefulShutdownMessage = flag.String("graceful-shutdown-message", "Graceful shutdown in %d seconds", - "graceful shutdown message") -) - -// run does the heavy lifting until the service is up and running. It will: -// - Load the config and initializes the logger -// - Start the status server in a goroutine -// - Start the business logic and eventually return the error from it -// - -func run(ctx context.Context) error { - // Load Configuration - cfg, err := loadConfig() - if err != nil { - return oops.In("main"). - Wrapf(err, errMsgLoadConfig) - } - - // LoggerConfig initialisation - err = logger.InitAsDefault(cfg.Logger, cfg.Application) - if err != nil { - return oops.In("main"). - Wrapf(err, errMsgLoggerInit) - } - - // OpenTelemetry initialisation - err = otlp.Init(ctx, &cfg.Application, &cfg.Telemetry, &cfg.Logger) - if err != nil { - return oops.In("main"). - Wrapf(err, errMsgLoadTelemetry) - } - - // Status Server Initialisation - startStatusServer(ctx, cfg) - - // Business Logic - err = business.Main(ctx, cfg) - if err != nil { - return oops.In("main"). - Wrapf(err, errMsgStartTheBusinessApp) - } - - return nil -} - func startStatusServer(ctx context.Context, cfg *config.Config) { liveness := status.WithLiveness( health.NewHandler( @@ -131,44 +89,122 @@ func loadConfig() (*config.Config, error) { err := commoncfg.LoadConfig( cfg, map[string]any{}, - "/etc/tenant-manager", + DefaultConfigPath1, + DefaultConfigPath2, ".", ) return cfg, err } -// runFuncWithSignalHandling runs the given function with signal handling. When -// a CTRL-C is received, the context will be cancelled on which the function can -// act upon. -func runFuncWithSignalHandling(f func(context.Context) error) int { +var ( + // BuildInfo will be set by the build system + BuildInfo = "{}" + + isVersionCmd bool + gracefulShutdownSec int64 + gracefulShutdownMessage string +) + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Tenant Manager Version", + RunE: func(cmd *cobra.Command, _ []string) error { + isVersionCmd = true + + value, err := utils.ExtractFromComplexValue(BuildInfo) + if err != nil { + return err + } + + slog.InfoContext(cmd.Context(), value) + + return nil + }, +} + +func rootCmd() *cobra.Command { + var cmd = &cobra.Command{ + Use: "tenant-manager", + Short: "CMK the Tenant Manager", + Long: `CMK Tenant Manager - a service to manage tenants.`, + RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + + // Load Configuration + cfg, err := loadConfig() + if err != nil { + return oops.In("main"). + Wrapf(err, errMsgLoadConfig) + } + + // Update Version + err = commoncfg.UpdateConfigVersion(&cfg.BaseConfig, BuildInfo) + if err != nil { + return oops.In("main"). + Wrapf(err, "Failed to update the version configuration") + } + + // LoggerConfig initialisation + err = logger.InitAsDefault(cfg.Logger, cfg.Application) + if err != nil { + return oops.In("main"). + Wrapf(err, errMsgLoggerInit) + } + + // OpenTelemetry initialisation + err = otlp.Init(ctx, &cfg.Application, &cfg.Telemetry, &cfg.Logger) + if err != nil { + return oops.In("main"). + Wrapf(err, errMsgLoadTelemetry) + } + + // Status Server Initialisation + startStatusServer(ctx, cfg) + + // Business Logic + err = business.Main(ctx, cfg) + if err != nil { + return oops.In("main"). + Wrapf(err, errMsgStartTheBusinessApp) + } + + return nil + }, + } + + cmd.AddCommand(versionCmd) + + return cmd +} + +func execute() error { ctx, cancelOnSignal := signal.NotifyContext( context.Background(), os.Interrupt, syscall.SIGTERM, ) defer cancelOnSignal() - exitCode := 0 - - err := f(ctx) + err := rootCmd().ExecuteContext(ctx) if err != nil { - log.Error(ctx, errMsgStartApp, err) + slogctx.Error(ctx, "Failed to start the application", "error", err) _, _ = fmt.Fprintln(os.Stderr, err) - exitCode = 1 + + return err } // graceful shutdown so running goroutines may finish - _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(*gracefulShutdownMessage, *gracefulShutdownSec)) - time.Sleep(time.Duration(*gracefulShutdownSec) * time.Second) + if !isVersionCmd { + _, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(gracefulShutdownMessage, gracefulShutdownSec)) + time.Sleep(time.Duration(gracefulShutdownSec) * time.Second) + } - return exitCode + return nil } -// main is the entry point for the application. It is intentionally kept small -// because it is hard to test, which would lower test coverage. func main() { - flag.Parse() - - exitCode := runFuncWithSignalHandling(run) - os.Exit(exitCode) + err := execute() + if err != nil { + os.Exit(1) + } } diff --git a/cmd/tenant-manager/export_test.go b/cmd/tenant-manager/export_test.go deleted file mode 100644 index b0739c5f..00000000 --- a/cmd/tenant-manager/export_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package main - -var ( - Run = run - RunFunctionWithSigHandling = runFuncWithSignalHandling - LoadConfig = loadConfig - StartStatusServer = startStatusServer -) diff --git a/cmd/tenant-manager/main_test.go b/cmd/tenant-manager/main_test.go deleted file mode 100644 index 84422ff7..00000000 --- a/cmd/tenant-manager/main_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package main_test - -import ( - "context" - "errors" - "os" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - tenantmanager "github.com/openkcm/cmk/cmd/tenant-manager" - "github.com/openkcm/cmk/internal/config" -) - -var ErrTest = errors.New("test error") - -func TestLoadConfig(t *testing.T) { - t.Run("Should return error if config file not found", func(t *testing.T) { - _, err := tenantmanager.LoadConfig() - t.Log("Error:", err) - require.Error(t, err) - }) - - t.Run("Should return error if config file has wrong struct", func(t *testing.T) { - content := []byte("application:\n nameE: test-app\n") - err := os.WriteFile("config.yaml", content, 0600) - require.NoError(t, err) - - defer os.Remove("config.yaml") - - _, err = tenantmanager.LoadConfig() - t.Log("Error:", err) - require.Error(t, err) - }) - - t.Run("Should load config if config file exists", func(t *testing.T) { - content := []byte("application:\n name: test-app\nlogger:\n level: info\n") - err := os.WriteFile("config.yaml", content, 0600) - require.NoError(t, err) - - defer os.Remove("config.yaml") - - cfg, err := tenantmanager.LoadConfig() - require.NoError(t, err) - require.NotNil(t, cfg) - require.Equal(t, "test-app", cfg.Application.Name) - }) -} - -func TestRunFuncWithSignalHandling(t *testing.T) { - t.Run("success", func(t *testing.T) { - exitCode := tenantmanager.RunFunctionWithSigHandling(func(_ context.Context) error { - return nil - }) - - assert.Equal(t, 0, exitCode) - }) - - t.Run("error", func(t *testing.T) { - exitCode := tenantmanager.RunFunctionWithSigHandling(func(_ context.Context) error { - return ErrTest - }) - - assert.Equal(t, 1, exitCode) - }) -} - -func TestStartStatusServer(t *testing.T) { - cfg := &config.Config{} - - // Call and check for no panic. - tenantmanager.StartStatusServer(t.Context(), cfg) - - // Optionally, wait a short time to let the goroutine start - time.Sleep(100 * time.Millisecond) -} - -func TestRun(t *testing.T) { - t.Run("should fail if no config", func(t *testing.T) { - err := tenantmanager.Run(t.Context()) - require.Error(t, err, "Run should return an error") - }) -} diff --git a/internal/controllers/cmk/keyconfiguration_tags_controller_test.go b/internal/controllers/cmk/keyconfiguration_tags_controller_test.go index d31b730e..0d1da033 100644 --- a/internal/controllers/cmk/keyconfiguration_tags_controller_test.go +++ b/internal/controllers/cmk/keyconfiguration_tags_controller_test.go @@ -19,7 +19,7 @@ import ( cmkcontext "github.com/openkcm/cmk/utils/context" ) -// startAPIKeyConfigTags starts the API server and returns a DB connection and a mux for testing +// startAPIKeyConfigTags starts the API server and returns a db connection and a mux for testing func startAPIKeyConfigTags(t *testing.T) (*multitenancy.DB, *http.ServeMux, string) { t.Helper() diff --git a/internal/db/connection.go b/internal/db/connection.go index 3bcd9ad9..0385800b 100644 --- a/internal/db/connection.go +++ b/internal/db/connection.go @@ -21,7 +21,7 @@ var ( ErrLoadingReplicaDialectors = errors.New("error loading replica dialectors") ) -// StartDBConnection opens DB connection using data from `config.DB`. +// StartDBConnection opens db connection using data from `config.db`. func StartDBConnection( conf config.Database, replicas []config.Database, @@ -29,7 +29,7 @@ func StartDBConnection( return StartDBConnectionPlugins(conf, replicas, map[string]gorm.Plugin{}) } -// StartDBConnectionPlugins opens DB connection using data from `config.DB` +// StartDBConnectionPlugins opens db connection using data from `config.db` // and plugins that are passed in a form of map because GORM config stores // them this way. // It is an extension of `StartDBConnection` functionality. diff --git a/internal/db/db.go b/internal/db/db.go index bb4ae199..d5c4c221 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -32,30 +32,30 @@ var ( const DBLogDomain = "db" -// StartDB starts DB connection and runs migrations +// StartDB starts db connection and runs migrations func StartDB( ctx context.Context, dbConf config.Database, provisioning config.Provisioning, replicas []config.Database, ) (*multitenancy.DB, error) { - log.Info(ctx, "Starting DB connection ") + log.Info(ctx, "Starting db connection ") dbCon, err := StartDBConnection(dbConf, replicas) if err != nil { - return nil, oops.In(DBLogDomain).Wrapf(err, "failed to initialize DB Connection") + return nil, oops.In(DBLogDomain).Wrapf(err, "failed to initialize db Connection") } dbCon = dbCon.WithContext(ctx) - log.Info(ctx, "Starting DB migration") + log.Info(ctx, "Starting db migration") err = migrate(ctx, dbCon) if err != nil { return nil, oops.In(DBLogDomain).Wrapf(err, "failed to run table creation migration") } - log.Info(ctx, "DB migration finished") + log.Info(ctx, "db migration finished") err = addKeystoreFromConfig(ctx, dbCon, provisioning.InitKeystoreConfig) if err != nil { @@ -65,7 +65,7 @@ func StartDB( return dbCon, nil } -// migrate runs DB migrations +// migrate runs db migrations func migrate(ctx context.Context, db *multitenancy.DB) error { err := db.RegisterModels( ctx, diff --git a/internal/db/dialect/postgres.go b/internal/db/dialect/postgres.go index 2677e15e..dba0481b 100644 --- a/internal/db/dialect/postgres.go +++ b/internal/db/dialect/postgres.go @@ -8,7 +8,7 @@ import ( ) // NewFrom returns a postgres dialector. -// Hint: `dsn` package contains utility to convert `config.DB` to DSN string that can be passed here. +// Hint: `dsn` package contains utility to convert `config.db` to DSN string that can be passed here. func NewFrom(dsn string) gorm.Dialector { return pg.New(pg.Config{ Config: postgres.Config{ diff --git a/internal/manager/certificate_test.go b/internal/manager/certificate_test.go index 2f6d60bf..d8130b83 100644 --- a/internal/manager/certificate_test.go +++ b/internal/manager/certificate_test.go @@ -313,7 +313,7 @@ func TestCertificateManager_GetDefaultClientCert(t *testing.T) { assert.Nil(t, cert) }) - t.Run("Failed to get default keystore certificate with DB error", func(t *testing.T) { + t.Run("Failed to get default keystore certificate with db error", func(t *testing.T) { forced := testutils.NewDBErrorForced(db, ErrForced) forced.Register() @@ -333,7 +333,7 @@ func TestCertificateManager_GetDefaultClientCert(t *testing.T) { assert.NotNil(t, cert) }) - t.Run("Failed to get default HYOK certificate with DB error", func(t *testing.T) { + t.Run("Failed to get default HYOK certificate with db error", func(t *testing.T) { forced := testutils.NewDBErrorForced(db, ErrForced) forced.Register() diff --git a/internal/manager/group_test.go b/internal/manager/group_test.go index 82d55380..98dc0a56 100644 --- a/internal/manager/group_test.go +++ b/internal/manager/group_test.go @@ -292,7 +292,7 @@ func TestUpdateGroup(t *testing.T) { assert.Error(t, err) }) - t.Run("Should error on rename with DB error", func(t *testing.T) { + t.Run("Should error on rename with db error", func(t *testing.T) { forced := testutils.NewDBErrorForced(db, ErrForced) forced.WithUpdate().Register() diff --git a/internal/manager/key.go b/internal/manager/key.go index 71e52cb5..3f6f2137 100644 --- a/internal/manager/key.go +++ b/internal/manager/key.go @@ -767,7 +767,7 @@ func (km *KeyManager) fetchImportParams(ctx context.Context, key *model.Key) (*m if err != nil { return nil, err } - // Set ImportParams in DB + // Set ImportParams in db err = km.repo.Transaction(ctx, func(ctx context.Context, r repo.Repo) error { err = r.Set(ctx, importParams) if err != nil { diff --git a/internal/manager/system.go b/internal/manager/system.go index e7ce5d24..c606da8b 100644 --- a/internal/manager/system.go +++ b/internal/manager/system.go @@ -418,7 +418,7 @@ func (m *SystemManager) createSystemIfNotExists(ctx context.Context, newSystem * } ctx = log.InjectSystem(ctx, newSystem) - log.Info(ctx, "Found new system from registry, adding to CMK DB") + log.Info(ctx, "Found new system from registry, adding to CMK db") err := m.repo.Create(ctx, newSystem) if err != nil { diff --git a/internal/manager/system_test.go b/internal/manager/system_test.go index 8d9ea1b1..e99e04b7 100644 --- a/internal/manager/system_test.go +++ b/internal/manager/system_test.go @@ -633,7 +633,7 @@ func TestRefreshSystems(t *testing.T) { } testutils.CreateTestEntities(ctx, t, r, existingSystem) - t.Run("No systems in registry - systems in DB remain unchanged", func(t *testing.T) { + t.Run("No systems in registry - systems in db remain unchanged", func(t *testing.T) { // Act m.RefreshSystemsData(ctx) // Verify @@ -649,7 +649,7 @@ func TestRefreshSystems(t *testing.T) { assert.Equal(t, existingSystem.ID, systems[0].ID) }) - t.Run("No systems for current tenant in registry - systems in DB remain unchanged", func(t *testing.T) { + t.Run("No systems for current tenant in registry - systems in db remain unchanged", func(t *testing.T) { // Prepare existingSystems := []*model.System{} existingSystemsCount, _ := r.List(ctx, &model.System{}, &existingSystems, *repo.NewQuery()) @@ -736,7 +736,7 @@ func TestRefreshSystems(t *testing.T) { assert.Equal(t, region, foundSystem.Region) }) - t.Run("Same System in a different region returned by the registry - two different systems in DB", func(t *testing.T) { + t.Run("Same System in a different region returned by the registry - two different systems in db", func(t *testing.T) { // Prepare existingSystems := []*model.System{} existingSystemsCount, _ := r.List(ctx, &model.System{}, &existingSystems, *repo.NewQuery()) diff --git a/internal/manager/workflow.go b/internal/manager/workflow.go index 18a83d28..b9060544 100644 --- a/internal/manager/workflow.go +++ b/internal/manager/workflow.go @@ -301,7 +301,7 @@ func (w *WorkflowManager) TransitionWorkflow( // addApprovers adds the specified approvers to the workflow // and transitions the workflow to the next state. -// This is wrapped in a transaction to ensure that DB state is consistent +// This is wrapped in a transaction to ensure that db state is consistent func (w *WorkflowManager) addApprovers( ctx context.Context, userID uuid.UUID, @@ -373,7 +373,7 @@ func (w *WorkflowManager) checkOngoingWorkflowForArtifact( // updateApproverDecisionAndApplyTransition updates the approver // decision and applies the transition to the wf. -// This is wrapped in a transaction to ensure that DB state is +// This is wrapped in a transaction to ensure that db state is // consistent in case of errors. func (w *WorkflowManager) applyTransition( ctx context.Context, diff --git a/tenant-manager/business/business.go b/internal/tenant-manager/business/business.go similarity index 97% rename from tenant-manager/business/business.go rename to internal/tenant-manager/business/business.go index cba10bc0..23d0264c 100644 --- a/tenant-manager/business/business.go +++ b/internal/tenant-manager/business/business.go @@ -12,7 +12,7 @@ import ( "github.com/openkcm/cmk/internal/config" "github.com/openkcm/cmk/internal/db" "github.com/openkcm/cmk/internal/log" - "github.com/openkcm/cmk/tenant-manager/internal/operator" + "github.com/openkcm/cmk/internal/tenant-manager/operator" ) const logDomain = "business" diff --git a/tenant-manager/business/business_test.go b/internal/tenant-manager/business/business_test.go similarity index 97% rename from tenant-manager/business/business_test.go rename to internal/tenant-manager/business/business_test.go index 9d7735a0..d4e460da 100644 --- a/tenant-manager/business/business_test.go +++ b/internal/tenant-manager/business/business_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/openkcm/cmk/internal/config" + "github.com/openkcm/cmk/internal/tenant-manager/business" "github.com/openkcm/cmk/internal/testutils" - "github.com/openkcm/cmk/tenant-manager/business" ) func TestBusinessMain(t *testing.T) { diff --git a/tenant-manager/tenant-cli/cmd/README.md b/internal/tenant-manager/cli/README.md similarity index 100% rename from tenant-manager/tenant-cli/cmd/README.md rename to internal/tenant-manager/cli/README.md diff --git a/tenant-manager/integration/cli_test.go b/internal/tenant-manager/cli/cli_test.go similarity index 76% rename from tenant-manager/integration/cli_test.go rename to internal/tenant-manager/cli/cli_test.go index ec7fdf60..c6fd141e 100644 --- a/tenant-manager/integration/cli_test.go +++ b/internal/tenant-manager/cli/cli_test.go @@ -1,4 +1,4 @@ -package integration_test +package cli_test import ( "bytes" @@ -16,9 +16,9 @@ import ( tenantgrpc "github.com/openkcm/api-sdk/proto/kms/api/cmk/registry/tenant/v1" "github.com/openkcm/cmk/internal/model" + "github.com/openkcm/cmk/internal/tenant-manager/cli" + tmdb "github.com/openkcm/cmk/internal/tenant-manager/db" "github.com/openkcm/cmk/internal/testutils" - tmdb "github.com/openkcm/cmk/tenant-manager/internal/db" - "github.com/openkcm/cmk/tenant-manager/tenant-cli/cmd" integrationutils "github.com/openkcm/cmk/test/integration_utils" "github.com/openkcm/cmk/utils/base62" ) @@ -29,10 +29,6 @@ type CLISuite struct { cancel context.CancelFunc db *multitenancy.DB - sleep bool - id string - status string - region string rootCmd *cobra.Command createGroupsCmd *cobra.Command createCmd *cobra.Command @@ -48,36 +44,21 @@ func (s *CLISuite) SetupSuite() { Models: []driver.TenantTabler{&model.Tenant{}, &model.Group{}}, }) - factory := cmd.NewCommandFactory(s.db) - s.rootCmd = factory.NewRootCmd(s.T().Context()) - s.rootCmd.PersistentFlags().BoolVar(&s.sleep, "sleep", false, "Enable sleep mode") - - s.createGroupsCmd = factory.NewCreateGroupsCmd(s.T().Context()) - s.createGroupsCmd.Flags().StringVarP(&s.id, "id", "i", "", "Tenant id") - s.rootCmd.AddCommand(s.createGroupsCmd) - - s.createCmd = factory.NewCreateTenantCmd(s.T().Context()) - s.createCmd.Flags().StringVarP(&s.id, "id", "i", "", "Tenant id") - s.createCmd.Flags().StringVarP(&s.region, "region", "r", "", "Tenant region") - s.createCmd.Flags().StringVarP(&s.status, "status", "s", "", "Tenant status") - s.rootCmd.AddCommand(s.createCmd) - - s.deleteTenantCmd = factory.NewDeleteTenantCmd(s.T().Context()) - s.deleteTenantCmd.Flags().StringVarP(&s.id, "id", "i", "", "Tenant id") - s.rootCmd.AddCommand(s.deleteTenantCmd) - - s.getTenantCmd = factory.NewGetTenantCmd(s.T().Context()) - s.getTenantCmd.Flags().StringVarP(&s.id, "id", "i", "", "Tenant id") - s.rootCmd.AddCommand(s.getTenantCmd) - - s.listTenantsCmd = factory.NewListTenantsCmd(s.T().Context()) - s.rootCmd.AddCommand(s.listTenantsCmd) - - s.updateTenantCmd = factory.NewUpdateTenantCmd(s.T().Context()) - s.updateTenantCmd.Flags().StringVarP(&s.id, "id", "i", "", "Tenant id") - s.updateTenantCmd.Flags().StringVarP(&s.region, "region", "r", "", "Tenant region") - s.updateTenantCmd.Flags().StringVarP(&s.status, "status", "s", "", "Tenant status") - s.rootCmd.AddCommand(s.updateTenantCmd) + factory := cli.NewCommandFactoryWithDB(s.db) + s.createGroupsCmd = factory.NewCreateGroupsCmd() + s.createCmd = factory.NewCreateTenantCmd() + s.deleteTenantCmd = factory.NewDeleteTenantCmd() + s.getTenantCmd = factory.NewGetTenantCmd() + s.listTenantsCmd = factory.NewListTenantsCmd() + s.updateTenantCmd = factory.NewUpdateTenantCmd() + s.rootCmd = cli.InitWithCommandFactory( + s.createGroupsCmd, + s.createCmd, + s.deleteTenantCmd, + s.getTenantCmd, + s.listTenantsCmd, + s.updateTenantCmd, + ) } func (s *CLISuite) TearDownSuite() { diff --git a/internal/tenant-manager/cli/command.go b/internal/tenant-manager/cli/command.go new file mode 100644 index 00000000..0cf0a231 --- /dev/null +++ b/internal/tenant-manager/cli/command.go @@ -0,0 +1,125 @@ +package cli + +import ( + "context" + "os" + "os/signal" + "syscall" + + "github.com/openkcm/common-sdk/pkg/commoncfg" + "github.com/openkcm/common-sdk/pkg/logger" + "github.com/samber/oops" + "github.com/spf13/cobra" + + multitenancy "github.com/bartventer/gorm-multitenancy/v8" + + "github.com/openkcm/cmk/internal/config" + "github.com/openkcm/cmk/internal/constants" + "github.com/openkcm/cmk/internal/db" +) + +const ( + DefaultConfigPath1 = "/etc/tenant-manager-cli" + DefaultConfigPath2 = "$HOME/.tenant-manager-cli" +) + +var ( + id, region, status string + sleep bool +) + +type CommandFactory struct { + dbConn *multitenancy.DB +} + +func NewCommandFactory() *CommandFactory { + return &CommandFactory{} +} + +func NewCommandFactoryWithDB(dbConn *multitenancy.DB) *CommandFactory { + return &CommandFactory{ + dbConn: dbConn, + } +} + +func loadConfig() (*config.Config, error) { + cfg := &config.Config{} + + loader := commoncfg.NewLoader( + cfg, + commoncfg.WithPaths( + DefaultConfigPath1, + DefaultConfigPath2, + ".", + ), + commoncfg.WithEnvOverride(constants.APIName), + ) + + err := loader.LoadConfig() + if err != nil { + return nil, oops.Hint("failed to load config").Wrap(err) + } + + err = logger.InitAsDefault(cfg.Logger, cfg.Application) + if err != nil { + return nil, oops.Hint("Unable to initialize logger").Wrap(err) + } + + return cfg, nil +} + +func (f *CommandFactory) db(ctx context.Context) (*multitenancy.DB, error) { + if f.dbConn != nil { + return f.dbConn, nil + } + + cfg, err := loadConfig() + if err != nil { + return nil, oops.Hint("failed to load config").Wrap(err) + } + + dbCon, err := db.StartDB(ctx, cfg.Database, cfg.Provisioning, cfg.DatabaseReplicas) + if err != nil { + return nil, oops.Hint("Check database configuration").Wrap(err) + } + + f.dbConn = dbCon + + return f.dbConn, err +} + +func InitWithCommandFactory(cmds ...*cobra.Command) *cobra.Command { + cmd := &cobra.Command{ + Use: "tenant-manager-cli", + Short: "Tenant Manager CLI Application", + Long: "Tenant Manager is a simple CLI tool to manage tenants, supporting: creating tenant, " + + "creating tenant with groups, " + + "creating groups, " + + "updating of region and status field on a tenant entity in public table, " + + "updating of group names, " + + "changing any field value in any table of a tenant schema.", + + PersistentPreRunE: func(_ *cobra.Command, _ []string) error { + return nil + }, + + Run: func(cmd *cobra.Command, _ []string) { + sleep, _ := cmd.Flags().GetBool("sleep") + if sleep { + cmd.Println("Pod running...") + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + <-sigs + cmd.Println("Shutting down gracefully...") + } + }, + } + + cmd.PersistentFlags().BoolVar(&sleep, "sleep", false, "Enable sleep mode") + + cmd.AddCommand(cmds...) + + return cmd +} diff --git a/tenant-manager/tenant-cli/cmd/creategroupscmd.go b/internal/tenant-manager/cli/creategroupscmd.go similarity index 68% rename from tenant-manager/tenant-cli/cmd/creategroupscmd.go rename to internal/tenant-manager/cli/creategroupscmd.go index 33d99566..60c7d98f 100644 --- a/tenant-manager/tenant-cli/cmd/creategroupscmd.go +++ b/internal/tenant-manager/cli/creategroupscmd.go @@ -1,24 +1,24 @@ -package cmd +package cli import ( - "context" "errors" "github.com/spf13/cobra" "github.com/openkcm/cmk/internal/repo/sql" - tmdb "github.com/openkcm/cmk/tenant-manager/internal/db" + tmdb "github.com/openkcm/cmk/internal/tenant-manager/db" ) -func (f *CommandFactory) NewCreateGroupsCmd(ctx context.Context) *cobra.Command { +func (f *CommandFactory) NewCreateGroupsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "add-default-groups", Short: "Create a group for tenant. Usage: tm add-default-groups -i [tenant id]", Long: "Create a group for tenant. Usage: tm add-default-groups --id [tenant id]", Args: cobra.ExactArgs(0), - //nolint:contextcheck RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + id, _ := cmd.Flags().GetString("id") if id == "" { cmd.Println("Tenant id is required") @@ -26,17 +26,22 @@ func (f *CommandFactory) NewCreateGroupsCmd(ctx context.Context) *cobra.Command return nil } - ctx := cmd.Context() - r := sql.NewRepository(f.dbCon) + dbCon, err := f.db(ctx) + if err != nil { + cmd.Printf("Failed to connect to database: %v\n", err) + return nil + } + + r := sql.NewRepository(dbCon) - tenant := FindTenant(ctx, cmd, id, f.r) + tenant := FindTenant(ctx, cmd, id, r) if tenant == nil { cmd.Printf("Tenant with id %s not found\n", id) return nil } - err := tmdb.CreateDefaultGroups(cmd.Context(), tenant, r) + err = tmdb.CreateDefaultGroups(ctx, tenant, r) if err != nil { if errors.Is(err, tmdb.ErrOnboardingInProgress) { cmd.Printf("Default groups for tenant already exists") @@ -53,7 +58,7 @@ func (f *CommandFactory) NewCreateGroupsCmd(ctx context.Context) *cobra.Command }, } - cmd.SetContext(ctx) + cmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") return cmd } diff --git a/tenant-manager/tenant-cli/cmd/createtenantcmd.go b/internal/tenant-manager/cli/createtenantcmd.go similarity index 70% rename from tenant-manager/tenant-cli/cmd/createtenantcmd.go rename to internal/tenant-manager/cli/createtenantcmd.go index 77540b85..4255ca95 100644 --- a/tenant-manager/tenant-cli/cmd/createtenantcmd.go +++ b/internal/tenant-manager/cli/createtenantcmd.go @@ -1,7 +1,6 @@ -package cmd +package cli import ( - "context" "errors" "github.com/spf13/cobra" @@ -9,22 +8,24 @@ import ( multitenancy "github.com/bartventer/gorm-multitenancy/v8" "github.com/openkcm/cmk/internal/model" - tmdb "github.com/openkcm/cmk/tenant-manager/internal/db" + tmdb "github.com/openkcm/cmk/internal/tenant-manager/db" "github.com/openkcm/cmk/utils/base62" ) -func (f *CommandFactory) NewCreateTenantCmd(ctx context.Context) *cobra.Command { +//nolint:funlen +func (f *CommandFactory) NewCreateTenantCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create", Short: "Create a new tenant. Usage: tm create -i [tenant id] -r [tenant region] -s [tenant status]", Long: "Create a new tenant. Usage: tm create -id [tenant id] -region [tenant region] -status [tenant status]", Args: cobra.ExactArgs(0), - //nolint:contextcheck RunE: func(cmd *cobra.Command, _ []string) error { - id, _ := cmd.Flags().GetString("id") - region, _ := cmd.Flags().GetString("region") - status, _ := cmd.Flags().GetString("status") + ctx := cmd.Context() + + id, _ = cmd.Flags().GetString("id") + region, _ = cmd.Flags().GetString("region") + status, _ = cmd.Flags().GetString("status") if id == "" || region == "" || status == "" { cmd.Println("Tenant id, is required") @@ -57,7 +58,13 @@ func (f *CommandFactory) NewCreateTenantCmd(ctx context.Context) *cobra.Command }, } - err = tmdb.CreateSchema(cmd.Context(), f.dbCon, tenant) + dbCon, err := f.db(ctx) + if err != nil { + cmd.Printf("Failed to connect to database: %v\n", err) + return nil + } + + err = tmdb.CreateSchema(ctx, dbCon, tenant) if err != nil { if errors.Is(err, tmdb.ErrOnboardingInProgress) { cmd.Printf("Tenant with ID: %s already exists", tenant.ID) @@ -72,7 +79,9 @@ func (f *CommandFactory) NewCreateTenantCmd(ctx context.Context) *cobra.Command }, } - cmd.SetContext(ctx) + cmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") + cmd.Flags().StringVarP(®ion, "region", "r", "", "Tenant region") + cmd.Flags().StringVarP(&status, "status", "s", "", "Tenant status") return cmd } diff --git a/tenant-manager/integration/db_test.go b/internal/tenant-manager/cli/db_test.go similarity index 99% rename from tenant-manager/integration/db_test.go rename to internal/tenant-manager/cli/db_test.go index fd557605..3580a040 100644 --- a/tenant-manager/integration/db_test.go +++ b/internal/tenant-manager/cli/db_test.go @@ -1,4 +1,4 @@ -package integration_test +package cli_test import ( "context" @@ -18,8 +18,8 @@ import ( "github.com/openkcm/cmk/internal/model" sqlRepo "github.com/openkcm/cmk/internal/repo/sql" + tmdb "github.com/openkcm/cmk/internal/tenant-manager/db" "github.com/openkcm/cmk/internal/testutils" - tmdb "github.com/openkcm/cmk/tenant-manager/internal/db" integrationutils "github.com/openkcm/cmk/test/integration_utils" "github.com/openkcm/cmk/utils/base62" ) diff --git a/tenant-manager/tenant-cli/cmd/deletetenantcmd.go b/internal/tenant-manager/cli/deletetenantcmd.go similarity index 69% rename from tenant-manager/tenant-cli/cmd/deletetenantcmd.go rename to internal/tenant-manager/cli/deletetenantcmd.go index 9d231f9b..c18fd586 100644 --- a/tenant-manager/tenant-cli/cmd/deletetenantcmd.go +++ b/internal/tenant-manager/cli/deletetenantcmd.go @@ -1,7 +1,6 @@ -package cmd +package cli import ( - "context" "fmt" "github.com/spf13/cobra" @@ -10,34 +9,43 @@ import ( "github.com/openkcm/cmk/internal/model" "github.com/openkcm/cmk/internal/repo" + "github.com/openkcm/cmk/internal/repo/sql" ) -func (f *CommandFactory) NewDeleteTenantCmd(ctx context.Context) *cobra.Command { +func (f *CommandFactory) NewDeleteTenantCmd() *cobra.Command { cmd := &cobra.Command{ Use: "delete", Short: "Delete a new tenant. Usage: tm create -i [tenant id] -r [tenant region] -s [tenant status]", Long: "Delete a new tenant. Usage: tm create -id [tenant id] -region [tenant region] -status [tenant status]", Args: cobra.ExactArgs(0), - //nolint:contextcheck RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + id, _ := cmd.Flags().GetString("id") if id == "" { cmd.Println("Tenant id is required") return ErrTenantIDRequired } - tenant := FindTenant(cmd.Context(), cmd, id, f.r) + dbCon, err := f.db(ctx) + if err != nil { + cmd.Printf("Failed to connect to database: %v\n", err) + return nil + } + + r := sql.NewRepository(dbCon) + tenant := FindTenant(cmd.Context(), cmd, id, r) cmd.Printf("Deleting tenant. Id: %s, SchemaName: %s\n", tenant.ID, tenant.SchemaName) - err := DropSchema(f.dbCon, tenant.SchemaName) + err = DropSchema(dbCon, tenant.SchemaName) if err != nil { cmd.PrintErrf("%v %v\n", ErrDeleteTenant, err) return err } - _, err = f.r.Delete(cmd.Context(), &model.Tenant{ID: id}, *repo.NewQuery()) + _, err = r.Delete(ctx, &model.Tenant{ID: id}, *repo.NewQuery()) if err != nil { cmd.PrintErrf("%v %v\n", ErrDeleteTenant, err) return err @@ -49,7 +57,7 @@ func (f *CommandFactory) NewDeleteTenantCmd(ctx context.Context) *cobra.Command }, } - cmd.SetContext(ctx) + cmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") return cmd } diff --git a/tenant-manager/tenant-cli/cmd/errors.go b/internal/tenant-manager/cli/errors.go similarity index 96% rename from tenant-manager/tenant-cli/cmd/errors.go rename to internal/tenant-manager/cli/errors.go index 0f321684..ba065fc7 100644 --- a/tenant-manager/tenant-cli/cmd/errors.go +++ b/internal/tenant-manager/cli/errors.go @@ -1,4 +1,4 @@ -package cmd +package cli import "errors" diff --git a/tenant-manager/tenant-cli/cmd/gettenantcmd.go b/internal/tenant-manager/cli/gettenantcmd.go similarity index 63% rename from tenant-manager/tenant-cli/cmd/gettenantcmd.go rename to internal/tenant-manager/cli/gettenantcmd.go index 668ddc38..a6675923 100644 --- a/tenant-manager/tenant-cli/cmd/gettenantcmd.go +++ b/internal/tenant-manager/cli/gettenantcmd.go @@ -1,21 +1,23 @@ -package cmd +package cli import ( - "context" "encoding/json" "github.com/spf13/cobra" + + "github.com/openkcm/cmk/internal/repo/sql" ) -func (f *CommandFactory) NewGetTenantCmd(ctx context.Context) *cobra.Command { +func (f *CommandFactory) NewGetTenantCmd() *cobra.Command { cmd := &cobra.Command{ Use: "get", Short: "Get tenant by id. Usage: tm get -i [tenant id]", Long: "Get tenant by id. Usage: tm get --id [tenant id]", Args: cobra.ExactArgs(0), - //nolint:contextcheck RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + id, _ := cmd.Flags().GetString("id") if id == "" { @@ -23,7 +25,15 @@ func (f *CommandFactory) NewGetTenantCmd(ctx context.Context) *cobra.Command { return ErrTenantIDRequired } - tenant := FindTenant(cmd.Context(), cmd, id, f.r) + dbCon, err := f.db(ctx) + if err != nil { + cmd.Printf("Failed to connect to database: %v\n", err) + return nil + } + + r := sql.NewRepository(dbCon) + + tenant := FindTenant(ctx, cmd, id, r) if tenant == nil { cmd.Printf("Tenant with id %s not found\n", id) return ErrTenantNotFound @@ -39,8 +49,7 @@ func (f *CommandFactory) NewGetTenantCmd(ctx context.Context) *cobra.Command { return nil }, } - - cmd.SetContext(ctx) + cmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") return cmd } diff --git a/tenant-manager/tenant-cli/cmd/listtenantscmd.go b/internal/tenant-manager/cli/listtenantscmd.go similarity index 69% rename from tenant-manager/tenant-cli/cmd/listtenantscmd.go rename to internal/tenant-manager/cli/listtenantscmd.go index d8ea3fa3..764b339a 100644 --- a/tenant-manager/tenant-cli/cmd/listtenantscmd.go +++ b/internal/tenant-manager/cli/listtenantscmd.go @@ -1,27 +1,33 @@ -package cmd +package cli import ( - "context" - "github.com/spf13/cobra" "github.com/openkcm/cmk/internal/model" "github.com/openkcm/cmk/internal/repo" + "github.com/openkcm/cmk/internal/repo/sql" ) -func (f *CommandFactory) NewListTenantsCmd(ctx context.Context) *cobra.Command { +func (f *CommandFactory) NewListTenantsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "list", Short: "List all tenants. Usage: tm list", Long: "List all tenants. Usage: tm list", - //nolint:contextcheck RunE: func(cmd *cobra.Command, _ []string) error { ctx := cmd.Context() + dbCon, err := f.db(ctx) + if err != nil { + cmd.Printf("Failed to connect to database: %v\n", err) + return nil + } + + r := sql.NewRepository(dbCon) + var tenants []model.Tenant - _, err := f.r.List( + _, err = r.List( ctx, &model.Tenant{}, &tenants, *repo.NewQuery(), ) if err != nil { @@ -40,7 +46,5 @@ func (f *CommandFactory) NewListTenantsCmd(ctx context.Context) *cobra.Command { }, } - cmd.SetContext(ctx) - return cmd } diff --git a/tenant-manager/tenant-cli/cmd/updatetenantcmd.go b/internal/tenant-manager/cli/updatetenantcmd.go similarity index 65% rename from tenant-manager/tenant-cli/cmd/updatetenantcmd.go rename to internal/tenant-manager/cli/updatetenantcmd.go index a7cdac12..3a96bfdf 100644 --- a/tenant-manager/tenant-cli/cmd/updatetenantcmd.go +++ b/internal/tenant-manager/cli/updatetenantcmd.go @@ -1,15 +1,14 @@ -package cmd +package cli import ( - "context" - "github.com/spf13/cobra" "github.com/openkcm/cmk/internal/model" "github.com/openkcm/cmk/internal/repo" + "github.com/openkcm/cmk/internal/repo/sql" ) -func (f *CommandFactory) NewUpdateTenantCmd(ctx context.Context) *cobra.Command { +func (f *CommandFactory) NewUpdateTenantCmd() *cobra.Command { cmd := &cobra.Command{ Use: "update", Short: "Update existing tenant. Usage: tm update -i [tenant id] (-r [tenant region]) (-s [tenant status])", @@ -17,8 +16,9 @@ func (f *CommandFactory) NewUpdateTenantCmd(ctx context.Context) *cobra.Command "(--region [tenant region]) (--status [tenant status])", Args: cobra.ExactArgs(0), - //nolint:contextcheck RunE: func(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + id, _ := cmd.Flags().GetString("id") region, _ := cmd.Flags().GetString("region") status, _ := cmd.Flags().GetString("status") @@ -28,9 +28,15 @@ func (f *CommandFactory) NewUpdateTenantCmd(ctx context.Context) *cobra.Command return ErrTenantIDRequired } - ctx := cmd.Context() + dbCon, err := f.db(ctx) + if err != nil { + cmd.Printf("Failed to connect to database: %v\n", err) + return nil + } + + r := sql.NewRepository(dbCon) - tenant := FindTenant(ctx, cmd, id, f.r) + tenant := FindTenant(ctx, cmd, id, r) query := repo.NewQuery() @@ -42,7 +48,7 @@ func (f *CommandFactory) NewUpdateTenantCmd(ctx context.Context) *cobra.Command tenant.Region = region } - _, err := f.r.Patch(ctx, tenant, *query) + _, err = r.Patch(ctx, tenant, *query) if err != nil { cmd.PrintErrf("Failed to update tenant: %v\n", err) return err @@ -54,7 +60,9 @@ func (f *CommandFactory) NewUpdateTenantCmd(ctx context.Context) *cobra.Command }, } - cmd.SetContext(ctx) + cmd.Flags().StringVarP(&id, "id", "i", "", "Tenant id") + cmd.Flags().StringVarP(®ion, "region", "r", "", "Tenant region") + cmd.Flags().StringVarP(&status, "status", "s", "", "Tenant status") return cmd } diff --git a/tenant-manager/tenant-cli/cmd/utils.go b/internal/tenant-manager/cli/utils.go similarity index 98% rename from tenant-manager/tenant-cli/cmd/utils.go rename to internal/tenant-manager/cli/utils.go index f8262b30..e54bbdbc 100644 --- a/tenant-manager/tenant-cli/cmd/utils.go +++ b/internal/tenant-manager/cli/utils.go @@ -1,4 +1,4 @@ -package cmd +package cli import ( "context" diff --git a/tenant-manager/internal/db/db.go b/internal/tenant-manager/db/db.go similarity index 100% rename from tenant-manager/internal/db/db.go rename to internal/tenant-manager/db/db.go diff --git a/tenant-manager/internal/db/db_test.go b/internal/tenant-manager/db/db_test.go similarity index 99% rename from tenant-manager/internal/db/db_test.go rename to internal/tenant-manager/db/db_test.go index e5e7c91e..c97e34c2 100644 --- a/tenant-manager/internal/db/db_test.go +++ b/internal/tenant-manager/db/db_test.go @@ -12,8 +12,8 @@ import ( "github.com/openkcm/cmk/internal/constants" "github.com/openkcm/cmk/internal/model" + "github.com/openkcm/cmk/internal/tenant-manager/db" "github.com/openkcm/cmk/internal/testutils" - "github.com/openkcm/cmk/tenant-manager/internal/db" integrationutils "github.com/openkcm/cmk/test/integration_utils" "github.com/openkcm/cmk/utils/base62" ) diff --git a/tenant-manager/internal/db/errors.go b/internal/tenant-manager/db/errors.go similarity index 100% rename from tenant-manager/internal/db/errors.go rename to internal/tenant-manager/db/errors.go diff --git a/tenant-manager/internal/operator/errors.go b/internal/tenant-manager/operator/errors.go similarity index 100% rename from tenant-manager/internal/operator/errors.go rename to internal/tenant-manager/operator/errors.go diff --git a/tenant-manager/internal/operator/export_test.go b/internal/tenant-manager/operator/export_test.go similarity index 100% rename from tenant-manager/internal/operator/export_test.go rename to internal/tenant-manager/operator/export_test.go diff --git a/tenant-manager/internal/operator/operator.go b/internal/tenant-manager/operator/operator.go similarity index 99% rename from tenant-manager/internal/operator/operator.go rename to internal/tenant-manager/operator/operator.go index 92b6bc52..5f7bca82 100644 --- a/tenant-manager/internal/operator/operator.go +++ b/internal/tenant-manager/operator/operator.go @@ -23,7 +23,7 @@ import ( "github.com/openkcm/cmk/internal/model" "github.com/openkcm/cmk/internal/repo" "github.com/openkcm/cmk/internal/repo/sql" - tmdb "github.com/openkcm/cmk/tenant-manager/internal/db" + tmdb "github.com/openkcm/cmk/internal/tenant-manager/db" "github.com/openkcm/cmk/utils/base62" ) diff --git a/tenant-manager/internal/operator/operator_test.go b/internal/tenant-manager/operator/operator_test.go similarity index 99% rename from tenant-manager/internal/operator/operator_test.go rename to internal/tenant-manager/operator/operator_test.go index 4e147643..7d348395 100644 --- a/tenant-manager/internal/operator/operator_test.go +++ b/internal/tenant-manager/operator/operator_test.go @@ -24,8 +24,8 @@ import ( "github.com/openkcm/cmk/internal/clients/registry/tenants" "github.com/openkcm/cmk/internal/model" + "github.com/openkcm/cmk/internal/tenant-manager/operator" "github.com/openkcm/cmk/internal/testutils" - "github.com/openkcm/cmk/tenant-manager/internal/operator" integrationutils "github.com/openkcm/cmk/test/integration_utils" tmdb "github.com/openkcm/cmk/utils/base62" ) diff --git a/tenant-manager/internal/operator/probe.go b/internal/tenant-manager/operator/probe.go similarity index 100% rename from tenant-manager/internal/operator/probe.go rename to internal/tenant-manager/operator/probe.go diff --git a/tenant-manager/internal/operator/probe_test.go b/internal/tenant-manager/operator/probe_test.go similarity index 99% rename from tenant-manager/internal/operator/probe_test.go rename to internal/tenant-manager/operator/probe_test.go index 58c204e5..74a66a27 100644 --- a/tenant-manager/internal/operator/probe_test.go +++ b/internal/tenant-manager/operator/probe_test.go @@ -13,9 +13,9 @@ import ( "github.com/openkcm/cmk/internal/constants" "github.com/openkcm/cmk/internal/model" "github.com/openkcm/cmk/internal/repo/sql" + "github.com/openkcm/cmk/internal/tenant-manager/db" + "github.com/openkcm/cmk/internal/tenant-manager/operator" "github.com/openkcm/cmk/internal/testutils" - "github.com/openkcm/cmk/tenant-manager/internal/db" - "github.com/openkcm/cmk/tenant-manager/internal/operator" ) const ( diff --git a/internal/testutils/db.go b/internal/testutils/db.go index 4eeeae01..ec55c8a9 100644 --- a/internal/testutils/db.go +++ b/internal/testutils/db.go @@ -228,7 +228,7 @@ type TestDBConfig struct { // By default it creates only one tenant TenantCount int - // If true create DB instance for test instead of tenant + // If true create db instance for test instead of tenant RequiresMultitenancyOrShared bool // Tables that the test should contain @@ -255,7 +255,7 @@ func processNameForDB(n string) string { // If cfg.RequiresMultitenancy create a separate database to test multitenancy // // This is intended for internal use. In most cases please use NewTestDB -// to setup a DB for unit tests +// to setup a db for unit tests func newTestDBCon(tb testing.TB, cfg TestDBConfig) *multitenancy.DB { tb.Helper() diff --git a/internal/testutils/grpc.go b/internal/testutils/grpc.go index c203527e..b6e2621f 100644 --- a/internal/testutils/grpc.go +++ b/internal/testutils/grpc.go @@ -60,7 +60,7 @@ func NewGRPCSuite( } // NewGRPCServer is mostly used for internal reasons. -// In most cases please use NewGRPCSuite to set up a DB for unit tests +// In most cases please use NewGRPCSuite to set up a db for unit tests func NewGRPCServer( tb testing.TB, address string, diff --git a/tenant-manager/VERSION b/tenant-manager/VERSION deleted file mode 100644 index 45c7a584..00000000 --- a/tenant-manager/VERSION +++ /dev/null @@ -1 +0,0 @@ -v0.0.1 diff --git a/tenant-manager/tenant-cli/cmd/commands.go b/tenant-manager/tenant-cli/cmd/commands.go deleted file mode 100644 index 1ee8e09d..00000000 --- a/tenant-manager/tenant-cli/cmd/commands.go +++ /dev/null @@ -1,20 +0,0 @@ -package cmd - -import ( - multitenancy "github.com/bartventer/gorm-multitenancy/v8" - - "github.com/openkcm/cmk/internal/repo" - "github.com/openkcm/cmk/internal/repo/sql" -) - -type CommandFactory struct { - dbCon *multitenancy.DB - r repo.Repo -} - -func NewCommandFactory(dbCon *multitenancy.DB) *CommandFactory { - return &CommandFactory{ - dbCon: dbCon, - r: sql.NewRepository(dbCon), - } -} diff --git a/tenant-manager/tenant-cli/cmd/rootcmd.go b/tenant-manager/tenant-cli/cmd/rootcmd.go deleted file mode 100644 index 919608ec..00000000 --- a/tenant-manager/tenant-cli/cmd/rootcmd.go +++ /dev/null @@ -1,48 +0,0 @@ -package cmd - -import ( - "context" - "os" - "os/signal" - "syscall" - - "github.com/spf13/cobra" -) - -func (f *CommandFactory) NewRootCmd(ctx context.Context) *cobra.Command { - rootCmd := &cobra.Command{ - Use: "tm", - Short: "Tenant Manager CLI Application", - Long: "Tenant Manager is a simple CLI tool to manage tenants, supporting: creating tenant, " + - "creating tenant with groups, " + - "creating groups, " + - "updating of region and status field on a tenant entity in public table, " + - "updating of group names, " + - "changing any field value in any table of a tenant schema.", - - PersistentPreRunE: func(_ *cobra.Command, _ []string) error { - return nil - }, - - Run: func(cmd *cobra.Command, _ []string) { - sleep, _ := cmd.Flags().GetBool("sleep") - if sleep { - infiniteRun(cmd) - } - }, - } - - rootCmd.SetContext(ctx) - - return rootCmd -} - -func infiniteRun(cmd *cobra.Command) { - cmd.Println("Pod running...") - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - - <-sigs - cmd.Println("Shutting down gracefully...") -}