summaryrefslogtreecommitdiffhomepage
path: root/pkg/test/criutil/criutil.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/test/criutil/criutil.go')
-rw-r--r--pkg/test/criutil/criutil.go372
1 files changed, 0 insertions, 372 deletions
diff --git a/pkg/test/criutil/criutil.go b/pkg/test/criutil/criutil.go
deleted file mode 100644
index 3b41a2824..000000000
--- a/pkg/test/criutil/criutil.go
+++ /dev/null
@@ -1,372 +0,0 @@
-// Copyright 2018 The gVisor 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 criutil contains utility functions for interacting with the
-// Container Runtime Interface (CRI), principally via the crictl command line
-// tool. This requires critools to be installed on the local system.
-package criutil
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "os/exec"
- "path"
- "regexp"
- "strconv"
- "strings"
- "time"
-
- "gvisor.dev/gvisor/pkg/test/dockerutil"
- "gvisor.dev/gvisor/pkg/test/testutil"
-)
-
-// Crictl contains information required to run the crictl utility.
-type Crictl struct {
- logger testutil.Logger
- endpoint string
- cleanup []func()
-}
-
-// ResolvePath attempts to find binary paths. It may set the path to invalid,
-// which will cause the execution to fail with a sensible error.
-func ResolvePath(executable string) string {
- runtime, err := dockerutil.RuntimePath()
- if err == nil {
- // Check first the directory of the runtime itself.
- if dir := path.Dir(runtime); dir != "" && dir != "." {
- guess := path.Join(dir, executable)
- if fi, err := os.Stat(guess); err == nil && (fi.Mode()&0111) != 0 {
- return guess
- }
- }
- }
-
- // Favor /usr/local/bin, if it exists.
- localBin := fmt.Sprintf("/usr/local/bin/%s", executable)
- if _, err := os.Stat(localBin); err == nil {
- return localBin
- }
-
- // Try to find via the path.
- guess, _ := exec.LookPath(executable)
- if err == nil {
- return guess
- }
-
- // Return a bare path; this generates a suitable error.
- return executable
-}
-
-// NewCrictl returns a Crictl configured with a timeout and an endpoint over
-// which it will talk to containerd.
-func NewCrictl(logger testutil.Logger, endpoint string) *Crictl {
- // Attempt to find the executable, but don't bother propagating the
- // error at this point. The first command executed will return with a
- // binary not found error.
- return &Crictl{
- logger: logger,
- endpoint: endpoint,
- }
-}
-
-// CleanUp executes cleanup functions.
-func (cc *Crictl) CleanUp() {
- for _, c := range cc.cleanup {
- c()
- }
- cc.cleanup = nil
-}
-
-// RunPod creates a sandbox. It corresponds to `crictl runp`.
-func (cc *Crictl) RunPod(runtime, sbSpecFile string) (string, error) {
- podID, err := cc.run("runp", "--runtime", runtime, sbSpecFile)
- if err != nil {
- return "", fmt.Errorf("runp failed: %v", err)
- }
- // Strip the trailing newline from crictl output.
- return strings.TrimSpace(podID), nil
-}
-
-// Create creates a container within a sandbox. It corresponds to `crictl
-// create`.
-func (cc *Crictl) Create(podID, contSpecFile, sbSpecFile string) (string, error) {
- // In version 1.16.0, crictl annoying starting attempting to pull the
- // container, even if it was already available locally. We therefore
- // need to parse the version and add an appropriate --no-pull argument
- // since the image has already been loaded locally.
- out, err := cc.run("-v")
- if err != nil {
- return "", err
- }
- r := regexp.MustCompile("crictl version ([0-9]+)\\.([0-9]+)\\.([0-9+])")
- vs := r.FindStringSubmatch(out)
- if len(vs) != 4 {
- return "", fmt.Errorf("crictl -v had unexpected output: %s", out)
- }
- major, err := strconv.ParseUint(vs[1], 10, 64)
- if err != nil {
- return "", fmt.Errorf("crictl had invalid version: %v (%s)", err, out)
- }
- minor, err := strconv.ParseUint(vs[2], 10, 64)
- if err != nil {
- return "", fmt.Errorf("crictl had invalid version: %v (%s)", err, out)
- }
-
- args := []string{"create"}
- if (major == 1 && minor >= 16) || major > 1 {
- args = append(args, "--no-pull")
- }
- args = append(args, podID)
- args = append(args, contSpecFile)
- args = append(args, sbSpecFile)
-
- podID, err = cc.run(args...)
- if err != nil {
- time.Sleep(10 * time.Minute) // XXX
- return "", fmt.Errorf("create failed: %v", err)
- }
-
- // Strip the trailing newline from crictl output.
- return strings.TrimSpace(podID), nil
-}
-
-// Start starts a container. It corresponds to `crictl start`.
-func (cc *Crictl) Start(contID string) (string, error) {
- output, err := cc.run("start", contID)
- if err != nil {
- return "", fmt.Errorf("start failed: %v", err)
- }
- return output, nil
-}
-
-// Stop stops a container. It corresponds to `crictl stop`.
-func (cc *Crictl) Stop(contID string) error {
- _, err := cc.run("stop", contID)
- return err
-}
-
-// Exec execs a program inside a container. It corresponds to `crictl exec`.
-func (cc *Crictl) Exec(contID string, args ...string) (string, error) {
- a := []string{"exec", contID}
- a = append(a, args...)
- output, err := cc.run(a...)
- if err != nil {
- return "", fmt.Errorf("exec failed: %v", err)
- }
- return output, nil
-}
-
-// Logs retrieves the container logs. It corresponds to `crictl logs`.
-func (cc *Crictl) Logs(contID string, args ...string) (string, error) {
- a := []string{"logs", contID}
- a = append(a, args...)
- output, err := cc.run(a...)
- if err != nil {
- return "", fmt.Errorf("logs failed: %v", err)
- }
- return output, nil
-}
-
-// Rm removes a container. It corresponds to `crictl rm`.
-func (cc *Crictl) Rm(contID string) error {
- _, err := cc.run("rm", contID)
- return err
-}
-
-// StopPod stops a pod. It corresponds to `crictl stopp`.
-func (cc *Crictl) StopPod(podID string) error {
- _, err := cc.run("stopp", podID)
- return err
-}
-
-// containsConfig is a minimal copy of
-// https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/apis/cri/runtime/v1alpha2/api.proto
-// It only contains fields needed for testing.
-type containerConfig struct {
- Status containerStatus
-}
-
-type containerStatus struct {
- Network containerNetwork
-}
-
-type containerNetwork struct {
- IP string
-}
-
-// PodIP returns a pod's IP address.
-func (cc *Crictl) PodIP(podID string) (string, error) {
- output, err := cc.run("inspectp", podID)
- if err != nil {
- return "", err
- }
- conf := &containerConfig{}
- if err := json.Unmarshal([]byte(output), conf); err != nil {
- return "", fmt.Errorf("failed to unmarshal JSON: %v, %s", err, output)
- }
- if conf.Status.Network.IP == "" {
- return "", fmt.Errorf("no IP found in config: %s", output)
- }
- return conf.Status.Network.IP, nil
-}
-
-// RmPod removes a container. It corresponds to `crictl rmp`.
-func (cc *Crictl) RmPod(podID string) error {
- _, err := cc.run("rmp", podID)
- return err
-}
-
-// Import imports the given container from the local Docker instance.
-func (cc *Crictl) Import(image string) error {
- // Note that we provide a 10 minute timeout after connect because we may
- // be pushing a lot of bytes in order to import the image. The connect
- // timeout stays the same and is inherited from the Crictl instance.
- cmd := testutil.Command(cc.logger,
- ResolvePath("ctr"),
- fmt.Sprintf("--connect-timeout=%s", 30*time.Second),
- fmt.Sprintf("--address=%s", cc.endpoint),
- "-n", "k8s.io", "images", "import", "-")
- cmd.Stderr = os.Stderr // Pass through errors.
-
- // Create a pipe and start the program.
- w, err := cmd.StdinPipe()
- if err != nil {
- return err
- }
- if err := cmd.Start(); err != nil {
- return err
- }
-
- // Save the image on the other end.
- if err := dockerutil.Save(cc.logger, image, w); err != nil {
- cmd.Wait()
- return err
- }
-
- // Close our pipe reference & see if it was loaded.
- if err := w.Close(); err != nil {
- return w.Close()
- }
-
- return cmd.Wait()
-}
-
-// StartContainer pulls the given image ands starts the container in the
-// sandbox with the given podID.
-//
-// Note that the image will always be imported from the local docker daemon.
-func (cc *Crictl) StartContainer(podID, image, sbSpec, contSpec string) (string, error) {
- if err := cc.Import(image); err != nil {
- return "", err
- }
-
- // Write the specs to files that can be read by crictl.
- sbSpecFile, cleanup, err := testutil.WriteTmpFile("sbSpec", sbSpec)
- if err != nil {
- return "", fmt.Errorf("failed to write sandbox spec: %v", err)
- }
- cc.cleanup = append(cc.cleanup, cleanup)
- contSpecFile, cleanup, err := testutil.WriteTmpFile("contSpec", contSpec)
- if err != nil {
- return "", fmt.Errorf("failed to write container spec: %v", err)
- }
- cc.cleanup = append(cc.cleanup, cleanup)
-
- return cc.startContainer(podID, image, sbSpecFile, contSpecFile)
-}
-
-func (cc *Crictl) startContainer(podID, image, sbSpecFile, contSpecFile string) (string, error) {
- contID, err := cc.Create(podID, contSpecFile, sbSpecFile)
- if err != nil {
- return "", fmt.Errorf("failed to create container in pod %q: %v", podID, err)
- }
-
- if _, err := cc.Start(contID); err != nil {
- return "", fmt.Errorf("failed to start container %q in pod %q: %v", contID, podID, err)
- }
-
- return contID, nil
-}
-
-// StopContainer stops and deletes the container with the given container ID.
-func (cc *Crictl) StopContainer(contID string) error {
- if err := cc.Stop(contID); err != nil {
- return fmt.Errorf("failed to stop container %q: %v", contID, err)
- }
-
- if err := cc.Rm(contID); err != nil {
- return fmt.Errorf("failed to remove container %q: %v", contID, err)
- }
-
- return nil
-}
-
-// StartPodAndContainer starts a sandbox and container in that sandbox. It
-// returns the pod ID and container ID.
-func (cc *Crictl) StartPodAndContainer(runtime, image, sbSpec, contSpec string) (string, string, error) {
- if err := cc.Import(image); err != nil {
- return "", "", err
- }
-
- // Write the specs to files that can be read by crictl.
- sbSpecFile, cleanup, err := testutil.WriteTmpFile("sbSpec", sbSpec)
- if err != nil {
- return "", "", fmt.Errorf("failed to write sandbox spec: %v", err)
- }
- cc.cleanup = append(cc.cleanup, cleanup)
- contSpecFile, cleanup, err := testutil.WriteTmpFile("contSpec", contSpec)
- if err != nil {
- return "", "", fmt.Errorf("failed to write container spec: %v", err)
- }
- cc.cleanup = append(cc.cleanup, cleanup)
-
- podID, err := cc.RunPod(runtime, sbSpecFile)
- if err != nil {
- return "", "", err
- }
-
- contID, err := cc.startContainer(podID, image, sbSpecFile, contSpecFile)
-
- return podID, contID, err
-}
-
-// StopPodAndContainer stops a container and pod.
-func (cc *Crictl) StopPodAndContainer(podID, contID string) error {
- if err := cc.StopContainer(contID); err != nil {
- return fmt.Errorf("failed to stop container %q in pod %q: %v", contID, podID, err)
- }
-
- if err := cc.StopPod(podID); err != nil {
- return fmt.Errorf("failed to stop pod %q: %v", podID, err)
- }
-
- if err := cc.RmPod(podID); err != nil {
- return fmt.Errorf("failed to remove pod %q: %v", podID, err)
- }
-
- return nil
-}
-
-// run runs crictl with the given args.
-func (cc *Crictl) run(args ...string) (string, error) {
- defaultArgs := []string{
- ResolvePath("crictl"),
- "--image-endpoint", fmt.Sprintf("unix://%s", cc.endpoint),
- "--runtime-endpoint", fmt.Sprintf("unix://%s", cc.endpoint),
- }
- fullArgs := append(defaultArgs, args...)
- out, err := testutil.Command(cc.logger, fullArgs...).CombinedOutput()
- return string(out), err
-}