This change adds support for lists and maps in config. We now allow lists/maps (and nested structures) in `Pulumi.<stack>.yaml` (or `Pulumi.<stack>.json`; yes, we currently support that). For example: ```yaml config: proj:blah: - a - b - c proj:hello: world proj:outer: inner: value proj:servers: - port: 80 ``` While such structures could be specified in the `.yaml` file manually, we support setting values in maps/lists from the command line. As always, you can specify single values with: ```shell $ pulumi config set hello world ``` Which results in the following YAML: ```yaml proj:hello world ``` And single value secrets via: ```shell $ pulumi config set --secret token shhh ``` Which results in the following YAML: ```yaml proj:token: secure: v1:VZAhuroR69FkEPTk:isKafsoZVMWA9pQayGzbWNynww== ``` Values in a list can be set from the command line using the new `--path` flag, which indicates the config key contains a path to a property in a map or list: ```shell $ pulumi config set --path names[0] a $ pulumi config set --path names[1] b $ pulumi config set --path names[2] c ``` Which results in: ```yaml proj:names - a - b - c ``` Values can be obtained similarly: ```shell $ pulumi config get --path names[1] b ``` Or setting values in a map: ```shell $ pulumi config set --path outer.inner value ``` Which results in: ```yaml proj:outer: inner: value ``` Of course, setting values in nested structures is supported: ```shell $ pulumi config set --path servers[0].port 80 ``` Which results in: ```yaml proj:servers: - port: 80 ``` If you want to include a period in the name of a property, it can be specified as: ``` $ pulumi config set --path 'nested["foo.bar"]' baz ``` Which results in: ```yaml proj:nested: foo.bar: baz ``` Examples of valid paths: - root - root.nested - 'root["nested"]' - root.double.nest - 'root["double"].nest' - 'root["double"]["nest"]' - root.array[0] - root.array[100] - root.array[0].nested - root.array[0][1].nested - root.nested.array[0].double[1] - 'root["key with \"escaped\" quotes"]' - 'root["key with a ."]' - '["root key with \"escaped\" quotes"].nested' - '["root key with a ."][100]' Note: paths that contain quotes can be surrounded by single quotes. When setting values with `--path`, if the value is `"false"` or `"true"`, it will be saved as the boolean value, and if it is convertible to an integer, it will be saved as an integer. Secure values are supported in lists/maps as well: ```shell $ pulumi config set --path --secret tokens[0] shh ``` Will result in: ```yaml proj:tokens: - secure: v1:wpZRCe36sFg1RxwG:WzPeQrCn4n+m4Ks8ps15MxvFXg== ``` Note: maps of length 1 with a key of “secure” and string value are reserved for storing secret values. Attempting to create such a value manually will result in an error: ```shell $ pulumi config set --path parent.secure foo error: "secure" key in maps of length 1 are reserved ``` **Accessing config values from the command line with JSON** ```shell $ pulumi config --json ``` Will output: ```json { "proj:hello": { "value": "world", "secret": false, "object": false }, "proj:names": { "value": "[\"a\",\"b\",\"c\"]", "secret": false, "object": true, "objectValue": [ "a", "b", "c" ] }, "proj:nested": { "value": "{\"foo.bar\":\"baz\"}", "secret": false, "object": true, "objectValue": { "foo.bar": "baz" } }, "proj:outer": { "value": "{\"inner\":\"value\"}", "secret": false, "object": true, "objectValue": { "inner": "value" } }, "proj:servers": { "value": "[{\"port\":80}]", "secret": false, "object": true, "objectValue": [ { "port": 80 } ] }, "proj:token": { "secret": true, "object": false }, "proj:tokens": { "secret": true, "object": true } } ``` If the value is a map or list, `"object"` will be `true`. `"value"` will contain the object as serialized JSON and a new `"objectValue"` property will be available containing the value of the object. If the object contains any secret values, `"secret"` will be `true`, and just like with scalar values, the value will not be outputted unless `--show-secrets` is specified. **Accessing config values from Pulumi programs** Map/list values are available to Pulumi programs as serialized JSON, so the existing `getObject`/`requireObject`/`getSecretObject`/`requireSecretObject` functions can be used to retrieve such values, e.g.: ```typescript import * as pulumi from "@pulumi/pulumi"; interface Server { port: number; } const config = new pulumi.Config(); const names = config.requireObject<string[]>("names"); for (const n of names) { console.log(n); } const servers = config.requireObject<Server[]>("servers"); for (const s of servers) { console.log(s.port); } ```
53 lines
1.5 KiB
Python
53 lines
1.5 KiB
Python
# Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
|
|
|
import pulumi
|
|
|
|
# Just test that basic config works.
|
|
config = pulumi.Config('config_basic_py')
|
|
|
|
# This value is plaintext and doesn't require encryption.
|
|
value = config.require('aConfigValue')
|
|
assert value == 'this value is a Pythonic value'
|
|
|
|
# This value is a secret and is encrypted using the passphrase `supersecret`.
|
|
secret = config.require('bEncryptedSecret')
|
|
assert secret == 'this super Pythonic secret is encrypted'
|
|
|
|
test_data = [
|
|
{
|
|
'key': 'outer',
|
|
'expected_json': '{"inner":"value"}',
|
|
'expected_object': { 'inner': 'value' }
|
|
},
|
|
{
|
|
'key': 'names',
|
|
'expected_json': '["a","b","c","super secret name"]',
|
|
'expected_object': ['a', 'b', 'c', 'super secret name']
|
|
},
|
|
{
|
|
'key': 'servers',
|
|
'expected_json': '[{"host":"example","port":80}]',
|
|
'expected_object': [{ 'host': 'example', 'port': 80 }]
|
|
},
|
|
{
|
|
'key': 'a',
|
|
'expected_json': '{"b":[{"c":true},{"c":false}]}',
|
|
'expected_object': { 'b': [{ 'c': True }, { 'c': False }] }
|
|
},
|
|
{
|
|
'key': 'tokens',
|
|
'expected_json': '["shh"]',
|
|
'expected_object': ['shh']
|
|
},
|
|
{
|
|
'key': 'foo',
|
|
'expected_json': '{"bar":"don\'t tell"}',
|
|
'expected_object': { 'bar': "don't tell" }
|
|
}
|
|
]
|
|
|
|
for test in test_data:
|
|
json = config.require(test['key'])
|
|
obj = config.require_object(test['key'])
|
|
assert json == test['expected_json']
|
|
assert obj == test['expected_object']
|