Skip to content

Commit 60618e6

Browse files
committed
feat(cloudrun): create sample service for cloud run readiness probe and service health feature
1 parent ca42e6c commit 60618e6

File tree

12 files changed

+1239
-8
lines changed

12 files changed

+1239
-8
lines changed

go.work

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ use (
130130
./run/markdown-preview/renderer
131131
./run/pubsub
132132
./run/service-auth
133+
./run/service-health
133134
./run/sigterm-handler
134135
./run/system_package
135136
./run/testing

internal/cloudrunci/cloudrunci.go

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,21 @@ type Service struct {
8585

8686
// Location to deploy the Service, and related artifacts
8787
Location string
88+
89+
Readiness *struct {
90+
TimeoutSeconds int
91+
PerioidSeconds int
92+
SuccessThreshold int
93+
FailureThreshold int
94+
HttpGet *struct {
95+
Path string
96+
Port int
97+
}
98+
GRPC *struct {
99+
Port int
100+
Service string
101+
}
102+
}
88103
}
89104

90105
// runID is an identifier that changes between runs.
@@ -272,7 +287,7 @@ func (s *Service) validate() error {
272287

273288
// revision returns the revision that the service will be deployed to.
274289
// NOTE: Until traffic splitting is available, this will be used as the service name.
275-
func (s *Service) version() string {
290+
func (s *Service) Version() string {
276291
return s.Name + "-" + runID
277292
}
278293

@@ -293,7 +308,7 @@ func (s *Service) Deploy() error {
293308
}
294309

295310
if _, err := gcloud(s.operationLabel(labelOperationDeploy), s.deployCmd()); err != nil {
296-
return fmt.Errorf("gcloud: %s: %q", s.version(), err)
311+
return fmt.Errorf("gcloud: %s: %q", s.Version(), err)
297312
}
298313

299314
s.deployed = true
@@ -339,15 +354,15 @@ func (s *Service) Clean() error {
339354
}
340355

341356
if _, err := gcloud(s.operationLabel(labelOperationDeleteService), s.deleteServiceCmd()); err != nil {
342-
return fmt.Errorf("gcloud: %v: %q", s.version(), err)
357+
return fmt.Errorf("gcloud: %v: %q", s.Version(), err)
343358
}
344359
s.deployed = false
345360

346361
// If s.built is false no image was created or is not managed by cloudrun-ci.
347362
if s.built {
348363
_, err := gcloud(s.operationLabel("delete container image"), s.deleteImageCmd())
349364
if err != nil {
350-
return fmt.Errorf("gcloud: %v: %q", s.version(), err)
365+
return fmt.Errorf("gcloud: %v: %q", s.Version(), err)
351366
}
352367
s.built = false
353368
}
@@ -365,7 +380,7 @@ func (s *Service) deployCmd() *exec.Cmd {
365380
"alpha", // TODO until --use-http2 goes GA
366381
"run",
367382
"deploy",
368-
s.version(),
383+
s.Version(),
369384
"--project",
370385
s.ProjectID,
371386
"--image",
@@ -384,6 +399,22 @@ func (s *Service) deployCmd() *exec.Cmd {
384399
args = append(args, "--use-http2")
385400
}
386401

402+
if s.Readiness != nil {
403+
readinessFlag := "--readiness-probe="
404+
readinessFlag += fmt.Sprintf("timeoutSeconds=%d,", s.Readiness.TimeoutSeconds)
405+
readinessFlag += fmt.Sprintf("periodSeconds=%d,", s.Readiness.PerioidSeconds)
406+
readinessFlag += fmt.Sprintf("successThreshold=%d,", s.Readiness.SuccessThreshold)
407+
readinessFlag += fmt.Sprintf("failureThreshold=%d,", s.Readiness.FailureThreshold)
408+
if s.Readiness.HttpGet != nil {
409+
readinessFlag += fmt.Sprintf("httpGet.path=%s,", s.Readiness.HttpGet.Path)
410+
readinessFlag += fmt.Sprintf("httpGet.port=%d", s.Readiness.HttpGet.Port)
411+
} else if s.Readiness.GRPC != nil {
412+
readinessFlag += fmt.Sprintf("grpc.port=%d,", s.Readiness.GRPC.Port)
413+
readinessFlag += fmt.Sprintf("grpc.service=%s", s.Readiness.GRPC.Service)
414+
}
415+
args = append(args, readinessFlag)
416+
}
417+
387418
// NOTE: if the "beta" component is not available, and this is run in parallel,
388419
// gcloud will attempt to install those components multiple
389420
// times and will eventually fail on IO.
@@ -439,7 +470,7 @@ func (s *Service) deleteServiceCmd() *exec.Cmd {
439470
"run",
440471
"services",
441472
"delete",
442-
s.version(),
473+
s.Version(),
443474
"--project",
444475
s.ProjectID,
445476
}, s.Platform.CommandFlags()...)
@@ -458,7 +489,7 @@ func (s *Service) urlCmd() *exec.Cmd {
458489
"run",
459490
"services",
460491
"describe",
461-
s.version(),
492+
s.Version(),
462493
"--project",
463494
s.ProjectID,
464495
"--format",
@@ -481,7 +512,7 @@ func (s *Service) LogEntries(filter string, find string, maxAttempts int) (bool,
481512
}
482513
defer client.Close()
483514

484-
preparedFilter := fmt.Sprintf(`resource.type="cloud_run_revision" resource.labels.service_name="%s" %s`, s.version(), filter)
515+
preparedFilter := fmt.Sprintf(`resource.type="cloud_run_revision" resource.labels.service_name="%s" %s`, s.Version(), filter)
485516
log.Printf("Using log filter: %s\n", preparedFilter)
486517

487518
log.Println("Waiting for logs...")

internal/cloudrunci/gcs.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cloudrunci
16+
17+
import (
18+
"os/exec"
19+
)
20+
21+
func DeleteBucketAndContents(bucketName string) ([]byte, error) {
22+
cmd := exec.Command(gcloudBin, "storage", "rm", "-r", "gs://"+bucketName)
23+
return cmd.CombinedOutput()
24+
}

internal/cloudrunci/gcs_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cloudrunci
16+
17+
import (
18+
"strings"
19+
"testing"
20+
)
21+
22+
func TestDeleteBucketAndContents(t *testing.T) {
23+
out, err := DeleteBucketAndContents("some-radom-bucket-name")
24+
if err == nil {
25+
t.Error("gcloud: expect error but not nil")
26+
}
27+
28+
want := "not found: 404"
29+
if got := string(out); !strings.Contains(got, want) {
30+
t.Errorf("gcloud: got (%s), want (%s)", got, want)
31+
}
32+
}

run/service-health/assets/celebration.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)