mirror of
https://github.com/containers/podman.git
synced 2025-10-17 19:24:04 +08:00
network db rewrite: migrate existing settings
The new network db structure stores everything in the networks bucket. Previously some network settings were not written the the network bucket and only stored in the container config. Instead of the old format which used the container ID as value in the networks buckets we now use the PerNetworkoptions struct there. To migrate existing users we use the state.GetNetworks() function. If it fails to read the new format it will automatically migrate the old config format to the new one. This is allows a flawless migration path. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
@ -53,41 +53,6 @@ const (
|
||||
persistentCNIDir = "/var/lib/cni"
|
||||
)
|
||||
|
||||
// GetAllNetworkAliases returns all configured aliases for this container.
|
||||
// It also adds the container short ID as alias to match docker.
|
||||
func (c *Container) GetAllNetworkAliases() (map[string][]string, error) {
|
||||
allAliases, err := c.runtime.state.GetAllNetworkAliases(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get the all attached networks, we cannot use GetAllNetworkAliases()
|
||||
// since it returns nil if there are no aliases
|
||||
nets, _, err := c.networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// add container short ID as alias to match docker
|
||||
for _, net := range nets {
|
||||
allAliases[net] = append(allAliases[net], c.config.ID[:12])
|
||||
}
|
||||
return allAliases, nil
|
||||
}
|
||||
|
||||
// GetNetworkAliases returns configured aliases for this network.
|
||||
// It also adds the container short ID as alias to match docker.
|
||||
func (c *Container) GetNetworkAliases(netName string) ([]string, error) {
|
||||
aliases, err := c.runtime.state.GetNetworkAliases(c, netName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// add container short ID as alias to match docker
|
||||
aliases = append(aliases, c.config.ID[:12])
|
||||
return aliases, nil
|
||||
}
|
||||
|
||||
// convertPortMappings will remove the HostIP part from the ports when running inside podman machine.
|
||||
// This is need because a HostIP of 127.0.0.1 would now allow the gvproxy forwarder to reach to open ports.
|
||||
// For machine the HostIP must only be used by gvproxy and never in the VM.
|
||||
@ -104,53 +69,20 @@ func (c *Container) convertPortMappings() []types.PortMapping {
|
||||
return newPorts
|
||||
}
|
||||
|
||||
func (c *Container) getNetworkOptions() (types.NetworkOptions, error) {
|
||||
func (c *Container) getNetworkOptions(networkOpts map[string]types.PerNetworkOptions) (types.NetworkOptions, error) {
|
||||
opts := types.NetworkOptions{
|
||||
ContainerID: c.config.ID,
|
||||
ContainerName: getCNIPodName(c),
|
||||
}
|
||||
opts.PortMappings = c.convertPortMappings()
|
||||
networks, _, err := c.networks()
|
||||
if err != nil {
|
||||
return opts, err
|
||||
}
|
||||
aliases, err := c.GetAllNetworkAliases()
|
||||
if err != nil {
|
||||
return opts, err
|
||||
}
|
||||
|
||||
// If the container requested special network options use this instead of the config.
|
||||
// This is the case for container restore or network reload.
|
||||
if c.perNetworkOpts != nil {
|
||||
opts.Networks = c.perNetworkOpts
|
||||
return opts, nil
|
||||
} else {
|
||||
opts.Networks = networkOpts
|
||||
}
|
||||
|
||||
// Update container map of interface descriptions
|
||||
if err := c.setupNetworkDescriptions(networks); err != nil {
|
||||
return opts, err
|
||||
}
|
||||
|
||||
nets := make(map[string]types.PerNetworkOptions, len(networks))
|
||||
for i, network := range networks {
|
||||
eth, exists := c.state.NetInterfaceDescriptions.getInterfaceByName(network)
|
||||
if !exists {
|
||||
return opts, errors.Errorf("no network interface name for container %s on network %s", c.config.ID, network)
|
||||
}
|
||||
netOpts := types.PerNetworkOptions{
|
||||
InterfaceName: eth,
|
||||
Aliases: aliases[network],
|
||||
}
|
||||
// only set the static ip/mac on the first network
|
||||
if i == 0 {
|
||||
if c.config.StaticIP != nil {
|
||||
netOpts.StaticIPs = []net.IP{c.config.StaticIP}
|
||||
}
|
||||
netOpts.StaticMAC = c.config.StaticMAC
|
||||
}
|
||||
nets[network] = netOpts
|
||||
}
|
||||
opts.Networks = nets
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
@ -697,7 +629,7 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (status map[str
|
||||
if ctr.config.NetMode.IsSlirp4netns() {
|
||||
return nil, r.setupSlirp4netns(ctr, ctrNS)
|
||||
}
|
||||
networks, _, err := ctr.networks()
|
||||
networks, err := ctr.networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -707,7 +639,7 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (status map[str
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
netOpts, err := ctr.getNetworkOptions()
|
||||
netOpts, err := ctr.getNetworkOptions(networks)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -862,13 +794,13 @@ func (r *Runtime) teardownCNI(ctr *Container) error {
|
||||
|
||||
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
|
||||
|
||||
networks, _, err := ctr.networks()
|
||||
networks, err := ctr.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ctr.config.NetMode.IsSlirp4netns() && len(networks) > 0 {
|
||||
netOpts, err := ctr.getNetworkOptions()
|
||||
netOpts, err := ctr.getNetworkOptions(networks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -960,22 +892,17 @@ func (r *Runtime) reloadContainerNetwork(ctr *Container) (map[string]types.Statu
|
||||
}
|
||||
}
|
||||
|
||||
aliases, err := ctr.GetAllNetworkAliases()
|
||||
networkOpts, err := ctr.networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the same network settings as before..
|
||||
netStatus := ctr.getNetworkStatus()
|
||||
netOpts := make(map[string]types.PerNetworkOptions, len(netStatus))
|
||||
for network, status := range netStatus {
|
||||
perNetOpts := types.PerNetworkOptions{}
|
||||
for name, netInt := range status.Interfaces {
|
||||
perNetOpts = types.PerNetworkOptions{
|
||||
InterfaceName: name,
|
||||
Aliases: aliases[network],
|
||||
StaticMAC: netInt.MacAddress,
|
||||
}
|
||||
for network, perNetOpts := range networkOpts {
|
||||
for name, netInt := range netStatus[network].Interfaces {
|
||||
perNetOpts.InterfaceName = name
|
||||
perNetOpts.StaticMAC = netInt.MacAddress
|
||||
for _, netAddress := range netInt.Subnets {
|
||||
perNetOpts.StaticIPs = append(perNetOpts.StaticIPs, netAddress.IPNet.IP)
|
||||
}
|
||||
@ -983,16 +910,9 @@ func (r *Runtime) reloadContainerNetwork(ctr *Container) (map[string]types.Statu
|
||||
// For now just use the first interface to get the ips this should be good enough for most cases.
|
||||
break
|
||||
}
|
||||
if perNetOpts.InterfaceName == "" {
|
||||
eth, exists := ctr.state.NetInterfaceDescriptions.getInterfaceByName(network)
|
||||
if !exists {
|
||||
return nil, errors.Errorf("no network interface name for container %s on network %s", ctr.config.ID, network)
|
||||
}
|
||||
perNetOpts.InterfaceName = eth
|
||||
}
|
||||
netOpts[network] = perNetOpts
|
||||
networkOpts[network] = perNetOpts
|
||||
}
|
||||
ctr.perNetworkOpts = netOpts
|
||||
ctr.perNetworkOpts = networkOpts
|
||||
|
||||
return r.configureNetNS(ctr, ctr.state.NetNS)
|
||||
}
|
||||
@ -1049,7 +969,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
settings := new(define.InspectNetworkSettings)
|
||||
settings.Ports = makeInspectPortBindings(c.config.PortMappings, c.config.ExposedPorts)
|
||||
|
||||
networks, isDefault, err := c.networks()
|
||||
networks, err := c.networks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1060,14 +980,10 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
// the container joined.
|
||||
if len(networks) > 0 {
|
||||
settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(networks))
|
||||
for _, net := range networks {
|
||||
for net, opts := range networks {
|
||||
cniNet := new(define.InspectAdditionalNetwork)
|
||||
cniNet.NetworkID = net
|
||||
aliases, err := c.GetNetworkAliases(net)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cniNet.Aliases = aliases
|
||||
cniNet.Aliases = opts.Aliases
|
||||
settings.Networks[net] = cniNet
|
||||
}
|
||||
}
|
||||
@ -1092,7 +1008,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
|
||||
settings.Networks = make(map[string]*define.InspectAdditionalNetwork)
|
||||
|
||||
for _, name := range networks {
|
||||
for name, opts := range networks {
|
||||
result := netStatus[name]
|
||||
addedNet := new(define.InspectAdditionalNetwork)
|
||||
addedNet.NetworkID = name
|
||||
@ -1101,19 +1017,17 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
aliases, err := c.GetNetworkAliases(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedNet.Aliases = aliases
|
||||
addedNet.Aliases = opts.Aliases
|
||||
|
||||
addedNet.InspectBasicNetworkConfig = basicConfig
|
||||
|
||||
settings.Networks[name] = addedNet
|
||||
}
|
||||
|
||||
if !isDefault {
|
||||
// if not only the default network is connected we can return here
|
||||
// otherwise we have to populate the InspectBasicNetworkConfig settings
|
||||
_, isDefaultNet := networks[c.runtime.config.Network.DefaultNetwork]
|
||||
if !(len(networks) == 1 && isDefaultNet) {
|
||||
return settings, nil
|
||||
}
|
||||
}
|
||||
@ -1135,29 +1049,6 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// setupNetworkDescriptions adds networks and eth values to the container's
|
||||
// network descriptions
|
||||
func (c *Container) setupNetworkDescriptions(networks []string) error {
|
||||
// if the map is nil and we have networks
|
||||
if c.state.NetInterfaceDescriptions == nil && len(networks) > 0 {
|
||||
c.state.NetInterfaceDescriptions = make(ContainerNetworkDescriptions)
|
||||
}
|
||||
origLen := len(c.state.NetInterfaceDescriptions)
|
||||
for _, n := range networks {
|
||||
// if the network is not in the map, add it
|
||||
if _, exists := c.state.NetInterfaceDescriptions[n]; !exists {
|
||||
c.state.NetInterfaceDescriptions.add(n)
|
||||
}
|
||||
}
|
||||
// if the map changed, we need to save the container state
|
||||
if origLen != len(c.state.NetInterfaceDescriptions) {
|
||||
if err := c.save(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// resultToBasicNetworkConfig produces an InspectBasicNetworkConfig from a CNI
|
||||
// result
|
||||
func resultToBasicNetworkConfig(result types.StatusBlock) (define.InspectBasicNetworkConfig, error) {
|
||||
@ -1213,7 +1104,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
networks, err := c.networksByNameIndex()
|
||||
networks, err := c.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1254,14 +1145,8 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
|
||||
ContainerName: getCNIPodName(c),
|
||||
}
|
||||
opts.PortMappings = c.convertPortMappings()
|
||||
eth, exists := c.state.NetInterfaceDescriptions.getInterfaceByName(netName)
|
||||
if !exists {
|
||||
return errors.Errorf("no network interface name for container %s on network %s", c.config.ID, netName)
|
||||
}
|
||||
opts.Networks = map[string]types.PerNetworkOptions{
|
||||
netName: {
|
||||
InterfaceName: eth,
|
||||
},
|
||||
netName: networks[netName],
|
||||
}
|
||||
|
||||
if err := c.runtime.teardownNetwork(c.state.NetNS.Path(), opts); err != nil {
|
||||
@ -1294,7 +1179,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
networks, err := c.networksByNameIndex()
|
||||
networks, err := c.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1321,7 +1206,18 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
|
||||
return errors.Wrapf(define.ErrInvalidArg, "cannot set network aliases for network %q because dns is disabled", netName)
|
||||
}
|
||||
|
||||
if err := c.runtime.state.NetworkConnect(c, netName, aliases); err != nil {
|
||||
eth := getFreeInterfaceName(networks)
|
||||
if eth == "" {
|
||||
return errors.New("could not find free network interface name")
|
||||
}
|
||||
|
||||
perNetOpt := types.PerNetworkOptions{
|
||||
// always add the short id as alias to match docker
|
||||
Aliases: append(aliases, c.config.ID[:12]),
|
||||
InterfaceName: eth,
|
||||
}
|
||||
|
||||
if err := c.runtime.state.NetworkConnect(c, netName, perNetOpt); err != nil {
|
||||
return err
|
||||
}
|
||||
c.newNetworkEvent(events.NetworkConnect, netName)
|
||||
@ -1332,30 +1228,13 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
|
||||
return errors.Wrapf(define.ErrNoNetwork, "unable to connect %s to %s", nameOrID, netName)
|
||||
}
|
||||
|
||||
ctrNetworks, _, err := c.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update network descriptions
|
||||
if err := c.setupNetworkDescriptions(ctrNetworks); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := types.NetworkOptions{
|
||||
ContainerID: c.config.ID,
|
||||
ContainerName: getCNIPodName(c),
|
||||
}
|
||||
opts.PortMappings = c.convertPortMappings()
|
||||
eth, exists := c.state.NetInterfaceDescriptions.getInterfaceByName(netName)
|
||||
if !exists {
|
||||
return errors.Errorf("no network interface name for container %s on network %s", c.config.ID, netName)
|
||||
}
|
||||
aliases = append(aliases, c.config.ID[:12])
|
||||
opts.Networks = map[string]types.PerNetworkOptions{
|
||||
netName: {
|
||||
Aliases: aliases,
|
||||
InterfaceName: eth,
|
||||
},
|
||||
netName: perNetOpt,
|
||||
}
|
||||
|
||||
results, err := c.runtime.setUpNetwork(c.state.NetNS.Path(), opts)
|
||||
@ -1385,6 +1264,22 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// get a free interface name for a new network
|
||||
// return an empty string if no free name was found
|
||||
func getFreeInterfaceName(networks map[string]types.PerNetworkOptions) string {
|
||||
ifNames := make([]string, 0, len(networks))
|
||||
for _, opts := range networks {
|
||||
ifNames = append(ifNames, opts.InterfaceName)
|
||||
}
|
||||
for i := 0; i < 100000; i++ {
|
||||
ifName := fmt.Sprintf("eth%d", i)
|
||||
if !util.StringInSlice(ifName, ifNames) {
|
||||
return ifName
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// DisconnectContainerFromNetwork removes a container from its CNI network
|
||||
func (r *Runtime) DisconnectContainerFromNetwork(nameOrID, netName string, force bool) error {
|
||||
ctr, err := r.LookupContainer(nameOrID)
|
||||
|
Reference in New Issue
Block a user