From e69c36ad5583c0f821a667cab9b83c2d41d2025d Mon Sep 17 00:00:00 2001 From: Luke Kysow Date: Mon, 1 Oct 2018 11:35:45 -0500 Subject: [PATCH 1/2] Add new -var args for tf plan. Previously we added -var atlantis_repo=runatlantis/atlantis but the '/' character is not a valid character for the AWS assume role session name. To fix this, this commit adds -var atlantis_repo_owner=runatlantis and -var atlantis_repo_name=atlantis (where runatlantis and atlantis would be the values for the repo the pull request is from ). --- runatlantis.io/docs/server-configuration.md | 4 +-- server/events/runtime/plan_step_runner.go | 26 +++++--------- .../events/runtime/plan_step_runner_test.go | 36 +++++++++++++++++++ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/runatlantis.io/docs/server-configuration.md b/runatlantis.io/docs/server-configuration.md index 7ab368d5a1..0258bfa697 100644 --- a/runatlantis.io/docs/server-configuration.md +++ b/runatlantis.io/docs/server-configuration.md @@ -70,7 +70,7 @@ variable "atlantis_pull_num" { provider "aws" { assume_role { role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" - session_name = "${var.atlantis_user}-${var.atlantis_repo}-${var.atlantis_pull_num}" + session_name = "${var.atlantis_user}-${var.atlantis_repo_owner}-${var.atlantis_repo_name}-${var.atlantis_pull_num}" } } ``` @@ -97,7 +97,7 @@ terraform { ::: warning Terraform doesn't support interpolations in backend config so you will not be -able to use `session_name = "${var.atlantis_user}"`. However, the backend assumed +able to use `session_name = "${var.atlantis_user}"` in your backend block. However, the backend assumed role is only used for state-related API actions. Any other API actions will be performed using the assumed role specified in the `aws` provider and will have the session named as the GitHub user. ::: diff --git a/server/events/runtime/plan_step_runner.go b/server/events/runtime/plan_step_runner.go index 87426a0a71..367ed6196e 100644 --- a/server/events/runtime/plan_step_runner.go +++ b/server/events/runtime/plan_step_runner.go @@ -10,18 +10,6 @@ import ( "github.com/runatlantis/atlantis/server/events/models" ) -// atlantisUserTFVar is the name of the tf variable we execute terraform -// with set to the vcs username of who caused the plan command to run. -const atlantisUserTFVar = "atlantis_user" - -// atlantisRepoTFVar is the name of the tf variable we execute terraform -// with set to the full name of the repository this pull request is from, ex. -// "runatlantis/atlantis", "repo/gitlab/subgroup". -const atlantisRepoTFVar = "atlantis_repo" - -// atlantisPullNumTFVar is the name of the tf variable we execute terraform -// with set to the number of the pull request. -const atlantisPullNumTFVar = "atlantis_pull_num" const defaultWorkspace = "default" type PlanStepRunner struct { @@ -96,7 +84,7 @@ func (p *PlanStepRunner) switchWorkspace(ctx models.ProjectCommandContext, path } func (p *PlanStepRunner) buildPlanCmd(ctx models.ProjectCommandContext, extraArgs []string, path string) []string { - tfVars := p.tfVars(ctx.User.Username, ctx.BaseRepo.FullName, ctx.Pull.Num) + tfVars := p.tfVars(ctx) planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectConfig)) // Check if env/{workspace}.tfvars exist and include it. This is a use-case @@ -126,16 +114,20 @@ func (p *PlanStepRunner) buildPlanCmd(ctx models.ProjectCommandContext, extraArg // repo this command is running for. This can be used for naming the // session name in AWS which will identify in CloudTrail the source of // Atlantis API calls. -func (p *PlanStepRunner) tfVars(username string, baseRepoFullName string, pullNum int) []string { +func (p *PlanStepRunner) tfVars(ctx models.ProjectCommandContext) []string { // NOTE: not using maps and looping here because we need to keep the // ordering for testing purposes. return []string{ "-var", - fmt.Sprintf("%s=%s", atlantisUserTFVar, username), + fmt.Sprintf("%s=%s", "atlantis_user", ctx.User.Username), "-var", - fmt.Sprintf("%s=%s", atlantisRepoTFVar, baseRepoFullName), + fmt.Sprintf("%s=%s", "atlantis_repo", ctx.BaseRepo.FullName), "-var", - fmt.Sprintf("%s=%d", atlantisPullNumTFVar, pullNum), + fmt.Sprintf("%s=%s", "atlantis_repo_name", ctx.BaseRepo.Name), + "-var", + fmt.Sprintf("%s=%s", "atlantis_repo_owner", ctx.BaseRepo.Owner), + "-var", + fmt.Sprintf("%s=%d", "atlantis_pull_num", ctx.Pull.Num), } } diff --git a/server/events/runtime/plan_step_runner_test.go b/server/events/runtime/plan_step_runner_test.go index 617ca85ae4..82bd67084a 100644 --- a/server/events/runtime/plan_step_runner_test.go +++ b/server/events/runtime/plan_step_runner_test.go @@ -46,6 +46,8 @@ func TestRun_NoWorkspaceIn08(t *testing.T) { }, BaseRepo: models.Repo{ FullName: "owner/repo", + Owner: "owner", + Name: "repo", }, }, []string{"extra", "args"}, "/path") Ok(t, err) @@ -65,6 +67,10 @@ func TestRun_NoWorkspaceIn08(t *testing.T) { "-var", "atlantis_repo=owner/repo", "-var", + "atlantis_repo_name=repo", + "-var", + "atlantis_repo_owner=owner", + "-var", "atlantis_pull_num=2", "extra", "args", @@ -167,6 +173,8 @@ func TestRun_SwitchesWorkspace(t *testing.T) { }, BaseRepo: models.Repo{ FullName: "owner/repo", + Owner: "owner", + Name: "repo", }, }, []string{"extra", "args"}, "/path") Ok(t, err) @@ -194,6 +202,10 @@ func TestRun_SwitchesWorkspace(t *testing.T) { "-var", "atlantis_repo=owner/repo", "-var", + "atlantis_repo_name=repo", + "-var", + "atlantis_repo_owner=owner", + "-var", "atlantis_pull_num=2", "extra", "args", @@ -259,6 +271,10 @@ func TestRun_CreatesWorkspace(t *testing.T) { "-var", "atlantis_repo=owner/repo", "-var", + "atlantis_repo_name=repo", + "-var", + "atlantis_repo_owner=owner", + "-var", "atlantis_pull_num=2", "extra", "args", @@ -277,6 +293,8 @@ func TestRun_CreatesWorkspace(t *testing.T) { }, BaseRepo: models.Repo{ FullName: "owner/repo", + Owner: "owner", + Name: "repo", }, }, []string{"extra", "args"}, "/path") Ok(t, err) @@ -313,6 +331,10 @@ func TestRun_NoWorkspaceSwitchIfNotNecessary(t *testing.T) { "-var", "atlantis_repo=owner/repo", "-var", + "atlantis_repo_name=repo", + "-var", + "atlantis_repo_owner=owner", + "-var", "atlantis_pull_num=2", "extra", "args", @@ -331,6 +353,8 @@ func TestRun_NoWorkspaceSwitchIfNotNecessary(t *testing.T) { }, BaseRepo: models.Repo{ FullName: "owner/repo", + Owner: "owner", + Name: "repo", }, }, []string{"extra", "args"}, "/path") Ok(t, err) @@ -375,6 +399,10 @@ func TestRun_AddsEnvVarFile(t *testing.T) { "-var", "atlantis_repo=owner/repo", "-var", + "atlantis_repo_name=repo", + "-var", + "atlantis_repo_owner=owner", + "-var", "atlantis_pull_num=2", "extra", "args", @@ -396,6 +424,8 @@ func TestRun_AddsEnvVarFile(t *testing.T) { }, BaseRepo: models.Repo{ FullName: "owner/repo", + Owner: "owner", + Name: "repo", }, }, []string{"extra", "args"}, tmpDir) Ok(t, err) @@ -430,6 +460,10 @@ func TestRun_UsesDiffPathForProject(t *testing.T) { "-var", "atlantis_repo=owner/repo", "-var", + "atlantis_repo_name=repo", + "-var", + "atlantis_repo_owner=owner", + "-var", "atlantis_pull_num=2", "extra", "args", @@ -453,6 +487,8 @@ func TestRun_UsesDiffPathForProject(t *testing.T) { }, BaseRepo: models.Repo{ FullName: "owner/repo", + Owner: "owner", + Name: "repo", }, }, []string{"extra", "args"}, "/path") Ok(t, err) From 2881bd9012ab9283604788707d307b2c5013787a Mon Sep 17 00:00:00 2001 From: Luke Kysow Date: Mon, 1 Oct 2018 13:28:06 -0500 Subject: [PATCH 2/2] Update docs for new -var arguments. --- runatlantis.io/docs/server-configuration.md | 43 +++++++-------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/runatlantis.io/docs/server-configuration.md b/runatlantis.io/docs/server-configuration.md index 0258bfa697..cffd530788 100644 --- a/runatlantis.io/docs/server-configuration.md +++ b/runatlantis.io/docs/server-configuration.md @@ -47,26 +47,11 @@ won't work for multiple accounts since Atlantis wouldn't know which environment Terraform with. ### Assume Role Session Names -Atlantis injects 3 Terraform variables that can be used to dynamically name the assume role -session: +Atlantis injects 5 Terraform variables that can be used to dynamically name the assume role session name. +Setting the `session_name` allows you to trace API calls made through Atlantis back to a specific +user and repo via CloudWatch: ```bash -# Set to the VCS username of who is running the plan command, ex. lkysow -variable "atlantis_user" { - default = "atlantis_user" -} - -# Set to the full name of the repo the pull request is in, ex. runatlantis/atlantis -variable "atlantis_repo" { - default = "atlantis_repo" -} - -# Set to the pull request number, ex. 200 -variable "atlantis_pull_num" { - default = "atlantis_pull_num" -} - -# Can be used within the assume_role block for session_name. provider "aws" { assume_role { role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" @@ -75,13 +60,19 @@ provider "aws" { } ``` -Setting `session_name` allows you to trace where API calls made through Atlantis came from in -CloudWatch. +Atlantis runs `terraform` with the following variables: +| `-var` Argument | Description | +|-------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------| +| `atlantis_user=lkysow` | The VCS username of who is running the plan command. | +| `atlantis_repo=runatlantis/atlantis` | The full name of the repo the pull request is in. NOTE: This variable can't be used in the AWS session name because it contains a `/`. | +| `atlantis_repo_owner=runatlantis` | The name of the **owner** of the repo the pull request is in. | +| `atlantis_repo_name=atlantis` | The name of the repo the pull request is in. | +| `atlantis_pull_num=200` | The pull request number. | -If you're also using the [S3 Backend](https://www.terraform.io/docs/backends/types/s3.html) +If you want to use `assume_role` with Atlantis and you're also using the [S3 Backend](https://www.terraform.io/docs/backends/types/s3.html), make sure to add the `role_arn` option: -```hcl +```bash terraform { backend "s3" { bucket = "mybucket" @@ -94,11 +85,3 @@ terraform { } } ``` - -::: warning -Terraform doesn't support interpolations in backend config so you will not be -able to use `session_name = "${var.atlantis_user}"` in your backend block. However, the backend assumed -role is only used for state-related API actions. Any other API actions will be performed using -the assumed role specified in the `aws` provider and will have the session named as the GitHub user. -::: -