github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/state/remote/manta.go (about)

     1  package remote
     2  
     3  import (
     4  	"crypto/md5"
     5  	"encoding/pem"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"log"
     9  	"os"
    10  
    11  	joyentclient "github.com/joyent/gocommon/client"
    12  	joyenterrors "github.com/joyent/gocommon/errors"
    13  	"github.com/joyent/gomanta/manta"
    14  	joyentauth "github.com/joyent/gosign/auth"
    15  )
    16  
    17  const DEFAULT_OBJECT_NAME = "terraform.tfstate"
    18  
    19  func mantaFactory(conf map[string]string) (Client, error) {
    20  	path, ok := conf["path"]
    21  	if !ok {
    22  		return nil, fmt.Errorf("missing 'path' configuration")
    23  	}
    24  
    25  	objectName, ok := conf["objectName"]
    26  	if !ok {
    27  		objectName = DEFAULT_OBJECT_NAME
    28  	}
    29  
    30  	creds, err := getCredentialsFromEnvironment()
    31  
    32  	if err != nil {
    33  		return nil, fmt.Errorf("Error getting Manta credentials: %s", err.Error())
    34  	}
    35  
    36  	client := manta.New(joyentclient.NewClient(
    37  		creds.MantaEndpoint.URL,
    38  		"",
    39  		creds,
    40  		log.New(os.Stderr, "", log.LstdFlags),
    41  	))
    42  
    43  	return &MantaClient{
    44  		Client:     client,
    45  		Path:       path,
    46  		ObjectName: objectName,
    47  	}, nil
    48  }
    49  
    50  type MantaClient struct {
    51  	Client     *manta.Client
    52  	Path       string
    53  	ObjectName string
    54  }
    55  
    56  func (c *MantaClient) Get() (*Payload, error) {
    57  	bytes, err := c.Client.GetObject(c.Path, c.ObjectName)
    58  	if err != nil {
    59  		if joyenterrors.IsResourceNotFound(err.(joyenterrors.Error).Cause()) {
    60  			return nil, nil
    61  		}
    62  
    63  		return nil, err
    64  	}
    65  
    66  	md5 := md5.Sum(bytes)
    67  
    68  	return &Payload{
    69  		Data: bytes,
    70  		MD5:  md5[:],
    71  	}, nil
    72  }
    73  
    74  func (c *MantaClient) Put(data []byte) error {
    75  	return c.Client.PutObject(c.Path, c.ObjectName, data)
    76  }
    77  
    78  func (c *MantaClient) Delete() error {
    79  	return c.Client.DeleteObject(c.Path, c.ObjectName)
    80  }
    81  
    82  func getCredentialsFromEnvironment() (cred *joyentauth.Credentials, err error) {
    83  
    84  	user := os.Getenv("MANTA_USER")
    85  	keyId := os.Getenv("MANTA_KEY_ID")
    86  	url := os.Getenv("MANTA_URL")
    87  	keyMaterial := os.Getenv("MANTA_KEY_MATERIAL")
    88  
    89  	if _, err := os.Stat(keyMaterial); err == nil {
    90  		// key material is a file path; try to read it
    91  		keyBytes, err := ioutil.ReadFile(keyMaterial)
    92  		if err != nil {
    93  			return nil, fmt.Errorf("Error reading key material from %s: %s",
    94  				keyMaterial, err)
    95  		} else {
    96  			block, _ := pem.Decode(keyBytes)
    97  			if block == nil {
    98  				return nil, fmt.Errorf(
    99  					"Failed to read key material '%s': no key found", keyMaterial)
   100  			}
   101  
   102  			if block.Headers["Proc-Type"] == "4,ENCRYPTED" {
   103  				return nil, fmt.Errorf(
   104  					"Failed to read key '%s': password protected keys are\n"+
   105  						"not currently supported. Please decrypt the key prior to use.", keyMaterial)
   106  			}
   107  
   108  			keyMaterial = string(keyBytes)
   109  		}
   110  	}
   111  
   112  	authentication, err := joyentauth.NewAuth(user, keyMaterial, "rsa-sha256")
   113  	if err != nil {
   114  		return nil, fmt.Errorf("Error constructing authentication for %s: %s", user, err)
   115  	}
   116  
   117  	return &joyentauth.Credentials{
   118  		UserAuthentication: authentication,
   119  		SdcKeyId:           "",
   120  		SdcEndpoint:        joyentauth.Endpoint{},
   121  		MantaKeyId:         keyId,
   122  		MantaEndpoint:      joyentauth.Endpoint{URL: url},
   123  	}, nil
   124  }