@@ -339,11 +339,6 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
339339 return nil , errors .Wrap (errtypes .ErrAlreadyExisted , "container name: " + name )
340340 }
341341
342- // parse volume config
343- if err := mgr .parseVolumes (ctx , id , config ); err != nil {
344- return nil , errors .Wrap (err , "failed to parse volume argument" )
345- }
346-
347342 // check the image existed or not, and convert image id to image ref
348343 image , err := mgr .ImageMgr .GetImage (ctx , config .Image )
349344 if err != nil {
@@ -392,6 +387,11 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty
392387 HostConfig : config .HostConfig ,
393388 }
394389
390+ // parse volume config
391+ if err := mgr .parseBinds (ctx , meta ); err != nil {
392+ return nil , errors .Wrap (err , "failed to parse volume argument" )
393+ }
394+
395395 // set container basefs
396396 mgr .setBaseFS (ctx , meta , id )
397397
@@ -1277,92 +1277,150 @@ func (mgr *ContainerManager) execExitedAndRelease(id string, m *ctrd.Message) er
12771277 return nil
12781278}
12791279
1280- func (mgr * ContainerManager ) parseVolumes (ctx context.Context , id string , c * types. ContainerCreateConfig ) error {
1281- logrus . Debugf ( "bind volumes: %v" , c . HostConfig . Binds )
1280+ func (mgr * ContainerManager ) bindVolume (ctx context.Context , name string , meta * ContainerMeta ) ( string , string , error ) {
1281+ id := meta . ID
12821282
1283- if c .Volumes == nil {
1284- c .Volumes = make (map [string ]interface {})
1283+ ref := ""
1284+ driver := "local"
1285+ v , err := mgr .VolumeMgr .Get (ctx , name )
1286+ if err != nil || v == nil {
1287+ opts := map [string ]string {
1288+ "backend" : "local" ,
1289+ }
1290+ if err := mgr .VolumeMgr .Create (ctx , name , meta .HostConfig .VolumeDriver , opts , nil ); err != nil {
1291+ logrus .Errorf ("failed to create volume: %s, err: %v" , name , err )
1292+ return "" , "" , errors .Wrap (err , "failed to create volume" )
1293+ }
1294+ } else {
1295+ ref = v .Option ("ref" )
1296+ driver = v .Driver ()
1297+ }
1298+
1299+ option := map [string ]string {}
1300+ if ref == "" {
1301+ option ["ref" ] = id
1302+ } else {
1303+ option ["ref" ] = ref + "," + id
1304+ }
1305+ if _ , err := mgr .VolumeMgr .Attach (ctx , name , option ); err != nil {
1306+ logrus .Errorf ("failed to attach volume: %s, err: %v" , name , err )
1307+ return "" , "" , errors .Wrap (err , "failed to attach volume" )
12851308 }
12861309
1310+ mountPath , err := mgr .VolumeMgr .Path (ctx , name )
1311+ if err != nil {
1312+ logrus .Errorf ("failed to get the mount path of volume: %s, err: %v" , name , err )
1313+ return "" , "" , errors .Wrap (err , "failed to get volume mount path" )
1314+ }
1315+
1316+ return mountPath , driver , nil
1317+ }
1318+
1319+ func (mgr * ContainerManager ) parseBinds (ctx context.Context , meta * ContainerMeta ) error {
1320+ logrus .Debugf ("bind volumes: %v" , meta .HostConfig .Binds )
1321+
1322+ var err error
1323+
1324+ if meta .Config .Volumes == nil {
1325+ meta .Config .Volumes = make (map [string ]interface {})
1326+ }
1327+
1328+ if meta .Mounts == nil {
1329+ meta .Mounts = make ([]* types.MountPoint , 0 )
1330+ }
1331+
1332+ defer func () {
1333+ if err != nil {
1334+ if err := mgr .detachVolumes (ctx , meta ); err != nil {
1335+ logrus .Errorf ("failed to detach volume, err: %v" , err )
1336+ }
1337+ }
1338+ }()
1339+
12871340 // TODO: parse c.HostConfig.VolumesFrom
12881341
1289- for i , b := range c .HostConfig .Binds {
1342+ for _ , b := range meta .HostConfig .Binds {
1343+ var parts []string
12901344 // TODO: when caused error, how to rollback.
1291- arr , err : = checkBind (b )
1345+ parts , err = checkBind (b )
12921346 if err != nil {
12931347 return err
12941348 }
1295- source := ""
1296- destination := ""
1297- switch len (arr ) {
1349+
1350+ mode := ""
1351+ mp := new (types.MountPoint )
1352+
1353+ switch len (parts ) {
12981354 case 1 :
1299- source = ""
1300- destination = arr [0 ]
1301- case 2 , 3 :
1302- source = arr [0 ]
1303- destination = arr [1 ]
1355+ mp .Source = ""
1356+ mp .Destination = parts [0 ]
1357+ case 2 :
1358+ mp .Source = parts [0 ]
1359+ mp .Destination = parts [1 ]
1360+ case 3 :
1361+ mp .Source = parts [0 ]
1362+ mp .Destination = parts [1 ]
1363+ mode = parts [2 ]
13041364 default :
13051365 return errors .Errorf ("unknown bind: %s" , b )
13061366 }
13071367
1308- if source == "" {
1309- source = randomid .Generate ()
1368+ if mp . Source == "" {
1369+ mp . Source = randomid .Generate ()
13101370 }
1311- if ! path .IsAbs (source ) {
1312- ref := ""
1313- v , err := mgr .VolumeMgr .Get (ctx , source )
1314- if err != nil || v == nil {
1315- opts := map [string ]string {
1316- "backend" : "local" ,
1317- }
1318- if err := mgr .VolumeMgr .Create (ctx , source , c .HostConfig .VolumeDriver , opts , nil ); err != nil {
1319- logrus .Errorf ("failed to create volume: %s, err: %v" , source , err )
1320- return errors .Wrap (err , "failed to create volume" )
1371+
1372+ err = parseBindMode (mp , mode )
1373+ if err != nil {
1374+ logrus .Errorf ("failed to parse bind mode: %s, err: %v" , mode , err )
1375+ return err
1376+ }
1377+
1378+ if ! path .IsAbs (mp .Source ) {
1379+ // volume bind.
1380+ name := mp .Source
1381+ if _ , exist := meta .Config .Volumes [name ]; ! exist {
1382+ mp .Name = name
1383+ mp .Source , mp .Driver , err = mgr .bindVolume (ctx , name , meta )
1384+ if err != nil {
1385+ logrus .Errorf ("failed to bind volume: %s, err: %v" , name , err )
1386+ return errors .Wrap (err , "failed to bind volume" )
13211387 }
1322- } else {
1323- ref = v .Option ("ref" )
1388+ meta .Config .Volumes [mp .Name ] = mp .Destination
13241389 }
13251390
1326- option := map [string ]string {}
1327- if ref == "" {
1328- option ["ref" ] = id
1329- } else {
1330- option ["ref" ] = ref + "," + id
1331- }
1332- if _ , err := mgr .VolumeMgr .Attach (ctx , source , option ); err != nil {
1333- logrus .Errorf ("failed to attach volume: %s, err: %v" , source , err )
1334- return errors .Wrap (err , "failed to attach volume" )
1335- }
1391+ if mp .Replace != "" {
1392+ mp .Source , err = mgr .VolumeMgr .Path (ctx , name )
1393+ if err != nil {
1394+ return err
1395+ }
1396+
1397+ switch mp .Replace {
1398+ case "dr" :
1399+ mp .Source = path .Join (mp .Source , mp .Destination )
1400+ case "rr" :
1401+ mp .Source = path .Join (mp .Source , randomid .Generate ())
1402+ }
13361403
1337- mountPath , err := mgr .VolumeMgr .Path (ctx , source )
1338- if err != nil {
1339- logrus .Errorf ("failed to get the mount path of volume: %s, err: %v" , source , err )
1340- return errors .Wrap (err , "failed to get volume mount path" )
1404+ mp .Name = ""
1405+ mp .Named = false
1406+ mp .Driver = ""
13411407 }
1408+ }
13421409
1343- c .Volumes [source ] = destination
1344- source = mountPath
1345- } else if _ , err := os .Stat (source ); err != nil {
1410+ if _ , err = os .Stat (mp .Source ); err != nil {
1411+ // host directory bind into container.
13461412 if ! os .IsNotExist (err ) {
1347- return errors .Errorf ("failed to stat %q: %v" , source , err )
1413+ return errors .Errorf ("failed to stat %q: %v" , mp . Source , err )
13481414 }
13491415 // Create the host path if it doesn't exist.
1350- if err : = os .MkdirAll (source , 0755 ); err != nil {
1351- return errors .Errorf ("failed to mkdir %q: %v" , source , err )
1416+ if err = os .MkdirAll (mp . Source , 0755 ); err != nil {
1417+ return errors .Errorf ("failed to mkdir %q: %v" , mp . Source , err )
13521418 }
13531419 }
13541420
1355- switch len (arr ) {
1356- case 1 :
1357- b = fmt .Sprintf ("%s:%s" , source , arr [0 ])
1358- case 2 , 3 :
1359- arr [0 ] = source
1360- b = strings .Join (arr , ":" )
1361- default :
1362- }
1363-
1364- c .HostConfig .Binds [i ] = b
1421+ meta .Mounts = append (meta .Mounts , mp )
13651422 }
1423+
13661424 return nil
13671425}
13681426
@@ -1463,3 +1521,49 @@ func checkBind(b string) ([]string, error) {
14631521
14641522 return arr , nil
14651523}
1524+
1525+ func parseBindMode (mp * types.MountPoint , mode string ) error {
1526+ mp .RW = true
1527+ mp .CopyData = true
1528+
1529+ defaultMode := 0
1530+ rwMode := 0
1531+ labelMode := 0
1532+ replaceMode := 0
1533+ copyMode := 0
1534+ propagationMode := 0
1535+
1536+ for _ , m := range strings .Split (mode , "," ) {
1537+ switch m {
1538+ case "" :
1539+ defaultMode ++
1540+ case "ro" :
1541+ mp .RW = false
1542+ rwMode ++
1543+ case "rw" :
1544+ mp .RW = true
1545+ rwMode ++
1546+ case "dr" , "rr" :
1547+ // direct replace mode, random replace mode
1548+ mp .Replace = m
1549+ replaceMode ++
1550+ case "z" , "Z" :
1551+ labelMode ++
1552+ case "nocopy" :
1553+ mp .CopyData = false
1554+ copyMode ++
1555+ case "private" , "rprivate" , "slave" , "rslave" , "shared" , "rshared" :
1556+ mp .Propagation = m
1557+ propagationMode ++
1558+ default :
1559+ return fmt .Errorf ("unknown bind mode: %s" , mode )
1560+ }
1561+ }
1562+
1563+ if defaultMode > 1 || rwMode > 1 || replaceMode > 1 || copyMode > 1 || propagationMode > 1 {
1564+ return fmt .Errorf ("invalid bind mode: %s" , mode )
1565+ }
1566+
1567+ mp .Mode = mode
1568+ return nil
1569+ }
0 commit comments