mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Merge pull request #825 from brendandburns/runin
Add support for "run in"
This commit is contained in:
		@@ -20,6 +20,7 @@ import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
 | 
			
		||||
@@ -63,6 +64,30 @@ func NewDockerPuller(client DockerInterface) DockerPuller {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type dockerContainerCommandRunner struct{}
 | 
			
		||||
 | 
			
		||||
func (d *dockerContainerCommandRunner) getRunInContainerCommand(containerID string, cmd []string) (*exec.Cmd, error) {
 | 
			
		||||
	args := append([]string{"exec"}, cmd...)
 | 
			
		||||
	command := exec.Command("/usr/sbin/nsinit", args...)
 | 
			
		||||
	command.Dir = fmt.Sprintf("/var/lib/docker/execdriver/native/%s", containerID)
 | 
			
		||||
	return command, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunInContainer uses nsinit to run the command inside the container identified by containerID
 | 
			
		||||
func (d *dockerContainerCommandRunner) RunInContainer(containerID string, cmd []string) ([]byte, error) {
 | 
			
		||||
	c, err := d.getRunInContainerCommand(containerID, cmd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return c.CombinedOutput()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewDockerContainerCommandRunner creates a ContainerCommandRunner which uses nsinit to run a command
 | 
			
		||||
// inside a container.
 | 
			
		||||
func NewDockerContainerCommandRunner() ContainerCommandRunner {
 | 
			
		||||
	return &dockerContainerCommandRunner{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p dockerPuller) Pull(image string) error {
 | 
			
		||||
	image, tag := parseImageName(image)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -89,6 +89,10 @@ func NewIntegrationTestKubelet(hn string, dc DockerInterface) *Kubelet {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ContainerCommandRunner interface {
 | 
			
		||||
	RunInContainer(containerID string, cmd []string) ([]byte, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Kubelet is the main kubelet implementation.
 | 
			
		||||
type Kubelet struct {
 | 
			
		||||
	hostname       string
 | 
			
		||||
@@ -107,6 +111,8 @@ type Kubelet struct {
 | 
			
		||||
	dockerPuller DockerPuller
 | 
			
		||||
	// Optional, defaults to /logs/ from /var/log
 | 
			
		||||
	logServer http.Handler
 | 
			
		||||
	// Optional, defaults to simple Docker implementation
 | 
			
		||||
	runner ContainerCommandRunner
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Run starts the kubelet reacting to config updates
 | 
			
		||||
@@ -666,3 +672,20 @@ func (kl *Kubelet) ServeLogs(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	// TODO: whitelist logs we are willing to serve
 | 
			
		||||
	kl.logServer.ServeHTTP(w, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Run a command in a container, returns the combined stdout, stderr as an array of bytes
 | 
			
		||||
func (kl *Kubelet) RunInContainer(pod *Pod, container string, cmd []string) ([]byte, error) {
 | 
			
		||||
	if kl.runner == nil {
 | 
			
		||||
		return nil, fmt.Errorf("no runner specified.")
 | 
			
		||||
	}
 | 
			
		||||
	podFullName := GetPodFullName(pod)
 | 
			
		||||
	dockerContainers, err := getKubeletDockerContainers(kl.dockerClient)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	dockerContainer, found := dockerContainers.FindPodContainer(podFullName, container)
 | 
			
		||||
	if !found {
 | 
			
		||||
		return nil, fmt.Errorf("container not found (%s)", container)
 | 
			
		||||
	}
 | 
			
		||||
	return kl.runner.RunInContainer(dockerContainer.ID, cmd)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -843,6 +843,86 @@ func TestGetContainerInfoOnNonExistContainer(t *testing.T) {
 | 
			
		||||
	mockCadvisor.AssertExpectations(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type fakeContainerCommandRunner struct {
 | 
			
		||||
	Cmd []string
 | 
			
		||||
	ID  string
 | 
			
		||||
	E   error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *fakeContainerCommandRunner) RunInContainer(id string, cmd []string) ([]byte, error) {
 | 
			
		||||
	f.Cmd = cmd
 | 
			
		||||
	f.ID = id
 | 
			
		||||
	return []byte{}, f.E
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRunInContainerNoSuchPod(t *testing.T) {
 | 
			
		||||
	fakeCommandRunner := fakeContainerCommandRunner{}
 | 
			
		||||
	kubelet, _, fakeDocker := makeTestKubelet(t)
 | 
			
		||||
	fakeDocker.containerList = []docker.APIContainers{}
 | 
			
		||||
	kubelet.runner = &fakeCommandRunner
 | 
			
		||||
 | 
			
		||||
	podName := "podFoo"
 | 
			
		||||
	podNamespace := "etcd"
 | 
			
		||||
	containerName := "containerFoo"
 | 
			
		||||
	output, err := kubelet.RunInContainer(
 | 
			
		||||
		&Pod{Name: podName, Namespace: podNamespace},
 | 
			
		||||
		containerName,
 | 
			
		||||
		[]string{"ls"})
 | 
			
		||||
	if output != nil {
 | 
			
		||||
		t.Errorf("unexpected non-nil command: %v", output)
 | 
			
		||||
	}
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		t.Error("unexpected non-error")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRunInContainer(t *testing.T) {
 | 
			
		||||
	fakeCommandRunner := fakeContainerCommandRunner{}
 | 
			
		||||
	kubelet, _, fakeDocker := makeTestKubelet(t)
 | 
			
		||||
	kubelet.runner = &fakeCommandRunner
 | 
			
		||||
 | 
			
		||||
	containerID := "abc1234"
 | 
			
		||||
	podName := "podFoo"
 | 
			
		||||
	podNamespace := "etcd"
 | 
			
		||||
	containerName := "containerFoo"
 | 
			
		||||
 | 
			
		||||
	fakeDocker.containerList = []docker.APIContainers{
 | 
			
		||||
		{
 | 
			
		||||
			ID:    containerID,
 | 
			
		||||
			Names: []string{"/k8s--" + containerName + "--" + podName + "." + podNamespace + "--1234"},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd := []string{"ls"}
 | 
			
		||||
	_, err := kubelet.RunInContainer(
 | 
			
		||||
		&Pod{Name: podName, Namespace: podNamespace},
 | 
			
		||||
		containerName,
 | 
			
		||||
		cmd)
 | 
			
		||||
	if fakeCommandRunner.ID != containerID {
 | 
			
		||||
		t.Errorf("unexected ID: %s", fakeCommandRunner.ID)
 | 
			
		||||
	}
 | 
			
		||||
	if !reflect.DeepEqual(fakeCommandRunner.Cmd, cmd) {
 | 
			
		||||
		t.Errorf("unexpected commnd: %s", fakeCommandRunner.Cmd)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Errorf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDockerContainerCommand(t *testing.T) {
 | 
			
		||||
	runner := dockerContainerCommandRunner{}
 | 
			
		||||
	containerID := "1234"
 | 
			
		||||
	command := []string{"ls"}
 | 
			
		||||
	cmd, _ := runner.getRunInContainerCommand(containerID, command)
 | 
			
		||||
	if cmd.Dir != "/var/lib/docker/execdriver/native/"+containerID {
 | 
			
		||||
		t.Errorf("unexpected command CWD: %s", cmd.Dir)
 | 
			
		||||
	}
 | 
			
		||||
	if !reflect.DeepEqual(cmd.Args, []string{"/usr/sbin/nsinit", "exec", "ls"}) {
 | 
			
		||||
		t.Errorf("unexpectd command args: %s", cmd.Args)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var parseImageNameTests = []struct {
 | 
			
		||||
	imageName string
 | 
			
		||||
	name      string
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user