mirror of
https://github.com/containers/podman.git
synced 2025-06-24 11:28:24 +08:00
Add support for network connect / disconnect to DB
Convert the existing network aliases set/remove code to network connect and disconnect. We can no longer modify aliases for an existing network, but we can add and remove entire networks. As part of this, we need to add a new function to retrieve current aliases the container is connected to (we had a table for this as of the first aliases PR, but it was not externally exposed). At the same time, remove all deconflicting logic for aliases. Docker does absolutely no checks of this nature, and allows two containers to have the same aliases, aliases that conflict with container names, etc - it's just left to DNS to return all the IP addresses, and presumably we round-robin from there? Most tests for the existing code had to be removed because of this. Convert all uses of the old container config.Networks field, which previously included all networks in the container, to use the new DB table. This ensures we actually get an up-to-date list of in-use networks. Also, add network aliases to the output of `podman inspect`. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
@ -94,7 +94,6 @@ func NewBoltState(path string, runtime *Runtime) (State, error) {
|
|||||||
volBkt,
|
volBkt,
|
||||||
allVolsBkt,
|
allVolsBkt,
|
||||||
execBkt,
|
execBkt,
|
||||||
aliasesBkt,
|
|
||||||
runtimeConfigBkt,
|
runtimeConfigBkt,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,6 +971,58 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
|
|||||||
return ctrs, nil
|
return ctrs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNetworks returns the CNI networks this container is a part of.
|
||||||
|
func (s *BoltState) GetNetworks(ctr *Container) ([]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)
|
||||||
|
|
||||||
|
networks := []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 {
|
||||||
|
return errors.Wrapf(define.ErrNoSuchNetwork, "container %s is not joined to any CNI networks", ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrNetworkBkt.ForEach(func(network, v []byte) error {
|
||||||
|
networks = append(networks, string(network))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return networks, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetNetworkAliases retrieves the network aliases for the given container in
|
// GetNetworkAliases retrieves the network aliases for the given container in
|
||||||
// the given CNI network.
|
// the given CNI network.
|
||||||
func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
|
func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
|
||||||
@ -1032,7 +1083,8 @@ func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string,
|
|||||||
|
|
||||||
netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
|
netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
|
||||||
if netAliasesBkt == nil {
|
if netAliasesBkt == nil {
|
||||||
return errors.Wrapf(define.ErrNoAliasesForNetwork, "container %s has no aliases for network %q", ctr.ID(), network)
|
// No aliases for this specific network.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return netAliasesBkt.ForEach(func(alias, v []byte) error {
|
return netAliasesBkt.ForEach(func(alias, v []byte) error {
|
||||||
@ -1120,10 +1172,9 @@ func (s *BoltState) GetAllNetworkAliases(ctr *Container) (map[string][]string, e
|
|||||||
return aliases, nil
|
return aliases, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNetworkAliases sets network aliases for the given container in the given
|
// NetworkConnect adds the given container to the given network. If aliases are
|
||||||
// network. All existing aliases for that network (if any exist) will be removed,
|
// specified, those will be added to the given network.
|
||||||
// to be replaced by the new aliases given.
|
func (s *BoltState) NetworkConnect(ctr *Container, network string, aliases []string) error {
|
||||||
func (s *BoltState) SetNetworkAliases(ctr *Container, network string, aliases []string) error {
|
|
||||||
if !s.valid {
|
if !s.valid {
|
||||||
return define.ErrDBClosed
|
return define.ErrDBClosed
|
||||||
}
|
}
|
||||||
@ -1154,278 +1205,124 @@ func (s *BoltState) SetNetworkAliases(ctr *Container, network string, aliases []
|
|||||||
return err
|
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)
|
dbCtr := ctrBucket.Bucket(ctrID)
|
||||||
if dbCtr == nil {
|
if dbCtr == nil {
|
||||||
ctr.valid = false
|
ctr.valid = false
|
||||||
return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
|
return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
|
ctrAliasesBkt, err := dbCtr.CreateBucketIfNotExists(aliasesBkt)
|
||||||
if ctrAliasesBkt == nil {
|
if err != nil {
|
||||||
return errors.Wrapf(define.ErrNoAliases, "container %s has no network aliases", ctr.ID())
|
return errors.Wrapf(err, "error creating aliases bucket for container %s", ctr.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrNetworksBkt := dbCtr.Bucket(networksBkt)
|
ctrNetworksBkt := dbCtr.Bucket(networksBkt)
|
||||||
if ctrNetworksBkt == nil {
|
if ctrNetworksBkt == nil {
|
||||||
return errors.Wrapf(define.ErrInvalidArg, "container %s is not connected to any CNI networks, so cannot add aliases", ctr.ID())
|
ctrNetworksBkt, err = dbCtr.CreateBucket(networksBkt)
|
||||||
}
|
|
||||||
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 {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not create bucket for network aliases for network %q", network)
|
return errors.Wrapf(err, "error creating networks bucket for container %s", ctr.ID())
|
||||||
}
|
}
|
||||||
netAliasesBkt = newBkt
|
ctrNetworks := ctr.config.Networks
|
||||||
}
|
if len(ctrNetworks) == 0 {
|
||||||
|
ctrNetworks = []string{ctr.runtime.netPlugin.GetDefaultNetworkName()}
|
||||||
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))
|
// Copy in all the container's CNI networks
|
||||||
if nameExists != nil {
|
for _, net := range ctrNetworks {
|
||||||
return errors.Wrapf(define.ErrCtrExists, "a container or pod already uses the name %q, cannot add network alias for container %s", alias, ctr.ID())
|
if err := ctrNetworksBkt.Put([]byte(net), ctrID); err != nil {
|
||||||
}
|
return errors.Wrapf(err, "error adding container %s network %s to DB", ctr.ID(), net)
|
||||||
|
|
||||||
// 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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
netConnected := ctrNetworksBkt.Get([]byte(network))
|
||||||
|
if netConnected != nil {
|
||||||
|
return errors.Wrapf(define.ErrNetworkExists, "container %s is already connected to CNI network %q", ctr.ID(), network)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the network
|
||||||
|
if err := ctrNetworksBkt.Put([]byte(network), ctrID); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s to network %s in DB", ctr.ID(), network)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrNetAliasesBkt, err := ctrAliasesBkt.CreateBucketIfNotExists([]byte(network))
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s network aliases bucket for network %s", ctr.ID(), network)
|
||||||
|
}
|
||||||
|
for _, alias := range aliases {
|
||||||
|
if err := ctrNetAliasesBkt.Put([]byte(alias), ctrID); err != nil {
|
||||||
|
return errors.Wrapf(err, "error adding container %s network alias %s for network %s", ctr.ID(), alias, network)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkDisconnect disconnects the container from the given network, also
|
||||||
|
// removing any aliases in the network.
|
||||||
|
func (s *BoltState) NetworkDisconnect(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
|
||||||
|
}
|
||||||
|
|
||||||
|
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.ErrNoSuchNetwork, "container %s is not connected to any CNI networks, so cannot disconnect", ctr.ID())
|
||||||
|
}
|
||||||
|
netConnected := ctrNetworksBkt.Get([]byte(network))
|
||||||
|
if netConnected == nil {
|
||||||
|
return errors.Wrapf(define.ErrNoSuchNetwork, "container %s is not connected to CNI network %q", ctr.ID(), network)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ctrNetworksBkt.Delete([]byte(network)); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing container %s from network %s", ctr.ID(), network)
|
||||||
|
}
|
||||||
|
|
||||||
|
bktExists := ctrAliasesBkt.Bucket([]byte(network))
|
||||||
|
if bktExists == nil {
|
||||||
return nil
|
return nil
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if err := ctrAliasesBkt.DeleteBucket([]byte(network)); err != nil {
|
||||||
|
return errors.Wrapf(err, "error removing container %s network aliases for network %s", ctr.ID(), network)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,14 +354,6 @@ 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 {
|
||||||
@ -584,11 +576,6 @@ 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
|
||||||
@ -635,41 +622,20 @@ 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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allNets := make(map[string]bool)
|
||||||
|
|
||||||
// Check that we don't have any empty network names
|
// Check that we don't have any empty network names
|
||||||
for _, net := range ctr.config.Networks {
|
for _, net := range ctr.config.Networks {
|
||||||
if net == "" {
|
if net == "" {
|
||||||
return errors.Wrapf(define.ErrInvalidArg, "network names cannot be an empty string")
|
return errors.Wrapf(define.ErrInvalidArg, "network names cannot be an empty string")
|
||||||
}
|
}
|
||||||
|
allNets[net] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have network aliases, check if they are already in use.
|
// Each network we have aliases for, must exist in networks
|
||||||
for net, aliases := range ctr.config.NetworkAliases {
|
for net := range ctr.config.NetworkAliases {
|
||||||
// Aliases cannot conflict with container names.
|
if !allNets[net] {
|
||||||
for _, alias := range aliases {
|
return errors.Wrapf(define.ErrNoSuchNetwork, "container %s has network aliases for network %q but is not part of that network", ctr.ID(), net)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,63 +656,6 @@ 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())
|
||||||
@ -998,49 +907,6 @@ 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())
|
||||||
}
|
}
|
||||||
|
@ -1085,3 +1085,31 @@ func (c *Container) Timezone() string {
|
|||||||
func (c *Container) Umask() string {
|
func (c *Container) Umask() string {
|
||||||
return c.config.Umask
|
return c.config.Umask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Networks gets all the networks this container is connected to.
|
||||||
|
// Please do NOT use ctr.config.Networks, as this can be changed from those
|
||||||
|
// values at runtime via network connect and disconnect.
|
||||||
|
// If the container is configured to use CNI and this function returns an empty
|
||||||
|
// array, the container will still be connected to the default network.
|
||||||
|
func (c *Container) Networks() ([]string, error) {
|
||||||
|
if !c.batched {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
|
|
||||||
|
if err := c.syncContainer(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.networks()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlocked accessor for networks
|
||||||
|
func (c *Container) networks() ([]string, error) {
|
||||||
|
networks, err := c.runtime.state.GetNetworks(c)
|
||||||
|
if err != nil && errors.Cause(err) == define.ErrNoSuchNetwork {
|
||||||
|
return c.config.Networks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return networks, err
|
||||||
|
}
|
||||||
|
@ -236,6 +236,9 @@ type ContainerNetworkConfig struct {
|
|||||||
// Will be appended to host's host file
|
// Will be appended to host's host file
|
||||||
HostAdd []string `json:"hostsAdd,omitempty"`
|
HostAdd []string `json:"hostsAdd,omitempty"`
|
||||||
// Network names (CNI) to add container to. Empty to use default network.
|
// Network names (CNI) to add container to. Empty to use default network.
|
||||||
|
// Please note that these can be altered at runtime. The actual list is
|
||||||
|
// stored in the DB and should be retrieved from there; this is only the
|
||||||
|
// set of networks the container was *created* with.
|
||||||
Networks []string `json:"networks,omitempty"`
|
Networks []string `json:"networks,omitempty"`
|
||||||
// Network mode specified for the default network.
|
// Network mode specified for the default network.
|
||||||
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
|
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
|
||||||
|
@ -641,12 +641,17 @@ func (c *Container) removeIPv4Allocations() error {
|
|||||||
cniDefaultNetwork = c.runtime.netPlugin.GetDefaultNetworkName()
|
cniDefaultNetwork = c.runtime.netPlugin.GetDefaultNetworkName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networks, err := c.networks()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case len(c.config.Networks) > 0 && len(c.config.Networks) != len(c.state.NetworkStatus):
|
case len(networks) > 0 && len(networks) != len(c.state.NetworkStatus):
|
||||||
return errors.Wrapf(define.ErrInternal, "network mismatch: asked to join %d CNI networks but got %d CNI results", len(c.config.Networks), len(c.state.NetworkStatus))
|
return errors.Wrapf(define.ErrInternal, "network mismatch: asked to join %d CNI networks but got %d CNI results", len(networks), len(c.state.NetworkStatus))
|
||||||
case len(c.config.Networks) == 0 && len(c.state.NetworkStatus) != 1:
|
case len(networks) == 0 && len(c.state.NetworkStatus) != 1:
|
||||||
return errors.Wrapf(define.ErrInternal, "network mismatch: did not specify CNI networks but joined more than one (%d)", len(c.state.NetworkStatus))
|
return errors.Wrapf(define.ErrInternal, "network mismatch: did not specify CNI networks but joined more than one (%d)", len(c.state.NetworkStatus))
|
||||||
case len(c.config.Networks) == 0 && cniDefaultNetwork == "":
|
case len(networks) == 0 && cniDefaultNetwork == "":
|
||||||
return errors.Wrapf(define.ErrInternal, "could not retrieve name of CNI default network")
|
return errors.Wrapf(define.ErrInternal, "could not retrieve name of CNI default network")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,11 +661,11 @@ func (c *Container) removeIPv4Allocations() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
candidate := ""
|
candidate := ""
|
||||||
if len(c.config.Networks) > 0 {
|
if len(networks) > 0 {
|
||||||
// CNI returns networks in order we passed them.
|
// CNI returns networks in order we passed them.
|
||||||
// So our index into results should be our index
|
// So our index into results should be our index
|
||||||
// into networks.
|
// into networks.
|
||||||
candidate = filepath.Join(cniNetworksDir, c.config.Networks[index], ctrIP.Address.IP.String())
|
candidate = filepath.Join(cniNetworksDir, networks[index], ctrIP.Address.IP.String())
|
||||||
} else {
|
} else {
|
||||||
candidate = filepath.Join(cniNetworksDir, cniDefaultNetwork, ctrIP.Address.IP.String())
|
candidate = filepath.Join(cniNetworksDir, cniDefaultNetwork, ctrIP.Address.IP.String())
|
||||||
}
|
}
|
||||||
|
@ -575,6 +575,8 @@ type InspectAdditionalNetwork struct {
|
|||||||
// Links is presently unused and maintained exclusively for
|
// Links is presently unused and maintained exclusively for
|
||||||
// compatibility.
|
// compatibility.
|
||||||
Links []string `json:"Links"`
|
Links []string `json:"Links"`
|
||||||
|
// Aliases are any network aliases the container has in this network.
|
||||||
|
Aliases []string `json:"Aliases,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InspectNetworkSettings holds information about the network settings of the
|
// InspectNetworkSettings holds information about the network settings of the
|
||||||
|
@ -33,9 +33,6 @@ var (
|
|||||||
// ErrNoAliases indicates that the container does not have any network
|
// ErrNoAliases indicates that the container does not have any network
|
||||||
// aliases.
|
// aliases.
|
||||||
ErrNoAliases = errors.New("no aliases for container")
|
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
|
||||||
@ -49,9 +46,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
|
// ErrNetworkExists indicates that a network with the given name already
|
||||||
// already exists in the network.
|
// exists.
|
||||||
ErrAliasExists = errors.New("alias already exists")
|
ErrNetworkExists = errors.New("network 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,8 +31,7 @@ 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
|
ctrNetworks map[string][]string
|
||||||
networkAliases map[string]map[string]string
|
|
||||||
// Maps container ID to network name to list of aliases.
|
// Maps container ID to network name to list of aliases.
|
||||||
ctrNetworkAliases map[string]map[string][]string
|
ctrNetworkAliases map[string]map[string][]string
|
||||||
// Global name registry - ensures name uniqueness and performs lookups.
|
// Global name registry - ensures name uniqueness and performs lookups.
|
||||||
@ -69,7 +68,7 @@ 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.ctrNetworks = make(map[string][]string)
|
||||||
state.ctrNetworkAliases = make(map[string]map[string][]string)
|
state.ctrNetworkAliases = make(map[string]map[string][]string)
|
||||||
|
|
||||||
state.nameIndex = registrar.NewRegistrar()
|
state.nameIndex = registrar.NewRegistrar()
|
||||||
@ -293,7 +292,7 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check network aliases
|
// Check network aliases
|
||||||
for network, aliases := range ctr.config.NetworkAliases {
|
for network := range ctr.config.NetworkAliases {
|
||||||
inNet := false
|
inNet := false
|
||||||
for _, net := range ctr.config.Networks {
|
for _, net := range ctr.config.Networks {
|
||||||
if net == network {
|
if net == network {
|
||||||
@ -304,19 +303,6 @@ func (s *InMemoryState) AddContainer(ctr *Container) error {
|
|||||||
if !inNet {
|
if !inNet {
|
||||||
return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network)
|
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
|
||||||
@ -375,46 +361,17 @@ 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 {
|
// Add networks
|
||||||
allNetAliases, ok := s.networkAliases[network]
|
newNets := make([]string, 0, len(ctr.config.Networks))
|
||||||
if !ok {
|
for _, net := range ctr.config.Networks {
|
||||||
continue
|
if net == "" {
|
||||||
|
return define.ErrInvalidArg
|
||||||
}
|
}
|
||||||
otherCtrID, ok := allNetAliases[ctr.Name()]
|
newNets = append(newNets, net)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
s.ctrNetworks[ctr.ID()] = newNets
|
||||||
|
|
||||||
// Add network aliases
|
// 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
|
s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -480,18 +437,12 @@ func (s *InMemoryState) RemoveContainer(ctr *Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove our network aliases
|
// Remove our network aliases
|
||||||
ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
|
if _, ok := s.ctrNetworkAliases[ctr.ID()]; ok {
|
||||||
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())
|
delete(s.ctrNetworkAliases, ctr.ID())
|
||||||
}
|
}
|
||||||
|
if _, ok := s.ctrNetworks[ctr.ID()]; ok {
|
||||||
|
delete(s.ctrNetworks, ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -569,6 +520,26 @@ func (s *InMemoryState) AllContainers() ([]*Container, error) {
|
|||||||
return ctrs, nil
|
return ctrs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get all networks this container is present in.
|
||||||
|
func (s *InMemoryState) GetNetworks(ctr *Container) ([]string, error) {
|
||||||
|
if !ctr.valid {
|
||||||
|
return nil, define.ErrCtrRemoved
|
||||||
|
}
|
||||||
|
|
||||||
|
ctr, ok := s.containers[ctr.ID()]
|
||||||
|
if !ok {
|
||||||
|
ctr.valid = false
|
||||||
|
return nil, define.ErrNoSuchCtr
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrNetworks, ok := s.ctrNetworks[ctr.ID()]
|
||||||
|
if !ok {
|
||||||
|
return nil, define.ErrNoSuchNetwork
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctrNetworks, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetNetworkAliases returns network aliases for the given container in the
|
// GetNetworkAliases returns network aliases for the given container in the
|
||||||
// given network.
|
// given network.
|
||||||
func (s *InMemoryState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
|
func (s *InMemoryState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
|
||||||
@ -582,6 +553,7 @@ func (s *InMemoryState) GetNetworkAliases(ctr *Container, network string) ([]str
|
|||||||
|
|
||||||
ctr, ok := s.containers[ctr.ID()]
|
ctr, ok := s.containers[ctr.ID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
ctr.valid = false
|
||||||
return nil, define.ErrNoSuchCtr
|
return nil, define.ErrNoSuchCtr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +587,7 @@ func (s *InMemoryState) GetAllNetworkAliases(ctr *Container) (map[string][]strin
|
|||||||
|
|
||||||
ctr, ok := s.containers[ctr.ID()]
|
ctr, ok := s.containers[ctr.ID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
ctr.valid = false
|
||||||
return nil, define.ErrNoSuchCtr
|
return nil, define.ErrNoSuchCtr
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,9 +599,8 @@ func (s *InMemoryState) GetAllNetworkAliases(ctr *Container) (map[string][]strin
|
|||||||
return ctrAliases, nil
|
return ctrAliases, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetNetworkAliases sets network aliases for the given container in the given
|
// NetworkConnect connects to the given network
|
||||||
// network.
|
func (s *InMemoryState) NetworkConnect(ctr *Container, network string, aliases []string) error {
|
||||||
func (s *InMemoryState) SetNetworkAliases(ctr *Container, network string, aliases []string) error {
|
|
||||||
if !ctr.valid {
|
if !ctr.valid {
|
||||||
return define.ErrCtrRemoved
|
return define.ErrCtrRemoved
|
||||||
}
|
}
|
||||||
@ -639,55 +611,37 @@ func (s *InMemoryState) SetNetworkAliases(ctr *Container, network string, aliase
|
|||||||
|
|
||||||
ctr, ok := s.containers[ctr.ID()]
|
ctr, ok := s.containers[ctr.ID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
ctr.valid = false
|
||||||
return define.ErrNoSuchCtr
|
return define.ErrNoSuchCtr
|
||||||
}
|
}
|
||||||
|
|
||||||
inNet := false
|
inNet := false
|
||||||
for _, net := range ctr.config.Networks {
|
ctrNetworks, ok := s.ctrNetworks[ctr.ID()]
|
||||||
|
if !ok {
|
||||||
|
return define.ErrNoSuchNetwork
|
||||||
|
}
|
||||||
|
for _, net := range ctrNetworks {
|
||||||
if net == network {
|
if net == network {
|
||||||
inNet = true
|
inNet = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !inNet {
|
if inNet {
|
||||||
return define.ErrInvalidArg
|
return define.ErrNoSuchNetwork
|
||||||
}
|
}
|
||||||
|
s.ctrNetworks[ctr.ID()] = append(ctrNetworks, network)
|
||||||
|
|
||||||
ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
|
ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
ctrAliases = make(map[string][]string)
|
ctrAliases = make(map[string][]string)
|
||||||
s.ctrNetworkAliases[ctr.ID()] = ctrAliases
|
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
|
ctrAliases[network] = aliases
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveNetworkAliases removes network aliases from the given container in the
|
// Disconnect from the given network and remove all aliases in it.
|
||||||
// given network.
|
func (s *InMemoryState) NetworkDisconnect(ctr *Container, network string) error {
|
||||||
func (s *InMemoryState) RemoveNetworkAliases(ctr *Container, network string) error {
|
|
||||||
if !ctr.valid {
|
if !ctr.valid {
|
||||||
return define.ErrCtrRemoved
|
return define.ErrCtrRemoved
|
||||||
}
|
}
|
||||||
@ -698,73 +652,36 @@ func (s *InMemoryState) RemoveNetworkAliases(ctr *Container, network string) err
|
|||||||
|
|
||||||
ctr, ok := s.containers[ctr.ID()]
|
ctr, ok := s.containers[ctr.ID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
ctr.valid = false
|
||||||
return define.ErrNoSuchCtr
|
return define.ErrNoSuchCtr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctrNetworks, ok := s.ctrNetworks[ctr.ID()]
|
||||||
|
if !ok {
|
||||||
|
return define.ErrNoSuchNetwork
|
||||||
|
}
|
||||||
inNet := false
|
inNet := false
|
||||||
for _, net := range ctr.config.Networks {
|
remainingNets := make([]string, 0, len(ctrNetworks))
|
||||||
|
for _, net := range ctrNetworks {
|
||||||
if net == network {
|
if net == network {
|
||||||
inNet = true
|
inNet = true
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
remainingNets = append(remainingNets, net)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !inNet {
|
if !inNet {
|
||||||
return define.ErrInvalidArg
|
return define.ErrNoSuchNetwork
|
||||||
}
|
}
|
||||||
|
s.ctrNetworks[ctr.ID()] = remainingNets
|
||||||
|
|
||||||
ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
|
ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
|
||||||
if !ok {
|
if !ok {
|
||||||
ctrAliases = make(map[string][]string)
|
ctrAliases = make(map[string][]string)
|
||||||
s.ctrNetworkAliases[ctr.ID()] = ctrAliases
|
s.ctrNetworkAliases[ctr.ID()] = ctrAliases
|
||||||
}
|
}
|
||||||
netAliases, ok := ctrAliases[network]
|
if _, ok := ctrAliases[network]; ok {
|
||||||
if !ok {
|
delete(ctrAliases, network)
|
||||||
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
|
return nil
|
||||||
@ -1422,7 +1339,7 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check network aliases
|
// Check network aliases
|
||||||
for network, aliases := range ctr.config.NetworkAliases {
|
for network := range ctr.config.NetworkAliases {
|
||||||
inNet := false
|
inNet := false
|
||||||
for _, net := range ctr.config.Networks {
|
for _, net := range ctr.config.Networks {
|
||||||
if net == network {
|
if net == network {
|
||||||
@ -1433,19 +1350,6 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
|
|||||||
if !inNet {
|
if !inNet {
|
||||||
return errors.Wrapf(define.ErrInvalidArg, "container %s has network aliases for network %q but is not joined to network", ctr.ID(), network)
|
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
|
||||||
@ -1525,46 +1429,17 @@ func (s *InMemoryState) AddContainerToPod(pod *Pod, ctr *Container) error {
|
|||||||
s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
|
s.addCtrToVolDependsMap(ctr.ID(), vol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, network := range ctr.config.Networks {
|
// Add networks
|
||||||
allNetAliases, ok := s.networkAliases[network]
|
newNets := make([]string, 0, len(ctr.config.Networks))
|
||||||
if !ok {
|
for _, net := range ctr.config.Networks {
|
||||||
continue
|
if net == "" {
|
||||||
|
return define.ErrInvalidArg
|
||||||
}
|
}
|
||||||
otherCtrID, ok := allNetAliases[ctr.Name()]
|
newNets = append(newNets, net)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
s.ctrNetworks[ctr.ID()] = newNets
|
||||||
|
|
||||||
// Add network aliases
|
// 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
|
s.ctrNetworkAliases[ctr.ID()] = ctr.config.NetworkAliases
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -1648,18 +1523,12 @@ func (s *InMemoryState) RemoveContainerFromPod(pod *Pod, ctr *Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove our network aliases
|
// Remove our network aliases
|
||||||
ctrAliases, ok := s.ctrNetworkAliases[ctr.ID()]
|
if _, ok := s.ctrNetworkAliases[ctr.ID()]; ok {
|
||||||
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())
|
delete(s.ctrNetworkAliases, ctr.ID())
|
||||||
}
|
}
|
||||||
|
if _, ok := s.ctrNetworks[ctr.ID()]; ok {
|
||||||
|
delete(s.ctrNetworks, ctr.ID())
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,11 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
|
|||||||
|
|
||||||
podName := getCNIPodName(ctr)
|
podName := getCNIPodName(ctr)
|
||||||
|
|
||||||
podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
networks, err := ctr.networks()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
||||||
aliases, err := ctr.runtime.state.GetAllNetworkAliases(ctr)
|
aliases, err := ctr.runtime.state.GetAllNetworkAliases(ctr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -209,7 +213,11 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
|
|||||||
if ctr.config.NetMode.IsSlirp4netns() {
|
if ctr.config.NetMode.IsSlirp4netns() {
|
||||||
return r.setupSlirp4netns(ctr)
|
return r.setupSlirp4netns(ctr)
|
||||||
}
|
}
|
||||||
if len(ctr.config.Networks) > 0 {
|
networks, err := ctr.networks()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(networks) > 0 {
|
||||||
// set up port forwarder for CNI-in-slirp4netns
|
// set up port forwarder for CNI-in-slirp4netns
|
||||||
netnsPath := ctr.state.NetNS.Path()
|
netnsPath := ctr.state.NetNS.Path()
|
||||||
// TODO: support slirp4netns port forwarder as well
|
// TODO: support slirp4netns port forwarder as well
|
||||||
@ -725,6 +733,11 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
|||||||
|
|
||||||
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
|
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
|
||||||
|
|
||||||
|
networks, err := ctr.networks()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// rootless containers do not use the CNI plugin directly
|
// rootless containers do not use the CNI plugin directly
|
||||||
if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
|
if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
|
||||||
var requestedIP net.IP
|
var requestedIP net.IP
|
||||||
@ -745,7 +758,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
|||||||
requestedMAC = ctr.config.StaticMAC
|
requestedMAC = ctr.config.StaticMAC
|
||||||
}
|
}
|
||||||
|
|
||||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
||||||
|
|
||||||
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
|
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
|
||||||
return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
|
return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
|
||||||
@ -753,7 +766,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CNI-in-slirp4netns
|
// CNI-in-slirp4netns
|
||||||
if rootless.IsRootless() && len(ctr.config.Networks) != 0 {
|
if rootless.IsRootless() && len(networks) != 0 {
|
||||||
if err := DeallocRootlessCNI(context.Background(), ctr); err != nil {
|
if err := DeallocRootlessCNI(context.Background(), ctr); err != nil {
|
||||||
return errors.Wrapf(err, "error tearing down CNI-in-slirp4netns for container %s", ctr.ID())
|
return errors.Wrapf(err, "error tearing down CNI-in-slirp4netns for container %s", ctr.ID())
|
||||||
}
|
}
|
||||||
@ -839,13 +852,18 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
|||||||
settings := new(define.InspectNetworkSettings)
|
settings := new(define.InspectNetworkSettings)
|
||||||
settings.Ports = makeInspectPortBindings(c.config.PortMappings)
|
settings.Ports = makeInspectPortBindings(c.config.PortMappings)
|
||||||
|
|
||||||
|
networks, err := c.networks()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// We can't do more if the network is down.
|
// We can't do more if the network is down.
|
||||||
if c.state.NetNS == nil {
|
if c.state.NetNS == nil {
|
||||||
// We still want to make dummy configurations for each CNI net
|
// We still want to make dummy configurations for each CNI net
|
||||||
// the container joined.
|
// the container joined.
|
||||||
if len(c.config.Networks) > 0 {
|
if len(networks) > 0 {
|
||||||
settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(c.config.Networks))
|
settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(networks))
|
||||||
for _, net := range c.config.Networks {
|
for _, net := range networks {
|
||||||
cniNet := new(define.InspectAdditionalNetwork)
|
cniNet := new(define.InspectAdditionalNetwork)
|
||||||
cniNet.NetworkID = net
|
cniNet.NetworkID = net
|
||||||
settings.Networks[net] = cniNet
|
settings.Networks[net] = cniNet
|
||||||
@ -864,16 +882,16 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we have CNI networks - handle that here
|
// If we have CNI networks - handle that here
|
||||||
if len(c.config.Networks) > 0 {
|
if len(networks) > 0 {
|
||||||
if len(c.config.Networks) != len(c.state.NetworkStatus) {
|
if len(networks) != len(c.state.NetworkStatus) {
|
||||||
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(c.config.Networks), len(c.state.NetworkStatus))
|
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(networks), len(c.state.NetworkStatus))
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.Networks = make(map[string]*define.InspectAdditionalNetwork)
|
settings.Networks = make(map[string]*define.InspectAdditionalNetwork)
|
||||||
|
|
||||||
// CNI results should be in the same order as the list of
|
// CNI results should be in the same order as the list of
|
||||||
// networks we pass into CNI.
|
// networks we pass into CNI.
|
||||||
for index, name := range c.config.Networks {
|
for index, name := range networks {
|
||||||
cniResult := c.state.NetworkStatus[index]
|
cniResult := c.state.NetworkStatus[index]
|
||||||
addedNet := new(define.InspectAdditionalNetwork)
|
addedNet := new(define.InspectAdditionalNetwork)
|
||||||
addedNet.NetworkID = name
|
addedNet.NetworkID = name
|
||||||
@ -882,6 +900,13 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aliases, err := c.runtime.state.GetNetworkAliases(c, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
addedNet.Aliases = aliases
|
||||||
|
|
||||||
addedNet.InspectBasicNetworkConfig = basicConfig
|
addedNet.InspectBasicNetworkConfig = basicConfig
|
||||||
|
|
||||||
settings.Networks[name] = addedNet
|
settings.Networks[name] = addedNet
|
||||||
|
@ -40,8 +40,12 @@ const (
|
|||||||
//
|
//
|
||||||
// AllocRootlessCNI does not lock c. c should be already locked.
|
// AllocRootlessCNI does not lock c. c should be already locked.
|
||||||
func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.Result, error) {
|
func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.Result, error) {
|
||||||
if len(c.config.Networks) == 0 {
|
networks, err := c.networks()
|
||||||
return nil, nil, errors.New("allocRootlessCNI shall not be called when len(c.config.Networks) == 0")
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if len(networks) == 0 {
|
||||||
|
return nil, nil, errors.New("rootless CNI networking requires that the container has joined at least one CNI network")
|
||||||
}
|
}
|
||||||
l, err := getRootlessCNIInfraLock(c.runtime)
|
l, err := getRootlessCNIInfraLock(c.runtime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -54,8 +58,8 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
k8sPodName := getCNIPodName(c) // passed to CNI as K8S_POD_NAME
|
k8sPodName := getCNIPodName(c) // passed to CNI as K8S_POD_NAME
|
||||||
cniResults := make([]*cnitypes.Result, len(c.config.Networks))
|
cniResults := make([]*cnitypes.Result, len(networks))
|
||||||
for i, nw := range c.config.Networks {
|
for i, nw := range networks {
|
||||||
cniRes, err := rootlessCNIInfraCallAlloc(infra, c.ID(), nw, k8sPodName)
|
cniRes, err := rootlessCNIInfraCallAlloc(infra, c.ID(), nw, k8sPodName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -77,8 +81,12 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.
|
|||||||
//
|
//
|
||||||
// DeallocRootlessCNI does not lock c. c should be already locked.
|
// DeallocRootlessCNI does not lock c. c should be already locked.
|
||||||
func DeallocRootlessCNI(ctx context.Context, c *Container) error {
|
func DeallocRootlessCNI(ctx context.Context, c *Container) error {
|
||||||
if len(c.config.Networks) == 0 {
|
networks, err := c.networks()
|
||||||
return errors.New("deallocRootlessCNI shall not be called when len(c.config.Networks) == 0")
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(networks) == 0 {
|
||||||
|
return errors.New("rootless CNI networking requires that the container has joined at least one CNI network")
|
||||||
}
|
}
|
||||||
l, err := getRootlessCNIInfraLock(c.runtime)
|
l, err := getRootlessCNIInfraLock(c.runtime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -91,7 +99,7 @@ func DeallocRootlessCNI(ctx context.Context, c *Container) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var errs *multierror.Error
|
var errs *multierror.Error
|
||||||
for _, nw := range c.config.Networks {
|
for _, nw := range networks {
|
||||||
err := rootlessCNIInfraCallDelloc(infra, c.ID(), nw)
|
err := rootlessCNIInfraCallDelloc(infra, c.ID(), nw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = multierror.Append(errs, err)
|
errs = multierror.Append(errs, err)
|
||||||
|
@ -98,20 +98,18 @@ type State interface {
|
|||||||
// returned.
|
// returned.
|
||||||
AllContainers() ([]*Container, error)
|
AllContainers() ([]*Container, error)
|
||||||
|
|
||||||
|
// Get networks the container is currently connected to.
|
||||||
|
GetNetworks(ctr *Container) ([]string, error)
|
||||||
// Get network aliases for the given container in the given network.
|
// Get network aliases for the given container in the given network.
|
||||||
GetNetworkAliases(ctr *Container, network string) ([]string, error)
|
GetNetworkAliases(ctr *Container, network string) ([]string, error)
|
||||||
// Get all network aliases for the given container.
|
// Get all network aliases for the given container.
|
||||||
GetAllNetworkAliases(ctr *Container) (map[string][]string, error)
|
GetAllNetworkAliases(ctr *Container) (map[string][]string, error)
|
||||||
// Set network aliases for the given container in the given network.
|
// Add the container to the given network, adding the given aliases
|
||||||
SetNetworkAliases(ctr *Container, network string, aliases []string) error
|
// (if present).
|
||||||
// Remove network aliases for the given container in the given network.
|
NetworkConnect(ctr *Container, network string, aliases []string) error
|
||||||
RemoveNetworkAliases(ctr *Container, network string) error
|
// Remove the container from the given network, removing all aliases for
|
||||||
// GetAllAliasesForNetwork returns all the aliases for a given
|
// the container in that network in the process.
|
||||||
// network. Returns a map of alias to container ID.
|
NetworkDisconnect(ctr *Container, network string) error
|
||||||
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)
|
||||||
|
@ -1345,224 +1345,6 @@ func TestAddContainerNetworkAliasesButNoMatchingNetwork(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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