bolt k/v pairs are only valid for the life of a transaction.
This means the memory that the k/v pair is referencing may be invalid if
it is accessed outside of the transaction.
This can potentially cause a panic.
For reference: https://godoc.org/github.com/boltdb/bolt#hdr-Caveats
To fix this issue, unmarshal the stored data into volume meta before
closing the transaction.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Previously, it was comparing against the driver name passed in by the
caller. This could lead to subtle issues when using plugins, like
"plugin" vs. "plugin:latest".
Also, remove "conflict:" prefix to improve the error message.
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
Ensures all known volumes (known b/c they are persisted to disk) have
their volume drivers refcounted properly.
In testing this, I found an issue with `--live-restore` (required since
currently the provided volume plugin doesn't keep state on restart)
where restorted plugins did not have a plugin client loaded causing a
panic when trying to use the plugin.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Adds 2 new methods to v2 plugin `Acquire` and `Release` which allow
refcounting directly at the plugin level instead of just the store.
Since a graphdriver is initialized exactly once, and is really managed
by a separate object, it didn't really seem right to call
`getter.Get()` to refcount graphdriver plugins.
On shutdown it was particularly weird where we'd either need to keep a
driver reference in daemon, or keep a reference to the pluggin getter in
the layer store, and even then still store extra details on if the
graphdriver is a plugin or not.
Instead the plugin proxy itself will handle calling the neccessary
refcounting methods directly on the plugin object.
Also adds a new interface in `plugingetter` to account for these new
functions which are not going to be implemented by v1 plugins.
Changes terms `plugingetter.CREATE` and `plugingetter.REMOVE` to
`ACQUIRE` and `RELEASE` respectively, which seems to be better
adjectives for what we're doing.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Legacy plugins expect host-relative paths (such as for Volume.Mount).
However, a containerized plugin cannot respond with a host-relative
path. Therefore, this commit modifies new volume plugins' paths in Mount
and List to prepend the container's rootfs path.
This introduces a new PropagatedMount field in the Plugin Config.
When it is set for volume plugins, RootfsPropagation is set to rshared
and the path specified by PropagatedMount is bind-mounted with rshared
prior to launching the container. This is so that the daemon code can
access the paths returned by the plugin from the host mount namespace.
Signed-off-by: Tibor Vass <tibor@docker.com>
The current implementation of getRefs is a bit fragile. It returns a
slice to callers without copying its contents, and assumes the contents
will not be modified elsewhere.
Also, the current implementation of Dereference requires copying the
slice of references, excluding the one we wish to remove.
To improve both of these things, change refs to be a map of maps.
Deleting an item becomes trivial, and returning a slice of references
necessitates copying from the map.
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
Fix issue where out-of-band deletions and then a `docker volume create`
on the same driver caused volume to not be re-created in the driver but
return as created since it was stored in the cache.
Previous fix only worked if the driver names did not match.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This fix tries to address the issue raised in 28769 where
checkpoint name was not checked before passing to containerd.
As a result, it was possible to use a special checkpoint name
to get outside of the container's directory.
This fix add restriction `[a-zA-Z0-9][a-zA-Z0-9_.-]+` (`RestrictedNamePattern`).
This is the same as container name restriction.
This fix fixes 28769.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Instead of converting nicely typed service mounts into untyped `Binds`
when creating containers, use the new `Mounts` API which is a 1-1
mapping between service mounts and container mounts.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
For some reason, `go vet` and `go fmt` validate does not capture
several issues.
The following was the output of `go vet`:
```
ubuntu@ubuntu:~/docker$ go vet ./... 2>&1 | grep -v ^vendor | grep -v '^exit status 1$'
cli/command/formatter/container_test.go:393: possible formatting directive in Log call
volume/volume_test.go:257: arg mp.RW for printf verb %s of wrong type: bool
```
The following was the output of `go fmt -s`:
```
ubuntu@ubuntu:~/docker$ gofmt -s -l . | grep -v ^vendor
cli/command/stack/list.go
daemon/commit.go
```
Fixed above issues with `go vet` and `go fmt -s`
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Fixes#22564
When an error occurs on mount, there should not be any call later to
unmount. This can throw off refcounting in the underlying driver
unexpectedly.
Consider these two cases:
```
$ docker run -v foo:/bar busybox true
```
```
$ docker run -v foo:/bar -w /foo busybox true
```
In the first case, if mounting `foo` fails, the volume driver will not
get a call to unmount (this is the incorrect behavior).
In the second case, the volume driver will not get a call to unmount
(correct behavior).
This occurs because in the first case, `/bar` does not exist in the
container, and as such there is no call to `volume.Mount()` during the
`create` phase. It will error out during the `start` phase.
In the second case `/bar` is created before dealing with the volume
because of the `-w`. Because of this, when the volume is being setup
docker will try to copy the image path contents in the volume, in which
case it will attempt to mount the volume and fail. This happens during
the `create` phase. This makes it so the container will not be created
(or at least fully created) and the user gets the error on `create`
instead of `start`. The error handling is different in these two phases.
Changed to only send `unmount` if the volume is mounted.
While investigating the cause of the reported issue I found some odd
behavior in unmount calls so I've cleaned those up a bit here as well.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
When a conflict is found in the volume cache, check with the driver if
that volume still actually exists.
If the volume doesn't exist, purge it from the cache and allow the
create to happen.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This fix tries to address the issue raised in 25545 where
volume options at the creation time is not showed up
in `docker volume inspect`.
This fix adds the field `Options` in `Volume` type and
persist the options in volume db so that `volume inspect`
could display the options.
This fix adds a couple of test cases to cover the changes.
This fix fixes 25545.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Found a couple of places where pretty low level errors were never being
wrapped with any sort of context.
For example, if you try to create a local volume using some bad mount
options, the kernel will return `invalid argument` when we try to mount
it at container start.
What would happen is a user would `docker run` with this volume and get
an error like `Error response from daemon: invalid argument`.
This uses github.com/pkg/errors to provide some context to the error
message without masking the original error.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
As part of making graphdrivers support pluginv2, a PluginGetter
interface was necessary for cleaner separation and avoiding import
cycles.
This commit creates a PluginGetter interface and makes pluginStore
implement it. Then the pluginStore object is created in the daemon
(rather than by the plugin manager) and passed to plugin init as
well as to the different subsystems (eg. graphdrivers, volumedrivers).
A side effect of this change was that some code was moved out of
experimental. This is good, since plugin support will be stable soon.
Signed-off-by: Anusha Ragunathan <anusha@docker.com>
`Mounts` allows users to specify in a much safer way the volumes they
want to use in the container.
This replaces `Binds` and `Volumes`, which both still exist, but
`Mounts` and `Binds`/`Volumes` are exclussive.
The CLI will continue to use `Binds` and `Volumes` due to concerns with
parsing the volume specs on the client side and cross-platform support
(for now).
The new API follows exactly the services mount API.
Example usage of `Mounts`:
```
$ curl -XPOST localhost:2375/containers/create -d '{
"Image": "alpine:latest",
"HostConfig": {
"Mounts": [{
"Type": "Volume",
"Target": "/foo"
},{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Target": "/var/run/docker.sock",
},{
"Type": "volume",
"Name": "important_data",
"Target": "/var/data",
"ReadOnly": true,
"VolumeOptions": {
"DriverConfig": {
Name: "awesomeStorage",
Options: {"size": "10m"},
Labels: {"some":"label"}
}
}]
}
}'
```
There are currently 2 types of mounts:
- **bind**: Paths on the host that get mounted into the
container. Paths must exist prior to creating the container.
- **volume**: Volumes that persist after the
container is removed.
Not all fields are available in each type, and validation is done to
ensure these fields aren't mixed up between types.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
daemon/events/testutils: rename eventstestutils to testutils
volume/testutils: rename volumetestutils to testutils
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
This makes sure that:
1. Already existing directories are left untouched
2. Newly created directories are chowned to the correct root UID/GID in case of user namespaces
3. All parent directories still get created with host root UID/GID
Fix#21738
Signed-off-by: Antonis Kalipetis <akalipetis@gmail.com>
Split plugin package into `store` and `v2/plugin`. Now the functionality
is clearly delineated:
- Manager: Manages the global state of the plugin sub-system.
- PluginStore: Manages a collection of plugins (in memory and on-disk)
- Plugin: Manages the single plugin unit.
This also facilitates splitting the global PluginManager lock into:
- PluginManager lock to protect global states.
- PluginStore lock to protect store states.
- Plugin lock to protect individual plugin states.
Importing "github.com/docker/docker/plugin/store" will provide access
to plugins and has lesser dependencies when compared to importing the
original monolithic `plugin package`.
Signed-off-by: Anusha Ragunathan <anusha@docker.com>
This fix tries to address the issue in raised #23367 where an out-of-band
volume driver deletion leaves some data in docker. This prevent the
reuse of deleted volume names (by out-of-band volume driver like flocker).
This fix adds a `--force` field in `docker volume rm` to forcefully purge
the data of the volume that has already been deleted.
Related documentations have been updated.
This fix is tested manually with flocker, as is specified in #23367.
An integration test has also been added for the scenario described.
This fix fixes#23367.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
When the daemon is started, it looks at all the volumes and checks to
see if any of them have mount options persisted to disk, and loads them
from disk if it does.
In some cases a volume will be created with an empty map causing the
options file to be persisted and volume options set to a non-nil value
on daemon restart... this causes problems later when the driver checks
for a non-nil value to determine if it should try and mount with the
persisted volume options.
Ensures 2 things:
1. Instead of only checking nilness for the opts map, use `len` to make
sure it is not an empty map, which we don't really need to persit.
2. An empty (or nulled) opts.json will not inadvertnatly set volume
options on daemon restart.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
this improves the error message if a user tries to
create a volume with a single-character name:
Before this change:
docker volume create --name a
Error response from daemon: create a: "a" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed
After this change:
docker volume create --name a
Error response from daemon: create a: volume name is too short, names should be at least two alphanumeric characters
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
On daemon restart the local volume driver will read options that it
persisted to disk, however it was reading an incorrect path, causing
volume options to be silently ignored after a daemon restart.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
these values were changed to lowercase in
690cb2d08c,
but not changed accordingly in docker/docker.
this changes the mounttypes to lowercase
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Legacy plugin model maintained a map of plugins. This is
not used by the new model. Using this map in the new model
causes incorrect lookup of plugins. This change uses adds
a plugin to the map only if its legacy.
Signed-off-by: Anusha Ragunathan <anusha@docker.com>
This patch introduces a new experimental engine-level plugin management
with a new API and command line. Plugins can be distributed via a Docker
registry, and their lifecycle is managed by the engine.
This makes plugins a first-class construct.
For more background, have a look at issue #20363.
Documentation is in a separate commit. If you want to understand how the
new plugin system works, you can start by reading the documentation.
Note: backwards compatibility with existing plugins is maintained,
albeit they won't benefit from the advantages of the new system.
Signed-off-by: Tibor Vass <tibor@docker.com>
Signed-off-by: Anusha Ragunathan <anusha@docker.com>
As described in our ROADMAP.md, introduce new Swarm management API
endpoints relying on swarmkit to deploy services. It currently vendors
docker/engine-api changes.
This PR is fully backward compatible (joining a Swarm is an optional
feature of the Engine, and existing commands are not impacted).
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Victor Vieux <vieux@docker.com>
Signed-off-by: Daniel Nephin <dnephin@docker.com>
Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
Signed-off-by: Madhu Venugopal <madhu@docker.com>
This is similar to network scopes where a volume can either be `local`
or `global`. A `global` volume is one that exists across the entire
cluster where as a `local` volume exists on a single engine.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
In order to be consistent on creation of volumes for bind mounts
we need to create the source directory if it does not exist and the
user specified he wants it relabeled.
Can not do this lower down the stack, since we are not passing in the
mode fields.
Signed-off-by: Dan Walsh <dwalsh@redhat.com>
Auto-creation of host-paths has been un-deprecated,
so to have feature-parity between Linux and Windows,
this feature should also be present on Windows.
This enables auto-creation on Windows.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This generates an ID string for calls to Mount/Unmount, allowing drivers
to differentiate between two callers of `Mount` and `Unmount`.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
The `Status` field is a `map[string]interface{}` which allows the driver to pass
back low-level details about the underlying volume.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Auto-creation of non-existing host directories
is no longer deprecated (9d5c26bed2),
so this warning is no longer relevant.
This removes the deprecation warning.
Also removes the "system" package here, because it's only used
on non-Windows, so basically just called os.MkdirAll()
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Implements a `CachedPath` function on the volume plugin adapter that we
call from the volume list function instead of `Path.
If a driver does not implement `CachedPath` it will just call `Path`.
Also makes sure we store the path on Mount and remove the path on
Unmount.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This allows a user to specify explicitly to enable
automatic copying of data from the container path to the volume path.
This does not change the default behavior of automatically copying, but
does allow a user to disable it at runtime.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Allows users to submit options similar to the `mount` command when
creating a volume with the `local` volume driver.
For example:
```go
$ docker volume create -d local --opt type=nfs --opt device=myNfsServer:/data --opt o=noatime,nosuid
```
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
As drivername maybe "" in hostconfig, so we should not
directly print dirvername with var drivername,
instead, we use the real driver name property to print it.
Fixes: #20900
Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
Moving all strings to the errors package wasn't a good idea after all.
Our custom implementation of Go errors predates everything that's nice
and good about working with errors in Go. Take as an example what we
have to do to get an error message:
```go
func GetErrorMessage(err error) string {
switch err.(type) {
case errcode.Error:
e, _ := err.(errcode.Error)
return e.Message
case errcode.ErrorCode:
ec, _ := err.(errcode.ErrorCode)
return ec.Message()
default:
return err.Error()
}
}
```
This goes against every good practice for Go development. The language already provides a simple, intuitive and standard way to get error messages, that is calling the `Error()` method from an error. Reinventing the error interface is a mistake.
Our custom implementation also makes very hard to reason about errors, another nice thing about Go. I found several (>10) error declarations that we don't use anywhere. This is a clear sign about how little we know about the errors we return. I also found several error usages where the number of arguments was different than the parameters declared in the error, another clear example of how difficult is to reason about errors.
Moreover, our custom implementation didn't really make easier for people to return custom HTTP status code depending on the errors. Again, it's hard to reason about when to set custom codes and how. Take an example what we have to do to extract the message and status code from an error before returning a response from the API:
```go
switch err.(type) {
case errcode.ErrorCode:
daError, _ := err.(errcode.ErrorCode)
statusCode = daError.Descriptor().HTTPStatusCode
errMsg = daError.Message()
case errcode.Error:
// For reference, if you're looking for a particular error
// then you can do something like :
// import ( derr "github.com/docker/docker/errors" )
// if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
daError, _ := err.(errcode.Error)
statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
errMsg = daError.Message
default:
// This part of will be removed once we've
// converted everything over to use the errcode package
// FIXME: this is brittle and should not be necessary.
// If we need to differentiate between different possible error types,
// we should create appropriate error types with clearly defined meaning
errStr := strings.ToLower(err.Error())
for keyword, status := range map[string]int{
"not found": http.StatusNotFound,
"no such": http.StatusNotFound,
"bad parameter": http.StatusBadRequest,
"conflict": http.StatusConflict,
"impossible": http.StatusNotAcceptable,
"wrong login/password": http.StatusUnauthorized,
"hasn't been activated": http.StatusForbidden,
} {
if strings.Contains(errStr, keyword) {
statusCode = status
break
}
}
}
```
You can notice two things in that code:
1. We have to explain how errors work, because our implementation goes against how easy to use Go errors are.
2. At no moment we arrived to remove that `switch` statement that was the original reason to use our custom implementation.
This change removes all our status errors from the errors package and puts them back in their specific contexts.
IT puts the messages back with their contexts. That way, we know right away when errors used and how to generate their messages.
It uses custom interfaces to reason about errors. Errors that need to response with a custom status code MUST implementent this simple interface:
```go
type errorWithStatus interface {
HTTPErrorStatusCode() int
}
```
This interface is very straightforward to implement. It also preserves Go errors real behavior, getting the message is as simple as using the `Error()` method.
I included helper functions to generate errors that use custom status code in `errors/errors.go`.
By doing this, we remove the hard dependency we have eeverywhere to our custom errors package. Yes, you can use it as a helper to generate error, but it's still very easy to generate errors without it.
Please, read this fantastic blog post about errors in Go: http://dave.cheney.net/2014/12/24/inspecting-errors
Signed-off-by: David Calavera <david.calavera@gmail.com>
In cases where the a plugin responds with both a null or empty volume
and a null or empty Err, the daemon would panic.
This is because we assumed the idiom if `err` is nil, then `v` must not
be but in reality the plugin may return whatever it wants and we want to
make sure it doesn't harm the daemon.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This fixes an issue where `docker run -v foo:/bar --volume-driver
<remote driver>` -> daemon restart -> `docker run -v foo:/bar` would
make a `local` volume after the restart instead of using the existing
volume from the remote driver.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This makes it so when calling `docker run --rm`, or `docker rm -v`, only
volumes specified without a name, e.g. `docker run -v /foo` instead of
`docker run -v awesome:/foo` are removed.
Note that all volumes are named, some are named by the user, some get a
generated name. This is specifically about how the volume was specified
on `run`, assuming that if the user specified it with a name they expect
it to persist after the container is cleaned up.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Use a back-compat struct to handle listing volumes for volumes we know
about (because, presumably, they are being used by a container) for
volume drivers which don't yet support `List`.
Adds a fall-back for the volume driver `Get` call, which will use
`Create` when the driver returns a `404` for `Get`. The old behavior was
to always use `Create` to get a volume reference.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This helps ensure that only one thing is trying to intialize a plugin at
once while also keeping the global lock free during initialization.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Makes `docker volume ls` and `docker volume inspect` ask the volume
drivers rather than only using what is cached locally.
Previously in order to use a volume from an external driver, one would
either have to use `docker volume create` or have a container that is
already using that volume for it to be visible to the other volume
API's.
For keeping uniqueness of volume names in the daemon, names are bound to
a driver on a first come first serve basis. If two drivers have a volume
with the same name, the first one is chosen, and a warning is logged
about the second one.
Adds 2 new methods to the plugin API, `List` and `Get`.
If a plugin does not implement these endpoints, a user will not be able
to find the specified volumes as well requests go through the drivers.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
The client API at fsouza/go-dockerclient has dependencies on packages in
the docker/docker repository which currently do not build on Solaris. In
particular, stat_unsupported.go makes use of the Mtimespec field of the
syscall.Stat_t struct, which is not present on Solaris, and a number of
Unix-specific packages do not list Solaris in their compile targets.
This commit adds enough support to be able to build
fsouza/go-dockerclient on SmartOS using Go 1.5.1 without affecting other
platforms.
Signed-off-by: James Nugent <james@jen20.com>
- Use the ones provided by docker/go-connections, they are a drop in replacement.
- Remove pkg/sockets from docker.
- Keep pkg/tlsconfig because libnetwork still needs it and there is a
circular dependency issue.
Signed-off-by: David Calavera <david.calavera@gmail.com>
When driver is `local` an empty string is given to the debug message.
This patch removes the debug statement.
```
Dec 20 19:07:01 localhost.localdomain docker[19734]:
time="2015-12-20T19:07:01.872021857+01:00" level=debug msg="Registering
new volume reference: driver , name
c2291b964b4d7b1b51ec51d2ccfe2544f83fd23404709225a43743c5faadad55"
```
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
Allow passing mount propagation option shared, slave, or private as volume
property.
For example.
docker run -ti -v /root/mnt-source:/root/mnt-dest:slave fedora bash
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
By removing deprecated volume structures, now that windows mount volumes we don't need a initializer per platform.
Signed-off-by: David Calavera <david.calavera@gmail.com>
Uses finer grained locking so that each volume name gets its own lock
rather than only being protected by the global lock, which itself needs
to be unlocked during cetain operations (`create` especially`)
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Delegate validation tasks to the volume drivers. It's up to them
to decide whether a name is valid or not.
Restrict volume names for the local driver to prevent creating
mount points outside docker's volumes directory.
Signed-off-by: David Calavera <david.calavera@gmail.com>
Adds support for the daemon to handle user namespace maps as a
per-daemon setting.
Support for handling uid/gid mapping is added to the builder,
archive/unarchive packages and functions, all graphdrivers (except
Windows), and the test suite is updated to handle user namespace daemon
rootgraph changes.
Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
- Add unit tests to make sure the functionality is correct.
- Add FilterByDriver to allow filtering volumes by driver, for future
`volume ls` filtering and whatnot.
Signed-off-by: David Calavera <david.calavera@gmail.com>
This is not a public interface and users are trying to use it.
We only use it to be able to generate the rpc protocol to talk with a plugin.
Signed-off-by: David Calavera <david.calavera@gmail.com>
Underlying volume data may have been removed by some other tool.
Ignore and remove the reference in this case.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
1. rename it from ValidateMountMode to ValidMountMode
Because it's a function simply check mount mode is valid or not.
2. remove the rw check return value
It's not supposed to be combined into this function, and we already
have a function for that check.
Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
This patch makes it such that plugin initialization is synchronized
based on the plugin name and not globally
Signed-off-by: Darren Shepherd <darren@rancher.com>
- comments on exported values
- constant string replaced by constant reference
- unexport implementation details of VolumeDriver 'local'
- add fixed packages to linter list
Signed-off-by: Morgan Bauer <mbauer@us.ibm.com>
- Refactor opts.ValidatePath and add an opts.ValidateDevice
ValidePath will now accept : containerPath:mode, hostPath:containerPath:mode
and hostPath:containerPath.
ValidateDevice will have the same behavior as current.
- Refactor opts.ValidateEnv, opts.ParseEnvFile
Environment variables will now be validated with the following
definition :
> Environment variables set by the user must have a name consisting
> solely of alphabetics, numerics, and underscores - the first of
> which must not be numeric.
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Signed by all authors:
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
Signed-off-by: David Calavera <david.calavera@gmail.com>
Signed-off-by: Jeff Lindsay <progrium@gmail.com>
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
Signed-off-by: Luke Marsden <luke@clusterhq.com>
Signed-off-by: David Calavera <david.calavera@gmail.com>