diff --git a/pkg/kubelet/rkt/rkt.go b/pkg/kubelet/rkt/rkt.go index 42a038f43c6..7d8ae3fc6af 100644 --- a/pkg/kubelet/rkt/rkt.go +++ b/pkg/kubelet/rkt/rkt.go @@ -82,7 +82,7 @@ const ( unitPodUID = "PodUID" unitPodName = "PodName" unitPodNamespace = "PodNamespace" - unitRestartCount = "RestartCount" + unitPodHostNetwork = "PodHostNetwork" k8sRktKubeletAnno = "rkt.kubernetes.io/managed-by-kubelet" k8sRktKubeletAnnoValue = "true" @@ -120,6 +120,13 @@ const ( // TODO(yifan): Reuse this const with Docker runtime. minimumGracePeriodInSeconds = 2 + + // The network name of the network when no-op plugin is being used. + // TODO(yifan): This is not ideal since today we cannot make the rkt's 'net.d' dir point to the + // CNI directory specified by kubelet. Once that is fixed, we can just use the network config + // under the CNI directory directly. + // See https://github.com/coreos/rkt/pull/2312#issuecomment-200068370. + defaultNetworkName = "rkt.kubernetes.io" ) // Runtime implements the Containerruntime for rkt. The implementation @@ -902,6 +909,20 @@ func serviceFilePath(serviceName string) string { return path.Join(systemdServiceDir, serviceName) } +// shouldCreateNetns returns true if: +// The pod does not run in host network. And +// The pod runs inside a netns created outside of rkt. +func (r *Runtime) shouldCreateNetns(pod *api.Pod) bool { + return !kubecontainer.IsHostNetworkPod(pod) && r.networkPlugin.Name() != network.DefaultPluginName +} + +// usesRktHostNetwork returns true if: +// The pod runs in the host network. Or +// The pod runs inside a netns created outside of rkt. +func (r *Runtime) usesRktHostNetwork(pod *api.Pod) bool { + return kubecontainer.IsHostNetworkPod(pod) || r.shouldCreateNetns(pod) +} + // generateRunCommand crafts a 'rkt run-prepared' command with necessary parameters. func (r *Runtime) generateRunCommand(pod *api.Pod, uuid, netnsName string) (string, error) { runPrepared := buildCommand(r.config, "run-prepared").Args @@ -921,10 +942,14 @@ func (r *Runtime) generateRunCommand(pod *api.Pod, uuid, netnsName string) (stri runPrepared = append(runPrepared, "--no-overlay=true") } - // Network namespace set up in kubelet; rkt networking not used - runPrepared = append(runPrepared, "--net=host") + // Apply '--net=host' to pod that is running on host network or inside a network namespace. + if r.usesRktHostNetwork(pod) { + runPrepared = append(runPrepared, "--net=host") + } else { + runPrepared = append(runPrepared, fmt.Sprintf("--net=%s", defaultNetworkName)) + } - if len(netnsName) == 0 { + if kubecontainer.IsHostNetworkPod(pod) { // TODO(yifan): Let runtimeHelper.GeneratePodHostNameAndDomain() to handle this. hostname, err = r.os.Hostname() if err != nil { @@ -951,7 +976,12 @@ func (r *Runtime) generateRunCommand(pod *api.Pod, uuid, netnsName string) (stri if err != nil { return "", err } + } + runPrepared = append(runPrepared, fmt.Sprintf("--hostname=%s", hostname)) + runPrepared = append(runPrepared, uuid) + + if r.shouldCreateNetns(pod) { // Drop the `rkt run-prepared` into the network namespace we // created. // TODO: switch to 'ip netns exec' once we can depend on a new @@ -961,18 +991,22 @@ func (r *Runtime) generateRunCommand(pod *api.Pod, uuid, netnsName string) (stri runPrepared = append(nsenterExec, runPrepared...) } - runPrepared = append(runPrepared, fmt.Sprintf("--hostname=%s", hostname)) - runPrepared = append(runPrepared, uuid) return strings.Join(runPrepared, " "), nil } func (r *Runtime) cleanupPodNetwork(pod *api.Pod) error { glog.V(3).Infof("Calling network plugin %s to tear down pod for %s", r.networkPlugin.Name(), format.Pod(pod)) + // No-op if the pod is not running in a created netns. + if !r.shouldCreateNetns(pod) { + return nil + } + var teardownErr error containerID := kubecontainer.ContainerID{ID: string(pod.UID)} if err := r.networkPlugin.TearDownPod(pod.Namespace, pod.Name, containerID); err != nil { teardownErr = fmt.Errorf("rkt: failed to tear down network for pod %s: %v", format.Pod(pod), err) + glog.Errorf("%v", teardownErr) } if _, err := r.execer.Command("ip", "netns", "del", makePodNetnsName(pod.UID)).Output(); err != nil { @@ -1089,6 +1123,8 @@ func (r *Runtime) preparePod(pod *api.Pod, podIP string, pullSecrets []api.Secre // TODO per container finishedAt, not just per pod markPodFinished := podFinishedMarkCommand(r.touchPath, r.runtimeHelper.GetPodDir(pod.UID), uuid) + + hostNetwork := kubecontainer.IsHostNetworkPod(pod) units := []*unit.UnitOption{ newUnitOption("Service", "ExecStart", runPrepared), newUnitOption("Service", "ExecStopPost", markPodFinished), @@ -1098,6 +1134,7 @@ func (r *Runtime) preparePod(pod *api.Pod, podIP string, pullSecrets []api.Secre newUnitOption(unitKubernetesSection, unitPodUID, string(pod.UID)), newUnitOption(unitKubernetesSection, unitPodName, pod.Name), newUnitOption(unitKubernetesSection, unitPodNamespace, pod.Namespace), + newUnitOption(unitKubernetesSection, unitPodHostNetwork, fmt.Sprintf("%v", hostNetwork)), } if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SELinuxOptions != nil { @@ -1161,7 +1198,7 @@ func (r *Runtime) generateEvents(runtimePod *kubecontainer.Pod, reason string, f } func makePodNetnsName(podID kubetypes.UID) string { - return fmt.Sprintf("%s_%s", kubernetesUnitPrefix, string(podID)) + return fmt.Sprintf("%s%s", kubernetesUnitPrefix, string(podID)) } func netnsPathFromName(netnsName string) string { @@ -1172,7 +1209,16 @@ func netnsPathFromName(netnsName string) string { // configured NetworkPlugin's setup function on it. // It returns the namespace name, configured IP (if available), and an error if // one occured. +// +// If the pod is running in host network or is running using the no-op plugin, then nothing will be done. func (r *Runtime) setupPodNetwork(pod *api.Pod) (string, string, error) { + glog.V(3).Infof("Calling network plugin %s to set up pod for %s", r.networkPlugin.Name(), format.Pod(pod)) + + // No-op if the pod is not running in a created netns. + if !r.shouldCreateNetns(pod) { + return "", "", nil + } + netnsName := makePodNetnsName(pod.UID) // Create a new network namespace for the pod @@ -1211,12 +1257,10 @@ func (r *Runtime) RunPod(pod *api.Pod, pullSecrets []api.Secret) error { var err error var netnsName string var podIP string - if !kubecontainer.IsHostNetworkPod(pod) { - netnsName, podIP, err = r.setupPodNetwork(pod) - if err != nil { - r.cleanupPodNetwork(pod) - return err - } + netnsName, podIP, err = r.setupPodNetwork(pod) + if err != nil { + r.cleanupPodNetwork(pod) + return err } name, runtimePod, prepareErr := r.preparePod(pod, podIP, pullSecrets, netnsName) @@ -1549,6 +1593,8 @@ func (r *Runtime) KillPod(pod *api.Pod, runningPod kubecontainer.Pod, gracePerio return err } serviceName := makePodServiceFileName(containerID.uuid) + serviceFile := serviceFilePath(serviceName) + r.generateEvents(&runningPod, "Killing", nil) for _, c := range runningPod.Containers { r.containerRefManager.ClearRef(c.ID) @@ -1556,7 +1602,7 @@ func (r *Runtime) KillPod(pod *api.Pod, runningPod kubecontainer.Pod, gracePerio // Touch the systemd service file to update the mod time so it will // not be garbage collected too soon. - if err := r.os.Chtimes(serviceFilePath(serviceName), time.Now(), time.Now()); err != nil { + if err := r.os.Chtimes(serviceFile, time.Now(), time.Now()); err != nil { glog.Errorf("rkt: Failed to change the modification time of the service file %q: %v", serviceName, err) return err } @@ -1576,19 +1622,10 @@ func (r *Runtime) KillPod(pod *api.Pod, runningPod kubecontainer.Pod, gracePerio return err } - // Clean up networking; use running pod details since 'pod' can be nil - if pod == nil || !kubecontainer.IsHostNetworkPod(pod) { - err := r.cleanupPodNetwork(&api.Pod{ - ObjectMeta: api.ObjectMeta{ - UID: runningPod.ID, - Name: runningPod.Name, - Namespace: runningPod.Namespace, - }, - }) - if err != nil { - glog.Errorf("rkt: failed to tear down network for unit %q: %v", serviceName, err) - return err - } + // Clean up networking. Use the service file to get pod details since 'pod' can be nil. + if err := r.cleanupPodNetworkFromServiceFile(serviceFile); err != nil { + glog.Errorf("rkt: failed to tear down network for unit %q: %v", serviceName, err) + return err } return nil @@ -1725,19 +1762,19 @@ func (r *Runtime) GetNetNS(containerID kubecontainer.ContainerID) (string, error return netnsPathFromName(makePodNetnsName(kubetypes.UID(containerID.ID))), nil } -func podDetailsFromServiceFile(serviceFilePath string) (string, string, string, error) { +func podDetailsFromServiceFile(serviceFilePath string) (string, string, string, bool, error) { f, err := os.Open(serviceFilePath) if err != nil { - return "", "", "", err + return "", "", "", false, err } defer f.Close() opts, err := unit.Deserialize(f) if err != nil { - return "", "", "", err + return "", "", "", false, err } - var id, name, namespace string + var id, name, namespace, hostnetwork string for _, o := range opts { if o.Section != unitKubernetesSection { continue @@ -1749,14 +1786,20 @@ func podDetailsFromServiceFile(serviceFilePath string) (string, string, string, name = o.Value case unitPodNamespace: namespace = o.Value + case unitPodHostNetwork: + hostnetwork = o.Value } - if id != "" && name != "" && namespace != "" { - return id, name, namespace, nil + if id != "" && name != "" && namespace != "" && hostnetwork != "" { + podHostNetwork, err := strconv.ParseBool(hostnetwork) + if err != nil { + return "", "", "", false, err + } + return id, name, namespace, podHostNetwork, nil } } - return "", "", "", fmt.Errorf("failed to parse pod from file %s", serviceFilePath) + return "", "", "", false, fmt.Errorf("failed to parse pod from file %s", serviceFilePath) } // GarbageCollect collects the pods/containers. @@ -1822,8 +1865,9 @@ func (r *Runtime) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy) error serviceFile := serviceFilePath(serviceName) // Network may not be around anymore so errors are ignored - r.cleanupPodNetworkFromServiceFile(serviceFile) - + if err := r.cleanupPodNetworkFromServiceFile(serviceFile); err != nil { + glog.Warningf("rkt: Failed to clean up pod network from service %q: %v, the network may not be around already", serviceName, err) + } if err := r.os.Remove(serviceFile); err != nil { errlist = append(errlist, fmt.Errorf("rkt: Failed to remove service file %q: %v", serviceFile, err)) } @@ -1859,17 +1903,23 @@ func (r *Runtime) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy) error // Read kubernetes pod UUID, namespace, and name from systemd service file and // use that to clean up any pod network that may still exist. -func (r *Runtime) cleanupPodNetworkFromServiceFile(serviceFilePath string) { - id, name, namespace, err := podDetailsFromServiceFile(serviceFilePath) - if err == nil { - r.cleanupPodNetwork(&api.Pod{ - ObjectMeta: api.ObjectMeta{ - UID: kubetypes.UID(id), - Name: name, - Namespace: namespace, - }, - }) +func (r *Runtime) cleanupPodNetworkFromServiceFile(serviceFilePath string) error { + id, name, namespace, hostnetwork, err := podDetailsFromServiceFile(serviceFilePath) + if err != nil { + return err } + return r.cleanupPodNetwork(&api.Pod{ + ObjectMeta: api.ObjectMeta{ + UID: kubetypes.UID(id), + Name: name, + Namespace: namespace, + }, + Spec: api.PodSpec{ + SecurityContext: &api.PodSecurityContext{ + HostNetwork: hostnetwork, + }, + }, + }) } // removePod calls 'rkt rm $UUID' to delete a rkt pod, it also remove the systemd service file @@ -1882,7 +1932,9 @@ func (r *Runtime) removePod(uuid string) error { serviceFile := serviceFilePath(serviceName) // Network may not be around anymore so errors are ignored - r.cleanupPodNetworkFromServiceFile(serviceFile) + if err := r.cleanupPodNetworkFromServiceFile(serviceFile); err != nil { + glog.Warningf("rkt: Failed to clean up pod network from service %q: %v, the network may not be around already", serviceName, err) + } if _, err := r.cli.RunCommand(nil, "rm", uuid); err != nil { errlist = append(errlist, fmt.Errorf("rkt: Failed to remove pod %q: %v", uuid, err)) @@ -2148,6 +2200,7 @@ func (r *Runtime) GetPodStatus(uid kubetypes.UID, name, namespace string) (*kube return nil, fmt.Errorf("couldn't list pods: %v", err) } + var latestPod *rktapi.Pod var latestRestartCount int = -1 // In this loop, we group all containers from all pods together, @@ -2160,6 +2213,7 @@ func (r *Runtime) GetPodStatus(uid kubetypes.UID, name, namespace string) (*kube } if restartCount > latestRestartCount { + latestPod = pod latestRestartCount = restartCount } @@ -2175,10 +2229,26 @@ func (r *Runtime) GetPodStatus(uid kubetypes.UID, name, namespace string) (*kube } } - // TODO(euank): this will not work in host networking mode - containerID := kubecontainer.ContainerID{ID: string(uid)} - if status, err := r.networkPlugin.GetPodNetworkStatus(namespace, name, containerID); err == nil { - podStatus.IP = status.IP.String() + // If we are running no-op network plugin, then get the pod IP from the rkt pod status. + if r.networkPlugin.Name() == network.DefaultPluginName { + if latestPod != nil { + for _, n := range latestPod.Networks { + if n.Name == defaultNetworkName { + podStatus.IP = n.Ipv4 + break + } + } + } + } else { + containerID := kubecontainer.ContainerID{ID: string(uid)} + status, err := r.networkPlugin.GetPodNetworkStatus(namespace, name, containerID) + if err != nil { + glog.Warningf("rkt: Failed to get pod network status for pod (UID %q, name %q, namespace %q): %v", uid, name, namespace, err) + } else if status != nil { + // status can be nil when the pod is running on the host network, in which case the pod IP + // will be populated by the upper layer. + podStatus.IP = status.IP.String() + } } return podStatus, nil diff --git a/pkg/kubelet/rkt/rkt_test.go b/pkg/kubelet/rkt/rkt_test.go index c02119dcd5b..dc2152cc6af 100644 --- a/pkg/kubelet/rkt/rkt_test.go +++ b/pkg/kubelet/rkt/rkt_test.go @@ -38,6 +38,7 @@ import ( kubetesting "k8s.io/kubernetes/pkg/kubelet/container/testing" "k8s.io/kubernetes/pkg/kubelet/lifecycle" "k8s.io/kubernetes/pkg/kubelet/network" + "k8s.io/kubernetes/pkg/kubelet/network/kubenet" "k8s.io/kubernetes/pkg/kubelet/network/mock_network" "k8s.io/kubernetes/pkg/kubelet/rkt/mock_os" "k8s.io/kubernetes/pkg/kubelet/types" @@ -75,7 +76,7 @@ func makeRktPod(rktPodState rktapi.PodState, rktPodID, podUID, podName, podNamespace string, podCreatedAt, podStartedAt int64, podRestartCount string, appNames, imgIDs, imgNames, containerHashes []string, appStates []rktapi.AppState, - exitcodes []int32) *rktapi.Pod { + exitcodes []int32, ips map[string]string) *rktapi.Pod { podManifest := &appcschema.PodManifest{ ACKind: appcschema.PodManifestKind, @@ -149,6 +150,11 @@ func makeRktPod(rktPodState rktapi.PodState, }) } + var networks []*rktapi.Network + for name, ip := range ips { + networks = append(networks, &rktapi.Network{Name: name, Ipv4: ip}) + } + return &rktapi.Pod{ Id: rktPodID, State: rktPodState, @@ -156,6 +162,7 @@ func makeRktPod(rktPodState rktapi.PodState, Manifest: mustMarshalPodManifest(podManifest), StartedAt: podStartedAt, CreatedAt: podCreatedAt, + Networks: networks, } } @@ -357,6 +364,7 @@ func TestGetPods(t *testing.T) { []string{"1001", "1002"}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []int32{0, 0}, + nil, ), }, []*kubecontainer.Pod{ @@ -395,6 +403,7 @@ func TestGetPods(t *testing.T) { []string{"1001", "1002"}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []int32{0, 0}, + nil, ), makeRktPod(rktapi.PodState_POD_STATE_EXITED, "uuid-4003", "43", "guestbook", "default", @@ -405,6 +414,7 @@ func TestGetPods(t *testing.T) { []string{"10011", "10022"}, []rktapi.AppState{rktapi.AppState_APP_STATE_EXITED, rktapi.AppState_APP_STATE_EXITED}, []int32{0, 0}, + nil, ), makeRktPod(rktapi.PodState_POD_STATE_EXITED, "uuid-4004", "43", "guestbook", "default", @@ -415,6 +425,7 @@ func TestGetPods(t *testing.T) { []string{"10011", "10022"}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_RUNNING}, []int32{0, 0}, + nil, ), }, []*kubecontainer.Pod{ @@ -560,16 +571,19 @@ func TestGetPodStatus(t *testing.T) { } tests := []struct { - pods []*rktapi.Pod - result *kubecontainer.PodStatus + networkPluginName string + pods []*rktapi.Pod + result *kubecontainer.PodStatus }{ - // No pods. + // # case 0, No pods. { + kubenet.KubenetPluginName, nil, &kubecontainer.PodStatus{ID: "42", Name: "guestbook", Namespace: "default"}, }, - // One pod. + // # case 1, One pod. { + kubenet.KubenetPluginName, []*rktapi.Pod{ makeRktPod(rktapi.PodState_POD_STATE_RUNNING, "uuid-4002", "42", "guestbook", "default", @@ -580,6 +594,7 @@ func TestGetPodStatus(t *testing.T) { []string{"1001", "1002"}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []int32{0, 0}, + nil, ), }, &kubecontainer.PodStatus{ @@ -616,8 +631,59 @@ func TestGetPodStatus(t *testing.T) { }, }, }, - // Multiple pods. + // # case 2, One pod with no-op network plugin name. { + network.DefaultPluginName, + []*rktapi.Pod{ + makeRktPod(rktapi.PodState_POD_STATE_RUNNING, + "uuid-4002", "42", "guestbook", "default", + ns(10), ns(20), "7", + []string{"app-1", "app-2"}, + []string{"img-id-1", "img-id-2"}, + []string{"img-name-1", "img-name-2"}, + []string{"1001", "1002"}, + []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, + []int32{0, 0}, + map[string]string{defaultNetworkName: "10.10.10.22"}, + ), + }, + &kubecontainer.PodStatus{ + ID: "42", + Name: "guestbook", + Namespace: "default", + IP: "10.10.10.22", + ContainerStatuses: []*kubecontainer.ContainerStatus{ + { + ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"), + Name: "app-1", + State: kubecontainer.ContainerStateRunning, + CreatedAt: time.Unix(10, 0), + StartedAt: time.Unix(20, 0), + FinishedAt: time.Unix(0, 30), + Image: "img-name-1:latest", + ImageID: "rkt://img-id-1", + Hash: 1001, + RestartCount: 7, + }, + { + ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"), + Name: "app-2", + State: kubecontainer.ContainerStateExited, + CreatedAt: time.Unix(10, 0), + StartedAt: time.Unix(20, 0), + FinishedAt: time.Unix(0, 30), + Image: "img-name-2:latest", + ImageID: "rkt://img-id-2", + Hash: 1002, + RestartCount: 7, + Reason: "Completed", + }, + }, + }, + }, + // # case 3, Multiple pods. + { + kubenet.KubenetPluginName, []*rktapi.Pod{ makeRktPod(rktapi.PodState_POD_STATE_EXITED, "uuid-4002", "42", "guestbook", "default", @@ -628,6 +694,7 @@ func TestGetPodStatus(t *testing.T) { []string{"1001", "1002"}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []int32{0, 0}, + nil, ), makeRktPod(rktapi.PodState_POD_STATE_RUNNING, // The latest pod is running. "uuid-4003", "42", "guestbook", "default", @@ -638,6 +705,7 @@ func TestGetPodStatus(t *testing.T) { []string{"1001", "1002"}, []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED}, []int32{0, 1}, + nil, ), }, &kubecontainer.PodStatus{ @@ -721,13 +789,16 @@ func TestGetPodStatus(t *testing.T) { mockFI.EXPECT().ModTime().Return(podTime) return mockFI, nil } + fnp.EXPECT().Name().Return(tt.networkPluginName) - if tt.result.IP != "" { - fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}). - Return(&network.PodNetworkStatus{IP: net.ParseIP(tt.result.IP)}, nil) - } else { - fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}). - Return(nil, fmt.Errorf("no such network")) + if tt.networkPluginName == kubenet.KubenetPluginName { + if tt.result.IP != "" { + fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}). + Return(&network.PodNetworkStatus{IP: net.ParseIP(tt.result.IP)}, nil) + } else { + fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}). + Return(nil, fmt.Errorf("no such network")) + } } status, err := r.GetPodStatus("42", "guestbook", "default") @@ -1070,9 +1141,10 @@ func TestSetApp(t *testing.T) { func TestGenerateRunCommand(t *testing.T) { hostName := "test-hostname" tests := []struct { - pod *api.Pod - uuid string - netnsName string + networkPlugin network.NetworkPlugin + pod *api.Pod + uuid string + netnsName string dnsServers []string dnsSearches []string @@ -1083,6 +1155,7 @@ func TestGenerateRunCommand(t *testing.T) { }{ // Case #0, returns error. { + kubenet.NewPlugin("/tmp"), &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod-name-foo", @@ -1099,6 +1172,7 @@ func TestGenerateRunCommand(t *testing.T) { }, // Case #1, returns no dns, with private-net. { + kubenet.NewPlugin("/tmp"), &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod-name-foo", @@ -1110,10 +1184,11 @@ func TestGenerateRunCommand(t *testing.T) { []string{}, "pod-hostname-foo", nil, - " --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo", + "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo", }, // Case #2, returns no dns, with host-net. { + kubenet.NewPlugin("/tmp"), &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod-name-foo", @@ -1134,6 +1209,7 @@ func TestGenerateRunCommand(t *testing.T) { }, // Case #3, returns dns, dns searches, with private-net. { + kubenet.NewPlugin("/tmp"), &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod-name-foo", @@ -1150,10 +1226,11 @@ func TestGenerateRunCommand(t *testing.T) { []string{"."}, "pod-hostname-foo", nil, - " --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --dns=127.0.0.1 --dns-search=. --dns-opt=ndots:5 --hostname=pod-hostname-foo rkt-uuid-foo", + "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --dns=127.0.0.1 --dns-search=. --dns-opt=ndots:5 --hostname=pod-hostname-foo rkt-uuid-foo", }, // Case #4, returns no dns, dns searches, with host-network. { + kubenet.NewPlugin("/tmp"), &api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pod-name-foo", @@ -1172,10 +1249,28 @@ func TestGenerateRunCommand(t *testing.T) { nil, fmt.Sprintf("/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=%s rkt-uuid-foo", hostName), }, + // Case #5, with no-op plugin, returns --net=rkt.kubernetes.io, with dns and dns search. + { + &network.NoopNetworkPlugin{}, + &api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "pod-name-foo", + }, + Spec: api.PodSpec{}, + }, + "rkt-uuid-foo", + "default", + []string{"127.0.0.1"}, + []string{"."}, + "pod-hostname-foo", + nil, + "/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=rkt.kubernetes.io --dns=127.0.0.1 --dns-search=. --dns-opt=ndots:5 --hostname=pod-hostname-foo rkt-uuid-foo", + }, } rkt := &Runtime{ - os: &kubetesting.FakeOS{HostName: hostName}, + nsenterPath: "/usr/bin/nsenter", + os: &kubetesting.FakeOS{HostName: hostName}, config: &Config{ Path: "/bin/rkt/rkt", Stage1Image: "/bin/rkt/stage1-coreos.aci", @@ -1187,6 +1282,7 @@ func TestGenerateRunCommand(t *testing.T) { for i, tt := range tests { testCaseHint := fmt.Sprintf("test case #%d", i) + rkt.networkPlugin = tt.networkPlugin rkt.runtimeHelper = &fakeRuntimeHelper{tt.dnsServers, tt.dnsSearches, tt.hostName, "", tt.err} rkt.execer = &utilexec.FakeExec{CommandScript: []utilexec.FakeCommandAction{func(cmd string, args ...string) utilexec.Cmd { return utilexec.InitFakeCmd(&utilexec.FakeCmd{}, cmd, args...)