github.com/coreos/mantle@v0.13.0/platform/api/gcloud/image.go (about)

     1  // Copyright 2016 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package gcloud
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"golang.org/x/net/context"
    22  	"google.golang.org/api/compute/v1"
    23  )
    24  
    25  type DeprecationState string
    26  
    27  const (
    28  	DeprecationStateActive     DeprecationState = "ACTIVE"
    29  	DeprecationStateDeprecated DeprecationState = "DEPRECATED"
    30  	DeprecationStateObsolete   DeprecationState = "OBSOLETE"
    31  	DeprecationStateDeleted    DeprecationState = "DELETED"
    32  )
    33  
    34  type ImageSpec struct {
    35  	SourceImage string
    36  	Family      string
    37  	Name        string
    38  	Description string
    39  	Licenses    []string // short names
    40  }
    41  
    42  // CreateImage creates an image on GCE and returns operation details and
    43  // a Pending. If overwrite is true, an existing image will be overwritten
    44  // if it exists.
    45  func (a *API) CreateImage(spec *ImageSpec, overwrite bool) (*compute.Operation, *Pending, error) {
    46  	licenses := make([]string, len(spec.Licenses))
    47  	for i, l := range spec.Licenses {
    48  		license, err := a.compute.Licenses.Get(a.options.Project, l).Do()
    49  		if err != nil {
    50  			return nil, nil, fmt.Errorf("Invalid GCE license %s: %v", l, err)
    51  		}
    52  		licenses[i] = license.SelfLink
    53  	}
    54  
    55  	if overwrite {
    56  		plog.Debugf("Overwriting image %q", spec.Name)
    57  		// delete existing image, ignore error since it might not exist.
    58  		op, err := a.compute.Images.Delete(a.options.Project, spec.Name).Do()
    59  
    60  		if op != nil {
    61  			doable := a.compute.GlobalOperations.Get(a.options.Project, op.Name)
    62  			if err := a.NewPending(op.Name, doable).Wait(); err != nil {
    63  				return nil, nil, err
    64  			}
    65  		}
    66  
    67  		// don't return error when delete fails because image doesn't exist
    68  		if err != nil && !strings.HasSuffix(err.Error(), "notFound") {
    69  			return nil, nil, fmt.Errorf("deleting image: %v", err)
    70  		}
    71  	}
    72  
    73  	image := &compute.Image{
    74  		Family:      spec.Family,
    75  		Name:        spec.Name,
    76  		Description: spec.Description,
    77  		Licenses:    licenses,
    78  		GuestOsFeatures: []*compute.GuestOsFeature{
    79  			&compute.GuestOsFeature{
    80  				Type: "VIRTIO_SCSI_MULTIQUEUE",
    81  			},
    82  		},
    83  		RawDisk: &compute.ImageRawDisk{
    84  			Source: spec.SourceImage,
    85  		},
    86  	}
    87  
    88  	plog.Debugf("Creating image %q from %q", spec.Name, spec.SourceImage)
    89  
    90  	op, err := a.compute.Images.Insert(a.options.Project, image).Do()
    91  	if err != nil {
    92  		return nil, nil, err
    93  	}
    94  
    95  	doable := a.compute.GlobalOperations.Get(a.options.Project, op.Name)
    96  	return op, a.NewPending(op.Name, doable), nil
    97  }
    98  
    99  func (a *API) ListImages(ctx context.Context, prefix string) ([]*compute.Image, error) {
   100  	var images []*compute.Image
   101  	listReq := a.compute.Images.List(a.options.Project)
   102  	if prefix != "" {
   103  		listReq.Filter(fmt.Sprintf("name eq ^%s.*", prefix))
   104  	}
   105  	err := listReq.Pages(ctx, func(i *compute.ImageList) error {
   106  		images = append(images, i.Items...)
   107  		return nil
   108  	})
   109  	if err != nil {
   110  		return nil, fmt.Errorf("Listing GCE images failed: %v", err)
   111  	}
   112  	return images, nil
   113  }
   114  
   115  func (a *API) GetPendingForImage(image *compute.Image) (*Pending, error) {
   116  	op := a.compute.GlobalOperations.List(a.options.Project)
   117  	op.Filter(fmt.Sprintf("(targetId eq %v) (operationType eq insert)", image.Id))
   118  	pendingOps, err := op.Do()
   119  	if err != nil {
   120  		return nil, fmt.Errorf("Couldn't list pending operations on %q: %v", image.Name, err)
   121  	}
   122  	if len(pendingOps.Items) != 1 {
   123  		return nil, fmt.Errorf("Found %d != 1 insert operations on %q", len(pendingOps.Items), image.Name)
   124  	}
   125  	pendingOp := pendingOps.Items[0]
   126  	doable := a.compute.GlobalOperations.Get(a.options.Project, pendingOp.Name)
   127  	return a.NewPending(pendingOp.Name, doable), nil
   128  }
   129  
   130  func (a *API) DeprecateImage(name string, state DeprecationState, replacement string) (*Pending, error) {
   131  	req := a.compute.Images.Deprecate(a.options.Project, name, &compute.DeprecationStatus{
   132  		State:       string(state),
   133  		Replacement: replacement,
   134  	})
   135  	op, err := req.Do()
   136  	if err != nil {
   137  		return nil, fmt.Errorf("Deprecating %s failed: %v", name, err)
   138  	}
   139  	opReq := a.compute.GlobalOperations.Get(a.options.Project, op.Name)
   140  	return a.NewPending(op.Name, opReq), nil
   141  }
   142  
   143  func (a *API) DeleteImage(name string) (*Pending, error) {
   144  	op, err := a.compute.Images.Delete(a.options.Project, name).Do()
   145  	if err != nil {
   146  		return nil, fmt.Errorf("Deleting %s failed: %v", name, err)
   147  	}
   148  	opReq := a.compute.GlobalOperations.Get(a.options.Project, op.Name)
   149  	return a.NewPending(op.Name, opReq), nil
   150  }