diff options
| author | KubeEdge Bot <48982446+kubeedge-bot@users.noreply.github.com> | 2022-03-04 16:22:43 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-04 16:22:43 +0800 |
| commit | 5e63a9508950c8df28cb0fd9dafdd9ed22eb535e (patch) | |
| tree | 3da50d2d065643d9968a0c503b12bf3165decb0a | |
| parent | Merge pull request #3534 from gy95/keadmconfig (diff) | |
| parent | update vendor (diff) | |
| download | kubeedge-1.10.0-beta.0.tar.gz | |
Merge pull request #3637 from wackxu/edgemarkv1.10.0-beta.0
Add Edgemark for scalability test
20 files changed, 1779 insertions, 7 deletions
@@ -13,7 +13,8 @@ BINARIES=cloudcore \ edgesite-server \ keadm \ csidriver \ - iptablesmanager + iptablesmanager \ + edgemark COMPONENTS=cloud \ edge @@ -46,7 +47,7 @@ ifeq ($(HELP),y) all: clean @echo "$$ALL_HELP_INFO" else -all: +all: KUBEEDGE_OUTPUT_SUBPATH=$(OUT_DIR) hack/make-rules/build.sh $(WHAT) endif @@ -174,7 +175,7 @@ ifeq ($(HELP),y) crossbuild: @echo "$$CROSSBUILD_HELP_INFO" else -crossbuild: +crossbuild: hack/make-rules/crossbuild.sh $(WHAT) $(ARM_VERSION) endif @@ -194,7 +195,7 @@ define GENERATE_CRDS_HELP_INFO # RELIABLESYNCS_VERSION, default: v1alpha1 # # Example: -# make generate +# make generate # make generate -e CRD_VERSIONS=v1 -e CRD_OUTPUTS=build/crds # endef @@ -227,7 +228,7 @@ ifeq ($(HELP),y) smallbuild: @echo "$$SMALLBUILD_HELP_INFO" else -smallbuild: +smallbuild: hack/make-rules/smallbuild.sh $(WHAT) endif diff --git a/build/edgemark/Dockerfile b/build/edgemark/Dockerfile new file mode 100644 index 000000000..8f4b85884 --- /dev/null +++ b/build/edgemark/Dockerfile @@ -0,0 +1,19 @@ +ARG BUILD_FROM=golang:1.16-alpine3.13
+
+FROM ${BUILD_FROM} AS builder
+
+ARG GO_LDFLAGS
+
+COPY . /go/src/github.com/kubeedge/kubeedge
+
+RUN apk --no-cache update && \
+apk --no-cache upgrade && \
+apk --no-cache add build-base linux-headers sqlite-dev binutils-gold && \
+CGO_ENABLED=1 GO111MODULE=off go build -v -o /usr/local/bin/edgemark -ldflags="${GO_LDFLAGS} -w -s -extldflags -static" \
+github.com/kubeedge/kubeedge/edge/cmd/edgemark
+
+FROM alpine:3.13
+
+COPY --from=builder /usr/local/bin/edgemark /usr/local/bin/edgemark
+
+ENTRYPOINT ["edgemark"]
\ No newline at end of file diff --git a/build/edgemark/README.md b/build/edgemark/README.md new file mode 100644 index 000000000..d74d5becf --- /dev/null +++ b/build/edgemark/README.md @@ -0,0 +1,48 @@ +# Edgemark User Guide + +## Introduction + +Edgemark is a performance testing tool that inspired by +[Kubemark](https://github.com/kubernetes/kubernetes/tree/master/cmd/kubemark) +which allows users to run experiments on +simulated clusters. The primary use case is scalability testing, as simulated +clusters can be much bigger than the real ones. The objective is to expose +problems with the KubeEdge cloud components CloudCore that appear only on bigger clusters. + +This document serves as a primer to understand what Edgemark is, what it is not, +and how to use it. + +## Architecture + +On a very high level, Edgemark cluster consists of three parts: a real kubernetes master, +KubeEdge CloudCore component and a set of “Hollow” Edge Nodes. Hollow Edge Node is registered +with `HollowEdgeCore`, which pretends to be an ordinary EdgeCore, but does not create any real containers. +`HollowEdgeCore` mocks runtime manager with Kubernetes `k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/fake_runtime.go`, +where most logic sits. Except for simulating runtime manager, other behaviors is the same as edgecore. + + + +Currently, Kubernetes master components run on a dedicated machine as pods that are +created/managed by kubelet, which itself runs as either a systemd or a supervisord +service on the master VM depending on the VM distro. Having a dedicated machine for the master +has a slight advantage over running the master components on an external cluster, +which is being able to completely isolate master resources from everything else. +The CloudCore has multiple instances and requires multiple dedicated nodes to maintain high reliability. +Usually In highly available configurations, a load balancer must sit in front of the CloudCore +to correctly route requests to healthy CloudCore servers. And The HollowEdgeNodes +on the other hand are run on an ‘external’ Kubernetes cluster +as pods in an isolated namespace (named edgemark). This idea of using pods on a +real cluster behave (or act) as nodes on the edgemark cluster lies at the heart of +edgemark's design. + +## Requirements + +To run Edgemark, you need: + +1. A Kubernetes cluster (called `external cluster`) for running all your HollowEdgeNodes +2. A Kubernetes cluster (called `edgemark cluster`) the master for HollowEdgeNodes. +3. Several dedicated nodes in `edgemark cluster` for deploy CloudCore, a load balancer + that expose CloudCore service for HollowEdgeNodes and the load balancer has to be directly + routable from HollowEdgeNodes. +4. You also need access to a Docker repository that has the + container images for CloudCore, hollow-edge-node and node-problem-detector. diff --git a/build/edgemark/edgemark_setup_guide.md b/build/edgemark/edgemark_setup_guide.md new file mode 100644 index 000000000..fd0a48885 --- /dev/null +++ b/build/edgemark/edgemark_setup_guide.md @@ -0,0 +1,97 @@ +## Introduction +This document serves to understand how to set up edgemark cluster given +that a base cluster (to run hollow-edge-node pods) and +separate master (to act as master for the hollow edge nodes) are already present. + +## Precondition +You need edgemark master and external cluster to set up a edgemark cluster. + +The functions are as follows: + +- edgemark master: can be StandAlone or HA, used to be the edgemark cluster's master +- external cluster: used to create hollow edge nodes for the edgemark cluster + +## Steps: +1. Deploy CloudCore in edgemark cluster, refer to [CloudCore deploy](https://kubeedge.io/en/docs/setup/ha/) for more details. + +2. Build edgemark image + +If you want to build/use your own edgemark image, do as follows. + +- i. pull kubeedge code + +``` +cd $GOPATH/src/github.com/kubeedge +git clone git@github.com:kubeedge/kubeedge.git +``` + +- ii. build edgemark image + +``` +cd $GOPATH/src/github.com/kubeedge/kubeedge +make image WHAT=edgemark +``` + +Then you can get the image named `kubeedge/edgemark:{tag}` locally. + +3. Create hollow nodes in external cluster + +- i. create namespace and secret + +Copy edgemark master's `tokensecret` which is generated by CloudCore which is used to access CloudCore for edge node, +and create it in namespace that will deploy hollow edge node in external cluster. + +first, save `tokensecret` in file from edgemark cluster, + +``` +kubectl get secret -nkubeedge tokensecret -oyaml > tokensecret.yaml +``` + +modify namespace in `tokensecret.yaml` +``` +sed -i "s|namespace: .*|namespace: {ns}|g" tokensecret.yaml +``` + +create ns and tokensecret in external cluster + +``` +kubectl create ns edgemark + +kubectl create -f tokensecret.yaml +``` + +- ii. apply yaml to create hollow nodes + +You can use `hollow-edge-node_template.yaml` in the current directory. + +Note: + +- the parameters `{{numreplicas}}` means the number of hollow nodes in the edgemark cluster +- the parameters `{{server}}` means the server address exposed for hollow nodes join in +- the parameters `{{server}}`, `{{numreplicas}}`, `{{edgemark_image_registry}}` and `{{edgemark_image_tag}}` need to be filled in the template +- your external cluster should have enough resources to be able to run `{{numreplicas}}` no. of hollow-node pods + +``` +kubectl create -f hollow-edge-node_template.yaml +``` + +Waiting for these hollow-node pods to be running. Then you can see these pods register as edgemark master's nodes. + +Finally, edgemark master and external cluster set up the edgemark cluster. + + +4. Run performance testing with ClusterLoader2 + +After set up the edgemark cluster, we can do our performance testing with ClusterLoader2. +[ClusterLoader2](https://github.com/kubernetes/perf-tests/tree/master/clusterloader2) is +an official K8s scalability and performance testing framework. +refer to [ClusterLoader2 Getting started](https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/docs/GETTING_STARTED.md) for more details. +we just need config `--provider=kubemark` when we run performance test, for example: + +``` +./clusterloader --testconfig=config.yaml --provider=kubemark --kubeconfig=${HOME}/.kube/config --v=2 +``` + + + + diff --git a/build/edgemark/hollow_edge_node_template.yaml b/build/edgemark/hollow_edge_node_template.yaml new file mode 100644 index 000000000..aa677ad94 --- /dev/null +++ b/build/edgemark/hollow_edge_node_template.yaml @@ -0,0 +1,50 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: hollow-edge-node +spec: + replicas: {{numreplicas}} + selector: + matchLabels: + app: hollow-edge-node + template: + metadata: + labels: + app: hollow-edge-node + spec: + containers: + - name: hollow-edgecore + image: {{edgemark_image_registry}}/edgemark:{{edgemark_image_tag}} + command: + - edgemark + args: + - --token=$(TOKEN) + - --name=$(NODE_NAME) + - --http-server=https://{{server}}:10002 + - --websocket-server={{server}}:10000 + - --alsologtostderr + - --v=2 + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: TOKEN + valueFrom: + secretKeyRef: + name: tokensecret + key: tokendata + resources: + requests: + cpu: 20m + memory: 50M + securityContext: + privileged: true + tolerations: + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/not-ready + operator: Exists diff --git a/build/edgemark/images/edgemark.jpg b/build/edgemark/images/edgemark.jpg Binary files differnew file mode 100644 index 000000000..2dfe3dadf --- /dev/null +++ b/build/edgemark/images/edgemark.jpg diff --git a/edge/cmd/edgemark/hollow_edgecore.go b/edge/cmd/edgemark/hollow_edgecore.go new file mode 100644 index 000000000..c76ff63f8 --- /dev/null +++ b/edge/cmd/edgemark/hollow_edgecore.go @@ -0,0 +1,153 @@ +/* +Copyright 2022 The KubeEdge 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 main + +import ( + "flag" + "fmt" + "os" + "time" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + cliflag "k8s.io/component-base/cli/flag" + internalapi "k8s.io/cri-api/pkg/apis" + "k8s.io/kubernetes/pkg/kubelet/cri/remote" + fakeremote "k8s.io/kubernetes/pkg/kubelet/cri/remote/fake" + + "github.com/kubeedge/beehive/pkg/core" + "github.com/kubeedge/kubeedge/edge/pkg/common/dbm" + "github.com/kubeedge/kubeedge/edge/pkg/edged" + "github.com/kubeedge/kubeedge/edge/pkg/edgehub" + "github.com/kubeedge/kubeedge/edge/pkg/metamanager" + "github.com/kubeedge/kubeedge/pkg/apis/componentconfig/edgecore/v1alpha1" + "github.com/kubeedge/kubeedge/pkg/version/verflag" +) + +type hollowEdgeNodeConfig struct { + Token string + NodeName string + HTTPServer string + WebsocketServer string + NodeLabels map[string]string +} + +func main() { + command := newHollowEdgeNodeCommand() + if err := command.Execute(); err != nil { + os.Exit(1) + } +} + +// newHollowEdgeNodeCommand creates a *cobra.Command object with default parameters +func newHollowEdgeNodeCommand() *cobra.Command { + s := &hollowEdgeNodeConfig{ + NodeLabels: make(map[string]string), + } + + cmd := &cobra.Command{ + Use: "edgemark", + Long: "edgemark", + Run: func(cmd *cobra.Command, args []string) { + verflag.PrintAndExitIfRequested() + run(s) + }, + Args: func(cmd *cobra.Command, args []string) error { + for _, arg := range args { + if len(arg) > 0 { + return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args) + } + } + return nil + }, + } + + fs := cmd.Flags() + fs.AddGoFlagSet(flag.CommandLine) // for flags like --docker-only + s.addFlags(fs) + + return cmd +} + +func run(config *hollowEdgeNodeConfig) { + c := EdgeCoreConfig(config) + + // use fake runtime service + edged.DefaultGetRuntimeService = GetFakeRuntimeAndImageServices + + edged.Register(c.Modules.Edged) + edgehub.Register(c.Modules.EdgeHub, c.Modules.Edged.HostnameOverride) + metamanager.Register(c.Modules.MetaManager) + + dbm.InitDBConfig(c.DataBase.DriverName, c.DataBase.AliasName, c.DataBase.DataSource) + + // start all modules + core.Run() +} + +func (c *hollowEdgeNodeConfig) addFlags(fs *pflag.FlagSet) { + fs.StringVar(&c.Token, "token", "", "Token indicates the priority of joining the cluster for the edge.") + fs.StringVar(&c.NodeName, "name", "fake-node", "Name of this Hollow Node.") + fs.StringVar(&c.WebsocketServer, "websocket-server", "", "Server indicates websocket server address.") + fs.StringVar(&c.HTTPServer, "http-server", "", "HTTPServer indicates the server for edge to apply for the certificate.") + bindableNodeLabels := cliflag.ConfigurationMap(c.NodeLabels) + fs.Var(&bindableNodeLabels, "node-labels", "Additional node labels") +} + +func EdgeCoreConfig(config *hollowEdgeNodeConfig) *v1alpha1.EdgeCoreConfig { + edgeCoreConfig := v1alpha1.NewDefaultEdgeCoreConfig() + + // overWrite config + edgeCoreConfig.DataBase.DataSource = "/edgecore.db" + edgeCoreConfig.Modules.EdgeHub.Token = config.Token + edgeCoreConfig.Modules.EdgeHub.HTTPServer = config.HTTPServer + edgeCoreConfig.Modules.EdgeHub.WebSocket.Server = config.WebsocketServer + + // use fake runtime for test + edgeCoreConfig.Modules.Edged.RuntimeType = "fake" + edgeCoreConfig.Modules.Edged.RemoteRuntimeEndpoint = "/run/fake/fake.sock" + edgeCoreConfig.Modules.Edged.RemoteImageEndpoint = "/run/fake/fake.sock" + edgeCoreConfig.Modules.Edged.EnableMetrics = false + + edgeCoreConfig.Modules.Edged.HostnameOverride = config.NodeName + edgeCoreConfig.Modules.Edged.Labels = config.NodeLabels + + return edgeCoreConfig +} + +func GetFakeRuntimeAndImageServices( + remoteRuntimeEndpoint, + remoteImageEndpoint string, + runtimeRequestTimeout metav1.Duration) (internalapi.RuntimeService, internalapi.ImageManagerService, error) { + endpoint, err := fakeremote.GenerateEndpoint() + if err != nil { + return nil, nil, fmt.Errorf("failed to generate fake endpoint %v", err) + } + + fakeRemoteRuntime := fakeremote.NewFakeRemoteRuntime() + if err = fakeRemoteRuntime.Start(endpoint); err != nil { + return nil, nil, fmt.Errorf("failed to start fake runtime %v", err) + } + + runtimeService, err := remote.NewRemoteRuntimeService(endpoint, 15*time.Second) + if err != nil { + return nil, nil, fmt.Errorf("failed to init runtime service %v", err) + } + + return runtimeService, fakeRemoteRuntime.ImageService, err +} diff --git a/edge/pkg/edged/edged.go b/edge/pkg/edged/edged.go index 974674645..6039c1b8f 100644 --- a/edge/pkg/edged/edged.go +++ b/edge/pkg/edged/edged.go @@ -163,6 +163,13 @@ const ( ResolvConfDefault = "/etc/resolv.conf" ) +type GetRuntimeServiceFunc func( + remoteRuntimeEndpoint, + remoteImageEndpoint string, + runtimeRequestTimeout metav1.Duration) (internalapi.RuntimeService, internalapi.ImageManagerService, error) + +var DefaultGetRuntimeService GetRuntimeServiceFunc = getRuntimeAndImageServices + // podReady holds the initPodReady flag and its lock type podReady struct { // initPodReady is flag to check Pod ready status @@ -509,7 +516,7 @@ func newEdged(enable bool) (*edged, error) { ResolvConfDefault) httpClient := &http.Client{} - runtimeService, imageService, err := getRuntimeAndImageServices( + runtimeService, imageService, err := DefaultGetRuntimeService( edgedconfig.Config.RemoteRuntimeEndpoint, edgedconfig.Config.RemoteImageEndpoint, metav1.Duration{ @@ -518,6 +525,7 @@ func newEdged(enable bool) (*edged, error) { if err != nil { return nil, err } + if ed.os == nil { ed.os = kubecontainer.RealOS{} } diff --git a/hack/lib/golang.sh b/hack/lib/golang.sh index eaee5d42b..fe9288506 100755 --- a/hack/lib/golang.sh +++ b/hack/lib/golang.sh @@ -177,6 +177,7 @@ ALL_BINARIES_AND_TARGETS=( edgesite-server:edgesite/cmd/edgesite-server csidriver:cloud/cmd/csidriver iptablesmanager:cloud/cmd/iptablesmanager + edgemark:edge/cmd/edgemark ) kubeedge::golang::get_target_by_binary() { diff --git a/hack/make-rules/crossbuildimage.sh b/hack/make-rules/crossbuildimage.sh index 67f8d4e25..5d65b48b2 100755 --- a/hack/make-rules/crossbuildimage.sh +++ b/hack/make-rules/crossbuildimage.sh @@ -34,6 +34,7 @@ ALL_IMAGES_AND_TARGETS=( edgesite-server:edgesite-server:build/edgesite/server-build.Dockerfile csidriver:csidriver:build/csidriver/Dockerfile iptablesmanager:iptables-manager:build/iptablesmanager/Dockerfile + edgemark:edgemark:build/edgemark/Dockerfile ) function get_imagename_by_target() { @@ -82,7 +83,7 @@ function build_multi_arch_images() { DOCKERFILE_PATH="$(get_dockerfile_by_target ${arg})" set -x - + # If there's any issues when using buildx, can refer to the issue below # https://github.com/docker/buildx/issues/495 # https://github.com/multiarch/qemu-user-static/issues/100 diff --git a/hack/make-rules/image.sh b/hack/make-rules/image.sh index 49642be8b..f2067deed 100755 --- a/hack/make-rules/image.sh +++ b/hack/make-rules/image.sh @@ -31,6 +31,7 @@ ALL_IMAGES_AND_TARGETS=( edgesite-server:edgesite-server:build/edgesite/server-build.Dockerfile csidriver:csidriver:build/csidriver/Dockerfile iptablesmanager:iptables-manager:build/iptablesmanager/Dockerfile + edgemark:edgemark:build/edgemark/Dockerfile ) GO_LDFLAGS="$(${KUBEEDGE_ROOT}/hack/make-rules/version.sh)" diff --git a/vendor/k8s.io/cri-api/pkg/apis/testing/fake_image_service.go b/vendor/k8s.io/cri-api/pkg/apis/testing/fake_image_service.go new file mode 100644 index 000000000..17100abd3 --- /dev/null +++ b/vendor/k8s.io/cri-api/pkg/apis/testing/fake_image_service.go @@ -0,0 +1,230 @@ +/* +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 testing + +import ( + "sync" + "testing" + + "github.com/stretchr/testify/assert" + + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// FakeImageService fakes the image service. +type FakeImageService struct { + sync.Mutex + + FakeImageSize uint64 + Called []string + Errors map[string][]error + Images map[string]*runtimeapi.Image + + pulledImages []*pulledImage + + FakeFilesystemUsage []*runtimeapi.FilesystemUsage +} + +// SetFakeImages sets the list of fake images for the FakeImageService. +func (r *FakeImageService) SetFakeImages(images []string) { + r.Lock() + defer r.Unlock() + + r.Images = make(map[string]*runtimeapi.Image) + for _, image := range images { + r.Images[image] = r.makeFakeImage( + &runtimeapi.ImageSpec{ + Image: image, + Annotations: make(map[string]string)}) + } +} + +// SetFakeImagesWithAnnotations sets the list of fake images for the FakeImageService with annotations. +func (r *FakeImageService) SetFakeImagesWithAnnotations(imageSpecs []*runtimeapi.ImageSpec) { + r.Lock() + defer r.Unlock() + + r.Images = make(map[string]*runtimeapi.Image) + for _, imageSpec := range imageSpecs { + r.Images[imageSpec.Image] = r.makeFakeImage(imageSpec) + } +} + +// SetFakeImageSize sets the image size for the FakeImageService. +func (r *FakeImageService) SetFakeImageSize(size uint64) { + r.Lock() + defer r.Unlock() + + r.FakeImageSize = size +} + +// SetFakeFilesystemUsage sets the FilesystemUsage for FakeImageService. +func (r *FakeImageService) SetFakeFilesystemUsage(usage []*runtimeapi.FilesystemUsage) { + r.Lock() + defer r.Unlock() + + r.FakeFilesystemUsage = usage +} + +// NewFakeImageService creates a new FakeImageService. +func NewFakeImageService() *FakeImageService { + return &FakeImageService{ + Called: make([]string, 0), + Errors: make(map[string][]error), + Images: make(map[string]*runtimeapi.Image), + } +} + +func (r *FakeImageService) makeFakeImage(image *runtimeapi.ImageSpec) *runtimeapi.Image { + return &runtimeapi.Image{ + Id: image.Image, + Size_: r.FakeImageSize, + Spec: image, + RepoTags: []string{image.Image}, + } +} + +// stringInSlice returns true if s is in list +func stringInSlice(s string, list []string) bool { + for _, v := range list { + if v == s { + return true + } + } + + return false +} + +// InjectError sets the error message for the FakeImageService. +func (r *FakeImageService) InjectError(f string, err error) { + r.Lock() + defer r.Unlock() + r.Errors[f] = append(r.Errors[f], err) +} + +// caller of popError must grab a lock. +func (r *FakeImageService) popError(f string) error { + if r.Errors == nil { + return nil + } + errs := r.Errors[f] + if len(errs) == 0 { + return nil + } + err, errs := errs[0], errs[1:] + r.Errors[f] = errs + return err +} + +// ListImages returns the list of images from FakeImageService or error if it was previously set. +func (r *FakeImageService) ListImages(filter *runtimeapi.ImageFilter) ([]*runtimeapi.Image, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ListImages") + if err := r.popError("ListImages"); err != nil { + return nil, err + } + + images := make([]*runtimeapi.Image, 0) + for _, img := range r.Images { + if filter != nil && filter.Image != nil { + if !stringInSlice(filter.Image.Image, img.RepoTags) { + continue + } + } + + images = append(images, img) + } + return images, nil +} + +// ImageStatus returns the status of the image from the FakeImageService. +func (r *FakeImageService) ImageStatus(image *runtimeapi.ImageSpec) (*runtimeapi.Image, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ImageStatus") + if err := r.popError("ImageStatus"); err != nil { + return nil, err + } + + return r.Images[image.Image], nil +} + +// PullImage emulate pulling the image from the FakeImageService. +func (r *FakeImageService) PullImage(image *runtimeapi.ImageSpec, auth *runtimeapi.AuthConfig, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "PullImage") + if err := r.popError("PullImage"); err != nil { + return "", err + } + + r.pulledImages = append(r.pulledImages, &pulledImage{imageSpec: image, authConfig: auth}) + // ImageID should be randomized for real container runtime, but here just use + // image's name for easily making fake images. + imageID := image.Image + if _, ok := r.Images[imageID]; !ok { + r.Images[imageID] = r.makeFakeImage(image) + } + + return imageID, nil +} + +// RemoveImage removes image from the FakeImageService. +func (r *FakeImageService) RemoveImage(image *runtimeapi.ImageSpec) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "RemoveImage") + if err := r.popError("RemoveImage"); err != nil { + return err + } + + // Remove the image + delete(r.Images, image.Image) + + return nil +} + +// ImageFsInfo returns information of the filesystem that is used to store images. +func (r *FakeImageService) ImageFsInfo() ([]*runtimeapi.FilesystemUsage, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ImageFsInfo") + if err := r.popError("ImageFsInfo"); err != nil { + return nil, err + } + + return r.FakeFilesystemUsage, nil +} + +// AssertImagePulledWithAuth validates whether the image was pulled with auth and asserts if it wasn't. +func (r *FakeImageService) AssertImagePulledWithAuth(t *testing.T, image *runtimeapi.ImageSpec, auth *runtimeapi.AuthConfig, failMsg string) { + r.Lock() + defer r.Unlock() + expected := &pulledImage{imageSpec: image, authConfig: auth} + assert.Contains(t, r.pulledImages, expected, failMsg) +} + +type pulledImage struct { + imageSpec *runtimeapi.ImageSpec + authConfig *runtimeapi.AuthConfig +} diff --git a/vendor/k8s.io/cri-api/pkg/apis/testing/fake_runtime_service.go b/vendor/k8s.io/cri-api/pkg/apis/testing/fake_runtime_service.go new file mode 100644 index 000000000..dff770f4a --- /dev/null +++ b/vendor/k8s.io/cri-api/pkg/apis/testing/fake_runtime_service.go @@ -0,0 +1,636 @@ +/* +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 testing + +import ( + "fmt" + "reflect" + "sync" + "time" + + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +var ( + // FakeVersion is a version of a fake runtime. + FakeVersion = "0.1.0" + + // FakeRuntimeName is the name of the fake runtime. + FakeRuntimeName = "fakeRuntime" + + // FakePodSandboxIPs is an IP address of the fake runtime. + FakePodSandboxIPs = []string{"192.168.192.168"} +) + +// FakePodSandbox is the fake implementation of runtimeapi.PodSandboxStatus. +type FakePodSandbox struct { + // PodSandboxStatus contains the runtime information for a sandbox. + runtimeapi.PodSandboxStatus + // RuntimeHandler is the runtime handler that was issued with the RunPodSandbox request. + RuntimeHandler string +} + +// FakeContainer is a fake container. +type FakeContainer struct { + // ContainerStatus contains the runtime information for a container. + runtimeapi.ContainerStatus + + // LinuxResources contains the resources specific to linux containers. + LinuxResources *runtimeapi.LinuxContainerResources + + // the sandbox id of this container + SandboxID string +} + +// FakeRuntimeService is a fake runetime service. +type FakeRuntimeService struct { + sync.Mutex + + Called []string + Errors map[string][]error + + FakeStatus *runtimeapi.RuntimeStatus + Containers map[string]*FakeContainer + Sandboxes map[string]*FakePodSandbox + FakeContainerStats map[string]*runtimeapi.ContainerStats + + ErrorOnSandboxCreate bool +} + +// GetContainerID returns the unique container ID from the FakeRuntimeService. +func (r *FakeRuntimeService) GetContainerID(sandboxID, name string, attempt uint32) (string, error) { + r.Lock() + defer r.Unlock() + + for id, c := range r.Containers { + if c.SandboxID == sandboxID && c.Metadata.Name == name && c.Metadata.Attempt == attempt { + return id, nil + } + } + return "", fmt.Errorf("container (name, attempt, sandboxID)=(%q, %d, %q) not found", name, attempt, sandboxID) +} + +// SetFakeSandboxes sets the fake sandboxes for the FakeRuntimeService. +func (r *FakeRuntimeService) SetFakeSandboxes(sandboxes []*FakePodSandbox) { + r.Lock() + defer r.Unlock() + + r.Sandboxes = make(map[string]*FakePodSandbox) + for _, sandbox := range sandboxes { + sandboxID := sandbox.Id + r.Sandboxes[sandboxID] = sandbox + } +} + +// SetFakeContainers sets fake containers for the FakeRuntimeService. +func (r *FakeRuntimeService) SetFakeContainers(containers []*FakeContainer) { + r.Lock() + defer r.Unlock() + + r.Containers = make(map[string]*FakeContainer) + for _, c := range containers { + containerID := c.Id + r.Containers[containerID] = c + } + +} + +// AssertCalls validates whether specified calls were made to the FakeRuntimeService. +func (r *FakeRuntimeService) AssertCalls(calls []string) error { + r.Lock() + defer r.Unlock() + + if !reflect.DeepEqual(calls, r.Called) { + return fmt.Errorf("expected %#v, got %#v", calls, r.Called) + } + return nil +} + +// GetCalls returns the list of calls made to the FakeRuntimeService. +func (r *FakeRuntimeService) GetCalls() []string { + r.Lock() + defer r.Unlock() + return append([]string{}, r.Called...) +} + +// InjectError inject the error to the next call to the FakeRuntimeService. +func (r *FakeRuntimeService) InjectError(f string, err error) { + r.Lock() + defer r.Unlock() + r.Errors[f] = append(r.Errors[f], err) +} + +// caller of popError must grab a lock. +func (r *FakeRuntimeService) popError(f string) error { + if r.Errors == nil { + return nil + } + errs := r.Errors[f] + if len(errs) == 0 { + return nil + } + err, errs := errs[0], errs[1:] + r.Errors[f] = errs + return err +} + +// NewFakeRuntimeService creates a new FakeRuntimeService. +func NewFakeRuntimeService() *FakeRuntimeService { + return &FakeRuntimeService{ + Called: make([]string, 0), + Errors: make(map[string][]error), + Containers: make(map[string]*FakeContainer), + Sandboxes: make(map[string]*FakePodSandbox), + FakeContainerStats: make(map[string]*runtimeapi.ContainerStats), + } +} + +// Version returns version information from the FakeRuntimeService. +func (r *FakeRuntimeService) Version(apiVersion string) (*runtimeapi.VersionResponse, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "Version") + if err := r.popError("Version"); err != nil { + return nil, err + } + + return &runtimeapi.VersionResponse{ + Version: FakeVersion, + RuntimeName: FakeRuntimeName, + RuntimeVersion: FakeVersion, + RuntimeApiVersion: FakeVersion, + }, nil +} + +// Status returns runtime status of the FakeRuntimeService. +func (r *FakeRuntimeService) Status() (*runtimeapi.RuntimeStatus, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "Status") + if err := r.popError("Status"); err != nil { + return nil, err + } + + return r.FakeStatus, nil +} + +// RunPodSandbox emulates the run of the pod sandbox in the FakeRuntimeService. +func (r *FakeRuntimeService) RunPodSandbox(config *runtimeapi.PodSandboxConfig, runtimeHandler string) (string, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "RunPodSandbox") + if err := r.popError("RunPodSandbox"); err != nil { + return "", err + } + + if r.ErrorOnSandboxCreate { + return "", fmt.Errorf("error on sandbox create") + } + + // PodSandboxID should be randomized for real container runtime, but here just use + // fixed name from BuildSandboxName() for easily making fake sandboxes. + podSandboxID := BuildSandboxName(config.Metadata) + createdAt := time.Now().UnixNano() + r.Sandboxes[podSandboxID] = &FakePodSandbox{ + PodSandboxStatus: runtimeapi.PodSandboxStatus{ + Id: podSandboxID, + Metadata: config.Metadata, + State: runtimeapi.PodSandboxState_SANDBOX_READY, + CreatedAt: createdAt, + Network: &runtimeapi.PodSandboxNetworkStatus{ + Ip: FakePodSandboxIPs[0], + }, + // Without setting sandboxStatus's Linux.Namespaces.Options, kubeGenericRuntimeManager's podSandboxChanged will consider it as network + // namespace changed and always recreate sandbox which causes pod creation failed. + // Ref `sandboxStatus.GetLinux().GetNamespaces().GetOptions().GetNetwork() != networkNamespaceForPod(pod)` in podSandboxChanged function. + Linux: &runtimeapi.LinuxPodSandboxStatus{ + Namespaces: &runtimeapi.Namespace{ + Options: config.GetLinux().GetSecurityContext().GetNamespaceOptions(), + }, + }, + Labels: config.Labels, + Annotations: config.Annotations, + RuntimeHandler: runtimeHandler, + }, + RuntimeHandler: runtimeHandler, + } + // assign additional IPs + additionalIPs := FakePodSandboxIPs[1:] + additionalPodIPs := make([]*runtimeapi.PodIP, 0, len(additionalIPs)) + for _, ip := range additionalIPs { + additionalPodIPs = append(additionalPodIPs, &runtimeapi.PodIP{ + Ip: ip, + }) + } + r.Sandboxes[podSandboxID].PodSandboxStatus.Network.AdditionalIps = additionalPodIPs + return podSandboxID, nil +} + +// StopPodSandbox emulates the stop of pod sandbox in the FakeRuntimeService. +func (r *FakeRuntimeService) StopPodSandbox(podSandboxID string) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "StopPodSandbox") + if err := r.popError("StopPodSandbox"); err != nil { + return err + } + + if s, ok := r.Sandboxes[podSandboxID]; ok { + s.State = runtimeapi.PodSandboxState_SANDBOX_NOTREADY + } else { + return fmt.Errorf("pod sandbox %s not found", podSandboxID) + } + + return nil +} + +// RemovePodSandbox emulates removal of the pod sadbox in the FakeRuntimeService. +func (r *FakeRuntimeService) RemovePodSandbox(podSandboxID string) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "RemovePodSandbox") + if err := r.popError("RemovePodSandbox"); err != nil { + return err + } + + // Remove the pod sandbox + delete(r.Sandboxes, podSandboxID) + + return nil +} + +// PodSandboxStatus returns pod sandbox status from the FakeRuntimeService. +func (r *FakeRuntimeService) PodSandboxStatus(podSandboxID string) (*runtimeapi.PodSandboxStatus, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "PodSandboxStatus") + if err := r.popError("PodSandboxStatus"); err != nil { + return nil, err + } + + s, ok := r.Sandboxes[podSandboxID] + if !ok { + return nil, fmt.Errorf("pod sandbox %q not found", podSandboxID) + } + + status := s.PodSandboxStatus + return &status, nil +} + +// ListPodSandbox returns the list of pod sandboxes in the FakeRuntimeService. +func (r *FakeRuntimeService) ListPodSandbox(filter *runtimeapi.PodSandboxFilter) ([]*runtimeapi.PodSandbox, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ListPodSandbox") + if err := r.popError("ListPodSandbox"); err != nil { + return nil, err + } + + result := make([]*runtimeapi.PodSandbox, 0) + for id, s := range r.Sandboxes { + if filter != nil { + if filter.Id != "" && filter.Id != id { + continue + } + if filter.State != nil && filter.GetState().State != s.State { + continue + } + if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, s.GetLabels()) { + continue + } + } + + result = append(result, &runtimeapi.PodSandbox{ + Id: s.Id, + Metadata: s.Metadata, + State: s.State, + CreatedAt: s.CreatedAt, + Labels: s.Labels, + Annotations: s.Annotations, + RuntimeHandler: s.RuntimeHandler, + }) + } + + return result, nil +} + +// PortForward emulates the set up of port forward in the FakeRuntimeService. +func (r *FakeRuntimeService) PortForward(*runtimeapi.PortForwardRequest) (*runtimeapi.PortForwardResponse, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "PortForward") + if err := r.popError("PortForward"); err != nil { + return nil, err + } + + return &runtimeapi.PortForwardResponse{}, nil +} + +// CreateContainer emulates container creation in the FakeRuntimeService. +func (r *FakeRuntimeService) CreateContainer(podSandboxID string, config *runtimeapi.ContainerConfig, sandboxConfig *runtimeapi.PodSandboxConfig) (string, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "CreateContainer") + if err := r.popError("CreateContainer"); err != nil { + return "", err + } + + // ContainerID should be randomized for real container runtime, but here just use + // fixed BuildContainerName() for easily making fake containers. + containerID := BuildContainerName(config.Metadata, podSandboxID) + createdAt := time.Now().UnixNano() + createdState := runtimeapi.ContainerState_CONTAINER_CREATED + imageRef := config.Image.Image + r.Containers[containerID] = &FakeContainer{ + ContainerStatus: runtimeapi.ContainerStatus{ + Id: containerID, + Metadata: config.Metadata, + Image: config.Image, + ImageRef: imageRef, + CreatedAt: createdAt, + State: createdState, + Labels: config.Labels, + Annotations: config.Annotations, + }, + SandboxID: podSandboxID, + LinuxResources: config.GetLinux().GetResources(), + } + + return containerID, nil +} + +// StartContainer emulates start of a container in the FakeRuntimeService. +func (r *FakeRuntimeService) StartContainer(containerID string) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "StartContainer") + if err := r.popError("StartContainer"); err != nil { + return err + } + + c, ok := r.Containers[containerID] + if !ok { + return fmt.Errorf("container %s not found", containerID) + } + + // Set container to running. + c.State = runtimeapi.ContainerState_CONTAINER_RUNNING + c.StartedAt = time.Now().UnixNano() + + return nil +} + +// StopContainer emulates stop of a container in the FakeRuntimeService. +func (r *FakeRuntimeService) StopContainer(containerID string, timeout int64) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "StopContainer") + if err := r.popError("StopContainer"); err != nil { + return err + } + + c, ok := r.Containers[containerID] + if !ok { + return fmt.Errorf("container %q not found", containerID) + } + + // Set container to exited state. + finishedAt := time.Now().UnixNano() + exitedState := runtimeapi.ContainerState_CONTAINER_EXITED + c.State = exitedState + c.FinishedAt = finishedAt + + return nil +} + +// RemoveContainer emulates remove of a container in the FakeRuntimeService. +func (r *FakeRuntimeService) RemoveContainer(containerID string) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "RemoveContainer") + if err := r.popError("RemoveContainer"); err != nil { + return err + } + + // Remove the container + delete(r.Containers, containerID) + + return nil +} + +// ListContainers returns the list of containers in the FakeRuntimeService. +func (r *FakeRuntimeService) ListContainers(filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ListContainers") + if err := r.popError("ListContainers"); err != nil { + return nil, err + } + + result := make([]*runtimeapi.Container, 0) + for _, s := range r.Containers { + if filter != nil { + if filter.Id != "" && filter.Id != s.Id { + continue + } + if filter.PodSandboxId != "" && filter.PodSandboxId != s.SandboxID { + continue + } + if filter.State != nil && filter.GetState().State != s.State { + continue + } + if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, s.GetLabels()) { + continue + } + } + + result = append(result, &runtimeapi.Container{ + Id: s.Id, + CreatedAt: s.CreatedAt, + PodSandboxId: s.SandboxID, + Metadata: s.Metadata, + State: s.State, + Image: s.Image, + ImageRef: s.ImageRef, + Labels: s.Labels, + Annotations: s.Annotations, + }) + } + + return result, nil +} + +// ContainerStatus returns the container status given the container ID in FakeRuntimeService. +func (r *FakeRuntimeService) ContainerStatus(containerID string) (*runtimeapi.ContainerStatus, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ContainerStatus") + if err := r.popError("ContainerStatus"); err != nil { + return nil, err + } + + c, ok := r.Containers[containerID] + if !ok { + return nil, fmt.Errorf("container %q not found", containerID) + } + + status := c.ContainerStatus + return &status, nil +} + +// UpdateContainerResources returns the container resource in the FakeRuntimeService. +func (r *FakeRuntimeService) UpdateContainerResources(string, *runtimeapi.LinuxContainerResources) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "UpdateContainerResources") + return r.popError("UpdateContainerResources") +} + +// ExecSync emulates the sync execution of a command in a container in the FakeRuntimeService. +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") + err = r.popError("ExecSync") + return +} + +// Exec emulates the execution of a command in a container in the FakeRuntimeService. +func (r *FakeRuntimeService) Exec(*runtimeapi.ExecRequest) (*runtimeapi.ExecResponse, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "Exec") + if err := r.popError("Exec"); err != nil { + return nil, err + } + + return &runtimeapi.ExecResponse{}, nil +} + +// Attach emulates the attach request in the FakeRuntimeService. +func (r *FakeRuntimeService) Attach(req *runtimeapi.AttachRequest) (*runtimeapi.AttachResponse, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "Attach") + if err := r.popError("Attach"); err != nil { + return nil, err + } + + return &runtimeapi.AttachResponse{}, nil +} + +// UpdateRuntimeConfig emulates the update of a runtime config for the FakeRuntimeService. +func (r *FakeRuntimeService) UpdateRuntimeConfig(runtimeCOnfig *runtimeapi.RuntimeConfig) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "UpdateRuntimeConfig") + return r.popError("UpdateRuntimeConfig") +} + +// SetFakeContainerStats sets the fake container stats in the FakeRuntimeService. +func (r *FakeRuntimeService) SetFakeContainerStats(containerStats []*runtimeapi.ContainerStats) { + r.Lock() + defer r.Unlock() + + r.FakeContainerStats = make(map[string]*runtimeapi.ContainerStats) + for _, s := range containerStats { + r.FakeContainerStats[s.Attributes.Id] = s + } +} + +// ContainerStats returns the container stats in the FakeRuntimeService. +func (r *FakeRuntimeService) ContainerStats(containerID string) (*runtimeapi.ContainerStats, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ContainerStats") + if err := r.popError("ContainerStats"); err != nil { + return nil, err + } + + s, found := r.FakeContainerStats[containerID] + if !found { + return nil, fmt.Errorf("no stats for container %q", containerID) + } + return s, nil +} + +// ListContainerStats returns the list of all container stats given the filter in the FakeRuntimeService. +func (r *FakeRuntimeService) ListContainerStats(filter *runtimeapi.ContainerStatsFilter) ([]*runtimeapi.ContainerStats, error) { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ListContainerStats") + if err := r.popError("ListContainerStats"); err != nil { + return nil, err + } + + var result []*runtimeapi.ContainerStats + for _, c := range r.Containers { + if filter != nil { + if filter.Id != "" && filter.Id != c.Id { + continue + } + if filter.PodSandboxId != "" && filter.PodSandboxId != c.SandboxID { + continue + } + if filter.LabelSelector != nil && !filterInLabels(filter.LabelSelector, c.GetLabels()) { + continue + } + } + s, found := r.FakeContainerStats[c.Id] + if !found { + continue + } + result = append(result, s) + } + + return result, nil +} + +// ReopenContainerLog emulates call to the reopen container log in the FakeRuntimeService. +func (r *FakeRuntimeService) ReopenContainerLog(containerID string) error { + r.Lock() + defer r.Unlock() + + r.Called = append(r.Called, "ReopenContainerLog") + + if err := r.popError("ReopenContainerLog"); err != nil { + return err + } + + return nil +} diff --git a/vendor/k8s.io/cri-api/pkg/apis/testing/utils.go b/vendor/k8s.io/cri-api/pkg/apis/testing/utils.go new file mode 100644 index 000000000..5b3814e9d --- /dev/null +++ b/vendor/k8s.io/cri-api/pkg/apis/testing/utils.go @@ -0,0 +1,48 @@ +/* +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 testing + +import ( + "fmt" + + runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// BuildContainerName creates a unique container name string. +func BuildContainerName(metadata *runtimeapi.ContainerMetadata, sandboxID string) string { + // include the sandbox ID to make the container ID unique. + return fmt.Sprintf("%s_%s_%d", sandboxID, metadata.Name, metadata.Attempt) +} + +// BuildSandboxName creates a unique sandbox name string. +func BuildSandboxName(metadata *runtimeapi.PodSandboxMetadata) string { + return fmt.Sprintf("%s_%s_%s_%d", metadata.Name, metadata.Namespace, metadata.Uid, metadata.Attempt) +} + +func filterInLabels(filter, labels map[string]string) bool { + for k, v := range filter { + if value, ok := labels[k]; ok { + if value != v { + return false + } + } else { + return false + } + } + + return true +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/doc.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/doc.go new file mode 100644 index 000000000..fc92f3c76 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/doc.go @@ -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 diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/endpoint.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/endpoint.go new file mode 100644 index 000000000..52ef573bf --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/endpoint.go @@ -0,0 +1,34 @@ +// +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" + "k8s.io/apimachinery/pkg/util/rand" +) + +const ( + defaultUnixEndpoint = "unix:///tmp/kubelet_remote_%v.sock" +) + +// GenerateEndpoint generates a new unix socket server of grpc server. +func GenerateEndpoint() (string, error) { + // use random int be a part fo file name + return fmt.Sprintf(defaultUnixEndpoint, rand.Int()), nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/endpoint_windows.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/endpoint_windows.go new file mode 100644 index 000000000..cb43296bc --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/endpoint_windows.go @@ -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 +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/fake_image_service.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/fake_image_service.go new file mode 100644 index 000000000..c85f9ecf9 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/fake_image_service.go @@ -0,0 +1,81 @@ +/* +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 ( + "context" + + kubeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" +) + +// 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, req.SandboxConfig) + 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 +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/fake_runtime.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/fake_runtime.go new file mode 100644 index 000000000..e49f311aa --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cri/remote/fake/fake_runtime.go @@ -0,0 +1,303 @@ +/* +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 ( + "context" + "fmt" + "time" + + "google.golang.org/grpc" + kubeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" + apitest "k8s.io/cri-api/pkg/apis/testing" + "k8s.io/kubernetes/pkg/kubelet/cri/remote/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) + } + + go f.server.Serve(l) + + // Set runtime and network conditions ready. + f.RuntimeService.FakeStatus = &kubeapi.RuntimeStatus{ + Conditions: []*kubeapi.RuntimeCondition{ + {Type: kubeapi.RuntimeReady, Status: true}, + {Type: kubeapi.NetworkReady, Status: true}, + }, + } + + return nil +} + +// 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, req.RuntimeHandler) + 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 &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 +} + +// ReopenContainerLog reopens the container log file. +func (f *RemoteRuntime) ReopenContainerLog(ctx context.Context, req *kubeapi.ReopenContainerLogRequest) (*kubeapi.ReopenContainerLogResponse, error) { + err := f.RuntimeService.ReopenContainerLog(req.ContainerId) + if err != nil { + return nil, err + } + + return &kubeapi.ReopenContainerLogResponse{}, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e4d19c035..22ce229fd 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1625,6 +1625,7 @@ k8s.io/component-helpers/storage/volume ## explicit k8s.io/cri-api/pkg/apis k8s.io/cri-api/pkg/apis/runtime/v1alpha2 +k8s.io/cri-api/pkg/apis/testing # k8s.io/csi-translation-lib v0.22.6 ## explicit k8s.io/csi-translation-lib @@ -1819,6 +1820,7 @@ k8s.io/kubernetes/pkg/kubelet/configmap k8s.io/kubernetes/pkg/kubelet/container k8s.io/kubernetes/pkg/kubelet/container/testing k8s.io/kubernetes/pkg/kubelet/cri/remote +k8s.io/kubernetes/pkg/kubelet/cri/remote/fake k8s.io/kubernetes/pkg/kubelet/cri/remote/util k8s.io/kubernetes/pkg/kubelet/cri/streaming k8s.io/kubernetes/pkg/kubelet/cri/streaming/portforward |
