summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state.go270
-rw-r--r--libpod/boltdb_state_internal.go174
-rw-r--r--libpod/container_config.go9
-rw-r--r--libpod/container_validate.go11
-rw-r--r--libpod/define/errors.go10
-rw-r--r--libpod/in_memory_state.go261
-rw-r--r--libpod/options.go14
-rw-r--r--libpod/state.go7
8 files changed, 734 insertions, 22 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index 9dd5ca465..e0db92082 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -50,10 +50,12 @@ type BoltState struct {
// containers in the pod.
// - allPodsBkt: Map of ID to name containing only pods. Used for pod lookup
// operations.
-// - execBkt: Map of exec session ID to exec session - contains a sub-bucket for
-// each exec session in the DB.
-// - execRegistryBkt: Map of exec session ID to nothing. Contains one entry for
-// each exec session. Used for iterating through all exec sessions.
+// - execBkt: Map of exec session ID to container ID - used for resolving
+// exec session IDs to the containers that hold the exec session.
+// - aliasesBkt - Contains a bucket for each CNI network, which contain a map of
+// network alias (an extra name for containers in DNS) to the ID of the
+// container holding the alias. Aliases must be unique per-network, and cannot
+// conflict with names registered in nameRegistryBkt.
// - runtimeConfigBkt: Contains configuration of the libpod instance that
// initially created the database. This must match for any further instances
// that access the database, to ensure that state mismatches with
@@ -92,6 +94,7 @@ func NewBoltState(path string, runtime *Runtime) (State, error) {
volBkt,
allVolsBkt,
execBkt,
+ aliasesBkt,
runtimeConfigBkt,
}
@@ -969,6 +972,265 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
return ctrs, nil
}
+// GetNetworkAliases retrieves the network aliases for the given container in
+// the given CNI network.
+func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
+ if !s.valid {
+ return nil, define.ErrDBClosed
+ }
+
+ if !ctr.valid {
+ return nil, define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ if s.namespace != "" && s.namespace != ctr.config.Namespace {
+ return nil, errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+
+ ctrID := []byte(ctr.ID())
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return nil, err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ aliases := []string{}
+
+ err = db.View(func(tx *bolt.Tx) error {
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ ctr.valid = false
+ return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
+ }
+
+ ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
+ if ctrAliasesBkt == nil {
+ return errors.Wrapf(define.ErrNoAliases, "container %s has no network aliases", ctr.ID())
+ }
+
+ netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
+ if netAliasesBkt == nil {
+ return errors.Wrapf(define.ErrNoAliasesForNetwork, "container %s has no aliases for network %q", ctr.ID(), network)
+ }
+
+ return netAliasesBkt.ForEach(func(alias, v []byte) error {
+ aliases = append(aliases, string(alias))
+ return nil
+ })
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return aliases, nil
+}
+
+// SetNetworkAliases sets network aliases for the given container in the given
+// network. All existing aliases for that network (if any exist) will be removed,
+// to be replaced by the new aliases given.
+func (s *BoltState) SetNetworkAliases(ctr *Container, network string, aliases []string) error {
+ if !s.valid {
+ return define.ErrDBClosed
+ }
+
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ if s.namespace != "" && s.namespace != ctr.config.Namespace {
+ return errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+
+ ctrID := []byte(ctr.ID())
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ return db.Update(func(tx *bolt.Tx) error {
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ allAliasesBucket, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ netAllAliasesBucket, err := allAliasesBucket.CreateBucketIfNotExists([]byte(network))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %s", network)
+ }
+
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ ctr.valid = false
+ return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
+ }
+
+ ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
+ if ctrAliasesBkt == nil {
+ return errors.Wrapf(define.ErrNoAliases, "container %s has no network aliases", ctr.ID())
+ }
+
+ ctrNetworksBkt := dbCtr.Bucket(networksBkt)
+ if ctrNetworksBkt == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to any CNI networks, so cannot add aliases", ctr.ID())
+ }
+ netConnected := ctrNetworksBkt.Get([]byte(network))
+ if netConnected == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to CNI network %q, so cannot add aliases for this network", ctr.ID(), network)
+ }
+
+ namesBucket, err := getNamesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ // Check if the container already has network aliases for this network.
+ netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
+ if netAliasesBkt != nil {
+ // We have aliases. Have to remove them.
+ forEachErr := netAliasesBkt.ForEach(func(alias, v []byte) error {
+ // Relies on errors.Wrapf(nil, ...) returning
+ // nil.
+ return errors.Wrapf(netAllAliasesBucket.Delete(alias), "error removing alias %q from network %q when changing aliases for container %s", string(alias), network, ctr.ID())
+ })
+ if forEachErr != nil {
+ return forEachErr
+ }
+ }
+
+ if netAliasesBkt == nil {
+ newBkt, err := ctrAliasesBkt.CreateBucket([]byte(network))
+ if err != nil {
+ return errors.Wrapf(err, "could not create bucket for network aliases for network %q", network)
+ }
+ netAliasesBkt = newBkt
+ }
+
+ for _, alias := range aliases {
+ // Check if safe to use
+ aliasExists := netAllAliasesBucket.Get([]byte(alias))
+ if aliasExists != nil {
+ return errors.Wrapf(define.ErrAliasExists, "network alias %q already exists in network %q (used by container %s)", alias, network, string(aliasExists))
+ }
+ nameExists := namesBucket.Get([]byte(alias))
+ if nameExists != nil {
+ return errors.Wrapf(define.ErrCtrExists, "a container or pod already uses the name %q, cannot add network alias for container %s", alias, ctr.ID())
+ }
+
+ // Add alias
+ if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding container %s network %q alias %q to DB", ctr.ID(), network, alias)
+ }
+ if err := netAllAliasesBucket.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding container %s network %q alias %q to all aliases in DB", ctr.ID(), network, alias)
+ }
+ }
+
+ return nil
+ })
+}
+
+// RemoveNetworkAliases removes network aliases of the given container in the
+// given network.
+func (s *BoltState) RemoveNetworkAliases(ctr *Container, network string) error {
+ if !s.valid {
+ return define.ErrDBClosed
+ }
+
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ if s.namespace != "" && s.namespace != ctr.config.Namespace {
+ return errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
+ }
+
+ ctrID := []byte(ctr.ID())
+
+ db, err := s.getDBCon()
+ if err != nil {
+ return err
+ }
+ defer s.deferredCloseDBCon(db)
+
+ return db.Update(func(tx *bolt.Tx) error {
+ ctrBucket, err := getCtrBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ allAliasesBucket, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
+ netAllAliasesBucket, err := allAliasesBucket.CreateBucketIfNotExists([]byte(network))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %s", network)
+ }
+
+ dbCtr := ctrBucket.Bucket(ctrID)
+ if dbCtr == nil {
+ ctr.valid = false
+ return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
+ }
+
+ ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
+ if ctrAliasesBkt == nil {
+ return errors.Wrapf(define.ErrNoAliases, "container %s has no network aliases", ctr.ID())
+ }
+
+ ctrNetworksBkt := dbCtr.Bucket(networksBkt)
+ if ctrNetworksBkt == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to any CNI networks, so cannot add aliases", ctr.ID())
+ }
+ netConnected := ctrNetworksBkt.Get([]byte(network))
+ if netConnected == nil {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to CNI network %q, so cannot add aliases for this network", ctr.ID(), network)
+ }
+
+ // Check if the container already has network aliases for this network.
+ netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
+ if netAliasesBkt != nil {
+ // We have aliases. Remove them.
+ forEachErr := netAliasesBkt.ForEach(func(alias, v []byte) error {
+ // Relies on errors.Wrapf(nil, ...) returning
+ // nil.
+ return errors.Wrapf(netAllAliasesBucket.Delete(alias), "error removing alias %q from network %q when changing aliases for container %s", string(alias), network, ctr.ID())
+ })
+ if forEachErr != nil {
+ return forEachErr
+ }
+ }
+
+ return nil
+ })
+}
+
// GetContainerConfig returns a container config from the database by full ID
func (s *BoltState) GetContainerConfig(id string) (*ContainerConfig, error) {
if len(id) == 0 {
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index e195ca314..1ecf99661 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -25,6 +25,7 @@ const (
volName = "vol"
allVolsName = "allVolumes"
execName = "exec"
+ aliasesName = "aliases"
runtimeConfigName = "runtime-config"
configName = "config"
@@ -35,6 +36,7 @@ const (
containersName = "containers"
podIDName = "pod-id"
namespaceName = "namespace"
+ networksName = "networks"
staticDirName = "static-dir"
tmpDirName = "tmp-dir"
@@ -46,26 +48,28 @@ const (
)
var (
- idRegistryBkt = []byte(idRegistryName)
- nameRegistryBkt = []byte(nameRegistryName)
- nsRegistryBkt = []byte(nsRegistryName)
- ctrBkt = []byte(ctrName)
- allCtrsBkt = []byte(allCtrsName)
- podBkt = []byte(podName)
- allPodsBkt = []byte(allPodsName)
- volBkt = []byte(volName)
- allVolsBkt = []byte(allVolsName)
- execBkt = []byte(execName)
- runtimeConfigBkt = []byte(runtimeConfigName)
-
- configKey = []byte(configName)
- stateKey = []byte(stateName)
+ idRegistryBkt = []byte(idRegistryName)
+ nameRegistryBkt = []byte(nameRegistryName)
+ nsRegistryBkt = []byte(nsRegistryName)
+ ctrBkt = []byte(ctrName)
+ allCtrsBkt = []byte(allCtrsName)
+ podBkt = []byte(podName)
+ allPodsBkt = []byte(allPodsName)
+ volBkt = []byte(volName)
+ allVolsBkt = []byte(allVolsName)
+ execBkt = []byte(execName)
+ aliasesBkt = []byte(aliasesName)
+ runtimeConfigBkt = []byte(runtimeConfigName)
dependenciesBkt = []byte(dependenciesName)
volDependenciesBkt = []byte(volCtrDependencies)
- netNSKey = []byte(netNSName)
- containersBkt = []byte(containersName)
- podIDKey = []byte(podIDName)
- namespaceKey = []byte(namespaceName)
+ networksBkt = []byte(networksName)
+
+ configKey = []byte(configName)
+ stateKey = []byte(stateName)
+ netNSKey = []byte(netNSName)
+ containersBkt = []byte(containersName)
+ podIDKey = []byte(podIDName)
+ namespaceKey = []byte(namespaceName)
staticDirKey = []byte(staticDirName)
tmpDirKey = []byte(tmpDirName)
@@ -349,6 +353,14 @@ func getExecBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
return bkt, nil
}
+func getAliasesBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
+ bkt := tx.Bucket(aliasesBkt)
+ if bkt == nil {
+ return nil, errors.Wrapf(define.ErrDBBadConfig, "aliases bucket not found in DB")
+ }
+ return bkt, nil
+}
+
func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
bkt := tx.Bucket(runtimeConfigBkt)
if bkt == nil {
@@ -571,6 +583,11 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return err
}
+ allAliasesBkt, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+
// If a pod was given, check if it exists
var podDB *bolt.Bucket
var podCtrs *bolt.Bucket
@@ -617,6 +634,37 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return errors.Wrapf(err, "name \"%s\" is in use", ctr.Name())
}
+ // If we have network aliases, check if they are already in use.
+ for net, aliases := range ctr.config.NetworkAliases {
+ // Aliases cannot conflict with container names.
+ for _, alias := range aliases {
+ aliasExist := namesBucket.Get([]byte(alias))
+ if aliasExist != nil {
+ return errors.Wrapf(define.ErrCtrExists, "alias %q conflicts with existing container/pod name", alias)
+ }
+ }
+
+ netAliasesBkt := allAliasesBkt.Bucket([]byte(net))
+ if netAliasesBkt != nil {
+ for _, alias := range aliases {
+ aliasExist := netAliasesBkt.Get([]byte(alias))
+ if aliasExist != nil {
+ return errors.Wrapf(define.ErrAliasExists, "network alias %q already exists for network %q", net, alias)
+ }
+ }
+ }
+ hasNet := false
+ for _, testNet := range ctr.config.Networks {
+ if testNet == net {
+ hasNet = true
+ break
+ }
+ }
+ if !hasNet {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not part of that network", ctr.ID(), net)
+ }
+ }
+
// No overlapping containers
// Add the new container to the DB
if err := idsBucket.Put(ctrID, ctrName); err != nil {
@@ -634,6 +682,24 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return errors.Wrapf(err, "error adding container %s to all containers bucket in DB", ctr.ID())
}
+ for net, aliases := range ctr.config.NetworkAliases {
+ netAliasesBkt, err := allAliasesBkt.CreateBucketIfNotExists([]byte(net))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %q", net)
+ }
+ for _, alias := range aliases {
+ if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding container %s network aliasa %q to network %q", ctr.ID(), alias, net)
+ }
+ }
+ // If the container's name is present in the aliases - remove it.
+ if namePresent := netAliasesBkt.Get(ctrName); namePresent != nil {
+ if err := netAliasesBkt.Delete(ctrName); err != nil {
+ return errors.Wrapf(err, "error cleaning container name %q from network %q aliases", ctr.Name(), net)
+ }
+ }
+ }
+
newCtrBkt, err := ctrBucket.CreateBucket(ctrID)
if err != nil {
return errors.Wrapf(err, "error adding container %s bucket to DB", ctr.ID())
@@ -660,6 +726,35 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return errors.Wrapf(err, "error adding container %s netns path to DB", ctr.ID())
}
}
+ if ctr.config.Networks != nil {
+ ctrNetworksBkt, err := newCtrBkt.CreateBucket(networksBkt)
+ if err != nil {
+ return errors.Wrapf(err, "error creating networks bucket for container %s", ctr.ID())
+ }
+ for _, network := range ctr.config.Networks {
+ if err := ctrNetworksBkt.Put([]byte(network), ctrID); err != nil {
+ return errors.Wrapf(err, "error adding network %q to networks bucket for container %s", network, ctr.ID())
+ }
+ }
+ }
+ if ctr.config.NetworkAliases != nil {
+ ctrAliasesBkt, err := newCtrBkt.CreateBucket(aliasesBkt)
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for container %s", ctr.ID())
+ }
+ for net, aliases := range ctr.config.NetworkAliases {
+ netAliasesBkt, err := ctrAliasesBkt.CreateBucket([]byte(net))
+ if err != nil {
+ return errors.Wrapf(err, "error creating network aliases bucket for network %q in container %s", net, ctr.ID())
+ }
+ for _, alias := range aliases {
+ if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil {
+ return errors.Wrapf(err, "error creating network alias %q in network %q for container %s", alias, net, ctr.ID())
+ }
+ }
+ }
+ }
+
if _, err := newCtrBkt.CreateBucket(dependenciesBkt); err != nil {
return errors.Wrapf(err, "error creating dependencies bucket for container %s", ctr.ID())
}
@@ -856,6 +951,49 @@ func (s *BoltState) removeContainer(ctr *Container, pod *Pod, tx *bolt.Tx) error
return errors.Wrapf(define.ErrCtrExists, "container %s is a dependency of the following containers: %s", ctr.ID(), strings.Join(deps, ", "))
}
+ // Does the container have any network aliases?
+ ctrNetAliasesBkt := ctrExists.Bucket(aliasesBkt)
+ if ctrNetAliasesBkt != nil {
+ allAliasesBkt, err := getAliasesBucket(tx)
+ if err != nil {
+ return err
+ }
+ ctrNetworksBkt := ctrExists.Bucket(networksBkt)
+ // Internal state mismatch if this doesn't exist - we'll just
+ // assume there are no aliases in that case.
+ if ctrNetworksBkt != nil {
+ // This is a little gross. Iterate through all networks
+ // the container is joined to. Check if we have aliases
+ // for them. If we do have such aliases, remove all of
+ // then from the global aliases table for that network.
+ err = ctrNetworksBkt.ForEach(func(network, v []byte) error {
+ netAliasesBkt := ctrNetAliasesBkt.Bucket(network)
+ if netAliasesBkt == nil {
+ return nil
+ }
+ netAllAliasesBkt := allAliasesBkt.Bucket(network)
+ if netAllAliasesBkt == nil {
+ // Again the state is inconsistent here,
+ // but the best we can do is try and
+ // recover by ignoring it.
+ return nil
+ }
+ return netAliasesBkt.ForEach(func(alias, v []byte) error {
+ // We don't want to hard-fail on a
+ // missing alias, so continue if we hit
+ // errors.
+ if err := netAllAliasesBkt.Delete(alias); err != nil {
+ logrus.Errorf("Error removing alias %q from network %q when removing container %s", string(alias), string(network), ctr.ID())
+ }
+ return nil
+ })
+ })
+ if err != nil {
+ return err
+ }
+ }
+ }
+
if err := ctrBucket.DeleteBucket(ctrID); err != nil {
return errors.Wrapf(define.ErrInternal, "error deleting container %s from DB", ctr.ID())
}
diff --git a/libpod/container_config.go b/libpod/container_config.go
index e264da4da..fb1ba373b 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -239,6 +239,15 @@ type ContainerNetworkConfig struct {
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
// NetworkOptions are additional options for each network
NetworkOptions map[string][]string `json:"network_options,omitempty"`
+ // NetworkAliases are aliases that will be added to each network.
+ // These are additional names that this container can be accessed as via
+ // DNS when the CNI dnsname plugin is in use.
+ // Please note that these can be altered at runtime. As such, the actual
+ // list is stored in the database and should be retrieved from there;
+ // this is only the set of aliases the container was *created with*.
+ // Formatted as map of network name to aliases. All network names must
+ // be present in the Networks list above.
+ NetworkAliases map[string][]string `json:"network_alises,omitempty"`
}
// ContainerImageConfig is an embedded sub-config providing image configuration
diff --git a/libpod/container_validate.go b/libpod/container_validate.go
index b78168cd1..ee3c8583c 100644
--- a/libpod/container_validate.go
+++ b/libpod/container_validate.go
@@ -107,5 +107,16 @@ func (c *Container) validate() error {
destinations[vol.Dest] = true
}
+ // Check that networks and network aliases match up.
+ ctrNets := make(map[string]bool)
+ for _, net := range c.config.Networks {
+ ctrNets[net] = true
+ }
+ for net := range c.config.NetworkAliases {
+ if _, ok := ctrNets[net]; !ok {
+ return errors.Wrapf(define.ErrNoSuchNetwork, "container tried to set network aliases for network %s but is not connected to the network", net)
+ }
+ }
+
return nil
}
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index 627928ef7..36a919cf6 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -27,6 +27,13 @@ var (
// not exist.
ErrNoSuchExecSession = errors.New("no such exec session")
+ // ErrNoAliases indicates that the container does not have any network
+ // aliases.
+ ErrNoAliases = errors.New("no aliases for container")
+ // ErrNoAliasesForNetwork indicates that the container has no aliases
+ // for a specific network.
+ ErrNoAliasesForNetwork = errors.New("no aliases for network")
+
// ErrCtrExists indicates a container with the same name or ID already
// exists
ErrCtrExists = errors.New("container already exists")
@@ -39,6 +46,9 @@ var (
// ErrExecSessionExists indicates an exec session with the same ID
// already exists.
ErrExecSessionExists = errors.New("exec session already exists")
+ // ErrAliasExists indicates that a network alias with the same name
+ // already exists in the network.
+ ErrAliasExists = errors.New("alias already exists")
// ErrCtrStateInvalid indicates a container is in an improper state for
// the requested operation
diff --git a/libpod/in_memory_state.go b/libpod/in_memory_state.go
index 0de25a6ef..66c2a5cbd 100644
--- a/libpod/in_memory_state.go
+++ b/libpod/in_memory_state.go
@@ -31,6 +31,10 @@ type InMemoryState struct {
ctrExecSessions map[string][]string
// Maps pod ID to a map of container ID to container struct.
podContainers map[string]map[string]*Container
+ // Maps network name to alias to container ID
+ networkAliases map[string]map[string]string
+ // Maps container ID to network name to list of aliases.
+ ctrNetworkAliases map[string]map[string][]string
// Global name registry - ensures name uniqueness and performs lookups.
nameIndex *registrar.Registrar
// Global ID registry - ensures ID uniqueness and performs lookups.
@@ -65,6 +69,9 @@ func NewInMemoryState() (State, error) {
state.podContainers = make(map[string]map[string]*Container)
+ state.networkAliases = make(map[string]map[string]string)
+ state.ctrNetworkAliases = make(map[string]map[string][]string)
+
state.nameIndex = registrar.NewRegistrar()
state.idIndex = truncindex.NewTruncIndex([]string{})
@@ -278,6 +285,29 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
return err
}
+ // Check network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ break
+ }
+ }
+ if !inNet {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network)
+ }
+
+ allNetAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ if _, ok := allNetAliases[alias]; ok {
+ return define.ErrAliasExists
+ }
+ }
+ }
+ }
+
// There are potential race conditions with this
// But in-memory state is intended purely for testing and not production
// use, so this should be fine.
@@ -334,6 +364,20 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
}
+ // Add network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ allNetAliases, ok := s.networkAliases[network]
+ if !ok {
+ allNetAliases = make(map[string]string)
+ s.networkAliases[network] = allNetAliases
+ }
+
+ for _, alias := range aliases {
+ allNetAliases[alias] = ctr.ID()
+ }
+ }
+ s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases
+
return nil
}
@@ -396,6 +440,20 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
s.removeCtrFromVolDependsMap(ctr.ID(), vol.Name)
}
+ // Remove our network aliases
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if ok {
+ for network, aliases := range ctrAliases {
+ netAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ delete(netAliases, alias)
+ }
+ }
+ }
+ delete(s.ctrNetworkAliases, ctr.ID())
+ }
+
return nil
}
@@ -472,6 +530,153 @@ func (s *InMemoryState) AllContainers() ([]*Container, error) {
return ctrs, nil
}
+// GetNetworkAliases returns network aliases for the given container in the
+// given network.
+func (s *InMemoryState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
+ if !ctr.valid {
+ return nil, define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ ctr, ok := s.containers[ctr.ID()]
+ if !ok {
+ return nil, define.ErrNoSuchCtr
+ }
+
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ }
+ }
+ if !inNet {
+ return nil, define.ErrInvalidArg
+ }
+
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if !ok {
+ return []string{}, nil
+ }
+ netAliases, ok := ctrAliases[network]
+ if !ok {
+ return []string{}, nil
+ }
+
+ return netAliases, nil
+}
+
+// SetNetworkAliases sets network aliases for the given container in the given
+// network.
+func (s *InMemoryState) SetNetworkAliases(ctr *Container, network string, aliases []string) error {
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ ctr, ok := s.containers[ctr.ID()]
+ if !ok {
+ return define.ErrNoSuchCtr
+ }
+
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ }
+ }
+ if !inNet {
+ return define.ErrInvalidArg
+ }
+
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if !ok {
+ ctrAliases = make(map[string][]string)
+ s.ctrNetworkAliases[ctr.ID()] = ctrAliases
+ }
+ netAliases, ok := ctrAliases[network]
+ if !ok {
+ netAliases = []string{}
+ ctrAliases[network] = netAliases
+ }
+
+ allAliases, ok := s.networkAliases[network]
+ if !ok {
+ allAliases = make(map[string]string)
+ s.networkAliases[network] = allAliases
+ }
+
+ for _, alias := range netAliases {
+ delete(allAliases, alias)
+ }
+
+ for _, newAlias := range aliases {
+ if _, ok := allAliases[newAlias]; ok {
+ return define.ErrAliasExists
+ }
+ allAliases[newAlias] = ctr.ID()
+ }
+
+ ctrAliases[network] = aliases
+
+ return nil
+}
+
+// RemoveNetworkAliases removes network aliases from the given container in the
+// given network.
+func (s *InMemoryState) RemoveNetworkAliases(ctr *Container, network string) error {
+ if !ctr.valid {
+ return define.ErrCtrRemoved
+ }
+
+ if network == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
+ }
+
+ ctr, ok := s.containers[ctr.ID()]
+ if !ok {
+ return define.ErrNoSuchCtr
+ }
+
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ }
+ }
+ if !inNet {
+ return define.ErrInvalidArg
+ }
+
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if !ok {
+ ctrAliases = make(map[string][]string)
+ s.ctrNetworkAliases[ctr.ID()] = ctrAliases
+ }
+ netAliases, ok := ctrAliases[network]
+ if !ok {
+ netAliases = []string{}
+ ctrAliases[network] = netAliases
+ }
+
+ allAliases, ok := s.networkAliases[network]
+ if !ok {
+ allAliases = make(map[string]string)
+ s.networkAliases[network] = allAliases
+ }
+
+ for _, alias := range netAliases {
+ delete(allAliases, alias)
+ }
+
+ return nil
+}
+
// GetContainerConfig returns a container config from the database by full ID
func (s *InMemoryState) GetContainerConfig(id string) (*ContainerConfig, error) {
ctr, err := s.LookupContainer(id)
@@ -1116,6 +1321,29 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
return err
}
+ // Check network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ inNet := false
+ for _, net := range ctr.config.Networks {
+ if net == network {
+ inNet = true
+ break
+ }
+ }
+ if !inNet {
+ return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network)
+ }
+
+ allNetAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ if _, ok := allNetAliases[alias]; ok {
+ return define.ErrAliasExists
+ }
+ }
+ }
+ }
+
// Retrieve pod containers list
podCtrs, ok := s.podContainers[pod.ID()]
if !ok {
@@ -1188,6 +1416,25 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
s.addCtrToDependsMap(ctr.ID(), depCtr)
}
+ // Add container to volume dependencies
+ for _, vol := range ctr.config.NamedVolumes {
+ s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
+ }
+
+ // Add network aliases
+ for network, aliases := range ctr.config.NetworkAliases {
+ allNetAliases, ok := s.networkAliases[network]
+ if !ok {
+ allNetAliases = make(map[string]string)
+ s.networkAliases[network] = allNetAliases
+ }
+
+ for _, alias := range aliases {
+ allNetAliases[alias] = ctr.ID()
+ }
+ }
+ s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases
+
return nil
}
@@ -1268,6 +1515,20 @@ func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
s.removeCtrFromDependsMap(ctr.ID(), depCtr)
}
+ // Remove our network aliases
+ ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
+ if ok {
+ for network, aliases := range ctrAliases {
+ netAliases, ok := s.networkAliases[network]
+ if ok {
+ for _, alias := range aliases {
+ delete(netAliases, alias)
+ }
+ }
+ }
+ delete(s.ctrNetworkAliases, ctr.ID())
+ }
+
return nil
}
diff --git a/libpod/options.go b/libpod/options.go
index 1ffb78da9..da2fc983a 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1487,6 +1487,20 @@ func WithCreateWorkingDir() CtrCreateOption {
}
}
+// WithNetworkAliases sets network aliases for the container.
+// Accepts a map of network name to aliases.
+func WithNetworkAliases(aliases map[string][]string) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+
+ ctr.config.NetworkAliases = aliases
+
+ return nil
+ }
+}
+
// Volume Creation Options
// WithVolumeName sets the name of the volume.
diff --git a/libpod/state.go b/libpod/state.go
index 44632b02f..fca0548c4 100644
--- a/libpod/state.go
+++ b/libpod/state.go
@@ -98,6 +98,13 @@ type State interface {
// returned.
AllContainers() ([]*Container, error)
+ // Get network aliases for the given container in the given network.
+ GetNetworkAliases(ctr *Container, network string) ([]string, error)
+ // Set network aliases for the given container in the given network.
+ SetNetworkAliases(ctr *Container, network string, aliases []string) error
+ // Remove network aliases for the given container in the given network.
+ RemoveNetworkAliases(ctr *Container, network string) error
+
// Return a container config from the database by full ID
GetContainerConfig(id string) (*ContainerConfig, error)