Skip to content

Commit b9cda80

Browse files
authored
feat: Add support for configurable statusCheckDeadlineSeconds field for Cloud Run (#9778)
* update cloud run to use statuscheckdeadline * Add support for configurable statusCheckDeadlineSeconds field for Cloud Run * update tests and doc
1 parent ef4b0b8 commit b9cda80

File tree

7 files changed

+161
-52
lines changed

7 files changed

+161
-52
lines changed

docs-v2/content/en/docs/status-check.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ featureId: deploy.status_check
66
aliases: [/docs/how-tos/status-check, /docs/pipeline-stages/status-check]
77
---
88

9-
This page describes how Skaffold's _deployment status checking_ waits for deployed resources to become ready, and reports errors if they fails to stabilize within a certain time period.
9+
This page describes how Skaffold's _deployment status checking_ waits for deployed resources to become ready, and reports errors if they fail to stabilize within a certain time period.
1010

1111
### Overview
1212

13-
Commands that trigger a deployment, like `skaffold dev`, `skaffold deploy`, `skaffold run`, and `skaffold apply`, monitor select Kubernetes resources and wait for them to become ready.
13+
Commands that trigger a deployment, like `skaffold dev`, `skaffold deploy`, `skaffold run`, and `skaffold apply`, monitor select resources and wait for them to become ready.
1414

1515
Skaffold monitors the status of the following resource types:
1616
* [`Pod`](https://kubernetes.io/docs/concepts/workloads/pods/): check that the pod and its containers are in a `Ready` state.
1717
* [`Deployment`](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/): check the output of `kubectl rollout status deployment` command
1818
* [`Stateful Sets`](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/): check the output of `kubectl rollout status statefulset` command
19+
* Cloud Run instances (running containers) are ready to receive traffic
1920

2021
{{<alert title="Note">}}
2122
* Status checking is enabled by default; it can be disabled with the `--status-check=false`

pkg/skaffold/deploy/cloudrun/deploy.go

+17-13
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"io"
2323
"net/http"
24+
"time"
2425

2526
"google.golang.org/api/googleapi"
2627
"google.golang.org/api/option"
@@ -55,17 +56,19 @@ type Config interface {
5556
Tail() bool
5657
}
5758

58-
// Deployer deploys code to Google Cloud Run.
59+
// Deployer deploys code to Google Cloud Run. This implements the Deployer
60+
// interface for Cloud Run.
5961
type Deployer struct {
6062
configName string
6163

6264
*latest.CloudRunDeploy
6365

64-
logger *LogAggregator
65-
accessor *RunAccessor
66-
monitor *Monitor
67-
labeller *label.DefaultLabeller
68-
hookRunner hooks.Runner
66+
logger *LogAggregator
67+
accessor *RunAccessor
68+
monitor *Monitor
69+
labeller *label.DefaultLabeller
70+
hookRunner hooks.Runner
71+
statusCheckDeadline time.Duration
6972

7073
Project string
7174
Region string
@@ -76,18 +79,19 @@ type Deployer struct {
7679
}
7780

7881
// NewDeployer creates a new Deployer for Cloud Run from the Skaffold deploy config.
79-
func NewDeployer(cfg Config, labeller *label.DefaultLabeller, crDeploy *latest.CloudRunDeploy, configName string) (*Deployer, error) {
82+
func NewDeployer(cfg Config, labeller *label.DefaultLabeller, crDeploy *latest.CloudRunDeploy, configName string, statusCheckDeadline time.Duration) (*Deployer, error) {
8083
return &Deployer{
8184
configName: configName,
8285
CloudRunDeploy: crDeploy,
8386
Project: crDeploy.ProjectID,
8487
Region: crDeploy.Region,
8588
// TODO: implement logger for Cloud Run.
86-
logger: NewLoggerAggregator(cfg, labeller.GetRunID()),
87-
accessor: NewAccessor(cfg, labeller.GetRunID()),
88-
labeller: labeller,
89-
hookRunner: hooks.NewCloudRunDeployRunner(crDeploy.LifecycleHooks, hooks.NewDeployEnvOpts(labeller.GetRunID(), "", []string{})),
90-
useGcpOptions: true,
89+
logger: NewLoggerAggregator(cfg, labeller.GetRunID()),
90+
accessor: NewAccessor(cfg, labeller.GetRunID()),
91+
labeller: labeller,
92+
hookRunner: hooks.NewCloudRunDeployRunner(crDeploy.LifecycleHooks, hooks.NewDeployEnvOpts(labeller.GetRunID(), "", []string{})),
93+
useGcpOptions: true,
94+
statusCheckDeadline: statusCheckDeadline,
9195
}, nil
9296
}
9397

@@ -178,7 +182,7 @@ func (d *Deployer) PostDeployHooks(ctx context.Context, out io.Writer) error {
178182

179183
func (d *Deployer) getMonitor() *Monitor {
180184
if d.monitor == nil {
181-
d.monitor = NewMonitor(d.labeller, d.clientOptions)
185+
d.monitor = NewMonitor(d.labeller, d.clientOptions, d.statusCheckDeadline)
182186
}
183187
return d.monitor
184188
}

pkg/skaffold/deploy/cloudrun/deploy_test.go

+96-27
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"net/http/httptest"
2525
"os"
2626
"testing"
27+
"time"
2728

2829
"github.com/google/go-cmp/cmp"
2930
"google.golang.org/api/option"
@@ -46,21 +47,25 @@ const (
4647
configName = "default"
4748
)
4849

50+
var defaultStatusCheckDeadline = 10 * time.Minute
51+
4952
func TestDeployService(tOuter *testing.T) {
5053
tests := []struct {
51-
description string
52-
toDeploy *run.Service
53-
defaultProject string
54-
region string
55-
expectedPath string
56-
httpErr int
57-
errCode proto.StatusCode
54+
description string
55+
toDeploy *run.Service
56+
defaultProject string
57+
region string
58+
statusCheckDeadline time.Duration
59+
expectedPath string
60+
httpErr int
61+
errCode proto.StatusCode
5862
}{
5963
{
60-
description: "test deploy",
61-
defaultProject: "testProject",
62-
region: "us-central1",
63-
expectedPath: "/v1/projects/testProject/locations/us-central1/services",
64+
description: "test deploy",
65+
defaultProject: "testProject",
66+
region: "us-central1",
67+
expectedPath: "/v1/projects/testProject/locations/us-central1/services",
68+
statusCheckDeadline: defaultStatusCheckDeadline,
6469
toDeploy: &run.Service{
6570
ApiVersion: "serving.knative.dev/v1",
6671
Kind: "Service",
@@ -70,10 +75,25 @@ func TestDeployService(tOuter *testing.T) {
7075
},
7176
},
7277
{
73-
description: "test deploy with specified project",
74-
defaultProject: "testProject",
75-
region: "us-central1",
76-
expectedPath: "/v1/projects/testProject/locations/us-central1/services",
78+
description: "test deploy with status check deadline set to a non default value",
79+
defaultProject: "testProject",
80+
region: "us-central1",
81+
expectedPath: "/v1/projects/testProject/locations/us-central1/services",
82+
statusCheckDeadline: 15 * time.Minute,
83+
toDeploy: &run.Service{
84+
ApiVersion: "serving.knative.dev/v1",
85+
Kind: "Service",
86+
Metadata: &run.ObjectMeta{
87+
Name: "test-service",
88+
},
89+
},
90+
},
91+
{
92+
description: "test deploy with specified project",
93+
defaultProject: "testProject",
94+
region: "us-central1",
95+
statusCheckDeadline: defaultStatusCheckDeadline,
96+
expectedPath: "/v1/projects/testProject/locations/us-central1/services",
7797
toDeploy: &run.Service{
7898
ApiVersion: "serving.knative.dev/v1",
7999
Kind: "Service",
@@ -84,10 +104,11 @@ func TestDeployService(tOuter *testing.T) {
84104
},
85105
},
86106
{
87-
description: "test permission denied on deploy errors",
88-
defaultProject: "testProject",
89-
region: "us-central1",
90-
httpErr: http.StatusUnauthorized,
107+
description: "test permission denied on deploy errors",
108+
defaultProject: "testProject",
109+
region: "us-central1",
110+
statusCheckDeadline: defaultStatusCheckDeadline,
111+
httpErr: http.StatusUnauthorized,
91112
toDeploy: &run.Service{
92113
ApiVersion: "serving.knative.dev/v1",
93114
Kind: "Service",
@@ -99,8 +120,9 @@ func TestDeployService(tOuter *testing.T) {
99120
errCode: proto.StatusCode_DEPLOY_CLOUD_RUN_GET_SERVICE_ERR,
100121
},
101122
{
102-
description: "test no project specified",
103-
region: "us-central1",
123+
description: "test no project specified",
124+
region: "us-central1",
125+
statusCheckDeadline: defaultStatusCheckDeadline,
104126
toDeploy: &run.Service{
105127
ApiVersion: "serving.knative.dev/v1",
106128
Kind: "Service",
@@ -139,7 +161,14 @@ func TestDeployService(tOuter *testing.T) {
139161
w.Write(b)
140162
}))
141163

142-
deployer, _ := NewDeployer(&runcontext.RunContext{}, &label.DefaultLabeller{}, &latest.CloudRunDeploy{ProjectID: test.defaultProject, Region: test.region}, configName)
164+
deployer, _ := NewDeployer(
165+
&runcontext.RunContext{},
166+
&label.DefaultLabeller{},
167+
&latest.CloudRunDeploy{
168+
ProjectID: test.defaultProject,
169+
Region: test.region},
170+
configName,
171+
test.statusCheckDeadline)
143172
deployer.clientOptions = append(deployer.clientOptions, option.WithEndpoint(ts.URL), option.WithoutAuthentication())
144173
deployer.useGcpOptions = false
145174
manifestList, _ := json.Marshal(test.toDeploy)
@@ -311,7 +340,15 @@ func TestDeployJob(tOuter *testing.T) {
311340
w.Write(b)
312341
}))
313342

314-
deployer, _ := NewDeployer(&runcontext.RunContext{}, &label.DefaultLabeller{}, &latest.CloudRunDeploy{ProjectID: test.defaultProject, Region: test.region}, configName)
343+
deployer, _ := NewDeployer(
344+
&runcontext.RunContext{},
345+
&label.DefaultLabeller{},
346+
&latest.CloudRunDeploy{
347+
ProjectID: test.defaultProject,
348+
Region: test.region,
349+
},
350+
configName,
351+
defaultStatusCheckDeadline)
315352
deployer.clientOptions = append(deployer.clientOptions, option.WithEndpoint(ts.URL), option.WithoutAuthentication())
316353
deployer.useGcpOptions = false
317354
manifestList, _ := k8syaml.Marshal(test.toDeploy)
@@ -469,7 +506,15 @@ func TestDeployRewrites(tOuter *testing.T) {
469506
}
470507
w.Write(b)
471508
}))
472-
deployer, _ := NewDeployer(&runcontext.RunContext{}, &label.DefaultLabeller{}, &latest.CloudRunDeploy{ProjectID: test.defaultProject, Region: test.region}, "")
509+
deployer, _ := NewDeployer(
510+
&runcontext.RunContext{},
511+
&label.DefaultLabeller{},
512+
&latest.CloudRunDeploy{
513+
ProjectID: test.defaultProject,
514+
Region: test.region,
515+
},
516+
"",
517+
defaultStatusCheckDeadline)
473518
deployer.clientOptions = append(deployer.clientOptions, option.WithEndpoint(ts.URL), option.WithoutAuthentication())
474519
deployer.useGcpOptions = false
475520
m, _ := json.Marshal(test.toDeploy)
@@ -555,7 +600,15 @@ func TestCleanupService(tOuter *testing.T) {
555600
w.Write(b)
556601
}))
557602
defer ts.Close()
558-
deployer, _ := NewDeployer(&runcontext.RunContext{}, &label.DefaultLabeller{}, &latest.CloudRunDeploy{ProjectID: test.defaultProject, Region: test.region}, configName)
603+
deployer, _ := NewDeployer(
604+
&runcontext.RunContext{},
605+
&label.DefaultLabeller{},
606+
&latest.CloudRunDeploy{
607+
ProjectID: test.defaultProject,
608+
Region: test.region,
609+
},
610+
configName,
611+
defaultStatusCheckDeadline)
559612
deployer.clientOptions = append(deployer.clientOptions, option.WithEndpoint(ts.URL), option.WithoutAuthentication())
560613
deployer.useGcpOptions = false
561614
manifestListByConfig := manifest.NewManifestListByConfig()
@@ -629,7 +682,15 @@ func TestCleanupJob(tOuter *testing.T) {
629682
w.Write(b)
630683
}))
631684
defer ts.Close()
632-
deployer, _ := NewDeployer(&runcontext.RunContext{}, &label.DefaultLabeller{}, &latest.CloudRunDeploy{ProjectID: test.defaultProject, Region: test.region}, configName)
685+
deployer, _ := NewDeployer(
686+
&runcontext.RunContext{},
687+
&label.DefaultLabeller{},
688+
&latest.CloudRunDeploy{
689+
ProjectID: test.defaultProject,
690+
Region: test.region,
691+
},
692+
configName,
693+
defaultStatusCheckDeadline)
633694
deployer.clientOptions = append(deployer.clientOptions, option.WithEndpoint(ts.URL), option.WithoutAuthentication())
634695
deployer.useGcpOptions = false
635696
manifestListByConfig := manifest.NewManifestListByConfig()
@@ -693,7 +754,15 @@ func TestCleanupMultipleResources(tOuter *testing.T) {
693754
w.Write(b)
694755
}))
695756
defer ts.Close()
696-
deployer, _ := NewDeployer(&runcontext.RunContext{}, &label.DefaultLabeller{}, &latest.CloudRunDeploy{ProjectID: test.defaultProject, Region: test.region}, configName)
757+
deployer, _ := NewDeployer(
758+
&runcontext.RunContext{},
759+
&label.DefaultLabeller{},
760+
&latest.CloudRunDeploy{
761+
ProjectID: test.defaultProject,
762+
Region: test.region,
763+
},
764+
configName,
765+
defaultStatusCheckDeadline)
697766
deployer.clientOptions = append(deployer.clientOptions, option.WithEndpoint(ts.URL), option.WithoutAuthentication())
698767
deployer.useGcpOptions = false
699768
manifestListByConfig := manifest.NewManifestListByConfig()

pkg/skaffold/deploy/cloudrun/status.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ import (
3737
)
3838

3939
var (
40-
defaultStatusCheckDeadline = 10 * time.Minute
41-
defaultPollPeriod = 1000 * time.Millisecond
42-
defaultReportStatusTime = 5 * time.Second
40+
defaultPollPeriod = 1000 * time.Millisecond
41+
defaultReportStatusTime = 5 * time.Second
4342
)
4443

4544
type Monitor struct {
@@ -53,11 +52,11 @@ type Monitor struct {
5352
reportStatusTime time.Duration
5453
}
5554

56-
func NewMonitor(labeller *label.DefaultLabeller, clientOptions []option.ClientOption) *Monitor {
55+
func NewMonitor(labeller *label.DefaultLabeller, clientOptions []option.ClientOption, statusCheckDeadline time.Duration) *Monitor {
5756
return &Monitor{
5857
labeller: labeller,
5958
clientOptions: clientOptions,
60-
statusCheckDeadline: defaultStatusCheckDeadline,
59+
statusCheckDeadline: statusCheckDeadline,
6160
pollPeriod: defaultPollPeriod,
6261
reportStatusTime: defaultReportStatusTime,
6362
}

pkg/skaffold/deploy/cloudrun/status_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func TestPrintSummaryStatus(t *testing.T) {
8484
status: Status{ae: test.ae},
8585
sub: &runServiceResource{path: test.resource.String()},
8686
}
87-
s := NewMonitor(labeller, []option.ClientOption{})
87+
s := NewMonitor(labeller, []option.ClientOption{}, defaultStatusCheckDeadline)
8888
out := new(bytes.Buffer)
8989
testEvent.InitializeState([]latest.Pipeline{{}})
9090
c := newCounter(10)
@@ -428,7 +428,7 @@ func TestMonitorPrintStatus(t *testing.T) {
428428
testutil.Run(t, test.description, func(t *testutil.T) {
429429
testEvent.InitializeState([]latest.Pipeline{{}})
430430

431-
monitor := NewMonitor(labeller, []option.ClientOption{})
431+
monitor := NewMonitor(labeller, []option.ClientOption{}, defaultStatusCheckDeadline)
432432
out := new(bytes.Buffer)
433433
done := monitor.printStatus(test.resources, out)
434434
if done != test.done {

pkg/skaffold/runner/deployer.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"fmt"
2424
"os"
2525
"strconv"
26+
"time"
2627

2728
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/config"
2829
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/deploy"
@@ -41,6 +42,8 @@ import (
4142
"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/util/stringslice"
4243
)
4344

45+
var DefaultStatusCheckDeadline = 10 * time.Minute
46+
4447
// deployerCtx encapsulates a given skaffold run context along with additional deployer constructs.
4548
type deployerCtx struct {
4649
*runcontext.RunContext
@@ -353,12 +356,29 @@ func getCloudRunDeployer(runCtx *runcontext.RunContext, labeller *label.DefaultL
353356
}
354357
}
355358
}
359+
statusCheckDeadline := maxStatusCheckDeadline(deployers)
356360

357361
lifecycleHooks := latest.CloudRunDeployHooks{}
358362
if configName != "" {
359363
currentPipeline := runCtx.Pipelines.GetForConfigName(configName)
360364
lifecycleHooks = currentPipeline.Deploy.CloudRunDeploy.LifecycleHooks
361365
}
362366

363-
return cloudrun.NewDeployer(runCtx, labeller, &latest.CloudRunDeploy{Region: region, ProjectID: defaultProject, LifecycleHooks: lifecycleHooks}, configName)
367+
return cloudrun.NewDeployer(runCtx, labeller, &latest.CloudRunDeploy{Region: region, ProjectID: defaultProject, LifecycleHooks: lifecycleHooks}, configName, statusCheckDeadline)
368+
}
369+
370+
// maxStatusCheckDeadline goes through each of the Deploy Configs and finds the
371+
// max. If none have the field set, it uses the default.
372+
func maxStatusCheckDeadline(deployConfigs []latest.DeployConfig) time.Duration {
373+
c := 0
374+
// set the group status check deadline to maximum of any individually specified value
375+
for _, d := range deployConfigs {
376+
if d.StatusCheckDeadlineSeconds > c {
377+
c = d.StatusCheckDeadlineSeconds
378+
}
379+
}
380+
if c == 0 {
381+
return DefaultStatusCheckDeadline
382+
}
383+
return time.Duration(c) * time.Second
364384
}

0 commit comments

Comments
 (0)