Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new -var args for tf plan. #300

Merged
merged 2 commits into from
Oct 1, 2018
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
45 changes: 14 additions & 31 deletions runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,41 +47,32 @@ 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"
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}"
}
}
```

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"
Expand All @@ -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}"`. 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.
:::

26 changes: 9 additions & 17 deletions server/events/runtime/plan_step_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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),
}
}

Expand Down
36 changes: 36 additions & 0 deletions server/events/runtime/plan_step_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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",
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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)
Expand Down Expand Up @@ -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",
Expand All @@ -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)
Expand Down Expand Up @@ -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",
Expand All @@ -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)
Expand Down Expand Up @@ -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",
Expand All @@ -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)
Expand Down