Skip to content

Commit cc321b2

Browse files
Add yaml example that does math and uses pulumi-std functions (#1738)
In addition to programming languages such as Python, Go, Typescript, C#, Pulumi also supports YAML. However, YAML is limited when it comes to constructs such as loops and conditionals and it is not always obvious how one can do math in a Pulumi YAML program. Similarly, using the `pulumi-std` library can be a little tricky. This project is meant to provide some YAML program examples for these use-cases.
1 parent 549de02 commit cc321b2

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

yaml-math-and-objects/Pulumi.yaml

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
name: yaml-math-and-objects
2+
description: A Pulumi YAML program that demonstrates how to do math and manipulate objects in YAML.
3+
runtime: yaml
4+
5+
## Stack Config
6+
config:
7+
# The length of the string to generate.
8+
length:
9+
type: integer
10+
default: 16
11+
# When this config is set to true, we then want to implement some logic related to the string generation.
12+
useLowerCase:
13+
type: boolean
14+
default: true
15+
# An array of key-value pairs as strings used to build the keepers map array.
16+
configKeepersArray:
17+
type: array
18+
items:
19+
type: string
20+
default:
21+
- "configKey1:configValue1"
22+
- "configKey2:configValue2"
23+
24+
25+
## Variables used by the RandomString resource below constructed from the config and functions and a little help from the Command resource.
26+
variables:
27+
# Get the length from the config.
28+
stringLength: ${length}
29+
30+
# Build keepersArrayPart1 using the structured config (which is limited to an array of strings) by leveraging pulumi-std functions
31+
# to build the requisite map array.
32+
keepersArrayPart1:
33+
# Build the required map array from an array of strings such that each pair of strings is used to create the key-value pair.
34+
fn::invoke:
35+
function: std:map
36+
arguments:
37+
args:
38+
# Split the string of strings created by joining the array of strings from the config.
39+
# This is needed for the map function to build the array of key-value pairs.
40+
fn::invoke:
41+
function: std:split
42+
arguments:
43+
separator: ":"
44+
text:
45+
# Build one big string of strings from the array of strings in the config.
46+
fn::invoke:
47+
function: std:join
48+
arguments:
49+
# The array of strings from the config.
50+
input: ${configKeepersArray}
51+
separator: ":"
52+
return: result
53+
return: result
54+
return: result
55+
56+
# Hard-coded map for the second part of the keepers array to have something to merge.
57+
keepersArrayPart2:
58+
part2aKey: "part2aValue"
59+
part2bKey: "part2bValue"
60+
61+
# Combine the two parts of the keepers map arrays into a single map array to be used in the RandomString resource.
62+
keepersArrayCombined:
63+
fn::invoke:
64+
function: std:merge
65+
arguments:
66+
input:
67+
- ${keepersArrayPart1}
68+
- ${keepersArrayPart2}
69+
return: result
70+
71+
# Lowercase settings object to use for the RandomString resource.
72+
lowerCaseSettings:
73+
# Just passing along the config value as part of this variable.
74+
uselower: ${useLowerCase}
75+
# Want to only set minLower based on length and only set it if useLowerCase is true.
76+
# Since we don't have a way to run logic and math in YAML, we can use the Pulumi Command resource (see below) to do this.
77+
# But we need to use the srd-pareint function to convert the string output from the Command resource to an integer for the RandomString resource.
78+
minLower:
79+
fn::invoke:
80+
function: std:parseint
81+
arguments:
82+
input: ${calculateMinLower.stdout}
83+
return: result
84+
85+
## Resources
86+
resources:
87+
# Creating a RandomString resource (https://www.pulumi.com/registry/packages/random/api-docs/randomstring/)
88+
randomString:
89+
type: random:RandomString
90+
properties:
91+
# Must be a number. Taken from config.
92+
length: ${stringLength}
93+
# Must be an array of key-value pairs. Built from the config and hard-coded values (see above).
94+
keepers: ${keepersArrayCombined}
95+
# Must be a boolean. Taken from config.
96+
lower: ${lowerCaseSettings.uselower}
97+
# Must be a number. Calculated value based on boolean logic and math using the Command provider (see below).
98+
minLower: ${lowerCaseSettings.minLower}
99+
100+
# Since we don't yet have math operations (other than `sum`) in YAML,
101+
# see https://github.com/pulumi/pulumi-std/issues/70
102+
# we can use the Pulumi Command resource to do math.
103+
# The output is then referenced by the `lowerCaseSettings` variable.
104+
calculateMinLower:
105+
type: command:local:Command
106+
properties:
107+
# we want about a quarter of the password to be lowercase letters if useLowerCase is true.
108+
create: if ${useLowerCase}; then echo "${stringLength} / 4" | bc; else echo 0; fi
109+
110+
111+
# Stack outputs
112+
outputs:
113+
# Generated string
114+
randomString: ${randomString.result}
115+
# Lowercase settings reflecting the config-based value and the calculated minLower value.
116+
lowerCaseSettings: ${lowerCaseSettings}
117+
# The keepers array that was built using the config and hard-coded values.
118+
keepersArrayCombined: ${keepersArrayCombined}

yaml-math-and-objects/README.md

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Math and Collection and String Manipulation in YAML
2+
3+
In addition to programming languages such as Python, Go, Typescript, C#, Pulumi also supports YAML.
4+
However, YAML is limited when it comes to constructs such as loops and conditionals and it is not always obvious how one can do math in a Pulumi YAML program.
5+
Similarly, using the `pulumi-std` library can be a little tricky.
6+
7+
This project is meant to provide some YAML program examples for these use-cases.
8+
9+
## References
10+
* [Pulumi YAML Docs Page](https://www.pulumi.com/docs/iac/languages-sdks/yaml/)
11+
* [Pulumi YAML Language Reference](https://www.pulumi.com/docs/iac/languages-sdks/yaml/yaml-language-reference/)
12+
* [pulum-std Function List](https://github.com/pulumi/pulumi-std/blob/master/FUNCTION_LIST.md)
13+
* These are functions that are available to YAML programs.
14+
15+
## Tips and Tricks for Using the pulumi-std Functions
16+
Start with the functions list page in the `pulumi-std` repo, [pulum-std Function List](https://github.com/pulumi/pulumi-std/blob/master/FUNCTION_LIST.md)
17+
Here you will find the list of functions that are available.
18+
19+
To understand how to use a given function, click on the link from the function list page.
20+
This will take you to the go code for the function.
21+
From here you can learn two important things:
22+
* What the function does.
23+
* What the function's input parameters are.
24+
25+
To understand what the function does, look for the `Annotate` function code block. This will provide an explanation of what the function does.
26+
27+
To understand the function's inputs, look for the `...Args` structure code block. This will list the inputs' names and types (e.g. string, array, etc).
28+
29+
For example, look at [std-merge](https://github.com/pulumi/pulumi-std/blob/master/std/merge.go).
30+
You'll see it expects a single parameter named `input` that is an array of map of strings.
31+
So something like: `[goo:"foo", moo:"boo"]` and if you look at the Pulumi YAML program in this folder you'll see how that is represented in YAML.
32+
33+
Now, look at [std-split](https://github.com/pulumi/pulumi-std/blob/master/std/split.go) and you'll see it wants two parameters: `separator` and `text`.
34+
35+
## Using the Pulumi Program
36+
Read the `Pulumi.yaml` file to see what the program does and how it does it.
37+
38+
Then, from the folder containing the program:
39+
```bash
40+
$ pulumi stack init dev
41+
$ pulumi up
42+
```
43+
44+
This creates a random string and outputs some values used in the code.
45+
46+
Now, tinker with the stack config values in `Pulumi.yaml` or via `pulumi config set` commands to see what happens when you:
47+
* Change the length of the string.
48+
* Change `length` to, say, `32`
49+
* Run `pulumi up` and you should see that `minLower` is now set to one-fourth(ish) of whatever value you set for the length and there are at least that many lowercase letters in the string.
50+
* Disable using lowercase characters.
51+
* Change `useLowerCase` to `false`
52+
* Run `pulumi up` and you should see that there are no lowercase characters and the stack output show `minLower` set to 0.
53+
* Change one of the key-value pairs in `configKeepersArray`.
54+
* Run `pulumi up` and see that the array map is updated and that a new string is generated since that's what the `keepers` property is for - to trigger a regeneration of the key even though no property directly related to the resource like length, etc is changed..

0 commit comments

Comments
 (0)