mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Implement streaming CRI methods in dockershim
This commit is contained in:
		@@ -17,7 +17,7 @@ limitations under the License.
 | 
				
			|||||||
package api
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"io"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
						runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -43,8 +43,13 @@ type ContainerManager interface {
 | 
				
			|||||||
	ListContainers(filter *runtimeApi.ContainerFilter) ([]*runtimeApi.Container, error)
 | 
						ListContainers(filter *runtimeApi.ContainerFilter) ([]*runtimeApi.Container, error)
 | 
				
			||||||
	// ContainerStatus returns the status of the container.
 | 
						// ContainerStatus returns the status of the container.
 | 
				
			||||||
	ContainerStatus(containerID string) (*runtimeApi.ContainerStatus, error)
 | 
						ContainerStatus(containerID string) (*runtimeApi.ContainerStatus, error)
 | 
				
			||||||
	// Exec executes a command in the container.
 | 
						// ExecSync executes a command in the container, and returns the stdout output.
 | 
				
			||||||
	Exec(containerID string, cmd []string, tty bool, stdin io.Reader, stdout, stderr io.WriteCloser) error
 | 
						// If command exits with a non-zero exit code, an error is returned.
 | 
				
			||||||
 | 
						ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error)
 | 
				
			||||||
 | 
						// Exec prepares a streaming endpoint to execute a command in the container, and returns the address.
 | 
				
			||||||
 | 
						Exec(*runtimeApi.ExecRequest) (*runtimeApi.ExecResponse, error)
 | 
				
			||||||
 | 
						// Attach prepares a streaming endpoint to attach to a running container, and returns the address.
 | 
				
			||||||
 | 
						Attach(req *runtimeApi.AttachRequest) (*runtimeApi.AttachResponse, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// PodSandboxManager contains methods for operating on PodSandboxes. The methods
 | 
					// PodSandboxManager contains methods for operating on PodSandboxes. The methods
 | 
				
			||||||
@@ -63,6 +68,8 @@ type PodSandboxManager interface {
 | 
				
			|||||||
	PodSandboxStatus(podSandboxID string) (*runtimeApi.PodSandboxStatus, error)
 | 
						PodSandboxStatus(podSandboxID string) (*runtimeApi.PodSandboxStatus, error)
 | 
				
			||||||
	// ListPodSandbox returns a list of Sandbox.
 | 
						// ListPodSandbox returns a list of Sandbox.
 | 
				
			||||||
	ListPodSandbox(filter *runtimeApi.PodSandboxFilter) ([]*runtimeApi.PodSandbox, error)
 | 
						ListPodSandbox(filter *runtimeApi.PodSandboxFilter) ([]*runtimeApi.PodSandbox, error)
 | 
				
			||||||
 | 
						// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address.
 | 
				
			||||||
 | 
						PortForward(*runtimeApi.PortForwardRequest) (*runtimeApi.PortForwardResponse, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RuntimeService interface should be implemented by a container runtime.
 | 
					// RuntimeService interface should be implemented by a container runtime.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ package testing
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -214,6 +213,14 @@ func (r *FakeRuntimeService) ListPodSandbox(filter *runtimeApi.PodSandboxFilter)
 | 
				
			|||||||
	return result, nil
 | 
						return result, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *FakeRuntimeService) PortForward(*runtimeApi.PortForwardRequest) (*runtimeApi.PortForwardResponse, error) {
 | 
				
			||||||
 | 
						r.Lock()
 | 
				
			||||||
 | 
						defer r.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r.Called = append(r.Called, "PortForward")
 | 
				
			||||||
 | 
						return &runtimeApi.PortForwardResponse{}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *FakeRuntimeService) CreateContainer(podSandboxID string, config *runtimeApi.ContainerConfig, sandboxConfig *runtimeApi.PodSandboxConfig) (string, error) {
 | 
					func (r *FakeRuntimeService) CreateContainer(podSandboxID string, config *runtimeApi.ContainerConfig, sandboxConfig *runtimeApi.PodSandboxConfig) (string, error) {
 | 
				
			||||||
	r.Lock()
 | 
						r.Lock()
 | 
				
			||||||
	defer r.Unlock()
 | 
						defer r.Unlock()
 | 
				
			||||||
@@ -349,12 +356,28 @@ func (r *FakeRuntimeService) ContainerStatus(containerID string) (*runtimeApi.Co
 | 
				
			|||||||
	return &status, nil
 | 
						return &status, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *FakeRuntimeService) Exec(containerID string, cmd []string, tty bool, stdin io.Reader, stdout, stderr io.WriteCloser) error {
 | 
					func (r *FakeRuntimeService) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) {
 | 
				
			||||||
 | 
						r.Lock()
 | 
				
			||||||
 | 
						defer r.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r.Called = append(r.Called, "ExecSync")
 | 
				
			||||||
 | 
						return nil, nil, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *FakeRuntimeService) Exec(*runtimeApi.ExecRequest) (*runtimeApi.ExecResponse, error) {
 | 
				
			||||||
	r.Lock()
 | 
						r.Lock()
 | 
				
			||||||
	defer r.Unlock()
 | 
						defer r.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r.Called = append(r.Called, "Exec")
 | 
						r.Called = append(r.Called, "Exec")
 | 
				
			||||||
	return nil
 | 
						return &runtimeApi.ExecResponse{}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *FakeRuntimeService) Attach(req *runtimeApi.AttachRequest) (*runtimeApi.AttachResponse, error) {
 | 
				
			||||||
 | 
						r.Lock()
 | 
				
			||||||
 | 
						defer r.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r.Called = append(r.Called, "Attach")
 | 
				
			||||||
 | 
						return &runtimeApi.AttachResponse{}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *FakeRuntimeService) UpdateRuntimeConfig(runtimeCOnfig *runtimeApi.RuntimeConfig) error {
 | 
					func (r *FakeRuntimeService) UpdateRuntimeConfig(runtimeCOnfig *runtimeApi.RuntimeConfig) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ go_library(
 | 
				
			|||||||
        "docker_image.go",
 | 
					        "docker_image.go",
 | 
				
			||||||
        "docker_sandbox.go",
 | 
					        "docker_sandbox.go",
 | 
				
			||||||
        "docker_service.go",
 | 
					        "docker_service.go",
 | 
				
			||||||
 | 
					        "docker_streaming.go",
 | 
				
			||||||
        "helpers.go",
 | 
					        "helpers.go",
 | 
				
			||||||
        "legacy.go",
 | 
					        "legacy.go",
 | 
				
			||||||
        "naming.go",
 | 
					        "naming.go",
 | 
				
			||||||
@@ -32,7 +33,9 @@ go_library(
 | 
				
			|||||||
        "//pkg/kubelet/dockertools:go_default_library",
 | 
					        "//pkg/kubelet/dockertools:go_default_library",
 | 
				
			||||||
        "//pkg/kubelet/leaky:go_default_library",
 | 
					        "//pkg/kubelet/leaky:go_default_library",
 | 
				
			||||||
        "//pkg/kubelet/qos:go_default_library",
 | 
					        "//pkg/kubelet/qos:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/kubelet/server/streaming:go_default_library",
 | 
				
			||||||
        "//pkg/kubelet/types:go_default_library",
 | 
					        "//pkg/kubelet/types:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/kubelet/util/ioutils:go_default_library",
 | 
				
			||||||
        "//pkg/util/term:go_default_library",
 | 
					        "//pkg/util/term:go_default_library",
 | 
				
			||||||
        "//vendor:github.com/docker/engine-api/types",
 | 
					        "//vendor:github.com/docker/engine-api/types",
 | 
				
			||||||
        "//vendor:github.com/docker/engine-api/types/container",
 | 
					        "//vendor:github.com/docker/engine-api/types/container",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,6 @@ package dockershim
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -388,10 +387,3 @@ func (ds *dockerService) ContainerStatus(containerID string) (*runtimeApi.Contai
 | 
				
			|||||||
		Annotations: annotations,
 | 
							Annotations: annotations,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// Exec execute a command in the container.
 | 
					 | 
				
			||||||
// TODO: Need to handle terminal resizing before implementing this function.
 | 
					 | 
				
			||||||
// https://github.com/kubernetes/kubernetes/issues/29579.
 | 
					 | 
				
			||||||
func (ds *dockerService) Exec(containerID string, cmd []string, tty bool, stdin io.Reader, stdout, stderr io.WriteCloser) error {
 | 
					 | 
				
			||||||
	return fmt.Errorf("not implemented")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ import (
 | 
				
			|||||||
	runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
						runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
				
			||||||
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
						kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/kubelet/dockertools"
 | 
						"k8s.io/kubernetes/pkg/kubelet/dockertools"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/kubelet/server/streaming"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/term"
 | 
						"k8s.io/kubernetes/pkg/util/term"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,13 +56,27 @@ const (
 | 
				
			|||||||
var internalLabelKeys []string = []string{containerTypeLabelKey, containerLogPathLabelKey, sandboxIDLabelKey}
 | 
					var internalLabelKeys []string = []string{containerTypeLabelKey, containerLogPathLabelKey, sandboxIDLabelKey}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
 | 
					// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
 | 
				
			||||||
func NewDockerService(client dockertools.DockerInterface, seccompProfileRoot string, podSandboxImage string) DockerService {
 | 
					func NewDockerService(client dockertools.DockerInterface, seccompProfileRoot string, podSandboxImage string, streamingConfig *streaming.Config) (DockerService, error) {
 | 
				
			||||||
	return &dockerService{
 | 
						ds := &dockerService{
 | 
				
			||||||
		seccompProfileRoot: seccompProfileRoot,
 | 
							seccompProfileRoot: seccompProfileRoot,
 | 
				
			||||||
		client:             dockertools.NewInstrumentedDockerInterface(client),
 | 
							client:             dockertools.NewInstrumentedDockerInterface(client),
 | 
				
			||||||
		os:                 kubecontainer.RealOS{},
 | 
							os:                 kubecontainer.RealOS{},
 | 
				
			||||||
		podSandboxImage:    podSandboxImage,
 | 
							podSandboxImage:    podSandboxImage,
 | 
				
			||||||
 | 
							streamingRuntime: &streamingRuntime{
 | 
				
			||||||
 | 
								client: client,
 | 
				
			||||||
 | 
								// Only the native exec handling is supported for now.
 | 
				
			||||||
 | 
								// TODO(#35747) - Either deprecate nsenter exec handling, or add support for it here.
 | 
				
			||||||
 | 
								execHandler: &dockertools.NativeExecHandler{},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if streamingConfig != nil {
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
							ds.streamingServer, err = streaming.NewServer(*streamingConfig, ds.streamingRuntime)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ds, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DockerService is an interface that embeds both the new RuntimeService and
 | 
					// DockerService is an interface that embeds both the new RuntimeService and
 | 
				
			||||||
@@ -78,11 +93,9 @@ type DockerService interface {
 | 
				
			|||||||
type DockerLegacyService interface {
 | 
					type DockerLegacyService interface {
 | 
				
			||||||
	// Supporting legacy methods for docker.
 | 
						// Supporting legacy methods for docker.
 | 
				
			||||||
	GetContainerLogs(pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error)
 | 
						GetContainerLogs(pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error)
 | 
				
			||||||
	kubecontainer.ContainerAttacher
 | 
						LegacyExec(containerID kubecontainer.ContainerID, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error
 | 
				
			||||||
	PortForward(sandboxID string, port uint16, stream io.ReadWriteCloser) error
 | 
						LegacyAttach(id kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error
 | 
				
			||||||
 | 
						LegacyPortForward(sandboxID string, port uint16, stream io.ReadWriteCloser) error
 | 
				
			||||||
	// TODO: Remove this once exec is properly defined in CRI.
 | 
					 | 
				
			||||||
	ExecInContainer(containerID kubecontainer.ContainerID, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type dockerService struct {
 | 
					type dockerService struct {
 | 
				
			||||||
@@ -90,6 +103,8 @@ type dockerService struct {
 | 
				
			|||||||
	client             dockertools.DockerInterface
 | 
						client             dockertools.DockerInterface
 | 
				
			||||||
	os                 kubecontainer.OSInterface
 | 
						os                 kubecontainer.OSInterface
 | 
				
			||||||
	podSandboxImage    string
 | 
						podSandboxImage    string
 | 
				
			||||||
 | 
						streamingRuntime   *streamingRuntime
 | 
				
			||||||
 | 
						streamingServer    streaming.Server
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Version returns the runtime name, runtime version and runtime API version
 | 
					// Version returns the runtime name, runtime version and runtime API version
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										149
									
								
								pkg/kubelet/dockershim/docker_streaming.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								pkg/kubelet/dockershim/docker_streaming.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2016 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dockershim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dockertypes "github.com/docker/engine-api/types"
 | 
				
			||||||
 | 
						runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/kubelet/dockertools"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/kubelet/server/streaming"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/kubelet/util/ioutils"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/util/term"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type streamingRuntime struct {
 | 
				
			||||||
 | 
						client      dockertools.DockerInterface
 | 
				
			||||||
 | 
						execHandler dockertools.ExecHandler
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ streaming.Runtime = &streamingRuntime{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *streamingRuntime) Exec(containerID string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan term.Size) error {
 | 
				
			||||||
 | 
						return r.exec(containerID, cmd, in, out, err, tty, resize, 0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Internal version of Exec adds a timeout.
 | 
				
			||||||
 | 
					func (r *streamingRuntime) exec(containerID string, cmd []string, in io.Reader, out, errw io.WriteCloser, tty bool, resize <-chan term.Size, timeout time.Duration) error {
 | 
				
			||||||
 | 
						container, err := checkContainerStatus(r.client, containerID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO(timstclair): Clean this up once PR#33366 merges.
 | 
				
			||||||
 | 
						if timeout <= 0 {
 | 
				
			||||||
 | 
							// Run until command exits.
 | 
				
			||||||
 | 
							return r.execHandler.ExecInContainer(r.client, container, cmd, in, out, errw, tty, resize)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						errCh := make(chan error)
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							errCh <- r.execHandler.ExecInContainer(r.client, container, cmd, in, out, errw, tty, resize)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						select {
 | 
				
			||||||
 | 
						case err := <-errCh:
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						case <-time.After(timeout):
 | 
				
			||||||
 | 
							return streaming.ErrorTimeout("exec", timeout)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *streamingRuntime) Attach(containerID string, in io.Reader, out, errw io.WriteCloser, resize <-chan term.Size) error {
 | 
				
			||||||
 | 
						container, err := checkContainerStatus(r.client, containerID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tty := container.Config.Tty
 | 
				
			||||||
 | 
						return dockertools.AttachContainer(r.client, containerID, in, out, errw, tty, resize)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *streamingRuntime) PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error {
 | 
				
			||||||
 | 
						if port < 0 || port > math.MaxUint16 {
 | 
				
			||||||
 | 
							return fmt.Errorf("invalid port %d", port)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return dockertools.PortForward(r.client, podSandboxID, uint16(port), stream)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ExecSync executes a command in the container, and returns the stdout output.
 | 
				
			||||||
 | 
					// If command exits with a non-zero exit code, an error is returned.
 | 
				
			||||||
 | 
					func (ds *dockerService) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) {
 | 
				
			||||||
 | 
						var stdoutBuffer, stderrBuffer bytes.Buffer
 | 
				
			||||||
 | 
						err = ds.streamingRuntime.exec(containerID, cmd,
 | 
				
			||||||
 | 
							nil, // in
 | 
				
			||||||
 | 
							ioutils.WriteCloserWrapper(&stdoutBuffer),
 | 
				
			||||||
 | 
							ioutils.WriteCloserWrapper(&stderrBuffer),
 | 
				
			||||||
 | 
							false, // tty
 | 
				
			||||||
 | 
							nil,   // resize
 | 
				
			||||||
 | 
							timeout)
 | 
				
			||||||
 | 
						return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Exec prepares a streaming endpoint to execute a command in the container, and returns the address.
 | 
				
			||||||
 | 
					func (ds *dockerService) Exec(req *runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) {
 | 
				
			||||||
 | 
						if ds.streamingServer == nil {
 | 
				
			||||||
 | 
							return nil, streaming.ErrorStreamingDisabled("exec")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err := checkContainerStatus(ds.client, req.GetContainerId())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ds.streamingServer.GetExec(req)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Attach prepares a streaming endpoint to attach to a running container, and returns the address.
 | 
				
			||||||
 | 
					func (ds *dockerService) Attach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) {
 | 
				
			||||||
 | 
						if ds.streamingServer == nil {
 | 
				
			||||||
 | 
							return nil, streaming.ErrorStreamingDisabled("attach")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						container, err := checkContainerStatus(ds.client, req.GetContainerId())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tty := container.Config.Tty
 | 
				
			||||||
 | 
						return ds.streamingServer.GetAttach(req, tty)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address.
 | 
				
			||||||
 | 
					func (ds *dockerService) PortForward(req *runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) {
 | 
				
			||||||
 | 
						if ds.streamingServer == nil {
 | 
				
			||||||
 | 
							return nil, streaming.ErrorStreamingDisabled("port forward")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err := checkContainerStatus(ds.client, req.GetPodSandboxId())
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// TODO(timstclair): Verify that ports are exposed.
 | 
				
			||||||
 | 
						return ds.streamingServer.GetPortForward(req)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func checkContainerStatus(client dockertools.DockerInterface, containerID string) (*dockertypes.ContainerJSON, error) {
 | 
				
			||||||
 | 
						container, err := client.InspectContainer(containerID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !container.State.Running {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("container not running (%s)", container.ID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return container, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -17,7 +17,6 @@ limitations under the License.
 | 
				
			|||||||
package dockershim
 | 
					package dockershim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
@@ -31,8 +30,8 @@ import (
 | 
				
			|||||||
// directly.
 | 
					// directly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: implement the methods in this file.
 | 
					// TODO: implement the methods in this file.
 | 
				
			||||||
func (ds *dockerService) AttachContainer(id kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) (err error) {
 | 
					func (ds *dockerService) LegacyAttach(id kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) (err error) {
 | 
				
			||||||
	return dockertools.AttachContainer(ds.client, id, stdin, stdout, stderr, tty, resize)
 | 
						return ds.streamingRuntime.Attach(id.ID, stdin, stdout, stderr, resize)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ds *dockerService) GetContainerLogs(pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error) {
 | 
					func (ds *dockerService) GetContainerLogs(pod *api.Pod, containerID kubecontainer.ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error) {
 | 
				
			||||||
@@ -43,19 +42,10 @@ func (ds *dockerService) GetContainerLogs(pod *api.Pod, containerID kubecontaine
 | 
				
			|||||||
	return dockertools.GetContainerLogs(ds.client, pod, containerID, logOptions, stdout, stderr, container.Config.Tty)
 | 
						return dockertools.GetContainerLogs(ds.client, pod, containerID, logOptions, stdout, stderr, container.Config.Tty)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ds *dockerService) PortForward(sandboxID string, port uint16, stream io.ReadWriteCloser) error {
 | 
					func (ds *dockerService) LegacyPortForward(sandboxID string, port uint16, stream io.ReadWriteCloser) error {
 | 
				
			||||||
	return dockertools.PortForward(ds.client, sandboxID, port, stream)
 | 
						return ds.streamingRuntime.PortForward(sandboxID, int32(port), stream)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ds *dockerService) ExecInContainer(containerID kubecontainer.ContainerID, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
 | 
					func (ds *dockerService) LegacyExec(containerID kubecontainer.ContainerID, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
 | 
				
			||||||
	container, err := ds.client.InspectContainer(containerID.ID)
 | 
						return ds.streamingRuntime.Exec(containerID.ID, cmd, stdin, stdout, stderr, tty, resize)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !container.State.Running {
 | 
					 | 
				
			||||||
		return fmt.Errorf("container not running (%s)", container.ID)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	handler := &dockertools.NativeExecHandler{}
 | 
					 | 
				
			||||||
	return handler.ExecInContainer(ds.client, container, cmd, stdin, stdout, stderr, tty, resize)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1269,16 +1269,16 @@ func (dm *DockerManager) ExecInContainer(containerID kubecontainer.ContainerID,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (dm *DockerManager) AttachContainer(containerID kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
 | 
					func (dm *DockerManager) AttachContainer(containerID kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
 | 
				
			||||||
	return AttachContainer(dm.client, containerID, stdin, stdout, stderr, tty, resize)
 | 
						return AttachContainer(dm.client, containerID.ID, stdin, stdout, stderr, tty, resize)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Temporarily export this function to share with dockershim.
 | 
					// Temporarily export this function to share with dockershim.
 | 
				
			||||||
// TODO: clean this up.
 | 
					// TODO: clean this up.
 | 
				
			||||||
func AttachContainer(client DockerInterface, containerID kubecontainer.ContainerID, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
 | 
					func AttachContainer(client DockerInterface, containerID string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan term.Size) error {
 | 
				
			||||||
	// Have to start this before the call to client.AttachToContainer because client.AttachToContainer is a blocking
 | 
						// Have to start this before the call to client.AttachToContainer because client.AttachToContainer is a blocking
 | 
				
			||||||
	// call :-( Otherwise, resize events don't get processed and the terminal never resizes.
 | 
						// call :-( Otherwise, resize events don't get processed and the terminal never resizes.
 | 
				
			||||||
	kubecontainer.HandleResizing(resize, func(size term.Size) {
 | 
						kubecontainer.HandleResizing(resize, func(size term.Size) {
 | 
				
			||||||
		client.ResizeContainerTTY(containerID.ID, int(size.Height), int(size.Width))
 | 
							client.ResizeContainerTTY(containerID, int(size.Height), int(size.Width))
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO(random-liu): Do we really use the *Logs* field here?
 | 
						// TODO(random-liu): Do we really use the *Logs* field here?
 | 
				
			||||||
@@ -1294,7 +1294,7 @@ func AttachContainer(client DockerInterface, containerID kubecontainer.Container
 | 
				
			|||||||
		ErrorStream:  stderr,
 | 
							ErrorStream:  stderr,
 | 
				
			||||||
		RawTerminal:  tty,
 | 
							RawTerminal:  tty,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return client.AttachToContainer(containerID.ID, opts, sopts)
 | 
						return client.AttachToContainer(containerID, opts, sopts)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func noPodInfraContainerError(podName, podNamespace string) error {
 | 
					func noPodInfraContainerError(podName, podNamespace string) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -489,7 +489,10 @@ func NewMainKubelet(kubeCfg *componentconfig.KubeletConfiguration, kubeDeps *Kub
 | 
				
			|||||||
		case "cri":
 | 
							case "cri":
 | 
				
			||||||
			// Use the new CRI shim for docker. This is needed for testing the
 | 
								// Use the new CRI shim for docker. This is needed for testing the
 | 
				
			||||||
			// docker integration through CRI, and may be removed in the future.
 | 
								// docker integration through CRI, and may be removed in the future.
 | 
				
			||||||
			dockerService := dockershim.NewDockerService(klet.dockerClient, kubeCfg.SeccompProfileRoot, kubeCfg.PodInfraContainerImage)
 | 
								dockerService, err := dockershim.NewDockerService(klet.dockerClient, kubeCfg.SeccompProfileRoot, kubeCfg.PodInfraContainerImage, nil)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			runtimeService := dockerService.(internalApi.RuntimeService)
 | 
								runtimeService := dockerService.(internalApi.RuntimeService)
 | 
				
			||||||
			imageService := dockerService.(internalApi.ImageManagerService)
 | 
								imageService := dockerService.(internalApi.ImageManagerService)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,6 @@ limitations under the License.
 | 
				
			|||||||
package kuberuntime
 | 
					package kuberuntime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"io"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	internalApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
						internalApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
				
			||||||
@@ -123,13 +122,31 @@ func (in instrumentedRuntimeService) ContainerStatus(containerID string) (*runti
 | 
				
			|||||||
	return out, err
 | 
						return out, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (in instrumentedRuntimeService) Exec(containerID string, cmd []string, tty bool, stdin io.Reader, stdout, stderr io.WriteCloser) error {
 | 
					func (in instrumentedRuntimeService) ExecSync(containerID string, cmd []string, timeout time.Duration) ([]byte, []byte, error) {
 | 
				
			||||||
 | 
						const operation = "exec_sync"
 | 
				
			||||||
 | 
						defer recordOperation(operation, time.Now())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stdout, stderr, err := in.service.ExecSync(containerID, cmd, timeout)
 | 
				
			||||||
 | 
						recordError(operation, err)
 | 
				
			||||||
 | 
						return stdout, stderr, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (in instrumentedRuntimeService) Exec(req *runtimeApi.ExecRequest) (*runtimeApi.ExecResponse, error) {
 | 
				
			||||||
	const operation = "exec"
 | 
						const operation = "exec"
 | 
				
			||||||
	defer recordOperation(operation, time.Now())
 | 
						defer recordOperation(operation, time.Now())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := in.service.Exec(containerID, cmd, tty, stdin, stdout, stderr)
 | 
						resp, err := in.service.Exec(req)
 | 
				
			||||||
	recordError(operation, err)
 | 
						recordError(operation, err)
 | 
				
			||||||
	return err
 | 
						return resp, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (in instrumentedRuntimeService) Attach(req *runtimeApi.AttachRequest) (*runtimeApi.AttachResponse, error) {
 | 
				
			||||||
 | 
						const operation = "attach"
 | 
				
			||||||
 | 
						defer recordOperation(operation, time.Now())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := in.service.Attach(req)
 | 
				
			||||||
 | 
						recordError(operation, err)
 | 
				
			||||||
 | 
						return resp, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (in instrumentedRuntimeService) RunPodSandbox(config *runtimeApi.PodSandboxConfig) (string, error) {
 | 
					func (in instrumentedRuntimeService) RunPodSandbox(config *runtimeApi.PodSandboxConfig) (string, error) {
 | 
				
			||||||
@@ -177,6 +194,15 @@ func (in instrumentedRuntimeService) ListPodSandbox(filter *runtimeApi.PodSandbo
 | 
				
			|||||||
	return out, err
 | 
						return out, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (in instrumentedRuntimeService) PortForward(req *runtimeApi.PortForwardRequest) (*runtimeApi.PortForwardResponse, error) {
 | 
				
			||||||
 | 
						const operation = "port_forward"
 | 
				
			||||||
 | 
						defer recordOperation(operation, time.Now())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := in.service.PortForward(req)
 | 
				
			||||||
 | 
						recordError(operation, err)
 | 
				
			||||||
 | 
						return resp, err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (in instrumentedRuntimeService) UpdateRuntimeConfig(runtimeConfig *runtimeApi.RuntimeConfig) error {
 | 
					func (in instrumentedRuntimeService) UpdateRuntimeConfig(runtimeConfig *runtimeApi.RuntimeConfig) error {
 | 
				
			||||||
	const operation = "update_runtime_config"
 | 
						const operation = "update_runtime_config"
 | 
				
			||||||
	defer recordOperation(operation, time.Now())
 | 
						defer recordOperation(operation, time.Now())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -668,7 +668,7 @@ func (m *kubeGenericRuntimeManager) AttachContainer(id kubecontainer.ContainerID
 | 
				
			|||||||
	// now to unblock other tests.
 | 
						// now to unblock other tests.
 | 
				
			||||||
	// TODO: remove this hack after attach is defined in CRI.
 | 
						// TODO: remove this hack after attach is defined in CRI.
 | 
				
			||||||
	if ds, ok := m.runtimeService.(dockershim.DockerLegacyService); ok {
 | 
						if ds, ok := m.runtimeService.(dockershim.DockerLegacyService); ok {
 | 
				
			||||||
		return ds.AttachContainer(id, stdin, stdout, stderr, tty, resize)
 | 
							return ds.LegacyAttach(id, stdin, stdout, stderr, tty, resize)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return fmt.Errorf("not implemented")
 | 
						return fmt.Errorf("not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -694,7 +694,7 @@ func (m *kubeGenericRuntimeManager) ExecInContainer(containerID kubecontainer.Co
 | 
				
			|||||||
	// now to unblock other tests.
 | 
						// now to unblock other tests.
 | 
				
			||||||
	// TODO: remove this hack after exec is defined in CRI.
 | 
						// TODO: remove this hack after exec is defined in CRI.
 | 
				
			||||||
	if ds, ok := m.runtimeService.(dockershim.DockerLegacyService); ok {
 | 
						if ds, ok := m.runtimeService.(dockershim.DockerLegacyService); ok {
 | 
				
			||||||
		return ds.ExecInContainer(containerID, cmd, stdin, stdout, stderr, tty, resize)
 | 
							return ds.LegacyExec(containerID, cmd, stdin, stdout, stderr, tty, resize)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return fmt.Errorf("not implemented")
 | 
						return fmt.Errorf("not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1001,7 +1001,7 @@ func (m *kubeGenericRuntimeManager) PortForward(pod *kubecontainer.Pod, port uin
 | 
				
			|||||||
	// now to unblock other tests.
 | 
						// now to unblock other tests.
 | 
				
			||||||
	// TODO: remove this hack after portforward is defined in CRI.
 | 
						// TODO: remove this hack after portforward is defined in CRI.
 | 
				
			||||||
	if ds, ok := m.runtimeService.(dockershim.DockerLegacyService); ok {
 | 
						if ds, ok := m.runtimeService.(dockershim.DockerLegacyService); ok {
 | 
				
			||||||
		return ds.PortForward(pod.Sandboxes[0].ID.ID, port, stream)
 | 
							return ds.LegacyPortForward(pod.Sandboxes[0].ID.ID, port, stream)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return fmt.Errorf("not implemented")
 | 
						return fmt.Errorf("not implemented")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ go_library(
 | 
				
			|||||||
    deps = [
 | 
					    deps = [
 | 
				
			||||||
        "//pkg/kubelet/api:go_default_library",
 | 
					        "//pkg/kubelet/api:go_default_library",
 | 
				
			||||||
        "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
 | 
					        "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/util/exec:go_default_library",
 | 
				
			||||||
        "//vendor:github.com/golang/glog",
 | 
					        "//vendor:github.com/golang/glog",
 | 
				
			||||||
        "//vendor:golang.org/x/net/context",
 | 
					        "//vendor:golang.org/x/net/context",
 | 
				
			||||||
        "//vendor:google.golang.org/grpc",
 | 
					        "//vendor:google.golang.org/grpc",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,14 +17,15 @@ limitations under the License.
 | 
				
			|||||||
package remote
 | 
					package remote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"io"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
	"google.golang.org/grpc"
 | 
						"google.golang.org/grpc"
 | 
				
			||||||
	internalApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
						internalApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
				
			||||||
	runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
						runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
				
			||||||
 | 
						utilexec "k8s.io/kubernetes/pkg/util/exec"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RemoteRuntimeService is a gRPC implementation of internalApi.RuntimeService.
 | 
					// RemoteRuntimeService is a gRPC implementation of internalApi.RuntimeService.
 | 
				
			||||||
@@ -247,10 +248,75 @@ func (r *RemoteRuntimeService) ContainerStatus(containerID string) (*runtimeApi.
 | 
				
			|||||||
	return resp.Status, nil
 | 
						return resp.Status, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Exec executes a command in the container.
 | 
					// ExecSync executes a command in the container, and returns the stdout output.
 | 
				
			||||||
// TODO: support terminal resizing for exec, refer https://github.com/kubernetes/kubernetes/issues/29579.
 | 
					// If command exits with a non-zero exit code, an error is returned.
 | 
				
			||||||
func (r *RemoteRuntimeService) Exec(containerID string, cmd []string, tty bool, stdin io.Reader, stdout, stderr io.WriteCloser) error {
 | 
					func (r *RemoteRuntimeService) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) {
 | 
				
			||||||
	return fmt.Errorf("Not implemented")
 | 
						ctx, cancel := getContextWithTimeout(r.timeout)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						timeoutSeconds := int64(timeout.Seconds())
 | 
				
			||||||
 | 
						req := &runtimeApi.ExecSyncRequest{
 | 
				
			||||||
 | 
							ContainerId: &containerID,
 | 
				
			||||||
 | 
							Cmd:         cmd,
 | 
				
			||||||
 | 
							Timeout:     &timeoutSeconds,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						resp, err := r.runtimeClient.ExecSync(ctx, req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Errorf("ExecSync %s '%s' from runtime service failed: %v", containerID, strings.Join(cmd, " "), err)
 | 
				
			||||||
 | 
							return nil, nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = nil
 | 
				
			||||||
 | 
						if resp.GetExitCode() != 0 {
 | 
				
			||||||
 | 
							err = utilexec.CodeExitError{
 | 
				
			||||||
 | 
								Err:  fmt.Errorf("command '%s' exited with %d: %s", strings.Join(cmd, " "), resp.GetExitCode(), resp.GetStderr()),
 | 
				
			||||||
 | 
								Code: int(resp.GetExitCode()),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp.GetStdout(), resp.GetStderr(), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Exec prepares a streaming endpoint to execute a command in the container, and returns the address.
 | 
				
			||||||
 | 
					func (r *RemoteRuntimeService) Exec(req *runtimeApi.ExecRequest) (*runtimeApi.ExecResponse, error) {
 | 
				
			||||||
 | 
						ctx, cancel := getContextWithTimeout(r.timeout)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := r.runtimeClient.Exec(ctx, req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Errorf("Exec %s '%s' from runtime service failed: %v", req.GetContainerId(), strings.Join(req.GetCmd(), " "), err)
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Attach prepares a streaming endpoint to attach to a running container, and returns the address.
 | 
				
			||||||
 | 
					func (r *RemoteRuntimeService) Attach(req *runtimeApi.AttachRequest) (*runtimeApi.AttachResponse, error) {
 | 
				
			||||||
 | 
						ctx, cancel := getContextWithTimeout(r.timeout)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := r.runtimeClient.Attach(ctx, req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Errorf("Attach %s from runtime service failed: %v", req.GetContainerId(), err)
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address.
 | 
				
			||||||
 | 
					func (r *RemoteRuntimeService) PortForward(req *runtimeApi.PortForwardRequest) (*runtimeApi.PortForwardResponse, error) {
 | 
				
			||||||
 | 
						ctx, cancel := getContextWithTimeout(r.timeout)
 | 
				
			||||||
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := r.runtimeClient.PortForward(ctx, req)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							glog.Errorf("PortForward %s from runtime service failed: %v", req.GetPodSandboxId(), err)
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return resp, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *RemoteRuntimeService) UpdateRuntimeConfig(runtimeConfig *runtimeApi.RuntimeConfig) error {
 | 
					func (r *RemoteRuntimeService) UpdateRuntimeConfig(runtimeConfig *runtimeApi.RuntimeConfig) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ go_library(
 | 
				
			|||||||
    deps = [
 | 
					    deps = [
 | 
				
			||||||
        "//pkg/kubelet/api:go_default_library",
 | 
					        "//pkg/kubelet/api:go_default_library",
 | 
				
			||||||
        "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
 | 
					        "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/kubelet/util/ioutils:go_default_library",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ limitations under the License.
 | 
				
			|||||||
package rktshim
 | 
					package rktshim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"io"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kubeletApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
						kubeletApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
				
			||||||
	runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
						runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
				
			||||||
@@ -65,7 +65,18 @@ func (*Runtime) ContainerStatus(string) (*runtimeApi.ContainerStatus, error) {
 | 
				
			|||||||
	panic("not implemented")
 | 
						panic("not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Exec executes a command inside an app running inside a pod sanbox.
 | 
					// ExecSync executes a command in the container, and returns the stdout output.
 | 
				
			||||||
func (*Runtime) Exec(string, []string, bool, io.Reader, io.WriteCloser, io.WriteCloser) error {
 | 
					// If command exits with a non-zero exit code, an error is returned.
 | 
				
			||||||
 | 
					func (*Runtime) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) {
 | 
				
			||||||
 | 
						panic("not implemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Exec prepares a streaming endpoint to execute a command in the container, and returns the address.
 | 
				
			||||||
 | 
					func (*Runtime) Exec(*runtimeApi.ExecRequest) (*runtimeApi.ExecResponse, error) {
 | 
				
			||||||
 | 
						panic("not implemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Attach prepares a streaming endpoint to attach to a running container, and returns the address.
 | 
				
			||||||
 | 
					func (*Runtime) Attach(req *runtimeApi.AttachRequest) (*runtimeApi.AttachResponse, error) {
 | 
				
			||||||
	panic("not implemented")
 | 
						panic("not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ limitations under the License.
 | 
				
			|||||||
package rktshim
 | 
					package rktshim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"math/rand"
 | 
						"math/rand"
 | 
				
			||||||
@@ -24,6 +25,12 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	kubeletApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
						kubeletApi "k8s.io/kubernetes/pkg/kubelet/api"
 | 
				
			||||||
	runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
						runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/kubelet/util/ioutils"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						FakeStreamingHost = "localhost"
 | 
				
			||||||
 | 
						FakeStreamingPort = "12345"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
@@ -200,16 +207,34 @@ func (r *FakeRuntime) ContainerStatus(id string) (*runtimeApi.ContainerStatus, e
 | 
				
			|||||||
	return &c.Status, nil
 | 
						return &c.Status, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *FakeRuntime) Exec(id string, cmd []string, tty bool, in io.Reader, out, err io.WriteCloser) error {
 | 
					func (r *FakeRuntime) ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error) {
 | 
				
			||||||
	c, ok := r.Containers[id]
 | 
						c, ok := r.Containers[containerID]
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		return ErrContainerNotFound
 | 
							return nil, nil, ErrContainerNotFound
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO(tmrts): Validate the assumption that container has to be running for exec to work.
 | 
						// TODO(tmrts): Validate the assumption that container has to be running for exec to work.
 | 
				
			||||||
	if c.State != runtimeApi.ContainerState_RUNNING {
 | 
						if c.State != runtimeApi.ContainerState_RUNNING {
 | 
				
			||||||
		return ErrInvalidContainerStateTransition
 | 
							return nil, nil, ErrInvalidContainerStateTransition
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c.Exec(cmd, in, out, err)
 | 
						var stdoutBuffer, stderrBuffer bytes.Buffer
 | 
				
			||||||
 | 
						err = c.Exec(cmd, nil,
 | 
				
			||||||
 | 
							ioutils.WriteCloserWrapper(&stdoutBuffer),
 | 
				
			||||||
 | 
							ioutils.WriteCloserWrapper(&stderrBuffer))
 | 
				
			||||||
 | 
						return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *FakeRuntime) Exec(req *runtimeApi.ExecRequest) (*runtimeApi.ExecResponse, error) {
 | 
				
			||||||
 | 
						url := "http://" + FakeStreamingHost + ":" + FakeStreamingPort + "/exec/" + req.GetContainerId()
 | 
				
			||||||
 | 
						return &runtimeApi.ExecResponse{
 | 
				
			||||||
 | 
							Url: &url,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (r *FakeRuntime) Attach(req *runtimeApi.AttachRequest) (*runtimeApi.AttachResponse, error) {
 | 
				
			||||||
 | 
						url := "http://" + FakeStreamingHost + ":" + FakeStreamingPort + "/attach/" + req.GetContainerId()
 | 
				
			||||||
 | 
						return &runtimeApi.AttachResponse{
 | 
				
			||||||
 | 
							Url: &url,
 | 
				
			||||||
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,3 +57,8 @@ func (*PodSandboxManager) PodSandboxStatus(string) (*runtimeApi.PodSandboxStatus
 | 
				
			|||||||
func (*PodSandboxManager) ListPodSandbox(*runtimeApi.PodSandboxFilter) ([]*runtimeApi.PodSandbox, error) {
 | 
					func (*PodSandboxManager) ListPodSandbox(*runtimeApi.PodSandboxFilter) ([]*runtimeApi.PodSandbox, error) {
 | 
				
			||||||
	panic("not implemented")
 | 
						panic("not implemented")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PortForward prepares a streaming endpoint to forward ports from a PodSandbox, and returns the address.
 | 
				
			||||||
 | 
					func (*PodSandboxManager) PortForward(*runtimeApi.PortForwardRequest) (*runtimeApi.PortForwardResponse, error) {
 | 
				
			||||||
 | 
						panic("not implemented")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,10 @@ load(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
go_library(
 | 
					go_library(
 | 
				
			||||||
    name = "go_default_library",
 | 
					    name = "go_default_library",
 | 
				
			||||||
    srcs = ["server.go"],
 | 
					    srcs = [
 | 
				
			||||||
 | 
					        "errors.go",
 | 
				
			||||||
 | 
					        "server.go",
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
    tags = ["automanaged"],
 | 
					    tags = ["automanaged"],
 | 
				
			||||||
    deps = [
 | 
					    deps = [
 | 
				
			||||||
        "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
 | 
					        "//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
 | 
				
			||||||
@@ -21,6 +24,7 @@ go_library(
 | 
				
			|||||||
        "//pkg/types:go_default_library",
 | 
					        "//pkg/types:go_default_library",
 | 
				
			||||||
        "//pkg/util/term:go_default_library",
 | 
					        "//pkg/util/term:go_default_library",
 | 
				
			||||||
        "//vendor:github.com/emicklei/go-restful",
 | 
					        "//vendor:github.com/emicklei/go-restful",
 | 
				
			||||||
 | 
					        "//vendor:google.golang.org/grpc/codes",
 | 
				
			||||||
        "//vendor:k8s.io/client-go/pkg/api",
 | 
					        "//vendor:k8s.io/client-go/pkg/api",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								pkg/kubelet/server/streaming/errors.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								pkg/kubelet/server/streaming/errors.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2016 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package streaming
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"google.golang.org/grpc/codes"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ResponseError struct {
 | 
				
			||||||
 | 
						Err  string
 | 
				
			||||||
 | 
						Code codes.Code
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (e *ResponseError) Error() string {
 | 
				
			||||||
 | 
						return e.Err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ErrorStreamingDisabled(method string) error {
 | 
				
			||||||
 | 
						return &ResponseError{
 | 
				
			||||||
 | 
							Err:  fmt.Sprintf("streaming method %s disabled", method),
 | 
				
			||||||
 | 
							Code: codes.NotFound,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ErrorTimeout(op string, timeout time.Duration) error {
 | 
				
			||||||
 | 
						return &ResponseError{
 | 
				
			||||||
 | 
							Err:  fmt.Sprintf("%s timed out after %s", op, timeout.String()),
 | 
				
			||||||
 | 
							Code: codes.DeadlineExceeded,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user