diff --git a/yaml-math-and-objects/Pulumi.yaml b/yaml-math-and-objects/Pulumi.yaml new file mode 100644 index 000000000..f6d69d8d9 --- /dev/null +++ b/yaml-math-and-objects/Pulumi.yaml @@ -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} diff --git a/yaml-math-and-objects/README.md b/yaml-math-and-objects/README.md new file mode 100644 index 000000000..f0de423e5 --- /dev/null +++ b/yaml-math-and-objects/README.md @@ -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..