Skip to content
This repository has been archived by the owner on Jun 4, 2024. It is now read-only.

Terrform custom registry generator & promotion script #457

Merged
merged 27 commits into from
Apr 27, 2022

Conversation

tcsc
Copy link
Contributor

@tcsc tcsc commented Mar 18, 2022

This script is intended to maintain a custom terraform registry that will be used to distribute the Teleport terraform provider.

The basic promotion steps are:

  1. retrieve he pre-built terraform provider(s) from the staging bucket
  2. repack them into a terraform-registry compatible format
  3. retrieve the current repository versions index file (if present)
  4. update (or create, if necessary) a local copy of the registry index, end
  5. push all of the generated & updated files up the S3 bucket that backs the registry

The promotion code runs in response to two events:

  1. A terraform tag build. The promotion is dairy-chained onto the terraform provider builds using Drone's depends_on pipeline config, and the resulting package is uploaded to a staging repository, and
  2. A release promotion, where the resulting package is uploaded to the production repository

The Drone YAML is configured to execute the same code in both cases, with different values supplied via the Drone environment.

@tcsc tcsc requested review from fheinecke, logand22 and wadells March 18, 2022 07:20
Copy link
Contributor

@wadells wadells left a comment

Choose a reason for hiding this comment

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

Go code LGTM.

I may have missed this in the RFD, but I think it might be good to "shift left" the zip repacking and signing from promote to tag. For instance, this is what the current workflow looks like:

  • tag -> publish to dronestorage
  • promote -> copy tar from dronestorage to clientbuilds, repack from tar to zip and sign, generate new index, write to release bucket

Ignoring the fact that dronestorage and clientbuilds need to die, I'd propose:

  • tag -> publish tar to dronestorage, repack from tar to zip and sign, publish to internal staging repo/bucket, generate new staging index
  • promote -> copy tar from dronestorage to clientbuilds, copy signed zip from internal staging repo to release bucket, generate new release index

The benefit here is we can test changes to the zip -> tar conversion, signing, and index generation without actually publishing to customers. This is pretty valuable, especially during the next month where we'll be iterating on this quite a bit.

An alternative is to have a mirror infra (e.g. buckets in teleport-dev where publishing can be tested safely), but my gut says that wiring up to Drone will be a pain.

tooling/internal/filename/parse_test.go Outdated Show resolved Hide resolved
tooling/internal/filename/parse_test.go Show resolved Hide resolved
@tcsc
Copy link
Contributor Author

tcsc commented Mar 19, 2022

it might be good to "shift left" the zip repacking

I think it's possible in Drone to daisy-chain a new pipeline onto the existing tag build using prerequisites or something similar. Will have to do some more research. If so, that should be pretty easy to plug this into the back of the existing tag-triggered build.

If not, my alternative was (similarly to yours, I think) to use Drone's notion of promotion environments to:

  1. set up separate testing and production environments, and
  2. publish to "staging" during development.

Although, this may be a bit more dangerous, as we'd have to make sure to pick the right env every time we promote.

my gut says that wiring up to Drone will be a pain.

I'll listen to your gut for now, at least in matters of Drone.

@tcsc tcsc changed the title Initial pass at the terrform promotion script. Still a WIP. Initial pass at the terrform promotion script. Mar 28, 2022
@tcsc tcsc marked this pull request as ready for review March 28, 2022 00:20
@tcsc tcsc requested review from wadells, logand22 and gzigzigzeo March 28, 2022 00:27
.drone.yml Outdated Show resolved Hide resolved
@tcsc tcsc changed the title Initial pass at the terrform promotion script. Terrform customr registry generator & promotion script Mar 28, 2022
@tcsc tcsc changed the title Terrform customr registry generator & promotion script Terrform custom registry generator & promotion script Mar 28, 2022
.drone.yml Outdated

steps:
- name: Upload terraform provider to staging registry
image: golang:1.17.5
Copy link
Contributor

Choose a reason for hiding this comment

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

I think, we could parameterise the required Go version as it seems equal for the whole suite (if Drone allows it).

@echo Testing plugins against Teleport $(TELEPORT_GET_VERSION)
go test -race -count 1 ./...
go test -race -count 1 $(shell go list ./...)
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if my comment is applicable here, but looks like. Terraform provider tests need env var TF_ENV=true to be specified (Terraform framework requirement). Terraform must be available as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is change is to avoid go test picking up the tooling module here. For some reason, in my testing, ./... included the tooling package and failed, where $(shell go list ./...) correctly treated it as a separate module.

Just tested it again now an all seems fine.

tooling/cmd/promote-terraform/main.go Outdated Show resolved Hide resolved
tooling/cmd/promote-terraform/main.go Outdated Show resolved Hide resolved
Copy link
Contributor

@r0mant r0mant left a comment

Choose a reason for hiding this comment

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

lgtm mostly, just a few suggestions

files = append(files, versionsFilePath)

// Finally, push the new index files to the production bucket
err = uploadRegistry(ctx, s3client, prodBucket.bucketName, workspace.productionDir, files)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there anything we can do on the tool side to make sure that the index file hasn't changed between when we downloaded it above and saving it here? In case we get simultaneous builds running somehow. I don't suppose S3 has something like compare-and-swap?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh how I tried to do this :-)

Short answer is that there is no way to do this in S3 alone, although we might be able to implement it with some other AWS services.

Here's what I looked into:

  • Definitely no CAS on S3
  • Creating a lockfile, even with s3 now having strong consistency, won't work as S3 has no atomic "put only if the there is nothing there already" primitive
  • S3 object locking exists, but is not really applicable to this problem. It works at a whole-bucket level and is designed to protect objects from accidental or malicious erasure, rather than locking out concurrent changes and just won't do what we want.

To use an all-AWS solution we would have to look at implementing locking with a DynamoDB table or somesuch, which is certainbly do-able, but is probably not a lot better than relying on Drone to serialize these jobs at the pipeline level.

tooling/internal/filename/parse.go Show resolved Hide resolved
tooling/internal/terraform/registry/protocol.go Outdated Show resolved Hide resolved
tooling/internal/terraform/registry/sha.go Outdated Show resolved Hide resolved
tooling/internal/terraform/registry/sign.go Outdated Show resolved Hide resolved
tooling/internal/terraform/registry/sign.go Outdated Show resolved Hide resolved
tooling/internal/terraform/registry/sign.go Outdated Show resolved Hide resolved
@tcsc tcsc requested a review from r0mant March 31, 2022 07:59
event:
- promote
target:
- production
Copy link
Contributor

Choose a reason for hiding this comment

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

I like to add both production and a pipeline specific production-terraform as triggers on promotion steps. This allows rerunning only the production-terraform step if something goes wrong with it without needing to rerun the entire pipeline -- good for speed and also not re-uploading other artifacts unnecessarily.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Excellent idea. Added an explicit staging build as well for this same reason

@tcsc tcsc force-pushed the tcsc/terraform-promotion-script branch from 7f46d17 to b2a75d7 Compare April 21, 2022 03:22
@tcsc tcsc merged commit b2ef071 into master Apr 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants