github.com/Kevinklinger/open_terraform@v0.11.12-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  }