mirror of https://github.com/hashicorp/packer
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
5.1 KiB
184 lines
5.1 KiB
package googlecompute
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"code.google.com/p/goauth2/oauth"
|
|
"code.google.com/p/goauth2/oauth/jwt"
|
|
"code.google.com/p/google-api-go-client/compute/v1beta16"
|
|
)
|
|
|
|
// GoogleComputeClient represents a GCE client.
|
|
type GoogleComputeClient struct {
|
|
ProjectId string
|
|
Service *compute.Service
|
|
Zone string
|
|
clientSecrets *clientSecrets
|
|
}
|
|
|
|
// InstanceConfig represents a GCE instance configuration.
|
|
// Used for creating machine instances.
|
|
/*
|
|
type InstanceConfig struct {
|
|
Description string
|
|
Image string
|
|
MachineType string
|
|
Metadata *compute.Metadata
|
|
Name string
|
|
NetworkInterfaces []*compute.NetworkInterface
|
|
ServiceAccounts []*compute.ServiceAccount
|
|
Tags *compute.Tags
|
|
}
|
|
*/
|
|
|
|
// New initializes and returns a *GoogleComputeClient.
|
|
//
|
|
// The projectId must be the project name, i.e. myproject, not the project
|
|
// number.
|
|
func New(projectId string, zone string, c *clientSecrets, pemKey []byte) (*GoogleComputeClient, error) {
|
|
googleComputeClient := &GoogleComputeClient{
|
|
ProjectId: projectId,
|
|
Zone: zone,
|
|
}
|
|
// Get the access token.
|
|
t := jwt.NewToken(c.Web.ClientEmail, "", pemKey)
|
|
t.ClaimSet.Aud = c.Web.TokenURI
|
|
httpClient := &http.Client{}
|
|
token, err := t.Assert(httpClient)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config := &oauth.Config{
|
|
ClientId: c.Web.ClientId,
|
|
Scope: "",
|
|
TokenURL: c.Web.TokenURI,
|
|
AuthURL: c.Web.AuthURI,
|
|
}
|
|
transport := &oauth.Transport{Config: config}
|
|
transport.Token = token
|
|
s, err := compute.New(transport.Client())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
googleComputeClient.Service = s
|
|
return googleComputeClient, nil
|
|
}
|
|
|
|
// InstanceStatus returns a string representing the status of the named instance.
|
|
// Status will be one of: "PROVISIONING", "STAGING", "RUNNING", "STOPPING",
|
|
// "STOPPED", "TERMINATED".
|
|
func (g *GoogleComputeClient) InstanceStatus(zone, name string) (string, error) {
|
|
instanceGetCall := g.Service.Instances.Get(g.ProjectId, zone, name)
|
|
instance, err := instanceGetCall.Do()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return instance.Status, nil
|
|
}
|
|
|
|
// CreateImage registers a GCE Image with a project.
|
|
func (g *GoogleComputeClient) CreateImage(name, description, sourceURL string) (*compute.Operation, error) {
|
|
imageRawDisk := &compute.ImageRawDisk{
|
|
ContainerType: "TAR",
|
|
Source: sourceURL,
|
|
}
|
|
image := &compute.Image{
|
|
Description: description,
|
|
Name: name,
|
|
RawDisk: imageRawDisk,
|
|
SourceType: "RAW",
|
|
}
|
|
imageInsertCall := g.Service.Images.Insert(g.ProjectId, image)
|
|
operation, err := imageInsertCall.Do()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return operation, nil
|
|
}
|
|
|
|
// GetNatIp returns the public IPv4 address for named GCE instance.
|
|
func (g *GoogleComputeClient) GetNatIP(zone, name string) (string, error) {
|
|
instanceGetCall := g.Service.Instances.Get(g.ProjectId, zone, name)
|
|
instance, err := instanceGetCall.Do()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
for _, ni := range instance.NetworkInterfaces {
|
|
if ni.AccessConfigs == nil {
|
|
continue
|
|
}
|
|
for _, ac := range ni.AccessConfigs {
|
|
if ac.NatIP != "" {
|
|
return ac.NatIP, nil
|
|
}
|
|
}
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
// ZoneOperationStatus returns the status for the named zone operation.
|
|
func (g *GoogleComputeClient) ZoneOperationStatus(zone, name string) (string, error) {
|
|
zoneOperationsGetCall := g.Service.ZoneOperations.Get(g.ProjectId, zone, name)
|
|
operation, err := zoneOperationsGetCall.Do()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if operation.Status == "DONE" {
|
|
err = processOperationStatus(operation)
|
|
if err != nil {
|
|
return operation.Status, err
|
|
}
|
|
}
|
|
return operation.Status, nil
|
|
}
|
|
|
|
// GlobalOperationStatus returns the status for the named global operation.
|
|
func (g *GoogleComputeClient) GlobalOperationStatus(name string) (string, error) {
|
|
globalOperationsGetCall := g.Service.GlobalOperations.Get(g.ProjectId, name)
|
|
operation, err := globalOperationsGetCall.Do()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if operation.Status == "DONE" {
|
|
err = processOperationStatus(operation)
|
|
if err != nil {
|
|
return operation.Status, err
|
|
}
|
|
}
|
|
return operation.Status, nil
|
|
}
|
|
|
|
// processOperationStatus extracts errors from the specified operation.
|
|
func processOperationStatus(o *compute.Operation) error {
|
|
if o.Error != nil {
|
|
messages := make([]string, len(o.Error.Errors))
|
|
for _, e := range o.Error.Errors {
|
|
messages = append(messages, e.Message)
|
|
}
|
|
return errors.New(strings.Join(messages, "\n"))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteImage deletes the named image. Returns a Global Operation.
|
|
func (g *GoogleComputeClient) DeleteImage(name string) (*compute.Operation, error) {
|
|
imagesDeleteCall := g.Service.Images.Delete(g.ProjectId, name)
|
|
operation, err := imagesDeleteCall.Do()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return operation, nil
|
|
}
|
|
|
|
// DeleteInstance deletes the named instance. Returns a Zone Operation.
|
|
func (g *GoogleComputeClient) DeleteInstance(zone, name string) (*compute.Operation, error) {
|
|
instanceDeleteCall := g.Service.Instances.Delete(g.ProjectId, zone, name)
|
|
operation, err := instanceDeleteCall.Do()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return operation, nil
|
|
}
|