Skip to content

Commit a93a44a

Browse files
authored
Add templating to porter config file (#1879)
* Add templating to porter config file Support templating in the Porter config file, e.g. ~/.porter/config.json|toml|yaml. The template syntax uses a yaml-friendly delimiiter, ${}. For example, ${env.NAME} or ${secret.NAME}. If you are using toml or json for your config file format, then you may need to use quotes around template values to ensure that the config file has valid syntax when it is loaded. We load the config file first with only environment variables substituted, then we initialize the secrets plugin, and finally do a second pass of the config file to replace any secrets. So that first pass needs to be a valid file based on the current format. For example, in a porter.toml file, secrets should be quoted: ```toml [[storage]] name = "dev" plugin = "mongodb" [storage.config] url = "${secret.connection-string}" ``` Only environment variables and secrets can be substituted. The secrets are resolved from the default secret storage. I am implementing this with the liquid template engine (from shopify that was ported to Go). I don't want us to commit to supporting liquid templates at this time, it's just an implementaiton detail that liquid is used at the moment and it could change later. Signed-off-by: Carolyn Van Slyck <me@carolynvanslyck.com> * Review feedback Signed-off-by: Carolyn Van Slyck <me@carolynvanslyck.com>
1 parent 40ae7e3 commit a93a44a

14 files changed

Lines changed: 456 additions & 138 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/docs/public/
2+
/docs/content/operator
23
/bin
34
/porter
45
.DS_Store

cmd/porter/main.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ var usageText string
2323

2424
func main() {
2525
run := func() int {
26+
ctx := context.Background()
2627
p := porter.New()
28+
if err := p.Connect(ctx); err != nil {
29+
fmt.Fprintln(os.Stderr, err.Error())
30+
os.Exit(1)
31+
}
2732

2833
rootCmd := buildRootCommandFrom(p)
2934

@@ -116,8 +121,9 @@ Try our QuickStart https://porter.sh/quickstart to learn how to use Porter.
116121
case "porter", "help", "version", "docs":
117122
return nil
118123
default:
124+
// Reload configuration with the now parsed cli flags
119125
p.DataLoader = cli.LoadHierarchicalConfig(cmd)
120-
err := p.LoadData()
126+
err := p.Connect(cmd.Context())
121127
if err != nil {
122128
return err
123129
}

docs/content/configuration.md

Lines changed: 201 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,99 +3,171 @@ title: Configuration
33
description: Controlling Porter with its config file, environment variables and flags
44
---
55

6+
Porter has a hierarchical configuration system that loads configuration values in the following precedence order:
7+
8+
* Flags (highest)
9+
* Environment Variables
10+
* Config File (lowest)
11+
12+
You may set a default value for a configuration value in the config file, override it with an environment variable, and then override both for a particular command with a flag.
13+
614
* [Flags](#flags)
715
* [Environment Variables](#environment-variables)
816
* [Config File](#config-file)
917
* [Experimental Feature Flags](#experimental-feature-flags)
1018
* [Build Drivers](#build-drivers)
1119
* [Structured Logs](#structured-logs)
20+
* [Common Configuration Settings](#common-configuration-settings)
21+
* [Set Current Namespace](#namespace)
22+
* [Enable Debug Output](#debug)
23+
* [Debug Plugins](#debug-plugins)
24+
* [Output Formatting](#output)
25+
* [Allow Docker Host Access](#allow-docker-host-access)
1226

13-
Porter's configuration system has a precedence order:
27+
## Flags
1428

15-
* Flags (highest)
16-
* Environment Variables
17-
* Config File (lowest)
29+
Nearly all of Porter's configuration, except global configuration such as secret accounts, storage accounts, or telemetry, are configurable by flags.
30+
Use the `porter help` command to view available flags.
1831

19-
You may set a default value for a configuration value in the config file,
20-
override it in a shell session with an environment variable and then override
21-
both in a particular command with a flag.
32+
## Environment Variables
2233

23-
* [Set Current Namespace](#namespace)
24-
* [Enable Debug Output](#debug)
25-
* [Debug Plugins](#debug-plugins)
26-
* [Output Formatting](#output)
27-
* [Allow Docker Host Access](#allow-docker-host-access)
34+
Flags have corresponding environment variables that you can use so that you don't need to manually set the flag every time.
35+
The flag will default to the value of the environment variable, when defined.
36+
Global configuration settings can also be specified with an environment variable.
37+
For example, the experimental config file setting maps to PORTER_EXPERIMENTAL, and accepts a comma-separated list of values.
2838

29-
## Flags
39+
\--flag maps to the environment variable of PORTER_FLAG.
40+
Dashes in the flag name are represented as underscores in the environment variable name.
41+
So \--another-flag maps to the environment variable PORTER_ANOTHER_FLAG
3042

31-
### Namespace
32-
`--namespace` specifies the current namespace.
43+
For example, you can set PORTER_OUTPUT=json and then all subsequent porter commands will act as though the \--output=json flag was passed.
3344

34-
### Debug
45+
## Config File
3546

36-
`--debug` is a flag that is understood not only by the porter client but also the
37-
runtime and most mixins. They may use it to print additional information that
38-
may be useful when you think you may have found a bug, when you want to know
39-
what commands they are executing, or when you need really verbose output to send
40-
to the developers.
47+
Porter's configuration file is located in the PORTER_HOME directory, by default ~/.porter/.
48+
The file name should be config.FILE_EXTENSION, where the file extension can be json, toml, yaml, or hcl.
49+
For example, If you defined the configuration in YAML, the file is named config.yaml.
4150

42-
### Debug Plugins
51+
Do not embed sensitive data in the configuration file.
52+
Instead, use templates to inject environment variables or secrets in the configuration file.
53+
Environment variables are specified with ${env.NAME}, where name is case-sensitive.
54+
Secrets are specified with ${secret.KEY} and case sensitivity depends upon the secrets plugin used.
4355

44-
`--debug-plugins` controls if logs related to communication
45-
between porter and its plugins should be printed when debugging. This can be _very_
46-
verbose, so it is not turned on by default when debug is true.
56+
Below is an example configuration file in TOML:
4757

48-
### Output
58+
```toml
59+
# ~/.porter/config.toml
4960

50-
`--output` controls the format of the output printed by porter. Each command
51-
supports a different set of allowed outputs though usually there is some
52-
combination of: `table`, `json` and `yaml`.
61+
# Set the default namespace
62+
namespace = "dev"
5363

54-
### Allow Docker Host Access
64+
# Include debug logs
65+
debug = true
5566

56-
`--allow-docker-host-access` controls whether the local Docker daemon
57-
should be made available to executing bundles. This flag is available for the
58-
following commands: [install], [upgrade], [invoke] and [uninstall]. When this
59-
value is set to true, bundles are executed in a privileged container with the
60-
docker socket mounted. This allows you to use Docker from within your bundle,
61-
such as `docker push`, `docker-compose`, or docker-in-docker.
67+
# Include debug logs from the plugins
68+
debug-plugins = true
6269

63-
🚨 **There are security implications to enabling access! You should trust any
64-
bundles that you execute with this setting enabled as it gives them elevated
65-
access to the host machine.**
70+
# Default command output to JSON
71+
output = "json"
6672

67-
⚠️️ This configuration setting is only available when you are in an environment
68-
that provides access to the local docker daemon. Therefore it does not work with
69-
the Azure Cloud Shell driver.
73+
# Allow all bundles access to the Docker Host
74+
allow-docker-host-access = true
7075

71-
## Environment Variables
76+
# Enable experimental v1 features
77+
experimental = ["build-drivers", "structured-logs"]
7278

73-
Flags have corresponding environment variables that you can use so that you
74-
don't need to manually set the flag every time. The flag will default to the
75-
value of the environment variable, when defined.
79+
# Use Docker buildkit to build the bundle
80+
build-driver = "buildkit"
7681

77-
`--flag` has a corresponding environment variable of `PORTER_FLAG` and `--another-flag`
78-
corresponds to the environment variable `PORTER_ANOTHER_FLAG`.
82+
# Use the storage configuration named devdb
83+
default-storage = "devdb"
84+
85+
# When default-storage is not set, use the mongodb-docker plugin.
86+
# This mode does not support additional configuration for the plugin.
87+
# If the plugin requires configuration, use default-storage and define
88+
# the configuration in the storage section.
89+
default-storage-plugin = "mongodb-docker"
90+
91+
# Use the secrets configuration named mysecrets
92+
default-secrets = "mysecrets"
93+
94+
# When default-secrets is not set, use the kubernetes.secret plugin.
95+
# This mode does not support additional configuration for the plugin.
96+
# If the plugin requires configuration, use default-secrets and define
97+
# the configuration in the secrets section.
98+
default-secrets-plugin = "kubernetes.secret"
99+
100+
# Defines storage accounts
101+
[[storage]]
102+
# The storage account name
103+
name = "devdb"
104+
105+
# The plugin used to access the storage account
106+
plugin = "mongodb"
107+
108+
# Additional configuration for storage account
109+
# These values vary depending on the plugin used
110+
[storage.config]
111+
# The mongodb connection string
112+
url = "${secret.porter-db-connection-string}"
113+
114+
# Timeout for database queries
115+
timeout = 300
116+
117+
# Define secret store accounts
118+
[[secrets]]
119+
# The secret store name
120+
name = "mysecrets"
121+
122+
# The plugin used to access the secret store account
123+
plugin = "azure.keyvault"
124+
125+
# Additional configuration for secret store account
126+
# These values vary depending on the plugin used
127+
[secrets.config]
128+
# The name of the secret vault
129+
vault = "topsecret"
130+
131+
# The subscription where the vault is defined
132+
subscription-id = "${env.AZURE_SUBSCRIPTION_ID}"
133+
134+
# Log command output to a file in PORTER_HOME/logs/
135+
[logs]
136+
# Log command output to a file
137+
enabled = true
79138

80-
For example, you can set `PORTER_DEBUG=true` and then all subsequent porter
81-
commands will act as though the `--debug` flag was passed.
139+
# Sets the log level for what is written to the file
140+
# Allowed values: debug, info, warn, error
141+
level = "info"
82142

83-
## Config File
143+
# Send trace and log data to an Open Telemetry collector
144+
[telemetry]
145+
# Enable trace collection
146+
enabled = true
84147

85-
Common settings can be defaulted in the config file. The config file is located in
86-
the PORTER_HOME directory (**~/.porter**), is named **config** and can be in any
87-
of the following file types: JSON, TOML, YAML, HCL, envfile and Java Properties
88-
files.
148+
# Send telemetry via the grpc protocol
149+
# Allowed values: http/protobuf, grpc
150+
protocol = "grpc"
89151

90-
Below is an example configuration file in TOML
152+
# The Open Telemetry collector endpoint
153+
endpoint = "127.0.0.1:4318"
91154

92-
**~/.porter/config.toml**
93-
```toml
94-
namespace = "dev"
95-
debug = true
96-
debug-plugins = true
97-
output = "json"
98-
allow-docker-host-access = true
155+
# Specify if the collector endpoint is secured with TLS
156+
insecure = true
157+
158+
# Specify a certificate to connect to the collector endpoint
159+
certificate = "/home/me/some-cert.pem"
160+
161+
# The compression type used when communicating with the collector endpoint
162+
compression = "gzip"
163+
164+
# The timeout enforced when communicating with the collector endpoint
165+
timeout = "3s"
166+
167+
# Additional headers to send to the open telemetry collector
168+
[telemetry.headers]
169+
environment = "dev"
170+
owner = "myusername"
99171
```
100172

101173
## Experimental Feature Flags
@@ -104,11 +176,11 @@ Porter sometimes uses feature flags to release new functionality for users to
104176
evaluate, without affecting the stability of Porter. You can enable an experimental
105177
feature by:
106178

107-
* Using the experimental global flag `--experimental flagA,flagB`.
179+
* Using the experimental global flag \--experimental flagA,flagB.
108180
The value is a comma-separated list of strings.
109-
* Setting the PORTER_EXPERIMENTAL environment variable like so `PORTER_EXPERIMENTAL=flagA,flagB`.
181+
* Setting the PORTER_EXPERIMENTAL environment variable like so PORTER_EXPERIMENTAL=flagA,flagB.
110182
The value is a comma-separated list of strings.
111-
* Setting the experimental field in the configuration file like so `experimental = ["flagA","flagB"]`.
183+
* Setting the experimental field in the configuration file like so experimental = ["flagA","flagB"].
112184
The value is an array of strings.
113185

114186
### Build Drivers
@@ -117,11 +189,11 @@ The **build-drivers** experimental feature flag enables using a different
117189
driver to build OCI images used by the bundle, such as the installer.
118190

119191
You can set your desired driver with either using `porter build --driver`,
120-
`PORTER_BUILD_DRIVER` environment variable, or in the configuration file with
121-
`build-driver = "DRIVER"`
192+
PORTER_BUILD_DRIVER environment variable, or in the configuration file with
193+
build-driver = "DRIVER".
122194

123-
The default driver is [Docker], and the full list of available drivers
124-
is below.
195+
The default driver is docker, and the full list of available drivers
196+
is below:
125197

126198
* **Docker**: Build an OCI image using the [Docker library], without buildkit support.
127199
This requires access to a Docker daemon, either locally or remote.
@@ -212,4 +284,62 @@ experimental = ["structured-logs"]
212284
owner = "me"
213285
```
214286

215-
[otel]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/protocol/exporter.md
287+
[otel]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.8.0/specification/protocol/exporter.md
288+
289+
## Common Configuration Settings
290+
291+
Some configuration settings are applicable to many of Porter's commands and to save time you may want to set these values in the configuration file or with environment variables.
292+
293+
### Namespace
294+
\--namespace specifies the current namespace.
295+
It is set with the PORTER_NAMESPACE environment variable.
296+
297+
```toml
298+
namespace = "dev"
299+
```
300+
301+
### Debug
302+
303+
\--debug is a flag that is understood not only by the porter client but also the runtime and most mixins.
304+
They may use it to print additional information that may be useful when you think you may have found a bug, when you want to know what commands they are executing, or when you need really verbose output to send
305+
to the developers.
306+
It is set with the PORTER_DEBUG environment variable.
307+
308+
```toml
309+
debug = true
310+
```
311+
312+
### Debug Plugins
313+
314+
\--debug-plugins controls if logs related to communication between porter and its plugins should be printed when debugging.
315+
This can be _very_ verbose, so it is not turned on by default when debug is true.
316+
It is set with the PORTER_DEBUG_PLUGINS environment variable.
317+
318+
```toml
319+
debug-plugins = true
320+
```
321+
322+
### Output
323+
324+
\--output controls the format of the command output printed by porter.
325+
It is set with the PORTER_OUTPUT environment variable.
326+
Each command supports a different set of allowed outputs though usually there is some combination of: plaintext, json, and yaml.
327+
328+
```toml
329+
output = "json"
330+
```
331+
332+
### Allow Docker Host Access
333+
334+
\--allow-docker-host-access controls whether the local Docker daemon or host should be made available to executing bundles.
335+
It is set with the PORTER_ALLOW_DOCKER_HOST_ACCESS environment variable.
336+
337+
This flag is available for the following commands: install, upgrade, invoke, and uninstall.
338+
When this value is set to true, bundles are executed in a privileged container with the docker socket mounted.
339+
This allows you to use Docker from within your bundle, such as `docker push`, `docker-compose`, or docker-in-docker.
340+
341+
🚨 **There are security implications to enabling access!
342+
You should trust any bundles that you execute with this setting enabled as it gives them elevated access to the host machine.**
343+
344+
⚠️️ This configuration setting is only available when you are in an environment that provides access to the local docker daemon.
345+
Therefore, it does not work with the Azure Cloud Shell driver.

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ replace (
1919
// go.mod doesn't propogate replacements in the dependency graph so I'm copying this from github.com/moby/buildkit
2020
github.com/jaguilar/vt100 => github.com/tonistiigi/vt100 v0.0.0-20190402012908-ad4c4a574305
2121

22+
// expose-ast
23+
// https://github.com/osteele/liquid/pull/59
24+
github.com/osteele/liquid => github.com/carolynvs/liquid v1.2.5-0.20220131221838-2e107bef298f
25+
2226
// Fixes https://github.com/spf13/viper/issues/761
2327
github.com/spf13/viper => github.com/getporter/viper v1.7.1-porter.2.0.20210514172839-3ea827168363
2428
)
@@ -61,6 +65,7 @@ require (
6165
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635
6266
github.com/olekukonko/tablewriter v0.0.4
6367
github.com/opencontainers/go-digest v1.0.0
68+
github.com/osteele/liquid v1.2.4
6469
github.com/pelletier/go-toml v1.9.1
6570
github.com/pivotal/image-relocation v0.0.0-20191111101224-e94aff6df06c
6671
github.com/pkg/errors v0.9.1

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ github.com/carolynvs/cnab-go v0.20.2-0.20210805155536-9a543e0636f4 h1:w6gndqIhqX
251251
github.com/carolynvs/cnab-go v0.20.2-0.20210805155536-9a543e0636f4/go.mod h1:u/Y7piTNJuFs2KfQqmda6uqIx4rtqQ73H6IW7gudz7E=
252252
github.com/carolynvs/datetime-printer v0.2.0 h1:Td3FU4YGzx0OogCMhCmLBTUTDPQcq0xlgCeMhAKZmMc=
253253
github.com/carolynvs/datetime-printer v0.2.0/go.mod h1:p9W8ZUhmQUOVD5kiDuGXwRG65/nTkZWlLylY7s+Qw2k=
254+
github.com/carolynvs/liquid v1.2.5-0.20220131221838-2e107bef298f h1:VQBTZqr7lKJ7I5aibSzwlDd9QiPIJ2vZCYlHB4tUfuQ=
255+
github.com/carolynvs/liquid v1.2.5-0.20220131221838-2e107bef298f/go.mod h1:w8U5mURyI2WkBkOqadQ8C2W+oK+8TDGwo8V612sRSAI=
254256
github.com/carolynvs/magex v0.6.0 h1:rzz4RnBiR8hr2WYEsmq+mqkRLEstPnEK8ZP9MgxNY9Y=
255257
github.com/carolynvs/magex v0.6.0/go.mod h1:hqaEkr9TAv+kFb/5wgDiTdszF13rpe0Q+bWHmTe6N74=
256258
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
@@ -1184,6 +1186,8 @@ github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm
11841186
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
11851187
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
11861188
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
1189+
github.com/osteele/tuesday v1.0.3 h1:SrCmo6sWwSgnvs1bivmXLvD7Ko9+aJvvkmDjB5G4FTU=
1190+
github.com/osteele/tuesday v1.0.3/go.mod h1:pREKpE+L03UFuR+hiznj3q7j3qB1rUZ4XfKejwWFF2M=
11871191
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
11881192
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
11891193
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=

0 commit comments

Comments
 (0)