Skip to content

Commit ab34fbe

Browse files
authored
Merge pull request #1014 from Letty5411/0.3.x
feature: cherry-pich one commit
2 parents b06bc83 + 7618dd1 commit ab34fbe

File tree

8 files changed

+301
-80
lines changed

8 files changed

+301
-80
lines changed

apis/server/container_bridge.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,11 @@ func (s *Server) getContainer(ctx context.Context, rw http.ResponseWriter, req *
327327
}
328328
}
329329

330+
container.Mounts = []types.MountPoint{}
331+
for _, mp := range meta.Mounts {
332+
container.Mounts = append(container.Mounts, *mp)
333+
}
334+
330335
return EncodeResponse(rw, http.StatusOK, container)
331336
}
332337

apis/swagger.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2838,6 +2838,8 @@ definitions:
28382838
properties:
28392839
Type:
28402840
type: "string"
2841+
ID:
2842+
type: "string"
28412843
Name:
28422844
type: "string"
28432845
Source:
@@ -2850,6 +2852,12 @@ definitions:
28502852
type: "string"
28512853
RW:
28522854
type: "boolean"
2855+
CopyData:
2856+
type: "boolean"
2857+
Named:
2858+
type: "boolean"
2859+
Replace:
2860+
type: "string"
28532861
Propagation:
28542862
type: "string"
28552863

apis/types/mount_point.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/common_flags.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func addCommonFlags(flagSet *pflag.FlagSet) *container {
7777

7878
flagSet.StringVar(&c.utsMode, "uts", "", "UTS namespace to use")
7979

80-
flagSet.StringSliceVarP(&c.volume, "volume", "v", nil, "Bind mount volumes to container")
80+
flagSet.StringSliceVarP(&c.volume, "volume", "v", nil, "Bind mount volumes to container, format is: [source:]<destination>[:mode], [source] can be volume or host's path, <destination> is container's path, [mode] can be \"ro/rw/dr/rr/z/Z/nocopy/private/rprivate/slave/rslave/shared/rshared\"")
8181

8282
flagSet.StringVarP(&c.workdir, "workdir", "w", "", "Set the working directory in a container")
8383

daemon/mgr/container.go

Lines changed: 167 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)