github.com/camlistore/go4@v0.0.0-20200104003542-c7e774b10ea0/cloud/google/gceutil/gceutil.go (about) 1 /* 2 Copyright 2015 The Perkeep Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package gceutil provides utility functions to help with instances on 18 // Google Compute Engine. 19 package gceutil // import "go4.org/cloud/google/gceutil" 20 21 import ( 22 "encoding/json" 23 "errors" 24 "net/http" 25 "strings" 26 "time" 27 28 "google.golang.org/api/compute/v1" 29 ) 30 31 // CoreOSImageURL returns the URL of the latest stable CoreOS image for running 32 // on Google Compute Engine. 33 func CoreOSImageURL(cl *http.Client) (string, error) { 34 return osImageURL(cl, false) 35 } 36 37 // COSImageURL returns the URL of the latest stable Container-Optimized OS image 38 // for running on Google Compute Engine. 39 func COSImageURL(cl *http.Client) (string, error) { 40 return osImageURL(cl, true) 41 } 42 43 func osImageURL(cl *http.Client, cos bool) (string, error) { 44 project := "coreos-cloud" 45 if cos { 46 project = "cos-cloud" 47 } 48 resp, err := cl.Get("https://www.googleapis.com/compute/v1/projects/" + project + "/global/images") 49 if err != nil { 50 return "", err 51 } 52 defer resp.Body.Close() 53 54 type osImage struct { 55 SelfLink string 56 CreationTimestamp time.Time 57 Name string 58 } 59 60 type osImageList struct { 61 Items []osImage 62 } 63 64 imageList := &osImageList{} 65 if err := json.NewDecoder(resp.Body).Decode(imageList); err != nil { 66 return "", err 67 } 68 if imageList == nil || len(imageList.Items) == 0 { 69 return "", errors.New("no images list in response") 70 } 71 72 imageURL := "" 73 var max time.Time // latest stable image creation time 74 imgPrefix := "coreos-stable" 75 if cos { 76 imgPrefix = "cos-stable" 77 } 78 for _, v := range imageList.Items { 79 if !strings.HasPrefix(v.Name, imgPrefix) { 80 continue 81 } 82 if v.CreationTimestamp.After(max) { 83 max = v.CreationTimestamp 84 imageURL = v.SelfLink 85 } 86 } 87 if imageURL == "" { 88 if cos { 89 return "", errors.New("no stable Container-Optimized OS image found") 90 } 91 return "", errors.New("no stable coreOS image found") 92 } 93 return imageURL, nil 94 } 95 96 // InstanceGroupAndManager contains both an InstanceGroup and 97 // its InstanceGroupManager, if any. 98 type InstanceGroupAndManager struct { 99 Group *compute.InstanceGroup 100 101 // Manager is the manager of the Group. It may be nil. 102 Manager *compute.InstanceGroupManager 103 } 104 105 // InstanceGroups returns all the instance groups in a project's zone, along 106 // with their associated InstanceGroupManagers. 107 // The returned map is keyed by the instance group identifier URL. 108 func InstanceGroups(svc *compute.Service, proj, zone string) (map[string]InstanceGroupAndManager, error) { 109 managerList, err := svc.InstanceGroupManagers.List(proj, zone).Do() 110 if err != nil { 111 return nil, err 112 } 113 if managerList.NextPageToken != "" { 114 return nil, errors.New("too many managers; pagination not supported") 115 } 116 managedBy := make(map[string]*compute.InstanceGroupManager) // instance group URL -> its manager 117 for _, it := range managerList.Items { 118 managedBy[it.InstanceGroup] = it 119 } 120 groupList, err := svc.InstanceGroups.List(proj, zone).Do() 121 if err != nil { 122 return nil, err 123 } 124 if groupList.NextPageToken != "" { 125 return nil, errors.New("too many instance groups; pagination not supported") 126 } 127 ret := make(map[string]InstanceGroupAndManager) 128 for _, it := range groupList.Items { 129 ret[it.SelfLink] = InstanceGroupAndManager{it, managedBy[it.SelfLink]} 130 } 131 return ret, nil 132 }