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  }