| ... | ... |
@@ -6,8 +6,6 @@ import ( |
| 6 | 6 |
"strings" |
| 7 | 7 |
"time" |
| 8 | 8 |
|
| 9 |
- "golang.org/x/net/context" |
|
| 10 |
- |
|
| 11 | 9 |
"github.com/docker/docker/api/types" |
| 12 | 10 |
"github.com/docker/docker/api/types/swarm" |
| 13 | 11 |
"github.com/docker/docker/cli" |
| ... | ... |
@@ -17,6 +15,7 @@ import ( |
| 17 | 17 |
"github.com/docker/docker/utils/templates" |
| 18 | 18 |
"github.com/docker/go-units" |
| 19 | 19 |
"github.com/spf13/cobra" |
| 20 |
+ "golang.org/x/net/context" |
|
| 20 | 21 |
) |
| 21 | 22 |
|
| 22 | 23 |
type infoOptions struct {
|
| ... | ... |
@@ -66,11 +65,6 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
|
| 66 | 66 |
if info.DriverStatus != nil {
|
| 67 | 67 |
for _, pair := range info.DriverStatus {
|
| 68 | 68 |
fmt.Fprintf(dockerCli.Out(), " %s: %s\n", pair[0], pair[1]) |
| 69 |
- |
|
| 70 |
- // print a warning if devicemapper is using a loopback file |
|
| 71 |
- if pair[0] == "Data loop file" {
|
|
| 72 |
- fmt.Fprintln(dockerCli.Err(), " WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.") |
|
| 73 |
- } |
|
| 74 | 69 |
} |
| 75 | 70 |
|
| 76 | 71 |
} |
| ... | ... |
@@ -228,43 +222,6 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
|
| 228 | 228 |
fmt.Fprintf(dockerCli.Out(), "Registry: %v\n", info.IndexServerAddress) |
| 229 | 229 |
} |
| 230 | 230 |
|
| 231 |
- // Only output these warnings if the server does not support these features |
|
| 232 |
- if info.OSType != "windows" {
|
|
| 233 |
- if !info.MemoryLimit {
|
|
| 234 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No memory limit support") |
|
| 235 |
- } |
|
| 236 |
- if !info.SwapLimit {
|
|
| 237 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support") |
|
| 238 |
- } |
|
| 239 |
- if !info.KernelMemory {
|
|
| 240 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support") |
|
| 241 |
- } |
|
| 242 |
- if !info.OomKillDisable {
|
|
| 243 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support") |
|
| 244 |
- } |
|
| 245 |
- if !info.CPUCfsQuota {
|
|
| 246 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs quota support") |
|
| 247 |
- } |
|
| 248 |
- if !info.CPUCfsPeriod {
|
|
| 249 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs period support") |
|
| 250 |
- } |
|
| 251 |
- if !info.CPUShares {
|
|
| 252 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu shares support") |
|
| 253 |
- } |
|
| 254 |
- if !info.CPUSet {
|
|
| 255 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: No cpuset support") |
|
| 256 |
- } |
|
| 257 |
- if !info.IPv4Forwarding {
|
|
| 258 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: IPv4 forwarding is disabled") |
|
| 259 |
- } |
|
| 260 |
- if !info.BridgeNfIptables {
|
|
| 261 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-iptables is disabled") |
|
| 262 |
- } |
|
| 263 |
- if !info.BridgeNfIP6tables {
|
|
| 264 |
- fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-ip6tables is disabled") |
|
| 265 |
- } |
|
| 266 |
- } |
|
| 267 |
- |
|
| 268 | 231 |
if info.Labels != nil {
|
| 269 | 232 |
fmt.Fprintln(dockerCli.Out(), "Labels:") |
| 270 | 233 |
for _, attribute := range info.Labels {
|
| ... | ... |
@@ -317,11 +274,85 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
|
| 317 | 317 |
} |
| 318 | 318 |
} |
| 319 | 319 |
|
| 320 |
- fmt.Fprintf(dockerCli.Out(), "Live Restore Enabled: %v\n", info.LiveRestoreEnabled) |
|
| 320 |
+ fmt.Fprintf(dockerCli.Out(), "Live Restore Enabled: %v\n\n", info.LiveRestoreEnabled) |
|
| 321 |
+ |
|
| 322 |
+ // Only output these warnings if the server does not support these features |
|
| 323 |
+ if info.OSType != "windows" {
|
|
| 324 |
+ printStorageDriverWarnings(dockerCli, info) |
|
| 325 |
+ |
|
| 326 |
+ if !info.MemoryLimit {
|
|
| 327 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No memory limit support") |
|
| 328 |
+ } |
|
| 329 |
+ if !info.SwapLimit {
|
|
| 330 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support") |
|
| 331 |
+ } |
|
| 332 |
+ if !info.KernelMemory {
|
|
| 333 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support") |
|
| 334 |
+ } |
|
| 335 |
+ if !info.OomKillDisable {
|
|
| 336 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support") |
|
| 337 |
+ } |
|
| 338 |
+ if !info.CPUCfsQuota {
|
|
| 339 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs quota support") |
|
| 340 |
+ } |
|
| 341 |
+ if !info.CPUCfsPeriod {
|
|
| 342 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs period support") |
|
| 343 |
+ } |
|
| 344 |
+ if !info.CPUShares {
|
|
| 345 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu shares support") |
|
| 346 |
+ } |
|
| 347 |
+ if !info.CPUSet {
|
|
| 348 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: No cpuset support") |
|
| 349 |
+ } |
|
| 350 |
+ if !info.IPv4Forwarding {
|
|
| 351 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: IPv4 forwarding is disabled") |
|
| 352 |
+ } |
|
| 353 |
+ if !info.BridgeNfIptables {
|
|
| 354 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-iptables is disabled") |
|
| 355 |
+ } |
|
| 356 |
+ if !info.BridgeNfIP6tables {
|
|
| 357 |
+ fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-ip6tables is disabled") |
|
| 358 |
+ } |
|
| 359 |
+ } |
|
| 321 | 360 |
|
| 322 | 361 |
return nil |
| 323 | 362 |
} |
| 324 | 363 |
|
| 364 |
+func printStorageDriverWarnings(dockerCli *command.DockerCli, info types.Info) {
|
|
| 365 |
+ if info.DriverStatus == nil {
|
|
| 366 |
+ return |
|
| 367 |
+ } |
|
| 368 |
+ |
|
| 369 |
+ for _, pair := range info.DriverStatus {
|
|
| 370 |
+ if pair[0] == "Data loop file" {
|
|
| 371 |
+ fmt.Fprintf(dockerCli.Err(), "WARNING: %s: usage of loopback devices is strongly discouraged for production use.\n Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.\n", info.Driver) |
|
| 372 |
+ } |
|
| 373 |
+ if pair[0] == "Supports d_type" && pair[1] == "false" {
|
|
| 374 |
+ backingFs := getBackingFs(info) |
|
| 375 |
+ |
|
| 376 |
+ msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", info.Driver, backingFs)
|
|
| 377 |
+ if backingFs == "xfs" {
|
|
| 378 |
+ msg += " Reformat the filesystem with ftype=1 to enable d_type support.\n" |
|
| 379 |
+ } |
|
| 380 |
+ msg += " Running without d_type support will not be supported in future releases." |
|
| 381 |
+ fmt.Fprintln(dockerCli.Err(), msg) |
|
| 382 |
+ } |
|
| 383 |
+ } |
|
| 384 |
+} |
|
| 385 |
+ |
|
| 386 |
+func getBackingFs(info types.Info) string {
|
|
| 387 |
+ if info.DriverStatus == nil {
|
|
| 388 |
+ return "" |
|
| 389 |
+ } |
|
| 390 |
+ |
|
| 391 |
+ for _, pair := range info.DriverStatus {
|
|
| 392 |
+ if pair[0] == "Backing Filesystem" {
|
|
| 393 |
+ return pair[1] |
|
| 394 |
+ } |
|
| 395 |
+ } |
|
| 396 |
+ return "" |
|
| 397 |
+} |
|
| 398 |
+ |
|
| 325 | 399 |
func formatInfo(dockerCli *command.DockerCli, info types.Info, format string) error {
|
| 326 | 400 |
tmpl, err := templates.Parse(format) |
| 327 | 401 |
if err != nil {
|
| ... | ... |
@@ -213,6 +213,8 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
| 213 | 213 |
} |
| 214 | 214 |
} |
| 215 | 215 |
|
| 216 |
+ label.Relabel(localMountPath, c.MountLabel, false) |
|
| 217 |
+ |
|
| 216 | 218 |
// remount secrets ro |
| 217 | 219 |
if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "remount,ro,"+tmpfsOwnership); err != nil {
|
| 218 | 220 |
return errors.Wrap(err, "unable to remount secret dir as readonly") |
| ... | ... |
@@ -16,7 +16,6 @@ import ( |
| 16 | 16 |
"github.com/docker/docker/container" |
| 17 | 17 |
"github.com/docker/docker/volume" |
| 18 | 18 |
"github.com/docker/docker/volume/drivers" |
| 19 |
- "github.com/opencontainers/runc/libcontainer/label" |
|
| 20 | 19 |
) |
| 21 | 20 |
|
| 22 | 21 |
var ( |
| ... | ... |
@@ -195,9 +194,6 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo |
| 195 | 195 |
return err |
| 196 | 196 |
} |
| 197 | 197 |
|
| 198 |
- if err := label.Relabel(mp.Source, container.MountLabel, false); err != nil {
|
|
| 199 |
- return err |
|
| 200 |
- } |
|
| 201 | 198 |
mp.Volume = v |
| 202 | 199 |
mp.Name = v.Name() |
| 203 | 200 |
mp.Driver = v.DriverName() |
| ... | ... |
@@ -575,7 +575,7 @@ func (pm *Manager) Remove(name string, config *types.PluginRmConfig) error {
|
| 575 | 575 |
func getMounts(root string) ([]string, error) {
|
| 576 | 576 |
infos, err := mount.GetMounts() |
| 577 | 577 |
if err != nil {
|
| 578 |
- return nil, errors.Wrap(err, "failed to read mount table while performing recursive unmount") |
|
| 578 |
+ return nil, errors.Wrap(err, "failed to read mount table") |
|
| 579 | 579 |
} |
| 580 | 580 |
|
| 581 | 581 |
var mounts []string |
| ... | ... |
@@ -171,9 +171,17 @@ func (pm *Manager) upgradePlugin(p *v2.Plugin, configDigest digest.Digest, blobs |
| 171 | 171 |
|
| 172 | 172 |
pdir := filepath.Join(pm.config.Root, p.PluginObj.ID) |
| 173 | 173 |
orig := filepath.Join(pdir, "rootfs") |
| 174 |
+ |
|
| 175 |
+ // Make sure nothing is mounted |
|
| 176 |
+ // This could happen if the plugin was disabled with `-f` with active mounts. |
|
| 177 |
+ // If there is anything in `orig` is still mounted, this should error out. |
|
| 178 |
+ if err := recursiveUnmount(orig); err != nil {
|
|
| 179 |
+ return err |
|
| 180 |
+ } |
|
| 181 |
+ |
|
| 174 | 182 |
backup := orig + "-old" |
| 175 | 183 |
if err := os.Rename(orig, backup); err != nil {
|
| 176 |
- return err |
|
| 184 |
+ return errors.Wrap(err, "error backing up plugin data before upgrade") |
|
| 177 | 185 |
} |
| 178 | 186 |
|
| 179 | 187 |
defer func() {
|
| ... | ... |
@@ -519,7 +519,11 @@ func lookupVolume(driverName, volumeName string) (volume.Volume, error) {
|
| 519 | 519 |
if err != nil {
|
| 520 | 520 |
err = errors.Cause(err) |
| 521 | 521 |
if _, ok := err.(net.Error); ok {
|
| 522 |
- return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName()) |
|
| 522 |
+ if v != nil {
|
|
| 523 |
+ volumeName = v.Name() |
|
| 524 |
+ driverName = v.DriverName() |
|
| 525 |
+ } |
|
| 526 |
+ return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) |
|
| 523 | 527 |
} |
| 524 | 528 |
|
| 525 | 529 |
// At this point, the error could be anything from the driver, such as "no such volume" |
| ... | ... |
@@ -542,7 +546,7 @@ func (s *VolumeStore) Remove(v volume.Volume) error {
|
| 542 | 542 |
|
| 543 | 543 |
vd, err := volumedrivers.GetDriver(v.DriverName()) |
| 544 | 544 |
if err != nil {
|
| 545 |
- return &OpErr{Err: err, Name: vd.Name(), Op: "remove"}
|
|
| 545 |
+ return &OpErr{Err: err, Name: v.DriverName(), Op: "remove"}
|
|
| 546 | 546 |
} |
| 547 | 547 |
|
| 548 | 548 |
logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
|
| ... | ... |
@@ -124,7 +124,20 @@ type MountPoint struct {
|
| 124 | 124 |
|
| 125 | 125 |
// Setup sets up a mount point by either mounting the volume if it is |
| 126 | 126 |
// configured, or creating the source directory if supplied. |
| 127 |
-func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (string, error) {
|
|
| 127 |
+func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (path string, err error) {
|
|
| 128 |
+ defer func() {
|
|
| 129 |
+ if err == nil {
|
|
| 130 |
+ if label.RelabelNeeded(m.Mode) {
|
|
| 131 |
+ if err = label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode)); err != nil {
|
|
| 132 |
+ path = "" |
|
| 133 |
+ err = errors.Wrapf(err, "error setting label on mount source '%s'", m.Source) |
|
| 134 |
+ return |
|
| 135 |
+ } |
|
| 136 |
+ } |
|
| 137 |
+ } |
|
| 138 |
+ return |
|
| 139 |
+ }() |
|
| 140 |
+ |
|
| 128 | 141 |
if m.Volume != nil {
|
| 129 | 142 |
id := m.ID |
| 130 | 143 |
if id == "" {
|
| ... | ... |
@@ -152,11 +165,6 @@ func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (string, err |
| 152 | 152 |
} |
| 153 | 153 |
} |
| 154 | 154 |
} |
| 155 |
- if label.RelabelNeeded(m.Mode) {
|
|
| 156 |
- if err := label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode)); err != nil {
|
|
| 157 |
- return "", errors.Wrapf(err, "error setting label on mount source '%s'", m.Source) |
|
| 158 |
- } |
|
| 159 |
- } |
|
| 160 | 155 |
return m.Source, nil |
| 161 | 156 |
} |
| 162 | 157 |
|
| ... | ... |
@@ -303,10 +311,12 @@ func ParseMountSpec(cfg mounttypes.Mount, options ...func(*validateOpts)) (*Moun |
| 303 | 303 |
} |
| 304 | 304 |
case mounttypes.TypeBind: |
| 305 | 305 |
mp.Source = clean(convertSlash(cfg.Source)) |
| 306 |
- if cfg.BindOptions != nil {
|
|
| 307 |
- if len(cfg.BindOptions.Propagation) > 0 {
|
|
| 308 |
- mp.Propagation = cfg.BindOptions.Propagation |
|
| 309 |
- } |
|
| 306 |
+ if cfg.BindOptions != nil && len(cfg.BindOptions.Propagation) > 0 {
|
|
| 307 |
+ mp.Propagation = cfg.BindOptions.Propagation |
|
| 308 |
+ } else {
|
|
| 309 |
+ // If user did not specify a propagation mode, get |
|
| 310 |
+ // default propagation mode. |
|
| 311 |
+ mp.Propagation = DefaultPropagationMode |
|
| 310 | 312 |
} |
| 311 | 313 |
case mounttypes.TypeTmpfs: |
| 312 | 314 |
// NOP |
| ... | ... |
@@ -229,10 +229,10 @@ func TestParseMountSpec(t *testing.T) {
|
| 229 | 229 |
defer os.RemoveAll(testDir) |
| 230 | 230 |
|
| 231 | 231 |
cases := []c{
|
| 232 |
- {mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath, ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath}},
|
|
| 233 |
- {mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, RW: true}},
|
|
| 234 |
- {mount.Mount{Type: mount.TypeBind, Source: testDir + string(os.PathSeparator), Target: testDestinationPath, ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath}},
|
|
| 235 |
- {mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath + string(os.PathSeparator), ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath}},
|
|
| 232 |
+ {mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath, ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, Propagation: DefaultPropagationMode}},
|
|
| 233 |
+ {mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, RW: true, Propagation: DefaultPropagationMode}},
|
|
| 234 |
+ {mount.Mount{Type: mount.TypeBind, Source: testDir + string(os.PathSeparator), Target: testDestinationPath, ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, Propagation: DefaultPropagationMode}},
|
|
| 235 |
+ {mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath + string(os.PathSeparator), ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, Propagation: DefaultPropagationMode}},
|
|
| 236 | 236 |
{mount.Mount{Type: mount.TypeVolume, Target: testDestinationPath}, MountPoint{Type: mount.TypeVolume, Destination: testDestinationPath, RW: true, CopyData: DefaultCopyMode}},
|
| 237 | 237 |
{mount.Mount{Type: mount.TypeVolume, Target: testDestinationPath + string(os.PathSeparator)}, MountPoint{Type: mount.TypeVolume, Destination: testDestinationPath, RW: true, CopyData: DefaultCopyMode}},
|
| 238 | 238 |
} |