From fa353b04df79ab9aa0ad81e42c0109ce25f60440 Mon Sep 17 00:00:00 2001 From: Matt Spilchen Date: Wed, 8 Nov 2023 14:42:59 -0400 Subject: [PATCH] First drop --- .gitignore | 1 + Chart.yaml | 21 ++++ LICENSE | 2 +- README.md | 37 ++++++- templates/NOTES.txt | 24 +++++ templates/_helpers.tpl | 110 +++++++++++++++++++ templates/configmap.yaml | 32 ++++++ templates/deployment.yaml | 80 ++++++++++++++ templates/pod.yaml | 64 +++++++++++ templates/serviceaccount.yaml | 12 +++ values.schema.json | 197 ++++++++++++++++++++++++++++++++++ values.yaml | 121 +++++++++++++++++++++ vertica-logo.png | Bin 0 -> 25763 bytes 13 files changed, 698 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 Chart.yaml create mode 100644 templates/NOTES.txt create mode 100644 templates/_helpers.tpl create mode 100644 templates/configmap.yaml create mode 100644 templates/deployment.yaml create mode 100644 templates/pod.yaml create mode 100644 templates/serviceaccount.yaml create mode 100644 values.schema.json create mode 100644 values.yaml create mode 100644 vertica-logo.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa1ec1e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.tgz diff --git a/Chart.yaml b/Chart.yaml new file mode 100644 index 0000000..382e95f --- /dev/null +++ b/Chart.yaml @@ -0,0 +1,21 @@ +# (c) Copyright [2023] Open Text. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v2 +name: vertica-kafka-scheduler +description: Deploys the Vertica Kafka Scheduler in Kubernetes +type: application +version: 0.1.0 +# The appVersion corresponds to the Vertica version +appVersion: "23.4.0" +icon: https://raw.githubusercontent.com/vertica/kafka-scheduler-chart/main/vertica-logo.png diff --git a/LICENSE b/LICENSE index 261eeb9..3d5f40d 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [2023] Open Text. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 13ecc67..4ee60ec 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# kafka-scheduler-chart -Helm chart to deploy the Vertica Kafka Scheduler in Kubernetes +This helm chart will deploy the vertica kafka scheduler. It will deploy the vertica/vertica-kafka-scheduler in two modes: initializer and launcher. When deployed as the initializer it will run the container so that you can exec into it and do your setup. When deployed as the launcher, the container will automatically call 'vkconfig launch'. This is expected to be done once everything has been setup. + +| Parameter Name | Description | Default Value | +|----------------|-------------|---------------| +| affinity | Affinity to use with the pods to control where it is scheduled | | +| conf.configMapName | The name of the ConfigMap to use and optionally generate. If omitted, the chart will pick a suitable default. | | +| conf.content | Set of key/values pairs that will be included in the generated ConfigMap. This is ignored if conf.generate is false. | | +| conf.generate | If true, the helm chart will control creation of the vkconfig.conf ConfigMap. | true | +| fullNameOverride | Gives full controls over the name of the objects that get created. This takes precedence over nameOverride. | | +| initializerEnabled | If true, the initializer pod is created. This can be used to run any setup tasks needed. | true | +| image.pullPolicy | The pull policy to use for the image | IfNotPresent | +| image.repository | The image repository and name that contains the Vertica Kafka Scheduler | vertica/kafka-scheduler | +| image.tag | The tag corresponds to the version to use. The version of the Vertica Kafka Scheduler must match version of the Vertica server you are connecting to | Defaults to the charts appVersion | +| imagePullSecrets | A list of Secret's that are needed to be able to pull the image | | +| launcherEnabled | If true, the launch deployment is created. This should only be enabled once everything has been setup. | true | +| jvmOpts | Values to assign to the VKCONFIG_JVM_OPTS environment variable in the pods. You can omit most trustrtore/keystore settings as they are controlled by tls.* | | +| nameOverride | Controls the name of the objects that get created. This is combined with the helm chart release to form the name | | +| nodeSelector | A node selector to use with the pod to control where it is scheduled | | +| podAnnotations | Annotations to attach to the pods | | +| podSecurityContext | A PodSecurityContext to use for the pods | | +| replicaCount | If you want more than one launch pod deployed set this to a value greater than 1. | 1 | +| resourecs | Resources to use with the pod | | +| securityContext | A SecurityContext to use for the container in the pod | | +| serviceAccount.annotations | Annotations to attach to the ServiceAccount | | +| serviceAccount.create | If true, a ServiceAccount is created as part of the deployment | true | +| serviceAccount.name | Name of the service account. If not set and create is true, a name is generated using the fullname template | | +| tls.enabled | If true, we setup with the assumption that TLS authentication will be used. | false | +| tls.keyStoreMountPath | Directory name where the keystore will be mounted in the pod | | +| tls.keyStorePassword | The password to use along with the keystore | | +| tls.keyStoreSecretKey | A key within the tls.keyStoreSecretName that will be used as the keystore file name | | +| tls.keyStoreSecretName | Name of an existing Secret that contains the keystore | | +| tls.trustStoreMountPath | Directory name where the truststore will be mounted in the pod | | +| tls.trustStoreSecretKey | A key within tls.trustStoreSecretName that will be used as the truststore file name | | +| tls.trustStoreSecretName | Name of an existing Secret that contains the truststore | | +| tolerations | Tolerations to use with the pods to control where it is scheduled | | diff --git a/templates/NOTES.txt b/templates/NOTES.txt new file mode 100644 index 0000000..9601607 --- /dev/null +++ b/templates/NOTES.txt @@ -0,0 +1,24 @@ +Vertica's Kafka Scheduler has been deployed. + +{{ if .Values.initializerEnabled -}} +The initializer pod is running. You can exec into it and run your vkconfig +commands with this command: + +kubectl exec -n {{ .Release.Namespace }} -it {{ include "vertica-kafka-scheduler.initializer-fullname" . }} -- bash + +{{ end -}} +{{ if .Values.launcherEnabled -}} +{{- if eq (.Values.replicaCount | int) 1 }} +The launcher deployment object was created with a replica size of 1. You can +monitor the output of the pod with this command: + +kubectl logs -n {{ .Release.Namespace }} deployment/{{ include "vertica-kafka-scheduler.fullname" . }} +{{- else if eq (.Values.replicaCount | int) 0 }} +The launcher deployment object was created, but no launcher pods are running +since the replica count is 0. +{{- else }} +The launcher deployment object was created with multiple replicas. A leader election process occurs to decide the pod that actually handles the traffic. You can list the pods with this command: + +kubectl get pods -n {{ .Release.Namespace }} --selector vertica.com/kafka-scheduler-component=launcher +{{- end }} +{{ end }} diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl new file mode 100644 index 0000000..2b1510c --- /dev/null +++ b/templates/_helpers.tpl @@ -0,0 +1,110 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "vertica-kafka-scheduler.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- 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 "vertica-kafka-scheduler.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 a default fully qualified name for the initializer pod. +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 "vertica-kafka-scheduler.initializer-fullname" -}} +{{- if .Values.fullnameOverride }} +{{- cat .Values.fullnameOverride "-initializer" | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- printf "%s-initializer" .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s-initializer" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create a default fully qualified name for the configMap. +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 "vertica-kafka-scheduler.configmap-fullname" -}} +{{- if .Values.conf.configMapName }} +{{- .Values.conf.configMapName }} +{{- else 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 "vertica-kafka-scheduler.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "vertica-kafka-scheduler.labels" -}} +helm.sh/chart: {{ include "vertica-kafka-scheduler.chart" . }} +{{ include "vertica-kafka-scheduler.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "vertica-kafka-scheduler.selectorLabels" -}} +app.kubernetes.io/name: {{ include "vertica-kafka-scheduler.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "vertica-kafka-scheduler.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "vertica-kafka-scheduler.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Generate te value for VKCONFIG_JVM_OPTS based on values.yaml +*/}} +{{- define "vertica-kafka-scheduler.jvmOpts" -}} +{{ default (quote "") .Values.jvmOpts }} +{{- if .Values.tls.enabled }} + -Djavax.net.ssl.trustStore={{ .Values.tls.trustStoreMountPath }}/{{ .Values.tls.trustStoreSecretKey }} -Djavax.net.ssl.keyStore={{ .Values.tls.keyStoreMountPath }}/{{ .Values.tls.keyStoreSecretKey }} -Djavax.net.ssl.keyStorePassword={{ .Values.tls.keystorePassword }} +{{- end }} +{{- end }} diff --git a/templates/configmap.yaml b/templates/configmap.yaml new file mode 100644 index 0000000..4130f96 --- /dev/null +++ b/templates/configmap.yaml @@ -0,0 +1,32 @@ +{{- if .Values.conf.generate }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "vertica-kafka-scheduler.configmap-fullname" . }} + labels: + {{- include "vertica-kafka-scheduler.labels" . | nindent 4 }} +data: + vkconfig.conf: | +{{- range $key, $value := $.Values.conf.content }} + {{ $key }}={{ $value }} +{{- end }} + vkafka-log-config.xml: | + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{PID}:%t] %logger::%t %X{tuple} [%p] %m%n + + + + + + + + + + + +{{- end }} diff --git a/templates/deployment.yaml b/templates/deployment.yaml new file mode 100644 index 0000000..3c11143 --- /dev/null +++ b/templates/deployment.yaml @@ -0,0 +1,80 @@ +{{- if .Values.launcherEnabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "vertica-kafka-scheduler.fullname" . }} + labels: + {{- include "vertica-kafka-scheduler.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + vertica.com/kafka-scheduler-component: "launcher" + {{- include "vertica-kafka-scheduler.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + vertica.com/kafka-scheduler-component: "launcher" + {{- include "vertica-kafka-scheduler.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "vertica-kafka-scheduler.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: main + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - vkconfig + - launch + - --conf + - /opt/vertica/packages/kafka/config/vkconfig.conf + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: vkconfig + mountPath: /opt/vertica/packages/kafka/config + {{- if .Values.tls.enabled }} + - name: trustStore + mountPath: {{ .Values.tls.trustStoreMountPath }} + - name: keyStore + mountPath: {{ .Values.tls.keyStoreMountPath }} + {{- end }} + env: + - name: VKCONFIG_JVM_OPTS + value: {{ include "vertica-kafka-scheduler.jvmOpts" . }} + volumes: + - name: vkconfig + configMap: + name: {{ include "vertica-kafka-scheduler.configmap-fullname" . }} + {{- if .Values.tls.enabled }} + - name: trustStore + secret: + secretName: {{ .Values.tls.trustStoreSecretName }} + - name: keyStore + secret: + secretName: {{ .Values.tls.keyStoreSecretName }} + {{- 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/templates/pod.yaml b/templates/pod.yaml new file mode 100644 index 0000000..947cb48 --- /dev/null +++ b/templates/pod.yaml @@ -0,0 +1,64 @@ +{{- if .Values.initializerEnabled }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ include "vertica-kafka-scheduler.initializer-fullname" . }} + labels: + vertica.com/kafka-scheduler-component: "initializer" + {{- include "vertica-kafka-scheduler.labels" . | nindent 4 }} +spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "vertica-kafka-scheduler.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: main + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - sleep + - infinity + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: vkconfig + mountPath: /opt/vertica/packages/kafka/config + {{- if .Values.tls.enabled }} + - name: trustStore + mountPath: {{ .Values.tls.trustStoreMountPath }} + - name: keyStore + mountPath: {{ .Values.tls.keyStoreMountPath }} + {{- end }} + env: + - name: VKCONFIG_JVM_OPTS + value: {{ include "vertica-kafka-scheduler.jvmOpts" . }} + volumes: + - name: vkconfig + configMap: + name: {{ include "vertica-kafka-scheduler.configmap-fullname" . }} + {{- if .Values.tls.enabled }} + - name: trustStore + secret: + secretName: {{ .Values.tls.trustStoreSecretName }} + - name: keyStore + secret: + secretName: {{ .Values.tls.keyStoreSecretName }} + {{- 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/templates/serviceaccount.yaml b/templates/serviceaccount.yaml new file mode 100644 index 0000000..4c9fc20 --- /dev/null +++ b/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "vertica-kafka-scheduler.serviceAccountName" . }} + labels: + {{- include "vertica-kafka-scheduler.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/values.schema.json b/values.schema.json new file mode 100644 index 0000000..7f0150e --- /dev/null +++ b/values.schema.json @@ -0,0 +1,197 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "image": { + "type": "object", + "description": "The image has the java environment and vkconfig, which is compiled against a specific version of Vertica", + "additionalProperties": false, + "properties": { + "repository": { + "type": "string", + "description": "The image repository and name", + "default": "vertica/kafka-scheduler" + }, + "pullPolicy": { + "type": "string", + "default": "IfNotPresent", + "description": "The pull policy to use for the image" + }, + "tag": { + "type": "string", + "description": "Overrides the image tag whose default is the chart appVersion. If using the official vertica repository, this tag corresponds to the vertica version that vkconfig was complied against. Pick the same version that matches the Vertica server you have deployed." + } + }, + "required": [ + "pullPolicy", + "repository" + ], + "title": "Image" + }, + "launcherEnabled": { + "type": "boolean", + "description": "The launcher is a deployment object that runs the 'vkconfig launch' program. You must already have done setup of vkconfig for this program to work. You can temporarily disable it to allow for setup to occur.", + "additionalProperties": false, + "default": false + }, + "replicaCount": { + "type": "integer", + "description": "The number of pods for the launcher deployment. The pods themselves go through a leader election process such that only 1 pod is ever handling requests", + "default": 1 + }, + "initializerEnabled": { + "type": "boolean", + "description": "The initializer is a pod that runs the container without invoking vkconfig. It gives you CLI access to the vkconfig command. The intention is that you would use the CLI to do neccessary setup then disabled it when you want to run the launcher.", + "default": true + }, + "conf": { + "type": "object", + "additionalProperties": false, + "description": "The vkconfig.conf is a file that is mounted in the pods for command line options passed to vkconfig. This section controls how that file gets generated and mounted.", + "properties": { + "generate": { + "type": "boolean", + "description": "Set this to false if you already have a vkconfig.conf in a ConfigMap and don't need helm to generate one.", + "default": true + }, + "configMapName": { + "type": "string", + "description": "The name of the ConfigMap that contains the contents of vkconfig.conf. If generate=false, this must already exist before deployment. If this is omitted a suitable name for the ConfigMap is chosen based on the release/chart name." + }, + "content": { + "description": "Content is a set of key/value pairs that make up the vkconfig.conf. There is no prescribed set of keys that need to be here. See this to find options to set: https://docs.vertica.com/latest/en/kafka-integration/vkconfig-script-options/common-vkconfig-script-options/", + "type": "object", + "additionalProperties": true, + "properties": { + "config-schema": { + "type": "string", + "default": "Scheduler" + }, + "username": { + "type": "string", + "default": "dbadmin" + }, + "password": { + "type": "string" + }, + "dbhost": { + "type": "string" + }, + "dbport": { + "type": "string", + "format": "integer", + "default": 5433 + }, + "enable-ssl": { + "type": "string", + "format": "boolean", + "default": false + } + }, + "required": [ + "config-schema", + "dbport", + "enable-ssl", + "username" + ], + "title": "Content" + } + }, + "required": [ + "configMapName", + "content", + "generate" + ], + "title": "conf" + }, + "tls": { + "type": "object", + "description": "If vkconfig needs to have TLS setup in order to communicate fill in the following section.", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean", + "description": "Set this to true to mount the secrets and have the JVM options set for the trust/key store in the pods.", + "default": false + }, + "trustStoreSecretName": { + "description": "Name of a preexisting Secret that contains the truststore to use.", + "type": "string" + }, + "trustStoreMountPath": { + "description": "The directory mount for the trustStoreSecretName", + "type": "string" + }, + "trustStoreSecretKey": { + "description": "The key within trustStoreSecretName that has the truststore to use. This will be mounted as a file within the pod", + "type": "string" + }, + "keyStoreSecretName": { + "description": "Name of a preexisting Secret that contains the keystore to use", + "type": "string" + }, + "keyStoreMountPath": { + "description": "The directory mount for the keyStoreSecretName", + "type": "string" + }, + "keyStoreSecretKey": { + "description": "The key within keyStoreSecretName that has the keystore to use. This will be mounted as a file within the pod.", + "type": "string" + }, + "keyStorePassword": { + "description": "The password to access the keystore", + "type": "string" + } + }, + "required": [ + "enabled", + "keyStoreMountPath", + "keyStorePassword", + "keyStoreSecretKey", + "keyStoreSecretName", + "trustStoreMountPath", + "trustStoreSecretKey", + "trustStoreSecretName" + ], + "title": "TLS" + }, + "jvmOpts": { + "description": "Controls the setting of VKCONFIG_JVM_OPTS in the pods. Values for truststore and keystore are added automatically based on the tls.* values", + "type": "string" + }, + "serviceAccount": { + "type": "object", + "additionalProperties": false, + "description": "Controls the ServiceAccount to use for the pods", + "properties": { + "create": { + "description": "Specifies whether a service account should be created", + "default": true, + "type": "boolean" + }, + "annotations": { + "description": "Annotations to add to the service account", + "required": [], + "additionalProperties": { + "type": "string" + } + }, + "name": { + "description": "The name of the service account to use. If not set and create is true, a name is generated using the fullname template", + "type": "string" + } + }, + "required": [ + "annotations", + "create", + "name" + ], + "title": "ServiceAccount" + } + }, + "required": [ + "conf", + "image" + ], + "title": "Vertica Kafka Scheduler" +} diff --git a/values.yaml b/values.yaml new file mode 100644 index 0000000..ea07c9d --- /dev/null +++ b/values.yaml @@ -0,0 +1,121 @@ +# (c) Copyright [2023] Open Text. +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default values for vertica-kafka-scheduler. +# This is a YAML-formatted file. + +image: + repository: vertica/kafka-scheduler + pullPolicy: IfNotPresent + # Overrides the image tag. If using the official vertica repository, this tag + # corresponds to the vertica version that vkconfig was complied against. Pick + # the same version that matches the Vertica server you have deployed. + tag: "23.4.0" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +# The launcher is a deployment object that runs the 'vkconfig launch' program. +# You must already have done setup of vkconfig for this program to work. You +# can temporarily disable it to allow for setup to occur. +launcherEnabled: false + +# The size of the launcher deployment. +replicaCount: 1 + +# The initializer is a pod that runs the container without invoking vkconfig. It +# gives you CLI access to the vkconfig command. The intention is that you would +# use the CLI to do neccessary setup then disabled it when you want to run the +# launcher. +initializerEnabled: true + +# The vkconfig.conf is a file that is mounted in the pods for command line +# options passed to vkconfig. +conf: + # Set this to false if you already have a vkconfig.conf in a ConfigMap and + # don't need helm to generate one. + generate: true + # The name of the ConfigMap that contains the contents of vkconfig.conf. + # If generate=false, this must already exist before deployment. If this is + # omitted a suitable name for the ConfigMap is chosen based on the + # release/chart name. + configMapName: "" + # content is a set of key/value pairs that make up the vkconfig.conf. There + # is no prescribed set of keys that need to be here. See this to find options + # to set: + # https://docs.vertica.com/latest/en/kafka-integration/vkconfig-script-options/common-vkconfig-script-options/ + content: + config-schema: "Scheduler" + username: "dbadmin" + # password: "" + # dbhost: "" + dbport: "5433" + # If enabled, fill in the conf.tls section too. + enable-ssl: "false" + +# If vkconfig needs to have TLS setup in order to communicate fill in the +# following block. +tls: + # Set this to true to mount the secrets and have the JVM options set + # for the trust/key store in the pods. + enabled: false + # Name of a preexisting Secret that contains the truststore to use. + trustStoreSecretName: "" + # The next two control the name of the trust store. The path will be: + # / + # + # The directory mount for the trustStoreSecretName. + trustStoreMountPath: "" + # The key within trustStoreSecretName that has the truststore to use. This + # will be mounted as a file within the pod. + trustStoreSecretKey: "" + # Name of a preexisting Secret that contains the keystore to use. + keyStoreSecretName: "" + # The next two control the name of the key store. The path will be: + # / + # + # The directory mount for the keyStoreSecretName. + keyStoreMountPath: "" + # The key within keyStoreSecretName that has the keystore to use. This + # will be mounted as a file within the pod. + keyStoreSecretKey: "" + # The password to access the keystore + keyStorePassword: "" + +# Controls the setting of VKCONFIG_JVM_OPTS in the pods. Values for truststore +# and keystore are added automatically based on the tls.* values. +jvmOpts: "" + +serviceAccount: + # Specifies whether a service account should be created + create: 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: "" + +podAnnotations: {} + +podSecurityContext: {} + +securityContext: {} + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/vertica-logo.png b/vertica-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5da38f4e67c7d4ea72c02983bc8cf01c9b10752f GIT binary patch literal 25763 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 F{|CI7K7#-N literal 0 HcmV?d00001