Upgrade to Helm3 (#572)

OpenWhisk Helm chart now requires Helm3.
+ update documentation
+ update chart version
+ added values.schema.json to enforce typing constraints on values.yaml
+ misc small fixes found by better validation in Helm 3
diff --git a/README.md b/README.md
index c8e78ee..62a55b6 100644
--- a/README.md
+++ b/README.md
@@ -127,41 +127,26 @@
 the default configuration of OpenWhisk.  You can deploy to
 significantly larger clusters by scaling up the replica count of the
 various components and labeling multiple nodes as invoker nodes.
-There are some additional notes [here](docs/k8s-diy.md).
 
-[Here](docs/k8s-diy-ubuntu.md) a Kubernetes cluster example using kubeadm and Ubuntu 18.04.
-
+Additional more detailed instructions:
+* [Some general comments](docs/k8s-diy.md).
+* [Using kubeadm on Ubuntu 18.04](docs/k8s-diy-ubuntu.md).
 
 ## Helm
 
 [Helm](https://github.com/kubernetes/helm) is a tool to simplify the
-deployment and management of applications on Kubernetes clusters. Helm
-consists of the `helm` command line tool that you install on your
-development machine and the `tiller` runtime that is deployed on your
-Kubernetes cluster.
+deployment and management of applications on Kubernetes clusters.
+The OpenWhisk Helm chart requires the Helm 3.
 
-For details on installing Helm, see these [instructions](docs/helm.md).
+Our automated testing currently uses Helm v3.0.1.
 
-WARNING: There is a [serious regression in Helm v2.15.0](https://github.com/helm/helm/issues/6708)
-that impacts the OpenWhisk chart.  You should use Helm v2.14.3.
-
-In short if you already have the `helm` cli installed on your development machine,
-you will need to execute these two commands and wait a few seconds for the
-`tiller-deploy` pod in the `kube-system` namespace to be in the `Running` state.
-```shell
-helm init
-kubectl create clusterrolebinding tiller-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
-```
-
-If you are targeting an OKD/OpenShift cluster, you will need the
-`helm` cli on your development machine but will not run the
-`tiller-deploy` pod in the cluster as it is not allowed by
-OKD/OpenShift security policies.
+Follow the Helm [install instructions](https://github.com/kubernetes/helm)
+for your platform to install Helm v3.0.1 or newer.
 
 # Deploying OpenWhisk
 
-Now that you have your Kubernetes cluster and have installed and
-initialized Helm, you are ready to deploy OpenWhisk.
+Now that you have your Kubernetes cluster and have installed
+the Helm 3 CLI, you are ready to deploy OpenWhisk.
 
 ## Overview
 
@@ -240,25 +225,27 @@
 
 ## Deploy With Helm
 
-Deployment can be done by using the following single command:
-```shell
-helm install ./helm/openwhisk --namespace=openwhisk --name=owdev -f mycluster.yaml
-```
-
-Deploying to OKD/OpenShift uses the commands:
-```shell
-helm template ./helm/openwhisk --namespace=openwhisk --name=owdev -f mycluster.yaml > owdev.yaml
-oc create -f owdev.yaml
-```
-We recommend generating to a file to make it easier to undeploy openwhisk later
-by simply doing `oc delete -f owdev.yaml`
-
 For simplicity, in this README, we have used `owdev` as the release name and
 `openwhisk` as the namespace into which the Chart's resources will be deployed.
-You can use different names, or not specify a release name at all and let
-Helm auto-generate one for you.
+You can use a different name and/or namespace simply by changing the commands
+used below.
 
-You can use the command `helm status owdev` to get a summary
+Deployment can be done by using the following single command:
+```shell
+helm install owdev ./helm/openwhisk -n openwhisk -f mycluster.yaml
+```
+
+Deploying to OKD/OpenShift uses the command sequence:
+```shell
+helm template owdev ./helm/openwhisk -n openwhisk -f mycluster.yaml > owdev.yaml
+oc create -f owdev.yaml
+```
+The two step sequence is currently required because the `oc` command must be
+used to create the `Route` resource specified in the generated `owdev.yaml`.
+We recommend generating to a file to make it easier to undeploy OpenWhisk later
+by simply doing `oc delete -f owdev.yaml`
+
+You can use the command `helm status owdev -n openwhisk` to get a summary
 of the various Kubernetes artifacts that make up your OpenWhisk
 deployment. Once the `install-packages` Pod is in the `Completed` state,
 your OpenWhisk deployment is ready to be used.
@@ -294,10 +281,8 @@
 [these instructions](https://github.com/apache/openwhisk/blob/master/docs/actions.md)
 to define and invoke a sample OpenWhisk action in your favorite programming language.
 
-You can also issue the command `helm test owdev` to run the basic
-verification test suite included in the OpenWhisk Helm chart. Note
-that `helm test` is not supported for OpenShift deployments because it
-requires the `tiller` pod to be run in the cluster.
+You can also issue the command `helm test owdev -n openwhisk` to run the basic
+verification test suite included in the OpenWhisk Helm chart.
 
 Note: if you installed self-signed certificates, which is the default
 for the OpenWhisk Helm chart, you will need to use `wsk -i` to
@@ -402,7 +387,7 @@
 Redeploy with Helm by executing this commaned in your
 openwhisk-deploy-kube directory:
 ```shell
-helm upgrade ./helm/openwhisk --namespace=openwhisk --name=owdev -f mycluster.yaml
+helm upgrade owdev ./helm/openwhisk -n openwhisk -f mycluster.yaml
 ```
 
 ### Deploying Lean Openwhisk version.
@@ -417,17 +402,14 @@
 
 Use the following command to remove all the deployed OpenWhisk components:
 ```shell
-helm delete owdev
+helm uninstall owdev -n openwhisk
 ```
-Helm does keep a history of previous deployments.  If you want to
-completely remove the deployment from helm, for example so you can
-reuse owdev to deploy OpenWhisk again, use the command:
-```shell
-helm delete owdev --purge
-```
+By default, `helm uninstall` removes the history of previous deployments.
+If you want to keep the history, add the command line flag `--keep-history`.
 
-For OpenShift deployments, you cannot use Helm to remove the OpenWhisk
-deployment.  If you saved the output from `helm template` into a file,
+For OpenShift deployments, you cannot use `helm uninstall` to remove the OpenWhisk
+deployment because we did not do a `helm install`.
+If you saved the output from `helm template` into a file,
 you can simply use that file as an argument to `oc delete`.  If you
 did not save the file, you can redo the `helm template` command and
 feed the generated yaml into an `oc delete` command.
diff --git a/docs/helm.md b/docs/helm.md
deleted file mode 100644
index 5d42ee3..0000000
--- a/docs/helm.md
+++ /dev/null
@@ -1,56 +0,0 @@
-<!--
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You 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.
-#
--->
-
-## Installing Helm
-
-[Helm](https://github.com/kubernetes/helm) is a tool to simplify the
-deployment and management of applications on Kubernetes clusters.  We
-will use Helm to deploy OpenWhisk on Kubernetes.
-
-Before you can use Helm, you need to do a small amount of one-time
-setup on your Kubernetes cluster.
-
-1. Make sure that you have a running Kubernetes cluster and a
-`kubectl` client connected to this cluster as described in the
-[Requirements section](../README.md#requirements) of the main
-README.md.
-
-2. Follow the Helm [install instructions](https://github.com/kubernetes/helm)
-for your platform to install Helm v2.14.3.
-
-WARNING: There is a [serious regression in Helm v2.15.0](https://github.com/helm/helm/issues/6708)
-that impacts the OpenWhisk chart.  You cannout use versions of Helm newer than v2.14.3 until
-a there is a 2.15.x release with a fix for the regression.
-
-3. Run the following command to init `Helm Tiller`:
-```shell
-helm init
-```
-
-4. To see if Helm is ready, use the command below and make sure the
-`tiller-deploy` pod is in the `Running` state.
-```shell
-kubectl get pods -n kube-system
-```
-
-5. Grant the necessary privileges to the `Helm` user:
-```shell
-kubectl create clusterrolebinding tiller-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
-```
-
diff --git a/docs/k8s-docker-for-windows.md b/docs/k8s-docker-for-windows.md
index d83ffaa..8fbf06d 100644
--- a/docs/k8s-docker-for-windows.md
+++ b/docs/k8s-docker-for-windows.md
@@ -77,29 +77,21 @@
 
 ### Using helm to install OpenWhisk
 
-Execute these two commands and wait a few seconds for the tiller-deploy pod
-in the kube-system namespace to be in the Running state:
-
-```cmd
-helm init
-kubectl create clusterrolebinding tiller-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
-```
-
 Indicate the Kubernetes worker nodes that should be used to execute user
 containers by OpenWhisk's invokers. For a single node development cluster,
 simply run:
 
 `kubectl label nodes --all openwhisk-role=invoker`
 
-Now you're ready to run helm to set up OpenWhisk. Make sure you created your
+Make sure you created your
 `mycluster.yaml` file as described above, and run:
 
 ```cmd
 cd openwhisk-deploy-kube
-helm install ./helm/openwhisk --namespace=openwhisk --name=owdev -f mycluster.yaml
+helm install owdev ./helm/openwhisk -n openwhisk -f mycluster.yaml
 ```
 
-You can use the command `helm status owdev` to get a summary of the various
+You can use the command `helm status owdev -n openwhisk` to get a summary of the various
 Kubernetes artifacts that make up your OpenWhisk deployment. Once the
 `install-packages` Pod is in the Completed state, your OpenWhisk deployment
 is ready to be used.
diff --git a/docs/k8s-nfs-dynamic-storage.md b/docs/k8s-nfs-dynamic-storage.md
index 67a4a4a..e536180 100644
--- a/docs/k8s-nfs-dynamic-storage.md
+++ b/docs/k8s-nfs-dynamic-storage.md
@@ -89,14 +89,7 @@
   reclaimPolicy: Delete
 ```
 
-With Helm 2, run the command to install it:
-```
-helm install --name your-ow-release-name --namespace openwhisk \
-  --values ./openwhisk-nfs-client-provisioner.yaml \
-  stable/nfs-client-provisioner
-```
-
-Or if you're using Helm 3:
+Using Helm 3, run this command to install it:
 ```
 helm install your-ow-release-name --namespace openwhisk \
   stable/nfs-client-provisioner \
diff --git a/docs/okd-311.md b/docs/okd-311.md
index b8c9868..c2467a8 100644
--- a/docs/okd-311.md
+++ b/docs/okd-311.md
@@ -73,6 +73,5 @@
 prefixed 'vanity url' rewriting routes and the download of the cli/SDK
 binaries is not currently supported when deploying on OpenShift.
 
-Smoketesting a deployment via `helm test` is not supported because it
-relies on `tiller` (the server side component of Helm) and OpenShift
-forbids the use of the server-side components of Helm.
+Smoketesting a deployment via `helm test` is not supported because
+we did not use `helm install` to deploy the chart.
diff --git a/helm/openwhisk/Chart.yaml b/helm/openwhisk/Chart.yaml
index 8435a3f..7e99922 100644
--- a/helm/openwhisk/Chart.yaml
+++ b/helm/openwhisk/Chart.yaml
@@ -15,16 +15,17 @@
 # limitations under the License.
 #
 
-apiVersion: v1
-description: An open source, distributed serverless platform that executes functions in response to events at any scale
+apiVersion: v2
+type: application
 name: openwhisk
-version: 0.1.11
+version: 0.2.0
+home: https://openwhisk.apache.org
+description: Apache OpenWhisk is an open source serverless cloud platform
 icon: https://raw.githubusercontent.com/apache/openwhisk/682eb5b62ee6ba8017ab54226c2ace3637f4f1ec/docs/images/whisk_icon_full-color_with_tm_64x64-300dpi.png
 keywords:
   - Apache OpenWhisk
   - amd64
 maintainers:
-  - name: Apache OpenWhisk committers
+  - name: Apache OpenWhisk Community
     email: dev@openwhisk.apache.org
-tillerVersion: ">=2.9.0"
 kubeVersion: ">=v1.10.0-r0"
diff --git a/helm/openwhisk/values-metadata.yaml b/helm/openwhisk/values-metadata.yaml
deleted file mode 100644
index 91651d7..0000000
--- a/helm/openwhisk/values-metadata.yaml
+++ /dev/null
@@ -1,1790 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You 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.
-#
-
-
-## Metadata for OpenWhisk configuration
-## This describes values that are defined in values.yaml for Helm chart
-
-## apiHostName configuration metadata
-whisk:
-  __metadata:
-    label: "General OpenWhisk configuration"
-    description: "System-wide configuration parameters for your OpenWhisk deployment"
-  ingress:
-    apiHostName:
-      __metadata:
-        label: "API host name"
-        description: "The external hostname or IP address used to access the Ingress of your Kubernetes cluster"
-        type: "string"
-        required: true
-    apiHostPort:
-      __metadata:
-        label: "API host port"
-        description: "The external port used to access the Ingress of your Kubernetes cluster"
-        type: "string"
-        required: true
-    apiHostProto:
-      __metadata:
-        label: "API host protocol"
-        description: "The protocol to be used to connect to the Ingress of your Kubernetes cluster"
-        type: "string"
-        required: true
-        options:
-        - label: "http"
-          value: "http"
-        - label: "https"
-          value: "https"
-    type:
-      __metadata:
-        label: "Ingress type"
-        description: "The type of Ingress being deployed (NodePort, LoadBalancer, Standard)"
-        type: "string"
-        required: true
-        options:
-        - label: "NodePort"
-          value: "NodePort"
-        - label: "LoadBalancer"
-          value: "LoadBalancer"
-        - label: "Standard"
-          value: "Standard"
-    annotations:
-      __metadata:
-        label: "Ingress Annotations"
-        description: "Annotations to add to Ingress resource. Specify as a list of key: value pairs"
-        type: "string"
-        multiline: true
-        required: false
-    domain:
-      __metadata:
-        label: "Ingress Domain"
-        description: "The Fully Qualified Host Name for the Ingress domain"
-        type: "string"
-        required: true
-    tls:
-      enabled:
-        __metadata:
-          label: "TLS enabled"
-          description: "If TLS is enabled for the Ingress"
-          type: "boolean"
-          required: true
-      secretenabled:
-        __metadata:
-          label: "Secret enabled"
-          description: "If TLS secret is enabled for the Ingress"
-          type: "boolean"
-          required: true
-      createsecret:
-        __metadata:
-          label: "Create secret"
-          description: "If the Ingress TLS secret should be auto-created when chart is deployed"
-          type: "boolean"
-          required: true
-      secretname:
-        __metadata:
-          label: "TLS Secret name"
-          description: "The name of the Ingress TLS secret"
-          type: "string"
-          required: true
-      secrettype:
-        __metadata:
-          label: "TLS Secret type"
-          description: "The type of the Ingress TLS secret"
-          type: "string"
-          required: true
-      crt:
-        __metadata:
-          label: "TLS crt"
-          description: "The TLS certificate for the Ingress"
-          type: "string"
-          required: true
-      key:
-        __metadata:
-          label: "TLS Key"
-          description: "The TLS key for the Ingress"
-          type: "string"
-          required: true
-  auth:
-    system:
-      __metadata:
-        label: "System auth"
-        description: "The auth secret for the system namespace"
-        type: "string"
-        required: true
-    guest:
-      __metadata:
-        label: "Guest auth"
-        description: "The auth secret for the guest namespace"
-        type: "string"
-        required: true
-  systemNameSpace:
-    __metadata:
-      label: "System namespace"
-      description: "The namespace in which to install OpenWhisk system actions and packages"
-      type: "string"
-      required: true
-  limits:
-    actionsInvokesPerminute:
-      __metadata:
-        label: "Maximum actions invoked per minute"
-        description: "The maximum number of action invocations per minute by a single namespace"
-        type: "number"
-        required: true
-    actionsInvokesConcurrent:
-      __metadata:
-        label: "Maximum concurrent action invocations"
-        description: "The maximum number of concurrent action invocations by a single namespace"
-        type: "number"
-        required: true
-    triggersFiresPerminute:
-      __metadata:
-        label: "Maximum triggers fired per minute"
-        description: "The maximum triggers fired per minute for a single namespace"
-        type: "number"
-        required: true
-    actionsSequenceMaxlength:
-      __metadata:
-        label: "Maximum length of action sequence"
-        description: "The maximum length of an action sequence"
-        type: "number"
-        required: true
-    actions:
-      time:
-        min:
-          __metadata:
-            label: "Minimum action time"
-            description: "The minimum billing granularity for action execution time"
-            type: "string"
-            required: true
-        max:
-          __metadata:
-            label: "Maximum action time"
-            description: "The maximum allowed execution time for any action"
-            type: "string"
-            required: true
-        std:
-          __metadata:
-            label: "Standard action time"
-            description: "The default maximum execution time for an action"
-            type: "string"
-            required: true
-      memory:
-        min:
-          __metadata:
-            label: "Minimum action memory"
-            description: "The minimum memory allocation for an action"
-            type: "string"
-            required: true
-        max:
-          __metadata:
-            label: "Maximum action memory"
-            description: "The maximum allowed memory allocation for an action"
-            type: "string"
-            required: true
-        std:
-          __metadata:
-            label: "Standard action memory"
-            description: "The default memory allocation for an action"
-            type: "string"
-            required: true
-      concurrency:
-        min:
-          __metadata:
-            label: "Minimum action concurrency"
-            description: "The minimum number of concurrent requests supported by a single action container"
-            type: "number"
-            required: true
-        max:
-          __metadata:
-            label: "Maximum action concurrency"
-            description: "The maximum number of concurrent requests supported by a single action container"
-            type: "number"
-            required: true
-        std:
-          __metadata:
-            label: "Standard action concurrency"
-            description: "The default number of concurrent requests supported by a single action container"
-            type: "number"
-            required: true
-      log:
-        min:
-          __metadata:
-            label: "Mimimum action log size"
-            description: "The mimimum log size for an action invocation"
-            type: "string"
-            required: true
-        max:
-          __metadata:
-            label: "Maximum action log size"
-            description: "The maximum allowed log size for an action invocation"
-            type: "string"
-            required: true
-        std:
-          __metadata:
-            label: "Standard action log size"
-            description: "The default allowed log size for an action invocation"
-            type: "string"
-            required: true
-    activation:
-      payload:
-        max:
-          __metadata:
-            label: "Maximum activation payload"
-            description: "The maximum size of an activation payload"
-            type: "string"
-            required: true
-  loadbalancer:
-    blackboxFraction:
-      __metadata:
-        label: "Loadbalancer blackbox fraction"
-        description: "The fraction of invokers reserved to execute blackbox actions"
-        type: "string"
-        required: true
-    timeoutFactor:
-      __metadata:
-        label: "Loadbalancer timeout factor"
-        description: "The loadbalancer's timeout factor"
-        type: "number"
-        required: true
-  kafka:
-    replicationFactor:
-      __metadata:
-        label: "Kafka topic replication factor"
-        description: "The replication factor for all Kafka topics"
-        type: "string"
-        required: false
-    topics:
-      cacheInvalidation:
-        segmentBytes:
-          __metadata:
-            label: "cacheInvalidation segment bytes"
-            description: "Kafka topic configuration: the cacheInvalidation topic's segment bytes"
-            type: "string"
-            required: false
-        retentionBytes:
-          __metadata:
-            label: "cacheInvalidation retention bytes"
-            description: "Kafka topic configuration: the cacheInvalidation topic's retention bytes"
-            type: "string"
-            required: false
-        retentionMs:
-          __metadata:
-            label: "cacheInvalidation retention ms"
-            description: "Kafka topic configuration: the cacheInvalidation topic's retention ms"
-            type: "string"
-            required: false
-      completed:
-        segmentBytes:
-          __metadata:
-            label: "completed segment bytes"
-            description: "Kafka topic configuration: the completed topic's segment bytes"
-            type: "string"
-            required: false
-        retentionBytes:
-          __metadata:
-            label: "completed retention bytes"
-            description: "Kafka topic configuration: the completed topic's retention bytes"
-            type: "string"
-            required: false
-        retentionMs:
-          __metadata:
-            label: "completed retention ms"
-            description: "Kafka topic configuration: the completed topic's retention ms"
-            type: "string"
-            required: false
-      events:
-        segmentBytes:
-          __metadata:
-            label: "events segment bytes"
-            description: "Kafka topic configuration: the events topic's segment bytes"
-            type: "string"
-            required: false
-        retentionBytes:
-          __metadata:
-            label: "events retention bytes"
-            description: "Kafka topic configuration: the events topic's retention bytes"
-            type: "string"
-            required: false
-        retentionMs:
-          __metadata:
-            label: "events retention ms"
-            description: "Kafka topic configuration: the events topic's retention ms"
-            type: "string"
-            required: false
-      health:
-        segmentBytes:
-          __metadata:
-            label: "health segment bytes"
-            description: "Kafka topic configuration: the health topic's segment bytes"
-            type: "string"
-            required: false
-        retentionBytes:
-          __metadata:
-            label: "health retention bytes"
-            description: "Kafka topic configuration: the health topic's retention bytes"
-            type: "string"
-            required: false
-        retentionMs:
-          __metadata:
-            label: "health retention ms"
-            description: "Kafka topic configuration: the health topic's retention ms"
-            type: "string"
-            required: false
-      invoker:
-        segmentBytes:
-          __metadata:
-            label: "invoker segment bytes"
-            description: "Kafka topic configuration: the invoker-N topic's segment bytes"
-            type: "string"
-            required: false
-        retentionBytes:
-          __metadata:
-            label: "invoker retention bytes"
-            description: "Kafka topic configuration: the invoker-N topic's retention bytes"
-            type: "string"
-            required: false
-        retentionMs:
-          __metadata:
-            label: "invoker retention ms"
-            description: "Kafka topic configuration: the invoker-N topic's retention ms"
-            type: "string"
-            required: false
-  containerPool:
-    userMemory:
-      __metadata:
-        label: "Comtainerpool user memory"
-        description: "The total memory available to a single Invoker for executing user actions"
-        type: "string"
-        required: true
-  runtimes:
-    __metadata:
-      label: "Runtimes"
-      description: "The JSON file containing the runtimes manifest for this deployment"
-      type: "string"
-      required: true
-  testing:
-    includeTests:
-      __metadata:
-        label: "Include basic tests"
-        description: "If basic tests should be included in the Helm test suite"
-        type: "boolean"
-        required: true
-    includeSystemTests:
-      __metadata:
-        label: "Include system tests"
-        description: "If systems tests should be included in the Helm test suite"
-        type: "boolean"
-        required: true
-  versions:
-    openwhisk:
-      buildDate:
-        __metadata:
-          label: "OpenWhisk build date"
-          description: "The OpenWhisk build date"
-          type: "string"
-          required: true
-      buildNo:
-        __metadata:
-          label: "OpenWhisk build number"
-          description: "The OpenWhisk build number"
-          type: "string"
-          required: true
-      gitTag:
-        __metadata:
-          label: "OpenWhisk git tag"
-          description: "The git tag for openwhisk"
-          type: "string"
-          required: true
-    openwhiskCli:
-      tag:
-        __metadata:
-          label: "CLI tag"
-          description: "The git tag for openwhisk-cli"
-          type: "string"
-          required: true
-    openwhiskCatalog:
-      gitTag:
-        __metadata:
-          label: "Catalog git tag"
-          description: "The git tag for openwhisk-catalog"
-          type: "string"
-          required: true
-    openwhiskPackageAlarms:
-      gitTag:
-        __metadata:
-          label: "Alarms git tag"
-          description: "The git tag for openwhisk-package-alarms"
-          type: "string"
-          required: true
-    openwhiskPackageCloudant:
-      gitTag:
-        __metadata:
-          label: "Cloudant git tag"
-          description: "The git tag for openwhisk-package-cloudant"
-          type: "string"
-          required: true
-    openwhiskPackageKafka:
-      gitTag:
-        __metadata:
-          label: "Kafka git tag"
-          description: "The git tag for openwhisk-package-kafka"
-          type: "string"
-          required: true
-
-k8s:
-  __metadata:
-    label: "Kubernetes configuration"
-    description: "Configuration values to describe your Kubernetes cluster"
-  domain:
-    __metadata:
-      label: "Domain"
-      description: "The DNS suffix for services in your cluster (eg. \"cluster.local\")"
-      type: "string"
-      required: true
-  dns:
-    __metadata:
-      label: "Kubernetes DNS service"
-      description: "The name of your cluster's DNS service"
-      type: "string"
-      required: true
-  persistence:
-    enabled:
-      __metadata:
-        label: "Persistence enabled"
-        description: "If persistence should be enabled"
-        type: "boolean"
-        required: true
-    hasDefaultStorageClass:
-      __metadata:
-        label: "Has default storage class"
-        description: "If your cluster has a default storage class configured"
-        type: "boolean"
-        required: true
-    explicitStorageClass:
-      __metadata:
-        label: "Explicit storage class"
-        description: "The name of the StorageClass to use if not using the default StorageClass"
-        type: "string"
-        required: false
-
-utility:
-  __metadata:
-    label: "Utility configuration"
-    description: "Update these default values to configure utility images"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The name of the OpenWhisk utility image"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The tag of the OpenWhisk utility image"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-
-docker:
-  __metadata:
-    label: "Docker Registry configuration"
-    description: "Change these default values to configure the Docker Registry"
-  registry:
-    name:
-      __metadata:
-        label: "Docker Registry name"
-        description: "The Docker Registry name"
-        type: "string"
-        required: false
-    username:
-      __metadata:
-        label: "Docker Registry username"
-        description: "The username for the Docker Registry"
-        type: "string"
-        required: false
-    password:
-      __metadata:
-        label: "Docker Registry password"
-        description: "The password for the Docker Registry"
-        type: "password"
-        required: false
-  timezone:
-    __metadata:
-      label: "Timezone"
-      description: "The timezone to use when performing Docker operations"
-      type: "string"
-      required: false
-
-zookeeper:
-  __metadata:
-    label: "Zookeeper configuration"
-    description: "Update these default values to customize the Zookeeper deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "Number of zookeeper instances to deploy; must be an odd number."
-      type: "number"
-      required: true
-      options:
-      - label: "1"
-        value: "1"
-      - label: "3"
-        value: "3"
-      - label: "5"
-        value: "5"
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for zookeeper pods"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "Port"
-      description: "The primary zookeeper port"
-      type: "string"
-      required: true
-  serverPort:
-    __metadata:
-      label: "Server port"
-      description: "The zookeeper server port"
-      type: "string"
-      required: true
-  leaderElectionPort:
-    __metadata:
-      label: "Leader election port"
-      description: "The zookeeper leader election port"
-      type: "string"
-      required: true
-  persistence:
-    size:
-      __metadata:
-        label: "Size"
-        description: "The persistent volume size"
-        type: "string"
-        required: true
-  config:
-    tickTime:
-      __metadata:
-        label: "Tick time"
-        description: "Zookeeper configuration: Tick time"
-        type: "number"
-        required: true
-    initLimit:
-      __metadata:
-        label: "Init limit"
-        description: "Zookeeper configuration: Init limit"
-        type: "number"
-        required: true
-    syncLimit:
-      __metadata:
-        label: "Sync limit"
-        description: "Zookeeper configuration: Sync limit"
-        type: "number"
-        required: true
-    dataDir:
-      __metadata:
-        label: "Data directory"
-        description: "Zookeeper configuration: Data directory"
-        type: "string"
-        required: true
-    dataLogDir:
-      __metadata:
-        label: "Data log directory"
-        description: "Zookeeper configuration: Data log directory"
-        type: "string"
-        required: true
-
-kafka:
-  __metadata:
-    label: "Kafka configuration"
-    description: "Update these default values to customize the Kafka deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "Number of Kafka instances to deploy. Currently must be 1"
-      type: "number"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for Kafka pods"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "Port"
-      description: "The primary kafka port"
-      type: "string"
-      required: true
-  persistence:
-    size:
-      __metadata:
-        label: "Size"
-        description: "The size of the Kafka persistent volume"
-        type: "string"
-        required: true
-
-db:
-  __metadata:
-    label: "Database configuration"
-    description: "Update these default values to customize the CouchDB deployment"
-  external:
-    __metadata:
-      label: "External"
-      description: "If using an externally deployed CouchDB"
-      type: "boolean"
-      required: true
-  wipeAndInit:
-    __metadata:
-      label: "wipe and initialise"
-      description: "If the database should be wiped and initialised when OpenWhisk is deployed"
-      type: "boolean"
-      required: true
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "Number of database instances to deploy. Currently must be 1"
-      type: "number"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for database pods"
-      type: "string"
-      required: true
-  host:
-    __metadata:
-      label: "Host"
-      description: "If using an external database, the hostname or IP address to use to connect to the database"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "Port"
-      description: "If using an external database, the port to use to connect to the database"
-      type: "string"
-      required: true
-  provider:
-    __metadata:
-      label: "Provider"
-      description: "If using an external database, whether it is Cloudant or CouchDB"
-      type: "string"
-      required: true
-      options:
-      - label: "CouchDB"
-        value: "CouchDB"
-      - label: "Cloudant"
-        value: "Cloudant"
-  protocol:
-    __metadata:
-      label: "Protocol"
-      description: "If using an external database, the protocol to use to connect to the database"
-      type: "string"
-      required: true
-      options:
-      - label: "http"
-        value: "http"
-      - label: "https"
-        value: "https"
-  auth:
-    username:
-      __metadata:
-        label: "Username"
-        description: "The username to use when connecting to the database"
-        type: "string"
-        required: true
-    password:
-      __metadata:
-        label: "Password"
-        description: "The password to use when connecting to the database"
-        type: "password"
-        required: true
-  dbPrefix:
-    __metadata:
-      label: "Prefix"
-      description: "The prefix to use when creating database resources"
-      type: "string"
-      required: true
-  activationsTable:
-    __metadata:
-      label: "Activations table"
-      description: "The name of the activations table"
-      type: "string"
-      required: true
-  actionsTable:
-    __metadata:
-      label: "Actions table"
-      description: "The name of the actions table"
-      type: "string"
-      required: true
-  authsTable:
-    __metadata:
-      label: "Auths table"
-      description: "The name of the auths table"
-      type: "string"
-      required: true
-  persistence:
-    size:
-      __metadata:
-        label: "Size"
-        description: "The size of the persistent volume for CouchDB"
-        type: "string"
-        required: true
-
-nginx:
-  __metadata:
-    label: "NGINX Configuration"
-    description: "Update these default values to customize the NGINX deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "The number of nginx instances to deploy"
-      type: "string"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for nginx pods"
-      type: "string"
-      required: true
-  httpPort:
-    __metadata:
-      label: "HTTP port"
-      description: "The port to use for HTTP connections"
-      type: "string"
-      required: true
-  httpsPort:
-    __metadata:
-      label: "HTTPS port"
-      description: "The port to use for HTTPS connections"
-      type: "string"
-      required: true
-  httpsNodePort:
-    __metadata:
-      label: "HTTPS node port"
-      description: "The port for HTTPS connections when using a NodePort Ingress"
-      type: "string"
-      required: true
-
-controller:
-  __metadata:
-    label: "Controller configuration"
-    description: "Update these default values to customize the OpenWhisk Controller deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "The number of controller instances to deploy"
-      type: "number"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for controller pods"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "Port"
-      description: "The primary port for the controller service"
-      type: "string"
-      required: true
-  options:
-    __metadata:
-      label: "Options"
-      description: "Additional controller command line options"
-      type: "string"
-      required: false
-  jvmHeapMB:
-    __metadata:
-      label: "JVM heap memory (MB)"
-      description: "The maximum Java heap size in megabytes (MB)"
-      type: "string"
-      required: true
-  jvmOptions:
-    __metadata:
-      label: "JVM options"
-      description: "Additional JVM command line options"
-      type: "string"
-      required: false
-
-
-invoker:
-  __metadata:
-    label: "Invoker Configuration"
-    description: "Update these default values to customize the OpenWhisk Invoker deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "Docker image name for the Invoker"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag for the Invoker"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for invoker pods"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "Port"
-      description: "The primary invoker port"
-      type: "string"
-      required: true
-  options:
-    __metadata:
-      label: "Additional options"
-      description: "Additional command line options to give to the invoker"
-      type: "string"
-      required: false
-  jvmHeapMB:
-    __metadata:
-      label: "JVM heap memory (MB)"
-      description: "the maximum Java heap size in megabytes (MB)"
-      type: "string"
-      required: true
-  jvmOptions:
-    __metadata:
-      label: "JVM options"
-      description: "Additional JVM command line options"
-      type: "string"
-      required: false
-  containerFactory:
-    useRunc:
-      __metadata:
-        label: "useRunc"
-        description: "Should the invoker use runc to pause/unpause idle action containers"
-        type: "boolean"
-        required: true
-    impl:
-      __metadata:
-        label: "impl"
-        description: "Which ContainerFactory shoUld be used"
-        type: "string"
-        required: true
-        options:
-        - label: "docker"
-          value: "docker"
-        - label: "kubernetes"
-          value: "kubernetes"
-    enableConcurrency:
-      __metadata:
-        label: "Enable concurrency"
-        description: "Should the invoker pass `__OW_ALLOW_CONCURRENT=true` to action containers, enabling concurrent execution in supporting runtimes"
-        type: "boolean"
-        required: true
-    networkConfig:
-      name:
-        __metadata:
-          label: "Container Network Name"
-          description: "Name of the Docker network to be used by user action containers"
-          type: "string"
-          required: false
-      dns:
-        inheritInvokerConfig:
-          __metadata:
-            label: "Inherit Invoker DNS Configuration"
-            description: "Should the user action containers use the same DNS configuration as the Invoker's container?"
-            type: "boolean"
-            required: false
-        overrides:
-          nameservers:
-            __metadata:
-              label: "DNS nameservers"
-              description: "A list of IP addresses of DNS nameserver(s) to be used by user action containers"
-              type: "string"
-              required: false
-          search:
-            __metadata:
-              label: "DNS search domains"
-              description: "A list of DNS search domains to be used by user action containers"
-              type: "string"
-              required: false
-          options:
-            __metadata:
-              label: "options"
-              description: "A list of DNS options to be used by user action containers"
-              type: "string"
-          required: false
-    kubernetes:
-      replicaCount:
-        __metadata:
-          label: "ContainerFactory replica count"
-          description: "How many instances of the KubernetesContainerFactory should be deployed?"
-          type: "number"
-          required: true
-
-apigw:
-  __metadata:
-    label: "API gateway configuration"
-    description: "Update these default values to customize the API Gateway deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "Number of apigw instances to deploy"
-      type: "string"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for apigw pods"
-      type: "string"
-      required: true
-  apiPort:
-    __metadata:
-      label: "API port"
-      description: "The API port"
-      type: "string"
-      required: true
-  mgmtPort:
-    __metadata:
-      label: "Management port"
-      description: "The management port"
-      type: "string"
-      required: true
-
-redis:
-  __metadata:
-    label: "Redis configuration"
-    description: "Update these default values to customize the Redis deployment"
-  external:
-    __metadata:
-      label: "External"
-      description: "If using an externally deployed Redis"
-      type: "boolean"
-      required: true
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "The number of redis instances to deploy (currently must be 1)"
-      type: "string"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for redis pods"
-      type: "string"
-      required: true
-  host:
-    __metadata:
-      label: "Host"
-      description: "If using an external Redis, the hostname or IP address to use to connect to the Redis"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "Port"
-      description: "The primary service port"
-      type: "string"
-      required: true
-  persistence:
-    size:
-      __metadata:
-        label: "Size"
-        description: "The size of the persistent volume for redis"
-        type: "string"
-        required: true
-
-user-events:
-  __metadata:
-    label: "User-events Configuration"
-    description: "Update these default values to customize the User-events deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "The number of user-events instances to deploy"
-      type: "string"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for user-events pods"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "HTTP port"
-      description: "The port to use for HTTP connections"
-      type: "string"
-      required: true
-
-prometheus:
-  __metadata:
-    label: "Prometheus Configuration"
-    description: "Update these default values to customize the prometheus deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "The number of prometheus instances to deploy"
-      type: "string"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for prometheus pods"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "HTTP port"
-      description: "The port to use for HTTP connections"
-      type: "string"
-      required: true
-    persistence:
-      size:
-        __metadata:
-          label: "Prometheus persistence size"
-          description: "The size of the persistent volume for Prometheus"
-          type: "string"
-          required: true
-
-grafana:
-  __metadata:
-    label: "User-events Configuration"
-    description: "Update these default values to customize the User-events deployment"
-  imageName:
-    __metadata:
-      label: "Image name"
-      description: "The docker image name"
-      type: "string"
-      required: true
-  imageTag:
-    __metadata:
-      label: "Image tag"
-      description: "The docker image tag"
-      type: "string"
-      required: true
-  imagePullPolicy:
-    __metadata:
-      label: "Image pull policy"
-      description: "The image pull policy to apply for this image."
-      type: "string"
-      required: true
-      options:
-      - label: "Always"
-        value: "Always"
-      - label: "Never"
-        value: "Never"
-      - label: "IfNotPresent"
-        value: "IfNotPresent"
-  replicaCount:
-    __metadata:
-      label: "Replica count"
-      description: "The number of user-events instances to deploy"
-      type: "string"
-      required: true
-  restartPolicy:
-    __metadata:
-      label: "Restart policy"
-      description: "The restart policy for user-events pods"
-      type: "string"
-      required: true
-  port:
-    __metadata:
-      label: "HTTP port"
-      description: "The port to use for HTTP connections"
-      type: "string"
-      required: true
-  adminPassword:
-    __metadata:
-      label: "Grafana user admin password"
-      description: "The password used for logging in as an admin user in Grafana"
-      type: "string"
-      required: true
-  dashboards:
-    __metadata:
-      label: "List of dashboards Grafana dashboards"
-      description: "List of dashboards that should be configured in Grafana on container init"
-      type: "string"
-      required: true
-
-providers:
-  __metadata:
-    label: "OpenWhisk providers configuration"
-    description: "Update these default values to customize OpenWhisk providers (Alarm, Cloudant and Kafka)"
-  db:
-    external:
-      __metadata:
-        label: "External Providers Database"
-        description: "If the event providers database is external"
-        type: "boolean"
-        required: true
-    host:
-      __metadata:
-        label: "Database host"
-        description: "The external event providers database host"
-        type: "string"
-        required: true
-    port:
-      __metadata:
-        label: "Database port"
-        description: "The external event providers database port"
-        type: "string"
-        required: true
-    protocol:
-      __metadata:
-        label: "Database protocol"
-        description: "The external event providers database protocol"
-        type: "string"
-        required: true
-        options:
-        - label: "http"
-          value: "http"
-        - label: "https"
-          value: "https"
-    username:
-      __metadata:
-        label: "Database username"
-        description: "The external event providers database username"
-        type: "string"
-        required: true
-    password:
-      __metadata:
-        label: "Database password"
-        description: "The external event providers database password"
-        type: "password"
-        required: true
-
-  alarm:
-    enabled:
-      __metadata:
-        label: "Alarm enabled"
-        description: "If alarm provider should be enabled"
-        type: "boolean"
-        required: true
-    imageName:
-      __metadata:
-        label: "Alarm image name"
-        description: "The alarm docker image name"
-        type: "string"
-        required: true
-    imageTag:
-      __metadata:
-        label: "Alarm image tag"
-        description: "The alarm docker image tag"
-        type: "string"
-        required: true
-    imagePullPolicy:
-      __metadata:
-        label: "Image pull policy"
-        description: "The image pull policy to apply for this image."
-        type: "string"
-        required: true
-        options:
-        - label: "Always"
-          value: "Always"
-        - label: "Never"
-          value: "Never"
-        - label: "IfNotPresent"
-          value: "IfNotPresent"
-    replicaCount:
-      __metadata:
-        label: "Alarm replica count"
-        description: "The number of alarm provider instances to deploy"
-        type: "string"
-        required: true
-    restartPolicy:
-      __metadata:
-        label: "Alarm restart policy"
-        description: "The restart policy for Alarm provider pods"
-        type: "string"
-        required: true
-    apiPort:
-      __metadata:
-        label: "Alarm API port"
-        description: "The API port for the Alarm provider"
-        type: "string"
-        required: true
-    dbPrefix:
-      __metadata:
-        label: "Alarm DB prefix"
-        description: "The prefix for the Alarm provider's database tables"
-        type: "string"
-        required: true
-    persistence:
-      size:
-        __metadata:
-          label: "Alarm persistence size"
-          description: "The size of the persistent volume for the Alarm provider"
-          type: "string"
-          required: true
-
-  cloudant:
-    enabled:
-      __metadata:
-        label: "Cloudant enabled"
-        description: "if Cloudant provider should be enabled"
-        type: "boolean"
-        required: true
-    imageName:
-      __metadata:
-        label: "Cloudant image name"
-        description: "The Cloudant provider docker image name"
-        type: "string"
-        required: true
-    imageTag:
-      __metadata:
-        label: "Cloudant image tag"
-        description: "The Cloudant provider docker image tag"
-        type: "string"
-        required: true
-    imagePullPolicy:
-      __metadata:
-        label: "Image pull policy"
-        description: "The image pull policy to apply for this image."
-        type: "string"
-        required: true
-        options:
-        - label: "Always"
-          value: "Always"
-        - label: "Never"
-          value: "Never"
-        - label: "IfNotPresent"
-          value: "IfNotPresent"
-    replicaCount:
-      __metadata:
-        label: "Cloudant replica count"
-        description: "The number of Cloudant provider instances to deploy"
-        type: "string"
-        required: true
-    restartPolicy:
-      __metadata:
-        label: "Cloudant restart policy"
-        description: "The restart policy for Cloudant provider pods"
-        type: "string"
-        required: true
-    apiPort:
-      __metadata:
-        label: "Cloudant API port"
-        description: "The API port for the Cloudant provider"
-        type: "string"
-        required: true
-    dbPrefix:
-      __metadata:
-        label: "Cloudant DB prefix"
-        description: "The prefix to use for Cloudant provider database tables"
-        type: "string"
-        required: true
-    persistence:
-      size:
-        __metadata:
-          label: "Cloudant persistence size"
-          description: "The size of the persistent volume for the Cloudant provider"
-          type: "string"
-          required: true
-
-  kafka:
-    enabled:
-      __metadata:
-        label: "Kafka enabled"
-        description: "If the Kafka provider should be enabled"
-        type: "boolean"
-        required: true
-    imageName:
-      __metadata:
-        label: "Kafka image name"
-        description: "The docker image name for the Kakfa provider"
-        type: "string"
-        required: true
-    imageTag:
-      __metadata:
-        label: "Kafka image tag"
-        description: "The docker image tag for the Kafka provider"
-        type: "string"
-        required: true
-    imagePullPolicy:
-      __metadata:
-        label: "Image pull policy"
-        description: "The image pull policy to apply for this image."
-        type: "string"
-        required: true
-        options:
-        - label: "Always"
-          value: "Always"
-        - label: "Never"
-          value: "Never"
-        - label: "IfNotPresent"
-          value: "IfNotPresent"
-    replicaCount:
-      __metadata:
-        label: "Kafka replica count"
-        description: "The number of instances of the Kafka provider to deploy"
-        type: "string"
-        required: true
-    restartPolicy:
-      __metadata:
-        label: "Kafka restart policy"
-        description: "The restart policy for Kafka provider pods"
-        type: "string"
-        required: true
-    apiPort:
-      __metadata:
-        label: "Kafka API port"
-        description: "The API port for the Kafka provider"
-        type: "string"
-        required: true
-    dbPrefix:
-      __metadata:
-        label: "Kafka DB prefix"
-        description: "The prefix to use for the Kafka provider's database tables"
-        type: "string"
-        required: true
-
-affinity:
-  __metadata:
-    label: "Node affinity configuration"
-    description: "Labels used to tag Kubernetes worker nodes to enable scheduling affinity"
-  enabled:
-    __metadata:
-      label: "Affinity enabled"
-      description: "If affinity should be enabled"
-      type: "boolean"
-      required: true
-  coreNodeLabel:
-    __metadata:
-      label: "Core node label"
-      description: "Label used for worker nodes that should execute OpenWhisk core pods"
-      type: "string"
-      required: true
-  edgeNodeLabel:
-    __metadata:
-      label: "Edge node label"
-      description: "Label used for worker nodes that should execute OpenWhisk Ingress pods"
-      type: "string"
-      required: true
-  invokerNodeLabel:
-    __metadata:
-      label: "Invoker node label"
-      description: "Label used for worker nodes that should execute OpenWhisk Invoker pods and user actions"
-      type: "string"
-      required: true
-  providerNodeLabel:
-    __metadata:
-      label: "Provider node label"
-      description: "Label used for worker nodes that should execute OpenWhisk event provider pods"
-      type: "string"
-      required: true
-
-toleration:
-  __metadata:
-    label: "Node toleration configuration"
-    description: "Key used for node tolerations"
-  enabled:
-    __metadata:
-      label: "Toleration enabled"
-      description: "If toleration should be enabled"
-      type: "boolean"
-      required: true
-  coreValue:
-    __metadata:
-      label: "Core openwhisk-role toleration value"
-      description: "Value used for worker nodes toleration that should execute OpenWhisk core pods"
-      type: "string"
-      required: true
-  edgeValue:
-    __metadata:
-      label: "Edge openwhisk-role toleration value"
-      description: "Value used for worker nodes toleration that should execute OpenWhisk edge pods"
-      type: "string"
-      required: true
-  invokerValue:
-    __metadata:
-      label: "Invoker openwhisk-role toleration value"
-      description: "Value used for worker nodes toleration that should execute OpenWhisk invoker pods"
-      type: "string"
-      required: true
-
-probes:
-  _metadata:
-  label: "Pod's Probes Settings"
-  description: "Used for configurable liveness and readiness probes timing settings"
-  controller:
-    initialDelaySeconds:
-      _metadata:
-      label: "Initial wait time to start probes after container has started"
-      description: "Time in seconds to wait before starting the probes on pod in started state."
-      type: "number"
-      required: false
-    periodSeconds:
-      _metadata:
-      label: "Frequency to perform the probe in seconds"
-      description: "Frequency to perform the probe, default is 10, minimun is 1"
-      type: "number"
-      required: false
-    timeoutSeconds:
-      _metadata:
-      label: "Probe timeout in seconds"
-      description: "Probe will timeouts after defined seconds, defaults to 1 second, minimum value is 1"
-      type: "number"
-      required: false
-  zookeeper:
-    initialDelaySeconds:
-      _metadata:
-      label: "Initial wait time to start probes after container has started"
-      description: "Time in seconds to wait before starting the probes on pod in started state."
-      type: "number"
-      required: false
-    periodSeconds:
-      _metadata:
-      label: "Frequency to perform the probe in seconds"
-      description: "Frequency to perform the probe, default is 10, minimun is 1"
-      type: "number"
-      required: false
-    timeoutSeconds:
-      _metadata:
-      label: "Probe timeout in seconds"
-      description: "Probe will timeouts after defined seconds, defaults to 1 second, minimum value is 1"
-      type: "number"
-      required: false
-
-# Metrics
-metrics:
-  __metadata:
-    label: "Metrics configuration"
-    description: "configurations to enable and configure Kamon metrics from controller and invoker."
-  prometheusEnabled:
-    __metadata:
-      label: "enable Prometheus support"
-      description: "true to enable kamon-prometheus exporter, metrics would be exposed at `/metrics` endpoint"
-      type: "boolean"
-      required: true
-  whiskconfigFile:
-    __metadata:
-      label: "whiskconfig file name"
-      description: "file name of whiskconfig"
-      type: "string"
-      required: false
-  kamonEnabled:
-    __metadata:
-      label: "enable kamon metrics collection"
-      description: "whether metric information is sent to the configured reporters"
-      type: "boolean"
-      required: true
-  kamonTags:
-    __metadata:
-      label: "enable kamon tag"
-      description: "whether to use the Kamon tags when sending metrics"
-      type: "boolean"
-      required: true
-  userMetricsEnabled:
-    __metadata:
-      label: "enable user metrics"
-      description: "true to enable user metrics"
-      type: "boolean"
-      required: true
-pdb:
-  _metadata:
-  label: "Pod's Disruption Budget"
-  description: "Pod Disruption Budget settings for voluntary and nonvoluntary disruptions"
-  enable:
-    _metadata:
-      label: "Enable PDB"
-      description: "true to enable pod disruption budgets for pods"
-      type: "boolean"
-      required: false
-  zookeeper:
-    _metadata:
-      label: "Zookeeper"
-    maxUnavailable:
-      _metadata:
-      label: "Max Unavailable"
-      description: "Number of pods from replica set that can be unavailable after the eviction. Should be an absolute number and less than replicaCount value"
-      type: "number"
-      required: false
-  kafka:
-    _metadata:
-    label: "Kafka"
-    maxUnavailable:
-      _metadata:
-      label: "Max Unavailable"
-      description: "Number of pods from replica set that can be unavailable after the eviction. Should be an absolute number and less than replicaCount value"
-      type: "number"
-      required: false
-  controller:
-    _metadata:
-    label: "Controllers"
-    maxUnavailable:
-      _metadata:
-      label: "Max Unavailable"
-      description: "Number of pods from replica set that can be unavailable after the eviction. Should be an absolute number and less than replicaCount value"
-      type: "number"
-      required: false
-  invoker:
-    _metadata:
-    label: "Invokers"
-    maxUnavailable:
-      _metadata:
-      label: "Max Unavailable"
-      description: "Number of pods from replica set that can be unavailable after the eviction. Should be an absolute number and less than replicaCount value"
-      type: "number"
-      required: false
-
diff --git a/helm/openwhisk/values.schema.json b/helm/openwhisk/values.schema.json
new file mode 100644
index 0000000..d1c4639
--- /dev/null
+++ b/helm/openwhisk/values.schema.json
@@ -0,0 +1,524 @@
+{
+  "$schema": "https://json-schema.org/draft-07/schema#",
+
+  "definitions": {
+    "podspec": {
+      "type": "object",
+      "properties": {
+        "imageName":       { "type": "string" },
+        "imageTag":        { "type": "string" },
+        "imagePullPolicy": { "type": "string", "enum": ["Always", "Never", "IfNotPresent"] },
+        "replicaCount":    { "type": "integer", "minimum": 1 },
+        "restartPolicy":   { "type": "string" }
+      },
+      "required": ["imageName", "imageTag", "imagePullPolicy", "replicaCount", "restartPolicy"]
+    },
+
+    "daemonset": {
+      "type": "object",
+      "properties": {
+        "imageName":       { "type": "string" },
+        "imageTag":        { "type": "string" },
+        "imagePullPolicy": { "type": "string", "enum": ["Always", "Never", "IfNotPresent"] },
+        "restartPolicy":   { "type": "string" }
+      },
+      "required": ["imageName", "imageTag", "imagePullPolicy", "restartPolicy"]
+    },
+
+    "pvSizeValid": {
+      "$comment": "intended to validate the *.persistence.size portion of a podspec",
+      "type": "object",
+      "properties": {
+        "persistence": {
+          "type": "object",
+          "properties": {
+            "size": { "type": "string" }
+          },
+          "required": [ "size" ]
+        }
+      }
+    },
+
+    "probespec": {
+      "$comment": "configuration of liveness or readiness probe",
+      "properties": {
+        "initialDelaySeconds": { "type": "integer", "minimum": 0 },
+        "periodSeconds": { "type": "integer", "minimum": 0 },
+        "timeoutSeconds": { "type": "integer", "minimum": 0 }
+      },
+      "required": ["initialDelaySeconds", "periodSeconds", "timeoutSeconds"]
+    },
+
+    "standardPodProbes": {
+      "type": "object",
+      "properties": {
+        "livenessProbe": { "$ref": "#/definitions/probespec" },
+        "readinessProbe": { "$ref": "#/definitions/probespec" }
+      },
+      "required": ["livenessProbe", "readinessProbe"]
+    },
+
+    "optionalExternalHostCheck": {
+      "$comment": "external being true implies host is non-null string",
+      "properties": { "external": { "type": "boolean" } },
+      "required": ["external"],
+      "if": { "properties": { "external": { "const": true } } },
+      "then": { "properties": { "host": { "type": "string" } }, "required": ["host"] }
+    },
+
+    "actionLimitSpecString": {
+      "type": "object",
+      "properties": {
+        "min": { "type": "string" },
+        "max": { "type": "string" },
+        "std": { "type": "string" }
+      },
+      "required": ["min", "max", "std" ]
+    },
+
+    "actionLimitSpecInteger": {
+      "type": "object",
+      "properties": {
+        "min": { "type": "number" },
+        "max": { "type": "number" },
+        "std": { "type": "number" }
+      },
+      "required": ["min", "max", "std" ]
+    },
+
+    "kafkaTopicConfig": {
+      "type": "object",
+      "properties": {
+        "segmentBytes": { "type": "string" },
+        "retentionBytes": { "type": "string" },
+        "retentionMs": { "type": "string" }
+      },
+      "required": ["segmentBytes", "retentionBytes", "retentionMs" ]
+    }
+
+  },
+
+  "type": "object",
+  "name": "Values",
+  "properties": {
+    "whisk": {
+      "type": "object",
+      "properties": {
+        "ingress": {
+          "description": "Specification of the Ingress used to expose OpenWhisk outside your Kubernetes cluster",
+          "type": "object",
+          "properties": {
+            "apiHostName": { "type": "string", "description": "The external hostname or IP address used to access the Ingress of your Kubernetes cluster" },
+            "apiHostPort": { "type": "integer", "minimum": 0, "description": "The external port used to access the Ingress of your Kubernetes cluster" },
+            "apiHostProto": { "type": "string", "enum": ["http", "https"], "description": "The protocol to be used to connect to the Ingress of your Kubernetes cluster" },
+            "type": { "type": "string", "enum": ["NodePort", "Standard", "LoadBalancer", "OpenShift"], "description": "The type of Ingress being deployed" },
+            "annotations": { "type": "object", "description": "Annotations to add to Ingress resource. Specify as a list of key: value pairs" },
+            "domain": { "type": "string", "description": "The Fully Qualified Host Name for the Ingress domain" },
+            "tls": {
+              "type": "object",
+              "properties": {
+                "enabled": { "type": "boolean" },
+                "secretenabled": { "type": "boolean" },
+                "createsecret": { "type": "boolean" },
+                "secrettype": { "type": "string" },
+                "crt": { "type": "string" },
+                "key": { "type": "string" }
+              }
+            }
+          },
+          "required": ["apiHostName", "apiHostPort", "apiHostProto", "type"]
+        },
+        "auth": {
+          "type": "object",
+          "properties": {
+            "system": { "type": "string" },
+            "guest": { "type": "string" }
+          }
+        },
+        "systemNameSpace": { "type": "string" },
+        "limits": {
+          "type": "object",
+          "properties": {
+            "actionsInvokesPerminute": { "type": "number", "minimum": 0, "descrption": "The maximum number of action invocations per minute by a single namespace" },
+            "actionsInvokesConcurrent": { "type": "number", "minimum": 0, "descrption":  "The maximum number of concurrent action invocations by a single namespace" },
+            "triggersFiresPerminute": { "type": "number", "minimum": 0, "description": "The maximum triggers fired per minute for a single namespace" },
+            "actionsSequenceMaxLength": { "type": "number", "minimum": 0, "description": "The maximum length of an action sequence" },
+            "actions": {
+              "type": "object",
+              "properties": {
+                "time": { "$ref": "#/definitions/actionLimitSpecString" },
+                "memory": { "$ref": "#/definitions/actionLimitSpecString" },
+                "concurrency": { "$ref": "#/definitions/actionLimitSpecInteger" },
+                "log": { "$ref": "#/definitions/actionLimitSpecString" },
+                "time": { "$ref": "#/definitions/actionLimitSpecString" }
+              }
+            },
+            "activation": {
+              "type": "object",
+              "properties": {
+                "payload": {
+                  "type": "object",
+                  "properties": {
+                    "max": { "type": "string" }
+                  }
+                }
+              }
+            }
+          }
+        },
+        "loadbalancer": {
+          "type": "object",
+          "properties": {
+            "blackboxFraction": { "type": "string" },
+            "timeoutFactor": { "type": "number" }
+          }
+        }
+      },
+      "kafka": {
+        "type": "object",
+        "properties": {
+          "replicationFactor": { "type": "string" },
+          "topics": {
+            "type": "object",
+            "properties": {
+              "cacheInvalidation": { "$ref": "#/definitions/kafkaTopicConfig" },
+              "completed": { "$ref": "#/definitions/kafkaTopicConfig" },
+              "events": { "$ref": "#/definitions/kafkaTopicConfig" },
+              "health": { "$ref": "#/definitions/kafkaTopicConfig" },
+              "invoker": { "$ref": "#/definitions/kafkaTopicConfig" }
+            }
+          }
+        }
+      },
+      "containerPool": {
+        "type": "object",
+        "properties": {
+          "userMemory": { "type": "string" }
+        }
+      },
+      "runtimes": { "type": "string" },
+      "testing": {
+        "type": "object",
+        "properties": {
+          "includeTests": { "type": "boolean" },
+          "includeSystemTests": { "type": "boolean" }
+        }
+      },
+      "versions": {
+        "type": "object",
+        "properties": {
+          "openwhisk": {
+            "type": "object",
+            "properties": {
+              "buildDate": { "type": "string" },
+              "buildNo": { "type": "string" },
+              "gitTag": { "type": "string" }
+            },
+            "required": ["buildDate", "buildNo", "gitTag"]
+          },
+          "openwhiskCli": { "type": "object", "properties": { "gitTag": { "type": "string" }, "required": ["gitTag"] } },
+          "openwhiskCatalog": { "type": "object", "properties": { "gitTag": { "type": "string" }, "required": ["gitTag"] } },
+          "openwhiskPackageAlarms": { "type": "object", "properties": { "gitTag": { "type": "string" }, "required": ["gitTag"] } },
+          "openwhiskPackageCloudant": { "type": "object", "properties": { "gitTag": { "type": "string" }, "required": ["gitTag"] } },
+          "openwhiskPackageKafka": { "type": "object", "properties": { "gitTag": { "type": "string" }, "required": ["gitTag"] } },
+          "required": ["openwhisk", "openwhiskCli", "openwhiskCatalog", "openwhiskPackageAlarms", "openwhiskPackageCloudant", "openwhiskPackageKafka"]
+        }
+      },
+      "required": [ "ingress", "auth", "systemNameSpace", "versions" ]
+    },
+
+    "k8s": {
+      "type": "object",
+      "properties": {
+        "domain": { "type": "string" },
+        "dns": { "type": "string" },
+        "persistence": {
+          "type": "object",
+          "properties": { "enabled": { "type": "boolean" } },
+          "required": ["enabled"],
+          "if": { "properties": { "enabled": { "const": true } } },
+          "then": {
+            "allOf": [
+              { "properties": { "hasDefaultStorageClass": { "type": "boolean" } },
+                "required": ["hasDefaultStorageClass"]
+              },
+              { "if": { "properties": { "hasDefaultStorageClass": { "const": false } } },
+                "then": {
+                  "properties": { "explicitStorageClass": { "type": "string" } },
+                  "required": ["explicitStorageClass"]
+                }
+              }
+            ]
+          }
+        }
+      },
+      "required": ["domain", "dns", "persistence"]
+    },
+
+    "utility": {
+      "type": "object",
+      "properties": {
+        "imageName":       { "type": "string" },
+        "imageTag":        { "type": "string" },
+        "imagePullPolicy": { "type": "string", "enum": ["Always", "Never", "IfNotPresent"] }
+      },
+      "required": ["imageName", "imageTag", "imagePullPolicy"]
+    },
+
+    "docker": {
+      "type": "object",
+      "properties": {
+        "registry": {
+          "type": "object",
+          "properties": {
+            "name": { "type" : "string" },
+            "username": { "type" : "string" },
+            "password": { "type" : "string" }
+          }
+        },
+        "timezone": { "type": "string" }
+      }
+    },
+
+    "zookeeper": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "$comment": "Zookeeper's quorum protocol is designed to have an odd number of replicas",
+          "properties": { "replicaCount": { "not": { "multipleOf": 2 } } }
+        },
+        { "properties": {
+            "port": { "type": "integer", "minimum": 0 },
+            "serverPort": { "type": "integer", "minimum": 0 },
+            "leaderElectionPort": { "type": "integer", "minimum": 0 },
+            "config": {
+              "type": "object",
+              "properties": {
+                "tickTime": { "type": "integer" },
+                "initLimit": { "type": "integer" },
+                "syncLimit": { "type": "integer" },
+                "dataDir": { "type": "string" },
+                "dataLogDir": { "type": "string" }
+              },
+              "required": ["tickTime", "initLimit", "syncLimit", "dataDir", "dataLogDir"],
+              "additionalProperties": false
+            }
+          },
+          "required": ["port", "serverPort", "leaderElectionPort", "config"]
+        }
+      ]
+    },
+
+    "kafka": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] }
+      ]
+    },
+
+    "db": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] },
+        { "$comment": "wipeAndInit implies replicaCount is 1 because initdb.sh enables single node mode",
+          "if": { "properties": { "wipeAndInit": { "const": true } } },
+          "then": { "properties": { "replicaCount": { "const": 1 } } }
+        },
+        { "$ref": "#/definitions/optionalExternalHostCheck" }
+      ]
+    },
+
+    "nginx": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "httpPort": { "type": "integer", "minimum": 0 } }, "required": ["httpPort"] },
+        { "properties": { "httpsPort": { "type": "integer", "minimum": 0 } }, "required": ["httpsPort"] }
+      ]
+    },
+
+    "controller": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] },
+        { "properties": {
+            "options": { "type": "string" },
+            "jvmHeapMB": { "type": "string" },
+            "jvmOptions": { "type": "string" }
+           },
+           "required": ["jvmHeapMB"]
+        }
+      ]
+    },
+
+    "invoker": {
+      "allOf": [
+        { "$ref": "#/definitions/daemonset" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] }
+      ]
+    },
+
+    "apigw": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "apiPort": { "type": "integer", "minimum": 0 } }, "required": ["apiPort"] },
+        { "properties": { "mgmtPort": { "type": "integer", "minimum": 0 } }, "required": ["mgmtPort"] }
+      ]
+    },
+
+    "redis": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] },
+        { "properties": { "replicaCount": { "const": 1 } } },
+        { "$ref": "#/definitions/optionalExternalHostCheck" }
+      ]
+    },
+
+    "user_events": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] }
+      ]
+    },
+
+    "prometheus": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] },
+        { "properties": {
+            "persistentVolume": {
+              "type": "object",
+              "properties": { "mountPath": { "type": "string" } },
+              "required": ["mountPath" ]
+            }
+          }
+        }
+      ]
+    },
+
+    "grafana": {
+      "allOf": [
+        { "$ref": "#/definitions/podspec" },
+        { "properties": { "port": { "type": "integer", "minimum": 0 } }, "required": ["port"] },
+        { "properties": { "dashboards": { "type": "array", "items": { "type": "string" } } }, "required": ["dashboards"] }
+      ]
+    },
+
+    "metrics": {
+      "type": "object",
+      "properties": {
+        "prometheusEnabled": { "type": "boolean" },
+        "whiskconfigFile": { "type": "string" },
+        "kamonEnabled": { "type": "boolean" },
+        "kamonTags": { "type": "boolean" },
+        "userMetricsEnabled": { "type": "boolean" }
+      }
+    },
+
+    "providers": {
+      "type": "object",
+      "properties": {
+        "db": { "$ref": "#/definitions/optionalExternalHostCheck" },
+
+        "alarm": {
+          "allOf": [
+            { "$ref": "#/definitions/podspec" },
+            { "properties": { "apiPort": { "type": "integer", "minimum": 0 } }, "required": ["apiPort"] },
+            { "properties": { "replicaCount": { "const": 1 } } }
+          ]
+        },
+
+        "cloudant": {
+          "allOf": [
+            { "$ref": "#/definitions/podspec" },
+            { "properties": { "apiPort": { "type": "integer", "minimum": 0 } }, "required": ["apiPort"] },
+            { "properties": { "replicaCount": { "const": 1 } } }
+          ]
+        },
+
+        "kafka": {
+          "allOf": [
+            { "$ref": "#/definitions/podspec" },
+            { "properties": { "apiPort": { "type": "integer", "minimum": 0 } }, "required": ["apiPort"] },
+            { "properties": { "replicaCount": { "const": 1 } } }
+          ]
+        }
+      }
+    },
+
+    "affinity": {
+      "type": "object",
+      "properties": { "enabled": { "type": "boolean" } },
+      "required": ["enabled"],
+      "if": { "properties": { "enabled": { "const": true } } },
+      "then": {
+        "properties": {
+          "coreNodeLabel": { "type": "string" },
+          "edgeNodeLabel": { "type": "string" },
+          "invokerNodeLabel": { "type": "string" },
+          "providerNodeLabel": { "type": "string" }
+        },
+        "required": ["coreNodeLabel", "edgeNodeLabel", "invokerNodeLabel", "providerNodeLabel"]
+      }
+    },
+
+    "toleration": {
+      "type": "object",
+      "properties": { "enabled": { "type": "boolean" } },
+      "required": ["enabled"],
+      "if": { "properties": { "enabled": { "const": true } } },
+      "then": {
+        "properties": {
+          "coreValue": { "type": "string" },
+          "edgeValue": { "type": "string" },
+          "invokerValue": { "type": "string" }
+        },
+        "required": ["coreValue", "edgeValue", "invokerValue"]
+      }
+    },
+
+    "pdb": {
+      "type": "object",
+      "properties": { "enable": { "type": "boolean" } },
+      "required": ["enable"],
+      "if": { "properties": { "enable": { "const": true } } },
+      "then": {
+        "properties": {
+          "zookeeper": { "type": "object", "properties": { "maxUnavailable": { "type": "integer" } }, "required": ["maxUnavailable"] },
+          "kafka": { "type": "object", "properties": { "maxUnavailable": { "type": "integer" } }, "required": ["maxUnavailable"] },
+          "controller": { "type": "object", "properties": { "maxUnavailable": { "type": "integer" } }, "required": ["maxUnavailable"] },
+          "invoker": { "type": "object", "properties": { "maxUnavailable": { "type": "integer" } }, "required": ["maxUnavailable"] }
+        },
+        "required": ["zookeeper", "kafka", "controller", "invoker"]
+      }
+    },
+
+
+    "probes": {
+      "type": "object",
+      "properties": {
+        "zookeeper": { "$ref": "#/definitions/standardPodProbes" },
+        "controller": { "$ref": "#/definitions/standardPodProbes" }
+      }
+    }
+  },
+
+  "if": {
+    "properties": { "k8s": { "properties": { "persistence": { "properties": { "enabled": { "const": true } }}}}}
+  },
+  "then": {
+    "$comment": "If k8s.persistence.enabled then .persistence.size must be valid for each listed podspec",
+    "properties": {
+      "zookeeper": { "$ref": "#/definitions/pvSizeValid" },
+      "kafka": { "$ref": "#/definitions/pvSizeValid" },
+      "db": { "$ref": "#/definitions/pvSizeValid" },
+      "redis": { "$ref": "#/definitions/pvSizeValid" },
+      "prometheus": { "$ref": "#/definitions/pvSizeValid" },
+      "providers": {
+        "properties": {
+          "alarm": { "$ref": "#/definitions/pvSizeValid" },
+          "cloudant": { "$ref": "#/definitions/pvSizeValid" }
+        }
+      }
+    }
+  }
+}
diff --git a/helm/openwhisk/values.yaml b/helm/openwhisk/values.yaml
index 665c5f0..85105c1 100644
--- a/helm/openwhisk/values.yaml
+++ b/helm/openwhisk/values.yaml
@@ -148,7 +148,7 @@
   persistence:
     enabled: true
     hasDefaultStorageClass: true
-    explicitStorageClass: nil
+    explicitStorageClass: null
 
 # Images used to run auxillary tasks/jobs
 utility:
@@ -208,7 +208,7 @@
   # NOTE: must be 1 (because initdb.sh enables single node mode)
   replicaCount: 1
   restartPolicy: "Always"
-  host: nil
+  host: null
   port: 5984
   provider: "CouchDB"
   protocol: "http"
@@ -294,7 +294,7 @@
   # NOTE: setting replicaCount > 1 will not work; need to add redis cluster configuration
   replicaCount: 1
   restartPolicy: "Always"
-  host: nil
+  host: null
   port: 6379
   persistence:
     size: 256Mi