From e1fc0fa01f0e624a6a76a2fb03efd6b63886a2cf Mon Sep 17 00:00:00 2001 From: Levi Blackstone Date: Thu, 1 Aug 2019 09:30:19 -0600 Subject: [PATCH] Fix Python Helm LocalChartOpts inheritance --- CHANGELOG.md | 1 + pkg/gen/python-templates/helm/v2/helm.py | 2 +- sdk/python/pulumi_kubernetes/helm/v2/helm.py | 2 +- tests/examples/python/helm-local/Pulumi.yaml | 3 + tests/examples/python/helm-local/__main__.py | 22 ++++ .../python/helm-local/requirements.txt | 1 + .../python/helm-local/unbound/.helmignore | 21 ++++ .../python/helm-local/unbound/Chart.yaml | 13 ++ .../python/helm-local/unbound/README.md | 115 ++++++++++++++++++ .../helm-local/unbound/templates/NOTES.txt | 1 + .../helm-local/unbound/templates/_helpers.tpl | 32 +++++ .../unbound/templates/configmap.yaml | 69 +++++++++++ .../unbound/templates/deployment.yaml | 87 +++++++++++++ .../unbound/templates/disruption_budget.yaml | 15 +++ .../helm-local/unbound/templates/service.yaml | 26 ++++ .../python/helm-local/unbound/values.yaml | 56 +++++++++ 16 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 tests/examples/python/helm-local/Pulumi.yaml create mode 100644 tests/examples/python/helm-local/__main__.py create mode 100644 tests/examples/python/helm-local/requirements.txt create mode 100755 tests/examples/python/helm-local/unbound/.helmignore create mode 100755 tests/examples/python/helm-local/unbound/Chart.yaml create mode 100755 tests/examples/python/helm-local/unbound/README.md create mode 100755 tests/examples/python/helm-local/unbound/templates/NOTES.txt create mode 100755 tests/examples/python/helm-local/unbound/templates/_helpers.tpl create mode 100755 tests/examples/python/helm-local/unbound/templates/configmap.yaml create mode 100755 tests/examples/python/helm-local/unbound/templates/deployment.yaml create mode 100755 tests/examples/python/helm-local/unbound/templates/disruption_budget.yaml create mode 100755 tests/examples/python/helm-local/unbound/templates/service.yaml create mode 100755 tests/examples/python/helm-local/unbound/values.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index aaa379fc28..de3d2e7b5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Fall back to client-side diff if server-side diff fails. (https://github.com/pulumi/pulumi-kubernetes/pull/685). - Fix namespace arg for Python Helm SDK (https://github.com/pulumi/pulumi-kubernetes/pull/670). - Fix values arg for Python Helm SDK (https://github.com/pulumi/pulumi-kubernetes/pull/678). +- Fix Python Helm LocalChartOpts to inherit from BaseChartOpts (https://github.com/pulumi/pulumi-kubernetes/pull/681). ## 0.25.4 (August 1, 2019) diff --git a/pkg/gen/python-templates/helm/v2/helm.py b/pkg/gen/python-templates/helm/v2/helm.py index aa873d83d3..e917706f0a 100644 --- a/pkg/gen/python-templates/helm/v2/helm.py +++ b/pkg/gen/python-templates/helm/v2/helm.py @@ -263,7 +263,7 @@ def __init__(self, self.fetch_opts = fetch_opts -class LocalChartOpts: +class LocalChartOpts(BaseChartOpts): """ LocalChartOpts is a bag of configuration options for a local Helm chart. """ diff --git a/sdk/python/pulumi_kubernetes/helm/v2/helm.py b/sdk/python/pulumi_kubernetes/helm/v2/helm.py index aa873d83d3..e917706f0a 100644 --- a/sdk/python/pulumi_kubernetes/helm/v2/helm.py +++ b/sdk/python/pulumi_kubernetes/helm/v2/helm.py @@ -263,7 +263,7 @@ def __init__(self, self.fetch_opts = fetch_opts -class LocalChartOpts: +class LocalChartOpts(BaseChartOpts): """ LocalChartOpts is a bag of configuration options for a local Helm chart. """ diff --git a/tests/examples/python/helm-local/Pulumi.yaml b/tests/examples/python/helm-local/Pulumi.yaml new file mode 100644 index 0000000000..dcefdd11a1 --- /dev/null +++ b/tests/examples/python/helm-local/Pulumi.yaml @@ -0,0 +1,3 @@ +name: helm-local +description: A program that tests Helm chart creation from a local directory +runtime: python diff --git a/tests/examples/python/helm-local/__main__.py b/tests/examples/python/helm-local/__main__.py new file mode 100644 index 0000000000..dc045de36b --- /dev/null +++ b/tests/examples/python/helm-local/__main__.py @@ -0,0 +1,22 @@ +# Copyright 2016-2019, Pulumi Corporation. +# +# 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. +from pulumi_kubernetes.helm.v2 import Chart, LocalChartOpts + +values = {"unbound": {"image": {"pullPolicy": "Always"}}} + +Chart("unbound", LocalChartOpts("unbound", values=values)) + +# Deploy a duplicate chart with a different resource prefix to verify that multiple instances of the Chart +# can be managed in the same stack. +Chart("unbound", LocalChartOpts("unbound", resource_prefix="dup", values=values)) diff --git a/tests/examples/python/helm-local/requirements.txt b/tests/examples/python/helm-local/requirements.txt new file mode 100644 index 0000000000..e530895247 --- /dev/null +++ b/tests/examples/python/helm-local/requirements.txt @@ -0,0 +1 @@ +pulumi>=0.17.1,<0.18.0 diff --git a/tests/examples/python/helm-local/unbound/.helmignore b/tests/examples/python/helm-local/unbound/.helmignore new file mode 100755 index 0000000000..f0c1319444 --- /dev/null +++ b/tests/examples/python/helm-local/unbound/.helmignore @@ -0,0 +1,21 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/tests/examples/python/helm-local/unbound/Chart.yaml b/tests/examples/python/helm-local/unbound/Chart.yaml new file mode 100755 index 0000000000..17bf8bde64 --- /dev/null +++ b/tests/examples/python/helm-local/unbound/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +appVersion: 1.6.7 +description: Unbound is a fast caching DNS resolver +home: https://www.unbound.net/ +maintainers: +- email: betz.mark@gmail.com + name: Markbnj +name: unbound +sources: +- http://unbound.nlnetlabs.nl/svn/ +- https://github.com/Markbnj/unbound-docker +- https://github.com/kubernetes/contrib/tree/master/exec-healthz +version: 1.0.0 diff --git a/tests/examples/python/helm-local/unbound/README.md b/tests/examples/python/helm-local/unbound/README.md new file mode 100755 index 0000000000..b4a4ae903b --- /dev/null +++ b/tests/examples/python/helm-local/unbound/README.md @@ -0,0 +1,115 @@ +# Unbound + +[Unbound](http://www.unbound.net) is a caching DNS resolver written in C. It is suitable for use as an upstream DNS resolver for kube-dns. The image is based on alpine and includes unbound, bind-tools and bash and is approximately 20MB in size, making for fast startup. Google's [healthz container](https://hub.docker.com/r/googlecontainer/exechealthz/) is used as a sidecar to probe the unbound container on localhost, which allows unbound to run in a default configuration with restricted network access, and still play nice with kubelet. + +## Configuration + +The chart values file contains the default settings for the unbound server. In the default configuration unbound will allow queries from localhost only, and will not have any forward zones. This means that queries sent to the ClusterIP of the service will return access denied, and queries from localhost for anything other than the health check record `health.check.unbound` will return NXDOMAIN. + +You can configure unbound for your specific use case by passing a values file that contains the following properties. Most or all of these can also be set from the helm command line using `--set`. + +### Access control + +Controls which IP address ranges unbound will allow queries from. If you want to use unbound as an upstream for kube-dns, or allow other pods to query the resolver directly, you'll at least need to allow the `clusterIpV4Cidr` range. + +```yaml +allowedIpRanges: +- "10.10.10.10/20" +- "10.10.11.11/20" +``` + +### Forward zones + +You can set as many forward zones as needed by specifying the zone name and forward hosts. Forward hosts can be set by hostname or IP. + +```yaml +forwardZones: +- name: "fake.net" + forwardHosts: + - "fake1.host.net" + - "fake2.host.net" +- name: "stillfake.net" + forwardIps: + - "10.10.10.10" + - "10.11.10.10" +``` + +### Local records + +Unbound can store DNS records in a "local zone." This facility can be used to assign context-specific names to a given IP address, and could also be used for private DNS if you don't want or have an external resolver. + +```yaml +localRecords: +- name: "fake3.host.net" + ip: "10.12.10.10" +- name: "fake4.host.net" + ip: "10.13.10.10" +``` + +### Other configurable properties + +The following properties in values.yaml configure additional aspects of the unbound server. For more information see the [unbound documentation](http://unbound.net/documentation/unbound.conf.html). + +``` +unbound.verbosity: 1 +unbound.numThreads: 1 +unbound.statsInterval: 0 +unbound.statsCumulative: no +unbound.serverPort: 53 +``` + +### All configurable properties + +| Property | Default value | +| ------------------------ | --------------------------- | +| replicaCount | 1 | +| externalIP | "" | +| unbound.image.repository | markbnj/unbound-docker | +| unbound.image.tag | 0.1.0 | +| unbound.image.pullPolicy | IfNotPresent | +| unbound.verbosity | 1 | +| unbound.numThreads | 1 | +| unbound.statsInterval | 0 | +| unbound.statsCumulative | no | +| unbound.serverPort | 53 | +| healthz.image.repository | googlecontainer/exechealthz | +| healthz.image.tag | 1.2 | +| healthz.image.pullPolicy | IfNotPresent | +| resources | {} | +| nodeSelector | {} | +| tolerations | [] | +| affinity | {} | +| allowedIpRanges | [] | +| forwardZones | [] | +| stubZones | [] | +| localRecords | [] | +| localZones | [] | + +### Configuration changes + +The unbound deployment template includes the sha256 hash of the configmap as an annotation. This will cause the deployment to update if the configuration is changed. For more information on this and other useful stuff see [chart tips and tricks](https://github.com/kubernetes/helm/blob/master/docs/charts_tips_and_tricks.md). + +### Health checks + +Liveness and readiness probes are implemented by a side-car [healthz container](https://github.com/kubernetes/contrib/tree/master/exec-healthz). When a http GET is made to port 8080 healthz runs an nslookup against the unbound server on localhost querying for the name `health.check.unbound` which is stored as a local record in the configuration. + +## Configuring as an upstream resolver for kube-dns + +To configure unbound to act as an upstream resolver for kube-dns edit the `kube-dns` configmap in the kube-system namespace to add the `stubDomains` value as shown below. The forwarding address for the domain should be set to the ClusterIP of the unbound service. + +```yaml +apiVersion: v1 +data: + stubDomains: | + {"fake.net": ["10.10.10.10"]} +kind: ConfigMap +metadata: + creationTimestamp: 2018-01-04T18:09:38Z + labels: + addonmanager.kubernetes.io/mode: EnsureExists + name: kube-dns + namespace: kube-system + resourceVersion: "1825" + selfLink: /api/v1/namespaces/kube-system/configmaps/kube-dns + uid: 6d759f7d-f17a-11e7-898d-42010a800159 +``` diff --git a/tests/examples/python/helm-local/unbound/templates/NOTES.txt b/tests/examples/python/helm-local/unbound/templates/NOTES.txt new file mode 100755 index 0000000000..4eb8c273dc --- /dev/null +++ b/tests/examples/python/helm-local/unbound/templates/NOTES.txt @@ -0,0 +1 @@ +Unbound release has been installed or upgraded. For information on configuring unbound as an upstream resolver for kube-dns see the readme. diff --git a/tests/examples/python/helm-local/unbound/templates/_helpers.tpl b/tests/examples/python/helm-local/unbound/templates/_helpers.tpl new file mode 100755 index 0000000000..8e8740e51c --- /dev/null +++ b/tests/examples/python/helm-local/unbound/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* + +{{/* +Expand the name of the chart. +*/}} +{{- define "unbound.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a fully qualified app name +*/}} +{{- define "unbound.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 "unbound.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/tests/examples/python/helm-local/unbound/templates/configmap.yaml b/tests/examples/python/helm-local/unbound/templates/configmap.yaml new file mode 100755 index 0000000000..5deab5142a --- /dev/null +++ b/tests/examples/python/helm-local/unbound/templates/configmap.yaml @@ -0,0 +1,69 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "unbound.fullname" . }} + labels: + app: {{ template "unbound.name" . }} + chart: {{ template "unbound.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + unbound.conf: |- + server: + chroot: "" + num-threads: {{ .Values.unbound.numThreads }} + directory: "/etc/unbound" + port: {{ .Values.unbound.serverPort }} + so-reuseport: yes + do-daemonize: no + logfile: "" + use-syslog: no + auto-trust-anchor-file: "/var/lib/unbound/root.key" + verbosity: {{ .Values.unbound.verbosity }} + statistics-interval: {{ .Values.unbound.statsInterval }} + statistics-cumulative: {{ .Values.unbound.statsCumulative }} + + interface: 127.0.0.1 + interface: 0.0.0.0 + + access-control: 127.0.0.1/32 allow + + {{- range .Values.allowedIpRanges }} + access-control: {{ . }} allow + {{- end }} + + {{- range .Values.localRecords }} + local-data: "{{ .name }} A {{ .ip }}" + local-data-ptr: "{{ .ip }} {{ .name }}" + {{- end }} + + local-data: "health.check.unbound A 127.0.0.1" + local-data-ptr: "127.0.0.1 health.check.unbound" + + {{- range .Values.localZones }} + local-zone: "{{ .name }}" {{ .localType }} + {{- end }} + + {{- range .Values.forwardZones }} + + forward-zone: + name: {{ .name }} + {{- range .forwardHosts }} + forward-host: {{ . }} + {{- end }} + {{- range .forwardIps }} + forward-addr: {{ . }} + {{- end }} + {{- end }} + + {{- range .Values.stubZones }} + + stub-zone: + name: {{ .name }} + {{- range .stubHosts }} + stub-host: {{ . }} + {{- end }} + {{- range .stubIps }} + stub-addr: {{ . }} + {{- end }} + {{- end }} diff --git a/tests/examples/python/helm-local/unbound/templates/deployment.yaml b/tests/examples/python/helm-local/unbound/templates/deployment.yaml new file mode 100755 index 0000000000..488208dd13 --- /dev/null +++ b/tests/examples/python/helm-local/unbound/templates/deployment.yaml @@ -0,0 +1,87 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "unbound.fullname" . }} + labels: + app: {{ template "unbound.name" . }} + chart: {{ template "unbound.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "unbound.name" . }} + release: {{ .Release.Name }} + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + template: + metadata: + labels: + chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app: {{ template "unbound.name" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + spec: + containers: + - name: "unbound" + image: {{ .Values.unbound.image.repository }}:{{ .Values.unbound.image.tag }} + imagePullPolicy: {{ .Values.unbound.image.pullPolicy | quote }} +{{- with .Values.resources }} + resources: +{{ toYaml . | indent 10 }} +{{- end }} + ports: + - name: "dns-udp" + containerPort: {{ .Values.unbound.serverPort }} + protocol: "UDP" + - name: "dns-tcp" + containerPort: {{ .Values.unbound.serverPort }} + protocol: "TCP" + volumeMounts: + - name: "unbound-conf" + mountPath: "/etc/unbound/" + readOnly: true + livenessProbe: + httpGet: + path: "/healthz" + port: 8080 + initialDelaySeconds: 5 + timeoutSeconds: 2 + readinessProbe: + httpGet: + path: "/healthz" + port: 8080 + initialDelaySeconds: 5 + timeoutSeconds: 2 + - name: "healthz" + image: {{ .Values.healthz.image.repository }}:{{ .Values.healthz.image.tag }} + imagePullPolicy: {{ .Values.healthz.image.pullPolicy | quote }} + args: + - "-cmd=nslookup health.check.unbound 127.0.0.1:{{ .Values.unbound.serverPort }} > /dev/null" + ports: + - name: healthz + containerPort: 8080 + protocol: TCP + volumes: + - name: "unbound-conf" + configMap: + name: {{ template "unbound.fullname" . }} +{{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} + diff --git a/tests/examples/python/helm-local/unbound/templates/disruption_budget.yaml b/tests/examples/python/helm-local/unbound/templates/disruption_budget.yaml new file mode 100755 index 0000000000..2c502586c7 --- /dev/null +++ b/tests/examples/python/helm-local/unbound/templates/disruption_budget.yaml @@ -0,0 +1,15 @@ +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "unbound.fullname" . }} + labels: + app: {{ template "unbound.name" . }} + chart: {{ template "unbound.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + maxUnavailable: 1 + selector: + matchLabels: + app: {{ template "unbound.name" . }} + release: {{ .Release.Name }} diff --git a/tests/examples/python/helm-local/unbound/templates/service.yaml b/tests/examples/python/helm-local/unbound/templates/service.yaml new file mode 100755 index 0000000000..1743d22d51 --- /dev/null +++ b/tests/examples/python/helm-local/unbound/templates/service.yaml @@ -0,0 +1,26 @@ +kind: Service +apiVersion: v1 +metadata: + name: {{ template "unbound.fullname" . }} + labels: + app: {{ template "unbound.name" . }} + chart: {{ template "unbound.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + {{- if .Values.externalIP }} + externalIPs: + - {{ .Values.externalIP }} + {{- end }} + selector: + app: {{ template "unbound.name" . }} + release: {{ .Release.Name }} + ports: + - name: dns-udp + protocol: UDP + port: {{ .Values.unbound.serverPort }} + targetPort: dns-udp + - name: dns-tcp + protocol: TCP + port: {{ .Values.unbound.serverPort }} + targetPort: dns-tcp diff --git a/tests/examples/python/helm-local/unbound/values.yaml b/tests/examples/python/helm-local/unbound/values.yaml new file mode 100755 index 0000000000..11792410cc --- /dev/null +++ b/tests/examples/python/helm-local/unbound/values.yaml @@ -0,0 +1,56 @@ +replicaCount: 1 + +# values that pertain to the unbound container, for more information +# on unbound configuration see http://unbound.net/documentation/unbound.conf.html +unbound: + image: + repository: markbnj/unbound-docker + tag: "0.1.0" + pullPolicy: IfNotPresent + verbosity: 1 + numThreads: 1 + statsInterval: 0 + statsCumulative: "no" + serverPort: 53 + +# values that pertain to the exechealthz container, for more information see +# https://github.com/kubernetes/contrib/tree/master/exec-healthz +healthz: + image: + repository: googlecontainer/exechealthz + tag: "1.2" + pullPolicy: IfNotPresent + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# Controls which IP address ranges unbound will allow queries from. +# If you want to use unbound as an upstream for kube-dns, or allow other pods +# to query the resolver directly, you'll at least need to allow the +# clusterIpV4Cidr range. + +# allowedIpRanges: +# - "10.10.10.10/20" + +# You can set as many forward zones as needed by specifying the zone name +# and forward hosts. Forward hosts can be set by hostname or ip. + +# forwardZones: +# - name: "fake.net" +# forwardHosts: +# - "fake1.host.net" +# forwardIps: +# - "10.10.10.10" + +# Unbound can store DNS records in a "local zone." This facility can be used to +# assign context-specific names to a given IP address, and could also be used for +# private DNS if you don't want or have an external resolver. + +# localRecords: +# - name: "fake3.host.net" +# ip: "10.12.10.10"