mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 02:09:56 +00:00
Merge pull request #836 from brendandburns/runin
Add an API for calling RunInContainer on the kubelet.
This commit is contained in:
commit
1b24fe880a
@ -1056,7 +1056,7 @@ func TestRunInContainerNoSuchPod(t *testing.T) {
|
|||||||
podNamespace := "etcd"
|
podNamespace := "etcd"
|
||||||
containerName := "containerFoo"
|
containerName := "containerFoo"
|
||||||
output, err := kubelet.RunInContainer(
|
output, err := kubelet.RunInContainer(
|
||||||
podName+"."+podNamespace,
|
GetPodFullName(&Pod{Name: podName, Namespace: podNamespace}),
|
||||||
containerName,
|
containerName,
|
||||||
[]string{"ls"})
|
[]string{"ls"})
|
||||||
if output != nil {
|
if output != nil {
|
||||||
@ -1086,7 +1086,7 @@ func TestRunInContainer(t *testing.T) {
|
|||||||
|
|
||||||
cmd := []string{"ls"}
|
cmd := []string{"ls"}
|
||||||
_, err := kubelet.RunInContainer(
|
_, err := kubelet.RunInContainer(
|
||||||
podName+"."+podNamespace,
|
GetPodFullName(&Pod{Name: podName, Namespace: podNamespace}),
|
||||||
containerName,
|
containerName,
|
||||||
cmd)
|
cmd)
|
||||||
if fakeCommandRunner.ID != containerID {
|
if fakeCommandRunner.ID != containerID {
|
||||||
|
@ -65,6 +65,7 @@ type HostInterface interface {
|
|||||||
GetRootInfo(req *info.ContainerInfoRequest) (*info.ContainerInfo, error)
|
GetRootInfo(req *info.ContainerInfoRequest) (*info.ContainerInfo, error)
|
||||||
GetMachineInfo() (*info.MachineInfo, error)
|
GetMachineInfo() (*info.MachineInfo, error)
|
||||||
GetPodInfo(name string) (api.PodInfo, error)
|
GetPodInfo(name string) (api.PodInfo, error)
|
||||||
|
RunInContainer(name, container string, cmd []string) ([]byte, error)
|
||||||
ServeLogs(w http.ResponseWriter, req *http.Request)
|
ServeLogs(w http.ResponseWriter, req *http.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ func (s *Server) InstallDefaultHandlers() {
|
|||||||
s.mux.HandleFunc("/stats/", s.handleStats)
|
s.mux.HandleFunc("/stats/", s.handleStats)
|
||||||
s.mux.HandleFunc("/logs/", s.handleLogs)
|
s.mux.HandleFunc("/logs/", s.handleLogs)
|
||||||
s.mux.HandleFunc("/spec/", s.handleSpec)
|
s.mux.HandleFunc("/spec/", s.handleSpec)
|
||||||
|
s.mux.HandleFunc("/run/", s.handleRun)
|
||||||
}
|
}
|
||||||
|
|
||||||
// error serializes an error object into an HTTP response
|
// 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
|
// ServeHTTP responds to HTTP requests on the Kubelet
|
||||||
func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
defer httplog.NewLogged(req, &w).StacktraceWhen(
|
defer httplog.NewLogged(req, &w).StacktraceWhen(
|
||||||
|
@ -40,6 +40,7 @@ type fakeKubelet struct {
|
|||||||
rootInfoFunc func(query *info.ContainerInfoRequest) (*info.ContainerInfo, error)
|
rootInfoFunc func(query *info.ContainerInfoRequest) (*info.ContainerInfo, error)
|
||||||
machineInfoFunc func() (*info.MachineInfo, error)
|
machineInfoFunc func() (*info.MachineInfo, error)
|
||||||
logFunc func(w http.ResponseWriter, req *http.Request)
|
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) {
|
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)
|
fk.logFunc(w, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fk *fakeKubelet) RunInContainer(podFullName, containerName string, cmd []string) ([]byte, error) {
|
||||||
|
return fk.runFunc(podFullName, containerName, cmd)
|
||||||
|
}
|
||||||
|
|
||||||
type serverTestFramework struct {
|
type serverTestFramework struct {
|
||||||
updateChan chan interface{}
|
updateChan chan interface{}
|
||||||
updateReader *channelReader
|
updateReader *channelReader
|
||||||
@ -288,3 +293,42 @@ func TestServeLogs(t *testing.T) {
|
|||||||
t.Errorf("Received wrong data: %s", result)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user