remote: first pass at push state
This commit is contained in:
parent
f748b6ae71
commit
958bea4fca
|
@ -14,6 +14,12 @@ import (
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrConflict is used to indicate the upload was rejected
|
||||||
|
// due to a conflict on the state
|
||||||
|
ErrConflict = fmt.Errorf("Conflicting state file")
|
||||||
|
)
|
||||||
|
|
||||||
// RemoteStatePayload is used to return the remote state
|
// RemoteStatePayload is used to return the remote state
|
||||||
// along with associated meta data when we do a remote fetch.
|
// along with associated meta data when we do a remote fetch.
|
||||||
type RemoteStatePayload struct {
|
type RemoteStatePayload struct {
|
||||||
|
@ -125,3 +131,57 @@ func (r *remoteStateClient) GetState() (*RemoteStatePayload, error) {
|
||||||
|
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put is used to update the remote state
|
||||||
|
func (r *remoteStateClient) PutState(state []byte, force bool) error {
|
||||||
|
// Get the target URL
|
||||||
|
base, err := r.URL()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the MD5
|
||||||
|
hash := md5.Sum(state)
|
||||||
|
b64 := base64.StdEncoding.EncodeToString(hash[:md5.Size])
|
||||||
|
|
||||||
|
// Set the force query parameter if needed
|
||||||
|
if force {
|
||||||
|
values := base.Query()
|
||||||
|
values.Set("force", "true")
|
||||||
|
base.RawQuery = values.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the HTTP client and request
|
||||||
|
client := http.Client{}
|
||||||
|
req, err := http.NewRequest("PUT", base.String(), bytes.NewReader(state))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to make HTTP request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the request
|
||||||
|
req.Header.Set("Content-MD5", b64)
|
||||||
|
req.ContentLength = int64(len(state))
|
||||||
|
|
||||||
|
// Make the request
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to upload state: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Handle the error codes
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case http.StatusOK:
|
||||||
|
return nil
|
||||||
|
case http.StatusConflict:
|
||||||
|
return ErrConflict
|
||||||
|
case http.StatusUnauthorized:
|
||||||
|
return fmt.Errorf("Remote server requires authentication")
|
||||||
|
case http.StatusForbidden:
|
||||||
|
return fmt.Errorf("Invalid authentication")
|
||||||
|
case http.StatusInternalServerError:
|
||||||
|
return fmt.Errorf("Remote server reporting internal error")
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Unexpected HTTP response code %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue