Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add yaml example that does math and uses pulumi-std functions #1738

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions yaml-math-and-objects/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: yaml-math-and-objects
description: A Pulumi YAML program that demonstrates how to do math and manipulate objects in YAML.
runtime: yaml

## Stack Config
config:
# The length of the string to generate.
length:
type: integer
default: 16
# When this config is set to true, we then want to implement some logic related to the string generation.
useLowerCase:
type: boolean
default: true
# An array of key-value pairs as strings used to build the keepers map array.
configKeepersArray:
type: array
items:
type: string
default:
- "configKey1:configValue1"
- "configKey2:configValue2"


## Variables used by the RandomString resource below constructed from the config and functions and a little help from the Command resource.
variables:
# Get the length from the config.
stringLength: ${length}

# Build keepersArrayPart1 using the structured config (which is limited to an array of strings) by leveraging pulumi-std functions
# to build the requisite map array.
keepersArrayPart1:
# Build the required map array from an array of strings such that each pair of strings is used to create the key-value pair.
fn::invoke:
function: std:map
arguments:
args:
# Split the string of strings created by joining the array of strings from the config.
# This is needed for the map function to build the array of key-value pairs.
fn::invoke:
function: std:split
arguments:
separator: ":"
text:
# Build one big string of strings from the array of strings in the config.
fn::invoke:
function: std:join
arguments:
# The array of strings from the config.
input: ${configKeepersArray}
separator: ":"
return: result
return: result
return: result

# Hard-coded map for the second part of the keepers array to have something to merge.
keepersArrayPart2:
part2aKey: "part2aValue"
part2bKey: "part2bValue"

# Combine the two parts of the keepers map arrays into a single map array to be used in the RandomString resource.
keepersArrayCombined:
fn::invoke:
function: std:merge
arguments:
input:
- ${keepersArrayPart1}
- ${keepersArrayPart2}
return: result

# Lowercase settings object to use for the RandomString resource.
lowerCaseSettings:
# Just passing along the config value as part of this variable.
uselower: ${useLowerCase}
# Want to only set minLower based on length and only set it if useLowerCase is true.
# 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.
# 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.
minLower:
fn::invoke:
function: std:parseint
arguments:
input: ${calculateMinLower.stdout}
return: result

## Resources
resources:
# Creating a RandomString resource (https://www.pulumi.com/registry/packages/random/api-docs/randomstring/)
randomString:
type: random:RandomString
properties:
# Must be a number. Taken from config.
length: ${stringLength}
# Must be an array of key-value pairs. Built from the config and hard-coded values (see above).
keepers: ${keepersArrayCombined}
# Must be a boolean. Taken from config.
lower: ${lowerCaseSettings.uselower}
# Must be a number. Calculated value based on boolean logic and math using the Command provider (see below).
minLower: ${lowerCaseSettings.minLower}

# Since we don't yet have math operations (other than `sum`) in YAML,
# see https://github.com/pulumi/pulumi-std/issues/70
# we can use the Pulumi Command resource to do math.
# The output is then referenced by the `lowerCaseSettings` variable.
calculateMinLower:
type: command:local:Command
properties:
# we want about a quarter of the password to be lowercase letters if useLowerCase is true.
create: if ${useLowerCase}; then echo "${stringLength} / 4" | bc; else echo 0; fi


# Stack outputs
outputs:
# Generated string
randomString: ${randomString.result}
# Lowercase settings reflecting the config-based value and the calculated minLower value.
lowerCaseSettings: ${lowerCaseSettings}
# The keepers array that was built using the config and hard-coded values.
keepersArrayCombined: ${keepersArrayCombined}
54 changes: 54 additions & 0 deletions yaml-math-and-objects/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Math and Collection and String Manipulation in YAML

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.

## References
* [Pulumi YAML Docs Page](https://www.pulumi.com/docs/iac/languages-sdks/yaml/)
* [Pulumi YAML Language Reference](https://www.pulumi.com/docs/iac/languages-sdks/yaml/yaml-language-reference/)
* [pulum-std Function List](https://github.com/pulumi/pulumi-std/blob/master/FUNCTION_LIST.md)
* These are functions that are available to YAML programs.

## Tips and Tricks for Using the pulumi-std Functions
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)
Here you will find the list of functions that are available.

To understand how to use a given function, click on the link from the function list page.
This will take you to the go code for the function.
From here you can learn two important things:
* What the function does.
* What the function's input parameters are.

To understand what the function does, look for the `Annotate` function code block. This will provide an explanation of what the function does.

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).

For example, look at [std-merge](https://github.com/pulumi/pulumi-std/blob/master/std/merge.go).
You'll see it expects a single parameter named `input` that is an array of map of strings.
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.

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`.

## Using the Pulumi Program
Read the `Pulumi.yaml` file to see what the program does and how it does it.

Then, from the folder containing the program:
```bash
$ pulumi stack init dev
$ pulumi up
```

This creates a random string and outputs some values used in the code.

Now, tinker with the stack config values in `Pulumi.yaml` or via `pulumi config set` commands to see what happens when you:
* Change the length of the string.
* Change `length` to, say, `32`
* 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.
* Disable using lowercase characters.
* Change `useLowerCase` to `false`
* Run `pulumi up` and you should see that there are no lowercase characters and the stack output show `minLower` set to 0.
* Change one of the key-value pairs in `configKeepersArray`.
* 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..
Loading