1/* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15*/ 16 17/* 18Copyright 2016 The Kubernetes Authors. 19 20Licensed under the Apache License, Version 2.0 (the "License"); 21you may not use this file except in compliance with the License. 22You may obtain a copy of the License at 23 24 http://www.apache.org/licenses/LICENSE-2.0 25 26Unless required by applicable law or agreed to in writing, software 27distributed under the License is distributed on an "AS IS" BASIS, 28WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 29See the License for the specific language governing permissions and 30limitations under the License. 31*/ 32 33package remote 34 35import ( 36 "context" 37 "errors" 38 "fmt" 39 "strings" 40 "time" 41 42 "google.golang.org/grpc" 43 "k8s.io/klog/v2" 44 45 "k8s.io/component-base/logs/logreduction" 46 internalapi "k8s.io/cri-api/pkg/apis" 47 runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" 48 utilexec "k8s.io/utils/exec" 49 50 "github.com/containerd/containerd/integration/remote/util" 51) 52 53// RuntimeService is a gRPC implementation of internalapi.RuntimeService. 54type RuntimeService struct { 55 timeout time.Duration 56 runtimeClient runtimeapi.RuntimeServiceClient 57 // Cache last per-container error message to reduce log spam 58 logReduction *logreduction.LogReduction 59} 60 61const ( 62 // How frequently to report identical errors 63 identicalErrorDelay = 1 * time.Minute 64) 65 66// NewRuntimeService creates a new internalapi.RuntimeService. 67func NewRuntimeService(endpoint string, connectionTimeout time.Duration) (internalapi.RuntimeService, error) { 68 klog.V(3).Infof("Connecting to runtime service %s", endpoint) 69 addr, dialer, err := util.GetAddressAndDialer(endpoint) 70 if err != nil { 71 return nil, err 72 } 73 ctx, cancel := context.WithTimeout(context.Background(), connectionTimeout) 74 defer cancel() 75 76 conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithContextDialer(dialer), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize))) 77 if err != nil { 78 klog.Errorf("Connect remote runtime %s failed: %v", addr, err) 79 return nil, err 80 } 81 82 return &RuntimeService{ 83 timeout: connectionTimeout, 84 runtimeClient: runtimeapi.NewRuntimeServiceClient(conn), 85 logReduction: logreduction.NewLogReduction(identicalErrorDelay), 86 }, nil 87} 88 89// Version returns the runtime name, runtime version and runtime API version. 90func (r *RuntimeService) Version(apiVersion string) (*runtimeapi.VersionResponse, error) { 91 klog.V(10).Infof("[RuntimeService] Version (apiVersion=%v, timeout=%v)", apiVersion, r.timeout) 92 93 ctx, cancel := getContextWithTimeout(r.timeout) 94 defer cancel() 95 96 typedVersion, err := r.runtimeClient.Version(ctx, &runtimeapi.VersionRequest{ 97 Version: apiVersion, 98 }) 99 if err != nil { 100 klog.Errorf("Version from runtime service failed: %v", err) 101 return nil, err 102 } 103 104 klog.V(10).Infof("[RuntimeService] Version Response (typedVersion=%v)", typedVersion) 105 106 if typedVersion.Version == "" || typedVersion.RuntimeName == "" || typedVersion.RuntimeApiVersion == "" || typedVersion.RuntimeVersion == "" { 107 return nil, fmt.Errorf("not all fields are set in VersionResponse (%q)", *typedVersion) 108 } 109 110 return typedVersion, err 111} 112 113// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure 114// the sandbox is in ready state. 115func (r *RuntimeService) RunPodSandbox(config *runtimeapi.PodSandboxConfig, runtimeHandler string) (string, error) { 116 // Use 2 times longer timeout for sandbox operation (4 mins by default) 117 // TODO: Make the pod sandbox timeout configurable. 118 timeout := r.timeout * 2 119 120 klog.V(10).Infof("[RuntimeService] RunPodSandbox (config=%v, runtimeHandler=%v, timeout=%v)", config, runtimeHandler, timeout) 121 122 ctx, cancel := getContextWithTimeout(timeout) 123 defer cancel() 124 125 resp, err := r.runtimeClient.RunPodSandbox(ctx, &runtimeapi.RunPodSandboxRequest{ 126 Config: config, 127 RuntimeHandler: runtimeHandler, 128 }) 129 if err != nil { 130 klog.Errorf("RunPodSandbox from runtime service failed: %v", err) 131 return "", err 132 } 133 134 if resp.PodSandboxId == "" { 135 errorMessage := fmt.Sprintf("PodSandboxId is not set for sandbox %q", config.GetMetadata()) 136 klog.Errorf("RunPodSandbox failed: %s", errorMessage) 137 return "", errors.New(errorMessage) 138 } 139 140 klog.V(10).Infof("[RuntimeService] RunPodSandbox Response (PodSandboxId=%v)", resp.PodSandboxId) 141 142 return resp.PodSandboxId, nil 143} 144 145// StopPodSandbox stops the sandbox. If there are any running containers in the 146// sandbox, they should be forced to termination. 147func (r *RuntimeService) StopPodSandbox(podSandBoxID string) error { 148 klog.V(10).Infof("[RuntimeService] StopPodSandbox (podSandboxID=%v, timeout=%v)", podSandBoxID, r.timeout) 149 150 ctx, cancel := getContextWithTimeout(r.timeout) 151 defer cancel() 152 153 _, err := r.runtimeClient.StopPodSandbox(ctx, &runtimeapi.StopPodSandboxRequest{ 154 PodSandboxId: podSandBoxID, 155 }) 156 if err != nil { 157 klog.Errorf("StopPodSandbox %q from runtime service failed: %v", podSandBoxID, err) 158 return err 159 } 160 161 klog.V(10).Infof("[RuntimeService] StopPodSandbox Response (podSandboxID=%v)", podSandBoxID) 162 163 return nil 164} 165 166// RemovePodSandbox removes the sandbox. If there are any containers in the 167// sandbox, they should be forcibly removed. 168func (r *RuntimeService) RemovePodSandbox(podSandBoxID string) error { 169 klog.V(10).Infof("[RuntimeService] RemovePodSandbox (podSandboxID=%v, timeout=%v)", podSandBoxID, r.timeout) 170 ctx, cancel := getContextWithTimeout(r.timeout) 171 defer cancel() 172 173 _, err := r.runtimeClient.RemovePodSandbox(ctx, &runtimeapi.RemovePodSandboxRequest{ 174 PodSandboxId: podSandBoxID, 175 }) 176 if err != nil { 177 klog.Errorf("RemovePodSandbox %q from runtime service failed: %v", podSandBoxID, err) 178 return err 179 } 180 181 klog.V(10).Infof("[RuntimeService] RemovePodSandbox Response (podSandboxID=%v)", podSandBoxID) 182 183 return nil 184} 185 186// PodSandboxStatus returns the status of the PodSandbox. 187func (r *RuntimeService) PodSandboxStatus(podSandBoxID string) (*runtimeapi.PodSandboxStatus, error) { 188 klog.V(10).Infof("[RuntimeService] PodSandboxStatus (podSandboxID=%v, timeout=%v)", podSandBoxID, r.timeout) 189 ctx, cancel := getContextWithTimeout(r.timeout) 190 defer cancel() 191 192 resp, err := r.runtimeClient.PodSandboxStatus(ctx, &runtimeapi.PodSandboxStatusRequest{ 193 PodSandboxId: podSandBoxID, 194 }) 195 if err != nil { 196 return nil, err 197 } 198 199 klog.V(10).Infof("[RuntimeService] PodSandboxStatus Response (podSandboxID=%v, status=%v)", podSandBoxID, resp.Status) 200 201 if resp.Status != nil { 202 if err := verifySandboxStatus(resp.Status); err != nil { 203 return nil, err 204 } 205 } 206 207 return resp.Status, nil 208} 209 210// ListPodSandbox returns a list of PodSandboxes. 211func (r *RuntimeService) ListPodSandbox(filter *runtimeapi.PodSandboxFilter) ([]*runtimeapi.PodSandbox, error) { 212 klog.V(10).Infof("[RuntimeService] ListPodSandbox (filter=%v, timeout=%v)", filter, r.timeout) 213 ctx, cancel := getContextWithTimeout(r.timeout) 214 defer cancel() 215 216 resp, err := r.runtimeClient.ListPodSandbox(ctx, &runtimeapi.ListPodSandboxRequest{ 217 Filter: filter, 218 }) 219 if err != nil { 220 klog.Errorf("ListPodSandbox with filter %+v from runtime service failed: %v", filter, err) 221 return nil, err 222 } 223 224 klog.V(10).Infof("[RuntimeService] ListPodSandbox Response (filter=%v, items=%v)", filter, resp.Items) 225 226 return resp.Items, nil 227} 228 229// CreateContainer creates a new container in the specified PodSandbox. 230func (r *RuntimeService) CreateContainer(podSandBoxID string, config *runtimeapi.ContainerConfig, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error) { 231 klog.V(10).Infof("[RuntimeService] CreateContainer (podSandBoxID=%v, timeout=%v)", podSandBoxID, r.timeout) 232 ctx, cancel := getContextWithTimeout(r.timeout) 233 defer cancel() 234 235 resp, err := r.runtimeClient.CreateContainer(ctx, &runtimeapi.CreateContainerRequest{ 236 PodSandboxId: podSandBoxID, 237 Config: config, 238 SandboxConfig: sandboxConfig, 239 }) 240 if err != nil { 241 klog.Errorf("CreateContainer in sandbox %q from runtime service failed: %v", podSandBoxID, err) 242 return "", err 243 } 244 245 klog.V(10).Infof("[RuntimeService] CreateContainer (podSandBoxID=%v, ContainerId=%v)", podSandBoxID, resp.ContainerId) 246 if resp.ContainerId == "" { 247 errorMessage := fmt.Sprintf("ContainerId is not set for container %q", config.GetMetadata()) 248 klog.Errorf("CreateContainer failed: %s", errorMessage) 249 return "", errors.New(errorMessage) 250 } 251 252 return resp.ContainerId, nil 253} 254 255// StartContainer starts the container. 256func (r *RuntimeService) StartContainer(containerID string) error { 257 klog.V(10).Infof("[RuntimeService] StartContainer (containerID=%v, timeout=%v)", containerID, r.timeout) 258 ctx, cancel := getContextWithTimeout(r.timeout) 259 defer cancel() 260 261 _, err := r.runtimeClient.StartContainer(ctx, &runtimeapi.StartContainerRequest{ 262 ContainerId: containerID, 263 }) 264 if err != nil { 265 klog.Errorf("StartContainer %q from runtime service failed: %v", containerID, err) 266 return err 267 } 268 klog.V(10).Infof("[RuntimeService] StartContainer Response (containerID=%v)", containerID) 269 270 return nil 271} 272 273// StopContainer stops a running container with a grace period (i.e., timeout). 274func (r *RuntimeService) StopContainer(containerID string, timeout int64) error { 275 klog.V(10).Infof("[RuntimeService] StopContainer (containerID=%v, timeout=%v)", containerID, timeout) 276 // Use timeout + default timeout (2 minutes) as timeout to leave extra time 277 // for SIGKILL container and request latency. 278 t := r.timeout + time.Duration(timeout)*time.Second 279 ctx, cancel := getContextWithTimeout(t) 280 defer cancel() 281 282 r.logReduction.ClearID(containerID) 283 _, err := r.runtimeClient.StopContainer(ctx, &runtimeapi.StopContainerRequest{ 284 ContainerId: containerID, 285 Timeout: timeout, 286 }) 287 if err != nil { 288 klog.Errorf("StopContainer %q from runtime service failed: %v", containerID, err) 289 return err 290 } 291 klog.V(10).Infof("[RuntimeService] StopContainer Response (containerID=%v)", containerID) 292 293 return nil 294} 295 296// RemoveContainer removes the container. If the container is running, the container 297// should be forced to removal. 298func (r *RuntimeService) RemoveContainer(containerID string) error { 299 klog.V(10).Infof("[RuntimeService] RemoveContainer (containerID=%v, timeout=%v)", containerID, r.timeout) 300 ctx, cancel := getContextWithTimeout(r.timeout) 301 defer cancel() 302 303 r.logReduction.ClearID(containerID) 304 _, err := r.runtimeClient.RemoveContainer(ctx, &runtimeapi.RemoveContainerRequest{ 305 ContainerId: containerID, 306 }) 307 if err != nil { 308 klog.Errorf("RemoveContainer %q from runtime service failed: %v", containerID, err) 309 return err 310 } 311 klog.V(10).Infof("[RuntimeService] RemoveContainer Response (containerID=%v)", containerID) 312 313 return nil 314} 315 316// ListContainers lists containers by filters. 317func (r *RuntimeService) ListContainers(filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error) { 318 klog.V(10).Infof("[RuntimeService] ListContainers (filter=%v, timeout=%v)", filter, r.timeout) 319 ctx, cancel := getContextWithTimeout(r.timeout) 320 defer cancel() 321 322 resp, err := r.runtimeClient.ListContainers(ctx, &runtimeapi.ListContainersRequest{ 323 Filter: filter, 324 }) 325 if err != nil { 326 klog.Errorf("ListContainers with filter %+v from runtime service failed: %v", filter, err) 327 return nil, err 328 } 329 klog.V(10).Infof("[RuntimeService] ListContainers Response (filter=%v, containers=%v)", filter, resp.Containers) 330 331 return resp.Containers, nil 332} 333 334// ContainerStatus returns the container status. 335func (r *RuntimeService) ContainerStatus(containerID string) (*runtimeapi.ContainerStatus, error) { 336 klog.V(10).Infof("[RuntimeService] ContainerStatus (containerID=%v, timeout=%v)", containerID, r.timeout) 337 ctx, cancel := getContextWithTimeout(r.timeout) 338 defer cancel() 339 340 resp, err := r.runtimeClient.ContainerStatus(ctx, &runtimeapi.ContainerStatusRequest{ 341 ContainerId: containerID, 342 }) 343 if err != nil { 344 // Don't spam the log with endless messages about the same failure. 345 if r.logReduction.ShouldMessageBePrinted(err.Error(), containerID) { 346 klog.Errorf("ContainerStatus %q from runtime service failed: %v", containerID, err) 347 } 348 return nil, err 349 } 350 r.logReduction.ClearID(containerID) 351 klog.V(10).Infof("[RuntimeService] ContainerStatus Response (containerID=%v, status=%v)", containerID, resp.Status) 352 353 if resp.Status != nil { 354 if err := verifyContainerStatus(resp.Status); err != nil { 355 klog.Errorf("ContainerStatus of %q failed: %v", containerID, err) 356 return nil, err 357 } 358 } 359 360 return resp.Status, nil 361} 362 363// UpdateContainerResources updates a containers resource config 364func (r *RuntimeService) UpdateContainerResources(containerID string, resources *runtimeapi.LinuxContainerResources) error { 365 klog.V(10).Infof("[RuntimeService] UpdateContainerResources (containerID=%v, timeout=%v)", containerID, r.timeout) 366 ctx, cancel := getContextWithTimeout(r.timeout) 367 defer cancel() 368 369 _, err := r.runtimeClient.UpdateContainerResources(ctx, &runtimeapi.UpdateContainerResourcesRequest{ 370 ContainerId: containerID, 371 Linux: resources, 372 }) 373 if err != nil { 374 klog.Errorf("UpdateContainerResources %q from runtime service failed: %v", containerID, err) 375 return err 376 } 377 klog.V(10).Infof("[RuntimeService] UpdateContainerResources Response (containerID=%v)", containerID) 378 379 return nil 380} 381 382// ExecSync executes a command in the container, and returns the stdout output. 383// If command exits with a non-zero exit code, an error is returned. 384func (r *RuntimeService) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) { 385 klog.V(10).Infof("[RuntimeService] ExecSync (containerID=%v, timeout=%v)", containerID, timeout) 386 // Do not set timeout when timeout is 0. 387 var ctx context.Context 388 var cancel context.CancelFunc 389 if timeout != 0 { 390 // Use timeout + default timeout (2 minutes) as timeout to leave some time for 391 // the runtime to do cleanup. 392 ctx, cancel = getContextWithTimeout(r.timeout + timeout) 393 } else { 394 ctx, cancel = getContextWithCancel() 395 } 396 defer cancel() 397 398 timeoutSeconds := int64(timeout.Seconds()) 399 req := &runtimeapi.ExecSyncRequest{ 400 ContainerId: containerID, 401 Cmd: cmd, 402 Timeout: timeoutSeconds, 403 } 404 resp, err := r.runtimeClient.ExecSync(ctx, req) 405 if err != nil { 406 klog.Errorf("ExecSync %s '%s' from runtime service failed: %v", containerID, strings.Join(cmd, " "), err) 407 return nil, nil, err 408 } 409 410 klog.V(10).Infof("[RuntimeService] ExecSync Response (containerID=%v, ExitCode=%v)", containerID, resp.ExitCode) 411 err = nil 412 if resp.ExitCode != 0 { 413 err = utilexec.CodeExitError{ 414 Err: fmt.Errorf("command '%s' exited with %d: %s", strings.Join(cmd, " "), resp.ExitCode, resp.Stderr), 415 Code: int(resp.ExitCode), 416 } 417 } 418 419 return resp.Stdout, resp.Stderr, err 420} 421 422// Exec prepares a streaming endpoint to execute a command in the container, and returns the address. 423func (r *RuntimeService) Exec(req *runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) { 424 klog.V(10).Infof("[RuntimeService] Exec (timeout=%v)", r.timeout) 425 ctx, cancel := getContextWithTimeout(r.timeout) 426 defer cancel() 427 428 resp, err := r.runtimeClient.Exec(ctx, req) 429 if err != nil { 430 klog.Errorf("Exec %s '%s' from runtime service failed: %v", req.ContainerId, strings.Join(req.Cmd, " "), err) 431 return nil, err 432 } 433 klog.V(10).Info("[RuntimeService] Exec Response") 434 435 if resp.Url == "" { 436 errorMessage := "URL is not set" 437 klog.Errorf("Exec failed: %s", errorMessage) 438 return nil, errors.New(errorMessage) 439 } 440 441 return resp, nil 442} 443 444// Attach prepares a streaming endpoint to attach to a running container, and returns the address. 445func (r *RuntimeService) Attach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) { 446 klog.V(10).Infof("[RuntimeService] Attach (containerId=%v, timeout=%v)", req.ContainerId, r.timeout) 447 ctx, cancel := getContextWithTimeout(r.timeout) 448 defer cancel() 449 450 resp, err := r.runtimeClient.Attach(ctx, req) 451 if err != nil { 452 klog.Errorf("Attach %s from runtime service failed: %v", req.ContainerId, err) 453 return nil, err 454 } 455 klog.V(10).Infof("[RuntimeService] Attach Response (containerId=%v)", req.ContainerId) 456 457 if resp.Url == "" { 458 errorMessage := "URL is not set" 459 klog.Errorf("Attach failed: %s", errorMessage) 460 return nil, errors.New(errorMessage) 461 } 462 return resp, nil 463} 464 465// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address. 466func (r *RuntimeService) PortForward(req *runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) { 467 klog.V(10).Infof("[RuntimeService] PortForward (podSandboxID=%v, port=%v, timeout=%v)", req.PodSandboxId, req.Port, r.timeout) 468 ctx, cancel := getContextWithTimeout(r.timeout) 469 defer cancel() 470 471 resp, err := r.runtimeClient.PortForward(ctx, req) 472 if err != nil { 473 klog.Errorf("PortForward %s from runtime service failed: %v", req.PodSandboxId, err) 474 return nil, err 475 } 476 klog.V(10).Infof("[RuntimeService] PortForward Response (podSandboxID=%v)", req.PodSandboxId) 477 478 if resp.Url == "" { 479 errorMessage := "URL is not set" 480 klog.Errorf("PortForward failed: %s", errorMessage) 481 return nil, errors.New(errorMessage) 482 } 483 484 return resp, nil 485} 486 487// UpdateRuntimeConfig updates the config of a runtime service. The only 488// update payload currently supported is the pod CIDR assigned to a node, 489// and the runtime service just proxies it down to the network plugin. 490func (r *RuntimeService) UpdateRuntimeConfig(runtimeConfig *runtimeapi.RuntimeConfig) error { 491 klog.V(10).Infof("[RuntimeService] UpdateRuntimeConfig (runtimeConfig=%v, timeout=%v)", runtimeConfig, r.timeout) 492 ctx, cancel := getContextWithTimeout(r.timeout) 493 defer cancel() 494 495 // Response doesn't contain anything of interest. This translates to an 496 // Event notification to the network plugin, which can't fail, so we're 497 // really looking to surface destination unreachable. 498 _, err := r.runtimeClient.UpdateRuntimeConfig(ctx, &runtimeapi.UpdateRuntimeConfigRequest{ 499 RuntimeConfig: runtimeConfig, 500 }) 501 502 if err != nil { 503 return err 504 } 505 klog.V(10).Infof("[RuntimeService] UpdateRuntimeConfig Response (runtimeConfig=%v)", runtimeConfig) 506 507 return nil 508} 509 510// Status returns the status of the runtime. 511func (r *RuntimeService) Status() (*runtimeapi.RuntimeStatus, error) { 512 klog.V(10).Infof("[RuntimeService] Status (timeout=%v)", r.timeout) 513 ctx, cancel := getContextWithTimeout(r.timeout) 514 defer cancel() 515 516 resp, err := r.runtimeClient.Status(ctx, &runtimeapi.StatusRequest{}) 517 if err != nil { 518 klog.Errorf("Status from runtime service failed: %v", err) 519 return nil, err 520 } 521 522 klog.V(10).Infof("[RuntimeService] Status Response (status=%v)", resp.Status) 523 524 if resp.Status == nil || len(resp.Status.Conditions) < 2 { 525 errorMessage := "RuntimeReady or NetworkReady condition are not set" 526 klog.Errorf("Status failed: %s", errorMessage) 527 return nil, errors.New(errorMessage) 528 } 529 530 return resp.Status, nil 531} 532 533// ContainerStats returns the stats of the container. 534func (r *RuntimeService) ContainerStats(containerID string) (*runtimeapi.ContainerStats, error) { 535 klog.V(10).Infof("[RuntimeService] ContainerStats (containerID=%v, timeout=%v)", containerID, r.timeout) 536 ctx, cancel := getContextWithTimeout(r.timeout) 537 defer cancel() 538 539 resp, err := r.runtimeClient.ContainerStats(ctx, &runtimeapi.ContainerStatsRequest{ 540 ContainerId: containerID, 541 }) 542 if err != nil { 543 if r.logReduction.ShouldMessageBePrinted(err.Error(), containerID) { 544 klog.Errorf("ContainerStats %q from runtime service failed: %v", containerID, err) 545 } 546 return nil, err 547 } 548 r.logReduction.ClearID(containerID) 549 klog.V(10).Infof("[RuntimeService] ContainerStats Response (containerID=%v, stats=%v)", containerID, resp.GetStats()) 550 551 return resp.GetStats(), nil 552} 553 554// ListContainerStats lists all container stats given the provided filter 555func (r *RuntimeService) ListContainerStats(filter *runtimeapi.ContainerStatsFilter) ([]*runtimeapi.ContainerStats, error) { 556 klog.V(10).Infof("[RuntimeService] ListContainerStats (filter=%v)", filter) 557 // Do not set timeout, because writable layer stats collection takes time. 558 // TODO(random-liu): Should we assume runtime should cache the result, and set timeout here? 559 ctx, cancel := getContextWithCancel() 560 defer cancel() 561 562 resp, err := r.runtimeClient.ListContainerStats(ctx, &runtimeapi.ListContainerStatsRequest{ 563 Filter: filter, 564 }) 565 if err != nil { 566 klog.Errorf("ListContainerStats with filter %+v from runtime service failed: %v", filter, err) 567 return nil, err 568 } 569 klog.V(10).Infof("[RuntimeService] ListContainerStats Response (filter=%v, stats=%v)", filter, resp.GetStats()) 570 571 return resp.GetStats(), nil 572} 573 574// ReopenContainerLog reopens the container log for the given container ID 575func (r *RuntimeService) ReopenContainerLog(containerID string) error { 576 klog.V(10).Infof("[RuntimeService] ReopenContainerLog (containerID=%v, timeout=%v)", containerID, r.timeout) 577 ctx, cancel := getContextWithTimeout(r.timeout) 578 defer cancel() 579 580 _, err := r.runtimeClient.ReopenContainerLog(ctx, &runtimeapi.ReopenContainerLogRequest{ContainerId: containerID}) 581 if err != nil { 582 klog.Errorf("ReopenContainerLog %q from runtime service failed: %v", containerID, err) 583 return err 584 } 585 586 klog.V(10).Infof("[RuntimeService] ReopenContainerLog Response (containerID=%v)", containerID) 587 return nil 588} 589