Skip to content

Instantly share code, notes, and snippets.

@tommed
Created December 18, 2019 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tommed/63f4740402ecc95e794963285f2e6042 to your computer and use it in GitHub Desktop.
Save tommed/63f4740402ecc95e794963285f2e6042 to your computer and use it in GitHub Desktop.
package gcp_api
import (
"errors"
"fmt"
"google.golang.org/api/googleapi"
"google.golang.org/api/option"
"google.golang.org/api/run/v1"
"strings"
)
const (
cloudRunAPIVersion = "serving.knative.dev/v1"
cloudRunServiceKind = "Service"
)
// current list: https://cloud.google.com/run/docs/reference/rest/#rest_endpoints
var cloudRunEndpoints = []string{
"https://us-central1-run.googleapis.com",
"https://asia-northeast1-run.googleapis.com",
"https://europe-west1-run.googleapis.com",
"https://us-east1-run.googleapis.com",
}
func findCloudRunEndpoint(location string) (string, error) {
for _, ep := range cloudRunEndpoints {
if strings.Contains(ep, location) {
return ep, nil
}
}
return "", fmt.Errorf("Unable to find a supported CloudRun endpoint for location %s. List of supported endpoints available here, supply us with just location part: <https://cloud.google.com/run/docs/reference/rest/#rest_endpoints>", location)
}
type GCPCloudRunEndpoint struct {
api *GCPAPI
service *run.APIService
location string
}
func (api GCPAPI) CloudRun(location string) (*GCPCloudRunEndpoint, error) {
// endpoint dictates location
ep, err := findCloudRunEndpoint(location)
if err != nil { return nil, err }
var opts = api.clientOptions() // returns [option.WithCredentialsFile(serviceAccountFile)]
opts = append(opts, option.WithEndpoint(ep))
// build service using the selected endpoint
svc, err := run.NewService(api.ctx, opts...)
if err != nil {
return nil, err
}
return &GCPCloudRunEndpoint{
service: svc,
location: location,
api: &api}, nil
}
func (api GCPCloudRunEndpoint) ServiceIsUpdated(projectID string, serviceName string, imageName string, envVars map[string]string, serviceAccountEmail string) (string, error) {
var projectNumber = api.api.ProjectNumber
// convert env vars
var kNativeEnvVars = make([]*run.EnvVar, 0)
if envVars != nil {
for k, v := range envVars {
kNativeEnvVars = append(kNativeEnvVars, &run.EnvVar{
Name: k,
Value: v,
})
}
}
// define the service
var serviceDefinition = &run.Service{
ApiVersion: cloudRunAPIVersion,
Kind: cloudRunServiceKind,
Metadata: &run.ObjectMeta{
Name: serviceName,
Namespace: string(projectNumber),
Generation: 1,
Labels: map[string]string{ "cloud.googleapis.com/location": api.location },
},
Spec: &run.ServiceSpec{
Template: &run.RevisionTemplate{
Metadata: &run.ObjectMeta{
Name: serviceName,
Annotations: map[string]string{
"autoscaling.knative.dev/maxScale": "1000",
},
},
Spec: &run.RevisionSpec{
ContainerConcurrency: 80,
// ServiceAccountName: serviceAccountEmail,
TimeoutSeconds: 300,
Containers: []*run.Container{
{
Image: imageName,
Env: kNativeEnvVars,
Ports: []*run.ContainerPort{
{
ContainerPort: 8080,
},
},
Resources: &run.ResourceRequirements{
Limits: map[string]string{
"memory": "256Mi",
"cpu": "1000m",
},
},
},
},
},
},
Traffic: []*run.TrafficTarget{
{
LatestRevision: true,
Percent: 100,
},
},
},
}
// upsert
var parentUri = fmt.Sprintf("namespaces/%s", projectID)
var serviceUri = fmt.Sprintf("%s/services/%s", parentUri, serviceName)
var status = "CloudRun service was created"
_, err := api.service.Namespaces.Services.Get(serviceUri).Do()
if err == nil {
// service already exists
_, err = api.service.Namespaces.Services.ReplaceService(serviceUri, serviceDefinition).Do()
} else {
// update existing service
_, err = api.service.Namespaces.Services.Create(parentUri, serviceDefinition).Do()
status = "CloudRun service was updated"
}
if err != nil {
v, isGoogleError := err.(*googleapi.Error)
if isGoogleError {
return "", errors.New(v.Body)
}
return "", err
}
return status, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment