@@ -962,6 +962,170 @@ func ContainerCreate(opt *option.Option) {
962962 Expect (responseReadIopsDevices [0 ].String ()).Should (Equal (readIopsDevices [0 ].String ()))
963963 Expect (responseWriteIopsDevices [0 ].String ()).Should (Equal (writeIopsDevices [0 ].String ()))
964964 })
965+
966+ It ("should create container with volumes from another container" , func () {
967+ tID := testContainerName
968+
969+ // Create temporary directories
970+ rwDir , err := os .MkdirTemp ("" , "rw" )
971+ Expect (err ).Should (BeNil ())
972+ roDir , err := os .MkdirTemp ("" , "ro" )
973+ Expect (err ).Should (BeNil ())
974+ defer os .RemoveAll (rwDir )
975+ defer os .RemoveAll (roDir )
976+
977+ // Create named volumes
978+ rwVolName := tID + "-rw"
979+ roVolName := tID + "-ro"
980+ command .Run (opt , "volume" , "create" , rwVolName )
981+ command .Run (opt , "volume" , "create" , roVolName )
982+ defer command .Run (opt , "volume" , "rm" , "-f" , rwVolName )
983+ defer command .Run (opt , "volume" , "rm" , "-f" , roVolName )
984+
985+ // Create source container with multiple volume types
986+ fromContainerName := tID + "-from"
987+ sourceOptions := types.ContainerCreateRequest {}
988+ sourceOptions .Image = defaultImage
989+ sourceOptions .Cmd = []string {"top" }
990+ sourceOptions .HostConfig .Binds = []string {
991+ fmt .Sprintf ("%s:%s" , rwDir , "/mnt1" ),
992+ fmt .Sprintf ("%s:%s:ro" , roDir , "/mnt2" ),
993+ fmt .Sprintf ("%s:%s" , rwVolName , "/mnt3" ),
994+ fmt .Sprintf ("%s:%s:ro" , roVolName , "/mnt4" ),
995+ }
996+
997+ // Create and start source container
998+ statusCode , _ := createContainer (uClient , url , fromContainerName , sourceOptions )
999+ Expect (statusCode ).Should (Equal (http .StatusCreated ))
1000+ command .Run (opt , "start" , fromContainerName )
1001+ defer command .Run (opt , "rm" , "-f" , fromContainerName )
1002+
1003+ // Create target container with volumes-from
1004+ toContainerName := tID + "-to"
1005+ targetOptions := types.ContainerCreateRequest {}
1006+ targetOptions .Image = defaultImage
1007+ targetOptions .Cmd = []string {"top" }
1008+ targetOptions .HostConfig .VolumesFrom = []string {fromContainerName }
1009+
1010+ // Create and start target container
1011+ statusCode , _ = createContainer (uClient , url , toContainerName , targetOptions )
1012+ Expect (statusCode ).Should (Equal (http .StatusCreated ))
1013+ command .Run (opt , "start" , toContainerName )
1014+ defer command .Run (opt , "rm" , "-f" , toContainerName )
1015+
1016+ // Test write permissions
1017+ command .Run (opt , "exec" , toContainerName , "sh" , "-exc" , "echo -n str1 > /mnt1/file1" )
1018+ command .RunWithoutSuccessfulExit (opt , "exec" , toContainerName , "sh" , "-exc" , "echo -n str2 > /mnt2/file2" )
1019+ command .Run (opt , "exec" , toContainerName , "sh" , "-exc" , "echo -n str3 > /mnt3/file3" )
1020+ command .RunWithoutSuccessfulExit (opt , "exec" , toContainerName , "sh" , "-exc" , "echo -n str4 > /mnt4/file4" )
1021+
1022+ // Remove target container
1023+ command .Run (opt , "rm" , "-f" , toContainerName )
1024+
1025+ // Create a new container to verify data persistence
1026+ verifyOptions := types.ContainerCreateRequest {}
1027+ verifyOptions .Image = defaultImage
1028+ verifyOptions .Cmd = []string {"sh" , "-c" , "cat /mnt1/file1 /mnt3/file3" }
1029+ verifyOptions .HostConfig .VolumesFrom = []string {fromContainerName }
1030+
1031+ statusCode , _ = createContainer (uClient , url , "verify-container" , verifyOptions )
1032+ Expect (statusCode ).Should (Equal (http .StatusCreated ))
1033+ out := command .StdoutStr (opt , "start" , "-a" , "verify-container" )
1034+ Expect (out ).Should (Equal ("str1str3" ))
1035+ defer command .Run (opt , "rm" , "-f" , "verify-container" )
1036+ })
1037+
1038+ It ("should create a container with tmpfs mounts" , func () {
1039+ // Define options
1040+ options .Cmd = []string {"sleep" , "Infinity" }
1041+ options .HostConfig .Tmpfs = map [string ]string {
1042+ "/tmpfs1" : "rw,noexec,nosuid,size=65536k" ,
1043+ "/tmpfs2" : "" , // no options
1044+ }
1045+
1046+ // Create container
1047+ statusCode , ctr := createContainer (uClient , url , testContainerName , options )
1048+ Expect (statusCode ).Should (Equal (http .StatusCreated ))
1049+ Expect (ctr .ID ).ShouldNot (BeEmpty ())
1050+
1051+ // Start container
1052+ command .Run (opt , "start" , testContainerName )
1053+
1054+ // Verify tmpfs mounts using native inspect
1055+ nativeResp := command .Stdout (opt , "inspect" , "--mode=native" , testContainerName )
1056+ var nativeInspect []map [string ]interface {}
1057+ err := json .Unmarshal (nativeResp , & nativeInspect )
1058+ Expect (err ).Should (BeNil ())
1059+ Expect (nativeInspect ).Should (HaveLen (1 ))
1060+
1061+ // Navigate to the mounts section
1062+ spec , ok := nativeInspect [0 ]["Spec" ].(map [string ]interface {})
1063+ Expect (ok ).Should (BeTrue ())
1064+ mounts , ok := spec ["mounts" ].([]interface {})
1065+ Expect (ok ).Should (BeTrue ())
1066+
1067+ // Verify tmpfs mounts
1068+ foundMounts := make (map [string ]bool )
1069+ for _ , mount := range mounts {
1070+ m := mount .(map [string ]interface {})
1071+ if m ["type" ] == "tmpfs" {
1072+ foundMounts [m ["destination" ].(string )] = true
1073+ if m ["destination" ] == "/tmpfs1" {
1074+ options := m ["options" ].([]interface {})
1075+ optionsStr := make ([]string , len (options ))
1076+ for i , opt := range options {
1077+ optionsStr [i ] = opt .(string )
1078+ }
1079+ Expect (optionsStr ).Should (ContainElements (
1080+ "rw" ,
1081+ "noexec" ,
1082+ "nosuid" ,
1083+ "size=65536k" ,
1084+ ))
1085+ }
1086+ }
1087+ }
1088+ })
1089+
1090+ It ("should create a container with UTSMode set to host" , func () {
1091+ // Define options
1092+ options .Cmd = []string {"sleep" , "Infinity" }
1093+ options .HostConfig .UTSMode = "host"
1094+
1095+ // Create container
1096+ statusCode , ctr := createContainer (uClient , url , testContainerName , options )
1097+ Expect (statusCode ).Should (Equal (http .StatusCreated ))
1098+ Expect (ctr .ID ).ShouldNot (BeEmpty ())
1099+
1100+ // Start container
1101+ command .Run (opt , "start" , testContainerName )
1102+
1103+ // Inspect using native format to verify UTS namespace configuration
1104+ nativeResp := command .Stdout (opt , "inspect" , "--mode=native" , testContainerName )
1105+ var nativeInspect []map [string ]interface {}
1106+ err := json .Unmarshal (nativeResp , & nativeInspect )
1107+ Expect (err ).Should (BeNil ())
1108+ Expect (nativeInspect ).Should (HaveLen (1 ))
1109+
1110+ // Navigate to the namespaces section
1111+ spec , ok := nativeInspect [0 ]["Spec" ].(map [string ]interface {})
1112+ Expect (ok ).Should (BeTrue ())
1113+ linux , ok := spec ["linux" ].(map [string ]interface {})
1114+ Expect (ok ).Should (BeTrue ())
1115+ namespaces , ok := linux ["namespaces" ].([]interface {})
1116+ Expect (ok ).Should (BeTrue ())
1117+
1118+ // Verify UTS namespace is not present (indicating host namespace is used)
1119+ foundUTSNamespace := false
1120+ for _ , ns := range namespaces {
1121+ namespace := ns .(map [string ]interface {})
1122+ if namespace ["type" ] == "uts" {
1123+ foundUTSNamespace = true
1124+ break
1125+ }
1126+ }
1127+ Expect (foundUTSNamespace ).Should (BeFalse ())
1128+ })
9651129 })
9661130}
9671131
0 commit comments