Skip to content

Commit

Permalink
Merge pull request #300 from runatlantis/atlantis-vars
Browse files Browse the repository at this point in the history
Add new -var args for tf plan.
  • Loading branch information
lkysow authored Oct 1, 2018
2 parents f8a0e08 + 2881bd9 commit 5f26c81
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 48 deletions.
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

0 comments on commit 5f26c81

Please sign in to comment.