Merge pull request #49762 from feiskyer/fake-remote-runtime

Automatic merge from submit-queue (batch tested with PRs 49762, 52256). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Add fake remote runtime service

**What this PR does / why we need it**:

Add fake remote runtime service.

**Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: 

First step of #45206.

**Special notes for your reviewer**:

**Release note**:

```release-note
NONE
```
pull/6/head
Kubernetes Submit Queue 2017-10-27 22:48:25 -07:00 committed by GitHub
commit 0110db0b47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 599 additions and 7 deletions

View File

@ -26,7 +26,7 @@ import (
)
var (
version = "0.1.0"
FakeVersion = "0.1.0"
FakeRuntimeName = "fakeRuntime"
FakePodSandboxIP = "192.168.192.168"
@ -117,10 +117,10 @@ func (r *FakeRuntimeService) Version(apiVersion string) (*runtimeapi.VersionResp
r.Called = append(r.Called, "Version")
return &runtimeapi.VersionResponse{
Version: version,
Version: FakeVersion,
RuntimeName: FakeRuntimeName,
RuntimeVersion: version,
RuntimeApiVersion: version,
RuntimeVersion: FakeVersion,
RuntimeApiVersion: FakeVersion,
}, nil
}

View File

@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
@ -34,6 +35,23 @@ filegroup(
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
srcs = [
":package-srcs",
"//pkg/kubelet/remote/fake:all-srcs",
],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = ["remote_runtime_test.go"],
importpath = "k8s.io/kubernetes/pkg/kubelet/remote",
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/kubelet/apis/cri:go_default_library",
"//pkg/kubelet/apis/cri/testing:go_default_library",
"//pkg/kubelet/remote/fake:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library",
],
)

View File

@ -0,0 +1,46 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"endpoint.go",
"fake_image_service.go",
"fake_runtime.go",
] + select({
"@io_bazel_rules_go//go/platform:windows_amd64": [
"endpoint_windows.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/pkg/kubelet/remote/fake",
tags = ["automanaged"],
deps = [
"//pkg/kubelet/apis/cri/testing:go_default_library",
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
"//pkg/kubelet/util:go_default_library",
"//vendor/golang.org/x/net/context:go_default_library",
"//vendor/google.golang.org/grpc:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

View File

@ -0,0 +1,19 @@
/*
Copyright 2017 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 fake containers a fake gRPC implementation of internalapi.RuntimeService
// and internalapi.ImageManagerService.
package fake

View File

@ -0,0 +1,28 @@
// +build !windows
/*
Copyright 2017 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 fake
const (
defaultUnixEndpoint = "unix:///tmp/kubelet_remote.sock"
)
// GenerateEndpoint generates a new unix socket server of grpc server.
func GenerateEndpoint() (string, error) {
return defaultUnixEndpoint, nil
}

View File

@ -0,0 +1,40 @@
// +build windows
/*
Copyright 2017 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 fake
import (
"fmt"
"net"
)
// GenerateEndpoint generates a new tcp endpoint of grpc server.
func GenerateEndpoint() (string, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return "", nil
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return "", err
}
defer l.Close()
return fmt.Sprintf("tcp://127.0.0.1:%d", l.Addr().(*net.TCPAddr).Port), nil
}

View File

@ -0,0 +1,80 @@
/*
Copyright 2017 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 fake
import (
"golang.org/x/net/context"
kubeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)
// ListImages lists existing images.
func (f *RemoteRuntime) ListImages(ctx context.Context, req *kubeapi.ListImagesRequest) (*kubeapi.ListImagesResponse, error) {
images, err := f.ImageService.ListImages(req.Filter)
if err != nil {
return nil, err
}
return &kubeapi.ListImagesResponse{
Images: images,
}, nil
}
// ImageStatus returns the status of the image. If the image is not
// present, returns a response with ImageStatusResponse.Image set to
// nil.
func (f *RemoteRuntime) ImageStatus(ctx context.Context, req *kubeapi.ImageStatusRequest) (*kubeapi.ImageStatusResponse, error) {
status, err := f.ImageService.ImageStatus(req.Image)
if err != nil {
return nil, err
}
return &kubeapi.ImageStatusResponse{Image: status}, nil
}
// PullImage pulls an image with authentication config.
func (f *RemoteRuntime) PullImage(ctx context.Context, req *kubeapi.PullImageRequest) (*kubeapi.PullImageResponse, error) {
image, err := f.ImageService.PullImage(req.Image, req.Auth)
if err != nil {
return nil, err
}
return &kubeapi.PullImageResponse{
ImageRef: image,
}, nil
}
// RemoveImage removes the image.
// This call is idempotent, and must not return an error if the image has
// already been removed.
func (f *RemoteRuntime) RemoveImage(ctx context.Context, req *kubeapi.RemoveImageRequest) (*kubeapi.RemoveImageResponse, error) {
err := f.ImageService.RemoveImage(req.Image)
if err != nil {
return nil, err
}
return &kubeapi.RemoveImageResponse{}, nil
}
// ImageFsInfo returns information of the filesystem that is used to store images.
func (f *RemoteRuntime) ImageFsInfo(ctx context.Context, req *kubeapi.ImageFsInfoRequest) (*kubeapi.ImageFsInfoResponse, error) {
fsUsage, err := f.ImageService.ImageFsInfo()
if err != nil {
return nil, err
}
return &kubeapi.ImageFsInfoResponse{ImageFilesystems: fsUsage}, nil
}

View File

@ -0,0 +1,285 @@
/*
Copyright 2017 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 fake
import (
"fmt"
"time"
"golang.org/x/net/context"
"google.golang.org/grpc"
apitest "k8s.io/kubernetes/pkg/kubelet/apis/cri/testing"
kubeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
"k8s.io/kubernetes/pkg/kubelet/util"
utilexec "k8s.io/utils/exec"
)
// RemoteRuntime represents a fake remote container runtime.
type RemoteRuntime struct {
server *grpc.Server
// Fake runtime service.
RuntimeService *apitest.FakeRuntimeService
// Fake image service.
ImageService *apitest.FakeImageService
}
// NewFakeRemoteRuntime creates a new RemoteRuntime.
func NewFakeRemoteRuntime() *RemoteRuntime {
fakeRuntimeService := apitest.NewFakeRuntimeService()
fakeImageService := apitest.NewFakeImageService()
f := &RemoteRuntime{
server: grpc.NewServer(),
RuntimeService: fakeRuntimeService,
ImageService: fakeImageService,
}
kubeapi.RegisterRuntimeServiceServer(f.server, f)
kubeapi.RegisterImageServiceServer(f.server, f)
return f
}
// Start starts the fake remote runtime.
func (f *RemoteRuntime) Start(endpoint string) error {
l, err := util.CreateListener(endpoint)
if err != nil {
return fmt.Errorf("failed to listen on %q: %v", endpoint, err)
}
return f.server.Serve(l)
}
// Stop stops the fake remote runtime.
func (f *RemoteRuntime) Stop() {
f.server.Stop()
}
// Version returns the runtime name, runtime version, and runtime API version.
func (f *RemoteRuntime) Version(ctx context.Context, req *kubeapi.VersionRequest) (*kubeapi.VersionResponse, error) {
return f.RuntimeService.Version(req.Version)
}
// RunPodSandbox creates and starts a pod-level sandbox. Runtimes must ensure
// the sandbox is in the ready state on success.
func (f *RemoteRuntime) RunPodSandbox(ctx context.Context, req *kubeapi.RunPodSandboxRequest) (*kubeapi.RunPodSandboxResponse, error) {
sandboxID, err := f.RuntimeService.RunPodSandbox(req.Config)
if err != nil {
return nil, err
}
return &kubeapi.RunPodSandboxResponse{PodSandboxId: sandboxID}, nil
}
// StopPodSandbox stops any running process that is part of the sandbox and
// reclaims network resources (e.g., IP addresses) allocated to the sandbox.
// If there are any running containers in the sandbox, they must be forcibly
// terminated.
func (f *RemoteRuntime) StopPodSandbox(ctx context.Context, req *kubeapi.StopPodSandboxRequest) (*kubeapi.StopPodSandboxResponse, error) {
err := f.RuntimeService.StopPodSandbox(req.PodSandboxId)
if err != nil {
return nil, err
}
return &kubeapi.StopPodSandboxResponse{}, nil
}
// RemovePodSandbox removes the sandbox. If there are any running containers
// in the sandbox, they must be forcibly terminated and removed.
// This call is idempotent, and must not return an error if the sandbox has
// already been removed.
func (f *RemoteRuntime) RemovePodSandbox(ctx context.Context, req *kubeapi.RemovePodSandboxRequest) (*kubeapi.RemovePodSandboxResponse, error) {
err := f.RuntimeService.StopPodSandbox(req.PodSandboxId)
if err != nil {
return nil, err
}
return &kubeapi.RemovePodSandboxResponse{}, nil
}
// PodSandboxStatus returns the status of the PodSandbox. If the PodSandbox is not
// present, returns an error.
func (f *RemoteRuntime) PodSandboxStatus(ctx context.Context, req *kubeapi.PodSandboxStatusRequest) (*kubeapi.PodSandboxStatusResponse, error) {
podStatus, err := f.RuntimeService.PodSandboxStatus(req.PodSandboxId)
if err != nil {
return nil, err
}
return &kubeapi.PodSandboxStatusResponse{Status: podStatus}, nil
}
// ListPodSandbox returns a list of PodSandboxes.
func (f *RemoteRuntime) ListPodSandbox(ctx context.Context, req *kubeapi.ListPodSandboxRequest) (*kubeapi.ListPodSandboxResponse, error) {
items, err := f.RuntimeService.ListPodSandbox(req.Filter)
if err != nil {
return nil, err
}
return &kubeapi.ListPodSandboxResponse{Items: items}, nil
}
// CreateContainer creates a new container in specified PodSandbox
func (f *RemoteRuntime) CreateContainer(ctx context.Context, req *kubeapi.CreateContainerRequest) (*kubeapi.CreateContainerResponse, error) {
containerID, err := f.RuntimeService.CreateContainer(req.PodSandboxId, req.Config, req.SandboxConfig)
if err != nil {
return nil, err
}
return &kubeapi.CreateContainerResponse{ContainerId: containerID}, nil
}
// StartContainer starts the container.
func (f *RemoteRuntime) StartContainer(ctx context.Context, req *kubeapi.StartContainerRequest) (*kubeapi.StartContainerResponse, error) {
err := f.RuntimeService.StartContainer(req.ContainerId)
if err != nil {
return nil, err
}
return &kubeapi.StartContainerResponse{}, nil
}
// StopContainer stops a running container with a grace period (i.e., timeout).
// This call is idempotent, and must not return an error if the container has
// already been stopped.
func (f *RemoteRuntime) StopContainer(ctx context.Context, req *kubeapi.StopContainerRequest) (*kubeapi.StopContainerResponse, error) {
err := f.RuntimeService.StopContainer(req.ContainerId, req.Timeout)
if err != nil {
return nil, err
}
return &kubeapi.StopContainerResponse{}, nil
}
// RemoveContainer removes the container. If the container is running, the
// container must be forcibly removed.
// This call is idempotent, and must not return an error if the container has
// already been removed.
func (f *RemoteRuntime) RemoveContainer(ctx context.Context, req *kubeapi.RemoveContainerRequest) (*kubeapi.RemoveContainerResponse, error) {
err := f.RuntimeService.RemoveContainer(req.ContainerId)
if err != nil {
return nil, err
}
return &kubeapi.RemoveContainerResponse{}, nil
}
// ListContainers lists all containers by filters.
func (f *RemoteRuntime) ListContainers(ctx context.Context, req *kubeapi.ListContainersRequest) (*kubeapi.ListContainersResponse, error) {
items, err := f.RuntimeService.ListContainers(req.Filter)
if err != nil {
return nil, err
}
return &kubeapi.ListContainersResponse{Containers: items}, nil
}
// ContainerStatus returns status of the container. If the container is not
// present, returns an error.
func (f *RemoteRuntime) ContainerStatus(ctx context.Context, req *kubeapi.ContainerStatusRequest) (*kubeapi.ContainerStatusResponse, error) {
status, err := f.RuntimeService.ContainerStatus(req.ContainerId)
if err != nil {
return nil, err
}
return &kubeapi.ContainerStatusResponse{Status: status}, nil
}
// ExecSync runs a command in a container synchronously.
func (f *RemoteRuntime) ExecSync(ctx context.Context, req *kubeapi.ExecSyncRequest) (*kubeapi.ExecSyncResponse, error) {
var exitCode int32
stdout, stderr, err := f.RuntimeService.ExecSync(req.ContainerId, req.Cmd, time.Duration(req.Timeout)*time.Second)
if err != nil {
exitError, ok := err.(utilexec.ExitError)
if !ok {
return nil, err
}
exitCode = int32(exitError.ExitStatus())
return nil, err
}
return &kubeapi.ExecSyncResponse{
Stdout: stdout,
Stderr: stderr,
ExitCode: exitCode,
}, nil
}
// Exec prepares a streaming endpoint to execute a command in the container.
func (f *RemoteRuntime) Exec(ctx context.Context, req *kubeapi.ExecRequest) (*kubeapi.ExecResponse, error) {
return f.RuntimeService.Exec(req)
}
// Attach prepares a streaming endpoint to attach to a running container.
func (f *RemoteRuntime) Attach(ctx context.Context, req *kubeapi.AttachRequest) (*kubeapi.AttachResponse, error) {
return f.RuntimeService.Attach(req)
}
// PortForward prepares a streaming endpoint to forward ports from a PodSandbox.
func (f *RemoteRuntime) PortForward(ctx context.Context, req *kubeapi.PortForwardRequest) (*kubeapi.PortForwardResponse, error) {
return f.RuntimeService.PortForward(req)
}
// ContainerStats returns stats of the container. If the container does not
// exist, the call returns an error.
func (f *RemoteRuntime) ContainerStats(ctx context.Context, req *kubeapi.ContainerStatsRequest) (*kubeapi.ContainerStatsResponse, error) {
stats, err := f.RuntimeService.ContainerStats(req.ContainerId)
if err != nil {
return nil, err
}
return &kubeapi.ContainerStatsResponse{Stats: stats}, nil
}
// ListContainerStats returns stats of all running containers.
func (f *RemoteRuntime) ListContainerStats(ctx context.Context, req *kubeapi.ListContainerStatsRequest) (*kubeapi.ListContainerStatsResponse, error) {
stats, err := f.RuntimeService.ListContainerStats(req.Filter)
if err != nil {
return nil, err
}
return &kubeapi.ListContainerStatsResponse{Stats: stats}, nil
}
// UpdateRuntimeConfig updates the runtime configuration based on the given request.
func (f *RemoteRuntime) UpdateRuntimeConfig(ctx context.Context, req *kubeapi.UpdateRuntimeConfigRequest) (*kubeapi.UpdateRuntimeConfigResponse, error) {
err := f.RuntimeService.UpdateRuntimeConfig(req.RuntimeConfig)
if err != nil {
return nil, err
}
return &kubeapi.UpdateRuntimeConfigResponse{}, nil
}
// Status returns the status of the runtime.
func (f *RemoteRuntime) Status(ctx context.Context, req *kubeapi.StatusRequest) (*kubeapi.StatusResponse, error) {
status, err := f.RuntimeService.Status()
if err != nil {
return nil, err
}
return &kubeapi.StatusResponse{Status: status}, nil
}
// UpdateContainerResources updates ContainerConfig of the container.
func (f *RemoteRuntime) UpdateContainerResources(ctx context.Context, req *kubeapi.UpdateContainerResourcesRequest) (*kubeapi.UpdateContainerResourcesResponse, error) {
err := f.RuntimeService.UpdateContainerResources(req.ContainerId, req.Linux)
if err != nil {
return nil, err
}
return &kubeapi.UpdateContainerResourcesResponse{}, nil
}

View File

@ -0,0 +1,69 @@
/*
Copyright 2017 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 remote
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri"
apitest "k8s.io/kubernetes/pkg/kubelet/apis/cri/testing"
fakeremote "k8s.io/kubernetes/pkg/kubelet/remote/fake"
)
const (
defaultConnectionTimeout = 15 * time.Second
)
// createAndStartFakeRemoteRuntime creates and starts fakeremote.RemoteRuntime.
// It returns the RemoteRuntime, endpoint on success.
// Users should call fakeRuntime.Stop() to cleanup the server.
func createAndStartFakeRemoteRuntime(t *testing.T) (*fakeremote.RemoteRuntime, string) {
endpoint, err := fakeremote.GenerateEndpoint()
assert.NoError(t, err)
fakeRuntime := fakeremote.NewFakeRemoteRuntime()
go fakeRuntime.Start(endpoint)
return fakeRuntime, endpoint
}
func createRemoteRuntimeService(endpoint string, t *testing.T) internalapi.RuntimeService {
runtimeService, err := NewRemoteRuntimeService(endpoint, defaultConnectionTimeout)
assert.NoError(t, err)
return runtimeService
}
func createRemoteImageService(endpoint string, t *testing.T) internalapi.ImageManagerService {
imageService, err := NewRemoteImageService(endpoint, defaultConnectionTimeout)
assert.NoError(t, err)
return imageService
}
func TestVersion(t *testing.T) {
fakeRuntime, endpoint := createAndStartFakeRemoteRuntime(t)
defer fakeRuntime.Stop()
r := createRemoteRuntimeService(endpoint, t)
version, err := r.Version(apitest.FakeVersion)
assert.NoError(t, err)
assert.Equal(t, apitest.FakeVersion, version.Version)
assert.Equal(t, apitest.FakeRuntimeName, version.RuntimeName)
}

View File

@ -21,6 +21,9 @@ go_library(
"util.go",
"util_unsupported.go",
] + select({
"@io_bazel_rules_go//go/platform:darwin_amd64": [
"util_unix.go",
],
"@io_bazel_rules_go//go/platform:linux_amd64": [
"util_unix.go",
],
@ -33,6 +36,10 @@ go_library(
deps = [
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:darwin_amd64": [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"@io_bazel_rules_go//go/platform:linux_amd64": [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",

View File

@ -1,4 +1,4 @@
// +build freebsd linux
// +build freebsd linux darwin
/*
Copyright 2017 The Kubernetes Authors.

View File

@ -1,4 +1,4 @@
// +build !freebsd,!linux,!windows
// +build !freebsd,!linux,!windows,!darwin
/*
Copyright 2017 The Kubernetes Authors.