github.com/hugorut/terraform@v1.1.3/src/backend/remote-state/manta/backend.go (about)

     1  package manta
     2  
     3  import (
     4  	"context"
     5  	"encoding/pem"
     6  	"errors"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  
    11  	"github.com/hashicorp/errwrap"
    12  	"github.com/hashicorp/go-multierror"
    13  	"github.com/hugorut/terraform/src/backend"
    14  	"github.com/hugorut/terraform/src/legacy/helper/schema"
    15  	triton "github.com/joyent/triton-go"
    16  	"github.com/joyent/triton-go/authentication"
    17  	"github.com/joyent/triton-go/storage"
    18  )
    19  
    20  func New() backend.Backend {
    21  	s := &schema.Backend{
    22  		Schema: map[string]*schema.Schema{
    23  			"account": {
    24  				Type:        schema.TypeString,
    25  				Required:    true,
    26  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_ACCOUNT", "SDC_ACCOUNT"}, ""),
    27  			},
    28  
    29  			"user": {
    30  				Type:        schema.TypeString,
    31  				Optional:    true,
    32  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_USER", "SDC_USER"}, ""),
    33  			},
    34  
    35  			"url": {
    36  				Type:        schema.TypeString,
    37  				Optional:    true,
    38  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"MANTA_URL"}, "https://us-east.manta.joyent.com"),
    39  			},
    40  
    41  			"key_material": {
    42  				Type:        schema.TypeString,
    43  				Optional:    true,
    44  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_KEY_MATERIAL", "SDC_KEY_MATERIAL"}, ""),
    45  			},
    46  
    47  			"key_id": {
    48  				Type:        schema.TypeString,
    49  				Required:    true,
    50  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_KEY_ID", "SDC_KEY_ID"}, ""),
    51  			},
    52  
    53  			"insecure_skip_tls_verify": {
    54  				Type:        schema.TypeBool,
    55  				Optional:    true,
    56  				DefaultFunc: schema.EnvDefaultFunc("TRITON_SKIP_TLS_VERIFY", false),
    57  			},
    58  
    59  			"path": {
    60  				Type:     schema.TypeString,
    61  				Required: true,
    62  			},
    63  
    64  			"object_name": {
    65  				Type:     schema.TypeString,
    66  				Optional: true,
    67  				Default:  "terraform.tfstate",
    68  			},
    69  		},
    70  	}
    71  
    72  	result := &Backend{Backend: s}
    73  	result.Backend.ConfigureFunc = result.configure
    74  	return result
    75  }
    76  
    77  type Backend struct {
    78  	*schema.Backend
    79  	data *schema.ResourceData
    80  
    81  	// The fields below are set from configure
    82  	storageClient *storage.StorageClient
    83  	path          string
    84  	objectName    string
    85  }
    86  
    87  type BackendConfig struct {
    88  	AccountId   string
    89  	Username    string
    90  	KeyId       string
    91  	AccountUrl  string
    92  	KeyMaterial string
    93  	SkipTls     bool
    94  }
    95  
    96  func (b *Backend) configure(ctx context.Context) error {
    97  	if b.path != "" {
    98  		return nil
    99  	}
   100  
   101  	data := schema.FromContextBackendConfig(ctx)
   102  
   103  	config := &BackendConfig{
   104  		AccountId:  data.Get("account").(string),
   105  		AccountUrl: data.Get("url").(string),
   106  		KeyId:      data.Get("key_id").(string),
   107  		SkipTls:    data.Get("insecure_skip_tls_verify").(bool),
   108  	}
   109  
   110  	if v, ok := data.GetOk("user"); ok {
   111  		config.Username = v.(string)
   112  	}
   113  
   114  	if v, ok := data.GetOk("key_material"); ok {
   115  		config.KeyMaterial = v.(string)
   116  	}
   117  
   118  	b.path = data.Get("path").(string)
   119  	b.objectName = data.Get("object_name").(string)
   120  
   121  	// If object_name is not set, try the deprecated objectName.
   122  	if b.objectName == "" {
   123  		b.objectName = data.Get("objectName").(string)
   124  	}
   125  
   126  	var validationError *multierror.Error
   127  
   128  	if data.Get("account").(string) == "" {
   129  		validationError = multierror.Append(validationError, errors.New("`Account` must be configured for the Triton provider"))
   130  	}
   131  	if data.Get("key_id").(string) == "" {
   132  		validationError = multierror.Append(validationError, errors.New("`Key ID` must be configured for the Triton provider"))
   133  	}
   134  	if b.path == "" {
   135  		validationError = multierror.Append(validationError, errors.New("`Path` must be configured for the Triton provider"))
   136  	}
   137  
   138  	if validationError != nil {
   139  		return validationError
   140  	}
   141  
   142  	var signer authentication.Signer
   143  	var err error
   144  
   145  	if config.KeyMaterial == "" {
   146  		input := authentication.SSHAgentSignerInput{
   147  			KeyID:       config.KeyId,
   148  			AccountName: config.AccountId,
   149  			Username:    config.Username,
   150  		}
   151  		signer, err = authentication.NewSSHAgentSigner(input)
   152  		if err != nil {
   153  			return errwrap.Wrapf("Error Creating SSH Agent Signer: {{err}}", err)
   154  		}
   155  	} else {
   156  		var keyBytes []byte
   157  		if _, err = os.Stat(config.KeyMaterial); err == nil {
   158  			keyBytes, err = ioutil.ReadFile(config.KeyMaterial)
   159  			if err != nil {
   160  				return fmt.Errorf("Error reading key material from %s: %s",
   161  					config.KeyMaterial, err)
   162  			}
   163  			block, _ := pem.Decode(keyBytes)
   164  			if block == nil {
   165  				return fmt.Errorf(
   166  					"Failed to read key material '%s': no key found", config.KeyMaterial)
   167  			}
   168  
   169  			if block.Headers["Proc-Type"] == "4,ENCRYPTED" {
   170  				return fmt.Errorf(
   171  					"Failed to read key '%s': password protected keys are\n"+
   172  						"not currently supported. Please decrypt the key prior to use.", config.KeyMaterial)
   173  			}
   174  
   175  		} else {
   176  			keyBytes = []byte(config.KeyMaterial)
   177  		}
   178  
   179  		input := authentication.PrivateKeySignerInput{
   180  			KeyID:              config.KeyId,
   181  			PrivateKeyMaterial: keyBytes,
   182  			AccountName:        config.AccountId,
   183  			Username:           config.Username,
   184  		}
   185  
   186  		signer, err = authentication.NewPrivateKeySigner(input)
   187  		if err != nil {
   188  			return errwrap.Wrapf("Error Creating SSH Private Key Signer: {{err}}", err)
   189  		}
   190  	}
   191  
   192  	clientConfig := &triton.ClientConfig{
   193  		MantaURL:    config.AccountUrl,
   194  		AccountName: config.AccountId,
   195  		Username:    config.Username,
   196  		Signers:     []authentication.Signer{signer},
   197  	}
   198  	triton, err := storage.NewClient(clientConfig)
   199  	if err != nil {
   200  		return err
   201  	}
   202  
   203  	b.storageClient = triton
   204  
   205  	return nil
   206  }