Skip to content

Commit 2df7175

Browse files
vvolandk8s-infra-cherrypick-robot
authored andcommitted
client/New: Don't unlazy the gRPC connection implicitly
When moving to gRPC 1.64 (commit 63b4688) the usage of the deprecated `grpc.DialContext` was replaced with `grpc.NewClient`. However, this change also required to drop the `WithBlock` option, which made sure that the connection is actually established before returning. Now, `grpc.NewClient` doesn't attempt to perform the connection but defers it to the actual first RPC. Querying the default runtime on client creation breaks that property depending on whether the default namespace is set or not. This commit defers the `runtime` field initialization to the first time the field is actually needed. Signed-off-by: Paweł Gronowski <[email protected]>
1 parent 2797e57 commit 2df7175

2 files changed

Lines changed: 55 additions & 31 deletions

File tree

client/client.go

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,7 @@ func New(address string, opts ...Opt) (*Client, error) {
114114
}
115115

116116
if copts.defaultRuntime != "" {
117-
c.runtime = copts.defaultRuntime
118-
} else {
119-
c.runtime = defaults.DefaultRuntime
117+
c.runtime.value = copts.defaultRuntime
120118
}
121119

122120
if copts.defaultPlatform != nil {
@@ -174,15 +172,6 @@ func New(address string, opts ...Opt) (*Client, error) {
174172
return nil, fmt.Errorf("no grpc connection or services is available: %w", errdefs.ErrUnavailable)
175173
}
176174

177-
// check namespace labels for default runtime
178-
if copts.defaultRuntime == "" && c.defaultns != "" {
179-
if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil {
180-
return nil, err
181-
} else if label != "" {
182-
c.runtime = label
183-
}
184-
}
185-
186175
return c, nil
187176
}
188177

@@ -198,7 +187,10 @@ func NewWithConn(conn *grpc.ClientConn, opts ...Opt) (*Client, error) {
198187
c := &Client{
199188
defaultns: copts.defaultns,
200189
conn: conn,
201-
runtime: defaults.DefaultRuntime,
190+
}
191+
192+
if copts.defaultRuntime != "" {
193+
c.runtime.value = copts.defaultRuntime
202194
}
203195

204196
if copts.defaultPlatform != nil {
@@ -207,15 +199,6 @@ func NewWithConn(conn *grpc.ClientConn, opts ...Opt) (*Client, error) {
207199
c.platform = platforms.Default()
208200
}
209201

210-
// check namespace labels for default runtime
211-
if copts.defaultRuntime == "" && c.defaultns != "" {
212-
if label, err := c.GetLabel(context.Background(), defaults.DefaultRuntimeNSLabel); err != nil {
213-
return nil, err
214-
} else if label != "" {
215-
c.runtime = label
216-
}
217-
}
218-
219202
if copts.services != nil {
220203
c.services = *copts.services
221204
}
@@ -228,10 +211,15 @@ type Client struct {
228211
services
229212
connMu sync.Mutex
230213
conn *grpc.ClientConn
231-
runtime string
232214
defaultns string
233215
platform platforms.MatchComparer
234216
connector func() (*grpc.ClientConn, error)
217+
218+
// this should only be accessed via defaultRuntime()
219+
runtime struct {
220+
value string
221+
mut sync.Mutex
222+
}
235223
}
236224

237225
// Reconnect re-establishes the GRPC connection to the containerd daemon
@@ -252,7 +240,31 @@ func (c *Client) Reconnect() error {
252240

253241
// Runtime returns the name of the runtime being used
254242
func (c *Client) Runtime() string {
255-
return c.runtime
243+
runtime, _ := c.defaultRuntime(context.TODO())
244+
return runtime
245+
}
246+
247+
func (c *Client) defaultRuntime(ctx context.Context) (string, error) {
248+
c.runtime.mut.Lock()
249+
defer c.runtime.mut.Unlock()
250+
251+
if c.runtime.value != "" {
252+
return c.runtime.value, nil
253+
}
254+
255+
if c.defaultns != "" {
256+
label, err := c.GetLabel(ctx, defaults.DefaultRuntimeNSLabel)
257+
if err != nil {
258+
// Don't set the runtime value if there's an error
259+
return defaults.DefaultRuntime, fmt.Errorf("failed to get default runtime label: %w", err)
260+
}
261+
if label != "" {
262+
c.runtime.value = label
263+
return label, nil
264+
}
265+
}
266+
c.runtime.value = defaults.DefaultRuntime
267+
return c.runtime.value, nil
256268
}
257269

258270
// IsServing returns true if the client can successfully connect to the
@@ -299,10 +311,15 @@ func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContain
299311
}
300312
defer done(ctx)
301313

314+
runtime, err := c.defaultRuntime(ctx)
315+
if err != nil {
316+
return nil, err
317+
}
318+
302319
container := containers.Container{
303320
ID: id,
304321
Runtime: containers.RuntimeInfo{
305-
Name: c.runtime,
322+
Name: runtime,
306323
},
307324
}
308325
for _, o := range opts {
@@ -935,14 +952,16 @@ type RuntimeInfo struct {
935952
}
936953

937954
func (c *Client) RuntimeInfo(ctx context.Context, runtimePath string, runtimeOptions interface{}) (*RuntimeInfo, error) {
938-
rt := c.runtime
955+
runtime, err := c.defaultRuntime(ctx)
956+
if err != nil {
957+
return nil, err
958+
}
939959
if runtimePath != "" {
940-
rt = runtimePath
960+
runtime = runtimePath
941961
}
942962
rr := &apitypes.RuntimeRequest{
943-
RuntimePath: rt,
963+
RuntimePath: runtime,
944964
}
945-
var err error
946965
if runtimeOptions != nil {
947966
rr.Options, err = typeurl.MarshalAnyToProto(runtimeOptions)
948967
if err != nil {

client/task.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,15 @@ func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStat
373373
return nil, err
374374
}
375375

376+
runtime, err := t.client.defaultRuntime(ctx)
377+
if err != nil {
378+
return nil, fmt.Errorf("failed to get default runtime: %w", err)
379+
}
380+
376381
switch status.Status {
377382
case Stopped, Unknown, "":
378383
case Created:
379-
if t.client.runtime == plugins.RuntimePlugin.String()+".windows" {
384+
if runtime == plugins.RuntimePlugin.String()+".windows" {
380385
// On windows Created is akin to Stopped
381386
break
382387
}
@@ -393,7 +398,7 @@ func (t *task) Delete(ctx context.Context, opts ...ProcessDeleteOpts) (*ExitStat
393398
// io.Wait locks for restored tasks on Windows unless we call
394399
// io.Close first (https://github.com/containerd/containerd/issues/5621)
395400
// in other cases, preserve the contract and let IO finish before closing
396-
if t.client.runtime == plugins.RuntimePlugin.String()+".windows" {
401+
if runtime == plugins.RuntimePlugin.String()+".windows" {
397402
t.io.Close()
398403
}
399404
// io.Cancel is used to cancel the io goroutine while it is in

0 commit comments

Comments
 (0)