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