Skip to content

Commit

Permalink
Readme (runatlantis#92)
Browse files Browse the repository at this point in the history
* readme improvements

* Return plan errors back to the user

* README
  • Loading branch information
lkysow authored and anubhavmishra committed Aug 1, 2017
1 parent 1120087 commit 0ade406
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 91 deletions.
200 changes: 113 additions & 87 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,125 +10,152 @@ A unified workflow for collaborating on Terraform through GitHub.
- **Lock environments** until pull requests are merged to prevent concurrent modification and confusion

➜ Developers can write Terraform safely
- **No need to distribute AWS credentials** to your whole team! Developers can submit Terraform changes and run `plan` and `apply` directly from the pull request
- **No need to distribute AWS credentials** to your whole team. Developers can submit Terraform changes and run `plan` and `apply` directly from the pull request
- Optionally, require a **review and approval** prior to running `apply`

➜ Also
- No more **copy-pasted code across environments**. Atlantis supports using an `env/{env}.tfvars` file per environment so you can write your base configuration once
- Support **multiple versions of Terraform** with a simple project config file

## Getting Started
Atlantis runs as a server that receives GitHub webhooks. Once it's running and hooked up with GitHub, you can interact with it directly through GitHub comments.
* [Getting Started](#getting-started)
* [Production-Ready Deployment](#production-ready-deployment)
* [Install Terraform](#install-terraform)
* [Hosting Atlantis](#hosting-atlantis)
* [Add GitHub Webhook](#add-github-webhook)
* [Create a GitHub Token](#create-a-github-token)
* [Start Atlantis](#start-atlantis)
* [Testing Out Atlantis](#testing-out-atlantis)
* [Configuration](#configuration)
* [AWS Credentials](#aws-credentials)
* [Assume Role Session Names](#assume-role-session-names)
* [Environments](#environments)
* [Locking](#locking)
* [Glossary](#glossary)
* [Project](#project)
* [Environment](#environment)

### First Download Atlantis
## Getting Started
Download from https://github.com/hootsuite/atlantis/releases

### Start with `atlantis bootstrap` (recommended)
Run `atlantis bootstrap` to get started quickly with Atlantis.

If you want to manually run through all the steps that `bootstrap` performs, keep reading.

### Start Manually
To manually get started with Atlantis, you'll need to
- install `terraform` into your `$PATH`
- download from https://www.terraform.io/downloads.html
- `unzip path/to/terraform_*.zip -d /usr/local/bin`
- check that it's installed by running `terraform version`
- Atlantis needs to be reachable on an IP address or hostname that github.com can access. By default, Atlantis runs on port `4141` (this can be changed with the `--port` flag). You can install `ngrok` to make exposing Atlantis easy for testing purposes
- download from https://ngrok.com/download
- `unzip path/to/ngrok*.zip -d /usr/local/bin`
- start ngrok with `ngrok http 4141`
- Create a GitHub personal access token for Atlantis to use GitHub's API
- follow [https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token)
- copy the access token to your clipboard
- now you're ready to start Atlantis! Run:
Run
```
./atlantis bootstrap
```
This will walk you through running Atlantis locally. It will
- fork an example terraform project
- install terraform (if not already in your PATH)
- install ngrok so we can expose Atlantis to GitHub
- start Atlantis

If you're ready to permanently set up Atlantis see [Production-Ready Deployment](#production-ready-deployment)

## Production-Ready Deployment
### Install Terraform
`terraform` needs to be in the `$PATH` for Atlantis.
Download from https://www.terraform.io/downloads.html
```
unzip path/to/terraform_*.zip -d /usr/local/bin
```
Check that it's in your `$PATH`
```
$ terraform version
Terraform v0.9.11
```
If you want to use a different version of Terraform see [Terraform Versions](#terraform-versions)

### Hosting Atlantis
Atlantis needs to be hosted somewhere that github.com or your GitHub Enterprise installation can reach. Developers in your organization also need to be able to access Atlantis to view the UI and to delete locks.

By default Atlantis runs on port `4141`. This can be changed with the `--port` flag.

### Add GitHub Webhook
Once you've decided where to host Atlantis you can add it as a Webhook to GitHub.
If you already have a GitHub organization we recommend installing the webhook at the **organization level** rather than on each repository, however both methods will work.

> If you're not sure if you have a GitHub organization see https://help.github.com/articles/differences-between-user-and-organization-accounts/
If you're installing on the organization, navigate to your organization's page and click **Settings**.
If installing on a single repository, navigate to the repository home page and click **Settings**.
- Select **Webhooks** or **Hooks** in the sidebar
- Click **Add webhook**
- set **Payload URL** to `http://$URL/events` where `$URL` is where Atlantis is hosted. **Be sure to add `/events`**
- set **Content type** to `application/json`
- leave **Secret** blank
- select **Let me select individual events**
- check the boxes
- **Pull request review**
- **Push**
- **Issue comment**
- **Pull request**
- leave **Active** checked
- click **Add webhook**

### Create a GitHub Token
We recommend creating a new user in GitHub named **atlantis** that performs all API actions however you can use any user.
Once you've created the user (or have decided to use an existing user) you need to create a personal access token.
- follow [https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/#creating-a-token)
- copy the access token

### Start Atlantis
Now you're ready to start Atlantis! Run
```
$ atlantis server --atlantis-url $URL --gh-username $USERNAME --gh-token $TOKEN
2049/10/6 00:00:00 [WARN] server: Atlantis started - listening on port 4141
```

- where `$URL` is the URL that Atlantis can be reached at. If using `ngrok` it will be something like `https://68da2fdd.ngrok.io`
- where `$USERNAME` is your GitHub username
- where `$TOKEN` is the access token you created

Now that Atlantis is running, it's time to test it out. You'll need to set up a pull request first

- Fork https://github.com/hootsuite/atlantis-example to your user
- Add Atlantis as a webhook to the forked repo
- navigate to `{your-repo-url}/settings/hooks/new`, ex. https://github.com/hootsuite/atlantis-example/settings/hooks/new
- set **Payload URL** to `$URL/events` where `$URL` is what you used above, ex. `https://68da2fdd.ngrok.io/events`. **Be sure to add `/events` to the end**
- set **Content type** to `application/json`
- leave **Secret** blank
- select **Let me select individual events**
- check the boxes
- **Pull request review**
- **Push**
- **Issue comment**
- **Pull request**
- leave **Active** checked
- click **Add webhook**
- Now that Atlantis can receive events you should be able to comment on a pull request to trigger Atlantis. Let's create a pull request
- Navigate to `{your-repo-url}/branches`, ex. https://github.com/hootsuite/atlantis-example/branches
- `$URL` is the URL that Atlantis can be reached at
- `$USERNAME` is the GitHub username you generated the token for
- `$TOKEN` is the access token you created. If you don't want this to be passed in as an argument for security reasons you can specify it in a config file (see [Configuration](#configuration)) or as an environment variable: `ATLANTIS_GH_TOKEN`

Atlantis is now running!
**We recommend running it under something like Systemd or Supervisord.**

### Testing Out Atlantis

If you'd like to test out Atlantis before running it on your own repositories you can fork our example repo.

- Fork https://github.com/hootsuite/atlantis-example
- If you didn't add the Webhook as to your organization add Atlantis as a Webhook to the forked repo (see [Add GitHub Webhook](#add-github-webhook))
- Now that Atlantis can receive events you should be able to comment on a pull request to trigger Atlantis. Create a pull request
- Click **Branches** on your forked repo's homepage
- click the **New pull request** button next to the `example` branch
- Change the `base` to `{your-repo}/master`
- click **Create pull request**
- Finally we're ready to talk to Atlantis!
- Now you can test out Atlantis
- Create a comment `atlantis help` to see what commands you can run from the pull request
- `atlantis plan` will run `terraform plan` behind the scenes. You should see the output commented back on the pull request. You should also see some logs show up where you're running `atlantis server`
- You could also type `atlantis apply` but since you may not have AWS credentials set up this probably won't work TODO: VERIFY THIS

You're done! If you're ready to set up Atlantis for a production deployment, see [Production-Ready Deployment](#Production-Ready+Deployment)
- `atlantis apply` will run `terraform apply`. Since our pull request creates a `null_resource` (which does nothing) this is safe to do.


## Production-Ready Deployment

## Configuration
Atlantis configuration can be specified via command line flags or a YAML config file.

```
$ atlantis server --help
...
Usage:
atlantis server [flags]
Flags:
--atlantis-url string Url that Atlantis can be reached at. Defaults to http://$(hostname):$port where $port comes from the port flag.
--aws-assume-role-arn string ARN of the role to assume when running Terraform against AWS. If not using assume role, no need to set.
--aws-region string The Amazon region to connect to for API actions. (default "us-east-1")
--config string Path to config file.
--data-dir string Path to directory to store Atlantis data. (default "~/.atlantis")
--gh-hostname string Hostname of your Github Enterprise installation. If using github.com, no need to set. (default "github.com")
--gh-password string [REQUIRED] GitHub password of API user. Can also be specified via the ATLANTIS_GH_PASSWORD environment variable.
--gh-user string [REQUIRED] GitHub username of API user.
-h, --help help for server
--log-level string Log level. Either debug, info, warn, or error. (default "warn")
--port int Port to bind to. (default 4141)
--require-approval Require pull requests to be "Approved" before allowing the apply command to be run. (default true)
```

The `gh-password` flag can also be specified via an `ATLANTIS_GH_PASSWORD` environment variable.
The `gh-token` flag can also be specified via an `ATLANTIS_GH_TOKEN` environment variable.
Config file values are overridden by environment variables which in turn are overridden by flags.

To use a yaml config file, run atlantis with `--config /path/to/config.yaml`.
The keys of your config file should be the same as the flag, ex.
```yaml
---
log-level: debug
gh-token: ...
log-level: ...
```
To see a list of all flags and their descriptions run `atlantis server -h`
To see a list of all flags and their descriptions run `atlantis server --help`

## AWS Credentials
Atlantis simply shells out to `terraform` so you don't need to do anything special with AWS credentials.
As long as `terraform` works where you're hosting Atlantis, then Atlantis will work.
See https://www.terraform.io/docs/providers/aws/#authentication for more detail.

### AWS Credentials
Atlantis handles AWS credentials in the same way as Terraform.
It looks in the regular places for AWS credentials in this order:
1. `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables
2. The AWS credentials file located at `~/.aws/credentials`
3. Instance profile credentials if Atlantis is running on an EC2 instance
### Assume Role Session Names
Atlantis provides the ability to use AWS's Assume Role and **dynamically name the session** with the GitHub username of whoever commented `atlantis apply`.

One additional feature of Atlantis is the ability to use the AWS Security Token Service (STS)
to assume a role (specified by the `--aws-assume-role-arn` flag) and **dynamically
name the session** with the GitHub username of whoever is running `atlantis apply`.
To take advantage of this feature, simply set the `--aws-assume-role-arn` flag.
This is used at Hootsuite so AWS API actions can be correlated with a specific user.
To take advantage of this feature, simply set the `--aws-assume-role-arn` flag to the
role to be assumed: `arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME`.

If you're using Terraform's [built-in support](https://www.terraform.io/docs/providers/aws/#assume-role) for assume role then there is no need to set this flag (unless you also want your sessions to take the name of the GitHub user).

## Environments

Expand All @@ -141,12 +168,11 @@ users from seeing a `plan` that will be invalid if another pull request is merge
To unlock the project and environment without completing an `apply`, click the link
at the bottom of each plan to discard the plan and delete the lock.

## `atlantis.yaml` Config File

## Glossary
#### Project
A Terraform project. Multiple projects can be in a single GitHub repo.

#### Environment
A Terraform environment. See [terraform docs](https://www.terraform.io/docs/state/environments.html) for more information.


9 changes: 5 additions & 4 deletions terraform/terraform_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,13 @@ func (c *Client) RunCommandWithVersion(log *logging.SimpleLogger, path string, a
terraformCmd.Env = append(os.Environ(), envVars...)
}
out, err := terraformCmd.CombinedOutput()
commandStr := strings.Join(terraformCmd.Args, " ")
if err != nil {
// show debug output for terraform commands if they fail, helpful for debugging
log.Debug("error running %q in %q: \n%s", strings.Join(terraformCmd.Args, " "), path, out)
return "", fmt.Errorf("%s: running %q in %q", err, strings.Join(terraformCmd.Args, " "), path)
err := fmt.Errorf("%s: running %q in %q: %s", err, commandStr, path, out)
log.Debug("error: %s", err)
return "", err
}
log.Info("successfully ran %q in %q", strings.Join(terraformCmd.Args, " "), path)
log.Info("successfully ran %q in %q", commandStr, path)
return string(out), nil
}

Expand Down

0 comments on commit 0ade406

Please sign in to comment.