diff --git a/README.md b/README.md index 267356828..90cd670fb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,17 @@ it is intended to be. | Minikube | 1.10 | >= 3.3.13 | Runs | Not intended | | Docker for Mac Edge | 1.10 | >= 3.3.13 | Runs | Not intended | -## Installation of latest release +## Installation of latest release using Helm + +```bash +# The following will install the operator for `ArangoDeployment` & +# `ArangoDeplomentReplication` resources. +helm install https://github.com/arangodb/kube-arangodb/releases/download/0.2.2/kube-arangodb.tgz +# To use `ArangoLocalStorage`, also run +helm install https://github.com/arangodb/kube-arangodb/releases/download/0.2.2/kube-arangodb-storage.tgz +``` + +## Installation of latest release using Kubectl ```bash kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-arangodb/0.2.2/manifests/crd.yaml diff --git a/docs/Manual/Deployment/Kubernetes/Helm.md b/docs/Manual/Deployment/Kubernetes/Helm.md new file mode 100644 index 000000000..271dc645b --- /dev/null +++ b/docs/Manual/Deployment/Kubernetes/Helm.md @@ -0,0 +1,91 @@ +# Using the ArangoDB Kubernetes Operator with Helm + +[`Helm`](https://www.helm.sh/) is a package manager for Kubernetes, which enables +you to install various packages (include the ArangoDB Kubernetes Operator) +into your Kubernetes cluster. + +The benefit of `helm` (in the context of the ArangoDB Kubernetes Operator) +is that it allows for a lot of flexibility in how you install the operator. +For example you can install the operator in a namespace other than +`default`. + +## Charts + +The ArangoDB Kubernetes Operator is contained in two `helm` charts: + +- `kube-arangodb` which contains the operator for the `ArangoDeployment` + and `ArangoDeploymentReplication` resource types. +- `kube-arangodb-storage` which contains the operator for the `ArangoLocalStorage` + resource type. + +The `kube-arangodb-storage` only has to be installed if your Kubernetes cluster +does not already provide `StorageClasses` that use locally attached SSDs. + +## Configurable values for ArangoDB Kubernetes Operator + +The following values can be configured when installing the +ArangoDB Kubernetes Operator with `helm`. + +Values are passed to `helm` using an `--set==` argument passed +to the `helm install` or `helm upgrade` command. + +### Values applicable to both charts + +| Key | Type | Description +|-------------------|--------|-----| +| Image | string | Override the docker image used by the operators +| ImagePullPolicy | string | Override the image pull policy used by the operators. See [Updating Images](https://kubernetes.io/docs/concepts/containers/images/#updating-images) for details. +| RBAC.Create | bool | Set to `true` (default) to create roles & role bindings. + +### Values applicable to the `kube-arangodb` chart + +| Key | Type | Description +|-------------------|--------|-----| +| Deployment.Create | bool | Set to `true` (default) to deploy the `ArangoDeployment` operator +| Deployment.User.ServiceAccountName | string | Name of the `ServiceAccount` that is the subject of the `RoleBinding` of users of the `ArangoDeployment` operator +| Deployment.Operator.ServiceAccountName | string | Name of the `ServiceAccount` used to run the `ArangoDeployment` operator +| Deployment.Operator.ServiceType | string | Type of `Service` created for the dashboard of the `ArangoDeployment` operator +| Deployment.AllowChaos | bool | Set to `true` to allow the introduction of chaos. **Only use for testing, never for production!** Defaults to `false`. +| DeploymentReplication.Create | bool | Set to `true` (default) to deploy the `ArangoDeploymentReplication` operator +| DeploymentReplication.User.ServiceAccountName | string | Name of the `ServiceAccount` that is the subject of the `RoleBinding` of users of the `ArangoDeploymentReplication` operator +| DeploymentReplication.Operator.ServiceAccountName | string | Name of the `ServiceAccount` used to run the `ArangoDeploymentReplication` operator +| DeploymentReplication.Operator.ServiceType | string | Type of `Service` created for the dashboard of the `ArangoDeploymentReplication` operator + +### Values applicable to the `kube-arangodb-storage` chart + +| Key | Type | Description +|-------------------|--------|-----| +| Storage.User.ServiceAccountName | string | Name of the `ServiceAccount` that is the subject of the `RoleBinding` of users of the `ArangoLocalStorage` operator +| Storage.Operator.ServiceAccountName | string | Name of the `ServiceAccount` used to run the `ArangoLocalStorage` operator +| Storage.Operator.ServiceType | string | Type of `Service` created for the dashboard of the `ArangoLocalStorage` operator + +## Alternate namespaces + +The `kube-arangodb` chart supports deployment into a non-default namespace. + +To install the `kube-arangodb` chart is a non-default namespace, use the `--namespace` +argument like this. + +```bash +helm install --namespace=mynamespace kube-arangodb.tgz +``` + +Note that since the operators claim exclusive access to a namespace, you can +install the `kube-arangodb` chart in a namespace once. +You can install the `kube-arangodb` chart in multiple namespaces. To do so, run: + +```bash +helm install --namespace=namespace1 kube-arangodb.tgz +helm install --namespace=namespace2 kube-arangodb.tgz +``` + +The `kube-arangodb-storage` chart is always installed in the `kube-system` namespace. + +## Common problems + +### Error: no available release name found + +This error is given by `helm install ...` in some cases where it has +insufficient permissions to install charts. + +For various ways to work around this problem go to [this Stackoverflow article](https://stackoverflow.com/questions/43499971/helm-error-no-available-release-name-found). diff --git a/docs/Manual/Deployment/Kubernetes/Usage.md b/docs/Manual/Deployment/Kubernetes/Usage.md index 627bcb676..1079310cf 100644 --- a/docs/Manual/Deployment/Kubernetes/Usage.md +++ b/docs/Manual/Deployment/Kubernetes/Usage.md @@ -5,7 +5,38 @@ The ArangoDB Kubernetes Operator needs to be installed in your Kubernetes cluster first. -To do so, run (replace `` with the version of the operator that you want to install): +If you have `Helm` available, we recommend installation using `Helm`. + +### Installation with Helm + +To install the ArangoDB Kubernetes Operator with [`helm`](https://www.helm.sh/), +run (replace `` with the version of the operator that you want to install): + +```bash +export URLPREFIX=https://github.com/arangodb/kube-arangodb/releases/download/ +helm install $URLPREFIX/kube-arangodb.tgz +``` + +This installs operators for the `ArangoDeployment` and `ArangoDeploymentReplication` +resource types. + +If you want to avoid the installation of the operator for the `ArangoDeploymentReplication` +resource type, add `--set=DeploymentReplication.Create=false` to the `helm install` +command. + +To use `ArangoLocalStorage` resources, also run: + +```bash +helm install $URLPREFIX/kube-arangodb-storage.tgz +``` + +For more information on installing with `Helm` and how to customize an installation, +see [Using the ArangoDB Kubernetes Operator with Helm](./Helm.md). + +### Installation with Kubectl + +To install the ArangoDB Kubernetes Operator without `Helm`, +run (replace `` with the version of the operator that you want to install): ```bash export URLPREFIX=https://raw.githubusercontent.com/arangodb/kube-arangodb//manifests @@ -60,6 +91,14 @@ If you want to keep your data, make sure to create a backup before removing the To remove the entire ArangoDB Kubernetes Operator, remove all clusters first and then remove the operator by running: +```bash +helm delete +# If `ArangoLocalStorage` operator is installed +helm delete +``` + +or when you used `kubectl` to install the operator, run: + ```bash kubectl delete deployment arango-deployment-operator # If `ArangoLocalStorage` operator is installed @@ -73,3 +112,4 @@ kubectl delete deployment arango-deployment-replication-operator - [Driver configuration](./DriverConfiguration.md) - [Scaling](./Scaling.md) - [Upgrading](./Upgrading.md) +- [Using the ArangoDB Kubernetes Operator with Helm](./Helm.md) \ No newline at end of file diff --git a/manifests/templates/deployment-replication/deployment-replication.yaml b/manifests/templates/deployment-replication/deployment-replication.yaml index 7b5301127..fc8bc7ec4 100644 --- a/manifests/templates/deployment-replication/deployment-replication.yaml +++ b/manifests/templates/deployment-replication/deployment-replication.yaml @@ -1,3 +1,4 @@ +{{ .DeploymentReplication.FilterStart }} apiVersion: extensions/v1beta1 kind: Deployment @@ -14,6 +15,7 @@ spec: name: {{ .DeploymentReplication.OperatorDeploymentName }} app: arango-deployment-replication-operator spec: + serviceAccountName: {{ .DeploymentReplication.Operator.ServiceAccountName }} containers: - name: operator imagePullPolicy: {{ .ImagePullPolicy }} @@ -59,3 +61,5 @@ spec: operator: "Exists" effect: "NoExecute" tolerationSeconds: 5 + +{{ .DeploymentReplication.FilterEnd }} diff --git a/manifests/templates/deployment-replication/rbac.yaml b/manifests/templates/deployment-replication/rbac.yaml index 5c7671ed6..3e62b13ad 100644 --- a/manifests/templates/deployment-replication/rbac.yaml +++ b/manifests/templates/deployment-replication/rbac.yaml @@ -1,4 +1,6 @@ -{{- if .RBAC -}} +{{ .DeploymentReplication.FilterStart }} +{{ .RBACFilterStart }} + ## Cluster role granting access to ArangoDeploymentReplication resources. apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole @@ -72,4 +74,5 @@ subjects: name: {{ .DeploymentReplication.Operator.ServiceAccountName }} namespace: {{ .DeploymentReplication.Operator.Namespace }} -{{- end -}} +{{ .RBACFilterEnd }} +{{ .DeploymentReplication.FilterEnd }} diff --git a/manifests/templates/deployment-replication/service.yaml b/manifests/templates/deployment-replication/service.yaml index 2f946ad43..301fe9bee 100644 --- a/manifests/templates/deployment-replication/service.yaml +++ b/manifests/templates/deployment-replication/service.yaml @@ -1,3 +1,5 @@ +{{ .DeploymentReplication.FilterStart }} + apiVersion: v1 kind: Service metadata: @@ -17,3 +19,5 @@ spec: app: arango-deployment-replication-operator role: leader type: {{ .DeploymentReplication.Operator.ServiceType }} + +{{ .DeploymentReplication.FilterEnd }} diff --git a/manifests/templates/deployment/deployment.yaml b/manifests/templates/deployment/deployment.yaml index 01b6a14a6..808ed87cd 100644 --- a/manifests/templates/deployment/deployment.yaml +++ b/manifests/templates/deployment/deployment.yaml @@ -1,3 +1,4 @@ +{{ .Deployment.FilterStart }} apiVersion: extensions/v1beta1 kind: Deployment @@ -14,6 +15,7 @@ spec: name: {{ .Deployment.OperatorDeploymentName }} app: arango-deployment-operator spec: + serviceAccountName: {{ .Deployment.Operator.ServiceAccountName }} containers: - name: operator imagePullPolicy: {{ .ImagePullPolicy }} @@ -60,3 +62,5 @@ spec: operator: "Exists" effect: "NoExecute" tolerationSeconds: 5 + +{{ .Deployment.FilterEnd }} diff --git a/manifests/templates/deployment/rbac.yaml b/manifests/templates/deployment/rbac.yaml index 208b34ac4..6b0c662ef 100644 --- a/manifests/templates/deployment/rbac.yaml +++ b/manifests/templates/deployment/rbac.yaml @@ -1,4 +1,6 @@ -{{- if .RBAC -}} +{{ .Deployment.FilterStart }} +{{ .RBACFilterStart }} + ## Cluster role granting access to ArangoDeployment resources. apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole @@ -72,4 +74,5 @@ subjects: name: {{ .Deployment.Operator.ServiceAccountName }} namespace: {{ .Deployment.Operator.Namespace }} -{{- end -}} +{{ .RBACFilterEnd }} +{{ .Deployment.FilterEnd }} diff --git a/manifests/templates/deployment/service.yaml b/manifests/templates/deployment/service.yaml index e7cc83a68..089596562 100644 --- a/manifests/templates/deployment/service.yaml +++ b/manifests/templates/deployment/service.yaml @@ -1,3 +1,5 @@ +{{ .Deployment.FilterStart }} + apiVersion: v1 kind: Service metadata: @@ -17,3 +19,5 @@ spec: app: arango-deployment-operator role: leader type: {{ .Deployment.Operator.ServiceType }} + +{{ .Deployment.FilterEnd }} diff --git a/manifests/templates/storage/deployment.yaml b/manifests/templates/storage/deployment.yaml index f6ffbf51b..1ec6a5f9c 100644 --- a/manifests/templates/storage/deployment.yaml +++ b/manifests/templates/storage/deployment.yaml @@ -1,3 +1,5 @@ +{{ .Storage.FilterStart }} + ## Service accounts apiVersion: v1 kind: ServiceAccount @@ -68,3 +70,5 @@ spec: operator: "Exists" effect: "NoExecute" tolerationSeconds: 5 + +{{ .Storage.FilterEnd }} diff --git a/manifests/templates/storage/rbac.yaml b/manifests/templates/storage/rbac.yaml index 99a447150..6126852f8 100644 --- a/manifests/templates/storage/rbac.yaml +++ b/manifests/templates/storage/rbac.yaml @@ -1,5 +1,6 @@ +{{ .Storage.FilterStart }} +{{ .RBACFilterStart }} -{{- if .RBAC -}} ## Cluster role granting access to ArangoLocalStorage resources. apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole @@ -81,4 +82,6 @@ subjects: - kind: ServiceAccount name: {{ .Storage.Operator.ServiceAccountName }} namespace: {{ .Storage.Operator.Namespace }} -{{- end -}} + +{{ .RBACFilterEnd }} +{{ .Storage.FilterEnd }} diff --git a/manifests/templates/storage/service.yaml b/manifests/templates/storage/service.yaml index 2fb9c2cde..c40163abb 100644 --- a/manifests/templates/storage/service.yaml +++ b/manifests/templates/storage/service.yaml @@ -1,3 +1,5 @@ +{{ .Storage.FilterStart }} + apiVersion: v1 kind: Service metadata: @@ -17,3 +19,5 @@ spec: app: arango-storage-operator role: leader type: {{ .Storage.Operator.ServiceType }} + +{{ .Storage.FilterEnd }} diff --git a/manifests/templates/test/rbac.yaml b/manifests/templates/test/rbac.yaml index 16848c872..973a0d725 100644 --- a/manifests/templates/test/rbac.yaml +++ b/manifests/templates/test/rbac.yaml @@ -1,4 +1,4 @@ -{{- if .RBAC -}} +{{ .RBACFilterStart }} ## Cluster role granting access to resources needed by the integration tests. apiVersion: rbac.authorization.k8s.io/v1beta1 @@ -34,4 +34,4 @@ subjects: name: {{ .Test.ServiceAccountName }} namespace: {{ .Test.Namespace }} -{{- end -}} +{{ .RBACFilterEnd }} diff --git a/scripts/patch_readme.sh b/scripts/patch_readme.sh index b19eac2b7..523351a5b 100755 --- a/scripts/patch_readme.sh +++ b/scripts/patch_readme.sh @@ -15,3 +15,6 @@ sed -e "s@^kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-aran sed -e "s@^kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-arangodb/.*/manifests/arango-deployment.yaml\$@kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-arangodb/${VERSION}/manifests/arango-deployment.yaml@g" -i "" $f sed -e "s@^kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-arangodb/.*/manifests/arango-deployment-replication.yaml\$@kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-arangodb/${VERSION}/manifests/arango-deployment-replication.yaml@g" -i "" $f sed -e "s@^kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-arangodb/.*/manifests/arango-storage.yaml\$@kubectl apply -f https://raw.githubusercontent.com/arangodb/kube-arangodb/${VERSION}/manifests/arango-storage.yaml@g" -i "" $f + +sed -e "s@^helm install https://github.com/arangodb/kube-arangodb/releases/download/.*/kube-arangodb.tgz\$@helm install https://github.com/arangodb/kube-arangodb/releases/download/${VERSION}/kube-arangodb.tgz@g" -i "" $f +sed -e "s@^helm install https://github.com/arangodb/kube-arangodb/releases/download/.*/kube-arangodb-storage.tgz\$@helm install https://github.com/arangodb/kube-arangodb/releases/download/${VERSION}/kube-arangodb-storage.tgz@g" -i "" $f diff --git a/tools/manifests/manifest_builder.go b/tools/manifests/manifest_builder.go index 1be5ab740..7e0d7842b 100644 --- a/tools/manifests/manifest_builder.go +++ b/tools/manifests/manifest_builder.go @@ -23,13 +23,17 @@ package main import ( + "archive/tar" "bytes" + "compress/gzip" "fmt" "io/ioutil" "log" "os" "os/exec" + "path" "path/filepath" + "strconv" "strings" "text/template" @@ -51,23 +55,142 @@ var ( RBAC bool AllowChaos bool } - deploymentTemplateNames = []string{ - "rbac.yaml", - "deployment.yaml", - "service.yaml", + deploymentTemplateNames = []Template{ + Template{Name: "rbac.yaml", Predicate: hasRBAC}, + Template{Name: "deployment.yaml"}, + Template{Name: "service.yaml"}, } - deploymentReplicationTemplateNames = []string{ - "rbac.yaml", - "deployment-replication.yaml", - "service.yaml", + deploymentReplicationTemplateNames = []Template{ + Template{Name: "rbac.yaml", Predicate: hasRBAC}, + Template{Name: "deployment-replication.yaml"}, + Template{Name: "service.yaml"}, } - storageTemplateNames = []string{ - "rbac.yaml", - "deployment.yaml", - "service.yaml", + storageTemplateNames = []Template{ + Template{Name: "rbac.yaml", Predicate: hasRBAC}, + Template{Name: "deployment.yaml"}, + Template{Name: "service.yaml"}, } - testTemplateNames = []string{ - "rbac.yaml", + testTemplateNames = []Template{ + Template{Name: "rbac.yaml", Predicate: func(o TemplateOptions, isHelm bool) bool { return o.RBAC && !isHelm }}, + } +) + +type Template struct { + Name string + Predicate func(o TemplateOptions, isHelm bool) bool +} + +type TemplateGroup struct { + ChartName string + Templates []Template +} + +func hasRBAC(o TemplateOptions, isHelm bool) bool { + return o.RBAC || isHelm +} + +var ( + tmplFuncs = template.FuncMap{ + "quote": func(x string) string { return strconv.Quote(x) }, + } +) + +type ( + chartTemplates map[string]string +) + +const ( + kubeArangoDBChartTemplate = ` +apiVersion: v1 +name: kube-arangodb +version: "{{ .Version }}" +description: | + Kube-ArangoDB is a set of operators to easily deploy ArangoDB deployments on Kubernetes +home: https://arangodb.com +` + kubeArangoDBStorageChartTemplate = ` +apiVersion: v1 +name: kube-arangodb-storage +version: "{{ .Version }}" +description: | + Kube-ArangoDB-Storage is a cluster-wide operator used to provision PersistentVolumes on disks attached locally to Nodes +home: https://arangodb.com +` + kubeArangoDBValuesTemplate = ` +# Image containing the kube-arangodb operators +Image: {{ .Image | quote }} +# Image pull policy for Image +ImagePullPolicy: {{ .ImagePullPolicy | quote }} +RBAC: + Create: {{ .RBAC }} +Deployment: + Create: {{ .Deployment.Create }} + User: + ServiceAccountName: {{ .Deployment.User.ServiceAccountName | quote }} + Operator: + ServiceAccountName: {{ .Deployment.Operator.ServiceAccountName | quote }} + ServiceType: {{ .Deployment.Operator.ServiceType | quote }} + AllowChaos: {{ .Deployment.AllowChaos }} +DeploymentReplication: + Create: {{ .DeploymentReplication.Create }} + User: + ServiceAccountName: {{ .DeploymentReplication.User.ServiceAccountName | quote }} + Operator: + ServiceAccountName: {{ .DeploymentReplication.Operator.ServiceAccountName | quote }} + ServiceType: {{ .DeploymentReplication.Operator.ServiceType | quote }} +` + kubeArangoDBStorageValuesTemplate = ` +Image: {{ .Image | quote }} +ImagePullPolicy: {{ .ImagePullPolicy | quote }} +RBAC: + Create: {{ .RBAC }} +Storage: + User: + ServiceAccountName: {{ .Storage.User.ServiceAccountName | quote }} + Operator: + ServiceAccountName: {{ .Storage.Operator.ServiceAccountName | quote }} + ServiceType: {{ .Storage.Operator.ServiceType | quote }} +` + kubeArangoDBNotesText = ` +kube-arangodb has been deployed successfully! + +Your release is named '{{ .Release.Name }}'. + +{{ if and .Values.Deployment.Create .Values.DeploymentReplication.Create -}} +You can now deploy ArangoDeployment & ArangoDeploymentReplication resources. +{{- else if and .Values.Deployment.Create (not .Values.DeploymentReplication.Create) -}} +You can now deploy ArangoDeployment resources. +{{- else if and (not .Values.Deployment.Create) .Values.DeploymentReplication.Create -}} +You can now deploy ArangoDeploymentReplication resources. +{{- end }} + +See https://docs.arangodb.com/devel/Manual/Tutorials/Kubernetes/ +for how to get started. +` + kubeArangoDBStorageNotesText = ` +kube-arangodb-storage has been deployed successfully! + +Your release is named '{{ .Release.Name }}'. + +You can now deploy an ArangoLocalStorage resource. + +See https://docs.arangodb.com/devel/Manual/Deployment/Kubernetes/StorageResource.html +for further instructions. +` +) + +var ( + chartTemplateGroups = map[string]chartTemplates{ + "kube-arangodb": chartTemplates{ + "Chart.yaml": kubeArangoDBChartTemplate, + "values.yaml": kubeArangoDBValuesTemplate, + "templates/NOTES.txt": kubeArangoDBNotesText, + }, + "kube-arangodb-storage": chartTemplates{ + "Chart.yaml": kubeArangoDBStorageChartTemplate, + "values.yaml": kubeArangoDBStorageValuesTemplate, + "templates/NOTES.txt": kubeArangoDBStorageNotesText, + }, } ) @@ -88,9 +211,12 @@ func init() { } type TemplateOptions struct { + Version string Image string ImagePullPolicy string RBAC bool + RBACFilterStart string + RBACFilterEnd string Deployment ResourceOptions DeploymentReplication ResourceOptions Storage ResourceOptions @@ -106,10 +232,13 @@ type CommonOptions struct { } type ResourceOptions struct { + Create string + FilterStart string + FilterEnd string User CommonOptions Operator CommonOptions OperatorDeploymentName string - AllowChaos bool + AllowChaos string } func main() { @@ -138,19 +267,36 @@ func main() { } // Prepare templates to include - templateNameSet := map[string][]string{ - "deployment": deploymentTemplateNames, - "deployment-replication": deploymentReplicationTemplateNames, - "storage": storageTemplateNames, - "test": testTemplateNames, + templateInfoSet := map[string]TemplateGroup{ + "deployment": TemplateGroup{ChartName: "kube-arangodb", Templates: deploymentTemplateNames}, + "deployment-replication": TemplateGroup{ChartName: "kube-arangodb", Templates: deploymentReplicationTemplateNames}, + "storage": TemplateGroup{ChartName: "kube-arangodb-storage", Templates: storageTemplateNames}, + "test": TemplateGroup{ChartName: "", Templates: testTemplateNames}, + } + + // Read VERSION + version, err := ioutil.ReadFile("VERSION") + if err != nil { + log.Fatalf("Failed to read VERSION file: %v", err) + } + + // Prepare chart tars + chartTarBufs := make(map[string]*bytes.Buffer) + chartTars := make(map[string]*tar.Writer) + for groupName := range chartTemplateGroups { + buf := &bytes.Buffer{} + chartTarBufs[groupName] = buf + chartTars[groupName] = tar.NewWriter(buf) } // Process templates templateOptions := TemplateOptions{ + Version: strings.TrimSpace(string(version)), Image: options.Image, ImagePullPolicy: options.ImagePullPolicy, RBAC: options.RBAC, Deployment: ResourceOptions{ + Create: "true", User: CommonOptions{ Namespace: options.Namespace, RoleName: "arango-deployments", @@ -165,9 +311,10 @@ func main() { ServiceType: "ClusterIP", }, OperatorDeploymentName: "arango-deployment-operator", - AllowChaos: options.AllowChaos, + AllowChaos: strconv.FormatBool(options.AllowChaos), }, DeploymentReplication: ResourceOptions{ + Create: "true", User: CommonOptions{ Namespace: options.Namespace, RoleName: "arango-deployment-replications", @@ -184,6 +331,7 @@ func main() { OperatorDeploymentName: "arango-deployment-replication-operator", }, Storage: ResourceOptions{ + Create: "true", User: CommonOptions{ Namespace: options.Namespace, RoleName: "arango-storages", @@ -206,27 +354,207 @@ func main() { ServiceAccountName: "default", }, } - for group, templateNames := range templateNameSet { - output := &bytes.Buffer{} - for i, name := range templateNames { - t, err := template.New(name).ParseFiles(filepath.Join(options.TemplatesDir, group, name)) - if err != nil { - log.Fatalf("Failed to parse template %s: %v", name, err) + chartTemplateOptions := TemplateOptions{ + Version: strings.TrimSpace(string(version)), + RBACFilterStart: "{{- if .Values.RBAC.Create }}", + RBACFilterEnd: "{{- end }}", + Image: "{{ .Values.Image }}", + ImagePullPolicy: "{{ .Values.ImagePullPolicy }}", + Deployment: ResourceOptions{ + Create: "{{ .Values.Deployment.Create }}", + FilterStart: "{{- if .Values.Deployment.Create }}", + FilterEnd: "{{- end }}", + User: CommonOptions{ + Namespace: "{{ .Release.Namespace }}", + RoleName: `{{ printf "%s-%s" .Release.Name "deployments" | trunc 63 | trimSuffix "-" }}`, + RoleBindingName: `{{ printf "%s-%s" .Release.Name "deployments" | trunc 63 | trimSuffix "-" }}`, + ServiceAccountName: "{{ .Values.Deployment.User.ServiceAccountName }}", + }, + Operator: CommonOptions{ + Namespace: "{{ .Release.Namespace }}", + RoleName: `{{ printf "%s-%s" .Release.Name "deployment-operator" | trunc 63 | trimSuffix "-" }}`, + RoleBindingName: `{{ printf "%s-%s" .Release.Name "deployment-operator" | trunc 63 | trimSuffix "-" }}`, + ServiceAccountName: "{{ .Values.Deployment.Operator.ServiceAccountName }}", + ServiceType: "{{ .Values.Deployment.Operator.ServiceType }}", + }, + OperatorDeploymentName: "arango-deployment-operator", // Fixed name because only 1 is allowed per namespace + AllowChaos: "{{ .Values.Deployment.AllowChaos }}", + }, + DeploymentReplication: ResourceOptions{ + Create: "{{ .Values.DeploymentReplication.Create }}", + FilterStart: "{{- if .Values.DeploymentReplication.Create }}", + FilterEnd: "{{- end }}", + User: CommonOptions{ + Namespace: "{{ .Release.Namespace }}", + RoleName: `{{ printf "%s-%s" .Release.Name "deployment-replications" | trunc 63 | trimSuffix "-" }}`, + RoleBindingName: `{{ printf "%s-%s" .Release.Name "deployment-replications" | trunc 63 | trimSuffix "-" }}`, + ServiceAccountName: "{{ .Values.DeploymentReplication.User.ServiceAccountName }}", + }, + Operator: CommonOptions{ + Namespace: "{{ .Release.Namespace }}", + RoleName: `{{ printf "%s-%s" .Release.Name "deployment-replication-operator" | trunc 63 | trimSuffix "-" }}`, + RoleBindingName: `{{ printf "%s-%s" .Release.Name "deployment-replication-operator" | trunc 63 | trimSuffix "-" }}`, + ServiceAccountName: "{{ .Values.DeploymentReplication.Operator.ServiceAccountName }}", + ServiceType: "{{ .Values.DeploymentReplication.Operator.ServiceType }}", + }, + OperatorDeploymentName: "arango-deployment-replication-operator", // Fixed name because only 1 is allowed per namespace + }, + Storage: ResourceOptions{ + Create: "{{ .Values.Storage.Create }}", + User: CommonOptions{ + Namespace: "{{ .Release.Namespace }}", + RoleName: `{{ printf "%s-%s" .Release.Name "storages" | trunc 63 | trimSuffix "-" }}`, + RoleBindingName: `{{ printf "%s-%s" .Release.Name "storages" | trunc 63 | trimSuffix "-" }}`, + ServiceAccountName: "{{ .Values.Storage.User.ServiceAccountName }}", + }, + Operator: CommonOptions{ + Namespace: "kube-system", + RoleName: `{{ printf "%s-%s" .Release.Name "storage-operator" | trunc 63 | trimSuffix "-" }}`, + RoleBindingName: `{{ printf "%s-%s" .Release.Name "storage-operator" | trunc 63 | trimSuffix "-" }}`, + ServiceAccountName: "{{ .Values.Storage.Operator.ServiceAccountName }}", + ServiceType: "{{ .Values.Storage.Operator.ServiceType }}", + }, + OperatorDeploymentName: "arango-storage-operator", // Fixed name because only 1 is allowed per namespace + }, + } + + for group, templateGroup := range templateInfoSet { + // Build standalone yaml file for this group + { + output := &bytes.Buffer{} + for _, tempInfo := range templateGroup.Templates { + if tempInfo.Predicate == nil || tempInfo.Predicate(templateOptions, false) { + name := tempInfo.Name + t, err := template.New(name).ParseFiles(filepath.Join(options.TemplatesDir, group, name)) + if err != nil { + log.Fatalf("Failed to parse template %s: %v", name, err) + } + // Execute to tmp buffer + tmpBuf := &bytes.Buffer{} + t.Execute(tmpBuf, templateOptions) + // Add tmp buffer to output, unless empty + if strings.TrimSpace(tmpBuf.String()) != "" { + if output.Len() > 0 { + output.WriteString("\n---\n\n") + } + output.WriteString(fmt.Sprintf("## %s/%s\n", group, name)) + tmpBuf.WriteTo(output) + output.WriteString("\n") + } + } } - if i > 0 { - output.WriteString("\n---\n\n") + + // Save output + if output.Len() > 0 { + outputDir, err := filepath.Abs("manifests") + if err != nil { + log.Fatalf("Failed to get absolute output dir: %v\n", err) + } + outputPath := filepath.Join(outputDir, "arango-"+group+options.OutputSuffix+".yaml") + if err := os.MkdirAll(outputDir, 0755); err != nil { + log.Fatalf("Failed to create output directory: %v\n", err) + } + if err := ioutil.WriteFile(outputPath, output.Bytes(), 0644); err != nil { + log.Fatalf("Failed to write output file: %v\n", err) + } } - output.WriteString(fmt.Sprintf("## %s/%s\n", group, name)) - t.Execute(output, templateOptions) - output.WriteString("\n") } - // Save output - outputDir, err := filepath.Abs("manifests") + // Build helm template file for this group + { + output := &bytes.Buffer{} + for _, tempInfo := range templateGroup.Templates { + if tempInfo.Predicate == nil || tempInfo.Predicate(chartTemplateOptions, true) { + name := tempInfo.Name + t, err := template.New(name).ParseFiles(filepath.Join(options.TemplatesDir, group, name)) + if err != nil { + log.Fatalf("Failed to parse template %s: %v", name, err) + } + // Execute to tmp buffer + tmpBuf := &bytes.Buffer{} + t.Execute(tmpBuf, templateOptions) + // Add tmp buffer to output, unless empty + if strings.TrimSpace(tmpBuf.String()) != "" { + if output.Len() > 0 { + output.WriteString("\n---\n\n") + } + output.WriteString(fmt.Sprintf("## %s/%s\n", group, name)) + tmpBuf.WriteTo(output) + output.WriteString("\n") + } + } + } + + // Save output + if output.Len() > 0 { + tarPath := path.Join(templateGroup.ChartName, "templates", group+".yaml") + hdr := &tar.Header{ + Name: tarPath, + Mode: 0644, + Size: int64(output.Len()), + } + tw := chartTars[templateGroup.ChartName] + if err := tw.WriteHeader(hdr); err != nil { + log.Fatal(err) + } + if _, err := tw.Write(output.Bytes()); err != nil { + log.Fatal(err) + } + } + } + } + + // Build Chart files + for groupName, chartTemplates := range chartTemplateGroups { + for name, templateSource := range chartTemplates { + output := &bytes.Buffer{} + if strings.HasSuffix(name, ".txt") { + // Plain text + output.WriteString(templateSource) + } else { + // Template + t, err := template.New(name).Funcs(tmplFuncs).Parse(templateSource) + if err != nil { + log.Fatalf("Failed to parse template %s: %v", name, err) + } + t.Execute(output, templateOptions) + } + + // Save output + tarPath := path.Join(groupName, name) + hdr := &tar.Header{ + Name: tarPath, + Mode: 0644, + Size: int64(output.Len()), + } + tw := chartTars[groupName] + if err := tw.WriteHeader(hdr); err != nil { + log.Fatal(err) + } + if _, err := tw.Write(output.Bytes()); err != nil { + log.Fatal(err) + } + } + } + + // Save charts + for groupName, tw := range chartTars { + if err := tw.Close(); err != nil { + log.Fatal(err) + } + // Gzip tarball + tarBytes := chartTarBufs[groupName].Bytes() + output := &bytes.Buffer{} + gw := gzip.NewWriter(output) + if _, err := gw.Write(tarBytes); err != nil { + log.Fatal(err) + } + gw.Close() + outputDir, err := filepath.Abs("bin/charts") if err != nil { log.Fatalf("Failed to get absolute output dir: %v\n", err) } - outputPath := filepath.Join(outputDir, "arango-"+group+options.OutputSuffix+".yaml") + outputPath := filepath.Join(outputDir, groupName+".tgz") if err := os.MkdirAll(outputDir, 0755); err != nil { log.Fatalf("Failed to create output directory: %v\n", err) } diff --git a/tools/release/release.go b/tools/release/release.go index f32aed77b..84e008c2d 100644 --- a/tools/release/release.go +++ b/tools/release/release.go @@ -23,6 +23,8 @@ package main import ( + "crypto/sha256" + "encoding/hex" "flag" "fmt" "io/ioutil" @@ -41,6 +43,12 @@ var ( ghRelease string // Full path of github-release tool ghUser string // Github account name to create release in ghRepo string // Github repository name to create release in + binFolder string // Folder containing binaries + + binaries = map[string]string{ + "kube-arangodb.tgz": "charts/kube-arangodb.tgz", + "kube-arangodb-storage.tgz": "charts/kube-arangodb-storage.tgz", + } ) func init() { @@ -49,6 +57,7 @@ func init() { flag.StringVar(&ghRelease, "github-release", ".gobuild/bin/github-release", "Full path of github-release tool") flag.StringVar(&ghUser, "github-user", "arangodb", "Github account name to create release in") flag.StringVar(&ghRepo, "github-repo", "kube-arangodb", "Github repository name to create release in") + flag.StringVar(&binFolder, "bin-folder", "./bin", "Folder containing binaries") } func main() { @@ -65,6 +74,7 @@ func main() { }) make("patch-readme", nil) make("build-ghrelease", nil) + createSHA256Sums() gitCommitAll(fmt.Sprintf("Updated manifest to %s", version)) // Commit manifest gitTag(version) make("changelog", nil) @@ -155,6 +165,23 @@ func gitTag(version string) { } } +func createSHA256Sums() { + sums := []string{} + for name, p := range binaries { + blob, err := ioutil.ReadFile(filepath.Join(binFolder, p)) + if err != nil { + log.Fatalf("Failed to read binary '%s': %#v\n", name, err) + } + bytes := sha256.Sum256(blob) + sha := hex.EncodeToString(bytes[:]) + sums = append(sums, sha+" "+name) + } + sumsPath := filepath.Join(binFolder, "SHA256SUMS") + if err := ioutil.WriteFile(sumsPath, []byte(strings.Join(sums, "\n")+"\n"), 0644); err != nil { + log.Fatalf("Failed to write '%s': %#v\n", sumsPath, err) + } +} + func githubCreateRelease(version string) { // Create draft release args := []string{ @@ -167,6 +194,26 @@ func githubCreateRelease(version string) { if err := run(ghRelease, args, nil); err != nil { log.Fatalf("Failed to create github release: %v\n", err) } + // Upload binaries + assets := map[string]string{ + "SHA256SUMS": "SHA256SUMS", + } + for k, v := range binaries { + assets[k] = v + } + for name, file := range assets { + args := []string{ + "upload", + "--user", ghUser, + "--repo", ghRepo, + "--tag", version, + "--name", name, + "--file", filepath.Join(binFolder, file), + } + if err := run(ghRelease, args, nil); err != nil { + log.Fatalf("Failed to upload asset '%s': %v\n", name, err) + } + } // Finalize release args = []string{ "edit",