mirror of
https://github.com/containers/podman.git
synced 2025-07-03 17:27:18 +08:00
Merge pull request #8156 from mheon/add_net_aliases_db
Add network aliases for containers to DB
This commit is contained in:
@ -50,10 +50,12 @@ type BoltState struct {
|
|||||||
// containers in the pod.
|
// containers in the pod.
|
||||||
// - allPodsBkt: Map of ID to name containing only pods. Used for pod lookup
|
// - allPodsBkt: Map of ID to name containing only pods. Used for pod lookup
|
||||||
// operations.
|
// operations.
|
||||||
// - execBkt: Map of exec session ID to exec session - contains a sub-bucket for
|
// - execBkt: Map of exec session ID to container ID - used for resolving
|
||||||
// each exec session in the DB.
|
// exec session IDs to the containers that hold the exec session.
|
||||||
// - execRegistryBkt: Map of exec session ID to nothing. Contains one entry for
|
// - aliasesBkt - Contains a bucket for each CNI network, which contain a map of
|
||||||
// each exec session. Used for iterating through all exec sessions.
|
// 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
|
// - runtimeConfigBkt: Contains configuration of the libpod instance that
|
||||||
// initially created the database. This must match for any further instances
|
// initially created the database. This must match for any further instances
|
||||||
// that access the database, to ensure that state mismatches with
|
// that access the database, to ensure that state mismatches with
|
||||||
@ -92,6 +94,7 @@ func NewBoltState(path string, runtime *Runtime) (State, error) {
|
|||||||
volBkt,
|
volBkt,
|
||||||
allVolsBkt,
|
allVolsBkt,
|
||||||
execBkt,
|
execBkt,
|
||||||
|
aliasesBkt,
|
||||||
runtimeConfigBkt,
|
runtimeConfigBkt,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -969,6 +972,463 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
|
|||||||
return ctrs, nil
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrNetworkBkt := dbCtr.Bucket(networksBkt)
|
||||||
|
if ctrNetworkBkt == nil {
|
||||||
|
// No networks joined, so no aliases
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
inNetwork := ctrNetworkBkt.Get([]byte(network))
|
||||||
|
if inNetwork == nil {
|
||||||
|
return errors.Wrapf(define.ErrNoAliases, "container %s is not part of network %s, no aliases found", ctr.ID(), network)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
|
||||||
|
if ctrAliasesBkt == nil {
|
||||||
|
// No aliases
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllNetworkAliases retrieves the network aliases for the given container in
|
||||||
|
// all CNI networks.
|
||||||
|
func (s *BoltState) GetAllNetworkAliases(ctr *Container) (map[string][]string, error) {
|
||||||
|
if !s.valid {
|
||||||
|
return nil, define.ErrDBClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctr.valid {
|
||||||
|
return nil, define.ErrCtrRemoved
|
||||||
|
}
|
||||||
|
|
||||||
|
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 := make(map[string][]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 {
|
||||||
|
// No aliases present
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrNetworkBkt := dbCtr.Bucket(networksBkt)
|
||||||
|
if ctrNetworkBkt == nil {
|
||||||
|
// No networks joined, so no aliases
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrNetworkBkt.ForEach(func(network, v []byte) error {
|
||||||
|
netAliasesBkt := ctrAliasesBkt.Bucket(network)
|
||||||
|
if netAliasesBkt == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
netAliases := []string{}
|
||||||
|
|
||||||
|
_ = netAliasesBkt.ForEach(func(alias, v []byte) error {
|
||||||
|
netAliases = append(netAliases, string(alias))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
aliases[string(network)] = netAliases
|
||||||
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all network aliases for a single CNI network. Returns a map of alias to
|
||||||
|
// container ID.
|
||||||
|
func (s *BoltState) GetAllAliasesForNetwork(network string) (map[string]string, error) {
|
||||||
|
if !s.valid {
|
||||||
|
return nil, define.ErrDBClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
if network == "" {
|
||||||
|
return nil, errors.Wrapf(define.ErrInvalidArg, "network name must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := s.getDBCon()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer s.deferredCloseDBCon(db)
|
||||||
|
|
||||||
|
aliases := make(map[string]string)
|
||||||
|
|
||||||
|
err = db.View(func(tx *bolt.Tx) error {
|
||||||
|
aliasBucket, err := getAliasesBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbAlias := aliasBucket.Bucket([]byte(network))
|
||||||
|
if dbAlias == nil {
|
||||||
|
// We can't tell if the network exists, or doesn't exist
|
||||||
|
// So... Assume it exists, but has no aliases.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbAlias.ForEach(func(alias, ctrId []byte) error {
|
||||||
|
aliases[string(alias)] = string(ctrId)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return aliases, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAllAliasesForNetwork removes all the aliases in a given CNI network, as
|
||||||
|
// part of that network being removed.
|
||||||
|
func (s *BoltState) RemoveAllAliasesForNetwork(network string) error {
|
||||||
|
if !s.valid {
|
||||||
|
return define.ErrDBClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
if network == "" {
|
||||||
|
return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := s.getDBCon()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.deferredCloseDBCon(db)
|
||||||
|
|
||||||
|
return db.Update(func(tx *bolt.Tx) error {
|
||||||
|
allCtrsBucket, err := getAllCtrsBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrBucket, err := getCtrBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
allAliasesBucket, err := getAliasesBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAliasesBucketExists := allAliasesBucket.Bucket([]byte(network))
|
||||||
|
if checkAliasesBucketExists != nil {
|
||||||
|
if err := allAliasesBucket.DeleteBucket([]byte(network)); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing network %s aliases bucket from DB", network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through all containers and remove their aliases
|
||||||
|
// bucket for the network.
|
||||||
|
return allCtrsBucket.ForEach(func(ctrID, ctrName []byte) error {
|
||||||
|
dbCtr := ctrBucket.Bucket(ctrID)
|
||||||
|
if dbCtr == nil {
|
||||||
|
// DB State is inconsistent... but we can't do
|
||||||
|
// anything about it.
|
||||||
|
// Log and move on.
|
||||||
|
logrus.Errorf("Container %s listed in all containers, but has no bucket!", string(ctrID))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dbCtrAliases := dbCtr.Bucket(aliasesBkt)
|
||||||
|
if dbCtrAliases == nil {
|
||||||
|
// Container has no aliases, this is OK.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrNetAliases := dbCtrAliases.Bucket([]byte(network))
|
||||||
|
if ctrNetAliases != nil {
|
||||||
|
if err := dbCtrAliases.DeleteBucket([]byte(network)); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing bucket for network aliases for network %s from container %s", network, string(ctrID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// GetContainerConfig returns a container config from the database by full ID
|
// GetContainerConfig returns a container config from the database by full ID
|
||||||
func (s *BoltState) GetContainerConfig(id string) (*ContainerConfig, error) {
|
func (s *BoltState) GetContainerConfig(id string) (*ContainerConfig, error) {
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
|
@ -26,6 +26,7 @@ const (
|
|||||||
volName = "vol"
|
volName = "vol"
|
||||||
allVolsName = "allVolumes"
|
allVolsName = "allVolumes"
|
||||||
execName = "exec"
|
execName = "exec"
|
||||||
|
aliasesName = "aliases"
|
||||||
runtimeConfigName = "runtime-config"
|
runtimeConfigName = "runtime-config"
|
||||||
|
|
||||||
configName = "config"
|
configName = "config"
|
||||||
@ -36,6 +37,7 @@ const (
|
|||||||
containersName = "containers"
|
containersName = "containers"
|
||||||
podIDName = "pod-id"
|
podIDName = "pod-id"
|
||||||
namespaceName = "namespace"
|
namespaceName = "namespace"
|
||||||
|
networksName = "networks"
|
||||||
|
|
||||||
staticDirName = "static-dir"
|
staticDirName = "static-dir"
|
||||||
tmpDirName = "tmp-dir"
|
tmpDirName = "tmp-dir"
|
||||||
@ -57,12 +59,14 @@ var (
|
|||||||
volBkt = []byte(volName)
|
volBkt = []byte(volName)
|
||||||
allVolsBkt = []byte(allVolsName)
|
allVolsBkt = []byte(allVolsName)
|
||||||
execBkt = []byte(execName)
|
execBkt = []byte(execName)
|
||||||
|
aliasesBkt = []byte(aliasesName)
|
||||||
runtimeConfigBkt = []byte(runtimeConfigName)
|
runtimeConfigBkt = []byte(runtimeConfigName)
|
||||||
|
dependenciesBkt = []byte(dependenciesName)
|
||||||
|
volDependenciesBkt = []byte(volCtrDependencies)
|
||||||
|
networksBkt = []byte(networksName)
|
||||||
|
|
||||||
configKey = []byte(configName)
|
configKey = []byte(configName)
|
||||||
stateKey = []byte(stateName)
|
stateKey = []byte(stateName)
|
||||||
dependenciesBkt = []byte(dependenciesName)
|
|
||||||
volDependenciesBkt = []byte(volCtrDependencies)
|
|
||||||
netNSKey = []byte(netNSName)
|
netNSKey = []byte(netNSName)
|
||||||
containersBkt = []byte(containersName)
|
containersBkt = []byte(containersName)
|
||||||
podIDKey = []byte(podIDName)
|
podIDKey = []byte(podIDName)
|
||||||
@ -350,6 +354,14 @@ func getExecBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
|||||||
return bkt, nil
|
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) {
|
func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
|
||||||
bkt := tx.Bucket(runtimeConfigBkt)
|
bkt := tx.Bucket(runtimeConfigBkt)
|
||||||
if bkt == nil {
|
if bkt == nil {
|
||||||
@ -572,6 +584,11 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allAliasesBkt, err := getAliasesBucket(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// If a pod was given, check if it exists
|
// If a pod was given, check if it exists
|
||||||
var podDB *bolt.Bucket
|
var podDB *bolt.Bucket
|
||||||
var podCtrs *bolt.Bucket
|
var podCtrs *bolt.Bucket
|
||||||
@ -618,6 +635,44 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
|
|||||||
return errors.Wrapf(err, "name \"%s\" is in use", ctr.Name())
|
return errors.Wrapf(err, "name \"%s\" is in use", ctr.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that we don't have any empty network names
|
||||||
|
for _, net := range ctr.config.Networks {
|
||||||
|
if net == "" {
|
||||||
|
return errors.Wrapf(define.ErrInvalidArg, "network names cannot be an empty string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// No overlapping containers
|
||||||
// Add the new container to the DB
|
// Add the new container to the DB
|
||||||
if err := idsBucket.Put(ctrID, ctrName); err != nil {
|
if err := idsBucket.Put(ctrID, ctrName); err != nil {
|
||||||
@ -635,6 +690,63 @@ 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())
|
return errors.Wrapf(err, "error adding container %s to all containers bucket in DB", ctr.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check aliases for all networks, remove conflicts with the
|
||||||
|
// container name.
|
||||||
|
for _, net := range ctr.config.Networks {
|
||||||
|
netAliasesBkt := allAliasesBkt.Bucket([]byte(net))
|
||||||
|
if netAliasesBkt == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
otherCtrID := netAliasesBkt.Get(ctrName)
|
||||||
|
if otherCtrID == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := netAliasesBkt.Delete(ctrName); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing container %s name from network aliases for network %s", ctr.ID(), net)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now need to remove from the other container.
|
||||||
|
// To do this, we work through the container bucket,
|
||||||
|
// then its aliases bucket, then its aliases for this
|
||||||
|
// specific network, then we remove the alias.
|
||||||
|
// Just slightly ridiculous. Just slightly.
|
||||||
|
otherCtr := ctrBucket.Bucket(otherCtrID)
|
||||||
|
if otherCtr == nil {
|
||||||
|
// The state is inconsistent, but we can't do
|
||||||
|
// much...
|
||||||
|
logrus.Errorf("Container %s referred to by network alias but not present in state", string(otherCtrID))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
otherCtrAliases := otherCtr.Bucket(aliasesBkt)
|
||||||
|
if otherCtrAliases == nil {
|
||||||
|
logrus.Errorf("Container %s is missing aliases but but has an alias", string(otherCtrID))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
otherCtrNetworkAliases := otherCtrAliases.Bucket([]byte(net))
|
||||||
|
if otherCtrNetworkAliases == nil {
|
||||||
|
logrus.Errorf("Container %s is missing network aliases bucket for network %s but has alias in that network", string(otherCtrID), net)
|
||||||
|
}
|
||||||
|
if otherCtrNetworkAliases.Get(ctrName) != nil {
|
||||||
|
if err := otherCtrNetworkAliases.Delete(ctrName); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing container %s name from network %s aliases of container %s", ctr.Name(), net, string(otherCtrID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 alias %q to network %q", ctr.ID(), alias, net)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newCtrBkt, err := ctrBucket.CreateBucket(ctrID)
|
newCtrBkt, err := ctrBucket.CreateBucket(ctrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "error adding container %s bucket to DB", ctr.ID())
|
return errors.Wrapf(err, "error adding container %s bucket to DB", ctr.ID())
|
||||||
@ -661,6 +773,35 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
|
|||||||
return errors.Wrapf(err, "error adding container %s netns path to DB", ctr.ID())
|
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 {
|
if _, err := newCtrBkt.CreateBucket(dependenciesBkt); err != nil {
|
||||||
return errors.Wrapf(err, "error creating dependencies bucket for container %s", ctr.ID())
|
return errors.Wrapf(err, "error creating dependencies bucket for container %s", ctr.ID())
|
||||||
}
|
}
|
||||||
@ -857,6 +998,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, ", "))
|
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 {
|
if err := ctrBucket.DeleteBucket(ctrID); err != nil {
|
||||||
return errors.Wrapf(define.ErrInternal, "error deleting container %s from DB", ctr.ID())
|
return errors.Wrapf(define.ErrInternal, "error deleting container %s from DB", ctr.ID())
|
||||||
}
|
}
|
||||||
|
@ -241,6 +241,15 @@ type ContainerNetworkConfig struct {
|
|||||||
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
|
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
|
||||||
// NetworkOptions are additional options for each network
|
// NetworkOptions are additional options for each network
|
||||||
NetworkOptions map[string][]string `json:"network_options,omitempty"`
|
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
|
// ContainerImageConfig is an embedded sub-config providing image configuration
|
||||||
|
@ -115,5 +115,16 @@ func (c *Container) validate() error {
|
|||||||
destinations[vol.Dest] = true
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,13 @@ var (
|
|||||||
// not exist.
|
// not exist.
|
||||||
ErrNoSuchExecSession = errors.New("no such exec session")
|
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
|
// ErrCtrExists indicates a container with the same name or ID already
|
||||||
// exists
|
// exists
|
||||||
ErrCtrExists = errors.New("container already exists")
|
ErrCtrExists = errors.New("container already exists")
|
||||||
@ -42,6 +49,9 @@ var (
|
|||||||
// ErrExecSessionExists indicates an exec session with the same ID
|
// ErrExecSessionExists indicates an exec session with the same ID
|
||||||
// already exists.
|
// already exists.
|
||||||
ErrExecSessionExists = errors.New("exec session 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
|
// ErrCtrStateInvalid indicates a container is in an improper state for
|
||||||
// the requested operation
|
// the requested operation
|
||||||
|
@ -31,6 +31,10 @@ type InMemoryState struct {
|
|||||||
ctrExecSessions map[string][]string
|
ctrExecSessions map[string][]string
|
||||||
// Maps pod ID to a map of container ID to container struct.
|
// Maps pod ID to a map of container ID to container struct.
|
||||||
podContainers map[string]map[string]*Container
|
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.
|
// Global name registry - ensures name uniqueness and performs lookups.
|
||||||
nameIndex *registrar.Registrar
|
nameIndex *registrar.Registrar
|
||||||
// Global ID registry - ensures ID uniqueness and performs lookups.
|
// 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.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.nameIndex = registrar.NewRegistrar()
|
||||||
state.idIndex = truncindex.NewTruncIndex([]string{})
|
state.idIndex = truncindex.NewTruncIndex([]string{})
|
||||||
|
|
||||||
@ -278,6 +285,40 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check networks
|
||||||
|
for _, net := range ctr.config.Networks {
|
||||||
|
if net == "" {
|
||||||
|
return errors.Wrapf(define.ErrInvalidArg, "network names cannot be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Check if alias is a name
|
||||||
|
if _, err := s.nameIndex.Get(alias); err == nil {
|
||||||
|
return define.ErrInvalidArg
|
||||||
|
}
|
||||||
|
if _, ok := allNetAliases[alias]; ok {
|
||||||
|
return define.ErrAliasExists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// There are potential race conditions with this
|
// There are potential race conditions with this
|
||||||
// But in-memory state is intended purely for testing and not production
|
// But in-memory state is intended purely for testing and not production
|
||||||
// use, so this should be fine.
|
// use, so this should be fine.
|
||||||
@ -334,6 +375,48 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
|
|||||||
s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
|
s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, network := range ctr.config.Networks {
|
||||||
|
allNetAliases, ok := s.networkAliases[network]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
otherCtrID, ok := allNetAliases[ctr.Name()]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(allNetAliases, ctr.Name())
|
||||||
|
|
||||||
|
otherCtrAliases, ok := s.ctrNetworkAliases[otherCtrID]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
otherCtrNetAliases, ok := otherCtrAliases[network]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newAliases := []string{}
|
||||||
|
for _, alias := range otherCtrNetAliases {
|
||||||
|
if alias != ctr.Name() {
|
||||||
|
newAliases = append(newAliases, alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
otherCtrAliases[network] = newAliases
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,6 +479,20 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
|
|||||||
s.removeCtrFromVolDependsMap(ctr.ID(), vol.Name)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,6 +569,207 @@ func (s *InMemoryState) AllContainers() ([]*Container, error) {
|
|||||||
return ctrs, nil
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllNetworkAliases gets all network aliases for the given container.
|
||||||
|
func (s *InMemoryState) GetAllNetworkAliases(ctr *Container) (map[string][]string, error) {
|
||||||
|
if !ctr.valid {
|
||||||
|
return nil, define.ErrCtrRemoved
|
||||||
|
}
|
||||||
|
|
||||||
|
ctr, ok := s.containers[ctr.ID()]
|
||||||
|
if !ok {
|
||||||
|
return nil, define.ErrNoSuchCtr
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
|
||||||
|
if !ok {
|
||||||
|
return map[string][]string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrAliases, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllAliasesForNetwork gets all the aliases for a single network.
|
||||||
|
func (s *InMemoryState) GetAllAliasesForNetwork(network string) (map[string]string, error) {
|
||||||
|
if network == "" {
|
||||||
|
return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
allAliases, ok := s.networkAliases[network]
|
||||||
|
if !ok {
|
||||||
|
// Can't tell if the network exists.
|
||||||
|
// Assume it does.
|
||||||
|
return map[string]string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return allAliases, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAllAliasesForNetwork removes all the aliases for a given network.
|
||||||
|
func (s *InMemoryState) RemoveAllAliasesForNetwork(network string) error {
|
||||||
|
if network == "" {
|
||||||
|
return errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := s.networkAliases[network]; ok {
|
||||||
|
delete(s.networkAliases, network)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ctrAliases := range s.ctrNetworkAliases {
|
||||||
|
if _, ok := ctrAliases[network]; ok {
|
||||||
|
delete(ctrAliases, network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetContainerConfig returns a container config from the database by full ID
|
// GetContainerConfig returns a container config from the database by full ID
|
||||||
func (s *InMemoryState) GetContainerConfig(id string) (*ContainerConfig, error) {
|
func (s *InMemoryState) GetContainerConfig(id string) (*ContainerConfig, error) {
|
||||||
ctr, err := s.LookupContainer(id)
|
ctr, err := s.LookupContainer(id)
|
||||||
@ -1116,6 +1414,40 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check networks
|
||||||
|
for _, net := range ctr.config.Networks {
|
||||||
|
if net == "" {
|
||||||
|
return errors.Wrapf(define.ErrInvalidArg, "network names cannot be empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Check if alias is a name
|
||||||
|
if _, err := s.nameIndex.Get(alias); err == nil {
|
||||||
|
return define.ErrInvalidArg
|
||||||
|
}
|
||||||
|
if _, ok := allNetAliases[alias]; ok {
|
||||||
|
return define.ErrAliasExists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve pod containers list
|
// Retrieve pod containers list
|
||||||
podCtrs, ok := s.podContainers[pod.ID()]
|
podCtrs, ok := s.podContainers[pod.ID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1188,6 +1520,53 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
|
|||||||
s.addCtrToDependsMap(ctr.ID(), depCtr)
|
s.addCtrToDependsMap(ctr.ID(), depCtr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add container to volume dependencies
|
||||||
|
for _, vol := range ctr.config.NamedVolumes {
|
||||||
|
s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, network := range ctr.config.Networks {
|
||||||
|
allNetAliases, ok := s.networkAliases[network]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
otherCtrID, ok := allNetAliases[ctr.Name()]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(allNetAliases, ctr.Name())
|
||||||
|
|
||||||
|
otherCtrAliases, ok := s.ctrNetworkAliases[otherCtrID]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
otherCtrNetAliases, ok := otherCtrAliases[network]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newAliases := []string{}
|
||||||
|
for _, alias := range otherCtrNetAliases {
|
||||||
|
if alias != ctr.Name() {
|
||||||
|
newAliases = append(newAliases, alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
otherCtrAliases[network] = newAliases
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1268,6 +1647,20 @@ func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
|
|||||||
s.removeCtrFromDependsMap(ctr.ID(), depCtr)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1506,6 +1506,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
|
// Volume Creation Options
|
||||||
|
|
||||||
// WithVolumeName sets the name of the volume.
|
// WithVolumeName sets the name of the volume.
|
||||||
|
@ -98,6 +98,21 @@ type State interface {
|
|||||||
// returned.
|
// returned.
|
||||||
AllContainers() ([]*Container, error)
|
AllContainers() ([]*Container, error)
|
||||||
|
|
||||||
|
// Get network aliases for the given container in the given network.
|
||||||
|
GetNetworkAliases(ctr *Container, network string) ([]string, error)
|
||||||
|
// Get all network aliases for the given container.
|
||||||
|
GetAllNetworkAliases(ctr *Container) (map[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
|
||||||
|
// GetAllAliasesForNetwork returns all the aliases for a given
|
||||||
|
// network. Returns a map of alias to container ID.
|
||||||
|
GetAllAliasesForNetwork(network string) (map[string]string, error)
|
||||||
|
// RemoveAllAliasesForNetwork removes all the aliases for a given
|
||||||
|
// network.
|
||||||
|
RemoveAllAliasesForNetwork(network string) error
|
||||||
|
|
||||||
// Return a container config from the database by full ID
|
// Return a container config from the database by full ID
|
||||||
GetContainerConfig(id string) (*ContainerConfig, error)
|
GetContainerConfig(id string) (*ContainerConfig, error)
|
||||||
|
|
||||||
|
@ -1319,6 +1319,250 @@ func TestCannotUsePodAsDependency(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddContainerEmptyNetworkNameErrors(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testCtr.config.Networks = []string{""}
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddContainerNetworkAliasesButNoMatchingNetwork(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testCtr.config.Networks = []string{"test1"}
|
||||||
|
testCtr.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr.config.NetworkAliases["test2"] = []string{"alias1"}
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddContainerNetworkAliasConflictWithName(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr1, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
netName := "testnet"
|
||||||
|
testCtr1.config.Networks = []string{netName}
|
||||||
|
testCtr1.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr1.config.NetworkAliases[netName] = []string{"alias1"}
|
||||||
|
|
||||||
|
testCtr2, err := getTestCtr2(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testCtr2.config.Networks = []string{netName}
|
||||||
|
testCtr2.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr2.config.NetworkAliases[netName] = []string{testCtr1.Name()}
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr2)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddContainerNetworkAliasConflictWithAlias(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr1, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
netName := "testnet"
|
||||||
|
aliasName := "alias1"
|
||||||
|
testCtr1.config.Networks = []string{netName}
|
||||||
|
testCtr1.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr1.config.NetworkAliases[netName] = []string{aliasName}
|
||||||
|
|
||||||
|
testCtr2, err := getTestCtr2(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testCtr2.config.Networks = []string{netName}
|
||||||
|
testCtr2.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr2.config.NetworkAliases[netName] = []string{aliasName}
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr2)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddContainerNetworkAliasConflictWithAliasButDifferentNets(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr1, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
netName := "testnet"
|
||||||
|
aliasName := "alias1"
|
||||||
|
testCtr1.config.Networks = []string{netName}
|
||||||
|
testCtr1.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr1.config.NetworkAliases[netName] = []string{aliasName}
|
||||||
|
|
||||||
|
testCtr2, err := getTestCtr2(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
netName2 := "testnet2"
|
||||||
|
testCtr2.config.Networks = []string{netName2}
|
||||||
|
testCtr2.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr2.config.NetworkAliases[netName2] = []string{aliasName}
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddContainerNameConflictsWithAliasRemovesAlias(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr1, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testCtr2, err := getTestCtr2(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
netName := "testnet"
|
||||||
|
aliasName := testCtr2.Name()
|
||||||
|
testCtr1.config.Networks = []string{netName}
|
||||||
|
testCtr1.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr1.config.NetworkAliases[netName] = []string{aliasName}
|
||||||
|
|
||||||
|
testCtr2.config.Networks = []string{netName}
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
aliases, err := state.GetNetworkAliases(testCtr1, netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, len(aliases))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkAliasAddAndRemoveSingleContainer(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
netName := "testnet"
|
||||||
|
testCtr.config.Networks = []string{netName}
|
||||||
|
testCtr.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr.config.NetworkAliases[netName] = []string{"alias1"}
|
||||||
|
|
||||||
|
startAliases, err := state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, len(startAliases))
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
oneAlias, err := state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(oneAlias))
|
||||||
|
assert.Equal(t, testCtr.ID(), oneAlias["alias1"])
|
||||||
|
|
||||||
|
allAliases, err := state.GetAllNetworkAliases(testCtr)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(allAliases))
|
||||||
|
netAliases, ok := allAliases[netName]
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, 1, len(netAliases))
|
||||||
|
assert.Equal(t, "alias1", netAliases[0])
|
||||||
|
|
||||||
|
ctrNetAliases, err := state.GetNetworkAliases(testCtr, netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(ctrNetAliases))
|
||||||
|
assert.Equal(t, "alias1", ctrNetAliases[0])
|
||||||
|
|
||||||
|
err = state.RemoveContainer(testCtr)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
noAliases, err := state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, len(noAliases))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNetworkAliasAddAndRemoveTwoContainers(t *testing.T) {
|
||||||
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
|
testCtr1, err := getTestCtr1(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
netName := "testnet"
|
||||||
|
testCtr1.config.Networks = []string{netName}
|
||||||
|
testCtr1.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr1.config.NetworkAliases[netName] = []string{"alias1"}
|
||||||
|
|
||||||
|
testCtr2, err := getTestCtr2(manager)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
testCtr2.config.Networks = []string{netName}
|
||||||
|
testCtr2.config.NetworkAliases = make(map[string][]string)
|
||||||
|
testCtr2.config.NetworkAliases[netName] = []string{"alias2"}
|
||||||
|
|
||||||
|
startAliases, err := state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, len(startAliases))
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
oneAlias, err := state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(oneAlias))
|
||||||
|
assert.Equal(t, testCtr1.ID(), oneAlias["alias1"])
|
||||||
|
|
||||||
|
err = state.AddContainer(testCtr2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
twoAliases, err := state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 2, len(twoAliases))
|
||||||
|
assert.Equal(t, testCtr1.ID(), twoAliases["alias1"])
|
||||||
|
assert.Equal(t, testCtr2.ID(), twoAliases["alias2"])
|
||||||
|
|
||||||
|
allAliases, err := state.GetAllNetworkAliases(testCtr1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(allAliases))
|
||||||
|
netAliases, ok := allAliases[netName]
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, 1, len(netAliases))
|
||||||
|
assert.Equal(t, "alias1", netAliases[0])
|
||||||
|
|
||||||
|
ctrNetAliases, err := state.GetNetworkAliases(testCtr1, netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(ctrNetAliases))
|
||||||
|
assert.Equal(t, "alias1", ctrNetAliases[0])
|
||||||
|
|
||||||
|
err = state.RemoveContainer(testCtr2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
oneAlias, err = state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(oneAlias))
|
||||||
|
assert.Equal(t, testCtr1.ID(), oneAlias["alias1"])
|
||||||
|
|
||||||
|
err = state.RemoveContainer(testCtr1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
noAliases, err := state.GetAllAliasesForNetwork(netName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, len(noAliases))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestCannotUseBadIDAsDependency(t *testing.T) {
|
func TestCannotUseBadIDAsDependency(t *testing.T) {
|
||||||
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
|
||||||
testCtr, err := getTestCtr1(manager)
|
testCtr, err := getTestCtr1(manager)
|
||||||
|
Reference in New Issue
Block a user