Commit 0f1de417 authored by Lee Verberne's avatar Lee Verberne

Update kubelet for enumerated CRI namespaces

This adds support to both the Generic Runtime Manager and the dockershim for the CRI's enumerated namespaces.
parent f4ab2b63
......@@ -148,7 +148,7 @@ func (ds *dockerService) RunPodSandbox(ctx context.Context, r *runtimeapi.RunPod
}
// Do not invoke network plugins if in hostNetwork mode.
if nsOptions := config.GetLinux().GetSecurityContext().GetNamespaceOptions(); nsOptions != nil && nsOptions.HostNetwork {
if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtimeapi.NamespaceMode_NODE {
return resp, nil
}
......@@ -187,8 +187,7 @@ func (ds *dockerService) StopPodSandbox(ctx context.Context, r *runtimeapi.StopP
statusResp, statusErr := ds.PodSandboxStatus(ctx, &runtimeapi.PodSandboxStatusRequest{PodSandboxId: podSandboxID})
status := statusResp.GetStatus()
if statusErr == nil {
nsOpts := status.GetLinux().GetNamespaces().GetOptions()
hostNetwork = nsOpts != nil && nsOpts.HostNetwork
hostNetwork = status.GetLinux().GetNamespaces().GetOptions().GetNetwork() == runtimeapi.NamespaceMode_NODE
m := status.GetMetadata()
namespace = m.Namespace
name = m.Name
......@@ -323,7 +322,7 @@ func (ds *dockerService) getIP(podSandboxID string, sandbox *dockertypes.Contain
if sandbox.NetworkSettings == nil {
return ""
}
if sharesHostNetwork(sandbox) {
if networkNamespaceMode(sandbox) == runtimeapi.NamespaceMode_NODE {
// For sandboxes using host network, the shim is not responsible for
// reporting the IP.
return ""
......@@ -388,7 +387,6 @@ func (ds *dockerService) PodSandboxStatus(ctx context.Context, req *runtimeapi.P
if IP = ds.determinePodIPBySandboxID(podSandboxID); IP == "" {
IP = ds.getIP(podSandboxID, r)
}
hostNetwork := sharesHostNetwork(r)
metadata, err := parseSandboxName(r.Name)
if err != nil {
......@@ -408,9 +406,9 @@ func (ds *dockerService) PodSandboxStatus(ctx context.Context, req *runtimeapi.P
Linux: &runtimeapi.LinuxPodSandboxStatus{
Namespaces: &runtimeapi.Namespace{
Options: &runtimeapi.NamespaceOption{
HostNetwork: hostNetwork,
HostPid: sharesHostPid(r),
HostIpc: sharesHostIpc(r),
Network: networkNamespaceMode(r),
Pid: pidNamespaceMode(r),
Ipc: ipcNamespaceMode(r),
},
},
},
......@@ -592,31 +590,32 @@ func (ds *dockerService) makeSandboxDockerConfig(c *runtimeapi.PodSandboxConfig,
return createConfig, nil
}
// sharesHostNetwork returns true if the given container is sharing the host's
// network namespace.
func sharesHostNetwork(container *dockertypes.ContainerJSON) bool {
if container != nil && container.HostConfig != nil {
return string(container.HostConfig.NetworkMode) == namespaceModeHost
// networkNamespaceMode returns the network runtimeapi.NamespaceMode for this container.
// Supports: POD, NODE
func networkNamespaceMode(container *dockertypes.ContainerJSON) runtimeapi.NamespaceMode {
if container != nil && container.HostConfig != nil && string(container.HostConfig.NetworkMode) == namespaceModeHost {
return runtimeapi.NamespaceMode_NODE
}
return false
return runtimeapi.NamespaceMode_POD
}
// sharesHostPid returns true if the given container is sharing the host's pid
// namespace.
func sharesHostPid(container *dockertypes.ContainerJSON) bool {
if container != nil && container.HostConfig != nil {
return string(container.HostConfig.PidMode) == namespaceModeHost
// pidNamespaceMode returns the PID runtimeapi.NamespaceMode for this container.
// Supports: CONTAINER, NODE
// TODO(verb): add support for POD PID namespace sharing
func pidNamespaceMode(container *dockertypes.ContainerJSON) runtimeapi.NamespaceMode {
if container != nil && container.HostConfig != nil && string(container.HostConfig.PidMode) == namespaceModeHost {
return runtimeapi.NamespaceMode_NODE
}
return false
return runtimeapi.NamespaceMode_CONTAINER
}
// sharesHostIpc returns true if the given container is sharing the host's ipc
// namespace.
func sharesHostIpc(container *dockertypes.ContainerJSON) bool {
if container != nil && container.HostConfig != nil {
return string(container.HostConfig.IpcMode) == namespaceModeHost
// ipcNamespaceMode returns the IPC runtimeapi.NamespaceMode for this container.
// Supports: POD, NODE
func ipcNamespaceMode(container *dockertypes.ContainerJSON) runtimeapi.NamespaceMode {
if container != nil && container.HostConfig != nil && string(container.HostConfig.IpcMode) == namespaceModeHost {
return runtimeapi.NamespaceMode_NODE
}
return false
return runtimeapi.NamespaceMode_POD
}
func constructPodSandboxCheckpoint(config *runtimeapi.PodSandboxConfig) *PodSandboxCheckpoint {
......@@ -629,8 +628,8 @@ func constructPodSandboxCheckpoint(config *runtimeapi.PodSandboxConfig) *PodSand
Protocol: &proto,
})
}
if nsOptions := config.GetLinux().GetSecurityContext().GetNamespaceOptions(); nsOptions != nil {
checkpoint.Data.HostNetwork = nsOptions.HostNetwork
if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtimeapi.NamespaceMode_NODE {
checkpoint.Data.HostNetwork = true
}
return checkpoint
}
......
......@@ -103,13 +103,18 @@ func TestSandboxStatus(t *testing.T) {
state := runtimeapi.PodSandboxState_SANDBOX_READY
ct := int64(0)
hostNetwork := false
expected := &runtimeapi.PodSandboxStatus{
State: state,
CreatedAt: ct,
Metadata: config.Metadata,
Network: &runtimeapi.PodSandboxNetworkStatus{Ip: fakeIP},
Linux: &runtimeapi.LinuxPodSandboxStatus{Namespaces: &runtimeapi.Namespace{Options: &runtimeapi.NamespaceOption{HostNetwork: hostNetwork}}},
State: state,
CreatedAt: ct,
Metadata: config.Metadata,
Network: &runtimeapi.PodSandboxNetworkStatus{Ip: fakeIP},
Linux: &runtimeapi.LinuxPodSandboxStatus{
Namespaces: &runtimeapi.Namespace{
Options: &runtimeapi.NamespaceOption{
Pid: runtimeapi.NamespaceMode_CONTAINER,
},
},
},
Labels: labels,
Annotations: annotations,
}
......@@ -162,13 +167,18 @@ func TestSandboxStatusAfterRestart(t *testing.T) {
state := runtimeapi.PodSandboxState_SANDBOX_READY
ct := int64(0)
hostNetwork := false
expected := &runtimeapi.PodSandboxStatus{
State: state,
CreatedAt: ct,
Metadata: config.Metadata,
Network: &runtimeapi.PodSandboxNetworkStatus{Ip: fakeIP},
Linux: &runtimeapi.LinuxPodSandboxStatus{Namespaces: &runtimeapi.Namespace{Options: &runtimeapi.NamespaceOption{HostNetwork: hostNetwork}}},
State: state,
CreatedAt: ct,
Metadata: config.Metadata,
Network: &runtimeapi.PodSandboxNetworkStatus{Ip: fakeIP},
Linux: &runtimeapi.LinuxPodSandboxStatus{
Namespaces: &runtimeapi.Namespace{
Options: &runtimeapi.NamespaceOption{
Pid: runtimeapi.NamespaceMode_CONTAINER,
},
},
},
Labels: map[string]string{},
Annotations: map[string]string{},
}
......@@ -238,11 +248,10 @@ func TestHostNetworkPluginInvocation(t *testing.T) {
map[string]string{"label": name},
map[string]string{"annotation": ns},
)
hostNetwork := true
c.Linux = &runtimeapi.LinuxPodSandboxConfig{
SecurityContext: &runtimeapi.LinuxSandboxSecurityContext{
NamespaceOptions: &runtimeapi.NamespaceOption{
HostNetwork: hostNetwork,
Network: runtimeapi.NamespaceMode_NODE,
},
},
}
......
......@@ -79,7 +79,7 @@ func (ds *dockerService) updateCreateConfig(
createConfig.HostConfig.NetworkMode = dockercontainer.NetworkMode(networkMode)
} else if !shouldIsolatedByHyperV(sandboxConfig.Annotations) {
// Todo: Refactor this call in future for calling methods directly in security_context.go
modifyHostOptionsForContainer(false, podSandboxID, createConfig.HostConfig)
modifyHostOptionsForContainer(nil, podSandboxID, createConfig.HostConfig)
}
applyExperimentalCreateConfig(createConfig, sandboxConfig.Annotations)
......
......@@ -122,41 +122,30 @@ func modifyHostConfig(sc *runtimeapi.LinuxContainerSecurityContext, hostConfig *
// modifySandboxNamespaceOptions apply namespace options for sandbox
func modifySandboxNamespaceOptions(nsOpts *runtimeapi.NamespaceOption, hostConfig *dockercontainer.HostConfig, network *knetwork.PluginManager) {
hostNetwork := false
hostIpc := false
if nsOpts != nil {
hostNetwork = nsOpts.HostNetwork
hostIpc = nsOpts.HostIpc
}
modifyCommonNamespaceOptions(nsOpts, hostConfig)
modifyHostOptionsForSandbox(hostNetwork, hostIpc, network, hostConfig)
modifyHostOptionsForSandbox(nsOpts, network, hostConfig)
}
// modifyContainerNamespaceOptions apply namespace options for container
func modifyContainerNamespaceOptions(nsOpts *runtimeapi.NamespaceOption, podSandboxID string, hostConfig *dockercontainer.HostConfig) {
hostNetwork := false
if nsOpts != nil {
hostNetwork = nsOpts.HostNetwork
}
hostConfig.PidMode = dockercontainer.PidMode(fmt.Sprintf("container:%v", podSandboxID))
modifyCommonNamespaceOptions(nsOpts, hostConfig)
modifyHostOptionsForContainer(hostNetwork, podSandboxID, hostConfig)
modifyHostOptionsForContainer(nsOpts, podSandboxID, hostConfig)
}
// modifyCommonNamespaceOptions apply common namespace options for sandbox and container
func modifyCommonNamespaceOptions(nsOpts *runtimeapi.NamespaceOption, hostConfig *dockercontainer.HostConfig) {
if nsOpts != nil && nsOpts.HostPid {
if nsOpts.GetPid() == runtimeapi.NamespaceMode_NODE {
hostConfig.PidMode = namespaceModeHost
}
}
// modifyHostOptionsForSandbox applies NetworkMode/UTSMode to sandbox's dockercontainer.HostConfig.
func modifyHostOptionsForSandbox(hostNetwork bool, hostIpc bool, network *knetwork.PluginManager, hc *dockercontainer.HostConfig) {
if hostIpc {
func modifyHostOptionsForSandbox(nsOpts *runtimeapi.NamespaceOption, network *knetwork.PluginManager, hc *dockercontainer.HostConfig) {
if nsOpts.GetIpc() == runtimeapi.NamespaceMode_NODE {
hc.IpcMode = namespaceModeHost
}
if hostNetwork {
if nsOpts.GetNetwork() == runtimeapi.NamespaceMode_NODE {
hc.NetworkMode = namespaceModeHost
return
}
......@@ -177,13 +166,13 @@ func modifyHostOptionsForSandbox(hostNetwork bool, hostIpc bool, network *knetwo
}
// modifyHostOptionsForContainer applies NetworkMode/UTSMode to container's dockercontainer.HostConfig.
func modifyHostOptionsForContainer(hostNetwork bool, podSandboxID string, hc *dockercontainer.HostConfig) {
func modifyHostOptionsForContainer(nsOpts *runtimeapi.NamespaceOption, podSandboxID string, hc *dockercontainer.HostConfig) {
sandboxNSMode := fmt.Sprintf("container:%v", podSandboxID)
hc.NetworkMode = dockercontainer.NetworkMode(sandboxNSMode)
hc.IpcMode = dockercontainer.IpcMode(sandboxNSMode)
hc.UTSMode = ""
if hostNetwork {
if nsOpts.GetNetwork() == runtimeapi.NamespaceMode_NODE {
hc.UTSMode = namespaceModeHost
}
}
......
......@@ -228,25 +228,24 @@ func TestModifyHostConfigAndNamespaceOptionsForContainer(t *testing.T) {
}
func TestModifySandboxNamespaceOptions(t *testing.T) {
set := true
cases := []struct {
name string
nsOpt *runtimeapi.NamespaceOption
expected *dockercontainer.HostConfig
}{
{
name: "NamespaceOption.HostNetwork",
name: "Host Network NamespaceOption",
nsOpt: &runtimeapi.NamespaceOption{
HostNetwork: set,
Network: runtimeapi.NamespaceMode_NODE,
},
expected: &dockercontainer.HostConfig{
NetworkMode: namespaceModeHost,
},
},
{
name: "NamespaceOption.HostIpc",
name: "Host IPC NamespaceOption",
nsOpt: &runtimeapi.NamespaceOption{
HostIpc: set,
Ipc: runtimeapi.NamespaceMode_NODE,
},
expected: &dockercontainer.HostConfig{
IpcMode: namespaceModeHost,
......@@ -254,9 +253,9 @@ func TestModifySandboxNamespaceOptions(t *testing.T) {
},
},
{
name: "NamespaceOption.HostPid",
name: "Host PID NamespaceOption",
nsOpt: &runtimeapi.NamespaceOption{
HostPid: set,
Pid: runtimeapi.NamespaceMode_NODE,
},
expected: &dockercontainer.HostConfig{
PidMode: namespaceModeHost,
......@@ -272,7 +271,6 @@ func TestModifySandboxNamespaceOptions(t *testing.T) {
}
func TestModifyContainerNamespaceOptions(t *testing.T) {
set := true
sandboxID := "sandbox"
sandboxNSMode := fmt.Sprintf("container:%v", sandboxID)
cases := []struct {
......@@ -281,9 +279,9 @@ func TestModifyContainerNamespaceOptions(t *testing.T) {
expected *dockercontainer.HostConfig
}{
{
name: "NamespaceOption.HostNetwork",
name: "Host Network NamespaceOption",
nsOpt: &runtimeapi.NamespaceOption{
HostNetwork: set,
Network: runtimeapi.NamespaceMode_NODE,
},
expected: &dockercontainer.HostConfig{
NetworkMode: dockercontainer.NetworkMode(sandboxNSMode),
......@@ -293,9 +291,9 @@ func TestModifyContainerNamespaceOptions(t *testing.T) {
},
},
{
name: "NamespaceOption.HostIpc",
name: "Host IPC NamespaceOption",
nsOpt: &runtimeapi.NamespaceOption{
HostIpc: set,
Ipc: runtimeapi.NamespaceMode_NODE,
},
expected: &dockercontainer.HostConfig{
NetworkMode: dockercontainer.NetworkMode(sandboxNSMode),
......@@ -304,9 +302,9 @@ func TestModifyContainerNamespaceOptions(t *testing.T) {
},
},
{
name: "NamespaceOption.HostPid",
name: "Host PID NamespaceOption",
nsOpt: &runtimeapi.NamespaceOption{
HostPid: set,
Pid: runtimeapi.NamespaceMode_NODE,
},
expected: &dockercontainer.HostConfig{
NetworkMode: dockercontainer.NetworkMode(sandboxNSMode),
......
......@@ -278,3 +278,35 @@ func (m *kubeGenericRuntimeManager) getSeccompProfileFromAnnotations(annotations
return profile
}
func ipcNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
if pod != nil && pod.Spec.HostIPC {
return runtimeapi.NamespaceMode_NODE
}
return runtimeapi.NamespaceMode_POD
}
func networkNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
if pod != nil && pod.Spec.HostNetwork {
return runtimeapi.NamespaceMode_NODE
}
return runtimeapi.NamespaceMode_POD
}
func pidNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
if pod != nil && pod.Spec.HostPID {
return runtimeapi.NamespaceMode_NODE
}
// Note that PID does not default to the zero value
return runtimeapi.NamespaceMode_CONTAINER
}
// namespacesForPod returns the runtimeapi.NamespaceOption for a given pod.
// An empty or nil pod can be used to get the namespace defaults for v1.Pod.
func namespacesForPod(pod *v1.Pod) *runtimeapi.NamespaceOption {
return &runtimeapi.NamespaceOption{
Ipc: ipcNamespaceForPod(pod),
Network: networkNamespaceForPod(pod),
Pid: pidNamespaceForPod(pod),
}
}
......@@ -305,3 +305,45 @@ func TestGetSeccompProfileFromAnnotations(t *testing.T) {
assert.Equal(t, test.expectedProfile, seccompProfile, "TestCase[%d]", i)
}
}
func TestNamespacesForPod(t *testing.T) {
for desc, test := range map[string]struct {
input *v1.Pod
expected *runtimeapi.NamespaceOption
}{
"nil pod -> default v1 namespaces": {
nil,
&runtimeapi.NamespaceOption{
Ipc: runtimeapi.NamespaceMode_POD,
Network: runtimeapi.NamespaceMode_POD,
Pid: runtimeapi.NamespaceMode_CONTAINER,
},
},
"v1.Pod default namespaces": {
&v1.Pod{},
&runtimeapi.NamespaceOption{
Ipc: runtimeapi.NamespaceMode_POD,
Network: runtimeapi.NamespaceMode_POD,
Pid: runtimeapi.NamespaceMode_CONTAINER,
},
},
"Host Namespaces": {
&v1.Pod{
Spec: v1.PodSpec{
HostIPC: true,
HostNetwork: true,
HostPID: true,
},
},
&runtimeapi.NamespaceOption{
Ipc: runtimeapi.NamespaceMode_NODE,
Network: runtimeapi.NamespaceMode_NODE,
Pid: runtimeapi.NamespaceMode_NODE,
},
},
} {
t.Logf("TestCase: %s", desc)
actual := namespacesForPod(test.input)
assert.Equal(t, test.expected, actual)
}
}
......@@ -405,8 +405,7 @@ func (m *kubeGenericRuntimeManager) podSandboxChanged(pod *v1.Pod, podStatus *ku
}
// Needs to create a new sandbox when network namespace changed.
if sandboxStatus.Linux != nil && sandboxStatus.Linux.Namespaces != nil && sandboxStatus.Linux.Namespaces.Options != nil &&
sandboxStatus.Linux.Namespaces.Options.HostNetwork != kubecontainer.IsHostNetworkPod(pod) {
if sandboxStatus.GetLinux().GetNamespaces().GetOptions().GetNetwork() != networkNamespaceForPod(pod) {
glog.V(2).Infof("Sandbox for pod %q has changed. Need to start a new one", format.Pod(pod))
return true, sandboxStatus.Metadata.Attempt + 1, ""
}
......@@ -815,8 +814,8 @@ func (m *kubeGenericRuntimeManager) isHostNetwork(podSandBoxID string, pod *v1.P
return false, err
}
if nsOpts := podStatus.GetLinux().GetNamespaces().GetOptions(); nsOpts != nil {
return nsOpts.HostNetwork, nil
if podStatus.GetLinux().GetNamespaces().GetOptions().GetNetwork() == runtimeapi.NamespaceMode_NODE {
return true, nil
}
return false, nil
......
......@@ -145,11 +145,7 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *v1.Pod) (
if sc.RunAsUser != nil {
lc.SecurityContext.RunAsUser = &runtimeapi.Int64Value{Value: int64(*sc.RunAsUser)}
}
lc.SecurityContext.NamespaceOptions = &runtimeapi.NamespaceOption{
HostNetwork: pod.Spec.HostNetwork,
HostIpc: pod.Spec.HostIPC,
HostPid: pod.Spec.HostPID,
}
lc.SecurityContext.NamespaceOptions = namespacesForPod(pod)
if sc.FSGroup != nil {
lc.SecurityContext.SupplementalGroups = append(lc.SecurityContext.SupplementalGroups, int64(*sc.FSGroup))
......
......@@ -48,11 +48,7 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *v1.Po
}
// set namespace options and supplemental groups.
synthesized.NamespaceOptions = &runtimeapi.NamespaceOption{
HostNetwork: pod.Spec.HostNetwork,
HostIpc: pod.Spec.HostIPC,
HostPid: pod.Spec.HostPID,
}
synthesized.NamespaceOptions = namespacesForPod(pod)
podSc := pod.Spec.SecurityContext
if podSc != nil {
if podSc.FSGroup != nil {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment