@@ -334,11 +334,6 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
334334 return nil , errors .Wrap (errtypes .ErrAlreadyExisted , "container name: " + name )
335335 }
336336
337- // parse volume config
338- if err := mgr .parseVolumes (ctx , id , config ); err != nil {
339- return nil , errors .Wrap (err , "failed to parse volume argument" )
340- }
341-
342337 // check the image existed or not, and convert image id to image ref
343338 image , err := mgr .ImageMgr .GetImage (ctx , config .Image )
344339 if err != nil {
@@ -387,6 +382,11 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
387382 HostConfig : config .HostConfig ,
388383 }
389384
385+ // parse volume config
386+ if err := mgr .parseBinds (ctx , meta ); err != nil {
387+ return nil , errors .Wrap (err , "failed to parse volume argument" )
388+ }
389+
390390 // set container basefs
391391 mgr .setBaseFS (ctx , meta , id )
392392
@@ -1104,92 +1104,150 @@ func (mgr *ContainerManager) execExitedAndRelease(id string, m *ctrd.Message) er
11041104 return nil
11051105}
11061106
1107- func (mgr * ContainerManager ) parseVolumes (ctx context.Context , id string , c * types.ContainerCreateConfig ) error {
1108- logrus .Debugf ("bind volumes: %v" , c .HostConfig .Binds )
1107+ func (mgr * ContainerManager ) bindVolume (ctx context.Context , name string , meta * ContainerMeta ) (string , string , error ) {
1108+ id := meta .ID
1109+
1110+ ref := ""
1111+ driver := "local"
1112+ v , err := mgr .VolumeMgr .Get (ctx , name )
1113+ if err != nil || v == nil {
1114+ opts := map [string ]string {
1115+ "backend" : "local" ,
1116+ }
1117+ if err := mgr .VolumeMgr .Create (ctx , name , meta .HostConfig .VolumeDriver , opts , nil ); err != nil {
1118+ logrus .Errorf ("failed to create volume: %s, err: %v" , name , err )
1119+ return "" , "" , errors .Wrap (err , "failed to create volume" )
1120+ }
1121+ } else {
1122+ ref = v .Option ("ref" )
1123+ driver = v .Driver ()
1124+ }
1125+
1126+ option := map [string ]string {}
1127+ if ref == "" {
1128+ option ["ref" ] = id
1129+ } else {
1130+ option ["ref" ] = ref + "," + id
1131+ }
1132+ if _ , err := mgr .VolumeMgr .Attach (ctx , name , option ); err != nil {
1133+ logrus .Errorf ("failed to attach volume: %s, err: %v" , name , err )
1134+ return "" , "" , errors .Wrap (err , "failed to attach volume" )
1135+ }
1136+
1137+ mountPath , err := mgr .VolumeMgr .Path (ctx , name )
1138+ if err != nil {
1139+ logrus .Errorf ("failed to get the mount path of volume: %s, err: %v" , name , err )
1140+ return "" , "" , errors .Wrap (err , "failed to get volume mount path" )
1141+ }
1142+
1143+ return mountPath , driver , nil
1144+ }
1145+
1146+ func (mgr * ContainerManager ) parseBinds (ctx context.Context , meta * ContainerMeta ) error {
1147+ logrus .Debugf ("bind volumes: %v" , meta .HostConfig .Binds )
1148+
1149+ var err error
1150+
1151+ if meta .Config .Volumes == nil {
1152+ meta .Config .Volumes = make (map [string ]interface {})
1153+ }
11091154
1110- if c . Volumes == nil {
1111- c . Volumes = make (map [ string ] interface {} )
1155+ if meta . Mounts == nil {
1156+ meta . Mounts = make ([] * types. MountPoint , 0 )
11121157 }
11131158
1159+ defer func () {
1160+ if err != nil {
1161+ if err := mgr .detachVolumes (ctx , meta ); err != nil {
1162+ logrus .Errorf ("failed to detach volume, err: %v" , err )
1163+ }
1164+ }
1165+ }()
1166+
11141167 // TODO: parse c.HostConfig.VolumesFrom
11151168
1116- for i , b := range c .HostConfig .Binds {
1169+ for _ , b := range meta .HostConfig .Binds {
1170+ var parts []string
11171171 // TODO: when caused error, how to rollback.
1118- arr , err : = checkBind (b )
1172+ parts , err = checkBind (b )
11191173 if err != nil {
11201174 return err
11211175 }
1122- source := ""
1123- destination := ""
1124- switch len (arr ) {
1176+
1177+ mode := ""
1178+ mp := new (types.MountPoint )
1179+
1180+ switch len (parts ) {
11251181 case 1 :
1126- source = ""
1127- destination = arr [0 ]
1128- case 2 , 3 :
1129- source = arr [0 ]
1130- destination = arr [1 ]
1182+ mp .Source = ""
1183+ mp .Destination = parts [0 ]
1184+ case 2 :
1185+ mp .Source = parts [0 ]
1186+ mp .Destination = parts [1 ]
1187+ case 3 :
1188+ mp .Source = parts [0 ]
1189+ mp .Destination = parts [1 ]
1190+ mode = parts [2 ]
11311191 default :
11321192 return errors .Errorf ("unknown bind: %s" , b )
11331193 }
11341194
1135- if source == "" {
1136- source = randomid .Generate ()
1195+ if mp . Source == "" {
1196+ mp . Source = randomid .Generate ()
11371197 }
1138- if ! path .IsAbs (source ) {
1139- ref := ""
1140- v , err := mgr .VolumeMgr .Get (ctx , source )
1141- if err != nil || v == nil {
1142- opts := map [string ]string {
1143- "backend" : "local" ,
1144- }
1145- if err := mgr .VolumeMgr .Create (ctx , source , c .HostConfig .VolumeDriver , opts , nil ); err != nil {
1146- logrus .Errorf ("failed to create volume: %s, err: %v" , source , err )
1147- return errors .Wrap (err , "failed to create volume" )
1198+
1199+ err = parseBindMode (mp , mode )
1200+ if err != nil {
1201+ logrus .Errorf ("failed to parse bind mode: %s, err: %v" , mode , err )
1202+ return err
1203+ }
1204+
1205+ if ! path .IsAbs (mp .Source ) {
1206+ // volume bind.
1207+ name := mp .Source
1208+ if _ , exist := meta .Config .Volumes [name ]; ! exist {
1209+ mp .Name = name
1210+ mp .Source , mp .Driver , err = mgr .bindVolume (ctx , name , meta )
1211+ if err != nil {
1212+ logrus .Errorf ("failed to bind volume: %s, err: %v" , name , err )
1213+ return errors .Wrap (err , "failed to bind volume" )
11481214 }
1149- } else {
1150- ref = v .Option ("ref" )
1215+ meta .Config .Volumes [mp .Name ] = mp .Destination
11511216 }
11521217
1153- option := map [string ]string {}
1154- if ref == "" {
1155- option ["ref" ] = id
1156- } else {
1157- option ["ref" ] = ref + "," + id
1158- }
1159- if _ , err := mgr .VolumeMgr .Attach (ctx , source , option ); err != nil {
1160- logrus .Errorf ("failed to attach volume: %s, err: %v" , source , err )
1161- return errors .Wrap (err , "failed to attach volume" )
1162- }
1218+ if mp .Replace != "" {
1219+ mp .Source , err = mgr .VolumeMgr .Path (ctx , name )
1220+ if err != nil {
1221+ return err
1222+ }
11631223
1164- mountPath , err := mgr .VolumeMgr .Path (ctx , source )
1165- if err != nil {
1166- logrus .Errorf ("failed to get the mount path of volume: %s, err: %v" , source , err )
1167- return errors .Wrap (err , "failed to get volume mount path" )
1224+ switch mp .Replace {
1225+ case "dr" :
1226+ mp .Source = path .Join (mp .Source , mp .Destination )
1227+ case "rr" :
1228+ mp .Source = path .Join (mp .Source , randomid .Generate ())
1229+ }
1230+
1231+ mp .Name = ""
1232+ mp .Named = false
1233+ mp .Driver = ""
11681234 }
1235+ }
11691236
1170- c .Volumes [source ] = destination
1171- source = mountPath
1172- } else if _ , err := os .Stat (source ); err != nil {
1237+ if _ , err = os .Stat (mp .Source ); err != nil {
1238+ // host directory bind into container.
11731239 if ! os .IsNotExist (err ) {
1174- return errors .Errorf ("failed to stat %q: %v" , source , err )
1240+ return errors .Errorf ("failed to stat %q: %v" , mp . Source , err )
11751241 }
11761242 // Create the host path if it doesn't exist.
1177- if err : = os .MkdirAll (source , 0755 ); err != nil {
1178- return errors .Errorf ("failed to mkdir %q: %v" , source , err )
1243+ if err = os .MkdirAll (mp . Source , 0755 ); err != nil {
1244+ return errors .Errorf ("failed to mkdir %q: %v" , mp . Source , err )
11791245 }
11801246 }
11811247
1182- switch len (arr ) {
1183- case 1 :
1184- b = fmt .Sprintf ("%s:%s" , source , arr [0 ])
1185- case 2 , 3 :
1186- arr [0 ] = source
1187- b = strings .Join (arr , ":" )
1188- default :
1189- }
1190-
1191- c .HostConfig .Binds [i ] = b
1248+ meta .Mounts = append (meta .Mounts , mp )
11921249 }
1250+
11931251 return nil
11941252}
11951253
@@ -1290,3 +1348,49 @@ func checkBind(b string) ([]string, error) {
12901348
12911349 return arr , nil
12921350}
1351+
1352+ func parseBindMode (mp * types.MountPoint , mode string ) error {
1353+ mp .RW = true
1354+ mp .CopyData = true
1355+
1356+ defaultMode := 0
1357+ rwMode := 0
1358+ labelMode := 0
1359+ replaceMode := 0
1360+ copyMode := 0
1361+ propagationMode := 0
1362+
1363+ for _ , m := range strings .Split (mode , "," ) {
1364+ switch m {
1365+ case "" :
1366+ defaultMode ++
1367+ case "ro" :
1368+ mp .RW = false
1369+ rwMode ++
1370+ case "rw" :
1371+ mp .RW = true
1372+ rwMode ++
1373+ case "dr" , "rr" :
1374+ // direct replace mode, random replace mode
1375+ mp .Replace = m
1376+ replaceMode ++
1377+ case "z" , "Z" :
1378+ labelMode ++
1379+ case "nocopy" :
1380+ mp .CopyData = false
1381+ copyMode ++
1382+ case "private" , "rprivate" , "slave" , "rslave" , "shared" , "rshared" :
1383+ mp .Propagation = m
1384+ propagationMode ++
1385+ default :
1386+ return fmt .Errorf ("known bind mode: %s" , mode )
1387+ }
1388+ }
1389+
1390+ if defaultMode > 2 || rwMode > 2 || replaceMode > 2 || copyMode > 2 || propagationMode > 2 {
1391+ return fmt .Errorf ("invalid bind mode: %s" , mode )
1392+ }
1393+
1394+ mp .Mode = mode
1395+ return nil
1396+ }
0 commit comments