Post Code-Freeze Review, Bugsfixes and Documentation

- Fix traefik Portal Button
- Touchup Security Policies
- Update Support Policies
- Re-Add Deluge as incubator App
- Add Canary to Security Policies
- Add all-contributors basic config
This commit is contained in:
kjeld Schouten-Lebbing
2021-04-09 13:34:29 +02:00
parent 56211222bf
commit cde18639c7
568 changed files with 2295 additions and 1614 deletions
@@ -0,0 +1,82 @@
# TrueNAS SCALE Chart Structure
A TrueNAS SCALE chart repository differs slightly in directory structure from upstream repos in that it includes an `app version` directory.
A TrueNAS SCALE chart also has three additional files an `app-readme.md` file that provides a high level overview display in the TrueNAS SCALE UI and a `questions.yaml` file defining questions to prompt the user with and an `item.yaml` file outlining item specific details.
There are 2 directories `charts` and `test`, each representing a train. Chart releases created from catalog items in a specific train cannot be moved to another train. Currently only the `charts` train can be used inside the UI.
```
charts/ix-chart/<chart version>/
app-readme.md # TrueNAS SCALE Specific: Readme file for display in TrueNAS SCALE UI
charts/ # Directory containing dependency charts
Chart.yaml # Required Helm chart information file
questions.yaml # TrueNAS SCALE Specific: File containing questions for TrueNAS SCALE UI
README.md # Optional: Helm Readme file (will be rendered in TrueNAS SCALE UI as well)
templates/ # A directory of templates that, when combined with values.yml will generate K8s YAML
values.yaml # The default configuration values for this chart
```
*See the upstream Helm chart [developer reference](https://helm.sh/docs/chart_template_guide/) for a complete walk through of developing charts.*
To convert an upstream chart to take advantage of TrueNAS SCALE enhanced UX, first create an `item.yaml` file.
This file among other catalog item information provides a list of categories that this chart fits into. This helps users navigate and filtering when browsing the catalog UI.
```
$ cat charts/ix-chart/item.yaml
categories:
- generic
icon_url: "http://ix_url"
```
After that create `app-readme.md` file.
```
$ cat charts/ix-chart/<chart version>/app-readme.md
iX-chart is a chart designed to let user deploy a docker image in a TrueNAS SCALE kubernetes cluster.
It provides a mechanism to specify workload type, add external host interfaces in the pods, configure volumes and allocate host resources to the workload.
```
Then add a `questions.yaml` file to prompt the user for something.
```
groups:
- name: "Container Images"
description: "Image to be used for container"
questions:
- variable: image
description: "Docker Image Details"
group: "Container Images"
schema:
type: dict
required: true
attrs:
- variable: repository
description: "Docker image repository"
label: "Image repository"
schema:
type: string
required: true
- variable: tag
description: "Tag to use for specified image"
label: "Image Tag"
schema:
type: string
default: "latest"
- variable: pullPolicy
description: "Docker Image Pull Policy"
label: "Image Pull Policy"
schema:
type: string
default: "IfNotPresent"
enum:
- value: "IfNotPresent"
description: "Only pull image if not present on host"
- value: "Always"
description: "Always pull image even if present on host"
- value: "Never"
description: "Never pull image even if it's not present on host"
```
The above will prompt the user with 2 text fields and a dropdown in the UI getting details for image configuration in a helm chart.
_More information about questions.yaml is available [here](https://wiki.truecharts.org/development/questions-yaml/)_
@@ -0,0 +1,61 @@
# Chart.yaml layout
At TrueCharts we try to keep some files standardised, this enables us to make changes to these charts in bulk with less risk of mistakes. Chart.yaml is one of these files.
In this documentation we will explain the standardised layout options. For an example layout, please see our standard Chart.yaml [template](https://github.com/truecharts/apps/tree/master/.tools/templates/chart/Chart.yaml)
### Layout Explained
```
apiVersion: The chart API version (required)
kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
name: The name of the chart (required)
version: A SemVer 2 version (required)
upstream_version: A SemVer 2 version, as used by an upstream Helm Chart source (optional)
appVersion: The version of the app that this contains (optional). Needn't be SemVer. Quotes recommended.
description: A single-sentence description of this project (optional)
type: The type of the chart (optional)
deprecated: Whether this chart is deprecated (optional, boolean)
home: The URL of this projects home page (optional)
icon: A URL to an SVG or PNG image to be used as an icon (optional).
keywords:
- A list of keywords about this project (optional)
sources:
- A list of URLs to source code for this project (optional)
dependencies:
- name: The name of the chart (nginx)
repository: The repository URL ("https://example.com/charts") or alias ("@repo-name")
version: The version of the chart ("1.2.3")
condition: (optional) A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
tags: # (optional)
- Tags can be used to group charts for enabling/disabling together
import-values: # (optional)
- ImportValues holds the mapping of source values to parent key to be imported. Each item can be a string or pair of child/parent sublist items.
alias: (optional) Alias to be used for the chart. Useful when you have to add the same chart multiple times
maintainers: # (optional)
- name: The maintainers name (required for each maintainer)
email: The maintainers email (optional for each maintainer)
url: A URL for the maintainer (optional for each maintainer)
annotations:
example: A list of annotations keyed by name (optional).
```
##### Commenting
In the above description there are a lot of values that are not actually used. Some of those, like `deprecated`, we just set to false. While others, like `annotations` get commented out.
Please refer to our standard Chart.yaml [template](https://github.com/truecharts/apps/tree/master/.tools/templates/chart/Chart.yaml) to see which unused values needs which treatment.
##### Dependencies
We expect each chart to use our Common-Chart in some capacity, inless it's absolutely impossible to do so. This also means we expect the Common-Chart to always be the first dependency in the list. This enables us to easily update all common-chart references in bulk.
All other dependencies are expected to be listed in alphabetical order.
##### Maintainers
The first maintainer should always be TrueCharts, as the TrueCharts core team is expected to step in if the other maintainers fail to maintain their work.
An example of how to list TrueCharts as a maintainer is available in our standard Chart.yaml [template](https://github.com/truecharts/apps/tree/master/.tools/templates/chart/Chart.yaml).
While currently we primarily use the CODEOWNERS file to define maintainers. We might in the future either automate keeping track of maintainers, completely rely on the maintainers or do both. For this reason it's important to add yourself as a maintainer if you expect to maintain your work.
All other maintainers are, ofcoarse, expected to be entered in importance. With the primary maintainer under "truecharts" and secondary maintainers thereunder.
@@ -0,0 +1,9 @@
# Common Library Chart
In Helm 3, their team introduced the concept of a [Library chart](https://helm.sh/docs/topics/library_charts/).
> A library chart is a type of Helm chart that defines chart primitives or definitions which can be shared by Helm templates in other charts. This allows users to share snippets of code that can be re-used across charts, avoiding repetition and keeping charts DRY.
The first version of our Common library was ported from k8s-at-home, which they introduced because they saw many charts requiring only a few select configuration options in their Helm charts.
Let's take for example, Sonarr, Sabnzbd, Overseerr. Each of these charts only require setting `service`, `port`, `persistence`, `ingress` and `image` since state and app configuration is handled by the application itself. In order to stay somewhat DRY (Don't Repeat Yourself) and keeping with Helm 3 usage for a Library chart, we saw this pattern and decided it was worth it for us to create a library. This means each one of these app charts has a dependency on what we call the `common` library.
+366
View File
@@ -0,0 +1,366 @@
# Ingress
Ingress is what we call "Reverse Proxy" in the UI and in the user side of the documentation. Please be aware that those refer to the same system. An Ingress is, simply put, just Kubernetes way of connecting outsides to Apps running in containers.
### Ingress Types
We currently support:
- HTTP via Ingres
- HTTP via Traefik IngressRoute (HTTP-IR)
- TCP via Traefik IngressRouteTCP
- UDP via Traefik IngressRouteUDP
From questions.yaml and the UI, these can be changed with selecting another "Type". However: Under the hood IngressRoutes and Ingress are totally different beasts and have a seperate creation process. Errors for Plain HTTP do NOT have to be present in HTTP-IR.
It's also important to note that TCP (and even more so: UDP) have less options available. The example configurations below contain a mostly complete overview of what is currently available and reasonable.
##### Ingress and Services
It's important to know what Ingress does, before you start creating ingresses in questions.yaml. Ingresses send outside Traffic, to a kubernetes Service, which in turn forwards traffic to the actual containers.
This means that every container needs to know how to reach their Service. If they do not, things go wrong.
To ensure this, it's adviced to keep the names of your Ingresses the same as the names of your services. We made sure the ingress would automatically detect (and connect to) the main port of a Service with the same name.
However: In case you need to do this differently, need to connect to additionalServices and/or need to connect to a secondary port, you can manually set both the serviceName and servicePort in questions.yaml. We advice however, to only do so if absolutely necessary!
##### The Main Ingress
The main Ingress and Main service take an important role in our standardisation. Where the main Service is used for healthchecks and the "portal" button, the main Ingress is just used for the portal button.
However: As the maintainers expect new features to be connecting to the main service and main ingress, it will cause problems if you decide to bypass/ignore these.
### Standards/Examples
We try to maintain as much of a standardised questions.yaml format as possible, to ensure (bulk) editing stays as easy as possible.
##### HTTP Ingress
```
- variable: ingress
label: ""
group: "Reverse Proxy Configuration"
schema:
type: dict
attrs:
- variable: webui
label: "Web Reverse Proxy Configuration"
schema:
type: dict
attrs:
- variable: enabled
label: "Enable Web Reverse Proxy"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: type
label: "Reverse Proxy Type"
schema:
type: string
default: "HTTP"
hidden: true
editable: false
required: true
- variable: serviceName
label: "Service name to proxy to"
schema:
hidden: true
editable: false
type: string
default: ""
- variable: entrypoint
label: "Select Entrypoint"
schema:
type: string
default: "websecure"
required: true
enum:
- value: "websecure"
description: "Websecure: HTTPS/TLS port 443"
- variable: hosts
label: "Hosts"
schema:
type: list
default: []
items:
- variable: host
label: "Host"
schema:
type: dict
attrs:
- variable: host
label: "Domain Name"
required: true
schema:
type: string
- variable: path
label: "path"
schema:
type: string
required: true
hidden: true
default: "/"
- variable: certType
label: "Select Certificate Type"
schema:
type: string
default: "selfsigned"
enum:
- value: ""
description: "No Encryption/TLS/Certificates"
- value: "selfsigned"
description: "Self-Signed Certificate"
- value: "ixcert"
description: "TrueNAS SCALE Certificate"
- variable: certificate
label: "Select TrueNAS SCALE Certificate"
schema:
type: int
show_if: [["certType", "=", "ixcert"]]
$ref:
- "definitions/certificate"
- variable: authForwardURL
label: "Forward Authentication URL"
schema:
type: string
default: ""
```
##### TCP Ingress
```
- variable: tcp
label: "TCP Reverse Proxy Configuration"
schema:
type: dict
attrs:
- variable: enabled
label: "Enable TCP Reverse Proxy"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: type
label: "Select Reverse Proxy Type"
schema:
type: string
default: "TCP"
required: true
editable: false
hidden: true
- variable: serviceName
label: "Service name to proxy to"
schema:
hidden: true
editable: false
type: string
default: ""
- variable: entrypoint
label: "Select Entrypoint"
schema:
type: string
default: "torrent-tcp"
required: true
enum:
- value: "torrent-tcp"
description: "Torrent-TCP: port 51413"
```
##### UDP Ingress
```
- variable: udp
label: "UDP Reverse Proxy Configuration"
schema:
type: dict
attrs:
- variable: enabled
label: "Enable UDP Reverse Proxy"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: type
label: "Select Reverse Proxy Type"
schema:
type: string
default: "UDP"
required: true
editable: false
hidden: true
- variable: serviceName
label: "Service name to proxy to"
schema:
hidden: true
editable: false
type: string
default: ""
- variable: entrypoint
label: "Select Entrypoint"
schema:
type: string
default: "torrent-udp"
required: true
enum:
- value: "torrent-udp"
description: "Torrent-UDP: port 51413"
```
### Other Ingress options
There are a few other options that are rarely (if ever) used.
##### servicePort
```
- variable: servicePort
label: "Service Port to proxy to"
schema:
hidden: true
editable: false
type: int
default: 80
```
##### serviceKind
```
- variable: serviceKind
label: "Service Kind to proxy to"
schema:
hidden: true
editable: false
type: string
default: ""
```
### External Services
The externalServices option, is actually mostly an Ingress "under the hood" which just creates a very small (minimal) service.
```
- variable: externalServices
label: "(Advanced) Add External Services"
group: "Advanced"
schema:
type: list
default: []
items:
- variable: externalService
label: "External Service"
schema:
type: dict
attrs:
- variable: enabled
label: "Enable Web Reverse Proxy"
schema:
type: boolean
hidden: true
editable: false
default: true
- variable: type
label: "Reverse Proxy Type"
schema:
type: string
default: "HTTP"
hidden: true
editable: false
required: true
- variable: serviceName
label: "Service name to proxy to"
schema:
hidden: true
editable: false
type: string
default: ""
- variable: serviceTarget
label: "IP Adress of the external service"
schema:
hidden: false
editable: true
required: true
type: string
default: "192.168.0.0"
- variable: servicePort
label: "External Service Port"
description: "The port on the external service you want to proxy"
schema:
hidden: false
required: true
editable: true
type: int
default: 80
- variable: serviceType
label: "Connection Type"
description: "Connection Type between Traefik and the external service"
schema:
hidden: false
editable: true
required: true
default: "HTTP"
type: string
enum:
- value: "HTTP"
description: "HTTP"
- value: "HTTPS"
description: "HTTPS"
- variable: serviceKind
label: "Service Kind to proxy to"
schema:
hidden: true
editable: false
type: string
default: ""
- variable: entrypoint
label: "Select Entrypoint"
schema:
type: string
default: "websecure"
required: true
enum:
- value: "websecure"
description: "Websecure: HTTPS/TLS port 443"
- variable: host
label: "Domain Name"
required: true
schema:
type: string
- variable: path
label: "path"
schema:
type: string
required: true
hidden: false
default: "/"
- variable: certType
label: "Select Certificate Type"
schema:
type: string
default: "selfsigned"
enum:
- value: ""
description: "No Encryption/TLS/Certificates"
- value: "selfsigned"
description: "Self-Signed Certificate"
- value: "ixcert"
description: "TrueNAS SCALE Certificate"
- variable: certificate
label: "Select TrueNAS SCALE Certificate"
schema:
type: int
show_if: [["certType", "=", "ixcert"]]
$ref:
- "definitions/certificate"
- variable: authForwardURL
label: "Forward Authentication URL"
schema:
type: string
default: ""
```
@@ -0,0 +1,66 @@
# Portal Button
After installation almost every app should have a "portal" button. This button is an easy and streamlined way of entering the Applications after installation. However, one should be aware that it does not magically follow changes inside the application (for example: from http to https).
##### questions.yaml example
Every questions.yaml file should contain the following snippets to enable the portal button. Please be aware to change `"http"` to `"https"` in services.main.port.protocol if your application uses http instead of https when running using "NodePort".
Also please be aware that the portal only(!) points towards the main service, main service port and main ingress.
```
portals:
web_portal:
protocols:
- "$kubernetes-resource_configmap_portal_protocol"
host:
- "$kubernetes-resource_configmap_portal_host"
ports:
- "$kubernetes-resource_configmap_portal_port"
path: "/"
questions:
- variable: portal
group: "Container Image"
label: "Configure Portal Button"
schema:
type: dict
hidden: true
attrs:
- variable: enabled
label: "Enable"
description: "enable the portal button"
schema:
hidden: true
editable: false
type: boolean
default: true
```
There are also some additional (advanced) options availale, these can be added below the above required portion as required:
**ingressPort:**
```
- variable: ingressPort
label: "Port when ingress is not using 443"
description: "Advanced setting, please enter a different port to use if Ingress uses something other than port 443"
schema:
hidden: true
editable: false
type: int
default: 8443
```
**host:**
```
- variable: host
label: "override Host when using NodePort"
description: "Overrides the host setting when using NodePort. Example usecase would be loadbalanced NodePorts."
schema:
hidden: true
editable: false
type: string
default: "test.com"
```
@@ -0,0 +1,183 @@
# Questions.yaml
Questions.yaml is the file which get rendered by TrueNAS to create the UI. When not creating new charts, most of what this project does is stitching together questions.yaml files to turn existing Helm Charts into Apps.
### Syntax
In this document we give you a short reference guide (ported from IX Official) which lays out the settings available in questions.yaml.
#### Question Variable Reference
| Variable | Type | Required | Description |
| ------------- | ------------- | --- |------------- |
| variable | string | true | define the variable name specified in the `values.yaml`file. |
| label | string | true | define the UI label. |
| description | string | false | specify the description of the variable. |
| group | string | false | group questions by input value. |
| schema | dictionary | true | specify schema details for the `variable` |
| schema.type | string | true | specify type of value for `variable` (current supported types are string, int, boolean, path, hostpath, list, dict, ipaddr, and cron).|
| schema.required | bool | false | define if the variable is required or not (true \ false), defaults to false |
| schema.default | object | false | specify the default value. |
| schema.min_length | int | false | min character length for string type variable.|
| schema.max_length | int | false | max character length for string type variable.|
| schema.min | int | false | min integer length. |
| schema.max | int | false | max integer length. |
| schema.enum | []dictionary | false | specify the options when the variable type is `string`, for example, <br><br>enum:<br> - value: "RollingUpdate" <br>&nbsp;&nbsp;description: "Create new pods and then kill old ones"<br> - value: "Recreate"<br>&nbsp;&nbsp;description: "Kill existing pods before creating new ones"|
| schema.valid_chars | string | false | regular expression for input chars validation. |
| schema.subquestions | []subquestion | false | add an array of subquestions.|
| schema.show_if | string | false | show current variable if condition specified is true, for example `show_if: [["workloadType", "=", "CronJob"]]` |
| schema.show_subquestions_if | string | false | show subquestions if is true or equal to one of the options. for example `show_subquestion_if: "static"`. system will convert this to the filters format specifid for `shcema.show_if` automatically.|
| schema.attrs | []variables | false | specified when `schema.type` is dictionary to declare attributes allowed in the dictionary. |
| schema.items | []variables | false | specified when `schema.type` is list to declare attributes allowed in the list. |
| schema.private | bool | false | specified for declaring information sensitive fields. |
| schema.null | bool | false | specifies if the value for the variable can be null. defaults to false. |
##### Subquestions
`subquestions[]` cannot contain `subquestions` or `show_subquestions_if` keys, but all other keys in the above table are supported. Also variables having `schema.type` list do not support `subquestions`.
##### Special Questions
There are some novel cases where we would like to provide ability to configure / manage resources for workloads with getting some data from system dynamically.
So a chart can specify certain actions to be performed by the system for a variable by defining a reference. An example better illustrates this concept:
```
- variable: volume
label: "Volume"
schema:
type: dict
$ref:
- "normalize/ixVolume"
attrs:
- variable: mountPath
label: "Mount Path"
description: "Path where the volume will be mounted inside the pod"
schema:
type: path
required: true
- variable: datasetName
label: "Dataset Name"
schema:
type: string
required: true
```
In the above variable we define a `$ref` in schema which specifies that the system should take some action for normalising the value specified for the variable.
In this specific case, `ix_volume` is a concept introduced where we recommend using a volume which we are able to rollback automatically on chart release rollback. In essence,
it is just a `hostPath` volume for which the system automatically creates the dataset specified.
We have following types of actions supported in `$ref` right now:
1) definitions
2) normalize
For (1), system will automatically update schema for a particular definition. For example,
```
- variable: hostInterface
description: "Please specify host interface"
label: "Host Interface"
schema:
type: string
required: true
$ref:
- "definitions/interface"
```
System will automatically populate available interfaces for the user based on what interfaces are available on the system.
For (2), system will normalize values or perform some actions as discussed above.
### Standardised questions.yaml sections
To minimise the maintenance load of our App collection, we always aim to standardise as much as possible. The same goes for questions.yaml. Included here are some code standardised code-snippets that are expected to be included in every App.
Be aware that sometimes specific functions might or might not completely function. Leaving them out would, however, everely increase the maintenance load and often said functionality will be added in the common-chart later on anyway.
##### Groups
To make sure all apps stay somewhat the same, we use a standardised `groups:` section. Please make sure to use this in your Apps:
```
groups:
- name: "Container Image"
description: "Image to be used for container"
- name: "Workload Configuration"
description: "Configure workload deployment"
- name: "Configuration"
description: "additional container configuration"
- name: "Networking"
description: "Configure / service for container"
- name: "Storage and Devices"
description: "Persist and share data that is separate from the lifecycle of the container"
- name: "Resource Reservation"
description: "Specify resources to be allocated to workload"
- name: "Reverse Proxy Configuration"
description: "Reverse Proxy configuration"
- name: "WARNING"
description: "WARNING"
```
##### General Configuration options
These options are always included because almost every chart (eventually) has a use for them and/or other parts of the common chart depend on them.
They are called general options, because they affect the basic functionalities of a chart. For example: Custom User environment variables, permissions and timezones.
```
- variable: timezone
group: "Configuration"
label: "Timezone"
schema:
type: string
default: "Etc/UTC"
$ref:
- "definitions/timezone"
- variable: PUID
group: "Configuration"
label: "PUID"
description: "The UserID of the user running the application and owning the files"
schema:
type: int
default: 568
- variable: PGID
group: "Configuration"
label: "PGID"
description: "The groupID of the user/group running the application and owning the files"
schema:
type: int
default: 568
- variable: UMASK
group: "Configuration"
label: "UMASK (advanced)"
description: "The UMASK used if supported by the application"
schema:
type: string
default: "002"
# Configure Custom Enviroment Variables
- variable: environmentVariables
label: "Image environment"
group: "Configuration"
schema:
type: list
default: []
items:
- variable: environmentVariable
label: "Environment Variable"
schema:
type: dict
attrs:
- variable: name
label: "Name"
schema:
type: string
- variable: value
label: "Value"
schema:
type: string
```
@@ -0,0 +1,164 @@
# Services
Every App needs to be exposed to something, either an UI, API or other containers.However with Kubernetes we don't directly connect to the containers running the App, because those might be on another node or there might be multiple "high available" containers for the App. Instead we use what is called `Services`. Services are simply put "Internal Load-Balancers", they also guaranteed to be reachable by (internal!) DNS name and (in some cases) prevent traffic from reaching your App when the healthcheck isn't finished yet (or is failing).
### Two kinds of services
##### First: hostNetwork
Always add the hostNetwork option above the "services" section.
This is to try and keep things clear for the user.
```
# Enable Host Networking
- variable: hostNetwork
group: "Networking"
label: "Enable Host Networking"
schema:
type: boolean
default: false
```
##### Main Service
Every App is required to have a main service, the primary thing that users (or other Apps!) connect with. No mater if it's a webUI, an API, a database connection or something totally else, A service is always required.
Please keep in mind that every App is different, some just have one service (which *ALWAYS* has to be called `main`) and others need more (which each has to have an unique name). Every App also uses different ports, so please alter accordingly.
```
- variable: services
group: "Networking"
label: "Configure Service"
schema:
type: dict
attrs:
- variable: main
label: "Main service"
description: "The Primary service on which the healthcheck runs, often the webUI"
schema:
type: dict
attrs:
- variable: enabled
label: "Enable the service"
schema:
type: boolean
default: true
hidden: true
- variable: type
label: "Service type"
description: "ClusterIP's are only internally available, nodePorts expose the container to the host node System"
schema:
type: string
default: "ClusterIP"
enum:
- value: "nodePort"
description: "NodePort"
- value: "ClusterIP"
description: "ClusterIP"
- variable: port
label: "Port configuration"
schema:
type: dict
attrs:
- variable: protocol
label: "Port Type"
schema:
type: string
default: "HTTP"
hidden: false
enum:
- value: HTTP
description: "HTTP"
- value: "HTTPS"
description: "HTTPS"
- variable: port
label: "container port"
schema:
type: int
default: 80
editable: false
hidden: true
- variable: targetport
label: "Internal Service port"
description: "When connecting internally to this App, you'll need this port"
schema:
type: int
default: 80
editable: false
hidden: true
- variable: nodePort
label: "(optional) host nodePort to expose to"
description: "only get used when nodePort is selected"
schema:
type: int
min: 9000
max: 65535
default: 36052
required: true
```
##### Unlimited custom services
in some edgecases users might need or want to have the option to add unlimited custom Services. While we _highly_ suggest not doing so, these services can be added with the following standardised template:
```
- variable: additionalServices
label: "Custom Services"
group: "Networking"
schema:
type: list
default: []
items:
- variable: additionalService
label: "Custom Service"
schema:
type: dict
attrs:
- variable: enabled
label: "Enable the service"
schema:
type: boolean
default: true
hidden: true
- variable: type
label: "Service type"
description: "ClusterIP's are only internally available, nodePorts expose the container to the host node System"
schema:
type: string
default: "ClusterIP"
enum:
- value: "nodePort"
description: "NodePort"
- value: "ClusterIP"
description: "ClusterIP"
- variable: port
label: "Port configuration"
schema:
type: dict
attrs:
- variable: port
label: "container port"
schema:
type: int
default: 80
editable: false
hidden: true
- variable: targetport
label: "Internal Service port"
description: "When connecting internally to this App, you'll need this port"
schema:
type: int
default: 80
editable: false
hidden: true
- variable: nodePort
label: "(optional) host nodePort to expose to"
description: "only get used when nodePort is selected"
schema:
type: int
min: 9000
max: 65535
default: 36052
required: true
```
+154
View File
@@ -0,0 +1,154 @@
# Storage
This article serves as a development extention to the storage article available [here](https://wiki.truecharts.org/general/storage/)
##### Storage and Common-Chart
For all these storage solutions we require the commonchart to be added to the App.
The Common-Chart handles both the connection/addition of storage to the container and spinning up special k8s jobs to fix the permissions if requested.
### Fixed Storage
When adding an App, there are almost always certain folders that are required for solid Apps performance. For example config files that should be persistent across restarts.
For these storages we can easily add fixes values in the UI, these settings can not be disabled or removed and would, by default, bind to an ix_volume if nothing is changed.
Preventing the user to disable them, ensures that users don't (by mistake) remove the storage.
#####
```
- variable: appVolumeMounts
label: "app storage"
group: "Storage and Devices"
schema:
type: dict
attrs:
# Config ------------------------
- variable: config
label: "config dataset"
schema:
type: dict
$ref:
- "normalize/ixVolume"
attrs:
- variable: enabled
label: "Enabled"
schema:
type: boolean
default: true
required: true
hidden: true
editable: false
- variable: setPermissions
label: "Automatic Permissions"
description: "Automatically set permissions on install"
schema:
type: boolean
default: true
hidden: false
- variable: emptyDir
label: "emptyDir"
schema:
type: boolean
default: false
hidden: true
editable: false
- variable: datasetName
label: "Dataset Name"
schema:
type: string
default: "config"
required: true
editable: false
hidden: true
- variable: mountPath
label: "Mount Path"
description: "Path to mount inside the pod"
schema:
type: path
required: true
default: "/config"
editable: false
- variable: hostPathEnabled
label: "host Path Enabled"
schema:
type: boolean
default: false
show_subquestions_if: true
subquestions:
- variable: hostPath
label: "Host Path"
schema:
type: hostpath
required: true
```
### Unlimited Custom Storage Mounts
We support presenting the user with a "Do it yourself" style list, in which the user can add unlimited paths on the host system to mount.
It should always be included in any App, to give users the option to customise things however they like.
##### Example
```
- variable: additionalAppVolumeMounts
label: "Custom app storage"
group: "Storage and Devices"
schema:
type: list
default: []
items:
- variable: volumeMount
label: "Custom Storage"
schema:
type: dict
attrs:
- variable: enabled
label: "Enabled"
schema:
type: boolean
default: true
required: true
hidden: true
editable: false
- variable: setPermissions
label: "Automatic Permissions"
description: "Automatically set permissions on install"
schema:
type: boolean
default: true
hidden: false
- variable: name
label: "Mountpoint Name"
schema:
type: string
default: ""
required: true
editable: true
- variable: emptyDir
label: "emptyDir"
schema:
type: boolean
default: false
hidden: true
editable: false
- variable: mountPath
label: "Mount Path"
description: "Path to mount inside the pod"
schema:
type: path
required: true
default: ""
editable: true
- variable: hostPathEnabled
label: "host Path Enabled"
schema:
type: boolean
default: true
hidden: true
- variable: hostPath
label: "Host Path"
schema:
type: hostpath
required: true
```
@@ -0,0 +1,129 @@
# Unit tests
We unit test our common library, while it isn't near complete coverage but it does offer some basic checks.
## Running the tests
Running these tests can be done any way you like. In this document we describe a number of approaches:
* [Directly on your development machine](#directly-on-your-development-machine)
* [Through a development container in Visual Studio Code](#using-visual-studio-code)
* [Using a local Docker container](#using-a-local-docker-container)
### Directly on your development machine
First set up the environment:
```console
$ export RUBYJQ_USE_SYSTEM_LIBRARIES=1
$ bundle install
```
Run the tests:
```console
$ bundle exec m -r test/charts
```
### Using Visual Studio Code
Our repo comes with a Visual Studio Code [development container](https://code.visualstudio.com/docs/remote/containers) definition and `launch.json` that allow you to quickly set up an environment in which you can run the tests.
##### Prerequisites
- Visual Studio Code is installed.
- Docker is installed and running.
- The "Remote - Containers" extension is installed and enabled in Visual Studio Code.
For more details, please refer to the [official documentation](https://code.visualstudio.com/docs/remote/containers#_system-requirements).
##### Running tests
Once Visual Studio Code is set up, and you open the `charts` workspace, you will see a popup asking if you wish to re-open the workspace in a development container:
![Visual Studio Code development container popup](https://raw.githubusercontent.com/k8s-at-home/charts/master/docs/images/vscode_devcontainer_popup.png)
Select the option that you prefer. The workspace will be reopened and a Dockerized workspace will be built. You can now use Visual Studio Code as normal.
To run or debug the unit tests, click the "Run" button on the left sidebar and select the desired configuration:
![Visual Studio Code run configurations](https://raw.githubusercontent.com/k8s-at-home/charts/master/docs/images/vscode_run_unittests.png)
* _UnitTest - active spec file only_: This configuration will try to run the currently opened test file.
**Note:** Make sure that you have opened a valid test file (`.rb` files in the `test/charts` folder), or this will not work.
* _UnitTest - all spec files_: This configuration will run the all test files in the `test/charts` folder.
Next, press the green "Play" icon. This will start the tests show the outcome in a terminal window.
### Using a local Docker container
The [Visual Studio Code development container](#using-visual-studio-code) can also be leveraged without using Visual Studio Code.
##### Prerequisites
- Docker is installed and running.
- You have the charts repo root folder opened in your shell of choice. The commands in this article assume you are running a Bash-compatible shell.
##### Running tests
The first step is to build the development container image containing the required tools. This step only needs to be done once.
To build the container, run this command in your shell:
```console
$ docker build -t k8s-at-home/charts-unit-test -f .devcontainer/Dockerfile .
```
When you wish to run the tests, run this command in your shell:
```console
$ docker run --rm -it -v $(pwd):/charts --entrypoint "/bin/bash" -w /charts k8s-at-home/charts-unit-test -l -c "bundle exec m -r ./test/charts"
```
This will create a container with the charts repo root folder mounted to `/charts` and execute all the test files in the `test/charts` folder.
## Output
A successful test will output something like the following...
```text
Started with run options --seed 52955
common-test::statefulset volumeClaimTemplates
can set values for volumeClaimTemplates PASS (0.16s)
volumeClaimTemplates should be empty by default PASS (0.06s)
common-test::ports settings
targetPort can be overridden PASS (0.17s)
port name can be overridden PASS (0.17s)
defaults to name "http" on port 8080 PASS (0.16s)
targetPort cannot be a named port PASS (0.05s)
common-test::pod replicas
defaults to 1 PASS (0.08s)
accepts integer as value PASS (0.08s)
common-test::Environment settings
Check no environment variables PASS (0.05s)
set "valueFrom" environment variables PASS (0.11s)
set "static" and "Dynamic/Tpl" environment variables PASS (0.15s)
set "Dynamic/Tpl" environment variables PASS (0.11s)
set "static" environment variables PASS (0.10s)
common-test::ingress
ingress with hosts PASS (0.10s)
should be disabled when ingress.enabled: false PASS (0.06s)
ingress with hosts template is evaluated PASS (0.11s)
ingress with hosts and tls PASS (0.15s)
ingress with hosts and tls templates is evaluated PASS (0.16s)
should be enabled when ingress.enabled: true PASS (0.06s)
common-test::controller type
accepts "daemonset" PASS (0.06s)
accepts "statefulset" PASS (0.06s)
defaults to "Deployment" PASS (0.06s)
Finished in 2.26077s
22 tests, 59 assertions, 0 failures, 0 errors, 0 skips
```
@@ -0,0 +1,52 @@
# Values.yaml Files
Values.yaml files generally always contain configuration setting for Helm charts, TrueCharts is no different.
However, we have multiple different values.yaml files, with different goals. Because TrueNAS SCALE just works slightly differently from standard Helm Charts
### The Files
##### values.yaml
The normal file with default setting in helm charts. However, for our non-library and non-dependency charts, this is not used for TrueCharts. As questions.yaml generates configs on demand (with addition of ix_values.yaml), this file might interfere with some Helm operations combined with the questions.yaml or test_values.yaml systems or cause unexpected behavior if used.
##### ix_values.yaml
This file contains config values that are not included in questions.yaml, but should be copied into the resulting configuration anyway. It's mostly used to ensure setting can be changed by the maintainer with every update, such as versions, which is not possible when setting things as defaults inside questions.yaml
This file is, however, not very well checked by validation and CI. Use it when you absolutely have to.
One important setting in ix_values.yaml is the optional setting: `startAsRoot: true`
This setting is a compatibility toggle for containers that need to be started by root, often these containers use PUID and PGID to descalate (lower) away from root but require it to start.
A minimal example ix_values.yaml would be:
```
##
# This file contains Values.yaml content that gets added to the output of questions.yaml
# It's ONLY meant for content that the user is NOT expected to change.
# Example: Everything under "image" is not included in questions.yaml but is included here.
##
image:
repository: jacobalberty/unifi
tag: 6.0.45
pullPolicy: IfNotPresent
##
# Most other defaults are set in questions.yaml
# For other options please refer to the wiki, default_values.yaml or the common library chart
##
```
##### test_values.yaml
Our Apps often use special features of TrueNAS inside questions.yaml and our charts. However these features are not (always) compatible with stock Helm. Therefore we define a set of seperate "test" values.yaml setting that get used when we run the test CI.
They should, however, be as close as possible to your "actual" default settings in questions.yaml
##### default_values.yaml
This on is the "odd one" of the bunch. We prefer not to use it for actual default, but to store default when porting charts from upstream.