Merge pull request #836 from brendandburns/runin

Add an API for calling RunInContainer on the kubelet.
This commit is contained in:
Dawn Chen 2014-08-26 15:57:11 -07:00
commit 1b24fe880a
3 changed files with 73 additions and 2 deletions

View File

@ -1056,7 +1056,7 @@ func TestRunInContainerNoSuchPod(t *testing.T) {
podNamespace := "etcd"
containerName := "containerFoo"
output, err := kubelet.RunInContainer(
podName+"."+podNamespace,
GetPodFullName(&Pod{Name: podName, Namespace: podNamespace}),
containerName,
[]string{"ls"})
if output != nil {
@ -1086,7 +1086,7 @@ func TestRunInContainer(t *testing.T) {
cmd := []string{"ls"}
_, err := kubelet.RunInContainer(
podName+"."+podNamespace,
GetPodFullName(&Pod{Name: podName, Namespace: podNamespace}),
containerName,
cmd)
if fakeCommandRunner.ID != containerID {

View File

@ -65,6 +65,7 @@ type HostInterface interface {
GetRootInfo(req *info.ContainerInfoRequest) (*info.ContainerInfo, error)
GetMachineInfo() (*info.MachineInfo, error)
GetPodInfo(name string) (api.PodInfo, error)
RunInContainer(name, container string, cmd []string) ([]byte, error)
ServeLogs(w http.ResponseWriter, req *http.Request)
}
@ -88,6 +89,7 @@ func (s *Server) InstallDefaultHandlers() {
s.mux.HandleFunc("/stats/", s.handleStats)
s.mux.HandleFunc("/logs/", s.handleLogs)
s.mux.HandleFunc("/spec/", s.handleSpec)
s.mux.HandleFunc("/run/", s.handleRun)
}
// error serializes an error object into an HTTP response
@ -204,6 +206,31 @@ func (s *Server) handleSpec(w http.ResponseWriter, req *http.Request) {
}
// handleRun handles requests to run a command inside a container
func (s *Server) handleRun(w http.ResponseWriter, req *http.Request) {
u, err := url.ParseRequestURI(req.RequestURI)
if err != nil {
s.error(w, err)
return
}
parts := strings.Split(u.Path, "/")
if len(parts) != 4 {
http.Error(w, "Unexpected path for command running", http.StatusBadRequest)
return
}
podID := parts[2]
container := parts[3]
podFullName := GetPodFullName(&Pod{Name: podID, Namespace: "etcd"})
command := strings.Split(u.Query().Get("cmd"), " ")
data, err := s.host.RunInContainer(podFullName, container, command)
if err != nil {
s.error(w, err)
return
}
w.Header().Add("Content-type", "text/plain")
w.Write(data)
}
// ServeHTTP responds to HTTP requests on the Kubelet
func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
defer httplog.NewLogged(req, &w).StacktraceWhen(

View File

@ -40,6 +40,7 @@ type fakeKubelet struct {
rootInfoFunc func(query *info.ContainerInfoRequest) (*info.ContainerInfo, error)
machineInfoFunc func() (*info.MachineInfo, error)
logFunc func(w http.ResponseWriter, req *http.Request)
runFunc func(podFullName, containerName string, cmd []string) ([]byte, error)
}
func (fk *fakeKubelet) GetPodInfo(name string) (api.PodInfo, error) {
@ -62,6 +63,10 @@ func (fk *fakeKubelet) ServeLogs(w http.ResponseWriter, req *http.Request) {
fk.logFunc(w, req)
}
func (fk *fakeKubelet) RunInContainer(podFullName, containerName string, cmd []string) ([]byte, error) {
return fk.runFunc(podFullName, containerName, cmd)
}
type serverTestFramework struct {
updateChan chan interface{}
updateReader *channelReader
@ -288,3 +293,42 @@ func TestServeLogs(t *testing.T) {
t.Errorf("Received wrong data: %s", result)
}
}
func TestServeRunInContainer(t *testing.T) {
fw := newServerTest()
output := "foo bar"
podName := "foo"
expectedPodName := podName + ".etcd"
expectedContainerName := "baz"
expectedCommand := "ls -a"
fw.fakeKubelet.runFunc = func(podFullName, containerName string, cmd []string) ([]byte, error) {
if podFullName != expectedPodName {
t.Errorf("expected %s, got %s", expectedPodName, podFullName)
}
if containerName != expectedContainerName {
t.Errorf("expected %s, got %s", expectedContainerName, containerName)
}
if strings.Join(cmd, " ") != expectedCommand {
t.Errorf("expected: %s, got %v", expectedCommand, cmd)
}
return []byte(output), nil
}
resp, err := http.Get(fw.testHTTPServer.URL + "/run/" + podName + "/" + expectedContainerName + "?cmd=ls%20-a")
if err != nil {
t.Fatalf("Got error GETing: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
// copying the response body did not work
t.Errorf("Cannot copy resp: %#v", err)
}
result := string(body)
if result != output {
t.Errorf("expected %s, got %s", output, result)
}
}