mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
Merge pull request #825 from brendandburns/runin
Add support for "run in"
This commit is contained in:
commit
adc57da3f3
@ -20,6 +20,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"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 {
|
func (p dockerPuller) Pull(image string) error {
|
||||||
image, tag := parseImageName(image)
|
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.
|
// Kubelet is the main kubelet implementation.
|
||||||
type Kubelet struct {
|
type Kubelet struct {
|
||||||
hostname string
|
hostname string
|
||||||
@ -107,6 +111,8 @@ type Kubelet struct {
|
|||||||
dockerPuller DockerPuller
|
dockerPuller DockerPuller
|
||||||
// Optional, defaults to /logs/ from /var/log
|
// Optional, defaults to /logs/ from /var/log
|
||||||
logServer http.Handler
|
logServer http.Handler
|
||||||
|
// Optional, defaults to simple Docker implementation
|
||||||
|
runner ContainerCommandRunner
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts the kubelet reacting to config updates
|
// 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
|
// TODO: whitelist logs we are willing to serve
|
||||||
kl.logServer.ServeHTTP(w, req)
|
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)
|
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 {
|
var parseImageNameTests = []struct {
|
||||||
imageName string
|
imageName string
|
||||||
name string
|
name string
|
||||||
|
Loading…
Reference in New Issue
Block a user