Created
August 13, 2025 20:59
-
-
Save DazWilkin/76add445b6c883f1a0ff2dcca81edcca to your computer and use it in GitHub Desktop.
Stackoverflow: 79734079
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "log/slog" | |
| "math/rand/v2" | |
| "os" | |
| "cloud.google.com/go/run/apiv2/runpb" | |
| ) | |
| type config struct { | |
| project string | |
| region string | |
| service string | |
| revisions map[string]string | |
| } | |
| func new() config { | |
| return config{ | |
| project: os.Getenv("PROJECT"), | |
| region: os.Getenv("REGION"), | |
| service: os.Getenv("SERVICE"), | |
| revisions: map[string]string{ | |
| "blue": os.Getenv("BLUE"), | |
| "green": os.Getenv("GREEN"), | |
| "purple": os.Getenv("PURPLE"), | |
| }, | |
| } | |
| } | |
| func (c config) name() string { | |
| name := fmt.Sprintf("projects/%s/locations/%s/services/%s", | |
| c.project, | |
| c.region, | |
| c.service, | |
| ) | |
| return name | |
| } | |
| // traffic is a method that returns a Cloud RUn Service's TrafficTarget | |
| // It uses a random number, initially 100%, that reduces for each target | |
| // The last target must always consume the remaining percentage | |
| // So that the total of all the revisions is 100% | |
| func (c config) traffic() []*runpb.TrafficTarget { | |
| // Create TrafficTargets for each config revision | |
| num := len(c.revisions) | |
| targets := make([]*runpb.TrafficTarget, num) | |
| // Generate random traffic percent to avoid collisions | |
| // Start with 1..100 | |
| var remaining int32 = 100 | |
| var percent int32 | |
| // Iterator | |
| i := 0 | |
| for tag, revision := range c.revisions { | |
| // The last branch must consume the remaining percent so that the branches total 100% | |
| if i == num-1 { | |
| percent = remaining | |
| } else { | |
| percent = rand.N(int32(remaining + 1)) | |
| } | |
| slog.Info("Generating traffic", | |
| "tag", tag, | |
| "revision", revision, | |
| "percent", percent, | |
| ) | |
| targets[i] = &runpb.TrafficTarget{ | |
| Type: runpb.TrafficTargetAllocationType_TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION, | |
| Revision: revision, | |
| Percent: percent, | |
| Tag: tag, | |
| } | |
| // Increment the iterator | |
| i = i + 1 | |
| remaining = remaining - percent | |
| } | |
| return targets | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module github.com/DazWilkin/stackoverflow/79734079 | |
| go 1.25.0 | |
| require ( | |
| cloud.google.com/go/run v1.12.0 | |
| google.golang.org/protobuf v1.36.7 | |
| ) | |
| require ( | |
| cloud.google.com/go v0.120.0 // indirect | |
| cloud.google.com/go/auth v0.16.3 // indirect | |
| cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect | |
| cloud.google.com/go/compute/metadata v0.7.0 // indirect | |
| cloud.google.com/go/iam v1.5.2 // indirect | |
| cloud.google.com/go/longrunning v0.6.7 // indirect | |
| github.com/felixge/httpsnoop v1.0.4 // indirect | |
| github.com/go-logr/logr v1.4.3 // indirect | |
| github.com/go-logr/stdr v1.2.2 // indirect | |
| github.com/google/s2a-go v0.1.9 // indirect | |
| github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect | |
| github.com/googleapis/gax-go/v2 v2.15.0 // indirect | |
| go.opentelemetry.io/auto/sdk v1.1.0 // indirect | |
| go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect | |
| go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect | |
| go.opentelemetry.io/otel v1.36.0 // indirect | |
| go.opentelemetry.io/otel/metric v1.36.0 // indirect | |
| go.opentelemetry.io/otel/trace v1.36.0 // indirect | |
| golang.org/x/crypto v0.40.0 // indirect | |
| golang.org/x/net v0.42.0 // indirect | |
| golang.org/x/oauth2 v0.30.0 // indirect | |
| golang.org/x/sync v0.16.0 // indirect | |
| golang.org/x/sys v0.34.0 // indirect | |
| golang.org/x/text v0.27.0 // indirect | |
| golang.org/x/time v0.12.0 // indirect | |
| google.golang.org/api v0.246.0 // indirect | |
| google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect | |
| google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect | |
| google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect | |
| google.golang.org/grpc v1.74.2 // indirect | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "context" | |
| "log/slog" | |
| "os" | |
| run "cloud.google.com/go/run/apiv2" | |
| "cloud.google.com/go/run/apiv2/runpb" | |
| "google.golang.org/protobuf/types/known/fieldmaskpb" | |
| ) | |
| func main() { | |
| ctx := context.Background() | |
| client, err := run.NewServicesClient(ctx) | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer func() { | |
| if err := client.Close(); err != nil { | |
| slog.Error("Failed to close client", "err", err.Error()) | |
| os.Exit(1) | |
| } | |
| }() | |
| c := new() | |
| // Get the Service | |
| var resp *runpb.Service | |
| { | |
| rqst := &runpb.GetServiceRequest{ | |
| Name: c.name(), | |
| } | |
| var err error | |
| resp, err = client.GetService(ctx, rqst) | |
| if err != nil { | |
| panic(err) | |
| } | |
| slog.Info("Response", "resp", resp) | |
| } | |
| // Update the Service | |
| { | |
| // Update the Service's traffic | |
| resp.Traffic = c.traffic() | |
| rqst := &runpb.UpdateServiceRequest{ | |
| UpdateMask: &fieldmaskpb.FieldMask{ | |
| Paths: []string{ | |
| "traffic", | |
| }, | |
| }, | |
| Service: resp, | |
| } | |
| resp, err := client.UpdateService(ctx, rqst) | |
| if err != nil { | |
| panic(err) | |
| } | |
| slog.Info("Response", "resp", resp) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment