network db: add new strucutre to container create

Make sure we create new containers in the db with the correct structure.
Also remove some unneeded code for alias handling. We no longer need this
functions.

The specgen format has not been changed for now.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2021-12-07 23:04:47 +01:00
parent 4e8ad039ce
commit 9ce6b64133
12 changed files with 131 additions and 321 deletions

View File

@ -1063,7 +1063,7 @@ func (s *BoltState) GetNetworks(ctr *Container) (map[string]types.PerNetworkOpti
return errors.Wrapf(err, "error creating networks bucket for container %s", ctr.ID())
}
// the container has no networks in the db lookup config and write to the db
networkList = ctr.config.Networks
networkList = ctr.config.NetworksDeprecated
// if there are no networks we have to add the default
if len(networkList) == 0 {
networkList = []string{ctr.runtime.config.Network.DefaultNetwork}
@ -1146,155 +1146,6 @@ func (s *BoltState) GetNetworks(ctr *Container) (map[string]types.PerNetworkOpti
return networks, nil
}
// GetNetworkAliases retrieves the network aliases for the given container in
// the given CNI network.
func (s *BoltState) GetNetworkAliases(ctr *Container, network string) ([]string, error) {
if !s.valid {
return nil, define.ErrDBClosed
}
if !ctr.valid {
return nil, define.ErrCtrRemoved
}
if network == "" {
return nil, errors.Wrapf(define.ErrInvalidArg, "network names must not be empty")
}
if s.namespace != "" && s.namespace != ctr.config.Namespace {
return nil, errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
}
ctrID := []byte(ctr.ID())
db, err := s.getDBCon()
if err != nil {
return nil, err
}
defer s.deferredCloseDBCon(db)
aliases := []string{}
err = db.View(func(tx *bolt.Tx) error {
ctrBucket, err := getCtrBucket(tx)
if err != nil {
return err
}
dbCtr := ctrBucket.Bucket(ctrID)
if dbCtr == nil {
ctr.valid = false
return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
}
ctrNetworkBkt := dbCtr.Bucket(networksBkt)
if ctrNetworkBkt == nil {
// No networks joined, so no aliases
return nil
}
inNetwork := ctrNetworkBkt.Get([]byte(network))
if inNetwork == nil {
return errors.Wrapf(define.ErrNoAliases, "container %s is not part of network %s, no aliases found", ctr.ID(), network)
}
ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
if ctrAliasesBkt == nil {
// No aliases
return nil
}
netAliasesBkt := ctrAliasesBkt.Bucket([]byte(network))
if netAliasesBkt == nil {
// No aliases for this specific network.
return nil
}
return netAliasesBkt.ForEach(func(alias, v []byte) error {
aliases = append(aliases, string(alias))
return nil
})
})
if err != nil {
return nil, err
}
return aliases, nil
}
// GetAllNetworkAliases retrieves the network aliases for the given container in
// all CNI networks.
func (s *BoltState) GetAllNetworkAliases(ctr *Container) (map[string][]string, error) {
if !s.valid {
return nil, define.ErrDBClosed
}
if !ctr.valid {
return nil, define.ErrCtrRemoved
}
if s.namespace != "" && s.namespace != ctr.config.Namespace {
return nil, errors.Wrapf(define.ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
}
ctrID := []byte(ctr.ID())
db, err := s.getDBCon()
if err != nil {
return nil, err
}
defer s.deferredCloseDBCon(db)
aliases := make(map[string][]string)
err = db.View(func(tx *bolt.Tx) error {
ctrBucket, err := getCtrBucket(tx)
if err != nil {
return err
}
dbCtr := ctrBucket.Bucket(ctrID)
if dbCtr == nil {
ctr.valid = false
return errors.Wrapf(define.ErrNoSuchCtr, "container %s does not exist in database", ctr.ID())
}
ctrAliasesBkt := dbCtr.Bucket(aliasesBkt)
if ctrAliasesBkt == nil {
// No aliases present
return nil
}
ctrNetworkBkt := dbCtr.Bucket(networksBkt)
if ctrNetworkBkt == nil {
// No networks joined, so no aliases
return nil
}
return ctrNetworkBkt.ForEach(func(network, v []byte) error {
netAliasesBkt := ctrAliasesBkt.Bucket(network)
if netAliasesBkt == nil {
return nil
}
netAliases := []string{}
_ = netAliasesBkt.ForEach(func(alias, v []byte) error {
netAliases = append(netAliases, string(alias))
return nil
})
aliases[string(network)] = netAliases
return nil
})
})
if err != nil {
return nil, err
}
return aliases, nil
}
// NetworkConnect adds the given container to the given network. If aliases are
// specified, those will be added to the given network.
func (s *BoltState) NetworkConnect(ctr *Container, network string, opts types.PerNetworkOptions) error {

View File

@ -563,6 +563,28 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
ctrNamespace = []byte(ctr.config.Namespace)
}
// make sure to marshal the network options before we get the db lock
networks := make(map[string][]byte, len(ctr.config.Networks))
for net, opts := range ctr.config.Networks {
// Check that we don't have any empty network names
if net == "" {
return errors.Wrapf(define.ErrInvalidArg, "network names cannot be an empty string")
}
if opts.InterfaceName == "" {
return errors.Wrapf(define.ErrInvalidArg, "network interface name cannot be an empty string")
}
// always add the short id as alias for docker compat
opts.Aliases = append(opts.Aliases, ctr.config.ID[:12])
optBytes, err := json.Marshal(opts)
if err != nil {
return errors.Wrapf(err, "error marshalling network options JSON for container %s", ctr.ID())
}
networks[net] = optBytes
}
// Set the original value to nil. We can safe some space by not storing it in the config
// since we store it in a different mutable bucket anyway.
ctr.config.Networks = nil
db, err := s.getDBCon()
if err != nil {
return err
@ -646,23 +668,6 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
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
for _, net := range ctr.config.Networks {
if net == "" {
return errors.Wrapf(define.ErrInvalidArg, "network names cannot be an empty string")
}
allNets[net] = true
}
// Each network we have aliases for, must exist in networks
for net := range ctr.config.NetworkAliases {
if !allNets[net] {
return errors.Wrapf(define.ErrNoSuchNetwork, "container %s has network aliases for network %q but is not part of that network", ctr.ID(), net)
}
}
// No overlapping containers
// Add the new container to the DB
if err := idsBucket.Put(ctrID, ctrName); err != nil {
@ -706,34 +711,17 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
return errors.Wrapf(err, "error adding container %s netns path to DB", ctr.ID())
}
}
if ctr.config.Networks != nil {
if len(networks) > 0 {
ctrNetworksBkt, err := newCtrBkt.CreateBucket(networksBkt)
if err != nil {
return errors.Wrapf(err, "error creating networks bucket for container %s", ctr.ID())
}
for _, network := range ctr.config.Networks {
if err := ctrNetworksBkt.Put([]byte(network), ctrID); err != nil {
for network, opts := range networks {
if err := ctrNetworksBkt.Put([]byte(network), opts); err != nil {
return errors.Wrapf(err, "error adding network %q to networks bucket for container %s", network, ctr.ID())
}
}
}
if ctr.config.NetworkAliases != nil {
ctrAliasesBkt, err := newCtrBkt.CreateBucket(aliasesBkt)
if err != nil {
return errors.Wrapf(err, "error creating network aliases bucket for container %s", ctr.ID())
}
for net, aliases := range ctr.config.NetworkAliases {
netAliasesBkt, err := ctrAliasesBkt.CreateBucket([]byte(net))
if err != nil {
return errors.Wrapf(err, "error creating network aliases bucket for network %q in container %s", net, ctr.ID())
}
for _, alias := range aliases {
if err := netAliasesBkt.Put([]byte(alias), ctrID); err != nil {
return errors.Wrapf(err, "error creating network alias %q in network %q for container %s", alias, net, ctr.ID())
}
}
}
}
if _, err := newCtrBkt.CreateBucket(dependenciesBkt); err != nil {
return errors.Wrapf(err, "error creating dependencies bucket for container %s", ctr.ID())

View File

@ -229,10 +229,12 @@ type ContainerNetworkConfig struct {
// StaticIP is a static IP to request for the container.
// This cannot be set unless CreateNetNS is set.
// If not set, the container will be dynamically assigned an IP by CNI.
// Deprecated: Do no use this anymore, this is only for DB backwards compat.
StaticIP net.IP `json:"staticIP"`
// StaticMAC is a static MAC to request for the container.
// This cannot be set unless CreateNetNS is set.
// If not set, the container will be dynamically assigned a MAC by CNI.
// Deprecated: Do no use this anymore, this is only for DB backwards compat.
StaticMAC types.HardwareAddr `json:"staticMAC"`
// PortMappings are the ports forwarded to the container's network
// namespace
@ -269,24 +271,24 @@ type ContainerNetworkConfig struct {
// Hosts to add in container
// Will be appended to host's host file
HostAdd []string `json:"hostsAdd,omitempty"`
// Network names (CNI) to add container to. Empty to use default network.
// Network names with the network specific options.
// Please note that these can be altered at runtime. The actual list is
// stored in the DB and should be retrieved from there via c.networks()
// this value is only used for container create.
// Added in podman 4.0, previously NetworksDeprecated was used. Make
// sure to not change the json tags.
Networks map[string]types.PerNetworkOptions `json:"newNetworks,omitempty"`
// Network names 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"`
// Deprecated: Do no use this anymore, this is only for DB backwards compat.
// Also note that we need to keep the old json tag to decode from DB correctly
NetworksDeprecated []string `json:"networks,omitempty"`
// Network mode specified for the default network.
NetMode namespaces.NetworkMode `json:"networkMode,omitempty"`
// NetworkOptions are additional options for each network
NetworkOptions map[string][]string `json:"network_options,omitempty"`
// NetworkAliases are aliases that will be added to each network.
// These are additional names that this container can be accessed as via
// DNS when the CNI dnsname plugin is in use.
// Please note that these can be altered at runtime. As such, the actual
// list is stored in the database and should be retrieved from there;
// this is only the set of aliases the container was *created with*.
// Formatted as map of network name to aliases. All network names must
// be present in the Networks list above.
NetworkAliases map[string][]string `json:"network_alises,omitempty"`
}
// ContainerImageConfig is an embedded sub-config providing image configuration

View File

@ -74,7 +74,7 @@ func (c *Container) validate() error {
// Cannot set static IP or MAC if joining >1 CNI network.
if len(c.config.Networks) > 1 && (c.config.StaticIP != nil || c.config.StaticMAC != nil) {
return errors.Wrapf(define.ErrInvalidArg, "cannot set static IP or MAC address if joining more than one CNI network")
return errors.Wrapf(define.ErrInvalidArg, "cannot set static IP or MAC address if joining more than one network")
}
// Using image resolv.conf conflicts with various DNS settings.
@ -115,17 +115,6 @@ func (c *Container) validate() error {
destinations[vol.Dest] = true
}
// Check that networks and network aliases match up.
ctrNets := make(map[string]bool)
for _, net := range c.config.Networks {
ctrNets[net] = true
}
for net := range c.config.NetworkAliases {
if _, ok := ctrNets[net]; !ok {
return errors.Wrapf(define.ErrNoSuchNetwork, "container tried to set network aliases for network %s but is not connected to the network", net)
}
}
// If User in the OCI spec is set, require that c.config.User is set for
// security reasons (a lot of our code relies on c.config.User).
if c.config.User == "" && (c.config.Spec.Process.User.UID != 0 || c.config.Spec.Process.User.GID != 0) {

View File

@ -204,7 +204,8 @@ type PerNetworkOptions struct {
Aliases []string `json:"aliases,omitempty"`
// StaticMac for this container. Optional.
StaticMAC HardwareAddr `json:"static_mac,omitempty"`
// InterfaceName for this container. Required.
// InterfaceName for this container. Required in the backend.
// Optional in the frontend. Will be filled with ethX (where X is a integer) when empty.
InterfaceName string `json:"interface_name"`
}

View File

@ -1058,7 +1058,7 @@ func WithDependencyCtrs(ctrs []*Container) CtrCreateOption {
// namespace with a minimal configuration.
// An optional array of port mappings can be provided.
// Conflicts with WithNetNSFrom().
func WithNetNS(portMappings []nettypes.PortMapping, exposedPorts map[uint16][]string, postConfigureNetNS bool, netmode string, networks []string) CtrCreateOption {
func WithNetNS(portMappings []nettypes.PortMapping, exposedPorts map[uint16][]string, postConfigureNetNS bool, netmode string, networks map[string]nettypes.PerNetworkOptions) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
@ -1076,23 +1076,6 @@ func WithNetNS(portMappings []nettypes.PortMapping, exposedPorts map[uint16][]st
}
}
// WithStaticIP indicates that the container should request a static IP from
// the CNI plugins.
// It cannot be set unless WithNetNS has already been passed.
// Further, it cannot be set if additional CNI networks to join have been
// specified.
func WithStaticIP(ip net.IP) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.StaticIP = ip
return nil
}
}
// WithNetworkOptions sets additional options for the networks.
func WithNetworkOptions(options map[string][]string) CtrCreateOption {
return func(ctr *Container) error {
@ -1106,23 +1089,6 @@ func WithNetworkOptions(options map[string][]string) CtrCreateOption {
}
}
// WithStaticMAC indicates that the container should request a static MAC from
// the CNI plugins.
// It cannot be set unless WithNetNS has already been passed.
// Further, it cannot be set if additional CNI networks to join have been
// specified.
func WithStaticMAC(mac nettypes.HardwareAddr) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.StaticMAC = mac
return nil
}
}
// WithLogDriver sets the log driver for the container
func WithLogDriver(driver string) CtrCreateOption {
return func(ctr *Container) error {
@ -1572,20 +1538,6 @@ func WithCreateWorkingDir() CtrCreateOption {
}
}
// WithNetworkAliases sets network aliases for the container.
// Accepts a map of network name to aliases.
func WithNetworkAliases(aliases map[string][]string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
ctr.config.NetworkAliases = aliases
return nil
}
}
// Volume Creation Options
// WithVolumeName sets the name of the volume.

View File

@ -637,9 +637,17 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
infraConfig.HostAdd = make([]string, 0, len(infra.config.HostAdd))
infraConfig.HostAdd = append(infraConfig.HostAdd, infra.config.HostAdd...)
}
if len(infra.config.ContainerNetworkConfig.Networks) > 0 {
infraConfig.Networks = make([]string, 0, len(infra.config.ContainerNetworkConfig.Networks))
infraConfig.Networks = append(infraConfig.Networks, infra.config.ContainerNetworkConfig.Networks...)
networks, err := infra.networks()
if err != nil {
return nil, err
}
netNames := make([]string, 0, len(networks))
for name := range networks {
netNames = append(netNames, name)
}
if len(netNames) > 0 {
infraConfig.Networks = netNames
}
infraConfig.NetworkOptions = infra.config.ContainerNetworkConfig.NetworkOptions
infraConfig.PortBindings = makeInspectPortBindings(infra.config.ContainerNetworkConfig.PortMappings, nil)

View File

@ -2,6 +2,7 @@ package libpod
import (
"context"
"fmt"
"os"
"path"
"path/filepath"
@ -13,10 +14,12 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/events"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/libpod/shutdown"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
"github.com/containers/storage/pkg/stringid"
"github.com/docker/go-units"
@ -230,39 +233,56 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Container, retErr error) {
// normalize the networks to names
// ocicni only knows about cni names so we have to make
// the db backend only knows about network names so we have to make
// sure we do not use ids internally
if len(ctr.config.Networks) > 0 {
netNames := make([]string, 0, len(ctr.config.Networks))
for _, nameOrID := range ctr.config.Networks {
normalizeNetworks := make(map[string]types.PerNetworkOptions, len(ctr.config.Networks))
// first get the already used interface names so we do not conflict
usedIfNames := make([]string, 0, len(ctr.config.Networks))
for _, opts := range ctr.config.Networks {
if opts.InterfaceName != "" {
// check that no name is assigned to more than network
if util.StringInSlice(opts.InterfaceName, usedIfNames) {
return nil, errors.Errorf("network interface name %q is already assigned to another network", opts.InterfaceName)
}
usedIfNames = append(usedIfNames, opts.InterfaceName)
}
}
i := 0
for nameOrID, opts := range ctr.config.Networks {
netName, err := r.normalizeNetworkName(nameOrID)
if err != nil {
return nil, err
}
netNames = append(netNames, netName)
}
ctr.config.Networks = netNames
}
if len(opts.Aliases) > 0 {
network, err := r.network.NetworkInspect(netName)
if err != nil {
return nil, err
}
if !network.DNSEnabled {
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot set network aliases for network %q because dns is disabled", netName)
}
}
// assign interface name if empty
if opts.InterfaceName == "" {
for i < 100000 {
ifName := fmt.Sprintf("eth%d", i)
if !util.StringInSlice(ifName, usedIfNames) {
opts.InterfaceName = ifName
usedIfNames = append(usedIfNames, ifName)
break
}
i++
}
// if still empty we did not find a free name
if opts.InterfaceName == "" {
return nil, errors.New("failed to find free network interface name")
}
}
// https://github.com/containers/podman/issues/11285
// normalize the networks aliases to use network names and never ids
if len(ctr.config.NetworkAliases) > 0 {
netAliases := make(map[string][]string, len(ctr.config.NetworkAliases))
for nameOrID, aliases := range ctr.config.NetworkAliases {
netName, err := r.normalizeNetworkName(nameOrID)
if err != nil {
return nil, err
}
network, err := r.network.NetworkInspect(netName)
if err != nil {
return nil, err
}
if !network.DNSEnabled {
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot set network aliases for network %q because dns is disabled", netName)
}
netAliases[netName] = aliases
normalizeNetworks[netName] = opts
}
ctr.config.NetworkAliases = netAliases
ctr.config.Networks = normalizeNetworks
}
// Validate the container

View File

@ -102,12 +102,7 @@ type State interface {
// Get networks the container is currently connected to.
GetNetworks(ctr *Container) (map[string]types.PerNetworkOptions, error)
// Get network aliases for the given container in the given network.
GetNetworkAliases(ctr *Container, network string) ([]string, error)
// Get all network aliases for the given container.
GetAllNetworkAliases(ctr *Container) (map[string][]string, error)
// Add the container to the given network, adding the given aliases
// (if present).
// Add the container to the given network with the given options
NetworkConnect(ctr *Container, network string, opts types.PerNetworkOptions) error
// Remove the container from the given network, removing all aliases for
// the container in that network in the process.

View File

@ -1299,21 +1299,9 @@ func TestAddContainerEmptyNetworkNameErrors(t *testing.T) {
testCtr, err := getTestCtr1(manager)
assert.NoError(t, err)
testCtr.config.Networks = []string{""}
err = state.AddContainer(testCtr)
assert.Error(t, err)
})
}
func TestAddContainerNetworkAliasesButNoMatchingNetwork(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
testCtr, err := getTestCtr1(manager)
assert.NoError(t, err)
testCtr.config.Networks = []string{"test1"}
testCtr.config.NetworkAliases = make(map[string][]string)
testCtr.config.NetworkAliases["test2"] = []string{"alias1"}
testCtr.config.Networks = map[string]types.PerNetworkOptions{
"": {},
}
err = state.AddContainer(testCtr)
assert.Error(t, err)

View File

@ -160,10 +160,6 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
options = append(options, opts...)
if len(s.Aliases) > 0 {
options = append(options, libpod.WithNetworkAliases(s.Aliases))
}
if containerType := s.InitContainerType; len(containerType) > 0 {
options = append(options, libpod.WithInitCtrType(containerType))
}

View File

@ -10,6 +10,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/rootless"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
@ -250,7 +251,7 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if s.NetNS.Value != "" {
val = fmt.Sprintf("slirp4netns:%s", s.NetNS.Value)
}
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, s.CNINetworks))
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, val, nil))
case specgen.Private:
fallthrough
case specgen.Bridge:
@ -258,7 +259,32 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if err != nil {
return nil, err
}
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, "bridge", s.CNINetworks))
if len(s.CNINetworks) == 0 {
rtConfig, err := rt.GetConfigNoCopy()
if err != nil {
return nil, err
}
s.CNINetworks = append(s.CNINetworks, rtConfig.Network.DefaultNetwork)
}
networks := make(map[string]types.PerNetworkOptions, len(s.CNINetworks))
for i, netName := range s.CNINetworks {
opts := types.PerNetworkOptions{}
opts.Aliases = s.Aliases[netName]
if i == 0 {
if s.StaticIP != nil {
opts.StaticIPs = append(opts.StaticIPs, *s.StaticIP)
}
if s.StaticIPv6 != nil {
opts.StaticIPs = append(opts.StaticIPs, *s.StaticIPv6)
}
if s.StaticMAC != nil {
opts.StaticMAC = *s.StaticMAC
}
}
networks[netName] = opts
}
toReturn = append(toReturn, libpod.WithNetNS(portMappings, expose, postConfigureNetNS, "bridge", networks))
}
if s.UseImageHosts {
@ -281,12 +307,6 @@ func namespaceOptions(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.
if len(s.DNSOptions) > 0 {
toReturn = append(toReturn, libpod.WithDNSOption(s.DNSOptions))
}
if s.StaticIP != nil {
toReturn = append(toReturn, libpod.WithStaticIP(*s.StaticIP))
}
if s.StaticMAC != nil {
toReturn = append(toReturn, libpod.WithStaticMAC(*s.StaticMAC))
}
if s.NetworkOptions != nil {
toReturn = append(toReturn, libpod.WithNetworkOptions(s.NetworkOptions))
}