mirror of
https://github.com/moby/moby.git
synced 2025-08-01 05:47:11 +03:00
add label support for build, networks and volumes
build: implement --label Signed-off-by: Evan Hazlett <ejhazlett@gmail.com> network: allow adding labels on create Signed-off-by: Evan Hazlett <ejhazlett@gmail.com> volume: allow adding labels on create Signed-off-by: Evan Hazlett <ejhazlett@gmail.com> add tests for build, network, volume Signed-off-by: Evan Hazlett <ejhazlett@gmail.com> vendor: libnetwork and engine-api bump Signed-off-by: Evan Hazlett <ejhazlett@gmail.com>
This commit is contained in:
@ -62,6 +62,9 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||||||
cmd.Var(&flBuildArg, []string{"-build-arg"}, "Set build-time variables")
|
cmd.Var(&flBuildArg, []string{"-build-arg"}, "Set build-time variables")
|
||||||
isolation := cmd.String([]string{"-isolation"}, "", "Container isolation technology")
|
isolation := cmd.String([]string{"-isolation"}, "", "Container isolation technology")
|
||||||
|
|
||||||
|
flLabels := opts.NewListOpts(nil)
|
||||||
|
cmd.Var(&flLabels, []string{"-label"}, "Set metadata for an image")
|
||||||
|
|
||||||
ulimits := make(map[string]*units.Ulimit)
|
ulimits := make(map[string]*units.Ulimit)
|
||||||
flUlimits := runconfigopts.NewUlimitOpt(&ulimits)
|
flUlimits := runconfigopts.NewUlimitOpt(&ulimits)
|
||||||
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
|
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
|
||||||
@ -230,6 +233,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
|
|||||||
Ulimits: flUlimits.GetList(),
|
Ulimits: flUlimits.GetList(),
|
||||||
BuildArgs: runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()),
|
BuildArgs: runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()),
|
||||||
AuthConfigs: cli.retrieveAuthConfigs(),
|
AuthConfigs: cli.retrieveAuthConfigs(),
|
||||||
|
Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()),
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := cli.client.ImageBuild(context.Background(), options)
|
response, err := cli.client.ImageBuild(context.Background(), options)
|
||||||
|
@ -44,6 +44,7 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
|
|||||||
flIpamGateway := opts.NewListOpts(nil)
|
flIpamGateway := opts.NewListOpts(nil)
|
||||||
flIpamAux := opts.NewMapOpts(nil, nil)
|
flIpamAux := opts.NewMapOpts(nil, nil)
|
||||||
flIpamOpt := opts.NewMapOpts(nil, nil)
|
flIpamOpt := opts.NewMapOpts(nil, nil)
|
||||||
|
flLabels := opts.NewListOpts(nil)
|
||||||
|
|
||||||
cmd.Var(&flIpamSubnet, []string{"-subnet"}, "subnet in CIDR format that represents a network segment")
|
cmd.Var(&flIpamSubnet, []string{"-subnet"}, "subnet in CIDR format that represents a network segment")
|
||||||
cmd.Var(&flIpamIPRange, []string{"-ip-range"}, "allocate container ip from a sub-range")
|
cmd.Var(&flIpamIPRange, []string{"-ip-range"}, "allocate container ip from a sub-range")
|
||||||
@ -51,6 +52,7 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
|
|||||||
cmd.Var(flIpamAux, []string{"-aux-address"}, "auxiliary ipv4 or ipv6 addresses used by Network driver")
|
cmd.Var(flIpamAux, []string{"-aux-address"}, "auxiliary ipv4 or ipv6 addresses used by Network driver")
|
||||||
cmd.Var(flOpts, []string{"o", "-opt"}, "set driver specific options")
|
cmd.Var(flOpts, []string{"o", "-opt"}, "set driver specific options")
|
||||||
cmd.Var(flIpamOpt, []string{"-ipam-opt"}, "set IPAM driver specific options")
|
cmd.Var(flIpamOpt, []string{"-ipam-opt"}, "set IPAM driver specific options")
|
||||||
|
cmd.Var(&flLabels, []string{"-label"}, "set metadata on a network")
|
||||||
|
|
||||||
flInternal := cmd.Bool([]string{"-internal"}, false, "restricts external access to the network")
|
flInternal := cmd.Bool([]string{"-internal"}, false, "restricts external access to the network")
|
||||||
flIPv6 := cmd.Bool([]string{"-ipv6"}, false, "enable IPv6 networking")
|
flIPv6 := cmd.Bool([]string{"-ipv6"}, false, "enable IPv6 networking")
|
||||||
@ -82,6 +84,7 @@ func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
|
|||||||
CheckDuplicate: true,
|
CheckDuplicate: true,
|
||||||
Internal: *flInternal,
|
Internal: *flInternal,
|
||||||
EnableIPv6: *flIPv6,
|
EnableIPv6: *flIPv6,
|
||||||
|
Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()),
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.client.NetworkCreate(context.Background(), nc)
|
resp, err := cli.client.NetworkCreate(context.Background(), nc)
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
Cli "github.com/docker/docker/cli"
|
Cli "github.com/docker/docker/cli"
|
||||||
"github.com/docker/docker/opts"
|
"github.com/docker/docker/opts"
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
|
runconfigopts "github.com/docker/docker/runconfig/opts"
|
||||||
"github.com/docker/engine-api/types"
|
"github.com/docker/engine-api/types"
|
||||||
"github.com/docker/engine-api/types/filters"
|
"github.com/docker/engine-api/types/filters"
|
||||||
)
|
)
|
||||||
@ -128,6 +129,9 @@ func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
|
|||||||
flDriverOpts := opts.NewMapOpts(nil, nil)
|
flDriverOpts := opts.NewMapOpts(nil, nil)
|
||||||
cmd.Var(flDriverOpts, []string{"o", "-opt"}, "Set driver specific options")
|
cmd.Var(flDriverOpts, []string{"o", "-opt"}, "Set driver specific options")
|
||||||
|
|
||||||
|
flLabels := opts.NewListOpts(nil)
|
||||||
|
cmd.Var(&flLabels, []string{"-label"}, "Set metadata for a volume")
|
||||||
|
|
||||||
cmd.Require(flag.Exact, 0)
|
cmd.Require(flag.Exact, 0)
|
||||||
cmd.ParseFlags(args, true)
|
cmd.ParseFlags(args, true)
|
||||||
|
|
||||||
@ -135,6 +139,7 @@ func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
|
|||||||
Driver: *flDriver,
|
Driver: *flDriver,
|
||||||
DriverOpts: flDriverOpts.GetAll(),
|
DriverOpts: flDriverOpts.GetAll(),
|
||||||
Name: *flName,
|
Name: *flName,
|
||||||
|
Labels: runconfigopts.ConvertKVStringsToMap(flLabels.GetAll()),
|
||||||
}
|
}
|
||||||
|
|
||||||
vol, err := cli.client.VolumeCreate(context.Background(), volReq)
|
vol, err := cli.client.VolumeCreate(context.Background(), volReq)
|
||||||
|
@ -82,6 +82,15 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui
|
|||||||
}
|
}
|
||||||
options.BuildArgs = buildArgs
|
options.BuildArgs = buildArgs
|
||||||
}
|
}
|
||||||
|
var labels = map[string]string{}
|
||||||
|
labelsJSON := r.FormValue("labels")
|
||||||
|
if labelsJSON != "" {
|
||||||
|
if err := json.NewDecoder(strings.NewReader(labelsJSON)).Decode(&labels); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options.Labels = labels
|
||||||
|
}
|
||||||
|
|
||||||
return options, nil
|
return options, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ type Backend interface {
|
|||||||
GetNetworkByName(idName string) (libnetwork.Network, error)
|
GetNetworkByName(idName string) (libnetwork.Network, error)
|
||||||
GetNetworksByID(partialID string) []libnetwork.Network
|
GetNetworksByID(partialID string) []libnetwork.Network
|
||||||
GetAllNetworks() []libnetwork.Network
|
GetAllNetworks() []libnetwork.Network
|
||||||
CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string, internal bool, enableIPv6 bool) (libnetwork.Network, error)
|
CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string, labels map[string]string, internal bool, enableIPv6 bool) (libnetwork.Network, error)
|
||||||
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
|
||||||
DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error
|
DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error
|
||||||
DeleteNetwork(name string) error
|
DeleteNetwork(name string) error
|
||||||
|
@ -91,7 +91,7 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
|
|||||||
warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
|
warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
nw, err = n.backend.CreateNetwork(create.Name, create.Driver, create.IPAM, create.Options, create.Internal, create.EnableIPv6)
|
nw, err = n.backend.CreateNetwork(create.Name, create.Driver, create.IPAM, create.Options, create.Labels, create.Internal, create.EnableIPv6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -163,16 +163,18 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info := nw.Info()
|
||||||
r.Name = nw.Name()
|
r.Name = nw.Name()
|
||||||
r.ID = nw.ID()
|
r.ID = nw.ID()
|
||||||
r.Scope = nw.Info().Scope()
|
r.Scope = info.Scope()
|
||||||
r.Driver = nw.Type()
|
r.Driver = nw.Type()
|
||||||
r.EnableIPv6 = nw.Info().IPv6Enabled()
|
r.EnableIPv6 = info.IPv6Enabled()
|
||||||
r.Internal = nw.Info().Internal()
|
r.Internal = info.Internal()
|
||||||
r.Options = nw.Info().DriverOptions()
|
r.Options = info.DriverOptions()
|
||||||
r.Containers = make(map[string]types.EndpointResource)
|
r.Containers = make(map[string]types.EndpointResource)
|
||||||
buildIpamResources(r, nw)
|
buildIpamResources(r, info)
|
||||||
r.Internal = nw.Info().Internal()
|
r.Internal = info.Internal()
|
||||||
|
r.Labels = info.Labels()
|
||||||
|
|
||||||
epl := nw.Endpoints()
|
epl := nw.Endpoints()
|
||||||
for _, e := range epl {
|
for _, e := range epl {
|
||||||
@ -191,10 +193,10 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildIpamResources(r *types.NetworkResource, nw libnetwork.Network) {
|
func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
|
||||||
id, opts, ipv4conf, ipv6conf := nw.Info().IpamConfig()
|
id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig()
|
||||||
|
|
||||||
ipv4Info, ipv6Info := nw.Info().IpamInfo()
|
ipv4Info, ipv6Info := nwInfo.IpamInfo()
|
||||||
|
|
||||||
r.IPAM.Driver = id
|
r.IPAM.Driver = id
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
type Backend interface {
|
type Backend interface {
|
||||||
Volumes(filter string) ([]*types.Volume, []string, error)
|
Volumes(filter string) ([]*types.Volume, []string, error)
|
||||||
VolumeInspect(name string) (*types.Volume, error)
|
VolumeInspect(name string) (*types.Volume, error)
|
||||||
VolumeCreate(name, driverName string,
|
VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error)
|
||||||
opts map[string]string) (*types.Volume, error)
|
|
||||||
VolumeRm(name string) error
|
VolumeRm(name string) error
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ func (v *volumeRouter) postVolumesCreate(ctx context.Context, w http.ResponseWri
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
volume, err := v.backend.VolumeCreate(req.Name, req.Driver, req.DriverOpts)
|
volume, err := v.backend.VolumeCreate(req.Name, req.Driver, req.DriverOpts, req.Labels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,10 @@ func (b *Builder) build(config *types.ImageBuildOptions, context builder.Context
|
|||||||
|
|
||||||
var shortImgID string
|
var shortImgID string
|
||||||
for i, n := range b.dockerfile.Children {
|
for i, n := range b.dockerfile.Children {
|
||||||
|
// we only want to add labels to the last layer
|
||||||
|
if i == len(b.dockerfile.Children)-1 {
|
||||||
|
b.addLabels()
|
||||||
|
}
|
||||||
select {
|
select {
|
||||||
case <-b.cancelled:
|
case <-b.cancelled:
|
||||||
logrus.Debug("Builder: build cancelled!")
|
logrus.Debug("Builder: build cancelled!")
|
||||||
|
@ -37,6 +37,19 @@ import (
|
|||||||
"github.com/docker/engine-api/types/strslice"
|
"github.com/docker/engine-api/types/strslice"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (b *Builder) addLabels() {
|
||||||
|
// merge labels
|
||||||
|
if len(b.options.Labels) > 0 {
|
||||||
|
logrus.Debugf("[BUILDER] setting labels %v", b.options.Labels)
|
||||||
|
if b.runConfig.Labels == nil {
|
||||||
|
b.runConfig.Labels = make(map[string]string)
|
||||||
|
}
|
||||||
|
for kL, vL := range b.options.Labels {
|
||||||
|
b.runConfig.Labels[kL] = vL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) error {
|
func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) error {
|
||||||
if b.disableCommit {
|
if b.disableCommit {
|
||||||
return nil
|
return nil
|
||||||
@ -45,6 +58,7 @@ func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) e
|
|||||||
return fmt.Errorf("Please provide a source image with `from` prior to commit")
|
return fmt.Errorf("Please provide a source image with `from` prior to commit")
|
||||||
}
|
}
|
||||||
b.runConfig.Image = b.image
|
b.runConfig.Image = b.image
|
||||||
|
|
||||||
if id == "" {
|
if id == "" {
|
||||||
cmd := b.runConfig.Cmd
|
cmd := b.runConfig.Cmd
|
||||||
if runtime.GOOS != "windows" {
|
if runtime.GOOS != "windows" {
|
||||||
@ -81,6 +95,7 @@ func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string) e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.image = imageID
|
b.image = imageID
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -167,12 +167,12 @@ func (daemon *Daemon) setRWLayer(container *container.Container) error {
|
|||||||
|
|
||||||
// VolumeCreate creates a volume with the specified name, driver, and opts
|
// VolumeCreate creates a volume with the specified name, driver, and opts
|
||||||
// This is called directly from the remote API
|
// This is called directly from the remote API
|
||||||
func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) {
|
func (daemon *Daemon) VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
name = stringid.GenerateNonCryptoID()
|
name = stringid.GenerateNonCryptoID()
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := daemon.volumes.Create(name, driverName, opts)
|
v, err := daemon.volumes.Create(name, driverName, opts, labels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if volumestore.IsNameConflict(err) {
|
if volumestore.IsNameConflict(err) {
|
||||||
return nil, fmt.Errorf("A volume named %s already exists. Choose a different volume name.", name)
|
return nil, fmt.Errorf("A volume named %s already exists. Choose a different volume name.", name)
|
||||||
|
@ -45,7 +45,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
|
|||||||
return fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
|
return fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := daemon.volumes.CreateWithRef(name, hostConfig.VolumeDriver, container.ID, nil)
|
v, err := daemon.volumes.CreateWithRef(name, hostConfig.VolumeDriver, container.ID, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
|
|||||||
|
|
||||||
// Create the volume in the volume driver. If it doesn't exist,
|
// Create the volume in the volume driver. If it doesn't exist,
|
||||||
// a new one will be created.
|
// a new one will be created.
|
||||||
v, err := daemon.volumes.CreateWithRef(mp.Name, volumeDriver, container.ID, nil)
|
v, err := daemon.volumes.CreateWithRef(mp.Name, volumeDriver, container.ID, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1498,7 +1498,7 @@ func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore,
|
|||||||
}
|
}
|
||||||
|
|
||||||
volumedrivers.Register(volumesDriver, volumesDriver.Name())
|
volumedrivers.Register(volumesDriver, volumesDriver.Name())
|
||||||
return store.New(), nil
|
return store.New(config.Root)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthenticateToRegistry checks the validity of credentials in authConfig
|
// AuthenticateToRegistry checks the validity of credentials in authConfig
|
||||||
|
@ -118,10 +118,14 @@ func TestGetContainer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
|
func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
|
||||||
|
var err error
|
||||||
daemon := &Daemon{
|
daemon := &Daemon{
|
||||||
repository: tmp,
|
repository: tmp,
|
||||||
root: tmp,
|
root: tmp,
|
||||||
volumes: store.New(),
|
}
|
||||||
|
daemon.volumes, err = store.New(tmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
volumesDriver, err := local.New(tmp, 0, 0)
|
volumesDriver, err := local.New(tmp, 0, 0)
|
||||||
|
@ -91,22 +91,23 @@ func (daemon *Daemon) GetAllNetworks() []libnetwork.Network {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateNetwork creates a network with the given name, driver and other optional parameters
|
// CreateNetwork creates a network with the given name, driver and other optional parameters
|
||||||
func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, netOption map[string]string, internal bool, enableIPv6 bool) (libnetwork.Network, error) {
|
func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, netOption map[string]string, labels map[string]string, internal bool, enableIPv6 bool) (libnetwork.Network, error) {
|
||||||
c := daemon.netController
|
c := daemon.netController
|
||||||
if driver == "" {
|
if driver == "" {
|
||||||
driver = c.Config().Daemon.DefaultDriver
|
driver = c.Config().Daemon.DefaultDriver
|
||||||
}
|
}
|
||||||
|
|
||||||
nwOptions := []libnetwork.NetworkOption{}
|
|
||||||
|
|
||||||
v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
|
v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options))
|
nwOptions := []libnetwork.NetworkOption{
|
||||||
nwOptions = append(nwOptions, libnetwork.NetworkOptionEnableIPv6(enableIPv6))
|
libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options),
|
||||||
nwOptions = append(nwOptions, libnetwork.NetworkOptionDriverOpts(netOption))
|
libnetwork.NetworkOptionEnableIPv6(enableIPv6),
|
||||||
|
libnetwork.NetworkOptionDriverOpts(netOption),
|
||||||
|
libnetwork.NetworkOptionLabels(labels),
|
||||||
|
}
|
||||||
if internal {
|
if internal {
|
||||||
nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork())
|
nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork())
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,17 @@ type mounts []container.Mount
|
|||||||
|
|
||||||
// volumeToAPIType converts a volume.Volume to the type used by the remote API
|
// volumeToAPIType converts a volume.Volume to the type used by the remote API
|
||||||
func volumeToAPIType(v volume.Volume) *types.Volume {
|
func volumeToAPIType(v volume.Volume) *types.Volume {
|
||||||
return &types.Volume{
|
tv := &types.Volume{
|
||||||
Name: v.Name(),
|
Name: v.Name(),
|
||||||
Driver: v.DriverName(),
|
Driver: v.DriverName(),
|
||||||
Mountpoint: v.Path(),
|
Mountpoint: v.Path(),
|
||||||
}
|
}
|
||||||
|
if v, ok := v.(interface {
|
||||||
|
Labels() map[string]string
|
||||||
|
}); ok {
|
||||||
|
tv.Labels = v.Labels()
|
||||||
|
}
|
||||||
|
return tv
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the number of mounts. Used in sorting.
|
// Len returns the number of mounts. Used in sorting.
|
||||||
@ -118,7 +124,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
|||||||
|
|
||||||
if len(bind.Name) > 0 {
|
if len(bind.Name) > 0 {
|
||||||
// create the volume
|
// create the volume
|
||||||
v, err := daemon.volumes.CreateWithRef(bind.Name, bind.Driver, container.ID, nil)
|
v, err := daemon.volumes.CreateWithRef(bind.Name, bind.Driver, container.ID, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,12 @@ clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://gith
|
|||||||
clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
|
clone git golang.org/x/sys eb2c74142fd19a79b3f237334c7384d5167b1b46 https://github.com/golang/sys.git
|
||||||
clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
|
clone git github.com/docker/go-units 651fc226e7441360384da338d0fd37f2440ffbe3
|
||||||
clone git github.com/docker/go-connections v0.2.0
|
clone git github.com/docker/go-connections v0.2.0
|
||||||
clone git github.com/docker/engine-api 68a7b6bebf8f57d559b7788a46c55045438747b9
|
clone git github.com/docker/engine-api 9524d7ae81ff55771852b6269f40f2a878315de9
|
||||||
clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
|
clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
|
||||||
clone git github.com/imdario/mergo 0.2.1
|
clone git github.com/imdario/mergo 0.2.1
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
clone git github.com/docker/libnetwork v0.7.0-dev.8
|
clone git github.com/docker/libnetwork v0.7.0-dev.9
|
||||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||||
|
@ -6596,6 +6596,134 @@ func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildLabel(c *check.C) {
|
||||||
|
name := "testbuildlabel"
|
||||||
|
testLabel := "foo"
|
||||||
|
|
||||||
|
_, err := buildImage(name, `
|
||||||
|
FROM `+minimalBaseImage()+`
|
||||||
|
LABEL default foo
|
||||||
|
`, false, []string{"--label", testLabel}...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.Fatal("error building image with labels", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := inspectFieldJSON(c, name, "Config.Labels")
|
||||||
|
|
||||||
|
var labels map[string]string
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(res), &labels); err != nil {
|
||||||
|
c.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := labels[testLabel]; !ok {
|
||||||
|
c.Fatal("label not found in image")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildLabelCacheCommit(c *check.C) {
|
||||||
|
name := "testbuildlabelcachecommit"
|
||||||
|
testLabel := "foo"
|
||||||
|
|
||||||
|
if _, err := buildImage(name, `
|
||||||
|
FROM `+minimalBaseImage()+`
|
||||||
|
LABEL default foo
|
||||||
|
`, false); err != nil {
|
||||||
|
c.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := buildImage(name, `
|
||||||
|
FROM `+minimalBaseImage()+`
|
||||||
|
LABEL default foo
|
||||||
|
`, true, []string{"--label", testLabel}...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.Fatal("error building image with labels", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := inspectFieldJSON(c, name, "Config.Labels")
|
||||||
|
|
||||||
|
var labels map[string]string
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(res), &labels); err != nil {
|
||||||
|
c.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := labels[testLabel]; !ok {
|
||||||
|
c.Fatal("label not found in image")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildLabelMultiple(c *check.C) {
|
||||||
|
name := "testbuildlabelmultiple"
|
||||||
|
testLabels := map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"123": "456",
|
||||||
|
}
|
||||||
|
|
||||||
|
labelArgs := []string{}
|
||||||
|
|
||||||
|
for k, v := range testLabels {
|
||||||
|
labelArgs = append(labelArgs, "--label", k+"="+v)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := buildImage(name, `
|
||||||
|
FROM `+minimalBaseImage()+`
|
||||||
|
LABEL default foo
|
||||||
|
`, false, labelArgs...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.Fatal("error building image with labels", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := inspectFieldJSON(c, name, "Config.Labels")
|
||||||
|
|
||||||
|
var labels map[string]string
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(res), &labels); err != nil {
|
||||||
|
c.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range testLabels {
|
||||||
|
if x, ok := labels[k]; !ok || x != v {
|
||||||
|
c.Fatalf("label %s=%s not found in image", k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildLabelOverwrite(c *check.C) {
|
||||||
|
name := "testbuildlabeloverwrite"
|
||||||
|
testLabel := "foo"
|
||||||
|
testValue := "bar"
|
||||||
|
|
||||||
|
_, err := buildImage(name, `
|
||||||
|
FROM `+minimalBaseImage()+`
|
||||||
|
LABEL `+testLabel+`+ foo
|
||||||
|
`, false, []string{"--label", testLabel + "=" + testValue}...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.Fatal("error building image with labels", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := inspectFieldJSON(c, name, "Config.Labels")
|
||||||
|
|
||||||
|
var labels map[string]string
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(res), &labels); err != nil {
|
||||||
|
c.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := labels[testLabel]
|
||||||
|
if !ok {
|
||||||
|
c.Fatal("label not found in image")
|
||||||
|
}
|
||||||
|
|
||||||
|
if v != testValue {
|
||||||
|
c.Fatal("label not overwritten")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) {
|
func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) {
|
||||||
dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
|
dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
|
||||||
|
|
||||||
|
@ -341,6 +341,22 @@ func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {
|
|||||||
assertNwNotAvailable(c, "test")
|
assertNwNotAvailable(c, "test")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerNetworkSuite) TestDockerNetworkCreateLabel(c *check.C) {
|
||||||
|
testNet := "testnetcreatelabel"
|
||||||
|
testLabel := "foo"
|
||||||
|
testValue := "bar"
|
||||||
|
|
||||||
|
dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
|
||||||
|
assertNwIsAvailable(c, testNet)
|
||||||
|
|
||||||
|
out, _, err := dockerCmdWithError("network", "inspect", "--format='{{ .Labels."+testLabel+" }}'", testNet)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
c.Assert(strings.TrimSpace(out), check.Equals, testValue)
|
||||||
|
|
||||||
|
dockerCmd(c, "network", "rm", testNet)
|
||||||
|
assertNwNotAvailable(c, testNet)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) {
|
func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) {
|
||||||
out, _, err := dockerCmdWithError("network", "rm", "test")
|
out, _, err := dockerCmdWithError("network", "rm", "test")
|
||||||
c.Assert(err, checker.NotNil, check.Commentf("%v", out))
|
c.Assert(err, checker.NotNil, check.Commentf("%v", out))
|
||||||
|
@ -241,3 +241,43 @@ func (s *DockerSuite) TestVolumeCliCreateWithOpts(c *check.C) {
|
|||||||
}
|
}
|
||||||
c.Assert(found, checker.Equals, true)
|
c.Assert(found, checker.Equals, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestVolumeCliCreateLabel(c *check.C) {
|
||||||
|
testVol := "testvolcreatelabel"
|
||||||
|
testLabel := "foo"
|
||||||
|
testValue := "bar"
|
||||||
|
|
||||||
|
out, _, err := dockerCmdWithError("volume", "create", "--label", testLabel+"="+testValue, "--name", testVol)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
out, _ = dockerCmd(c, "volume", "inspect", "--format='{{ .Labels."+testLabel+" }}'", testVol)
|
||||||
|
c.Assert(strings.TrimSpace(out), check.Equals, testValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestVolumeCliCreateLabelMultiple(c *check.C) {
|
||||||
|
testVol := "testvolcreatelabel"
|
||||||
|
|
||||||
|
testLabels := map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": "foo",
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"volume",
|
||||||
|
"create",
|
||||||
|
"--name",
|
||||||
|
testVol,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range testLabels {
|
||||||
|
args = append(args, "--label", k+"="+v)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, _, err := dockerCmdWithError(args...)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
for k, v := range testLabels {
|
||||||
|
out, _ = dockerCmd(c, "volume", "inspect", "--format='{{ .Labels."+k+" }}'", testVol)
|
||||||
|
c.Assert(strings.TrimSpace(out), check.Equals, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -101,6 +101,11 @@ func imageBuildOptionsToQuery(options types.ImageBuildOptions) (url.Values, erro
|
|||||||
}
|
}
|
||||||
query.Set("buildargs", string(buildArgsJSON))
|
query.Set("buildargs", string(buildArgsJSON))
|
||||||
|
|
||||||
|
labelsJSON, err := json.Marshal(options.Labels)
|
||||||
|
if err != nil {
|
||||||
|
return query, err
|
||||||
|
}
|
||||||
|
query.Set("labels", string(labelsJSON))
|
||||||
return query, nil
|
return query, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +142,7 @@ type ImageBuildOptions struct {
|
|||||||
BuildArgs map[string]string
|
BuildArgs map[string]string
|
||||||
AuthConfigs map[string]AuthConfig
|
AuthConfigs map[string]AuthConfig
|
||||||
Context io.Reader
|
Context io.Reader
|
||||||
|
Labels map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageBuildResponse holds information
|
// ImageBuildResponse holds information
|
||||||
|
@ -103,6 +103,13 @@ type GraphDriverData struct {
|
|||||||
Data map[string]string
|
Data map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RootFS returns Image's RootFS description including the layer IDs.
|
||||||
|
type RootFS struct {
|
||||||
|
Type string
|
||||||
|
Layers []string `json:",omitempty"`
|
||||||
|
BaseLayer string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// ImageInspect contains response of Remote API:
|
// ImageInspect contains response of Remote API:
|
||||||
// GET "/images/{name:.*}/json"
|
// GET "/images/{name:.*}/json"
|
||||||
type ImageInspect struct {
|
type ImageInspect struct {
|
||||||
@ -122,6 +129,7 @@ type ImageInspect struct {
|
|||||||
Size int64
|
Size int64
|
||||||
VirtualSize int64
|
VirtualSize int64
|
||||||
GraphDriver GraphDriverData
|
GraphDriver GraphDriverData
|
||||||
|
RootFS RootFS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port stores open ports info of container
|
// Port stores open ports info of container
|
||||||
@ -372,6 +380,7 @@ type Volume struct {
|
|||||||
Driver string // Driver is the Driver name used to create the volume
|
Driver string // Driver is the Driver name used to create the volume
|
||||||
Mountpoint string // Mountpoint is the location on disk of the volume
|
Mountpoint string // Mountpoint is the location on disk of the volume
|
||||||
Status map[string]interface{} `json:",omitempty"` // Status provides low-level status information about the volume
|
Status map[string]interface{} `json:",omitempty"` // Status provides low-level status information about the volume
|
||||||
|
Labels map[string]string // Labels is metadata specific to the volume
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumesListResponse contains the response for the remote API:
|
// VolumesListResponse contains the response for the remote API:
|
||||||
@ -387,6 +396,7 @@ type VolumeCreateRequest struct {
|
|||||||
Name string // Name is the requested name of the volume
|
Name string // Name is the requested name of the volume
|
||||||
Driver string // Driver is the name of the driver that should be used to create the volume
|
Driver string // Driver is the name of the driver that should be used to create the volume
|
||||||
DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume.
|
DriverOpts map[string]string // DriverOpts holds the driver specific options to use for when creating the volume.
|
||||||
|
Labels map[string]string // Labels holds metadata specific to the volume being created.
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkResource is the body of the "get network" http response message
|
// NetworkResource is the body of the "get network" http response message
|
||||||
@ -400,6 +410,7 @@ type NetworkResource struct {
|
|||||||
Internal bool
|
Internal bool
|
||||||
Containers map[string]EndpointResource
|
Containers map[string]EndpointResource
|
||||||
Options map[string]string
|
Options map[string]string
|
||||||
|
Labels map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointResource contains network resources allocated and used for a container in a network
|
// EndpointResource contains network resources allocated and used for a container in a network
|
||||||
@ -420,6 +431,7 @@ type NetworkCreate struct {
|
|||||||
IPAM network.IPAM
|
IPAM network.IPAM
|
||||||
Internal bool
|
Internal bool
|
||||||
Options map[string]string
|
Options map[string]string
|
||||||
|
Labels map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkCreateResponse is the response message sent by the server for network create call
|
// NetworkCreateResponse is the response message sent by the server for network create call
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.7.0-dev.9 (2016-03-18)
|
||||||
|
- Support labels on networks
|
||||||
|
|
||||||
## 0.7.0-dev.8 (2016-03-16)
|
## 0.7.0-dev.8 (2016-03-16)
|
||||||
- Windows driver to respect user set MAC address.
|
- Windows driver to respect user set MAC address.
|
||||||
- Fix possible nil pointer reference in ServeDNS() with concurrent go routines.
|
- Fix possible nil pointer reference in ServeDNS() with concurrent go routines.
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
FROM golang:1.4-cross
|
FROM golang:1.5.3
|
||||||
RUN apt-get update && apt-get -y install iptables
|
RUN apt-get update && apt-get -y install iptables
|
||||||
|
|
||||||
RUN cd /go/src && mkdir -p golang.org/x && \
|
|
||||||
cd golang.org/x && git clone https://github.com/golang/tools && \
|
|
||||||
cd tools && git checkout release-branch.go1.5
|
|
||||||
|
|
||||||
RUN go get github.com/tools/godep \
|
RUN go get github.com/tools/godep \
|
||||||
github.com/golang/lint/golint \
|
github.com/golang/lint/golint \
|
||||||
golang.org/x/tools/cmd/vet \
|
golang.org/x/tools/cmd/vet \
|
||||||
|
@ -63,6 +63,7 @@ type NetworkInfo interface {
|
|||||||
Scope() string
|
Scope() string
|
||||||
IPv6Enabled() bool
|
IPv6Enabled() bool
|
||||||
Internal() bool
|
Internal() bool
|
||||||
|
Labels() map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointWalker is a client provided function which will be used to walk the Endpoints.
|
// EndpointWalker is a client provided function which will be used to walk the Endpoints.
|
||||||
@ -150,6 +151,7 @@ type network struct {
|
|||||||
networkType string
|
networkType string
|
||||||
id string
|
id string
|
||||||
scope string
|
scope string
|
||||||
|
labels map[string]string
|
||||||
ipamType string
|
ipamType string
|
||||||
ipamOptions map[string]string
|
ipamOptions map[string]string
|
||||||
addrSpace string
|
addrSpace string
|
||||||
@ -309,6 +311,14 @@ func (n *network) CopyTo(o datastore.KVObject) error {
|
|||||||
dstN.internal = n.internal
|
dstN.internal = n.internal
|
||||||
dstN.inDelete = n.inDelete
|
dstN.inDelete = n.inDelete
|
||||||
|
|
||||||
|
// copy labels
|
||||||
|
if dstN.labels == nil {
|
||||||
|
dstN.labels = make(map[string]string, len(n.labels))
|
||||||
|
}
|
||||||
|
for k, v := range n.labels {
|
||||||
|
dstN.labels[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
for _, v4conf := range n.ipamV4Config {
|
for _, v4conf := range n.ipamV4Config {
|
||||||
dstV4Conf := &IpamConf{}
|
dstV4Conf := &IpamConf{}
|
||||||
v4conf.CopyTo(dstV4Conf)
|
v4conf.CopyTo(dstV4Conf)
|
||||||
@ -359,6 +369,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
|
|||||||
netMap["id"] = n.id
|
netMap["id"] = n.id
|
||||||
netMap["networkType"] = n.networkType
|
netMap["networkType"] = n.networkType
|
||||||
netMap["scope"] = n.scope
|
netMap["scope"] = n.scope
|
||||||
|
netMap["labels"] = n.labels
|
||||||
netMap["ipamType"] = n.ipamType
|
netMap["ipamType"] = n.ipamType
|
||||||
netMap["addrSpace"] = n.addrSpace
|
netMap["addrSpace"] = n.addrSpace
|
||||||
netMap["enableIPv6"] = n.enableIPv6
|
netMap["enableIPv6"] = n.enableIPv6
|
||||||
@ -411,6 +422,15 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
|||||||
n.networkType = netMap["networkType"].(string)
|
n.networkType = netMap["networkType"].(string)
|
||||||
n.enableIPv6 = netMap["enableIPv6"].(bool)
|
n.enableIPv6 = netMap["enableIPv6"].(bool)
|
||||||
|
|
||||||
|
// if we weren't unmarshaling to netMap we could simply set n.labels
|
||||||
|
// unfortunately, we can't because map[string]interface{} != map[string]string
|
||||||
|
if labels, ok := netMap["labels"].(map[string]interface{}); ok {
|
||||||
|
n.labels = make(map[string]string, len(labels))
|
||||||
|
for label, value := range labels {
|
||||||
|
n.labels[label] = value.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if v, ok := netMap["generic"]; ok {
|
if v, ok := netMap["generic"]; ok {
|
||||||
n.generic = v.(map[string]interface{})
|
n.generic = v.(map[string]interface{})
|
||||||
// Restore opts in their map[string]string form
|
// Restore opts in their map[string]string form
|
||||||
@ -539,7 +559,7 @@ func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ip
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkOptionDriverOpts function returns an option setter for any parameter described by a map
|
// NetworkOptionDriverOpts function returns an option setter for any driver parameter described by a map
|
||||||
func NetworkOptionDriverOpts(opts map[string]string) NetworkOption {
|
func NetworkOptionDriverOpts(opts map[string]string) NetworkOption {
|
||||||
return func(n *network) {
|
return func(n *network) {
|
||||||
if n.generic == nil {
|
if n.generic == nil {
|
||||||
@ -553,6 +573,13 @@ func NetworkOptionDriverOpts(opts map[string]string) NetworkOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NetworkOptionLabels function returns an option setter for labels specific to a network
|
||||||
|
func NetworkOptionLabels(labels map[string]string) NetworkOption {
|
||||||
|
return func(n *network) {
|
||||||
|
n.labels = labels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NetworkOptionDeferIPv6Alloc instructs the network to defer the IPV6 address allocation until after the endpoint has been created
|
// NetworkOptionDeferIPv6Alloc instructs the network to defer the IPV6 address allocation until after the endpoint has been created
|
||||||
// It is being provided to support the specific docker daemon flags where user can deterministically assign an IPv6 address
|
// It is being provided to support the specific docker daemon flags where user can deterministically assign an IPv6 address
|
||||||
// to a container as combination of fixed-cidr-v6 + mac-address
|
// to a container as combination of fixed-cidr-v6 + mac-address
|
||||||
@ -1285,3 +1312,15 @@ func (n *network) IPv6Enabled() bool {
|
|||||||
|
|
||||||
return n.enableIPv6
|
return n.enableIPv6
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *network) Labels() map[string]string {
|
||||||
|
n.Lock()
|
||||||
|
defer n.Unlock()
|
||||||
|
|
||||||
|
var lbls = make(map[string]string, len(n.labels))
|
||||||
|
for k, v := range n.labels {
|
||||||
|
lbls[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return lbls
|
||||||
|
}
|
||||||
|
@ -313,8 +313,8 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
|
|||||||
}{
|
}{
|
||||||
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
|
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
|
||||||
{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
|
{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
|
||||||
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, i.Address())},
|
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %v", ifaceName, i.Address())},
|
||||||
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, i.AddressIPv6())},
|
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %v", ifaceName, i.AddressIPv6())},
|
||||||
{setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
|
{setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@ func (a *volumeDriverAdapter) Create(name string, opts map[string]string) (volum
|
|||||||
return &volumeAdapter{
|
return &volumeAdapter{
|
||||||
proxy: a.proxy,
|
proxy: a.proxy,
|
||||||
name: name,
|
name: name,
|
||||||
driverName: a.name}, nil
|
driverName: a.name,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *volumeDriverAdapter) Remove(v volume.Volume) error {
|
func (a *volumeDriverAdapter) Remove(v volume.Volume) error {
|
||||||
|
@ -21,7 +21,7 @@ const extName = "VolumeDriver"
|
|||||||
// NewVolumeDriver returns a driver has the given name mapped on the given client.
|
// NewVolumeDriver returns a driver has the given name mapped on the given client.
|
||||||
func NewVolumeDriver(name string, c client) volume.Driver {
|
func NewVolumeDriver(name string, c client) volume.Driver {
|
||||||
proxy := &volumeDriverProxy{c}
|
proxy := &volumeDriverProxy{c}
|
||||||
return &volumeDriverAdapter{name, proxy}
|
return &volumeDriverAdapter{name: name, proxy: proxy}
|
||||||
}
|
}
|
||||||
|
|
||||||
type opts map[string]string
|
type opts map[string]string
|
||||||
|
@ -77,6 +77,10 @@ func New(scope string, rootUID, rootGID int) (*Root, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range dirs {
|
for _, d := range dirs {
|
||||||
|
if !d.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
name := filepath.Base(d.Name())
|
name := filepath.Base(d.Name())
|
||||||
v := &localVolume{
|
v := &localVolume{
|
||||||
driverName: r.Name(),
|
driverName: r.Name(),
|
||||||
@ -198,7 +202,7 @@ func (r *Root) Remove(v volume.Volume) error {
|
|||||||
|
|
||||||
lv, ok := v.(*localVolume)
|
lv, ok := v.(*localVolume)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown volume type")
|
return fmt.Errorf("unknown volume type %T", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
realPath, err := filepath.EvalSymlinks(lv.path)
|
realPath, err := filepath.EvalSymlinks(lv.path)
|
||||||
|
@ -1,22 +1,77 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/boltdb/bolt"
|
||||||
"github.com/docker/docker/pkg/locker"
|
"github.com/docker/docker/pkg/locker"
|
||||||
"github.com/docker/docker/volume"
|
"github.com/docker/docker/volume"
|
||||||
"github.com/docker/docker/volume/drivers"
|
"github.com/docker/docker/volume/drivers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
volumeDataDir = "volumes"
|
||||||
|
volumeBucketName = "volumes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type volumeMetadata struct {
|
||||||
|
Name string
|
||||||
|
Labels map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type volumeWithLabels struct {
|
||||||
|
volume.Volume
|
||||||
|
labels map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v volumeWithLabels) Labels() map[string]string {
|
||||||
|
return v.labels
|
||||||
|
}
|
||||||
|
|
||||||
// New initializes a VolumeStore to keep
|
// New initializes a VolumeStore to keep
|
||||||
// reference counting of volumes in the system.
|
// reference counting of volumes in the system.
|
||||||
func New() *VolumeStore {
|
func New(rootPath string) (*VolumeStore, error) {
|
||||||
return &VolumeStore{
|
vs := &VolumeStore{
|
||||||
locks: &locker.Locker{},
|
locks: &locker.Locker{},
|
||||||
names: make(map[string]volume.Volume),
|
names: make(map[string]volume.Volume),
|
||||||
refs: make(map[string][]string),
|
refs: make(map[string][]string),
|
||||||
|
labels: make(map[string]map[string]string),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rootPath != "" {
|
||||||
|
// initialize metadata store
|
||||||
|
volPath := filepath.Join(rootPath, volumeDataDir)
|
||||||
|
if err := os.MkdirAll(volPath, 750); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbPath := filepath.Join(volPath, "metadata.db")
|
||||||
|
|
||||||
|
var err error
|
||||||
|
vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize volumes bucket
|
||||||
|
if err := vs.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
if _, err := tx.CreateBucketIfNotExists([]byte(volumeBucketName)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) {
|
func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) {
|
||||||
@ -39,6 +94,7 @@ func (s *VolumeStore) purge(name string) {
|
|||||||
s.globalLock.Lock()
|
s.globalLock.Lock()
|
||||||
delete(s.names, name)
|
delete(s.names, name)
|
||||||
delete(s.refs, name)
|
delete(s.refs, name)
|
||||||
|
delete(s.labels, name)
|
||||||
s.globalLock.Unlock()
|
s.globalLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +107,9 @@ type VolumeStore struct {
|
|||||||
names map[string]volume.Volume
|
names map[string]volume.Volume
|
||||||
// refs stores the volume name and the list of things referencing it
|
// refs stores the volume name and the list of things referencing it
|
||||||
refs map[string][]string
|
refs map[string][]string
|
||||||
|
// labels stores volume labels for each volume
|
||||||
|
labels map[string]map[string]string
|
||||||
|
db *bolt.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// List proxies to all registered volume drivers to get the full list of volumes
|
// List proxies to all registered volume drivers to get the full list of volumes
|
||||||
@ -137,12 +196,12 @@ func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
|
|||||||
// CreateWithRef creates a volume with the given name and driver and stores the ref
|
// CreateWithRef creates a volume with the given name and driver and stores the ref
|
||||||
// This is just like Create() except we store the reference while holding the lock.
|
// This is just like Create() except we store the reference while holding the lock.
|
||||||
// This ensures there's no race between creating a volume and then storing a reference.
|
// This ensures there's no race between creating a volume and then storing a reference.
|
||||||
func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts map[string]string) (volume.Volume, error) {
|
func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts, labels map[string]string) (volume.Volume, error) {
|
||||||
name = normaliseVolumeName(name)
|
name = normaliseVolumeName(name)
|
||||||
s.locks.Lock(name)
|
s.locks.Lock(name)
|
||||||
defer s.locks.Unlock(name)
|
defer s.locks.Unlock(name)
|
||||||
|
|
||||||
v, err := s.create(name, driverName, opts)
|
v, err := s.create(name, driverName, opts, labels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &OpErr{Err: err, Name: name, Op: "create"}
|
return nil, &OpErr{Err: err, Name: name, Op: "create"}
|
||||||
}
|
}
|
||||||
@ -152,12 +211,12 @@ func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts map[strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a volume with the given name and driver.
|
// Create creates a volume with the given name and driver.
|
||||||
func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (volume.Volume, error) {
|
func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
|
||||||
name = normaliseVolumeName(name)
|
name = normaliseVolumeName(name)
|
||||||
s.locks.Lock(name)
|
s.locks.Lock(name)
|
||||||
defer s.locks.Unlock(name)
|
defer s.locks.Unlock(name)
|
||||||
|
|
||||||
v, err := s.create(name, driverName, opts)
|
v, err := s.create(name, driverName, opts, labels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &OpErr{Err: err, Name: name, Op: "create"}
|
return nil, &OpErr{Err: err, Name: name, Op: "create"}
|
||||||
}
|
}
|
||||||
@ -169,7 +228,7 @@ func (s *VolumeStore) Create(name, driverName string, opts map[string]string) (v
|
|||||||
// If a volume with the name is already known, it will ask the stored driver for the volume.
|
// If a volume with the name is already known, it will ask the stored driver for the volume.
|
||||||
// If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned.
|
// If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned.
|
||||||
// It is expected that callers of this function hold any necessary locks.
|
// It is expected that callers of this function hold any necessary locks.
|
||||||
func (s *VolumeStore) create(name, driverName string, opts map[string]string) (volume.Volume, error) {
|
func (s *VolumeStore) create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
|
||||||
// Validate the name in a platform-specific manner
|
// Validate the name in a platform-specific manner
|
||||||
valid, err := volume.IsVolumeNameValid(name)
|
valid, err := volume.IsVolumeNameValid(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -205,7 +264,33 @@ func (s *VolumeStore) create(name, driverName string, opts map[string]string) (v
|
|||||||
if v, _ := vd.Get(name); v != nil {
|
if v, _ := vd.Get(name); v != nil {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
return vd.Create(name, opts)
|
v, err := vd.Create(name, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.labels[name] = labels
|
||||||
|
|
||||||
|
if s.db != nil {
|
||||||
|
metadata := &volumeMetadata{
|
||||||
|
Name: name,
|
||||||
|
Labels: labels,
|
||||||
|
}
|
||||||
|
|
||||||
|
volData, err := json.Marshal(metadata)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
b := tx.Bucket([]byte(volumeBucketName))
|
||||||
|
err := b.Put([]byte(name), volData)
|
||||||
|
return err
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return volumeWithLabels{v, labels}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWithRef gets a volume with the given name from the passed in driver and stores the ref
|
// GetWithRef gets a volume with the given name from the passed in driver and stores the ref
|
||||||
@ -227,6 +312,9 @@ func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.setNamed(v, ref)
|
s.setNamed(v, ref)
|
||||||
|
if labels, ok := s.labels[name]; ok {
|
||||||
|
return volumeWithLabels{v, labels}, nil
|
||||||
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,13 +336,43 @@ func (s *VolumeStore) Get(name string) (volume.Volume, error) {
|
|||||||
// if the driver is unknown it probes all drivers until it finds the first volume with that name.
|
// if the driver is unknown it probes all drivers until it finds the first volume with that name.
|
||||||
// it is expected that callers of this function hold any necessary locks
|
// it is expected that callers of this function hold any necessary locks
|
||||||
func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
|
func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
|
||||||
|
labels := map[string]string{}
|
||||||
|
|
||||||
|
if s.db != nil {
|
||||||
|
// get meta
|
||||||
|
if err := s.db.Update(func(tx *bolt.Tx) error {
|
||||||
|
b := tx.Bucket([]byte(volumeBucketName))
|
||||||
|
data := b.Get([]byte(name))
|
||||||
|
|
||||||
|
if string(data) == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var meta volumeMetadata
|
||||||
|
buf := bytes.NewBuffer(data)
|
||||||
|
|
||||||
|
if err := json.NewDecoder(buf).Decode(&meta); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
labels = meta.Labels
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logrus.Debugf("Getting volume reference for name: %s", name)
|
logrus.Debugf("Getting volume reference for name: %s", name)
|
||||||
if v, exists := s.names[name]; exists {
|
if v, exists := s.names[name]; exists {
|
||||||
vd, err := volumedrivers.GetDriver(v.DriverName())
|
vd, err := volumedrivers.GetDriver(v.DriverName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return vd.Get(name)
|
vol, err := vd.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return volumeWithLabels{vol, labels}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("Probing all drivers for volume with name: %s", name)
|
logrus.Debugf("Probing all drivers for volume with name: %s", name)
|
||||||
@ -268,7 +386,8 @@ func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return v, nil
|
|
||||||
|
return volumeWithLabels{v, labels}, nil
|
||||||
}
|
}
|
||||||
return nil, errNoSuchVolume
|
return nil, errNoSuchVolume
|
||||||
}
|
}
|
||||||
@ -289,7 +408,8 @@ func (s *VolumeStore) Remove(v volume.Volume) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
|
logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
|
||||||
if err := vd.Remove(v); err != nil {
|
vol := withoutLabels(v)
|
||||||
|
if err := vd.Remove(vol); err != nil {
|
||||||
return &OpErr{Err: err, Name: name, Op: "remove"}
|
return &OpErr{Err: err, Name: name, Op: "remove"}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,3 +492,11 @@ func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume
|
|||||||
}
|
}
|
||||||
return ls
|
return ls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withoutLabels(v volume.Volume) volume.Volume {
|
||||||
|
if vol, ok := v.(volumeWithLabels); ok {
|
||||||
|
return vol.Volume
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
@ -12,8 +12,11 @@ import (
|
|||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||||
defer volumedrivers.Unregister("fake")
|
defer volumedrivers.Unregister("fake")
|
||||||
s := New()
|
s, err := New("")
|
||||||
v, err := s.Create("fake1", "fake", nil)
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
v, err := s.Create("fake1", "fake", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -24,11 +27,11 @@ func TestCreate(t *testing.T) {
|
|||||||
t.Fatalf("Expected 1 volume in the store, got %v: %v", len(l), l)
|
t.Fatalf("Expected 1 volume in the store, got %v: %v", len(l), l)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := s.Create("none", "none", nil); err == nil {
|
if _, err := s.Create("none", "none", nil, nil); err == nil {
|
||||||
t.Fatalf("Expected unknown driver error, got nil")
|
t.Fatalf("Expected unknown driver error, got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.Create("fakeerror", "fake", map[string]string{"error": "create error"})
|
_, err = s.Create("fakeerror", "fake", map[string]string{"error": "create error"}, nil)
|
||||||
expected := &OpErr{Op: "create", Name: "fakeerror", Err: errors.New("create error")}
|
expected := &OpErr{Op: "create", Name: "fakeerror", Err: errors.New("create error")}
|
||||||
if err != nil && err.Error() != expected.Error() {
|
if err != nil && err.Error() != expected.Error() {
|
||||||
t.Fatalf("Expected create fakeError: create error, got %v", err)
|
t.Fatalf("Expected create fakeError: create error, got %v", err)
|
||||||
@ -40,7 +43,10 @@ func TestRemove(t *testing.T) {
|
|||||||
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
||||||
defer volumedrivers.Unregister("fake")
|
defer volumedrivers.Unregister("fake")
|
||||||
defer volumedrivers.Unregister("noop")
|
defer volumedrivers.Unregister("noop")
|
||||||
s := New()
|
s, err := New("")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// doing string compare here since this error comes directly from the driver
|
// doing string compare here since this error comes directly from the driver
|
||||||
expected := "no such volume"
|
expected := "no such volume"
|
||||||
@ -48,7 +54,7 @@ func TestRemove(t *testing.T) {
|
|||||||
t.Fatalf("Expected error %q, got %v", expected, err)
|
t.Fatalf("Expected error %q, got %v", expected, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := s.CreateWithRef("fake1", "fake", "fake", nil)
|
v, err := s.CreateWithRef("fake1", "fake", "fake", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -71,11 +77,14 @@ func TestList(t *testing.T) {
|
|||||||
defer volumedrivers.Unregister("fake")
|
defer volumedrivers.Unregister("fake")
|
||||||
defer volumedrivers.Unregister("fake2")
|
defer volumedrivers.Unregister("fake2")
|
||||||
|
|
||||||
s := New()
|
s, err := New("")
|
||||||
if _, err := s.Create("test", "fake", nil); err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := s.Create("test2", "fake2", nil); err != nil {
|
if _, err := s.Create("test", "fake", nil, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := s.Create("test2", "fake2", nil, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +97,10 @@ func TestList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// and again with a new store
|
// and again with a new store
|
||||||
s = New()
|
s, err = New("")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
ls, _, err = s.List()
|
ls, _, err = s.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -103,15 +115,18 @@ func TestFilterByDriver(t *testing.T) {
|
|||||||
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
||||||
defer volumedrivers.Unregister("fake")
|
defer volumedrivers.Unregister("fake")
|
||||||
defer volumedrivers.Unregister("noop")
|
defer volumedrivers.Unregister("noop")
|
||||||
s := New()
|
s, err := New("")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := s.Create("fake1", "fake", nil); err != nil {
|
if _, err := s.Create("fake1", "fake", nil, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := s.Create("fake2", "fake", nil); err != nil {
|
if _, err := s.Create("fake2", "fake", nil, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := s.Create("fake3", "noop", nil); err != nil {
|
if _, err := s.Create("fake3", "noop", nil, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,11 +143,15 @@ func TestFilterByUsed(t *testing.T) {
|
|||||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||||
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
volumedrivers.Register(vt.NewFakeDriver("noop"), "noop")
|
||||||
|
|
||||||
s := New()
|
s, err := New("")
|
||||||
if _, err := s.CreateWithRef("fake1", "fake", "volReference", nil); err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if _, err := s.Create("fake2", "fake", nil); err != nil {
|
|
||||||
|
if _, err := s.CreateWithRef("fake1", "fake", "volReference", nil, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := s.Create("fake2", "fake", nil, nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +180,12 @@ func TestFilterByUsed(t *testing.T) {
|
|||||||
func TestDerefMultipleOfSameRef(t *testing.T) {
|
func TestDerefMultipleOfSameRef(t *testing.T) {
|
||||||
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
volumedrivers.Register(vt.NewFakeDriver("fake"), "fake")
|
||||||
|
|
||||||
s := New()
|
s, err := New("")
|
||||||
v, err := s.CreateWithRef("fake1", "fake", "volReference", nil)
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := s.CreateWithRef("fake1", "fake", "volReference", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user