> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tensor9.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Terraform/OpenTofu Guide

> Use the AWS provider through Cloud Adapter and verify state, refresh, and cleanup behavior.

Terraform and OpenTofu can call Cloud Adapter through an origin cloud provider. Cloud Adapter is not a Terraform provider: it implements the supported cloud API operations that the provider calls.

This walkthrough uses the AWS provider and one S3 object. It deliberately reuses an existing test bucket so the first test exercises a small data-plane lifecycle instead of bucket provisioning, account discovery, policy, and tagging all at once.

## Start a local adapter

Use one service mapping before testing a larger Terraform graph. This guide's bounded fixture uses S3 backed by Google Cloud Storage:

**1. Install or update the Tensor9 CLI**

Install the customer CLI with Homebrew, then confirm the binary is available:

```bash theme={null}
brew tap tensor9ine/tensor9
brew trust tensor9ine/tensor9
brew install tensor9
tensor9 --version
```

If `tensor9` is already installed, run `brew upgrade tensor9` instead of the install command.

**2. Authenticate with Tensor9**

To create a Tensor9 account and download an API key yourself, follow [Get a Tensor9 API key](https://docs.tensor9.com/byoc/getting-started/api-key.md).

A Tensor9 API key is required. Use the key issued during onboarding, or email [hello@tensor9.com](mailto:hello@tensor9.com) to request one for your organization. Do not share your account or key with another customer or organization.

If your secret manager has already supplied `T9_API_KEY`, skip the prompt. Otherwise, enter your key at a hidden prompt in the terminal where you will run `tensor9`:

> [tab] Bash
>
> ```bash theme={null}
> set +x
> IFS= read -r -s -p 'Tensor9 API key: ' T9_API_KEY
> printf '\n'
> export T9_API_KEY
> ```

> [tab] Zsh
>
> ```zsh theme={null}
> set +x
> IFS= read -r -s 'T9_API_KEY?Tensor9 API key: '
> printf '\n'
> export T9_API_KEY
> ```

Check that the variable is set without printing it, then verify your Tensor9 identity:

```bash theme={null}
: "${T9_API_KEY:?Set T9_API_KEY before continuing}"
tensor9 whoami
```

Confirm that the reported identity belongs to the intended customer account. Do not continue if authentication fails or the account is wrong. While `T9_API_KEY` is set, `tensor9` commands in this terminal use the key instead of any controller profile, so use a separate terminal for this work and run `unset T9_API_KEY` when you finish. Keep shell tracing disabled while using the key. Do not paste the key into commands, shell profiles, source files, screenshots or support messages.

See [Install and Authenticate](https://docs.tensor9.com/cloud-adapter-early-access/getting-started/install-and-authenticate.md) for the planned license lifecycle, entitlements and credential boundaries.

**3. Inspect the S3 to Google Cloud Storage mapping**

Ask Tensor9 to describe the exact directed service mapping used by this guide:

```bash theme={null}
tensor9 explain \
  -origin aws::1.0.0::s3 \
  -target google::1.0.0::gcs \
  -fmt Human
```

Read the supported S3 operations and Google Cloud Storage limitations before starting the process. The mapping is directional: this command describes S3 requests adapted to Google Cloud Storage, not the reverse direction.

**4. Prepare Google Cloud access**

Authenticate with Google Cloud using its standard Application Default Credentials chain. The adapter uses that identity when it calls Google Cloud Storage.

Use a dedicated test project and narrowly scoped credentials. Do not put credentials in the command line, source code, or screenshots.

**5. Start the S3 service adapter**

Run the S3 to Google Cloud Storage adapter as a foreground process:

```bash theme={null}
tensor9 adapt svc run \
  --origin aws::1.0.0::s3 \
  --backend google::1.0.0::gcs
```

Leave this terminal open. This is the current foreground launcher, not the pending Docker launcher for [local development mode](https://docs.tensor9.com/cloud-adapter-early-access/deployment/single-binary.md). It calls your actual target-cloud services; it is separate from the in-memory emulator. Acquisition and license renewal require Tensor9 authentication. Keep the endpoint local to your test.

**6. Copy the listening endpoint**

When the command reports its listening endpoint, copy that exact value into a second terminal:

```bash theme={null}
export T9_CLOUD_ADAPTER_ENDPOINT="<endpoint printed by tensor9>"
```

Keep the endpoint local to the test unless you have deliberately configured network access and authentication for another machine.

**7. Run one bounded S3 request**

Continue with this page's client or tool instructions. Point only S3 at `T9_CLOUD_ADAPTER_ENDPOINT`, then perform one operation whose Google Cloud Storage effect you can verify independently.

Check both sides: read the S3-shaped response and inspect the native object or bucket in Google Cloud Storage. A successful client response alone does not prove that the target state is correct.

**8. Stop the local adapter**

Return to the first terminal and press **Control-C**. Confirm the process exits before deleting the test object or bucket with Google Cloud's native client.

If the request failed, preserve the request ID, adapter endpoint, S3 operation name, Google Cloud request ID, and any `x-t9-explain-*` receipt headers before stopping the process.

## What this test proves

A successful run proves that the selected provider version can use the endpoint and that the exact create, read, refresh, and delete operations in this configuration work for the selected target. It does not prove that every AWS resource, every S3 feature, import, drift recovery, or backend migration works.

## Prerequisites

* Terraform 1.6+ or a compatible OpenTofu release;
* AWS provider `5.100.0` for the exact configuration below;
* an installed AWS-origin adapter endpoint;
* a pre-created target bucket represented by an origin-facing bucket name;
* origin-side credentials for the provider;
* an isolated workspace and remote state policy suitable for test data.

Check [S3 service coverage](https://docs.tensor9.com/cloud-adapter-early-access/service-catalog/aws/databases-storage/s3.md) for your target before applying.

## Configure the provider endpoint

```hcl theme={null}
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "= 5.100.0"
    }
  }
}

variable "adapter_endpoint" {
  type = string
}

variable "test_bucket" {
  type = string
}

provider "aws" {
  region = "us-east-1"

  endpoints {
    s3 = var.adapter_endpoint
  }

  s3_use_path_style = true

  # Keep provider startup on the configured S3 route. These switches avoid
  # metadata, region, credential-validation, and account-discovery calls.
  skip_credentials_validation = true
  skip_metadata_api_check     = true
  skip_region_validation      = true
  skip_requesting_account_id  = true
}

resource "aws_s3_object" "smoke" {
  bucket       = var.test_bucket
  key          = "terraform/cloud-adapter-smoke.txt"
  content      = "hello through Cloud Adapter\n"
  content_type = "text/plain"
}

output "object_etag" {
  value = aws_s3_object.smoke.etag
}
```

The four `skip_*` settings are deliberate for this bounded S3 fixture: they prevent this provider version from making startup calls to EC2 metadata, region validation, or AWS STS outside the configured adapter route. They do not weaken Cloud Adapter authentication. Validate the origin identity independently, and reassess the startup call graph before changing provider versions.

## Run the lifecycle

```bash theme={null}
export TF_VAR_adapter_endpoint="$T9_CLOUD_ADAPTER_ENDPOINT"
export TF_VAR_test_bucket="adapter-smoke-test"
export AWS_PROFILE="adapter-test"
export AWS_REQUEST_CHECKSUM_CALCULATION="WHEN_REQUIRED"

terraform init
terraform fmt -check
terraform validate
terraform plan -out=adapter.tfplan
terraform apply adapter.tfplan
```

After apply:

1. Read the object through the origin API.
2. Inspect it in the native target service.
3. Confirm its bytes and content type.
4. Save the provider and adapter versions with the test evidence.

## Prove read-back and drift behavior

Run a second plan:

```bash theme={null}
terraform plan -detailed-exitcode
```

Exit code `0` means no diff, `2` means Terraform found a diff, and `1` means an error. If the provider cannot read a field it wrote, a perpetual diff can appear even though creation succeeded. Compare the diff with the target-specific fidelity and limitation tables.

For a controlled drift test, change only a disposable object's content through the native target API, run `terraform plan`, and observe whether the provider detects the change. Restore or destroy the object afterward.

## Clean up safely

```bash theme={null}
terraform plan -destroy -out=destroy.tfplan
terraform apply destroy.tfplan
```

Verify through both the origin API and target service that only the test object was removed. Retain or destroy the test bucket according to its separate ownership policy.

## State and migration boundaries

* Terraform state records provider-visible identity; it is not application data migration.
* Changing the provider endpoint can cause refreshes, replacement plans, or identity mismatches.
* Import requires compatible read and identity behavior, not only create support.
* A clean plan does not prove unsupported fields are preserved.
* Never point a production workspace at a new adapter endpoint before testing refresh and replacement behavior on a copy.

## Troubleshooting

| Failure stage | Likely boundary |
| - | - |
| `init` | Provider installation or state backend, before Cloud Adapter. |
| Provider configuration | Credentials, TLS, endpoint, region, or an unexpected discovery API such as STS. |
| `plan` refresh | Read/list coverage, identity translation, or target permissions. |
| `apply` | Create/update coverage, backend permissions, timeout, or target quota. |
| Second plan | Read-after-write fidelity, defaults, normalization, or identifier mapping. |
| Destroy | Delete coverage, retention policy, dependency ordering, or a target-side hold. |

Capture [diagnostic response headers](https://docs.tensor9.com/cloud-adapter-early-access/debugging/response-headers.md) and run the failing origin operation with the [AWS CLI guide](https://docs.tensor9.com/cloud-adapter-early-access/guides/aws-cli.md) to separate provider behavior from adapter behavior.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.