Repository: jupyterhub/zero-to-jupyterhub-k8s

Issue:
System to deprecate Helm value config
We need a way to systematically deprecate helm chart configuration. Here is [one approach I implemented in mattermost-team-edition](https://github.com/mattermost/mattermost-helm/blob/master/charts/mattermost-team-edition/templates/_deprecations.tpl).

1. We render individual deprecation messages in individual templates.
2. We render all these individual deprecation messages inside a collection template.
3. We conditionally fail the rendering of the chart templates if the collection template isn't empty. using the [fail directive](http://masterminds.github.io/sprig/flow_control.html), which is part of the [sprig library](http://masterminds.github.io/sprig/) available for use in Helm templates.

Further, we could also consider having two collection templates, one for _hard deprecations_ and one for _soft deprecations_ or _warnings_. This was also [something I added](https://github.com/mattermost/mattermost-helm/blob/master/charts/mattermost-team-edition/templates/_warnings.tpl) to mattermost-team-edition. A soft deprecation or warning would be something that the user would be notified about but that would not stop the upgrade process. A hard deprecation on the other hand would be something that if noticed would trigger the helm chart rendering to fail.

## Useful technical know how
- If you render a template, its output is always a string, even though its a valid YAML string. I've not realized this myself until very recently when @yuvipanda used it in #1409, but if a template has rendered a string you can use the `fromYaml` function to go back to a object you can inspect. The `fromYaml` function that Helm [is injected](https://github.com/helm/helm/blob/47ee538590e02854d595a44e6cf1ccd876084a5d/pkg/engine/engine.go#L79-L85) from [their chartutil GO class](https://godoc.org/k8s.io/helm/pkg/chartutil#FromYaml)) for use in Helm templates. We could potentially use this to combine the output of individual deprecations smarter, for example if they would render to a YAML structure that defined if it should be treated as a soft deprecation/warning, hard deprecation.
- [Helm's documentation relating to _partials_ and _templates_](https://helm.sh/docs/chart_template_guide/#partials-and-files).

## PR work to do
- [ ] Add a `_errors_and_warnings.tpl` file or similar.
- [ ] Document and support a demonstrative example for both a warning and an error and how to add new ones.
- [ ] Ensure to run a `fail` template directive if there is hard deprecations / errors. Note that if you don't render the template logic deciding if the `fail` directive will render, you won't stop an helm upgrade process.
- [ ] Add a place in NOTES.txt rendering the collection of soft deprecations / warnings and the collection of hard deprecations / errors.


Discussion:
I've kept this in mind for over a year now and have gained more experience with using Helm charts and how various charts has went about deprecations. I consider the best practice to be to use the `fail` function in a helm template to notify users of any breaking changes along with instructions on what to do.

Failing loudly with a clear error message during template rendering has been unproblematic and provided an excellent user experience for me as a user of other helm charts, and I suggest we follow such practice in general. This practice is also great for maintainers because its not cluttering the actual k8s manifest templates.
A tentative 👍 from me to failing hard as long as the docs are very clear on the upgrade process.

With my sysadmin hat on it's really annoying to have to manually fix a configuration when there's an upgrade so backwards compatibility is nice. With my maintainer hat on maintaining branching logic in Helm is horrible. In addition there have been some potential security issues related to management of deprecations or changes such as:
- Changing `orgWhitelist` to `org_whitelist` https://github.com/jupyterhub/zero-to-jupyterhub-k8s/pull/1107 (there's another issue I can't find where someone was unaware of this change, and inadvertently opened up their JupyterHub to all GitHub users)
- https://github.com/jupyterhub/zero-to-jupyterhub-k8s/issues/1914

So on balance I think failing hard, providing an informative message to administrators, and having clear release notes, is easier for us. Optionally we could make it easier for admins by providing a conversion script that updates an old config.yaml.

Resolving patch:
diff --git a/jupyterhub/files/hub/jupyterhub_config.py b/jupyterhub/files/hub/jupyterhub_config.py
--- a/jupyterhub/files/hub/jupyterhub_config.py
+++ b/jupyterhub/files/hub/jupyterhub_config.py
@@ -377,10 +377,7 @@ def camelCaseify(s):
 
 cloud_metadata = get_config("singleuser.cloudMetadata", {})
 
-if (
-    cloud_metadata.get("blockWithIptables") == True
-    or cloud_metadata.get("enabled") == False
-):
+if cloud_metadata.get("blockWithIptables") == True:
     # Use iptables to block access to cloud metadata by default
     network_tools_image_name = get_config("singleuser.networkTools.image.name")
     network_tools_image_tag = get_config("singleuser.networkTools.image.tag")


Test patch: