gcloud/gcloud.go (152 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 wraps up all of the cloud operations for DeployStack into // one client. It's mostly used to drive querying GCP projects and settings for // DeployStack ui. But it is also used to drive some of the authoring tooling package gcloud import ( "context" "fmt" "sort" "strings" domains "cloud.google.com/go/domains/apiv1beta1" scheduler "cloud.google.com/go/scheduler/apiv1beta1" "cloud.google.com/go/storage" "google.golang.org/api/cloudbilling/v1" "google.golang.org/api/cloudbuild/v1" "google.golang.org/api/cloudfunctions/v1" "google.golang.org/api/cloudresourcemanager/v1" "google.golang.org/api/compute/v1" "google.golang.org/api/iam/v1" "google.golang.org/api/option" "google.golang.org/api/run/v1" "google.golang.org/api/secretmanager/v1" "google.golang.org/api/serviceusage/v1" ) var ( // DefaultRegion is the default compute region used in compute calls. DefaultRegion = "us-central1" // DefaultMachineType is the default compute machine type used in compute calls. DefaultMachineType = "n1-standard" // DefaultMachineFamily is the default compute machine type used in compute calls. DefaultMachineFamily = "n1" // DefaultImageProject is the default project for images used in compute calls. DefaultImageProject = "debian-cloud" // DefaultImageFamily is the default project for images used in compute calls. DefaultImageFamily = "debian-11" // DefaultDiskSize is the default size for making disks for Compute Engine DefaultDiskSize = "200" // DefaultDiskType is the default style of disk DefaultDiskType = "pd-standard" // DefaultInstanceType is the default machine type of compute engine DefaultInstanceType = "n1-standard-1" // HTTPServerTags are the instance tags to open up the instance to be a // http server HTTPServerTags = "[http-server,https-server]" // DefaultZone is the default zone used in compute calls. DefaultZone = "us-central1-a" // ErrorBillingInvalidAccount is the error you get if you pass in a bad // Billing Account ID ErrorBillingInvalidAccount = fmt.Errorf("not a valid billing account") // ErrorBillingNoPermission is the error you get if the user lacks billing // related permissions ErrorBillingNoPermission = fmt.Errorf("user lacks permission") // ErrorProjectCreateTooLong is an error when you try to create a project // wuth more than 30 characters ErrorProjectCreateTooLong = fmt.Errorf("project_id contains too many characters, limit 30") // ErrorProjectCreateTooShort is an error when you try to create a project // wuth less than 6 characters ErrorProjectCreateTooShort = fmt.Errorf("project_id contains too few characters, minimum 6") // ErrorProjectInvalidCharacters is an error when you try and pass bad // characters into a CreateProjectCall ErrorProjectInvalidCharacters = fmt.Errorf("project_id contains invalid characters") // ErrorProjectAlreadyExists is an error when you try and create a project // That already exists ErrorProjectAlreadyExists = fmt.Errorf("project_id already exists") // ErrorProjectDidNotFinish is an error we cannot confirm that project completion actually occurred ErrorProjectDidNotFinish = fmt.Errorf("project creation did not complete in a timely manner") ) // Client is the tool that will handle all of the communication between gcloud // and the various product areas type Client struct { ctx context.Context services services userAgent string opts option.ClientOption enabledServices map[string]bool cache map[string]interface{} } // NewClient initiates a new gcloud Client func NewClient(ctx context.Context, ua string) Client { c := Client{} c.ctx = ctx c.userAgent = ua c.opts = option.WithCredentialsFile("") c.enabledServices = make(map[string]bool) c.cache = map[string]interface{}{} return c } func (c *Client) save(key string, value interface{}) { c.cache[key] = value } func (c *Client) get(key string) interface{} { return c.cache[key] } type services struct { resourceManager *cloudresourcemanager.Service billing *cloudbilling.APIService domains *domains.Client serviceUsage *serviceusage.Service computeService *compute.Service functions *cloudfunctions.Service run *run.APIService build *cloudbuild.Service iam *iam.Service scheduler *scheduler.CloudSchedulerClient secretManager *secretmanager.Service storage *storage.Client } // RegionList will return a list of RegionsList depending on product type func (c *Client) RegionList(project, product string) ([]string, error) { switch product { case "compute": return c.ComputeRegionList(project) case "functions": return c.FunctionRegionList(project) case "run": return c.RunRegionList(project) } return []string{}, fmt.Errorf("invalid product (%s) requested", product) } // LabeledValue is a struct that contains a label/value pair type LabeledValue struct { Value string Label string IsDefault bool } // NewLabeledValue takes a string and converts it to a LabeledValue. If a | // delimiter is present it will split into a different label/value func NewLabeledValue(s string) LabeledValue { l := LabeledValue{s, s, false} if strings.Contains(s, "|") { sl := strings.Split(s, "|") l = LabeledValue{sl[0], sl[1], false} } return l } // LabeledValues is collection of LabledValue structs type LabeledValues []LabeledValue // Sort orders the LabeledValues by Label func (l *LabeledValues) Sort() { sort.Slice(*l, func(i, j int) bool { iStr := strings.ToLower((*l)[i].Label) jStr := strings.ToLower((*l)[j].Label) return iStr < jStr }) } // LongestLen returns the length of longest LABEL in the list func (l *LabeledValues) LongestLen() int { longest := 0 for _, v := range *l { if len(v.Label) > longest { longest = len(v.Label) } } return longest } // GetDefault returns the default value of the LabeledValues list func (l *LabeledValues) GetDefault() LabeledValue { for _, v := range *l { if v.IsDefault { return v } } return LabeledValue{} } // SetDefault sets the default value of the list func (l *LabeledValues) SetDefault(value string) { for i, v := range *l { if v.Value == value { v.IsDefault = true (*l)[i] = v } } } // NewLabeledValues takes a slice of strings and returns a list of LabeledValues func NewLabeledValues(sl []string, defaultValue string) LabeledValues { r := LabeledValues{} for _, v := range sl { val := NewLabeledValue(v) if val.Value == defaultValue { val.IsDefault = true } r = append(r, val) } return r } // NewContactData returns a properly initialized ContactData func NewContactData() ContactData { c := ContactData{} d := DomainRegistrarContact{} d.PostalAddress.AddressLines = []string{} d.PostalAddress.Recipients = []string{} c.AllContacts = d return c }