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 }