Skip to content
49 changes: 30 additions & 19 deletions modules/meshstack/noop/buildingblock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,30 @@ Use it to:

## Input Types

| Input | Type | Assignment | Description |
|-------------------------|----------------------|----------------------------------|--------------------------------------------------------------------------------------------------------------------|
| Input | Type | Assignment | Description |
|---------------------------|----------------------|----------------------------------|-----------------------------------------------------------------------------------------------------------------------|
| `author` | `CODE` | `AUTHOR` | The principal that ordered the block, injected by meshStack |
| `user_permissions` | `CODE` | `USER_PERMISSIONS` | Project team members and their roles as a structured list |
| `user_permissions_json` | `CODE` | `USER_PERMISSIONS` | Same as above, as a raw JSON string |
| `user_permissions` | `CODE` | `USER_PERMISSIONS` | Project team members and their roles as a structured list |
| `user_permissions_json` | `CODE` | `USER_PERMISSIONS` | Same as above, as a raw JSON string |
| `workspace_identifier` | `STRING` | `WORKSPACE_IDENTIFIER` | Identifier of the workspace the block belongs to, injected by meshStack |
| `sensitive_yaml` | `CODE` | `STATIC` (sensitive) | Encrypted YAML/JSON value, decrypted at runtime |
| `static` | `STRING` | `STATIC` | A platform-engineer-defined string constant |
| `static_code` | `CODE` | `STATIC` | A platform-engineer-defined map |
| `flag` | `BOOLEAN` | `USER_INPUT` | Boolean flag chosen by the user |
| `num` | `INTEGER` | `USER_INPUT` | Integer chosen by the user |
| `text` | `STRING` | `USER_INPUT` | Free-text string from the user |
| `optional_text` | `STRING` | `USER_INPUT` | Optional string — can be omitted from the building block's inputs so the Terraform variable's default takes effect |
| `sensitive_text` | `STRING` (sensitive) | `USER_INPUT` | Sensitive string, masked in UI and logs |
| `single_select` | `SINGLE_SELECT` | `USER_INPUT` | One value from a predefined list |
| `multi_select` | `MULTI_SELECT` | `USER_INPUT` | One or more values from a predefined list |
| `multi_select_json` | `MULTI_SELECT` | `USER_INPUT` | Same as above, as a raw JSON string |
| `sensitive_yaml` | `CODE` | `STATIC` (sensitive) | Encrypted YAML/JSON value, decrypted at runtime |
| `static` | `STRING` | `STATIC` | A platform-engineer-defined string constant |
| `static_code` | `CODE` | `STATIC` | A platform-engineer-defined map |
| `tag_value` | `CODE` | `TAG` | Value of a meshStack tag, read from the target object rather than typed in by a user |
Comment thread
Jelledb marked this conversation as resolved.
| `flag` | `BOOLEAN` | `USER_INPUT` | Boolean flag chosen by the user |
| `num` | `INTEGER` | `USER_INPUT` | Integer chosen by the user |
| `text` | `STRING` | `USER_INPUT` | Free-text string from the user |
| `optional_text` | `STRING` | `USER_INPUT` | Optional string — can be omitted from the building block's inputs so the Terraform variable's default takes effect |
| `conditional_text` | `STRING` | `USER_INPUT` | Its `condition` (`input.flag == true`) holds, so it is asked for and its value flows through |
| `hidden_conditional_text` | `STRING` | `USER_INPUT` | Its `condition` (`input.flag == false`) never holds here, so it stays hidden and can be skipped |
| `deploy_settings` | `JSON` | `USER_INPUT` | Filled in through a meshPanel form declared by `json_schema`, decoded into the Terraform variable's declared object type |
| `sensitive_text` | `STRING` (sensitive) | `USER_INPUT` | Sensitive string, masked in UI and logs |
| `single_select` | `SINGLE_SELECT` | `USER_INPUT` | One value from a predefined list |
| `multi_select` | `MULTI_SELECT` | `USER_INPUT` | One or more values from a predefined list |
| `multi_select_json` | `MULTI_SELECT` | `USER_INPUT` | Same as above, as a raw JSON string |
| `operator_text` | `STRING` | `PLATFORM_OPERATOR_MANUAL_INPUT` | Only a platform operator can fill this in; a block missing it parks in `WAITING_FOR_OPERATOR_INPUT` |
| `some-file.yaml` | `FILE` | `STATIC` | Written to working directory; read via `file("some-file.yaml")` |
| `sensitive-file.yaml` | `FILE` | `STATIC` (sensitive) | Like above, encrypted at rest |
| `some-file.yaml` | `FILE` | `STATIC` | Written to working directory; read via `file("some-file.yaml")` |
| `sensitive-file.yaml` | `FILE` | `STATIC` (sensitive) | Like above, encrypted at rest |

## Output Assignment Types

Expand All @@ -65,8 +69,7 @@ meshStack's remaining input and output kinds cannot be exercised here, for two r
only thing it feeds is a tenant's console link and a workspace has no tenant. A test that reads
the output back still passes, so declaring one here would look like coverage and prove nothing.
- **Needs setup beyond this module.** `BUILDING_BLOCK_OUTPUT` needs a second definition to read an
output from, and `TAG` needs a tag definition in the instance's tag schema plus a tag value on the
workspace.
output from.

`LIST` is deprecated in favour of `CODE`, so it is deliberately absent.

Expand Down Expand Up @@ -105,7 +108,10 @@ No modules.
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_author"></a> [author](#input\_author) | Principal that ordered this building block, injected by the AUTHOR assignment type. | <pre>object({<br/> type = string<br/> identifier = string<br/> displayName = string<br/> username = optional(string)<br/> email = optional(string)<br/> euid = optional(string)<br/> })</pre> | n/a | yes |
| <a name="input_conditional_text"></a> [conditional\_text](#input\_conditional\_text) | n/a | `string` | `"tf-default-value"` | no |
| <a name="input_deploy_settings"></a> [deploy\_settings](#input\_deploy\_settings) | n/a | <pre>object({<br/> greeting = string<br/> shout = optional(bool)<br/> })</pre> | n/a | yes |
| <a name="input_flag"></a> [flag](#input\_flag) | n/a | `bool` | n/a | yes |
| <a name="input_hidden_conditional_text"></a> [hidden\_conditional\_text](#input\_hidden\_conditional\_text) | n/a | `string` | `"tf-default-value"` | no |
| <a name="input_multi_select"></a> [multi\_select](#input\_multi\_select) | n/a | `list(string)` | n/a | yes |
| <a name="input_multi_select_json"></a> [multi\_select\_json](#input\_multi\_select\_json) | n/a | `string` | n/a | yes |
| <a name="input_num"></a> [num](#input\_num) | n/a | `number` | n/a | yes |
Expand All @@ -116,6 +122,7 @@ No modules.
| <a name="input_single_select"></a> [single\_select](#input\_single\_select) | n/a | `string` | n/a | yes |
| <a name="input_static"></a> [static](#input\_static) | n/a | `string` | n/a | yes |
| <a name="input_static_code"></a> [static\_code](#input\_static\_code) | n/a | `map(string)` | n/a | yes |
| <a name="input_tag_value"></a> [tag\_value](#input\_tag\_value) | n/a | `list(string)` | n/a | yes |
| <a name="input_text"></a> [text](#input\_text) | n/a | `string` | n/a | yes |
| <a name="input_user_permissions"></a> [user\_permissions](#input\_user\_permissions) | n/a | <pre>list(object({<br/> meshIdentifier = string<br/> username = string<br/> firstName = string<br/> lastName = string<br/> email = string<br/> euid = string<br/> roles = list(string)<br/> }))</pre> | n/a | yes |
| <a name="input_user_permissions_json"></a> [user\_permissions\_json](#input\_user\_permissions\_json) | n/a | `string` | n/a | yes |
Expand All @@ -126,9 +133,12 @@ No modules.
| Name | Description |
|------|-------------|
| <a name="output_author"></a> [author](#output\_author) | n/a |
| <a name="output_conditional_text"></a> [conditional\_text](#output\_conditional\_text) | n/a |
| <a name="output_debug_input_files_json"></a> [debug\_input\_files\_json](#output\_debug\_input\_files\_json) | JSON-encoded map of all input files received, including sensitive values in plaintext. |
| <a name="output_debug_input_variables_json"></a> [debug\_input\_variables\_json](#output\_debug\_input\_variables\_json) | JSON-encoded map of all input variables received, including sensitive values in plaintext. |
| <a name="output_deploy_settings"></a> [deploy\_settings](#output\_deploy\_settings) | n/a |
| <a name="output_flag"></a> [flag](#output\_flag) | n/a |
| <a name="output_hidden_conditional_text"></a> [hidden\_conditional\_text](#output\_hidden\_conditional\_text) | n/a |
| <a name="output_multi_select"></a> [multi\_select](#output\_multi\_select) | n/a |
| <a name="output_multi_select_json"></a> [multi\_select\_json](#output\_multi\_select\_json) | n/a |
| <a name="output_num"></a> [num](#output\_num) | n/a |
Expand All @@ -143,6 +153,7 @@ No modules.
| <a name="output_static"></a> [static](#output\_static) | n/a |
| <a name="output_static_code"></a> [static\_code](#output\_static\_code) | n/a |
| <a name="output_summary"></a> [summary](#output\_summary) | n/a |
| <a name="output_tag_value"></a> [tag\_value](#output\_tag\_value) | n/a |
| <a name="output_text"></a> [text](#output\_text) | n/a |
| <a name="output_user_permissions"></a> [user\_permissions](#output\_user\_permissions) | n/a |
| <a name="output_user_permissions_json"></a> [user\_permissions\_json](#output\_user\_permissions\_json) | n/a |
Expand Down
52 changes: 36 additions & 16 deletions modules/meshstack/noop/buildingblock/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ output "static_code" {
value = var.static_code
}

output "tag_value" {
value = var.tag_value
}

output "flag" {
value = var.flag
}
Expand All @@ -46,6 +50,18 @@ output "optional_text" {
value = var.optional_text
}

output "conditional_text" {
value = var.conditional_text
}

output "hidden_conditional_text" {
value = var.hidden_conditional_text
}

output "deploy_settings" {
value = var.deploy_settings
}

output "sensitive_text" {
value = var.sensitive_text
sensitive = true
Expand Down Expand Up @@ -117,22 +133,26 @@ output "debug_input_variables_json" {
description = "JSON-encoded map of all input variables received, including sensitive values in plaintext."
sensitive = true # For test only. Do not do this in production code.
value = jsonencode({
flag = var.flag
num = var.num
text = var.text
optional_text = var.optional_text
single_select = var.single_select
sensitive_text = var.sensitive_text
sensitive_yaml = var.sensitive_yaml
multi_select = var.multi_select
multi_select_json = var.multi_select_json
static = var.static
static_code = var.static_code
user_permissions = var.user_permissions
user_permissions_json = var.user_permissions_json
author = var.author
operator_text = var.operator_text
workspace_identifier = var.workspace_identifier
flag = var.flag
num = var.num
text = var.text
optional_text = var.optional_text
conditional_text = var.conditional_text
hidden_conditional_text = var.hidden_conditional_text
deploy_settings = var.deploy_settings
single_select = var.single_select
sensitive_text = var.sensitive_text
sensitive_yaml = var.sensitive_yaml
multi_select = var.multi_select
multi_select_json = var.multi_select_json
static = var.static
static_code = var.static_code
tag_value = var.tag_value
user_permissions = var.user_permissions
user_permissions_json = var.user_permissions_json
author = var.author
operator_text = var.operator_text
workspace_identifier = var.workspace_identifier
})
}

Expand Down
29 changes: 29 additions & 0 deletions modules/meshstack/noop/buildingblock/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ variable "static_code" {
type = map(string)
}

variable "tag_value" {
# meshStack sends a TAG input as a JSON array of strings; a tag with no value resolves to null.
type = list(string)
nullable = true
}
Comment thread
Jelledb marked this conversation as resolved.

variable "flag" {
type = bool
}
Expand All @@ -44,6 +50,29 @@ variable "optional_text" {
default = "tf-default-value"
}

variable "conditional_text" {
# Sent only while its BBD `condition` holds; falls back to this default otherwise, exactly like optional_text.
type = string
default = "tf-default-value"
}

variable "hidden_conditional_text" {
# Its BBD `condition` (`input.flag == false`) never holds in this module's e2e tests, since flag
# is always true there, so this default is what every run actually uses.
type = string
default = "tf-default-value"
}

variable "deploy_settings" {
# meshStack decodes a JSON-type input into the Terraform variable's declared type, matching the
# shape of the json_schema below — same as a CODE input decodes into whatever type its variable
# declares (see tag_value, static_code).
type = object({
greeting = string
shout = optional(bool)
})
}

variable "sensitive_text" {
type = string
sensitive = true
Expand Down
38 changes: 38 additions & 0 deletions modules/meshstack/noop/e2e/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ variable "test_context" {
nullable = false
}

# A tag input reads its value from an existing meshStack tag, so the e2e test provisions its own
# tag definition and sets it on the test workspace to exercise the input end-to-end. It cannot be
# destroyed while the building block definition below reads it, so referencing its `spec.key` from
# the module's `tag_key` input (and the workspace tag depending on the definition) gets destroy
# order right on its own.
resource "meshstack_tag_definition" "noop_e2e" {
spec = {
target_kind = "meshWorkspace"
key = "noop-e2e-tag-${var.test_context.run_id}"
display_name = "NoOp E2E Tag"
value_type = { string = {} }
}
}

resource "meshstack_workspace_tag" "noop_e2e" {
metadata = {
workspace_identifier = var.test_context.workspace
key = meshstack_tag_definition.noop_e2e.spec.key
}
Comment thread
Jelledb marked this conversation as resolved.
spec = {
values = ["e2e-tag-value"]
}
}

module "noop" {
source = "../"

Expand All @@ -21,9 +45,14 @@ module "noop" {
git_ref = var.test_context.hub_git_ref
bbd_draft = true
}
tag_object = "WORKSPACE"
tag_key = meshstack_tag_definition.noop_e2e.spec.key
}

resource "meshstack_building_block" "this" {
# ensures the tag has a value before the building block run reads it
depends_on = [meshstack_workspace_tag.noop_e2e]

wait_for_completion = true
spec = {
building_block_definition_version_ref = module.noop.building_block_definition.version_ref
Expand All @@ -39,10 +68,19 @@ resource "meshstack_building_block" "this" {
num = { value = jsonencode(1) }
text = { value = jsonencode("Hello, World!") }
# optional_text = <nothing> -> We intentionally leave this empty to test we can use optional inputs and they take the variable default value.
# conditional_text is asked for because flag is true above; its condition is `input.flag == true`.
conditional_text = { value = jsonencode("Shown because flag is true") }
# hidden_conditional_text = <nothing> -> Its condition (`input.flag == false`) never holds while flag is true,
# so meshPanel hides it and it can be safely skipped here, exactly like optional_text.
# The meshStack API requires a JSON-type input's value to be sent as JSON text (a string),
# regardless of what type the Terraform variable declares it decodes into, so it must be
# jsonencode'd twice.
deploy_settings = { value = jsonencode(jsonencode({ greeting = "Hello from e2e", shout = true })) }
sensitive_text = { sensitive = { secret_value = "Hidden value" } }
single_select = { value = jsonencode("single1") }
multi_select = { value = jsonencode(["multi1", "multi2"]) }
multi_select_json = { value = jsonencode(["multi2", "multi1"]) }
# tag_value = <nothing> -> TAG-assigned inputs are read by meshStack from the workspace tag, not supplied here.
# Settable here because the test key owns the definition; an app team could not fill this in.
operator_text = { value = jsonencode("Set by the platform operator") }
}
Expand Down
Loading
Loading