mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-08-03 22:38:45 +00:00
Make bootstrap re-runnable. README edits
This commit is contained in:
3
Makefile
3
Makefile
@@ -33,6 +33,9 @@ test-coverage:
|
||||
dist: ## Package up everything in static/ using go-bindata-assetfs so it can be served by a single binary
|
||||
go-bindata-assetfs -pkg server static/... && mv bindata_assetfs.go server
|
||||
|
||||
release: ## Create packages for a release
|
||||
gox -os="darwin linux" -arch="amd64"
|
||||
|
||||
vendor-status:
|
||||
@govendor status
|
||||
|
||||
|
||||
30
README.md
30
README.md
@@ -1,14 +1,24 @@
|
||||
# atlantis
|
||||

|
||||
|
||||
A unified workflow for collaborating on Terraform through GitHub.
|
||||
|
||||
[](https://circleci.com/gh/hootsuite/atlantis/tree/master)
|
||||
|
||||
A unified workflow for collaborating on Terraform through GitHub.
|
||||
* [Features](#features)
|
||||
* [Getting Started](#getting-started)
|
||||
* [Production-Ready Deployment](#production-ready-deployment)
|
||||
* [Configuration](#configuration)
|
||||
* [AWS Credentials](#aws-credentials)
|
||||
* [Environments](#environments)
|
||||
* [Locking](#locking)
|
||||
* [Glossary](#glossary)
|
||||
* [Project](#project)
|
||||
* [Environment](#environment)
|
||||
|
||||
## Features
|
||||
➜ Collaborate on Terraform with your team
|
||||
- Run terraform `plan` and `apply` **from GitHub pull requests** so everyone can review the output
|
||||

|
||||
- **Lock environments** until pull requests are merged to prevent concurrent modification and confusion
|
||||
|
||||
➜ Developers can write Terraform safely
|
||||
@@ -19,22 +29,6 @@ A unified workflow for collaborating on Terraform through GitHub.
|
||||
- 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](#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)
|
||||
|
||||
## Getting Started
|
||||
Download from https://github.com/hootsuite/atlantis/releases
|
||||
|
||||
@@ -36,7 +36,7 @@ var pullRequestBody = "In this pull request we will learn how to use atlantis. T
|
||||
"* Start by typing `atlantis help` in the comments.\n" +
|
||||
"* Next, lets plan by typing `atlantis plan` in the comments. That will run a `terraform plan`.\n" +
|
||||
"* Now lets apply that plan. Type `atlantis apply` in the comments. This will run a `terraform apply`.\n" +
|
||||
"\nThank you for using atlantis. For more info on running atlantis in production please follow: https://atlantis.run/link/to/doc"
|
||||
"\nThank you for trying out atlantis. For more info on running atlantis in production see https://github.com/hootsuite/atlantis"
|
||||
|
||||
func Start() error {
|
||||
s := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
||||
@@ -133,11 +133,16 @@ Follow these instructions to create a token (we don't store any tokens):
|
||||
time.Sleep(2 * time.Second)
|
||||
s.Stop()
|
||||
colorstring.Println("\n[green]=> started tunnel!")
|
||||
tunnelURL, err := getTunnelAddr()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "getting tunnel url")
|
||||
}
|
||||
s.Stop()
|
||||
|
||||
// start atlantis server
|
||||
colorstring.Printf("[white]=> starting atlantis server ")
|
||||
s.Start()
|
||||
atlantisCmd, err := executeCmd("./atlantis", []string{"server", "--gh-user", githubUsername, "--gh-token", githubToken, "--data-dir", "/tmp/atlantis/data"})
|
||||
atlantisCmd, err := executeCmd(os.Args[0], []string{"server", "--gh-user", githubUsername, "--gh-token", githubToken, "--data-dir", "/tmp/atlantis/data", "--atlantis-url", tunnelURL})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "creating atlantis server")
|
||||
}
|
||||
@@ -148,12 +153,6 @@ Follow these instructions to create a token (we don't store any tokens):
|
||||
}()
|
||||
// if this function returns atlantis server should be stopped
|
||||
defer atlantisCmd.Process.Kill()
|
||||
|
||||
tunnelURL, err := getTunnelAddr()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "getting tunnel url")
|
||||
}
|
||||
s.Stop()
|
||||
colorstring.Printf("\n[green]=> atlantis server is now securely exposed at [bold][underline]%s", tunnelURL)
|
||||
fmt.Println("")
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/google/go-github/github"
|
||||
)
|
||||
|
||||
var githubHostname = "http://api.github.com"
|
||||
var githubUsername string
|
||||
var githubToken string
|
||||
|
||||
@@ -61,8 +60,22 @@ func (g *Client) CreateWebhook(ownerName string, repoName string, hookURL string
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreatePullRequest creates a github pull request with custom title and description
|
||||
// CreatePullRequest creates a github pull request with custom title and description.
|
||||
// It first checks if there's already a pull request open for this branch
|
||||
func (g *Client) CreatePullRequest(ownerName string, repoName string, head string, base string) (string, error) {
|
||||
|
||||
// first check if the pull request already exists
|
||||
pulls, _, err := g.client.PullRequests.List(g.ctx, ownerName, repoName, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, pull := range pulls {
|
||||
if pull.Head.GetRef() == head && pull.Base.GetRef() == base {
|
||||
return pull.GetHTMLURL(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// if not, create it
|
||||
newPullRequest := &github.NewPullRequest{
|
||||
Title: github.String("Welcome to Atlantis!"),
|
||||
Head: github.String(head),
|
||||
|
||||
@@ -33,7 +33,7 @@ const (
|
||||
var stringFlags = []stringFlag{
|
||||
{
|
||||
name: atlantisURLFlag,
|
||||
description: "Url that Atlantis can be reached at. Defaults to http://$(hostname):$port where $port comes from the port flag.",
|
||||
description: "Url that Atlantis can be reached at. Defaults to http://$(hostname):$port where $port is from --" + portFlag + ".",
|
||||
},
|
||||
{
|
||||
name: awsAssumeRoleFlag,
|
||||
@@ -41,7 +41,7 @@ var stringFlags = []stringFlag{
|
||||
},
|
||||
{
|
||||
name: awsRegionFlag,
|
||||
description: "The Amazon region to connect to for API actions.",
|
||||
description: "Amazon region to use for assume role. If not setting --" + awsAssumeRoleFlag + " then ignore.",
|
||||
value: "us-east-1",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -125,22 +125,28 @@ func (a *ApplyExecutor) apply(ctx *CommandContext, repoDir string, plan models.P
|
||||
applyExtraArgs = config.GetExtraArguments(ctx.Command.Name.String())
|
||||
}
|
||||
|
||||
awsSession, err := a.awsConfig.CreateSession(ctx.User.Username)
|
||||
if err != nil {
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
creds, err := awsSession.Config.Credentials.Get()
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "getting aws credentials")
|
||||
ctx.Log.Err(err.Error())
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
ctx.Log.Info("created aws session")
|
||||
// todo: de-duplicate this section between plan and apply
|
||||
var credsEnvVars []string
|
||||
// If awsConfig is nil we know that we're not using assume role and so
|
||||
// don't need to do an AWS calls ourselves
|
||||
if a.awsConfig != nil {
|
||||
awsSession, err := a.awsConfig.CreateSession(ctx.User.Username)
|
||||
if err != nil {
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
creds, err := awsSession.Config.Credentials.Get()
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "getting aws credentials")
|
||||
ctx.Log.Err(err.Error())
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
ctx.Log.Info("created aws session")
|
||||
|
||||
credsEnvVars := []string{
|
||||
fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", creds.AccessKeyID),
|
||||
fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", creds.SecretAccessKey),
|
||||
fmt.Sprintf("AWS_SESSION_TOKEN=%s", creds.SessionToken),
|
||||
credsEnvVars = []string{
|
||||
fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", creds.AccessKeyID),
|
||||
fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", creds.SecretAccessKey),
|
||||
fmt.Sprintf("AWS_SESSION_TOKEN=%s", creds.SessionToken),
|
||||
}
|
||||
}
|
||||
|
||||
// check if terraform version is >= 0.9.0
|
||||
|
||||
@@ -80,10 +80,10 @@ func (g *GithubCommentRenderer) renderProjectResults(pathResults []ProjectResult
|
||||
if result.Error != nil {
|
||||
results[result.Path] = g.renderTemplate(errTmpl, struct {
|
||||
Command string
|
||||
Error string
|
||||
Error string
|
||||
}{
|
||||
Command: common.Command,
|
||||
Error: result.Error.Error(),
|
||||
Error: result.Error.Error(),
|
||||
})
|
||||
} else if result.Failure != "" {
|
||||
results[result.Path] = g.renderTemplate(failureTmpl, struct {
|
||||
|
||||
@@ -119,23 +119,29 @@ func (p *PlanExecutor) plan(ctx *CommandContext, repoDir string, project models.
|
||||
planExtraArgs = config.GetExtraArguments(ctx.Command.Name.String())
|
||||
}
|
||||
|
||||
awsSession, err := p.awsConfig.CreateSession(ctx.User.Username)
|
||||
if err != nil {
|
||||
ctx.Log.Err(err.Error())
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
creds, err := awsSession.Config.Credentials.Get()
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "getting aws credentials")
|
||||
ctx.Log.Err(err.Error())
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
ctx.Log.Info("created aws session")
|
||||
// todo: de-duplicate this section between plan and apply
|
||||
var credsEnvVars []string
|
||||
// If awsConfig is nil we know that we're not using assume role and so
|
||||
// don't need to do an AWS calls ourselves
|
||||
if p.awsConfig != nil {
|
||||
awsSession, err := p.awsConfig.CreateSession(ctx.User.Username)
|
||||
if err != nil {
|
||||
ctx.Log.Err(err.Error())
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
creds, err := awsSession.Config.Credentials.Get()
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "getting aws credentials")
|
||||
ctx.Log.Err(err.Error())
|
||||
return ProjectResult{Error: err}
|
||||
}
|
||||
ctx.Log.Info("created aws session")
|
||||
|
||||
credsEnvVars := []string{
|
||||
fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", creds.AccessKeyID),
|
||||
fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", creds.SecretAccessKey),
|
||||
fmt.Sprintf("AWS_SESSION_TOKEN=%s", creds.SessionToken),
|
||||
credsEnvVars = []string{
|
||||
fmt.Sprintf("AWS_ACCESS_KEY_ID=%s", creds.AccessKeyID),
|
||||
fmt.Sprintf("AWS_SECRET_ACCESS_KEY=%s", creds.SecretAccessKey),
|
||||
fmt.Sprintf("AWS_SESSION_TOKEN=%s", creds.SessionToken),
|
||||
}
|
||||
}
|
||||
|
||||
// check if terraform version is >= 0.9.0
|
||||
|
||||
@@ -87,9 +87,15 @@ func NewServer(config ServerConfig) (*Server, error) {
|
||||
return nil, errors.Wrap(err, "initializing terraform")
|
||||
}
|
||||
githubComments := &GithubCommentRenderer{}
|
||||
awsConfig := &aws.Config{
|
||||
Region: config.AWSRegion,
|
||||
RoleARN: config.AssumeRole,
|
||||
|
||||
// a nil awsConfig indicates that we won't be doing any AWS
|
||||
// config in Atlantis
|
||||
var awsConfig *aws.Config
|
||||
if config.AssumeRole != "" {
|
||||
awsConfig = &aws.Config{
|
||||
Region: config.AWSRegion,
|
||||
RoleARN: config.AssumeRole,
|
||||
}
|
||||
}
|
||||
|
||||
boltdb, err := boltdb.New(config.DataDir)
|
||||
|
||||
Reference in New Issue
Block a user