-
Notifications
You must be signed in to change notification settings - Fork 0
feat(meshstack): add composition building block #247
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
base: main
Are you sure you want to change the base?
Changes from all commits
106832b
719f768
f893194
93702c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| --- | ||
| name: Composition Demo | ||
| 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 --> | ||
| 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." | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| } | ||
| 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." | ||
| } |
| 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" { | ||
| } |
| 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." | ||
| } |
| 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" | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
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.