gcloud/computeengine.go (220 lines of code) (raw):
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gcloud
import (
"fmt"
"sort"
"strings"
"google.golang.org/api/compute/v1"
)
// DiskProjects are the list of projects for disk images for Compute Engine
var DiskProjects = LabeledValues{
LabeledValue{Label: "CentOS", Value: "centos-cloud"},
LabeledValue{Label: "Container-Optimized OS (COS)", Value: "cos-cloud"},
LabeledValue{Label: "Debian", Value: "debian-cloud", IsDefault: true},
LabeledValue{Label: "Fedora CoreOS", Value: "fedora-coreos-cloud"},
LabeledValue{Label: "Red Hat Enterprise Linux (RHEL)", Value: "rhel-cloud"},
LabeledValue{Label: "Red Hat Enterprise Linux (RHEL) for SAP", Value: "rhel-sap-cloud"},
LabeledValue{Label: "Rocky Linux", Value: "rocky-linux-cloud"},
LabeledValue{Label: "SQL Server", Value: "windows-sql-cloud"},
LabeledValue{Label: "SUSE Linux Enterprise Server (SLES)", Value: "suse-cloud"},
LabeledValue{Label: "SUSE Linux Enterprise Server (SLES) for SAP", Value: "suse-cloud"},
LabeledValue{Label: "SUSE Linux Enterprise Server (SLES) BYOS", Value: "suse-byos-cloud"},
LabeledValue{Label: "Ubuntu LTS", Value: "ubuntu-os-cloud"},
LabeledValue{Label: "Ubuntu Pro", Value: "ubuntu-os-pro-cloud"},
LabeledValue{Label: "Windows Server", Value: "windows-cloud"},
}
func (c *Client) getComputeService(project string) (*compute.Service, error) {
var err error
svc := c.services.computeService
if svc != nil {
return svc, nil
}
if err := c.ServiceEnable(project, Compute); err != nil {
return nil, fmt.Errorf("error activating service for polling: %s", err)
}
svc, err = compute.NewService(c.ctx, c.opts)
if err != nil {
return nil, err
}
svc.UserAgent = c.userAgent
c.services.computeService = svc
return svc, nil
}
// ComputeRegionList will return a list of regions for Compute Engine
func (c *Client) ComputeRegionList(project string) ([]string, error) {
resp := []string{}
svc, err := c.getComputeService(project)
if err != nil {
return resp, err
}
results, err := svc.Regions.List(project).Do()
if err != nil {
return resp, err
}
for _, v := range results.Items {
resp = append(resp, v.Name)
}
sort.Strings(resp)
return resp, nil
}
// ZoneList will return a list of ComputeZoneList in a given region
func (c *Client) ZoneList(project, region string) ([]string, error) {
resp := []string{}
svc, err := c.getComputeService(project)
if err != nil {
return resp, err
}
filter := fmt.Sprintf("name=%s*", region)
results, err := svc.Zones.List(project).Filter(filter).Do()
if err != nil {
return resp, err
}
for _, v := range results.Items {
resp = append(resp, v.Name)
}
sort.Strings(resp)
return resp, nil
}
// MachineTypeList retrieves the list of Machine Types available in a
// given zone
func (c *Client) MachineTypeList(project, zone string) (*compute.MachineTypeList, error) {
resp := &compute.MachineTypeList{}
i := c.get("MachineTypeList" + zone)
switch val := i.(type) {
case *compute.MachineTypeList:
return val, nil
}
svc, err := c.getComputeService(project)
if err != nil {
return resp, err
}
results, err := svc.MachineTypes.List(project, zone).Do()
if err != nil {
return resp, err
}
c.save("MachineTypeList"+zone, results)
return results, nil
}
func formatMBToGB(i int64) string {
return fmt.Sprintf("%d GB", i/1024)
}
// ImageList gets the list of disk images available for a given image
// project
func (c *Client) ImageList(project, imageproject string) (*compute.ImageList, error) {
resp := &compute.ImageList{}
svc, err := c.getComputeService(project)
if err != nil {
return resp, err
}
results, err := svc.Images.List(imageproject).Do()
if err != nil {
return resp, err
}
tmp := []*compute.Image{}
for _, v := range results.Items {
// fmt.Printf("%v", v.Name)
if v.Deprecated == nil || v.Deprecated.State == "" {
// fmt.Printf("- not deprecated")
tmp = append(tmp, v)
}
// fmt.Printf("\n")
}
results.Items = tmp
return results, nil
}
// ImageLatestGet retrieves the latest image from a particular family
func (c *Client) ImageLatestGet(project, imageproject, imagefamily string) (string, error) {
resp := ""
svc, err := c.getComputeService(project)
if err != nil {
return resp, fmt.Errorf("ImageLatestGet: could not get compute service: %s", err)
}
filter := fmt.Sprintf("(family=\"%s\")", imagefamily)
results, err := svc.Images.List(imageproject).Filter(filter).Do()
if err != nil {
return resp, fmt.Errorf("ImageLatestGet: could not get filter list images: %s", err)
}
sort.Slice(results.Items, func(i, j int) bool {
return results.Items[i].CreationTimestamp > results.Items[j].CreationTimestamp
})
for _, v := range results.Items {
if v.Deprecated == nil || v.Deprecated.State == "" {
return fmt.Sprintf("%s/%s", imageproject, v.Name), nil
}
}
return "", fmt.Errorf("error: could not find ")
}
// MachineTypeFamilyList gets the list of machine type families
func (c *Client) MachineTypeFamilyList(imgs *compute.MachineTypeList) LabeledValues {
fam := make(map[string]string)
lb := LabeledValues{}
for _, v := range imgs.Items {
parts := strings.Split(v.Name, "-")
key := fmt.Sprintf("%s %s", parts[0], parts[1])
fam[key] = fmt.Sprintf("%s-%s", parts[0], parts[1])
}
for key, value := range fam {
if key == "" {
continue
}
lb = append(lb, LabeledValue{
Value: value,
Label: key,
IsDefault: false,
})
}
lb.SetDefault(DefaultImageFamily)
lb.Sort()
return lb
}
// MachineTypeListByFamily retrieves the list of machine types available
// for each family
func (c *Client) MachineTypeListByFamily(imgs *compute.MachineTypeList, family string) LabeledValues {
lb := LabeledValues{}
tempTypes := []compute.MachineType{}
for _, v := range imgs.Items {
if strings.Contains(v.Name, family) {
tempTypes = append(tempTypes, *v)
}
}
sort.Slice(tempTypes, func(i, j int) bool {
return tempTypes[i].GuestCpus < tempTypes[j].GuestCpus
})
for _, v := range tempTypes {
if strings.Contains(v.Name, family) {
value := v.Name
label := fmt.Sprintf("%s %s", v.Name, v.Description)
lb = append(lb, LabeledValue{
Value: value,
Label: label,
IsDefault: false,
})
}
}
lb.SetDefault(lb[0].Value)
return lb
}
// ImageFamilyList gets a list of image families
func (c *Client) ImageFamilyList(imgs *compute.ImageList) LabeledValues {
fam := make(map[string]bool)
lb := LabeledValues{}
for _, v := range imgs.Items {
fam[v.Family] = false
}
for i := range fam {
if i == "" {
continue
}
lb = append(lb, LabeledValue{
Value: i,
Label: i,
IsDefault: false,
})
}
lb.SetDefault(DefaultImageFamily)
lb.Sort()
return lb
}
// ImageTypeListByFamily retrieves a list of iamge types by the family
func (c *Client) ImageTypeListByFamily(imgs *compute.ImageList, project, family string) LabeledValues {
lb := LabeledValues{}
for _, v := range imgs.Items {
if v.Family == family {
value := fmt.Sprintf("%s/%s", project, v.Name)
lb = append(lb, LabeledValue{
Value: value,
Label: v.Name,
IsDefault: false,
})
}
}
last := lb[len(lb)-1]
last.Label = fmt.Sprintf("%s (Latest)", last.Label)
lb[len(lb)-1] = last
lb.Sort()
lb.SetDefault(last.Value)
return lb
}