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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Starting with v1.0.0, Terratest follows [semantic versioning](https://semver.org
only happen in major releases (e.g. v2.0.0).

Symbols renamed or replaced in v1 are kept with `// Deprecated:` annotations pointing at the new name; removals happen
in v2. Migrating from v0.x: see the [v1 migration guide](https://terratest.gruntwork.io/docs/migrating-to-v1/overview/).
in v2. Migrating from v0.x: see the [v1 migration guide](https://terratest.gruntwork.io/docs/migrating-to-v1/overview/). Migrating from v1 to v2: see the [v2 migration guide](https://terratest.gruntwork.io/docs/migrating-to-v2/overview/).

**v1 maintenance.** With v2 in development, the v1 line has entered maintenance: it receives security fixes only,
delivered on the `v1` branch, until 12 months after v2.0.0 reaches general availability. v2 ships under new `/v2`
Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ nav_title_link: /docs/ # X Cannot be changed

* `layout` - do not change! (Layout sets components like a navigation sidebar, page header, footer, etc.)
* `title` - document title
* `categories` - the document's category. Four categories are in use for now: "getting-started", "testing-best-practices", "alternative-testing-tools", and "community".
* `category` - the document's category. The categories in use are: 'getting-started', 'testing-best-practices', 'migrating-to-v1', 'migrating-to-v2', and 'community'.
* `excerpt` - description. Try to keep it short.
* `tags` - check other posts to see common tags, but you can set a new as well.
* `order` - it is used to sort the documents within collection.
Expand Down Expand Up @@ -186,7 +186,7 @@ nav_title_link: /docs/ # OPTIONAL
* categories - set one category. Use downcase with dashes, e.g. `getting-started`.
* excerpt - the doc description.
* tags - doc tags.
* order - it is use to list documents in the right order. "Getting Started" starts from 100, "Features" starts from 200, and "Community" starts from 300.
* order - it is used to list documents in the right order. "Getting Started" starts from 100, "Testing Best Practices" from 200, "Migrating to v1" from 300, "Migrating to v2" from 400, and "Community" from 500.
* nav_title - the title above navigation. It's optional. It's a link if `nav_title_link` is set.
* nav_title_link - it is a URL. If it is set, `nav_link` is transformed to the link.

Expand Down
2 changes: 2 additions & 0 deletions docs/_docs/01_getting-started/version-pinning.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ Replace `v0.56.0` with the tag you want from the [Releases page](https://github.
## Use `go get`, not subpath requires

`go get github.com/gruntwork-io/terratest@<tag>` is enough; the pin applies to every subpackage your tests import. Avoid writing subpath requires by hand (e.g. `go mod edit -require github.com/gruntwork-io/terratest/modules/terraform@<tag>`); Go searches for a `modules/terraform/<tag>` tag and fails with `unknown revision`.

This applies to v1. In v2 each module is published separately and does carry its own `modules/<name>/<tag>` tag, so you require them individually. See [migrating to v2]({{site.baseurl}}/docs/migrating-to-v2/overview/).
3 changes: 3 additions & 0 deletions docs/_docs/03_migrating-to-v1/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ changes to the public API only happen in major releases (e.g. v2.0.0), per
[semver](https://semver.org/). Renamed or replaced symbols stay around as
deprecated aliases inside v1; full removal is deferred to v2.

Already on v1 and looking for v2? See
[migrating to v2]({{site.baseurl}}/docs/migrating-to-v2/overview/).

This page is the orientation map for v0.x to v1.0.0. It tells you what
shape the changes take and where to look; the per-service guides hold the
mechanical details.
Expand Down
87 changes: 87 additions & 0 deletions docs/_docs/04_migrating-to-v2/behavior-changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
layout: collection-browser-doc
title: Behavior changes
category: migrating-to-v2
excerpt: >-
The two v2 changes the compiler will not find for you. Both are in the
k8s module.
tags: ["migration", "v2"]
order: 403
nav_title: Documentation
nav_title_link: /docs/
---

Everything else in the v2 migration is a compile error. These two are not:
your code builds and behaves differently. Both are in `k8s`, so skip this
page if you do not use it, and see the [v2
overview]({{site.baseurl}}/docs/migrating-to-v2/overview/) for the rest of
the migration.

## Node addresses prefer `ExternalIP`

`k8s.FindNodeHostnameContextE`, and `GetServiceEndpointContextE` for a
NodePort service, now return the `ExternalIP` recorded on the Node object
when one is present. They fall back to the internal hostname exactly as
before when it is not.

Cloud controller managers record an instance's public IP as an
`ExternalIP`. Terratest previously ignored that field and, on AWS, called
`ec2:DescribeInstances` to find the public IP instead. Reading the Node
object is the same answer without the API call, so:

- `ec2:DescribeInstances` is no longer needed for this path
- `k8s` no longer depends on the `aws` module, which removes 22 AWS service
clients from its dependency graph

**What to check.** If your cluster advertises an `ExternalIP` and your test
previously received an internal hostname, it now receives the external
address. That is the documented behavior and almost certainly what you
wanted, but it is a different string. Tests that assert on the endpoint
value, or that rely on reaching the node over its internal address, are the
ones to look at.

Signatures are unchanged. The `ExternalIP` preference applies to every
provider. For AWS-backed nodes that advertise no `ExternalIP`, a new pair of
functions takes `*KubectlOptions` and consults
a lookup you provide:

```go
options := k8s.NewKubectlOptions("", kubeconfig, "default")
options.NodePublicIPLookup = aws.GetPublicIpsOfEc2InstancesContextE

hostname, err := k8s.FindNodeHostnameWithOptionsContextE(t, ctx, options, node)
```

`NodePublicIPLookup` is only consulted after the Node's own `ExternalIP`
has been checked, so most callers can leave it nil.

## `KubectlOptions` carrying a `RestConfig` cannot be saved

`json.Marshal` of a `KubectlOptions` built by
`NewKubectlOptionsWithRestConfig` now fails with an error wrapping
`k8s.ErrRestConfigNotSerializable`. Match it with `errors.Is`, not `==`:
`encoding/json` returns a `*json.MarshalerError` around it. This affects
`k8s.SaveKubectlOptions`, `teststructure.SaveTestData`, and any code of
your own that marshals options.

This already failed in v1, with an opaque `json: unsupported type:
transport.WrapperFunc`, because `rest.Config` holds func-typed fields that
`encoding/json` rejects. What changed is that the error now says what is
wrong and what to do instead.

It is deliberately an error rather than silently dropping the config.
Dropped, the reloaded options would carry no cluster identity at all, fall
back to the ambient kubeconfig, and run your test against a different
cluster.

**What to do.** For staged tests, build options from a kubeconfig path or
from in-cluster auth. Both round trip:

```go
options := k8s.NewKubectlOptions(contextName, configPath, namespace)
// or
options := k8s.NewKubectlOptionsWithInClusterAuth()
```

If you need a `rest.Config` at runtime, keep building one, but rebuild it
in each stage rather than saving it.
80 changes: 80 additions & 0 deletions docs/_docs/04_migrating-to-v2/import-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
layout: collection-browser-doc
title: Import map
category: migrating-to-v2
excerpt: >-
Every v1 import path and what it becomes in v2.
tags: ["migration", "v2"]
order: 402
nav_title: Documentation
nav_title_link: /docs/
---

The complete v1 to v2 path mapping. See [rewriting
imports]({{site.baseurl}}/docs/migrating-to-v2/rewriting-imports/) for how
to apply it in bulk.

## Collapsed into `core`

Six utility packages became subpackages of one module. The package
identifier at call sites is unchanged.

| v1 | v2 |
|---|---|
| `modules/random` | `modules/core/v2/random` |
| `modules/files` | `modules/core/v2/files` |
| `modules/logger` | `modules/core/v2/logger` |
| `modules/shell` | `modules/core/v2/shell` |
| `modules/retry` | `modules/core/v2/retry` |
| `modules/testing` | `modules/core/v2/testing` |

`modules/logger/parser` becomes `modules/core/v2/logger/parser`.

`modules/core/v2/formatting` is new in v2 and has no v1 equivalent to
migrate: it was `internal/lib/formatting`, which was never importable.

## Renamed

Path *and* package identifier change.

| v1 | v2 |
|---|---|
| `modules/http-helper`, `http_helper.X` | `modules/httphelper/v2`, `httphelper.X` |
| `modules/dns-helper`, `dns_helper.X` | `modules/dnshelper/v2`, `dnshelper.X` |
| `modules/test-structure`, `test_structure.X` | `modules/teststructure/v2`, `teststructure.X` |

## Suffix only

Path gains `/v2`; package identifier unchanged.

| v1 | v2 |
|---|---|
| `modules/aws` | `modules/aws/v2` |
| `modules/azure` | `modules/azure/v2` |
| `modules/gcp` | `modules/gcp/v2` |
| `modules/k8s` | `modules/k8s/v2` |
| `modules/helm` | `modules/helm/v2` |
| `modules/ssh` | `modules/ssh/v2` |
| `modules/docker` | `modules/docker/v2` |
| `modules/packer` | `modules/packer/v2` |
| `modules/database` | `modules/database/v2` |
| `modules/opa` | `modules/opa/v2` |
| `modules/terraform` | `modules/terraform/v2` |
| `modules/terragrunt` | `modules/terragrunt/v2` |

## Removed

| v1 | Replacement |
|---|---|
| `modules/collections` | stdlib `slices` |
| `modules/environment` | stdlib `os.Getenv` |
| `modules/git` | stdlib `os/exec` |
| `modules/slack` | none; vendor from v1 if needed |
| `modules/version-checker` | none; shell out |
| `modules/oci` | none; Oracle Cloud is not carried forward to v2 |
| `cmd/pick-instance-type` | none |
| `cmd/terratest_log_parser` | none as a binary; the library survives at `modules/core/v2/logger/parser` |

These were deprecated in v1 first and deleted at the v2 cutover. If you
depend on `slack`, `version-checker` or `oci`, v1 stays available and is
the place to stay.
159 changes: 159 additions & 0 deletions docs/_docs/04_migrating-to-v2/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
---
layout: collection-browser-doc
title: v2 overview
category: migrating-to-v2
excerpt: >-
What changes when you move from Terratest v1 to v2, and the order to do
it in.
tags: ["migration", "v2"]
order: 400
nav_title: Documentation
nav_title_link: /docs/
---

Terratest v2 splits the single `github.com/gruntwork-io/terratest` module
into 16 independent modules, so you depend only on the parts you use. A
test that imports `terraform` no longer pulls in the AWS SDK, client-go,
and every other provider's dependencies.

The cost is that every import path changes. This page tells you what the
changes are and the order to apply them; the per-topic pages hold the
details.

## Should you migrate yet

v2 is in beta. v1 is in maintenance and receives security fixes only, until
12 months after v2.0.0 reaches general availability. Migrate now if you want
the smaller dependency graph or are starting fresh; wait for v2.0.0 if you
would rather not track beta releases.
Comment thread
james00012 marked this conversation as resolved.

You can migrate incrementally. v1 and v2 import paths differ, so both can
coexist in one module while you convert package by package. The change
touches only `.go` files, `go.mod` and `go.sum`, so `git checkout` undoes
it.

The minimum Go version is unchanged.

## The five changes

**1. Everything v1 deprecated is gone.** v1 kept deprecated aliases
alongside their replacements; v2 deletes them. This is the largest edit in
the migration, and it is not only the `Context` variants:

- non-`Context` wrappers: `terraform.Apply` is now only `ApplyContext`
- initialism renames: `random.UniqueId` is now `UniqueID`,
`aws.GetAccountIdE` is now `GetAccountIDContextE`
- reshaped helpers: `packer.BuildAmi` is now `BuildArtifactContextE`

The reliable way to find all of it is to run staticcheck against your
existing v1 code and clear every SA1019 (deprecated symbol) warning before
you touch imports. Once v1 is warning-free, the rest of this guide applies.

```go
// v1
out := terraform.Apply(t, options)
// v2
out := terraform.ApplyContext(t, t.Context(), options)
```

The `Context` variants always take `(t, ctx, ...originalArgs)`.
`t.Context()` is the best default; `context.Background()` also works. The
[v1 guide]({{site.baseurl}}/docs/migrating-to-v1/overview/) covers this
migration in detail, and doing it on v1 first, where both forms still
compile, is easier than doing it at the same time as the import rewrite.

**2. Import paths gain a `/v2` suffix.** The `/v2` goes after the module
root, not at the end of the path:

```go
// v1
"github.com/gruntwork-io/terratest/modules/terraform"
// v2
"github.com/gruntwork-io/terratest/modules/terraform/v2"
```

**3. Six utility packages collapse into `core`.** `random`, `files`,
`logger`, `shell`, `retry` and `testing` are no longer separate packages:

```go
// v1
"github.com/gruntwork-io/terratest/modules/random"
// v2
"github.com/gruntwork-io/terratest/modules/core/v2/random"
```

**4. Three packages are renamed to drop the hyphen.** This changes the
package identifier at call sites, not just the import path:

`http-helper` becomes `httphelper`, `dns-helper` becomes `dnshelper`, and
`test-structure` becomes `teststructure`. The full table is in the [import
map]({{site.baseurl}}/docs/migrating-to-v2/import-map/#renamed).

**5. Each module needs its own `require`.** Where v1 was one line in
`go.mod`, v2 needs one per module you import. Add them with `go get`
rather than by hand:

```bash
go get github.com/gruntwork-io/terratest/modules/terraform/v2@v2.0.0-beta.2
go get github.com/gruntwork-io/terratest/modules/aws/v2@v2.0.0-beta.2
```

Each module is tagged `modules/<name>/vX.Y.Z`, so the tag for the command
above is `modules/terraform/v2.0.0-beta.2`. The current version is on the
[releases page](https://github.com/gruntwork-io/terratest/releases). All 16
modules are released together and their cross-module requires are pinned to
the release version, so keep them on the same version.

The full path mapping is in [the import
map]({{site.baseurl}}/docs/migrating-to-v2/import-map/).

## Order to do it in

1. Move to the `Context` variants, ideally while still on v1 so both forms
compile.
2. Rewrite import paths and package identifiers. This is mechanical and the
compiler finds everything.
3. Fix the symbol relocations. Also compile errors, also mechanical. They
are listed under [rewriting
imports]({{site.baseurl}}/docs/migrating-to-v2/rewriting-imports/).
4. Add a `require` per module, then `go mod tidy`.
5. Review the [behavior
changes]({{site.baseurl}}/docs/migrating-to-v2/behavior-changes/), which
the compiler will *not* find for you. There are two, both in `k8s`.

Steps 1 to 4 are compiler-detectable, so the build tells you when they are
complete. Step 5 is not: the code compiles either way, so it needs reading
before you call the migration done.

## Removed packages

Six packages and two binaries are not carried forward. Three have a
standard library replacement:

| v1 | Replacement |
|---|---|
| `modules/collections` | stdlib `slices` |
| `modules/environment` | stdlib `os.Getenv` |
| `modules/git` | stdlib `os/exec` |
| `modules/slack` | none; vendor from v1 |
| `modules/version-checker` | none; shell out |
| `modules/oci` | none; Oracle Cloud is not carried forward, stay on v1 |

`cmd/pick-instance-type` and `cmd/terratest_log_parser` are gone as
binaries. The log parser's library survives at
`modules/core/v2/logger/parser`.

## What did not change

The `Foo` / `FooE` convention is unchanged: `FooContext` fails the test,
`FooContextE` returns an error. Beyond dropping the non-`Context` wrappers
and the relocations above, function arguments and return types are the
same. Test data written by v1 loads in v2, since filenames and JSON layout
are unchanged.

## Need help

Open an issue on the [Terratest
repo](https://github.com/gruntwork-io/terratest/issues) with the version
you are coming from and the error you hit. If you spot a gap in this
guide, send a PR against `docs/_docs/04_migrating-to-v2/`.
Loading
Loading