github.com/pdecat/terraform@v0.11.9-beta1/backend/atlas/backend.go (about) 1 package atlas 2 3 import ( 4 "context" 5 "fmt" 6 "net/url" 7 "os" 8 "strings" 9 "sync" 10 11 "github.com/hashicorp/terraform/backend" 12 "github.com/hashicorp/terraform/helper/schema" 13 "github.com/hashicorp/terraform/state" 14 "github.com/hashicorp/terraform/state/remote" 15 "github.com/hashicorp/terraform/terraform" 16 "github.com/mitchellh/cli" 17 "github.com/mitchellh/colorstring" 18 ) 19 20 // Backend is an implementation of EnhancedBackend that performs all operations 21 // in Atlas. State must currently also be stored in Atlas, although it is worth 22 // investigating in the future if state storage can be external as well. 23 type Backend struct { 24 // CLI and Colorize control the CLI output. If CLI is nil then no CLI 25 // output will be done. If CLIColor is nil then no coloring will be done. 26 CLI cli.Ui 27 CLIColor *colorstring.Colorize 28 29 // ContextOpts are the base context options to set when initializing a 30 // Terraform context. Many of these will be overridden or merged by 31 // Operation. See Operation for more details. 32 ContextOpts *terraform.ContextOpts 33 34 //--------------------------------------------------------------- 35 // Internal fields, do not set 36 //--------------------------------------------------------------- 37 // stateClient is the legacy state client, setup in Configure 38 stateClient *stateClient 39 40 // schema is the schema for configuration, set by init 41 schema *schema.Backend 42 43 // opLock locks operations 44 opLock sync.Mutex 45 } 46 47 // New returns a new initialized Atlas backend. 48 func New() *Backend { 49 b := &Backend{} 50 b.schema = &schema.Backend{ 51 Schema: map[string]*schema.Schema{ 52 "name": &schema.Schema{ 53 Type: schema.TypeString, 54 Required: true, 55 Description: schemaDescriptions["name"], 56 }, 57 58 "access_token": &schema.Schema{ 59 Type: schema.TypeString, 60 Required: true, 61 Description: schemaDescriptions["access_token"], 62 DefaultFunc: schema.EnvDefaultFunc("ATLAS_TOKEN", nil), 63 }, 64 65 "address": &schema.Schema{ 66 Type: schema.TypeString, 67 Optional: true, 68 Description: schemaDescriptions["address"], 69 DefaultFunc: schema.EnvDefaultFunc("ATLAS_ADDRESS", defaultAtlasServer), 70 }, 71 }, 72 73 ConfigureFunc: b.configure, 74 } 75 76 return b 77 } 78 79 func (b *Backend) configure(ctx context.Context) error { 80 d := schema.FromContextBackendConfig(ctx) 81 82 // Parse the address 83 addr := d.Get("address").(string) 84 addrUrl, err := url.Parse(addr) 85 if err != nil { 86 return fmt.Errorf("Error parsing 'address': %s", err) 87 } 88 89 // Parse the org/env 90 name := d.Get("name").(string) 91 parts := strings.Split(name, "/") 92 if len(parts) != 2 { 93 return fmt.Errorf("malformed name '%s', expected format '<org>/<name>'", name) 94 } 95 org := parts[0] 96 env := parts[1] 97 98 // Setup the client 99 b.stateClient = &stateClient{ 100 Server: addr, 101 ServerURL: addrUrl, 102 AccessToken: d.Get("access_token").(string), 103 User: org, 104 Name: env, 105 106 // This is optionally set during Atlas Terraform runs. 107 RunId: os.Getenv("ATLAS_RUN_ID"), 108 } 109 110 return nil 111 } 112 113 func (b *Backend) Input(ui terraform.UIInput, c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) { 114 return b.schema.Input(ui, c) 115 } 116 117 func (b *Backend) Validate(c *terraform.ResourceConfig) ([]string, []error) { 118 return b.schema.Validate(c) 119 } 120 121 func (b *Backend) Configure(c *terraform.ResourceConfig) error { 122 return b.schema.Configure(c) 123 } 124 125 func (b *Backend) State(name string) (state.State, error) { 126 if name != backend.DefaultStateName { 127 return nil, backend.ErrNamedStatesNotSupported 128 } 129 return &remote.State{Client: b.stateClient}, nil 130 } 131 132 func (b *Backend) DeleteState(name string) error { 133 return backend.ErrNamedStatesNotSupported 134 } 135 136 func (b *Backend) States() ([]string, error) { 137 return nil, backend.ErrNamedStatesNotSupported 138 } 139 140 // Colorize returns the Colorize structure that can be used for colorizing 141 // output. This is gauranteed to always return a non-nil value and so is useful 142 // as a helper to wrap any potentially colored strings. 143 func (b *Backend) Colorize() *colorstring.Colorize { 144 if b.CLIColor != nil { 145 return b.CLIColor 146 } 147 148 return &colorstring.Colorize{ 149 Colors: colorstring.DefaultColors, 150 Disable: true, 151 } 152 } 153 154 var schemaDescriptions = map[string]string{ 155 "name": "Full name of the environment in Atlas, such as 'hashicorp/myenv'", 156 "access_token": "Access token to use to access Atlas. If ATLAS_TOKEN is set then\n" + 157 "this will override any saved value for this.", 158 "address": "Address to your Atlas installation. This defaults to the publicly\n" + 159 "hosted version at 'https://atlas.hashicorp.com/'. This address\n" + 160 "should contain the full HTTP scheme to use.", 161 }