diff --git a/pkg/cri/sbserver/container_create_linux_test.go b/pkg/cri/sbserver/container_create_linux_test.go index e6d761427..035697443 100644 --- a/pkg/cri/sbserver/container_create_linux_test.go +++ b/pkg/cri/sbserver/container_create_linux_test.go @@ -804,6 +804,182 @@ func TestPidNamespace(t *testing.T) { } } +func TestUserNamespace(t *testing.T) { + testID := "test-id" + testPid := uint32(1234) + testSandboxID := "sandbox-id" + testContainerName := "container-name" + idMap := runtime.IDMapping{ + HostId: 1000, + ContainerId: 1000, + Length: 10, + } + otherIDMap := runtime.IDMapping{ + HostId: 2000, + ContainerId: 2000, + Length: 10, + } + expIDMap := runtimespec.LinuxIDMapping{ + HostID: 1000, + ContainerID: 1000, + Size: 10, + } + containerConfig, sandboxConfig, imageConfig, _ := getCreateContainerTestData() + ociRuntime := config.Runtime{} + c := newTestCRIService() + for desc, test := range map[string]struct { + userNS *runtime.UserNamespace + sandboxUserNS *runtime.UserNamespace + expNS *runtimespec.LinuxNamespace + expNotNS *runtimespec.LinuxNamespace // Does NOT contain this namespace + expUIDMapping []runtimespec.LinuxIDMapping + expGIDMapping []runtimespec.LinuxIDMapping + err bool + }{ + "node namespace mode": { + userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_NODE}, + // Expect userns to NOT be present. + expNotNS: &runtimespec.LinuxNamespace{ + Type: runtimespec.UserNamespace, + Path: opts.GetUserNamespace(testPid), + }, + }, + "node namespace mode with mappings": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_NODE, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + err: true, + }, + "container namespace mode": { + userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_CONTAINER}, + err: true, + }, + "target namespace mode": { + userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode_TARGET}, + err: true, + }, + "unknown namespace mode": { + userNS: &runtime.UserNamespace{Mode: runtime.NamespaceMode(100)}, + err: true, + }, + "pod namespace mode": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + expNS: &runtimespec.LinuxNamespace{ + Type: runtimespec.UserNamespace, + Path: opts.GetUserNamespace(testPid), + }, + expUIDMapping: []runtimespec.LinuxIDMapping{expIDMap}, + expGIDMapping: []runtimespec.LinuxIDMapping{expIDMap}, + }, + "pod namespace mode with inconsistent sandbox config (different GIDs)": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + sandboxUserNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&otherIDMap}, + }, + err: true, + }, + "pod namespace mode with inconsistent sandbox config (different UIDs)": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + sandboxUserNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&otherIDMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + err: true, + }, + "pod namespace mode with inconsistent sandbox config (different len)": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + sandboxUserNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap, &idMap}, + Gids: []*runtime.IDMapping{&idMap, &idMap}, + }, + err: true, + }, + "pod namespace mode with inconsistent sandbox config (different mode)": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + sandboxUserNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_NODE, + Uids: []*runtime.IDMapping{&idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + err: true, + }, + "pod namespace mode with several mappings": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap, &idMap}, + Gids: []*runtime.IDMapping{&idMap, &idMap}, + }, + err: true, + }, + "pod namespace mode with uneven mappings": { + userNS: &runtime.UserNamespace{ + Mode: runtime.NamespaceMode_POD, + Uids: []*runtime.IDMapping{&idMap, &idMap}, + Gids: []*runtime.IDMapping{&idMap}, + }, + err: true, + }, + } { + desc := desc + test := test + t.Run(desc, func(t *testing.T) { + containerConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{UsernsOptions: test.userNS} + // By default, set sandbox and container config to the same (this is + // required by containerSpec). However, if the test wants to test for what + // happens when they don't match, the test.sandboxUserNS should be set and + // we just use that. + sandboxUserns := test.userNS + if test.sandboxUserNS != nil { + sandboxUserns = test.sandboxUserNS + } + sandboxConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{UsernsOptions: sandboxUserns} + spec, err := c.buildContainerSpec(currentPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime) + + if test.err { + require.Error(t, err) + assert.Nil(t, spec) + return + } + require.NoError(t, err) + assert.Equal(t, spec.Linux.UIDMappings, test.expUIDMapping) + assert.Equal(t, spec.Linux.GIDMappings, test.expGIDMapping) + + if test.expNS != nil { + assert.Contains(t, spec.Linux.Namespaces, *test.expNS) + } + if test.expNotNS != nil { + assert.NotContains(t, spec.Linux.Namespaces, *test.expNotNS) + } + }) + } +} + func TestNoDefaultRunMount(t *testing.T) { testID := "test-id" testPid := uint32(1234) diff --git a/pkg/cri/sbserver/helpers.go b/pkg/cri/sbserver/helpers.go index a85b86cae..d83b67b86 100644 --- a/pkg/cri/sbserver/helpers.go +++ b/pkg/cri/sbserver/helpers.go @@ -478,7 +478,7 @@ func copyResourcesToStatus(spec *runtimespec.Spec, status containerstore.Status) } if spec.Linux.Resources.HugepageLimits != nil { - hugepageLimits := make([]*runtime.HugepageLimit, len(spec.Linux.Resources.HugepageLimits)) + hugepageLimits := make([]*runtime.HugepageLimit, 0) for _, l := range spec.Linux.Resources.HugepageLimits { hugepageLimits = append(hugepageLimits, &runtime.HugepageLimit{ PageSize: l.Pagesize, diff --git a/pkg/cri/sbserver/image_pull.go b/pkg/cri/sbserver/image_pull.go index 29e2cd403..fe4770240 100644 --- a/pkg/cri/sbserver/image_pull.go +++ b/pkg/cri/sbserver/image_pull.go @@ -425,7 +425,7 @@ func (c *criService) registryHosts(ctx context.Context, auth *runtime.AuthConfig if err != nil { return nil, fmt.Errorf("get TLSConfig for registry %q: %w", e, err) } - } else if isLocalHost(host) && u.Scheme == "http" { + } else if docker.IsLocalhost(host) && u.Scheme == "http" { // Skipping TLS verification for localhost transport.TLSClientConfig = &tls.Config{ InsecureSkipVerify: true, @@ -470,26 +470,12 @@ func (c *criService) registryHosts(ctx context.Context, auth *runtime.AuthConfig // defaultScheme returns the default scheme for a registry host. func defaultScheme(host string) string { - if isLocalHost(host) { + if docker.IsLocalhost(host) { return "http" } return "https" } -// isLocalHost checks if the registry host is local. -func isLocalHost(host string) bool { - if h, _, err := net.SplitHostPort(host); err == nil { - host = h - } - - if host == "localhost" { - return true - } - - ip := net.ParseIP(host) - return ip.IsLoopback() -} - // addDefaultScheme returns the endpoint with default scheme func addDefaultScheme(endpoint string) (string, error) { if strings.Contains(endpoint, "://") { diff --git a/pkg/cri/sbserver/sandbox_run.go b/pkg/cri/sbserver/sandbox_run.go index d94afe8a6..db848ecab 100644 --- a/pkg/cri/sbserver/sandbox_run.go +++ b/pkg/cri/sbserver/sandbox_run.go @@ -330,6 +330,8 @@ func (c *criService) setupPodNetwork(ctx context.Context, sandbox *sandboxstore. config = sandbox.Config path = sandbox.NetNSPath netPlugin = c.getNetworkPlugin(sandbox.RuntimeHandler) + err error + result *cni.Result ) if netPlugin == nil { return errors.New("cni config not initialized") @@ -341,7 +343,11 @@ func (c *criService) setupPodNetwork(ctx context.Context, sandbox *sandboxstore. } log.G(ctx).WithField("podsandboxid", id).Debugf("begin cni setup") netStart := time.Now() - result, err := netPlugin.Setup(ctx, id, path, opts...) + if c.config.CniConfig.NetworkPluginSetupSerially { + result, err = netPlugin.SetupSerially(ctx, id, path, opts...) + } else { + result, err = netPlugin.Setup(ctx, id, path, opts...) + } networkPluginOperations.WithValues(networkSetUpOp).Inc() networkPluginOperationsLatency.WithValues(networkSetUpOp).UpdateSince(netStart) if err != nil {