Skip to content

Commit 316d6d3

Browse files
committed
userns: Call runtime only once
Sascha suggested to run this only once. Let's cache the answer from the runtime and move the tests that need idmap mounts on the host to `When("Host idmap mount support is needed"`. While we split the tests in that way, let's just query idmap mount support for the tests that need it, using the cache. Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
1 parent 934f1cc commit 316d6d3

File tree

1 file changed

+103
-78
lines changed

1 file changed

+103
-78
lines changed

pkg/validate/security_context_linux.go

+103-78
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"os/exec"
2626
"path/filepath"
2727
"strings"
28+
"sync"
2829
"syscall"
2930
"time"
3031

@@ -850,7 +851,12 @@ var _ = framework.KubeDescribe("Security Context", func() {
850851

851852
Context("UserNamespaces", func() {
852853
var (
853-
podName string
854+
podName string
855+
856+
// We call rc.Status() once and save the result in statusResp.
857+
statusOnce sync.Once
858+
statusResp *runtimeapi.StatusResponse
859+
854860
defaultMapping = []*runtimeapi.IDMapping{{
855861
ContainerId: 0,
856862
HostId: 1000,
@@ -863,108 +869,127 @@ var _ = framework.KubeDescribe("Security Context", func() {
863869

864870
// Find a working runtime handler if none provided
865871
By("searching for runtime handler which supports user namespaces")
866-
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
867-
defer cancel()
868-
resp, err := rc.Status(ctx, true) // Set verbose to true so the info field is populated.
869-
framework.ExpectNoError(err, "failed to get runtime config: %v", err)
870-
871-
supportsUserNamespaces := false
872-
for _, rh := range resp.GetRuntimeHandlers() {
872+
statusOnce.Do(func() {
873+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
874+
defer cancel()
875+
// Set verbose to true, other BeforeEachs calls need the info field
876+
// populated.
877+
// XXX: Do NOT use ":=" here, it breaks the closure reference to
878+
// statusResp.
879+
var err error
880+
statusResp, err = rc.Status(ctx, true)
881+
framework.ExpectNoError(err, "failed to get runtime config: %v", err)
882+
_ = statusResp // Avoid unused variable error
883+
})
884+
885+
var supportsUserNamespaces bool
886+
for _, rh := range statusResp.GetRuntimeHandlers() {
873887
if rh.GetName() == framework.TestContext.RuntimeHandler {
874888
if rh.GetFeatures().GetUserNamespaces() {
875889
supportsUserNamespaces = true
876890
break
877891
}
878892
}
879893
}
880-
881894
if !supportsUserNamespaces {
882895
Skip("no runtime handler found which supports user namespaces")
883896
}
884-
885-
pathIDMap := rootfsPath(resp.GetInfo())
886-
if err := supportsIDMap(pathIDMap); err != nil {
887-
Skip("ID mapping is not supported" + " with path: " + pathIDMap + ": " + err.Error())
888-
}
889897
})
890898

891-
It("runtime should support NamespaceMode_POD", func() {
892-
namespaceOption := &runtimeapi.NamespaceOption{
893-
UsernsOptions: &runtimeapi.UserNamespace{
894-
Mode: runtimeapi.NamespaceMode_POD,
895-
Uids: defaultMapping,
896-
Gids: defaultMapping,
897-
},
898-
}
899+
When("Host idmap mount support is needed", func() {
900+
BeforeEach(func() {
901+
pathIDMap := rootfsPath(statusResp.GetInfo())
902+
if err := supportsIDMap(pathIDMap); err != nil {
903+
Skip("ID mapping is not supported" + " with path: " + pathIDMap + ": " + err.Error())
904+
}
905+
})
906+
907+
It("runtime should support NamespaceMode_POD", func() {
908+
namespaceOption := &runtimeapi.NamespaceOption{
909+
UsernsOptions: &runtimeapi.UserNamespace{
910+
Mode: runtimeapi.NamespaceMode_POD,
911+
Uids: defaultMapping,
912+
Gids: defaultMapping,
913+
},
914+
}
899915

900-
hostLogPath, podLogPath := createLogTempDir(podName)
901-
defer os.RemoveAll(hostLogPath)
902-
podID, podConfig = createNamespacePodSandbox(rc, namespaceOption, podName, podLogPath)
903-
containerName := runUserNamespaceContainer(rc, ic, podID, podConfig)
916+
hostLogPath, podLogPath := createLogTempDir(podName)
917+
defer os.RemoveAll(hostLogPath)
918+
podID, podConfig = createNamespacePodSandbox(rc, namespaceOption, podName, podLogPath)
919+
containerName := runUserNamespaceContainer(rc, ic, podID, podConfig)
904920

905-
matchContainerOutputRe(podConfig, containerName, `\s+0\s+1000\s+100000\n`)
906-
})
921+
matchContainerOutputRe(podConfig, containerName, `\s+0\s+1000\s+100000\n`)
922+
})
907923

908-
It("runtime should support NamespaceMode_NODE", func() {
909-
namespaceOption := &runtimeapi.NamespaceOption{
910-
UsernsOptions: &runtimeapi.UserNamespace{
911-
Mode: runtimeapi.NamespaceMode_NODE,
912-
},
913-
}
924+
})
914925

915-
hostLogPath, podLogPath := createLogTempDir(podName)
916-
defer os.RemoveAll(hostLogPath)
917-
podID, podConfig = createNamespacePodSandbox(rc, namespaceOption, podName, podLogPath)
918-
containerName := runUserNamespaceContainer(rc, ic, podID, podConfig)
926+
When("Host idmap mount support is not needed", func() {
927+
It("runtime should support NamespaceMode_NODE", func() {
928+
namespaceOption := &runtimeapi.NamespaceOption{
929+
UsernsOptions: &runtimeapi.UserNamespace{
930+
Mode: runtimeapi.NamespaceMode_NODE,
931+
},
932+
}
919933

920-
// 4294967295 means that the entire range is available
921-
matchContainerOutputRe(podConfig, containerName, `\s+0\s+0\s+4294967295\n`)
922-
})
934+
hostLogPath, podLogPath := createLogTempDir(podName)
935+
defer os.RemoveAll(hostLogPath)
936+
podID, podConfig = createNamespacePodSandbox(rc, namespaceOption, podName, podLogPath)
937+
containerName := runUserNamespaceContainer(rc, ic, podID, podConfig)
923938

924-
It("runtime should fail if more than one mapping provided", func() {
925-
wrongMapping := []*runtimeapi.IDMapping{{
926-
ContainerId: 0,
927-
HostId: 1000,
928-
Length: 100000,
929-
}, {
930-
ContainerId: 0,
931-
HostId: 2000,
932-
Length: 100000,
933-
}}
934-
usernsOptions := &runtimeapi.UserNamespace{
935-
Mode: runtimeapi.NamespaceMode_POD,
936-
Uids: wrongMapping,
937-
Gids: wrongMapping,
938-
}
939+
// 4294967295 means that the entire range is available
940+
expectedOutput := hostUsernsContent()
941+
if expectedOutput == "" {
942+
Fail("failed to get host userns content")
943+
}
944+
// 4294967295 means that the entire range is available
945+
matchContainerOutputRe(podConfig, containerName, `\s+0\s+0\s+4294967295\n`)
946+
})
947+
948+
It("runtime should fail if more than one mapping provided", func() {
949+
wrongMapping := []*runtimeapi.IDMapping{{
950+
ContainerId: 0,
951+
HostId: 1000,
952+
Length: 100000,
953+
}, {
954+
ContainerId: 0,
955+
HostId: 2000,
956+
Length: 100000,
957+
}}
958+
usernsOptions := &runtimeapi.UserNamespace{
959+
Mode: runtimeapi.NamespaceMode_POD,
960+
Uids: wrongMapping,
961+
Gids: wrongMapping,
962+
}
939963

940-
runUserNamespacePodWithError(rc, podName, usernsOptions)
941-
})
964+
runUserNamespacePodWithError(rc, podName, usernsOptions)
965+
})
942966

943-
It("runtime should fail if container ID 0 is not mapped", func() {
944-
mapping := []*runtimeapi.IDMapping{{
945-
ContainerId: 1,
946-
HostId: 1000,
947-
Length: 100000,
948-
}}
949-
usernsOptions := &runtimeapi.UserNamespace{
950-
Mode: runtimeapi.NamespaceMode_POD,
951-
Uids: mapping,
952-
Gids: mapping,
953-
}
967+
It("runtime should fail if container ID 0 is not mapped", func() {
968+
mapping := []*runtimeapi.IDMapping{{
969+
ContainerId: 1,
970+
HostId: 1000,
971+
Length: 100000,
972+
}}
973+
usernsOptions := &runtimeapi.UserNamespace{
974+
Mode: runtimeapi.NamespaceMode_POD,
975+
Uids: mapping,
976+
Gids: mapping,
977+
}
954978

955-
runUserNamespacePodWithError(rc, podName, usernsOptions)
956-
})
979+
runUserNamespacePodWithError(rc, podName, usernsOptions)
980+
})
957981

958-
It("runtime should fail with NamespaceMode_CONTAINER", func() {
959-
usernsOptions := &runtimeapi.UserNamespace{Mode: runtimeapi.NamespaceMode_CONTAINER}
982+
It("runtime should fail with NamespaceMode_CONTAINER", func() {
983+
usernsOptions := &runtimeapi.UserNamespace{Mode: runtimeapi.NamespaceMode_CONTAINER}
960984

961-
runUserNamespacePodWithError(rc, podName, usernsOptions)
962-
})
985+
runUserNamespacePodWithError(rc, podName, usernsOptions)
986+
})
963987

964-
It("runtime should fail with NamespaceMode_TARGET", func() {
965-
usernsOptions := &runtimeapi.UserNamespace{Mode: runtimeapi.NamespaceMode_TARGET}
988+
It("runtime should fail with NamespaceMode_TARGET", func() {
989+
usernsOptions := &runtimeapi.UserNamespace{Mode: runtimeapi.NamespaceMode_TARGET}
966990

967-
runUserNamespacePodWithError(rc, podName, usernsOptions)
991+
runUserNamespacePodWithError(rc, podName, usernsOptions)
992+
})
968993
})
969994
})
970995
})

0 commit comments

Comments
 (0)