Update kubelet for enumerated CRI namespaces

This adds support to both the Generic Runtime Manager and the
dockershim for the CRI's enumerated namespaces.
pull/6/head
Lee Verberne 2018-01-26 18:35:10 +01:00
parent f4ab2b6331
commit 0f1de41790
10 changed files with 150 additions and 90 deletions

View File

@ -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
}

View File

@ -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,
},
},
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -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),

View File

@ -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),
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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))

View File

@ -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 {