Skip to content
Draft
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
96 changes: 96 additions & 0 deletions modules/meshstack/composition/buildingblock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
name: Composition Demo

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d: actually this is a demo of an "architecture composition" which is an advanced use case of compositions. A plain composition is sth like the AKS StarterKit that only deploys application team resources (projects, tenants, building blocks)

This is a "reference architecture" composition that also deploys platform team artifacts like BBDs, (LZs forthcomming) etc.

supportedPlatforms:
- meshstack
description: |
Reference building block demonstrating the composition pattern: it uses the run's
ephemeral API key to create a building block definition and a building block from it.
# Creates only meshObjects through the meshStack API, so there is nothing to set up cloud-side.
requiresBackplane: false
---
# Composition Demo

This building block is a reference implementation of the **composition** pattern: a building block
that provisions other meshObjects through the meshStack API instead of cloud resources. It creates a
`meshBuildingBlockDefinition` in the consuming workspace and a `meshBuildingBlock` from that
definition.

The created definition runs the hub's [`link`](../../link) building block, which provisions nothing
but a `terraform_data` and needs neither a cloud provider nor an operator. Reusing it keeps the whole
chain automatic and avoids inventing a throwaway implementation just to have something to create.
Both created meshObjects are named after `link_name` (default `Link`) to keep them distinguishable
from the `Composition Demo` block that created them.

## How it works

The building block definition declares `permissions`, so meshStack issues an **ephemeral API key**
scoped to the consuming workspace for the duration of each run and injects it as `MESHSTACK_ENDPOINT`
/ `MESHSTACK_API_TOKEN`. The `meshstack` provider picks those up with no explicit configuration, so
`provider "meshstack" {}` is all this module needs.

Because both meshObjects are created with that key, meshStack records it as their creation author and
surfaces **"created by building block"** provenance on the definition and the building block, linking
back to the composition that created them. That makes this module a convenient end-to-end check of
that provenance without any cloud platform involved.

## Permissions

| Permission | Why |
|---|---|
| `BUILDINGBLOCKDEFINITION_LIST` / `_SAVE` / `_DELETE` | Manage the created building block definition |
| `BUILDINGBLOCK_LIST` / `_SAVE` / `_DELETE` | Manage the created building block |

The created definition itself declares no permissions, so it stays within meshStack's privilege
escalation guard (a nested definition may only request a subset of its parent's permissions).

## Notes

- This module does not wait for the created building block's run. That run needs a terraform runner,
and a stack with a single one cannot start it before this run returns. Provenance is recorded when
the block is created, so nothing here depends on the result.
- For the same reason the created definition uses `deletion_mode = "PURGE"`. `DELETE` would schedule
a deprovisioning run on teardown that cannot start until the composition's own destroy run returns.
Purging leaks nothing, since `link` provisions no infrastructure.
- `hub_git_ref` is wired in as a static input from the composition's own `var.hub.git_ref`, so the
created definition clones the `link` module from the same hub revision.
- The created definition's version stays a **draft**. Releasing needs admin approval, which the run's
ephemeral key — a plain workspace key — cannot obtain, so `draft = false` would leave the version
`DRAFT` regardless, warn on every run, and leave `version_latest_release` null. The created
building block therefore references `version_latest`, which a draft permits because the definition
and the building block's target are the same workspace.

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_meshstack"></a> [meshstack](#requirement\_meshstack) | >= 0.24.0 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [meshstack_building_block.created](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource |
| [meshstack_building_block_definition.created](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block_definition) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_hub_git_ref"></a> [hub\_git\_ref](#input\_hub\_git\_ref) | Hub reference the created building block definition clones its implementation from. Wired in as a static input from the composition's own `var.hub.git_ref`, so both definitions stay on the same hub revision. | `string` | n/a | yes |
| <a name="input_link_name"></a> [link\_name](#input\_link\_name) | Name given to the building block definition and building block this composition creates. | `string` | `"Link"` | no |
| <a name="input_link_url"></a> [link\_url](#input\_link\_url) | Target of the link the created building block publishes. | `string` | n/a | yes |
| <a name="input_workspace_identifier"></a> [workspace\_identifier](#input\_workspace\_identifier) | Workspace the created building block definition is owned by and the created building block is attached to. Wired in as a WORKSPACE\_IDENTIFIER input, so it is always the consuming workspace — the same one the run's ephemeral API key is scoped to. | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_created_building_block_definition_uuid"></a> [created\_building\_block\_definition\_uuid](#output\_created\_building\_block\_definition\_uuid) | UUID of the building block definition this composition created. |
| <a name="output_created_building_block_uuid"></a> [created\_building\_block\_uuid](#output\_created\_building\_block\_uuid) | UUID of the building block this composition created. |
| <a name="output_summary"></a> [summary](#output\_summary) | Markdown summary shown on the building block's detail page. |
<!-- END_TF_DOCS -->
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 118 additions & 0 deletions modules/meshstack/composition/buildingblock/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Both resources below are created through the meshStack API with the run's ephemeral API key, which
# meshStack records as their creation author. That is what makes them show "created by building
# block" provenance pointing back at the building block this module runs for.

# Runs the hub's `link` building block rather than an implementation of its own: `link` provisions
# nothing but a terraform_data, needs no cloud provider and no operator, which makes it the cheapest
# real implementation to hand a created definition. See modules/meshstack/link.
resource "meshstack_building_block_definition" "created" {
metadata = {
owned_by_workspace = var.workspace_identifier
}

spec = {
display_name = var.link_name
description = "Link building block definition created by the Composition Demo building block."

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d: parameterize this already so that it shows some dummy link, for example "this is an element of a composition"

target_type = "WORKSPACE_LEVEL"
run_transparency = true

readme = chomp(<<-EOT
A link building block definition created by a composition rather than by a platform engineer.

Ordering it publishes a link in your workspace and provisions no infrastructure.
EOT
)
}

version_spec = {
# Stays a draft: releasing a version needs admin approval, which the run's ephemeral key — a
# plain workspace key — cannot obtain. Setting draft = false would leave the version DRAFT
# anyway, warn on every run, and leave version_latest_release null. The building block below can
# still be created from a draft because the definition and the target are the same workspace,
# which satisfies BuildingBlockCreationValidator.requireAccess's `selfOwning` branch.
draft = true

# PURGE, not DELETE: DELETE would schedule a deprovisioning run for the building block below when

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d: I think that's not fully correct, and just a matter of correct depends_on because tofu doesn't know the BBD -> BB topology inside meshStack

# this composition is torn down, and that run cannot start until the composition's own destroy run
# returns — a deadlock wherever the terraform runner pool has a single worker. Nothing is leaked
# by purging, because the `link` implementation provisions nothing but a terraform_data.
deletion_mode = "PURGE"

implementation = {
terraform = {
repository_url = "https://github.com/meshcloud/meshstack-hub.git"
repository_path = "modules/meshstack/link/buildingblock"
ref_name = var.hub_git_ref
terraform_version = "1.11.0"
async = false
use_mesh_http_backend_fallback = true
}
}

# All static, so the created building block below has no inputs left to supply. Mirrors the
# wiring in modules/meshstack/link/meshstack_integration.tf.
inputs = {
url = {
display_name = "URL"
description = "Target of the link."
type = "STRING"
assignment_type = "STATIC"
argument = jsonencode(var.link_url)
}
title = {
display_name = "Title"
description = "Human-readable name of the linked resource."
type = "STRING"
assignment_type = "STATIC"
argument = jsonencode(var.link_name)
}
# Empty falls back to the summary the link module generates from title and url.
summary = {
display_name = "Summary"
description = "Markdown rendered for the application team after deployment."
type = "STRING"
assignment_type = "STATIC"
argument = jsonencode("")
}
}

outputs = {
url = {
display_name = var.link_name
type = "STRING"
assignment_type = "RESOURCE_URL"
}
summary = {
display_name = "Summary"
type = "STRING"
assignment_type = "SUMMARY"
}
}
}
}

resource "meshstack_building_block" "created" {
spec = {
# version_latest, not version_latest_release: the definition above stays a draft, so
# version_latest_release is null.
building_block_definition_version_ref = {
uuid = meshstack_building_block_definition.created.version_latest.uuid
content_hash = meshstack_building_block_definition.created.version_latest.content_hash
}

display_name = var.link_name

target_ref = {
kind = "meshWorkspace"
name = var.workspace_identifier
}

# Every input of the definition above is static, so there is nothing for this block to set.
inputs = {}
}

# Deliberately not waiting: this run would be waiting on a run of the same implementation type,
# which a stack with a single terraform runner cannot start until this one returns. Nothing below
# depends on the result either — provenance is recorded when the block is created.
wait_for_completion = false
}
23 changes: 23 additions & 0 deletions modules/meshstack/composition/buildingblock/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
output "created_building_block_definition_uuid" {
value = meshstack_building_block_definition.created.metadata.uuid
description = "UUID of the building block definition this composition created."
}

output "created_building_block_uuid" {
value = meshstack_building_block.created.metadata.uuid
description = "UUID of the building block this composition created."
}

output "summary" {
value = chomp(<<-EOT
Created a Link building block definition and a building block from it. Both show this building
block as their creator.

| meshObject | Name | UUID |
|---|---|---|
| Building Block Definition | ${var.link_name} | `${meshstack_building_block_definition.created.metadata.uuid}` |
| Building Block | ${var.link_name} | `${meshstack_building_block.created.metadata.uuid}` |
EOT
)
description = "Markdown summary shown on the building block's detail page."
}
4 changes: 4 additions & 0 deletions modules/meshstack/composition/buildingblock/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Authenticates from the MESHSTACK_ENDPOINT / MESHSTACK_API_TOKEN environment variables the runner
# injects for the run's ephemeral API key.
provider "meshstack" {
}
23 changes: 23 additions & 0 deletions modules/meshstack/composition/buildingblock/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Defaulted, unlike the other inputs, so that a run can still destroy a building block whose stored
# inputs predate a rename of this one. A destroy only has to delete the created meshObjects, and their
# display names have no bearing on that.
variable "link_name" {
type = string
default = "Link"
description = "Name given to the building block definition and building block this composition creates."
}

variable "link_url" {
type = string
description = "Target of the link the created building block publishes."
}

variable "workspace_identifier" {
type = string
description = "Workspace the created building block definition is owned by and the created building block is attached to. Wired in as a WORKSPACE_IDENTIFIER input, so it is always the consuming workspace — the same one the run's ephemeral API key is scoped to."
}

variable "hub_git_ref" {
type = string
description = "Hub reference the created building block definition clones its implementation from. Wired in as a static input from the composition's own `var.hub.git_ref`, so both definitions stay on the same hub revision."
}
8 changes: 8 additions & 0 deletions modules/meshstack/composition/buildingblock/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
meshstack = {
source = "meshcloud/meshstack"
version = ">= 0.24.0"
}
}
}
Loading
Loading