github.com/pdecat/terraform@v0.11.9-beta1/backend/remote-state/swift/backend.go (about) 1 package swift 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/gophercloud/gophercloud" 12 "github.com/gophercloud/gophercloud/openstack" 13 14 "github.com/hashicorp/terraform/backend" 15 "github.com/hashicorp/terraform/helper/schema" 16 tf_openstack "github.com/terraform-providers/terraform-provider-openstack/openstack" 17 ) 18 19 // New creates a new backend for Swift remote state. 20 func New() backend.Backend { 21 s := &schema.Backend{ 22 Schema: map[string]*schema.Schema{ 23 "auth_url": &schema.Schema{ 24 Type: schema.TypeString, 25 Required: true, 26 DefaultFunc: schema.EnvDefaultFunc("OS_AUTH_URL", nil), 27 Description: descriptions["auth_url"], 28 }, 29 30 "user_id": &schema.Schema{ 31 Type: schema.TypeString, 32 Optional: true, 33 DefaultFunc: schema.EnvDefaultFunc("OS_USER_ID", ""), 34 Description: descriptions["user_name"], 35 }, 36 37 "user_name": &schema.Schema{ 38 Type: schema.TypeString, 39 Optional: true, 40 DefaultFunc: schema.EnvDefaultFunc("OS_USERNAME", ""), 41 Description: descriptions["user_name"], 42 }, 43 44 "tenant_id": &schema.Schema{ 45 Type: schema.TypeString, 46 Optional: true, 47 DefaultFunc: schema.MultiEnvDefaultFunc([]string{ 48 "OS_TENANT_ID", 49 "OS_PROJECT_ID", 50 }, ""), 51 Description: descriptions["tenant_id"], 52 }, 53 54 "tenant_name": &schema.Schema{ 55 Type: schema.TypeString, 56 Optional: true, 57 DefaultFunc: schema.MultiEnvDefaultFunc([]string{ 58 "OS_TENANT_NAME", 59 "OS_PROJECT_NAME", 60 }, ""), 61 Description: descriptions["tenant_name"], 62 }, 63 64 "password": &schema.Schema{ 65 Type: schema.TypeString, 66 Optional: true, 67 Sensitive: true, 68 DefaultFunc: schema.EnvDefaultFunc("OS_PASSWORD", ""), 69 Description: descriptions["password"], 70 }, 71 72 "token": &schema.Schema{ 73 Type: schema.TypeString, 74 Optional: true, 75 DefaultFunc: schema.EnvDefaultFunc("OS_AUTH_TOKEN", ""), 76 Description: descriptions["token"], 77 }, 78 79 "domain_id": &schema.Schema{ 80 Type: schema.TypeString, 81 Optional: true, 82 DefaultFunc: schema.MultiEnvDefaultFunc([]string{ 83 "OS_USER_DOMAIN_ID", 84 "OS_PROJECT_DOMAIN_ID", 85 "OS_DOMAIN_ID", 86 }, ""), 87 Description: descriptions["domain_id"], 88 }, 89 90 "domain_name": &schema.Schema{ 91 Type: schema.TypeString, 92 Optional: true, 93 DefaultFunc: schema.MultiEnvDefaultFunc([]string{ 94 "OS_USER_DOMAIN_NAME", 95 "OS_PROJECT_DOMAIN_NAME", 96 "OS_DOMAIN_NAME", 97 "OS_DEFAULT_DOMAIN", 98 }, ""), 99 Description: descriptions["domain_name"], 100 }, 101 102 "region_name": &schema.Schema{ 103 Type: schema.TypeString, 104 Required: true, 105 DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), 106 Description: descriptions["region_name"], 107 }, 108 109 "insecure": &schema.Schema{ 110 Type: schema.TypeBool, 111 Optional: true, 112 DefaultFunc: schema.EnvDefaultFunc("OS_INSECURE", ""), 113 Description: descriptions["insecure"], 114 }, 115 116 "endpoint_type": &schema.Schema{ 117 Type: schema.TypeString, 118 Optional: true, 119 DefaultFunc: schema.EnvDefaultFunc("OS_ENDPOINT_TYPE", ""), 120 }, 121 122 "cacert_file": &schema.Schema{ 123 Type: schema.TypeString, 124 Optional: true, 125 DefaultFunc: schema.EnvDefaultFunc("OS_CACERT", ""), 126 Description: descriptions["cacert_file"], 127 }, 128 129 "cert": &schema.Schema{ 130 Type: schema.TypeString, 131 Optional: true, 132 DefaultFunc: schema.EnvDefaultFunc("OS_CERT", ""), 133 Description: descriptions["cert"], 134 }, 135 136 "key": &schema.Schema{ 137 Type: schema.TypeString, 138 Optional: true, 139 DefaultFunc: schema.EnvDefaultFunc("OS_KEY", ""), 140 Description: descriptions["key"], 141 }, 142 143 "path": &schema.Schema{ 144 Type: schema.TypeString, 145 Optional: true, 146 Description: descriptions["path"], 147 Deprecated: "Use container instead", 148 ConflictsWith: []string{"container"}, 149 }, 150 151 "container": &schema.Schema{ 152 Type: schema.TypeString, 153 Optional: true, 154 Description: descriptions["container"], 155 }, 156 157 "archive_path": &schema.Schema{ 158 Type: schema.TypeString, 159 Optional: true, 160 Description: descriptions["archive_path"], 161 Deprecated: "Use archive_container instead", 162 ConflictsWith: []string{"archive_container"}, 163 }, 164 165 "archive_container": &schema.Schema{ 166 Type: schema.TypeString, 167 Optional: true, 168 Description: descriptions["archive_container"], 169 }, 170 171 "expire_after": &schema.Schema{ 172 Type: schema.TypeString, 173 Optional: true, 174 Description: descriptions["expire_after"], 175 }, 176 }, 177 } 178 179 result := &Backend{Backend: s} 180 result.Backend.ConfigureFunc = result.configure 181 return result 182 } 183 184 var descriptions map[string]string 185 186 func init() { 187 descriptions = map[string]string{ 188 "auth_url": "The Identity authentication URL.", 189 190 "user_name": "Username to login with.", 191 192 "user_id": "User ID to login with.", 193 194 "tenant_id": "The ID of the Tenant (Identity v2) or Project (Identity v3)\n" + 195 "to login with.", 196 197 "tenant_name": "The name of the Tenant (Identity v2) or Project (Identity v3)\n" + 198 "to login with.", 199 200 "password": "Password to login with.", 201 202 "token": "Authentication token to use as an alternative to username/password.", 203 204 "domain_id": "The ID of the Domain to scope to (Identity v3).", 205 206 "domain_name": "The name of the Domain to scope to (Identity v3).", 207 208 "region_name": "The name of the Region to use.", 209 210 "insecure": "Trust self-signed certificates.", 211 212 "cacert_file": "A Custom CA certificate.", 213 214 "endpoint_type": "The catalog endpoint type to use.", 215 216 "cert": "A client certificate to authenticate with.", 217 218 "key": "A client private key to authenticate with.", 219 220 "path": "Swift container path to use.", 221 222 "container": "Swift container to create", 223 224 "archive_path": "Swift container path to archive state to.", 225 226 "archive_container": "Swift container to archive state to.", 227 228 "expire_after": "Archive object expiry duration.", 229 } 230 } 231 232 type Backend struct { 233 *schema.Backend 234 235 // Fields below are set from configure 236 client *gophercloud.ServiceClient 237 archive bool 238 archiveContainer string 239 expireSecs int 240 container string 241 } 242 243 func (b *Backend) configure(ctx context.Context) error { 244 if b.client != nil { 245 return nil 246 } 247 248 // Grab the resource data 249 data := schema.FromContextBackendConfig(ctx) 250 251 config := &tf_openstack.Config{ 252 CACertFile: data.Get("cacert_file").(string), 253 ClientCertFile: data.Get("cert").(string), 254 ClientKeyFile: data.Get("key").(string), 255 DomainID: data.Get("domain_id").(string), 256 DomainName: data.Get("domain_name").(string), 257 EndpointType: data.Get("endpoint_type").(string), 258 IdentityEndpoint: data.Get("auth_url").(string), 259 Insecure: data.Get("insecure").(bool), 260 Password: data.Get("password").(string), 261 Token: data.Get("token").(string), 262 TenantID: data.Get("tenant_id").(string), 263 TenantName: data.Get("tenant_name").(string), 264 Username: data.Get("user_name").(string), 265 UserID: data.Get("user_id").(string), 266 } 267 268 if err := config.LoadAndValidate(); err != nil { 269 return err 270 } 271 272 // Assign Container 273 b.container = data.Get("container").(string) 274 if b.container == "" { 275 // Check deprecated field 276 b.container = data.Get("path").(string) 277 } 278 279 // Enable object archiving? 280 if archiveContainer, ok := data.GetOk("archive_container"); ok { 281 log.Printf("[DEBUG] Archive_container set, enabling object versioning") 282 b.archive = true 283 b.archiveContainer = archiveContainer.(string) 284 } else if archivePath, ok := data.GetOk("archive_path"); ok { 285 log.Printf("[DEBUG] Archive_path set, enabling object versioning") 286 b.archive = true 287 b.archiveContainer = archivePath.(string) 288 } 289 290 // Enable object expiry? 291 if expireRaw, ok := data.GetOk("expire_after"); ok { 292 expire := expireRaw.(string) 293 log.Printf("[DEBUG] Requested that remote state expires after %s", expire) 294 295 if strings.HasSuffix(expire, "d") { 296 log.Printf("[DEBUG] Got a days expire after duration. Converting to hours") 297 days, err := strconv.Atoi(expire[:len(expire)-1]) 298 if err != nil { 299 return fmt.Errorf("Error converting expire_after value %s to int: %s", expire, err) 300 } 301 302 expire = fmt.Sprintf("%dh", days*24) 303 log.Printf("[DEBUG] Expire after %s hours", expire) 304 } 305 306 expireDur, err := time.ParseDuration(expire) 307 if err != nil { 308 log.Printf("[DEBUG] Error parsing duration %s: %s", expire, err) 309 return fmt.Errorf("Error parsing expire_after duration '%s': %s", expire, err) 310 } 311 log.Printf("[DEBUG] Seconds duration = %d", int(expireDur.Seconds())) 312 b.expireSecs = int(expireDur.Seconds()) 313 } 314 315 objClient, err := openstack.NewObjectStorageV1(config.OsClient, gophercloud.EndpointOpts{ 316 Region: data.Get("region_name").(string), 317 }) 318 if err != nil { 319 return err 320 } 321 322 b.client = objClient 323 324 return nil 325 }