mirror of
https://github.com/containers/podman.git
synced 2025-10-16 18:53:19 +08:00
Merge pull request #4451 from giuseppe/set-mac
podman: add support for specifying MAC
This commit is contained in:
3
Makefile
3
Makefile
@ -522,6 +522,9 @@ vendor:
|
||||
$(GO) mod vendor && \
|
||||
$(GO) mod verify
|
||||
|
||||
vendor-in-container:
|
||||
podman run --privileged --rm --env HOME=/root -v `pwd`:/src -w /src docker.io/library/golang:1.12 make vendor
|
||||
|
||||
.PHONY: \
|
||||
.gopathok \
|
||||
binaries \
|
||||
|
@ -467,14 +467,15 @@ type RestartValues struct {
|
||||
|
||||
type RestoreValues struct {
|
||||
PodmanCommand
|
||||
All bool
|
||||
Keep bool
|
||||
Latest bool
|
||||
TcpEstablished bool
|
||||
Import string
|
||||
Name string
|
||||
IgnoreRootfs bool
|
||||
IgnoreStaticIP bool
|
||||
All bool
|
||||
Keep bool
|
||||
Latest bool
|
||||
TcpEstablished bool
|
||||
Import string
|
||||
Name string
|
||||
IgnoreRootfs bool
|
||||
IgnoreStaticIP bool
|
||||
IgnoreStaticMAC bool
|
||||
}
|
||||
|
||||
type RmValues struct {
|
||||
|
@ -328,7 +328,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
|
||||
)
|
||||
createFlags.String(
|
||||
"mac-address", "",
|
||||
"Container MAC address (e.g. 92:d0:c6:0a:29:33), not currently supported",
|
||||
"Container MAC address (e.g. 92:d0:c6:0a:29:33)",
|
||||
)
|
||||
createFlags.StringP(
|
||||
"memory", "m", "",
|
||||
|
@ -47,6 +47,7 @@ func init() {
|
||||
flags.StringVarP(&restoreCommand.Name, "name", "n", "", "Specify new name for container restored from exported checkpoint (only works with --import)")
|
||||
flags.BoolVar(&restoreCommand.IgnoreRootfs, "ignore-rootfs", false, "Do not apply root file-system changes when importing from exported checkpoint")
|
||||
flags.BoolVar(&restoreCommand.IgnoreStaticIP, "ignore-static-ip", false, "Ignore IP address set via --static-ip")
|
||||
flags.BoolVar(&restoreCommand.IgnoreStaticMAC, "ignore-static-mac", false, "Ignore MAC address set via --mac-address")
|
||||
|
||||
markFlagHiddenForRemoteClient("latest", flags)
|
||||
}
|
||||
|
@ -336,10 +336,6 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.String("mac-address") != "" {
|
||||
return nil, errors.Errorf("--mac-address option not currently supported")
|
||||
}
|
||||
|
||||
imageID := ""
|
||||
|
||||
inputCommand = c.InputArgs[1:]
|
||||
|
@ -33,6 +33,9 @@
|
||||
{
|
||||
"type": "firewall",
|
||||
"backend": "iptables"
|
||||
},
|
||||
{
|
||||
"type": "tuning"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -877,6 +877,7 @@ _podman_container_restore() {
|
||||
--tcp-established
|
||||
--ignore-rootfs
|
||||
--ignore-static-ip
|
||||
--ignore-static-mac
|
||||
"
|
||||
case "$prev" in
|
||||
-i|--import)
|
||||
|
@ -76,6 +76,15 @@ a container is restored multiple times from an exported checkpoint with **--name
|
||||
Using **--ignore-static-ip** tells Podman to ignore the IP address if it was configured
|
||||
with **--ip** during container creation.
|
||||
|
||||
**--ignore-static-mac**
|
||||
|
||||
If the container was started with **--mac-address** the restored container also
|
||||
tries to use that MAC address and restore fails if that MAC address is already
|
||||
in use. This can happen, if a container is restored multiple times from an
|
||||
exported checkpoint with **--name, -n**.
|
||||
|
||||
Using **--ignore-static-mac** tells Podman to ignore the MAC address if it was
|
||||
configured with **--mac-address** during container creation.
|
||||
## EXAMPLE
|
||||
|
||||
podman container restore mywebserver
|
||||
|
4
go.mod
4
go.mod
@ -9,7 +9,7 @@ require (
|
||||
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
|
||||
github.com/containernetworking/cni v0.7.1
|
||||
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784
|
||||
github.com/containernetworking/plugins v0.8.2
|
||||
github.com/containers/buildah v1.11.5-0.20191031204705-20e92ffe0982
|
||||
github.com/containers/image/v5 v5.0.0
|
||||
@ -17,7 +17,7 @@ require (
|
||||
github.com/containers/storage v1.13.5
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
|
||||
github.com/cri-o/ocicni v0.1.1-0.20190702175919-7762645d18ca
|
||||
github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b
|
||||
github.com/cyphar/filepath-securejoin v0.2.2
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/docker/distribution v2.7.1+incompatible
|
||||
|
4
go.sum
4
go.sum
@ -53,6 +53,8 @@ github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL
|
||||
github.com/containernetworking/cni v0.7.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE=
|
||||
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784 h1:rqUVLD8I859xRgUx/WMC3v7QAFqbLKZbs+0kqYboRJc=
|
||||
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/plugins v0.8.2 h1:5lnwfsAYO+V7yXhysJKy3E1A2Gy9oVut031zfdOzI9w=
|
||||
github.com/containernetworking/plugins v0.8.2/go.mod h1:TxALKWZpWL79BC3GOYKJzzXr7U8R23PdhwaLp6F3adc=
|
||||
github.com/containers/buildah v1.11.4-0.20191028173731-21b4778b359e h1:iDavHEx5Yr7o+0l6495Ya6N0YEPplIUZuWC2e14baDM=
|
||||
@ -83,6 +85,8 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cri-o/ocicni v0.1.1-0.20190702175919-7762645d18ca h1:CJstDqYy9ClWuPcDHMTCAiUS+ckekluYetGR2iYYWuo=
|
||||
github.com/cri-o/ocicni v0.1.1-0.20190702175919-7762645d18ca/go.mod h1:BO0al9TKber3XUTucLzKgoG5sq8qiOB41H7zSdfw6r8=
|
||||
github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b h1:SgS+WV10y2Bubuy2HquSBori6DXj9sqRN77Hgs5H7Qc=
|
||||
github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b/go.mod h1:ZOuIEOp/3MB1eCBWANnNxM3zUA3NWh76wSRCsnKAg2c=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||
|
@ -138,6 +138,10 @@ type Container struct {
|
||||
// being checkpointed. If requestedIP is set it will be used instead
|
||||
// of config.StaticIP.
|
||||
requestedIP net.IP
|
||||
// A restored container should have the same MAC address as before
|
||||
// being checkpointed. If requestedMAC is set it will be used instead
|
||||
// of config.StaticMAC.
|
||||
requestedMAC net.HardwareAddr
|
||||
|
||||
// This is true if a container is restored from a checkpoint.
|
||||
restoreFromCheckpoint bool
|
||||
@ -296,6 +300,10 @@ type ContainerConfig struct {
|
||||
// This cannot be set unless CreateNetNS is set.
|
||||
// If not set, the container will be dynamically assigned an IP by CNI.
|
||||
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.
|
||||
StaticMAC net.HardwareAddr `json:"staticMAC"`
|
||||
// PortMappings are the ports forwarded to the container's network
|
||||
// namespace
|
||||
// These are not used unless CreateNetNS is true
|
||||
|
@ -794,6 +794,11 @@ type ContainerCheckpointOptions struct {
|
||||
// important to be able to restore a container multiple
|
||||
// times with '--import --name'.
|
||||
IgnoreStaticIP bool
|
||||
// IgnoreStaticMAC tells the API to ignore the MAC set
|
||||
// during 'podman run' with '--mac-address'. This is especially
|
||||
// important to be able to restore a container multiple
|
||||
// times with '--import --name'.
|
||||
IgnoreStaticMAC bool
|
||||
}
|
||||
|
||||
// Checkpoint checkpoints a container
|
||||
|
@ -794,6 +794,15 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
|
||||
c.config.StaticIP = nil
|
||||
}
|
||||
|
||||
// If a container is restored multiple times from an exported checkpoint with
|
||||
// the help of '--import --name', the restore will fail if during 'podman run'
|
||||
// a static container MAC address was set with '--mac-address'. The user
|
||||
// can tell the restore process to ignore the static MAC with
|
||||
// '--ignore-static-mac'
|
||||
if options.IgnoreStaticMAC {
|
||||
c.config.StaticMAC = nil
|
||||
}
|
||||
|
||||
// Read network configuration from checkpoint
|
||||
// Currently only one interface with one IP is supported.
|
||||
networkStatusFile, err := os.Open(filepath.Join(c.bundlePath(), "network.status"))
|
||||
@ -803,9 +812,9 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
|
||||
// TODO: This implicit restoring with or without IP depending on an
|
||||
// unrelated restore parameter (--name) does not seem like the
|
||||
// best solution.
|
||||
if err == nil && options.Name == "" && !options.IgnoreStaticIP {
|
||||
if err == nil && options.Name == "" && (!options.IgnoreStaticIP || !options.IgnoreStaticMAC) {
|
||||
// The file with the network.status does exist. Let's restore the
|
||||
// container with the same IP address as during checkpointing.
|
||||
// container with the same IP address / MAC address as during checkpointing.
|
||||
defer networkStatusFile.Close()
|
||||
var networkStatus []*cnitypes.Result
|
||||
networkJSON, err := ioutil.ReadAll(networkStatusFile)
|
||||
@ -815,16 +824,35 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
|
||||
if err := json.Unmarshal(networkJSON, &networkStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
// Take the first IP address
|
||||
var IP net.IP
|
||||
if len(networkStatus) > 0 {
|
||||
if len(networkStatus[0].IPs) > 0 {
|
||||
IP = networkStatus[0].IPs[0].Address.IP
|
||||
if !options.IgnoreStaticIP {
|
||||
// Take the first IP address
|
||||
var IP net.IP
|
||||
if len(networkStatus) > 0 {
|
||||
if len(networkStatus[0].IPs) > 0 {
|
||||
IP = networkStatus[0].IPs[0].Address.IP
|
||||
}
|
||||
}
|
||||
if IP != nil {
|
||||
// Tell CNI which IP address we want.
|
||||
c.requestedIP = IP
|
||||
}
|
||||
}
|
||||
if IP != nil {
|
||||
// Tell CNI which IP address we want.
|
||||
c.requestedIP = IP
|
||||
if !options.IgnoreStaticMAC {
|
||||
// Take the first device with a defined sandbox.
|
||||
var MAC net.HardwareAddr
|
||||
for _, n := range networkStatus[0].Interfaces {
|
||||
if n.Sandbox != "" {
|
||||
MAC, err = net.ParseMAC(n.Mac)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse MAC %v", n.Mac)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if MAC != nil {
|
||||
// Tell CNI which MAC address we want.
|
||||
c.requestedMAC = MAC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1314,7 +1342,7 @@ func (c *Container) copyOwnerAndPerms(source, dest string) error {
|
||||
// Teardown CNI config on refresh
|
||||
func (c *Container) refreshCNI() error {
|
||||
// Let's try and delete any lingering network config...
|
||||
podNetwork := c.runtime.getPodNetwork(c.ID(), c.config.Name, "", c.config.Networks, c.config.PortMappings, c.config.StaticIP)
|
||||
podNetwork := c.runtime.getPodNetwork(c.ID(), c.config.Name, "", c.config.Networks, c.config.PortMappings, c.config.StaticIP, c.config.StaticMAC)
|
||||
return c.runtime.netPlugin.TearDownPod(podNetwork)
|
||||
}
|
||||
|
||||
|
@ -28,23 +28,34 @@ import (
|
||||
)
|
||||
|
||||
// Get an OCICNI network config
|
||||
func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping, staticIP net.IP) ocicni.PodNetwork {
|
||||
func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping, staticIP net.IP, staticMAC net.HardwareAddr) ocicni.PodNetwork {
|
||||
defaultNetwork := r.netPlugin.GetDefaultNetworkName()
|
||||
network := ocicni.PodNetwork{
|
||||
Name: name,
|
||||
Namespace: name, // TODO is there something else we should put here? We don't know about Kube namespaces
|
||||
ID: id,
|
||||
NetNS: nsPath,
|
||||
Networks: networks,
|
||||
RuntimeConfig: map[string]ocicni.RuntimeConfig{
|
||||
defaultNetwork: {PortMappings: ports},
|
||||
},
|
||||
}
|
||||
|
||||
if staticIP != nil {
|
||||
network.Networks = []string{defaultNetwork}
|
||||
if staticIP != nil || staticMAC != nil {
|
||||
network.Networks = []ocicni.NetAttachment{{Name: defaultNetwork}}
|
||||
var rt ocicni.RuntimeConfig = ocicni.RuntimeConfig{PortMappings: ports}
|
||||
if staticIP != nil {
|
||||
rt.IP = staticIP.String()
|
||||
}
|
||||
if staticMAC != nil {
|
||||
rt.MAC = staticMAC.String()
|
||||
}
|
||||
network.RuntimeConfig = map[string]ocicni.RuntimeConfig{
|
||||
defaultNetwork: {IP: staticIP.String(), PortMappings: ports},
|
||||
defaultNetwork: rt,
|
||||
}
|
||||
} else {
|
||||
network.Networks = make([]ocicni.NetAttachment, len(networks))
|
||||
for i, netName := range networks {
|
||||
network.Networks[i].Name = netName
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +73,16 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
|
||||
requestedIP = ctr.config.StaticIP
|
||||
}
|
||||
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
|
||||
var requestedMAC net.HardwareAddr
|
||||
if ctr.requestedMAC != nil {
|
||||
requestedMAC = ctr.requestedMAC
|
||||
// cancel request for a specific MAC in case the container is reused later
|
||||
ctr.requestedMAC = nil
|
||||
} else {
|
||||
requestedMAC = ctr.config.StaticMAC
|
||||
}
|
||||
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
||||
|
||||
results, err := r.netPlugin.SetUpPod(podNetwork)
|
||||
if err != nil {
|
||||
@ -78,10 +98,10 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
|
||||
|
||||
networkStatus := make([]*cnitypes.Result, 0)
|
||||
for idx, r := range results {
|
||||
logrus.Debugf("[%d] CNI result: %v", idx, r.String())
|
||||
resultCurrent, err := cnitypes.GetResult(r)
|
||||
logrus.Debugf("[%d] CNI result: %v", idx, r.Result.String())
|
||||
resultCurrent, err := cnitypes.GetResult(r.Result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error parsing CNI plugin result %q: %v", r.String(), err)
|
||||
return nil, errors.Wrapf(err, "error parsing CNI plugin result %q: %v", r.Result.String(), err)
|
||||
}
|
||||
networkStatus = append(networkStatus, resultCurrent)
|
||||
}
|
||||
@ -443,7 +463,16 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
||||
requestedIP = ctr.config.StaticIP
|
||||
}
|
||||
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
|
||||
var requestedMAC net.HardwareAddr
|
||||
if ctr.requestedMAC != nil {
|
||||
requestedMAC = ctr.requestedMAC
|
||||
// cancel request for a specific MAC in case the container is reused later
|
||||
ctr.requestedMAC = nil
|
||||
} else {
|
||||
requestedMAC = ctr.config.StaticMAC
|
||||
}
|
||||
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
||||
|
||||
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
|
||||
return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
|
||||
|
@ -1052,6 +1052,31 @@ func WithStaticIP(ip net.IP) 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 net.HardwareAddr) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
if ctr.valid {
|
||||
return define.ErrCtrFinalized
|
||||
}
|
||||
|
||||
if !ctr.config.CreateNetNS {
|
||||
return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if the container is not creating a network namespace")
|
||||
}
|
||||
|
||||
if len(ctr.config.Networks) != 0 {
|
||||
return errors.Wrapf(define.ErrInvalidArg, "cannot set a static MAC if joining additional CNI networks")
|
||||
}
|
||||
|
||||
ctr.config.StaticMAC = mac
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogDriver sets the log driver for the container
|
||||
func WithLogDriver(driver string) CtrCreateOption {
|
||||
return func(ctr *Container) error {
|
||||
|
@ -538,12 +538,13 @@ func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues)
|
||||
)
|
||||
|
||||
options := libpod.ContainerCheckpointOptions{
|
||||
Keep: c.Keep,
|
||||
TCPEstablished: c.TcpEstablished,
|
||||
TargetFile: c.Import,
|
||||
Name: c.Name,
|
||||
IgnoreRootfs: c.IgnoreRootfs,
|
||||
IgnoreStaticIP: c.IgnoreStaticIP,
|
||||
Keep: c.Keep,
|
||||
TCPEstablished: c.TcpEstablished,
|
||||
TargetFile: c.Import,
|
||||
Name: c.Name,
|
||||
IgnoreRootfs: c.IgnoreRootfs,
|
||||
IgnoreStaticIP: c.IgnoreStaticIP,
|
||||
IgnoreStaticMAC: c.IgnoreStaticMAC,
|
||||
}
|
||||
|
||||
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
|
||||
|
@ -396,6 +396,14 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
||||
options = append(options, libpod.WithStaticIP(ip))
|
||||
}
|
||||
|
||||
if c.MacAddress != "" {
|
||||
mac, err := net.ParseMAC(c.MacAddress)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(define.ErrInvalidArg, "cannot parse %s as MAC address: %v", c.MacAddress, err)
|
||||
}
|
||||
options = append(options, libpod.WithStaticMAC(mac))
|
||||
}
|
||||
|
||||
options = append(options, libpod.WithPrivileged(c.Privileged))
|
||||
|
||||
useImageVolumes := c.ImageVolumeType == TypeBind
|
||||
|
@ -334,6 +334,10 @@ var _ = Describe("Podman checkpoint", func() {
|
||||
IPBefore.WaitWithDefaultTimeout()
|
||||
Expect(IPBefore.ExitCode()).To(Equal(0))
|
||||
|
||||
MACBefore := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.MacAddress}}"})
|
||||
MACBefore.WaitWithDefaultTimeout()
|
||||
Expect(MACBefore.ExitCode()).To(Equal(0))
|
||||
|
||||
result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
|
||||
@ -348,9 +352,16 @@ var _ = Describe("Podman checkpoint", func() {
|
||||
IPAfter.WaitWithDefaultTimeout()
|
||||
Expect(IPAfter.ExitCode()).To(Equal(0))
|
||||
|
||||
MACAfter := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.MacAddress}}"})
|
||||
MACAfter.WaitWithDefaultTimeout()
|
||||
Expect(MACAfter.ExitCode()).To(Equal(0))
|
||||
|
||||
// Check that IP address did not change between checkpointing and restoring
|
||||
Expect(IPBefore.OutputToString()).To(Equal(IPAfter.OutputToString()))
|
||||
|
||||
// Check that MAC address did not change between checkpointing and restoring
|
||||
Expect(MACBefore.OutputToString()).To(Equal(MACAfter.OutputToString()))
|
||||
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
|
||||
Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
|
||||
|
46
test/e2e/create_staticmac_test.go
Normal file
46
test/e2e/create_staticmac_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
// +build !remoteclient
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
. "github.com/containers/libpod/test/utils"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Podman run with --mac-address flag", func() {
|
||||
var (
|
||||
tempdir string
|
||||
err error
|
||||
podmanTest *PodmanTestIntegration
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
SkipIfRootless()
|
||||
tempdir, err = CreateTempDirInTempDir()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
podmanTest = PodmanTestCreate(tempdir)
|
||||
podmanTest.Setup()
|
||||
podmanTest.SeedImages()
|
||||
// Cleanup the CNI networks used by the tests
|
||||
os.RemoveAll("/var/lib/cni/networks/podman")
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
podmanTest.Cleanup()
|
||||
f := CurrentGinkgoTestDescription()
|
||||
processTestResult(f)
|
||||
|
||||
})
|
||||
|
||||
It("Podman run --mac-address", func() {
|
||||
result := podmanTest.Podman([]string{"run", "--mac-address", "92:d0:c6:0a:29:34", ALPINE, "ip", "addr"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result.ExitCode()).To(Equal(0))
|
||||
Expect(result.OutputToString()).To(ContainSubstring("92:d0:c6:0a:29:34"))
|
||||
})
|
||||
})
|
232
vendor/github.com/containernetworking/cni/libcni/api.go
generated
vendored
232
vendor/github.com/containernetworking/cni/libcni/api.go
generated
vendored
@ -25,6 +25,7 @@ import (
|
||||
|
||||
"github.com/containernetworking/cni/pkg/invoke"
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/containernetworking/cni/pkg/utils"
|
||||
"github.com/containernetworking/cni/pkg/version"
|
||||
)
|
||||
|
||||
@ -32,6 +33,10 @@ var (
|
||||
CacheDir = "/var/lib/cni"
|
||||
)
|
||||
|
||||
const (
|
||||
CNICacheV1 = "cniCacheV1"
|
||||
)
|
||||
|
||||
// A RuntimeConf holds the arguments to one invocation of a CNI plugin
|
||||
// excepting the network configuration, with the nested exception that
|
||||
// the `runtimeConfig` from the network configuration is included
|
||||
@ -48,7 +53,7 @@ type RuntimeConf struct {
|
||||
// to the plugin
|
||||
CapabilityArgs map[string]interface{}
|
||||
|
||||
// A cache directory in which to library data. Defaults to CacheDir
|
||||
// DEPRECATED. Will be removed in a future release.
|
||||
CacheDir string
|
||||
}
|
||||
|
||||
@ -70,19 +75,22 @@ type CNI interface {
|
||||
CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
|
||||
DelNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
|
||||
GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
|
||||
GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
|
||||
|
||||
AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
||||
CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
|
||||
DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
|
||||
GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
|
||||
GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
|
||||
|
||||
ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error)
|
||||
ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)
|
||||
}
|
||||
|
||||
type CNIConfig struct {
|
||||
Path []string
|
||||
exec invoke.Exec
|
||||
Path []string
|
||||
exec invoke.Exec
|
||||
cacheDir string
|
||||
}
|
||||
|
||||
// CNIConfig implements the CNI interface
|
||||
@ -92,9 +100,18 @@ var _ CNI = &CNIConfig{}
|
||||
// in the given paths and use the given exec interface to run those plugins,
|
||||
// or if the exec interface is not given, will use a default exec handler.
|
||||
func NewCNIConfig(path []string, exec invoke.Exec) *CNIConfig {
|
||||
return NewCNIConfigWithCacheDir(path, "", exec)
|
||||
}
|
||||
|
||||
// NewCNIConfigWithCacheDir returns a new CNIConfig object that will search for plugins
|
||||
// in the given paths use the given exec interface to run those plugins,
|
||||
// or if the exec interface is not given, will use a default exec handler.
|
||||
// The given cache directory will be used for temporary data storage when needed.
|
||||
func NewCNIConfigWithCacheDir(path []string, cacheDir string, exec invoke.Exec) *CNIConfig {
|
||||
return &CNIConfig{
|
||||
Path: path,
|
||||
exec: exec,
|
||||
Path: path,
|
||||
cacheDir: cacheDir,
|
||||
exec: exec,
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,33 +182,122 @@ func (c *CNIConfig) ensureExec() invoke.Exec {
|
||||
return c.exec
|
||||
}
|
||||
|
||||
func getResultCacheFilePath(netName string, rt *RuntimeConf) string {
|
||||
cacheDir := rt.CacheDir
|
||||
if cacheDir == "" {
|
||||
cacheDir = CacheDir
|
||||
}
|
||||
return filepath.Join(cacheDir, "results", fmt.Sprintf("%s-%s-%s", netName, rt.ContainerID, rt.IfName))
|
||||
type cachedInfo struct {
|
||||
Kind string `json:"kind"`
|
||||
ContainerID string `json:"containerId"`
|
||||
Config []byte `json:"config"`
|
||||
IfName string `json:"ifName"`
|
||||
NetworkName string `json:"networkName"`
|
||||
CniArgs [][2]string `json:"cniArgs,omitempty"`
|
||||
CapabilityArgs map[string]interface{} `json:"capabilityArgs,omitempty"`
|
||||
RawResult map[string]interface{} `json:"result,omitempty"`
|
||||
Result types.Result `json:"-"`
|
||||
}
|
||||
|
||||
func setCachedResult(result types.Result, netName string, rt *RuntimeConf) error {
|
||||
// getCacheDir returns the cache directory in this order:
|
||||
// 1) global cacheDir from CNIConfig object
|
||||
// 2) deprecated cacheDir from RuntimeConf object
|
||||
// 3) fall back to default cache directory
|
||||
func (c *CNIConfig) getCacheDir(rt *RuntimeConf) string {
|
||||
if c.cacheDir != "" {
|
||||
return c.cacheDir
|
||||
}
|
||||
if rt.CacheDir != "" {
|
||||
return rt.CacheDir
|
||||
}
|
||||
return CacheDir
|
||||
}
|
||||
|
||||
func (c *CNIConfig) getCacheFilePath(netName string, rt *RuntimeConf) (string, error) {
|
||||
if netName == "" || rt.ContainerID == "" || rt.IfName == "" {
|
||||
return "", fmt.Errorf("cache file path requires network name (%q), container ID (%q), and interface name (%q)", netName, rt.ContainerID, rt.IfName)
|
||||
}
|
||||
return filepath.Join(c.getCacheDir(rt), "results", fmt.Sprintf("%s-%s-%s", netName, rt.ContainerID, rt.IfName)), nil
|
||||
}
|
||||
|
||||
func (c *CNIConfig) cacheAdd(result types.Result, config []byte, netName string, rt *RuntimeConf) error {
|
||||
cached := cachedInfo{
|
||||
Kind: CNICacheV1,
|
||||
ContainerID: rt.ContainerID,
|
||||
Config: config,
|
||||
IfName: rt.IfName,
|
||||
NetworkName: netName,
|
||||
CniArgs: rt.Args,
|
||||
CapabilityArgs: rt.CapabilityArgs,
|
||||
}
|
||||
|
||||
// We need to get type.Result into cachedInfo as JSON map
|
||||
// Marshal to []byte, then Unmarshal into cached.RawResult
|
||||
data, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fname := getResultCacheFilePath(netName, rt)
|
||||
|
||||
err = json.Unmarshal(data, &cached.RawResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newBytes, err := json.Marshal(&cached)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fname, err := c.getCacheFilePath(netName, rt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(fname, data, 0600)
|
||||
|
||||
return ioutil.WriteFile(fname, newBytes, 0600)
|
||||
}
|
||||
|
||||
func delCachedResult(netName string, rt *RuntimeConf) error {
|
||||
fname := getResultCacheFilePath(netName, rt)
|
||||
func (c *CNIConfig) cacheDel(netName string, rt *RuntimeConf) error {
|
||||
fname, err := c.getCacheFilePath(netName, rt)
|
||||
if err != nil {
|
||||
// Ignore error
|
||||
return nil
|
||||
}
|
||||
return os.Remove(fname)
|
||||
}
|
||||
|
||||
func getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
|
||||
fname := getResultCacheFilePath(netName, rt)
|
||||
func (c *CNIConfig) getCachedConfig(netName string, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||
var bytes []byte
|
||||
|
||||
fname, err := c.getCacheFilePath(netName, rt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
bytes, err = ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
// Ignore read errors; the cached result may not exist on-disk
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
unmarshaled := cachedInfo{}
|
||||
if err := json.Unmarshal(bytes, &unmarshaled); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to unmarshal cached network %q config: %v", netName, err)
|
||||
}
|
||||
if unmarshaled.Kind != CNICacheV1 {
|
||||
return nil, nil, fmt.Errorf("read cached network %q config has wrong kind: %v", netName, unmarshaled.Kind)
|
||||
}
|
||||
|
||||
newRt := *rt
|
||||
if unmarshaled.CniArgs != nil {
|
||||
newRt.Args = unmarshaled.CniArgs
|
||||
}
|
||||
newRt.CapabilityArgs = unmarshaled.CapabilityArgs
|
||||
|
||||
return unmarshaled.Config, &newRt, nil
|
||||
}
|
||||
|
||||
func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
|
||||
fname, err := c.getCacheFilePath(netName, rt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
// Ignore read errors; the cached result may not exist on-disk
|
||||
@ -222,16 +328,73 @@ func getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result,
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
|
||||
fname, err := c.getCacheFilePath(netName, rt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fdata, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
// Ignore read errors; the cached result may not exist on-disk
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cachedInfo := cachedInfo{}
|
||||
if err := json.Unmarshal(fdata, &cachedInfo); err != nil || cachedInfo.Kind != CNICacheV1 {
|
||||
return c.getLegacyCachedResult(netName, cniVersion, rt)
|
||||
}
|
||||
|
||||
newBytes, err := json.Marshal(&cachedInfo.RawResult)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal cached network %q config: %v", netName, err)
|
||||
}
|
||||
|
||||
// Read the version of the cached result
|
||||
decoder := version.ConfigDecoder{}
|
||||
resultCniVersion, err := decoder.Decode(newBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure we can understand the result
|
||||
result, err := version.NewResult(resultCniVersion, newBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert to the config version to ensure plugins get prevResult
|
||||
// in the same version as the config. The cached result version
|
||||
// should match the config version unless the config was changed
|
||||
// while the container was running.
|
||||
result, err = result.GetAsVersion(cniVersion)
|
||||
if err != nil && resultCniVersion != cniVersion {
|
||||
return nil, fmt.Errorf("failed to convert cached result version %q to config version %q: %v", resultCniVersion, cniVersion, err)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
// GetNetworkListCachedResult returns the cached Result of the previous
|
||||
// previous AddNetworkList() operation for a network list, or an error.
|
||||
// AddNetworkList() operation for a network list, or an error.
|
||||
func (c *CNIConfig) GetNetworkListCachedResult(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
|
||||
return getCachedResult(list.Name, list.CNIVersion, rt)
|
||||
return c.getCachedResult(list.Name, list.CNIVersion, rt)
|
||||
}
|
||||
|
||||
// GetNetworkCachedResult returns the cached Result of the previous
|
||||
// previous AddNetwork() operation for a network, or an error.
|
||||
// AddNetwork() operation for a network, or an error.
|
||||
func (c *CNIConfig) GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
|
||||
return getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||
return c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||
}
|
||||
|
||||
// GetNetworkListCachedConfig copies the input RuntimeConf to output
|
||||
// RuntimeConf with fields updated with info from the cached Config.
|
||||
func (c *CNIConfig) GetNetworkListCachedConfig(list *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||
return c.getCachedConfig(list.Name, rt)
|
||||
}
|
||||
|
||||
// GetNetworkCachedConfig copies the input RuntimeConf to output
|
||||
// RuntimeConf with fields updated with info from the cached Config.
|
||||
func (c *CNIConfig) GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
|
||||
return c.getCachedConfig(net.Network.Name, rt)
|
||||
}
|
||||
|
||||
func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
|
||||
@ -240,6 +403,12 @@ func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := utils.ValidateContainerID(rt.ContainerID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := utils.ValidateNetworkName(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
|
||||
if err != nil {
|
||||
@ -260,7 +429,7 @@ func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList,
|
||||
}
|
||||
}
|
||||
|
||||
if err = setCachedResult(result, list.Name, rt); err != nil {
|
||||
if err = c.cacheAdd(result, list.Bytes, list.Name, rt); err != nil {
|
||||
return nil, fmt.Errorf("failed to set network %q cached result: %v", list.Name, err)
|
||||
}
|
||||
|
||||
@ -295,7 +464,7 @@ func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigLis
|
||||
return nil
|
||||
}
|
||||
|
||||
cachedResult, err := getCachedResult(list.Name, list.CNIVersion, rt)
|
||||
cachedResult, err := c.getCachedResult(list.Name, list.CNIVersion, rt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err)
|
||||
}
|
||||
@ -332,7 +501,7 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
|
||||
if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil {
|
||||
return err
|
||||
} else if gtet {
|
||||
cachedResult, err = getCachedResult(list.Name, list.CNIVersion, rt)
|
||||
cachedResult, err = c.getCachedResult(list.Name, list.CNIVersion, rt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err)
|
||||
}
|
||||
@ -344,7 +513,7 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
|
||||
return err
|
||||
}
|
||||
}
|
||||
_ = delCachedResult(list.Name, rt)
|
||||
_ = c.cacheDel(list.Name, rt)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -356,7 +525,7 @@ func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = setCachedResult(result, net.Network.Name, rt); err != nil {
|
||||
if err = c.cacheAdd(result, net.Bytes, net.Network.Name, rt); err != nil {
|
||||
return nil, fmt.Errorf("failed to set network %q cached result: %v", net.Network.Name, err)
|
||||
}
|
||||
|
||||
@ -372,7 +541,7 @@ func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *Ru
|
||||
return fmt.Errorf("configuration version %q does not support the CHECK command", net.Network.CNIVersion)
|
||||
}
|
||||
|
||||
cachedResult, err := getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||
cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err)
|
||||
}
|
||||
@ -387,7 +556,7 @@ func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
|
||||
if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil {
|
||||
return err
|
||||
} else if gtet {
|
||||
cachedResult, err = getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||
cachedResult, err = c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err)
|
||||
}
|
||||
@ -396,7 +565,7 @@ func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
|
||||
if err := c.delNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = delCachedResult(net.Network.Name, rt)
|
||||
_ = c.cacheDel(net.Network.Name, rt)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -455,7 +624,8 @@ func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]
|
||||
|
||||
// validatePlugin checks that an individual plugin's configuration is sane
|
||||
func (c *CNIConfig) validatePlugin(ctx context.Context, pluginName, expectedVersion string) error {
|
||||
pluginPath, err := invoke.FindInPath(pluginName, c.Path)
|
||||
c.ensureExec()
|
||||
pluginPath, err := c.exec.FindInPath(pluginName, c.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
4
vendor/github.com/containernetworking/cni/libcni/conf.go
generated
vendored
4
vendor/github.com/containernetworking/cni/libcni/conf.go
generated
vendored
@ -114,11 +114,11 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
|
||||
for i, conf := range plugins {
|
||||
newBytes, err := json.Marshal(conf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal plugin config %d: %v", i, err)
|
||||
return nil, fmt.Errorf("failed to marshal plugin config %d: %v", i, err)
|
||||
}
|
||||
netConf, err := ConfFromBytes(newBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse plugin config %d: %v", i, err)
|
||||
return nil, fmt.Errorf("failed to parse plugin config %d: %v", i, err)
|
||||
}
|
||||
list.Plugins = append(list.Plugins, netConf)
|
||||
}
|
||||
|
2
vendor/github.com/containernetworking/cni/pkg/invoke/args.go
generated
vendored
2
vendor/github.com/containernetworking/cni/pkg/invoke/args.go
generated
vendored
@ -32,7 +32,7 @@ type inherited struct{}
|
||||
|
||||
var inheritArgsFromEnv inherited
|
||||
|
||||
func (_ *inherited) AsEnv() []string {
|
||||
func (*inherited) AsEnv() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/containernetworking/cni/pkg/types/args.go
generated
vendored
2
vendor/github.com/containernetworking/cni/pkg/types/args.go
generated
vendored
@ -36,7 +36,7 @@ func (b *UnmarshallableBool) UnmarshalText(data []byte) error {
|
||||
case "0", "false":
|
||||
*b = false
|
||||
default:
|
||||
return fmt.Errorf("Boolean unmarshal error: invalid input %s", s)
|
||||
return fmt.Errorf("boolean unmarshal error: invalid input %s", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
25
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
25
vendor/github.com/containernetworking/cni/pkg/types/types.go
generated
vendored
@ -16,7 +16,6 @@ package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@ -134,9 +133,16 @@ func (r *Route) String() string {
|
||||
// Well known error codes
|
||||
// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
|
||||
const (
|
||||
ErrUnknown uint = iota // 0
|
||||
ErrIncompatibleCNIVersion // 1
|
||||
ErrUnsupportedField // 2
|
||||
ErrUnknown uint = iota // 0
|
||||
ErrIncompatibleCNIVersion // 1
|
||||
ErrUnsupportedField // 2
|
||||
ErrUnknownContainer // 3
|
||||
ErrInvalidEnvironmentVariables // 4
|
||||
ErrIOFailure // 5
|
||||
ErrDecodingFailure // 6
|
||||
ErrInvalidNetworkConfig // 7
|
||||
ErrTryAgainLater uint = 11
|
||||
ErrInternal uint = 999
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
@ -145,6 +151,14 @@ type Error struct {
|
||||
Details string `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
func NewError(code uint, msg, details string) *Error {
|
||||
return &Error{
|
||||
Code: code,
|
||||
Msg: msg,
|
||||
Details: details,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
details := ""
|
||||
if e.Details != "" {
|
||||
@ -194,6 +208,3 @@ func prettyPrint(obj interface{}) error {
|
||||
_, err = os.Stdout.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// NotImplementedError is used to indicate that a method is not implemented for the given platform
|
||||
var NotImplementedError = errors.New("Not Implemented")
|
||||
|
51
vendor/github.com/containernetworking/cni/pkg/utils/utils.go
generated
vendored
Normal file
51
vendor/github.com/containernetworking/cni/pkg/utils/utils.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2019 CNI authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
)
|
||||
|
||||
// cniValidNameChars is the regexp used to validate valid characters in
|
||||
// containerID and networkName
|
||||
const cniValidNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.\-]`
|
||||
|
||||
var cniReg = regexp.MustCompile(`^` + cniValidNameChars + `*$`)
|
||||
|
||||
// ValidateContainerID will validate that the supplied containerID is not empty does not contain invalid characters
|
||||
func ValidateContainerID(containerID string) *types.Error {
|
||||
|
||||
if containerID == "" {
|
||||
return types.NewError(types.ErrUnknownContainer, "missing containerID", "")
|
||||
}
|
||||
if !cniReg.MatchString(containerID) {
|
||||
return types.NewError(types.ErrInvalidEnvironmentVariables, "invalid characters in containerID", containerID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateNetworkName will validate that the supplied networkName does not contain invalid characters
|
||||
func ValidateNetworkName(networkName string) *types.Error {
|
||||
|
||||
if networkName == "" {
|
||||
return types.NewError(types.ErrInvalidNetworkConfig, "missing network name:", "")
|
||||
}
|
||||
if !cniReg.MatchString(networkName) {
|
||||
return types.NewError(types.ErrInvalidNetworkConfig, "invalid characters found in network name", networkName)
|
||||
}
|
||||
return nil
|
||||
}
|
411
vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
generated
vendored
411
vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
generated
vendored
@ -2,11 +2,14 @@ package ocicni
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -21,10 +24,11 @@ import (
|
||||
)
|
||||
|
||||
type cniNetworkPlugin struct {
|
||||
cniConfig *libcni.CNIConfig
|
||||
loNetwork *cniNetwork
|
||||
|
||||
sync.RWMutex
|
||||
defaultNetName string
|
||||
defaultNetName netName
|
||||
networks map[string]*cniNetwork
|
||||
|
||||
nsManager *nsManager
|
||||
@ -47,11 +51,15 @@ type cniNetworkPlugin struct {
|
||||
cacheDir string
|
||||
}
|
||||
|
||||
type netName struct {
|
||||
name string
|
||||
changeable bool
|
||||
}
|
||||
|
||||
type cniNetwork struct {
|
||||
name string
|
||||
filePath string
|
||||
NetworkConfig *libcni.NetworkConfigList
|
||||
CNIConfig *libcni.CNIConfig
|
||||
name string
|
||||
filePath string
|
||||
config *libcni.NetworkConfigList
|
||||
}
|
||||
|
||||
var errMissingDefaultNetwork = errors.New("Missing CNI default network")
|
||||
@ -186,6 +194,8 @@ func (plugin *cniNetworkPlugin) monitorConfDir(start *sync.WaitGroup) {
|
||||
// If defaultNetName is not empty, a CNI config with that network name will
|
||||
// be used as the default CNI network, and container network operations will
|
||||
// fail until that network config is present and valid.
|
||||
// If defaultNetName is empty, CNI config files should be reloaded real-time and
|
||||
// defaultNetName should be changeable and determined by file sorting.
|
||||
func InitCNI(defaultNetName string, confDir string, binDirs ...string) (CNIPlugin, error) {
|
||||
return initCNI(nil, "", defaultNetName, confDir, binDirs...)
|
||||
}
|
||||
@ -198,17 +208,24 @@ func initCNI(exec cniinvoke.Exec, cacheDir, defaultNetName string, confDir strin
|
||||
if len(binDirs) == 0 {
|
||||
binDirs = []string{DefaultBinDir}
|
||||
}
|
||||
|
||||
plugin := &cniNetworkPlugin{
|
||||
defaultNetName: defaultNetName,
|
||||
networks: make(map[string]*cniNetwork),
|
||||
loNetwork: getLoNetwork(exec, binDirs),
|
||||
confDir: confDir,
|
||||
binDirs: binDirs,
|
||||
shutdownChan: make(chan struct{}),
|
||||
done: &sync.WaitGroup{},
|
||||
pods: make(map[string]*podLock),
|
||||
exec: exec,
|
||||
cacheDir: cacheDir,
|
||||
cniConfig: libcni.NewCNIConfig(binDirs, exec),
|
||||
defaultNetName: netName{
|
||||
name: defaultNetName,
|
||||
// If defaultNetName is not assigned in initialization,
|
||||
// it should be changeable
|
||||
changeable: defaultNetName == "",
|
||||
},
|
||||
networks: make(map[string]*cniNetwork),
|
||||
loNetwork: getLoNetwork(),
|
||||
confDir: confDir,
|
||||
binDirs: binDirs,
|
||||
shutdownChan: make(chan struct{}),
|
||||
done: &sync.WaitGroup{},
|
||||
pods: make(map[string]*podLock),
|
||||
exec: exec,
|
||||
cacheDir: cacheDir,
|
||||
}
|
||||
|
||||
if exec == nil {
|
||||
@ -246,7 +263,7 @@ func (plugin *cniNetworkPlugin) Shutdown() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadNetworks(exec cniinvoke.Exec, confDir string, binDirs []string) (map[string]*cniNetwork, string, error) {
|
||||
func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork, string, error) {
|
||||
files, err := libcni.ConfFiles(confDir, []string{".conf", ".conflist", ".json"})
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
@ -284,17 +301,30 @@ func loadNetworks(exec cniinvoke.Exec, confDir string, binDirs []string) (map[st
|
||||
logrus.Warningf("CNI config list %s has no networks, skipping", confFile)
|
||||
continue
|
||||
}
|
||||
|
||||
// Validation on CNI config should be done to pre-check presence
|
||||
// of plugins which are necessary.
|
||||
if _, err := cni.ValidateNetworkList(context.TODO(), confList); err != nil {
|
||||
logrus.Warningf("Error validating CNI config file %s: %v", confFile, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if confList.Name == "" {
|
||||
confList.Name = path.Base(confFile)
|
||||
}
|
||||
|
||||
cniNet := &cniNetwork{
|
||||
name: confList.Name,
|
||||
filePath: confFile,
|
||||
config: confList,
|
||||
}
|
||||
|
||||
logrus.Infof("Found CNI network %s (type=%v) at %s", confList.Name, confList.Plugins[0].Network.Type, confFile)
|
||||
|
||||
networks[confList.Name] = &cniNetwork{
|
||||
name: confList.Name,
|
||||
filePath: confFile,
|
||||
NetworkConfig: confList,
|
||||
CNIConfig: libcni.NewCNIConfig(binDirs, exec),
|
||||
if _, ok := networks[confList.Name]; !ok {
|
||||
networks[confList.Name] = cniNet
|
||||
} else {
|
||||
logrus.Infof("Ignore CNI network %s (type=%v) at %s because already exists", confList.Name, confList.Plugins[0].Network.Type, confFile)
|
||||
}
|
||||
|
||||
if defaultNetName == "" {
|
||||
@ -305,39 +335,49 @@ func loadNetworks(exec cniinvoke.Exec, confDir string, binDirs []string) (map[st
|
||||
return networks, defaultNetName, nil
|
||||
}
|
||||
|
||||
func getLoNetwork(exec cniinvoke.Exec, binDirs []string) *cniNetwork {
|
||||
loConfig, err := libcni.ConfListFromBytes([]byte(`{
|
||||
"cniVersion": "0.2.0",
|
||||
"name": "cni-loopback",
|
||||
const (
|
||||
loIfname string = "lo"
|
||||
loNetname string = "cni-loopback"
|
||||
)
|
||||
|
||||
func getLoNetwork() *cniNetwork {
|
||||
loConfig, err := libcni.ConfListFromBytes([]byte(fmt.Sprintf(`{
|
||||
"cniVersion": "0.3.1",
|
||||
"name": "%s",
|
||||
"plugins": [{
|
||||
"type": "loopback"
|
||||
}]
|
||||
}`))
|
||||
}`, loNetname)))
|
||||
if err != nil {
|
||||
// The hardcoded config above should always be valid and unit tests will
|
||||
// catch this
|
||||
panic(err)
|
||||
}
|
||||
loNetwork := &cniNetwork{
|
||||
name: "lo",
|
||||
NetworkConfig: loConfig,
|
||||
CNIConfig: libcni.NewCNIConfig(binDirs, exec),
|
||||
name: loIfname,
|
||||
config: loConfig,
|
||||
}
|
||||
|
||||
return loNetwork
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) syncNetworkConfig() error {
|
||||
networks, defaultNetName, err := loadNetworks(plugin.exec, plugin.confDir, plugin.binDirs)
|
||||
networks, defaultNetName, err := loadNetworks(plugin.confDir, plugin.cniConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
plugin.Lock()
|
||||
defer plugin.Unlock()
|
||||
if plugin.defaultNetName == "" {
|
||||
plugin.defaultNetName = defaultNetName
|
||||
|
||||
// Update defaultNetName if it is changeable
|
||||
if plugin.defaultNetName.changeable {
|
||||
plugin.defaultNetName.name = defaultNetName
|
||||
logrus.Infof("Update default CNI network name to %s", defaultNetName)
|
||||
} else {
|
||||
logrus.Warnf("Default CNI network name %s is unchangeable", plugin.defaultNetName.name)
|
||||
}
|
||||
|
||||
plugin.networks = networks
|
||||
|
||||
return nil
|
||||
@ -356,7 +396,7 @@ func (plugin *cniNetworkPlugin) getNetwork(name string) (*cniNetwork, error) {
|
||||
func (plugin *cniNetworkPlugin) GetDefaultNetworkName() string {
|
||||
plugin.RLock()
|
||||
defer plugin.RUnlock()
|
||||
return plugin.defaultNetName
|
||||
return plugin.defaultNetName.name
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) getDefaultNetwork() *cniNetwork {
|
||||
@ -382,27 +422,120 @@ func (plugin *cniNetworkPlugin) Name() string {
|
||||
return CNIPluginName
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, forEachFunc func(*cniNetwork, string, *PodNetwork, RuntimeConfig) error) error {
|
||||
func (plugin *cniNetworkPlugin) loadNetworkFromCache(name string, rt *libcni.RuntimeConf) (*cniNetwork, *libcni.RuntimeConf, error) {
|
||||
cniNet := &cniNetwork{
|
||||
name: name,
|
||||
config: &libcni.NetworkConfigList{
|
||||
Name: name,
|
||||
},
|
||||
}
|
||||
|
||||
var confBytes []byte
|
||||
var err error
|
||||
confBytes, rt, err = plugin.cniConfig.GetNetworkListCachedConfig(cniNet.config, rt)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if confBytes == nil {
|
||||
return nil, nil, fmt.Errorf("network %q not found in CNI cache", name)
|
||||
}
|
||||
|
||||
cniNet.config, err = libcni.ConfListFromBytes(confBytes)
|
||||
if err != nil {
|
||||
// Might be a plain NetworkConfig
|
||||
netConf, err := libcni.ConfFromBytes(confBytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Up-convert to a NetworkConfigList
|
||||
cniNet.config, err = libcni.ConfListFromConf(netConf)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return cniNet, rt, nil
|
||||
}
|
||||
|
||||
type forEachNetworkFn func(*cniNetwork, *PodNetwork, *libcni.RuntimeConf) error
|
||||
|
||||
func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, fromCache bool, actionFn forEachNetworkFn) error {
|
||||
networks := podNetwork.Networks
|
||||
if len(networks) == 0 {
|
||||
networks = append(networks, plugin.GetDefaultNetworkName())
|
||||
networks = append(networks, NetAttachment{
|
||||
Name: plugin.GetDefaultNetworkName(),
|
||||
})
|
||||
}
|
||||
for i, netName := range networks {
|
||||
// Interface names start at "eth0" and count up for each network
|
||||
ifName := fmt.Sprintf("eth%d", i)
|
||||
network, err := plugin.getNetwork(netName)
|
||||
|
||||
allIfNames := make(map[string]bool)
|
||||
for _, req := range networks {
|
||||
if req.Ifname != "" {
|
||||
// Make sure the requested name isn't already assigned
|
||||
if allIfNames[req.Ifname] {
|
||||
return fmt.Errorf("network %q requested interface name %q already assigned", req.Name, req.Ifname)
|
||||
}
|
||||
allIfNames[req.Ifname] = true
|
||||
}
|
||||
}
|
||||
|
||||
for _, network := range networks {
|
||||
ifName := network.Ifname
|
||||
if ifName == "" {
|
||||
for i := 0; i < 10000; i++ {
|
||||
candidate := fmt.Sprintf("eth%d", i)
|
||||
if !allIfNames[candidate] {
|
||||
allIfNames[candidate] = true
|
||||
ifName = candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
if ifName == "" {
|
||||
return fmt.Errorf("failed to find free interface name for network %q", network.Name)
|
||||
}
|
||||
}
|
||||
|
||||
rt, err := buildCNIRuntimeConf(plugin.cacheDir, podNetwork, ifName, podNetwork.RuntimeConfig[network.Name])
|
||||
if err != nil {
|
||||
logrus.Errorf(err.Error())
|
||||
logrus.Errorf("error building CNI runtime config: %v", err)
|
||||
return err
|
||||
}
|
||||
if err := forEachFunc(network, ifName, podNetwork, podNetwork.RuntimeConfig[netName]); err != nil {
|
||||
|
||||
var cniNet *cniNetwork
|
||||
if fromCache {
|
||||
var newRt *libcni.RuntimeConf
|
||||
cniNet, newRt, err = plugin.loadNetworkFromCache(network.Name, rt)
|
||||
if err != nil {
|
||||
logrus.Errorf("error loading cached network config: %v", err)
|
||||
// fall back to loading from existing plugins on disk
|
||||
} else {
|
||||
// Use the updated RuntimeConf
|
||||
rt = newRt
|
||||
}
|
||||
}
|
||||
if cniNet == nil {
|
||||
cniNet, err = plugin.getNetwork(network.Name)
|
||||
if err != nil {
|
||||
logrus.Errorf(err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := actionFn(cniNet, podNetwork, rt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Result, error) {
|
||||
func buildLoopbackRuntimeConf(cacheDir string, podNetwork *PodNetwork) *libcni.RuntimeConf {
|
||||
return &libcni.RuntimeConf{
|
||||
ContainerID: podNetwork.ID,
|
||||
NetNS: podNetwork.NetNS,
|
||||
CacheDir: cacheDir,
|
||||
IfName: loIfname,
|
||||
}
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, error) {
|
||||
if err := plugin.networksAvailable(&podNetwork); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -410,20 +543,26 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Resu
|
||||
plugin.podLock(podNetwork).Lock()
|
||||
defer plugin.podUnlock(podNetwork)
|
||||
|
||||
_, err := plugin.loNetwork.addToNetwork(plugin.cacheDir, &podNetwork, "lo", RuntimeConfig{})
|
||||
if err != nil {
|
||||
loRt := buildLoopbackRuntimeConf(plugin.cacheDir, &podNetwork)
|
||||
if _, err := plugin.loNetwork.addToNetwork(loRt, plugin.cniConfig); err != nil {
|
||||
logrus.Errorf("Error while adding to cni lo network: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results := make([]cnitypes.Result, 0)
|
||||
if err := plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork, runtimeConfig RuntimeConfig) error {
|
||||
result, err := network.addToNetwork(plugin.cacheDir, podNetwork, ifName, runtimeConfig)
|
||||
results := make([]NetResult, 0)
|
||||
if err := plugin.forEachNetwork(&podNetwork, false, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
|
||||
result, err := network.addToNetwork(rt, plugin.cniConfig)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while adding pod to CNI network %q: %s", network.name, err)
|
||||
return err
|
||||
}
|
||||
results = append(results, result)
|
||||
results = append(results, NetResult{
|
||||
Result: result,
|
||||
NetAttachment: NetAttachment{
|
||||
Name: network.name,
|
||||
Ifname: rt.IfName,
|
||||
},
|
||||
})
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@ -432,16 +571,99 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Resu
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetAttachment, error) {
|
||||
cacheDir := libcni.CacheDir
|
||||
if plugin.cacheDir != "" {
|
||||
cacheDir = plugin.cacheDir
|
||||
}
|
||||
|
||||
dirPath := filepath.Join(cacheDir, "results")
|
||||
entries, err := ioutil.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileNames := make([]string, 0, len(entries))
|
||||
for _, e := range entries {
|
||||
fileNames = append(fileNames, e.Name())
|
||||
}
|
||||
sort.Strings(fileNames)
|
||||
|
||||
attachments := []NetAttachment{}
|
||||
for _, fname := range fileNames {
|
||||
part := fmt.Sprintf("-%s-", containerID)
|
||||
pos := strings.Index(fname, part)
|
||||
if pos <= 0 || pos+len(part) >= len(fname) {
|
||||
continue
|
||||
}
|
||||
|
||||
cacheFile := filepath.Join(dirPath, fname)
|
||||
bytes, err := ioutil.ReadFile(cacheFile)
|
||||
if err != nil {
|
||||
logrus.Warningf("failed to read CNI cache file %s: %v", cacheFile, err)
|
||||
continue
|
||||
}
|
||||
|
||||
cachedInfo := struct {
|
||||
Kind string `json:"kind"`
|
||||
IfName string `json:"ifName"`
|
||||
ContainerID string `json:"containerID"`
|
||||
NetName string `json:"networkName"`
|
||||
}{}
|
||||
|
||||
if err := json.Unmarshal(bytes, &cachedInfo); err != nil {
|
||||
logrus.Warningf("failed to unmarshal CNI cache file %s: %v", cacheFile, err)
|
||||
continue
|
||||
}
|
||||
if cachedInfo.Kind != libcni.CNICacheV1 {
|
||||
logrus.Warningf("unknown CNI cache file %s kind %q", cacheFile, cachedInfo.Kind)
|
||||
continue
|
||||
}
|
||||
if cachedInfo.ContainerID != containerID {
|
||||
continue
|
||||
}
|
||||
// Ignore the loopback interface; it's handled separately
|
||||
if cachedInfo.IfName == loIfname && cachedInfo.NetName == loNetname {
|
||||
continue
|
||||
}
|
||||
if cachedInfo.IfName == "" || cachedInfo.NetName == "" {
|
||||
logrus.Warningf("missing CNI cache file %s ifname %q or netname %q", cacheFile, cachedInfo.IfName, cachedInfo.NetName)
|
||||
continue
|
||||
}
|
||||
|
||||
attachments = append(attachments, NetAttachment{
|
||||
Name: cachedInfo.NetName,
|
||||
Ifname: cachedInfo.IfName,
|
||||
})
|
||||
}
|
||||
return attachments, nil
|
||||
}
|
||||
|
||||
// TearDownPod tears down pod networks. Prefers cached pod attachment information
|
||||
// but falls back to given network attachment information.
|
||||
func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
|
||||
if len(podNetwork.Networks) == 0 {
|
||||
attachments, err := plugin.getCachedNetworkInfo(podNetwork.ID)
|
||||
if err == nil && len(attachments) > 0 {
|
||||
podNetwork.Networks = attachments
|
||||
}
|
||||
}
|
||||
|
||||
if err := plugin.networksAvailable(&podNetwork); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
loRt := buildLoopbackRuntimeConf(plugin.cacheDir, &podNetwork)
|
||||
if err := plugin.loNetwork.deleteFromNetwork(loRt, plugin.cniConfig); err != nil {
|
||||
logrus.Errorf("Error while removing pod from CNI lo network: %v", err)
|
||||
// Loopback teardown errors are not fatal
|
||||
}
|
||||
|
||||
plugin.podLock(podNetwork).Lock()
|
||||
defer plugin.podUnlock(podNetwork)
|
||||
|
||||
return plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork, runtimeConfig RuntimeConfig) error {
|
||||
if err := network.deleteFromNetwork(plugin.cacheDir, podNetwork, ifName, runtimeConfig); err != nil {
|
||||
return plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
|
||||
if err := network.deleteFromNetwork(rt, plugin.cniConfig); err != nil {
|
||||
logrus.Errorf("Error while removing pod from CNI network %q: %s", network.name, err)
|
||||
return err
|
||||
}
|
||||
@ -451,19 +673,25 @@ func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
|
||||
|
||||
// GetPodNetworkStatus returns IP addressing and interface details for all
|
||||
// networks attached to the pod.
|
||||
func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]cnitypes.Result, error) {
|
||||
func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]NetResult, error) {
|
||||
plugin.podLock(podNetwork).Lock()
|
||||
defer plugin.podUnlock(podNetwork)
|
||||
|
||||
results := make([]cnitypes.Result, 0)
|
||||
if err := plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork, runtimeConfig RuntimeConfig) error {
|
||||
result, err := network.checkNetwork(plugin.cacheDir, podNetwork, ifName, runtimeConfig, plugin.nsManager)
|
||||
results := make([]NetResult, 0)
|
||||
if err := plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
|
||||
result, err := network.checkNetwork(rt, plugin.cniConfig, plugin.nsManager, podNetwork.NetNS)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error while checking pod to CNI network %q: %s", network.name, err)
|
||||
return err
|
||||
}
|
||||
if result != nil {
|
||||
results = append(results, result)
|
||||
results = append(results, NetResult{
|
||||
Result: result,
|
||||
NetAttachment: NetAttachment{
|
||||
Name: network.name,
|
||||
Ifname: rt.IfName,
|
||||
},
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -473,16 +701,9 @@ func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]cn
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (network *cniNetwork) addToNetwork(cacheDir string, podNetwork *PodNetwork, ifName string, runtimeConfig RuntimeConfig) (cnitypes.Result, error) {
|
||||
rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, runtimeConfig)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error adding network: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
netconf, cninet := network.NetworkConfig, network.CNIConfig
|
||||
logrus.Infof("About to add CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type)
|
||||
res, err := cninet.AddNetworkList(context.Background(), netconf, rt)
|
||||
func (network *cniNetwork) addToNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) (cnitypes.Result, error) {
|
||||
logrus.Infof("About to add CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type)
|
||||
res, err := cni.AddNetworkList(context.Background(), network.config, rt)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error adding network: %v", err)
|
||||
return nil, err
|
||||
@ -491,18 +712,10 @@ func (network *cniNetwork) addToNetwork(cacheDir string, podNetwork *PodNetwork,
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork, ifName string, runtimeConfig RuntimeConfig, nsManager *nsManager) (cnitypes.Result, error) {
|
||||
func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig, nsManager *nsManager, netns string) (cnitypes.Result, error) {
|
||||
logrus.Infof("About to check CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type)
|
||||
|
||||
rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, runtimeConfig)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error checking network: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
netconf, cninet := network.NetworkConfig, network.CNIConfig
|
||||
logrus.Infof("About to check CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type)
|
||||
|
||||
gtet, err := cniversion.GreaterThanOrEqualTo(netconf.CNIVersion, "0.4.0")
|
||||
gtet, err := cniversion.GreaterThanOrEqualTo(network.config.CNIVersion, "0.4.0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -511,15 +724,15 @@ func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork,
|
||||
|
||||
// When CNIVersion supports Check, use it. Otherwise fall back on what was done initially.
|
||||
if gtet {
|
||||
err = cninet.CheckNetworkList(context.Background(), netconf, rt)
|
||||
logrus.Infof("Checking CNI network %s (config version=%v)", netconf.Name, netconf.CNIVersion)
|
||||
err = cni.CheckNetworkList(context.Background(), network.config, rt)
|
||||
logrus.Infof("Checking CNI network %s (config version=%v)", network.name, network.config.CNIVersion)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error checking network: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
result, err = cninet.GetNetworkListCachedResult(netconf, rt)
|
||||
result, err = cni.GetNetworkListCachedResult(network.config, rt)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error GetNetworkListCachedResult: %v", err)
|
||||
return nil, err
|
||||
@ -528,19 +741,19 @@ func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork,
|
||||
}
|
||||
|
||||
// result doesn't exist, create one
|
||||
logrus.Infof("Checking CNI network %s (config version=%v) nsManager=%v", netconf.Name, netconf.CNIVersion, nsManager)
|
||||
logrus.Infof("Checking CNI network %s (config version=%v) nsManager=%v", network.name, network.config.CNIVersion, nsManager)
|
||||
|
||||
var cniInterface *cnicurrent.Interface
|
||||
ips := []*cnicurrent.IPConfig{}
|
||||
errs := []error{}
|
||||
for _, version := range []string{"4", "6"} {
|
||||
ip, mac, err := getContainerDetails(nsManager, podNetwork.NetNS, ifName, "-"+version)
|
||||
ip, mac, err := getContainerDetails(nsManager, netns, rt.IfName, "-"+version)
|
||||
if err == nil {
|
||||
if cniInterface == nil {
|
||||
cniInterface = &cnicurrent.Interface{
|
||||
Name: ifName,
|
||||
Name: rt.IfName,
|
||||
Mac: mac.String(),
|
||||
Sandbox: podNetwork.NetNS,
|
||||
Sandbox: netns,
|
||||
}
|
||||
}
|
||||
ips = append(ips, &cnicurrent.IPConfig{
|
||||
@ -557,25 +770,23 @@ func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork,
|
||||
}
|
||||
|
||||
result = &cnicurrent.Result{
|
||||
CNIVersion: netconf.CNIVersion,
|
||||
CNIVersion: network.config.CNIVersion,
|
||||
Interfaces: []*cnicurrent.Interface{cniInterface},
|
||||
IPs: ips,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (network *cniNetwork) deleteFromNetwork(cacheDir string, podNetwork *PodNetwork, ifName string, runtimeConfig RuntimeConfig) error {
|
||||
rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, runtimeConfig)
|
||||
// Result must be the same CNIVersion as the CNI config
|
||||
converted, err := result.GetAsVersion(network.config.CNIVersion)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error deleting network: %v", err)
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
netconf, cninet := network.NetworkConfig, network.CNIConfig
|
||||
logrus.Infof("About to del CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type)
|
||||
err = cninet.DelNetworkList(context.Background(), netconf, rt)
|
||||
if err != nil {
|
||||
return converted, nil
|
||||
}
|
||||
|
||||
func (network *cniNetwork) deleteFromNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) error {
|
||||
logrus.Infof("About to del CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type)
|
||||
if err := cni.DelNetworkList(context.Background(), network.config, rt); err != nil {
|
||||
logrus.Errorf("Error deleting network: %v", err)
|
||||
return err
|
||||
}
|
||||
@ -608,6 +819,16 @@ func buildCNIRuntimeConf(cacheDir string, podNetwork *PodNetwork, ifName string,
|
||||
rt.Args = append(rt.Args, [2]string{"IP", ip})
|
||||
}
|
||||
|
||||
// Add the requested static MAC to CNI_ARGS
|
||||
mac := runtimeConfig.MAC
|
||||
if mac != "" {
|
||||
_, err := net.ParseMAC(mac)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse MAC address %q: %v", mac, err)
|
||||
}
|
||||
rt.Args = append(rt.Args, [2]string{"MAC", mac})
|
||||
}
|
||||
|
||||
// Set PortMappings in Capabilities
|
||||
if len(runtimeConfig.PortMappings) != 0 {
|
||||
rt.CapabilityArgs["portMappings"] = runtimeConfig.PortMappings
|
||||
|
32
vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
generated
vendored
32
vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
generated
vendored
@ -44,6 +44,9 @@ type RuntimeConfig struct {
|
||||
// with the hostlocal IP allocator. If left unset, an IP will be
|
||||
// dynamically allocated.
|
||||
IP string
|
||||
// MAC is a static MAC address to be assigned to the network interface.
|
||||
// If left unset, a MAC will be dynamically allocated.
|
||||
MAC string
|
||||
// PortMappings is the port mapping of the sandbox.
|
||||
PortMappings []PortMapping
|
||||
// Bandwidth is the bandwidth limiting of the pod
|
||||
@ -75,9 +78,10 @@ type PodNetwork struct {
|
||||
// NetNS is the network namespace path of the sandbox.
|
||||
NetNS string
|
||||
|
||||
// Networks is a list of CNI network names to attach to the sandbox
|
||||
// Leave this list empty to attach the default network to the sandbox
|
||||
Networks []string
|
||||
// Networks is a list of CNI network names (and optional interface
|
||||
// names) to attach to the sandbox. Leave this list empty to attach the
|
||||
// default network to the sandbox
|
||||
Networks []NetAttachment
|
||||
|
||||
// NetworkConfig is configuration specific to a single CNI network.
|
||||
// It is optional, and can be omitted for some or all specified networks
|
||||
@ -85,6 +89,24 @@ type PodNetwork struct {
|
||||
RuntimeConfig map[string]RuntimeConfig
|
||||
}
|
||||
|
||||
// NetAttachment describes a container network attachment
|
||||
type NetAttachment struct {
|
||||
// NetName contains the name of the CNI network to which the container
|
||||
// should be or is attached
|
||||
Name string
|
||||
// Ifname contains the optional interface name of the attachment
|
||||
Ifname string
|
||||
}
|
||||
|
||||
// NetResult contains the result the network attachment operation
|
||||
type NetResult struct {
|
||||
// Result is the CNI Result
|
||||
Result types.Result
|
||||
// NetAttachment contains the network and interface names of this
|
||||
// network attachment
|
||||
NetAttachment
|
||||
}
|
||||
|
||||
// CNIPlugin is the interface that needs to be implemented by a plugin
|
||||
type CNIPlugin interface {
|
||||
// Name returns the plugin's name. This will be used when searching
|
||||
@ -98,13 +120,13 @@ type CNIPlugin interface {
|
||||
// SetUpPod is the method called after the sandbox container of
|
||||
// the pod has been created but before the other containers of the
|
||||
// pod are launched.
|
||||
SetUpPod(network PodNetwork) ([]types.Result, error)
|
||||
SetUpPod(network PodNetwork) ([]NetResult, error)
|
||||
|
||||
// TearDownPod is the method called before a pod's sandbox container will be deleted
|
||||
TearDownPod(network PodNetwork) error
|
||||
|
||||
// Status is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox
|
||||
GetPodNetworkStatus(network PodNetwork) ([]types.Result, error)
|
||||
GetPodNetworkStatus(network PodNetwork) ([]NetResult, error)
|
||||
|
||||
// NetworkStatus returns error if the network plugin is in error state
|
||||
Status() error
|
||||
|
5
vendor/modules.txt
vendored
5
vendor/modules.txt
vendored
@ -42,13 +42,14 @@ github.com/containerd/containerd/errdefs
|
||||
github.com/containerd/continuity/fs
|
||||
github.com/containerd/continuity/sysx
|
||||
github.com/containerd/continuity/syscallx
|
||||
# github.com/containernetworking/cni v0.7.1
|
||||
# github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784
|
||||
github.com/containernetworking/cni/pkg/types
|
||||
github.com/containernetworking/cni/pkg/types/current
|
||||
github.com/containernetworking/cni/pkg/version
|
||||
github.com/containernetworking/cni/libcni
|
||||
github.com/containernetworking/cni/pkg/invoke
|
||||
github.com/containernetworking/cni/pkg/types/020
|
||||
github.com/containernetworking/cni/pkg/utils
|
||||
# github.com/containernetworking/plugins v0.8.2
|
||||
github.com/containernetworking/plugins/pkg/ns
|
||||
github.com/containernetworking/plugins/pkg/ip
|
||||
@ -169,7 +170,7 @@ github.com/coreos/go-systemd/sdjournal
|
||||
github.com/coreos/go-systemd/journal
|
||||
# github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f
|
||||
github.com/coreos/pkg/dlopen
|
||||
# github.com/cri-o/ocicni v0.1.1-0.20190702175919-7762645d18ca
|
||||
# github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b
|
||||
github.com/cri-o/ocicni/pkg/ocicni
|
||||
# github.com/cyphar/filepath-securejoin v0.2.2
|
||||
github.com/cyphar/filepath-securejoin
|
||||
|
Reference in New Issue
Block a user