Skip to content
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
### Team Workspace Access
* Added Team Workspace Access resource list, read, add, update and remove methods along with models and examples for managing team access to workspaces by @iam404 [#168](https://github.com/hashicorp/python-tfe/pull/168)

### No-Code Provisioning
* Added no_code_modules resource with create, read, update, delete, read_variables, create_workspace, upgrade_workspace, read_workspace_upgrade, and confirm_workspace_upgrade methods.

## Enhancements

### Terraform Actions
Expand Down Expand Up @@ -97,7 +100,8 @@
## Bug Fixes
* Fixed task result relationships to map into typed SDK models instead of raw JSON by @TanyaSingh369-svg [#156](https://github.com/hashicorp/python-tfe/pull/156)
* Fixed task stage relationship mapping in the task result resource by @TanyaSingh369-svg [#156](https://github.com/hashicorp/python-tfe/pull/156)
* Updated variable set models to support ``global_`` inputs. Since ``global`` is a Python reserved word, callers previously had to use ``model_validate`` as a workaround; existing ``global`` alias usage continues to work unchanged.
* Updated variable set models to support **global_** inputs. Since **global** is a Python reserved word, callers previously had to use **model_validate** as a workaround; existing **global** alias usage continues to work unchanged.
* Fixed the workspace JSON:API parser to populate the singular agent_pool field instead of writing to a non-existent agent_pools key. The relationship was previously parsed off the wire but silently dropped because the model field is singular; workspace.agent_pool now returns the related AgentPool stub as documented.


# v0.1.5
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ and upstream HCP Terraform API docs.
|---|---|
| Configure the SDK | [Authentication](./docs/authentication.md), [Pagination](./docs/pagination.md), [Logging](./docs/LOGGING.md) |
| API guides | [API index](./docs/api/index.md), [Workspaces](./docs/api/workspaces.md), [Runs/plans/applies](./docs/api/runs-plans-applies.md), [State versions](./docs/api/state-versions.md) |
| Scenario guides | [API-driven run](./docs/scenarios/api-driven-run.md), [State management](./docs/scenarios/state-management.md), [Migrate workspaces and state](./docs/scenarios/migrate-workspaces-and-state.md), [Team access onboarding](./docs/scenarios/team-access-onboarding.md) |
| Scenario guides | [API-driven run](./docs/scenarios/api-driven-run.md), [State management](./docs/scenarios/state-management.md), [Migrate workspaces and state](./docs/scenarios/migrate-workspaces-and-state.md), [Team access onboarding](./docs/scenarios/team-access-onboarding.md), [No-code provisioning](./docs/scenarios/no-code-provisioning.md) |
| Operations guides | [Troubleshooting](./docs/troubleshooting.md), [Errors](./docs/errors.md), [Terraform Enterprise](./docs/terraform-enterprise.md) |
| Contribute to the SDK | [CONTRIBUTING](./docs/CONTRIBUTING.md), [ITERATORS](./docs/ITERATORS.md), [MODELS](./docs/MODELS.md), [RESOURCE](./docs/RESOURCE.md) |

Expand Down
2 changes: 2 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ column.
| `client.agents` | `Agents` | `list`, `read`, `delete` | [agent.py](../../examples/agent.py) | [Agents](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/agents) |
| `client.agent_tokens` | `AgentTokens` | `list`, `read`, `create`, `delete` | [agent.py](../../examples/agent.py) | [Agent tokens](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/agent-tokens) |
| `client.registry_modules` | `RegistryModules` | `list`, `read`, `create`, `update`, `delete`, version and upload helpers | [registry_module.py](../../examples/registry_module.py) | [Registry modules](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/modules) |
| `client.no_code_modules` | `NoCodeModules` | `create`, `read`, `update`, `delete`, `read_variables`, `create_workspace`, `upgrade_workspace`, `read_workspace_upgrade`, `confirm_workspace_upgrade` | [no_code_provisioning.py](../../examples/no_code_provisioning.py) | [No-code provisioning](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/no-code-provisioning) |
| `client.registry_providers` | `RegistryProviders` | `list`, `read`, `create`, `delete` | [registry_provider.py](../../examples/registry_provider.py) | [Registry providers](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/providers) |
| `client.registry_provider_versions` | `RegistryProviderVersions` | `list`, `read`, `create`, `delete` | [registry_provider_version.py](../../examples/registry_provider_version.py) | [Registry providers](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/providers) |
| `client.registry_provider_platforms` | `RegistryProviderPlatforms` | `list`, `read`, `create`, `delete` | [registry_provider_platform.py](../../examples/registry_provider_platform.py) | [Registry providers](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/providers) |
Expand All @@ -103,3 +104,4 @@ column.
- [teams-and-access.md](teams-and-access.md)
- [policies.md](policies.md)
- [run-tasks.md](run-tasks.md)
- [no-code-provisioning.md](no-code-provisioning.md)
274 changes: 274 additions & 0 deletions docs/api/no-code-provisioning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
# No-code provisioning

No-code provisioning lets users create workspaces from a curated registry
module without writing Terraform code. The workflow has three actors:

- A platform admin enables a registry module for no-code use and sets allowed
variable values.
- An end user creates a workspace from that module, supplying only variable
values.
- Either party can later upgrade an existing no-code workspace to a newer
module version.

`client.no_code_modules` covers all four pieces: module CRUD, variable
introspection, workspace creation, and workspace upgrade lifecycle.

Upstream docs: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/no-code-provisioning

Example: [no_code_provisioning.py](../../examples/no_code_provisioning.py)

## Token requirements

Every write endpoint (`create`, `update`, `delete`, `create_workspace`,
`upgrade_workspace`, `confirm_workspace_upgrade`) requires a **user or team
token**. Organization tokens are not accepted by the API. Read endpoints
(`read`, `read_variables`, `read_workspace_upgrade`) do not have this
restriction.

## Common methods

| Method | Purpose |
|---|---|
| `client.no_code_modules.create(organization, options)` | Enable no-code provisioning for a registry module. |
| `client.no_code_modules.read(no_code_module_id, options=None)` | Read a no-code module; pass `NoCodeModuleReadOptions(include=[VARIABLE_OPTIONS])` to materialise allowed-values. |
| `client.no_code_modules.update(no_code_module_id, options)` | Update enabled flag, version pin, or variable options. |
| `client.no_code_modules.delete(no_code_module_id)` | Disable no-code provisioning for the module. |
| `client.no_code_modules.read_variables(no_code_module_id, version)` | Iterate variables declared by a specific module version, for form-building. |
| `client.no_code_modules.create_workspace(no_code_module_id, options)` | Create a workspace from the no-code module. |
| `client.no_code_modules.upgrade_workspace(no_code_module_id, workspace_id, options=None)` | Start an upgrade; returns a `WorkspaceUpgrade` to poll. |
| `client.no_code_modules.read_workspace_upgrade(no_code_module_id, workspace_id, upgrade_id)` | Poll upgrade status. |
| `client.no_code_modules.confirm_workspace_upgrade(no_code_module_id, workspace_id, upgrade_id)` | Confirm and apply the upgrade plan. |

## Enable a registry module for no-code use

```python
from pytfe import TFEClient
from pytfe.models import (
NoCodeModuleCreateOptions,
NoCodeVariableOption,
)


client = TFEClient()

no_code_module = client.no_code_modules.create(
"my-organization",
NoCodeModuleCreateOptions(
registry_module_id="mod-abc123",
enabled=True,
version_pin="1.4.0",
variable_options=[
NoCodeVariableOption(
variable_name="region",
variable_type="string",
options=["us-east-1", "us-west-2", "eu-west-1"],
),
NoCodeVariableOption(
variable_name="instance_size",
variable_type="string",
options=["small", "medium", "large"],
),
],
),
)

print(no_code_module.id)
```

`version_pin` defaults to the latest version when omitted. Each
`NoCodeVariableOption` constrains end users to one of the listed values for
that variable.

## Read a module with its variable options

`variable_options` are returned by reference only unless you ask for them with
the `include` query:

```python
from pytfe.models import NoCodeModuleIncludeOpt, NoCodeModuleReadOptions

module = client.no_code_modules.read(
"nocode-abc123",
NoCodeModuleReadOptions(include=[NoCodeModuleIncludeOpt.VARIABLE_OPTIONS]),
)

for option in module.variable_options:
print(option.variable_name, option.options)
```

Without the include, `module.variable_options` contains stubs with `id` only.

## Update variable options

To update an existing option, pass its `id` in the entry; entries without an
`id` are added as new options. To remove an option, omit it from the list —
update calls replace the entire `variable-options` set.

The HCP API requires every PATCH on a no-code module to include the
`registry-module` relationship in the body, or the server returns `404`. The
SDK handles this transparently: if you don't supply `registry_module_id`
on `NoCodeModuleUpdateOptions`, the resource issues an extra GET to pick up
the current module's relationship. Pass `registry_module_id` explicitly to
skip the round trip:

```python
NoCodeModuleUpdateOptions(
registry_module_id="mod-abc123",
enabled=False,
)
```

```python
from pytfe.models import NoCodeModuleUpdateOptions, NoCodeVariableOption

updated = client.no_code_modules.update(
"nocode-abc123",
NoCodeModuleUpdateOptions(
version_pin="1.5.0",
variable_options=[
NoCodeVariableOption(
id="vo-existing123",
variable_name="region",
variable_type="string",
options=["us-east-1", "us-east-2", "us-west-2"],
),
NoCodeVariableOption(
variable_name="environment",
variable_type="string",
options=["dev", "staging", "prod"],
),
],
),
)
```

## Introspect variables for a module version

When building a UI that lets users pick variable values, use
`read_variables` to discover what the module accepts:

```python
for var in client.no_code_modules.read_variables("nocode-abc123", "1.4.0"):
print(var.name, var.type, var.required, var.options)
```

The returned `RegistryModuleVariable` objects include `name`, `type`,
`description`, `default`, `required`, `sensitive`, and `options`.

## Create a workspace from a no-code module

```python
from pytfe.models import (
NoCodeWorkspaceCreateOptions,
NoCodeWorkspaceVariable,
CategoryType,
)

workspace = client.no_code_modules.create_workspace(
"nocode-abc123",
NoCodeWorkspaceCreateOptions(
name="customer-acme-us-east-1",
project_id="prj-abc123",
description="Production environment for ACME (us-east-1)",
terraform_version="1.7.0",
vars=[
NoCodeWorkspaceVariable(
key="region",
value="us-east-1",
category=CategoryType.TERRAFORM,
),
NoCodeWorkspaceVariable(
key="environment",
value="prod",
category=CategoryType.TERRAFORM,
),
],
),
)

print(workspace.id, workspace.execution_mode)
```

The returned `Workspace` is parsed the same way as `client.workspaces.read`,
so relationships (`project`, `agent_pool`, `vars`) are available when the
server includes them.

For agent execution, set both `execution_mode` and `agent_pool_id`:

```python
from pytfe.models import ExecutionMode

workspace = client.no_code_modules.create_workspace(
"nocode-abc123",
NoCodeWorkspaceCreateOptions(
name="private-network-ws",
project_id="prj-abc123",
execution_mode=ExecutionMode.AGENT,
agent_pool_id="apool-abc123",
),
)
```

The SDK raises `RequiredAgentPoolIDError` if `execution_mode=AGENT` is set
without an `agent_pool_id`.

## Upgrade a no-code workspace

Upgrades are a three-step lifecycle: initiate → poll → confirm.

```python
import time

from pytfe.models import (
NoCodeWorkspaceUpgradeOptions,
NoCodeWorkspaceVariable,
CategoryType,
)

upgrade = client.no_code_modules.upgrade_workspace(
"nocode-abc123",
"ws-abc123",
NoCodeWorkspaceUpgradeOptions(
vars=[
NoCodeWorkspaceVariable(
key="region",
value="us-west-2",
category=CategoryType.TERRAFORM,
),
],
),
)

terminal_plan_states = {"planned_and_finished", "errored", "canceled"}
while True:
status = client.no_code_modules.read_workspace_upgrade(
"nocode-abc123", "ws-abc123", upgrade.id
)
print(status.status, status.plan_url)
if status.status in terminal_plan_states:
break
time.sleep(5)

if status.status == "planned_and_finished":
client.no_code_modules.confirm_workspace_upgrade(
"nocode-abc123", "ws-abc123", upgrade.id
)
```

`confirm_workspace_upgrade` returns `None` and signals success via HTTP
status; the API responds with a plain-text body (`"Workspace update
completed"`) which is intentionally not surfaced.

## Operational notes

- **Variable options are wire-replaced, not merged.** Every `update` call
with a `variable_options` list replaces the whole set. To keep an existing
option, include it (with its `id`) in the list.
- **`version_pin` controls what the no-code workspace gets.** Update it to
roll out a new module version; downstream workspaces still need explicit
`upgrade_workspace` calls to adopt it.
- **Pin a version explicitly in production.** Defaulting to "latest" means a
registry module publish can change behaviour for every consumer.
- **Treat the workspace returned by `create_workspace` like any other.**
Once created, use `client.workspaces`, `client.runs`, `client.state_versions`
to manage it.
Loading
Loading