network aliases for container creation

podman can now support adding network aliases when running containers
(--network-alias).  It requires an updated dnsname plugin as well as an
updated ocicni to work properly.

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude
2020-10-29 15:54:33 -05:00
parent 110a1d8f25
commit b7b5b6f8e3
19 changed files with 255 additions and 66 deletions

View File

@ -133,6 +133,7 @@ func stringMaptoArray(m map[string]string) []string {
// a specgen spec. // a specgen spec.
func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) { func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) {
var ( var (
aliases []string
capAdd []string capAdd []string
cappDrop []string cappDrop []string
entrypoint string entrypoint string
@ -242,8 +243,11 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
// network names // network names
endpointsConfig := cc.NetworkingConfig.EndpointsConfig endpointsConfig := cc.NetworkingConfig.EndpointsConfig
cniNetworks := make([]string, 0, len(endpointsConfig)) cniNetworks := make([]string, 0, len(endpointsConfig))
for netName := range endpointsConfig { for netName, endpoint := range endpointsConfig {
cniNetworks = append(cniNetworks, netName) cniNetworks = append(cniNetworks, netName)
if len(endpoint.Aliases) > 0 {
aliases = append(aliases, endpoint.Aliases...)
}
} }
// netMode // netMode
@ -262,6 +266,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
// defined when there is only one network. // defined when there is only one network.
netInfo := entities.NetOptions{ netInfo := entities.NetOptions{
AddHosts: cc.HostConfig.ExtraHosts, AddHosts: cc.HostConfig.ExtraHosts,
Aliases: aliases,
CNINetworks: cniNetworks, CNINetworks: cniNetworks,
DNSOptions: cc.HostConfig.DNSOptions, DNSOptions: cc.HostConfig.DNSOptions,
DNSSearch: cc.HostConfig.DNSSearch, DNSSearch: cc.HostConfig.DNSSearch,

View File

@ -43,6 +43,10 @@ func GetNetFlags() *pflag.FlagSet {
"network", containerConfig.NetNS(), "network", containerConfig.NetNS(),
"Connect a container to a network", "Connect a container to a network",
) )
netFlags.StringSlice(
"network-alias", []string{},
"Add network-scoped alias for the container",
)
netFlags.StringSliceP( netFlags.StringSliceP(
"publish", "p", []string{}, "publish", "p", []string{},
"Publish a container's port, or a range of ports, to the host (default [])", "Publish a container's port, or a range of ports, to the host (default [])",
@ -158,6 +162,9 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
} }
opts.NoHosts, err = cmd.Flags().GetBool("no-hosts") opts.NoHosts, err = cmd.Flags().GetBool("no-hosts")
if err != nil {
return nil, err
}
if cmd.Flags().Changed("network") { if cmd.Flags().Changed("network") {
network, err := cmd.Flags().GetString("network") network, err := cmd.Flags().GetString("network")
@ -181,5 +188,12 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
opts.CNINetworks = cniNets opts.CNINetworks = cniNets
} }
aliases, err := cmd.Flags().GetStringSlice("network-alias")
if err != nil {
return nil, err
}
if len(aliases) > 0 {
opts.Aliases = aliases
}
return &opts, err return &opts, err
} }

View File

@ -396,6 +396,17 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.ShmSize = &shmSize s.ShmSize = &shmSize
} }
s.CNINetworks = c.Net.CNINetworks s.CNINetworks = c.Net.CNINetworks
// Network aliases
if len(c.Net.Aliases) > 0 {
// build a map of aliases where key=cniName
aliases := make(map[string][]string, len(s.CNINetworks))
for _, cniNetwork := range s.CNINetworks {
aliases[cniNetwork] = c.Net.Aliases
}
s.Aliases = aliases
}
s.HostAdd = c.Net.AddHosts s.HostAdd = c.Net.AddHosts
s.UseImageResolvConf = c.Net.UseImageResolvConf s.UseImageResolvConf = c.Net.UseImageResolvConf
s.DNSServers = c.Net.DNSServers s.DNSServers = c.Net.DNSServers

View File

@ -600,7 +600,7 @@ Valid values are:
**--network-alias**=*alias* **--network-alias**=*alias*
Not implemented Add network-scoped alias for the container
**--no-healthcheck**=*true|false* **--no-healthcheck**=*true|false*

View File

@ -626,7 +626,7 @@ Valid _mode_ values are:
**--network-alias**=*alias* **--network-alias**=*alias*
Not implemented. Add network-scoped alias for the container
**--no-healthcheck**=*true|false* **--no-healthcheck**=*true|false*

4
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/containers/psgo v1.5.1 github.com/containers/psgo v1.5.1
github.com/containers/storage v1.23.9 github.com/containers/storage v1.23.9
github.com/coreos/go-systemd/v22 v22.1.0 github.com/coreos/go-systemd/v22 v22.1.0
github.com/cri-o/ocicni v0.2.0 github.com/cri-o/ocicni v0.2.1-0.20201102180012-75c612fda1a2
github.com/cyphar/filepath-securejoin v0.2.2 github.com/cyphar/filepath-securejoin v0.2.2
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/docker/distribution v2.7.1+incompatible github.com/docker/distribution v2.7.1+incompatible
@ -72,3 +72,5 @@ require (
k8s.io/apimachinery v0.19.3 k8s.io/apimachinery v0.19.3
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
) )
replace github.com/cri-o/ocicni => github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df

4
go.sum
View File

@ -119,8 +119,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cri-o/ocicni v0.2.0 h1:p0kO+/fcLTO574CcDwzAosFdP2U+NEL+a4wph3Bt85k= github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df h1:c35uRFkER07nAkB1X21e+PI5xO21SOyI6G7tdfvz1z4=
github.com/cri-o/ocicni v0.2.0/go.mod h1:ZOuIEOp/3MB1eCBWANnNxM3zUA3NWh76wSRCsnKAg2c= github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df/go.mod h1:vingr1ztOAzP2WyTgGbpMov9dFhbjNxdLtDv0+PhAvY=
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= 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/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=

View File

@ -131,8 +131,9 @@ func (f FirewallConfig) Bytes() ([]byte, error) {
// DNSNameConfig describes the dns container name resolution plugin config // DNSNameConfig describes the dns container name resolution plugin config
type DNSNameConfig struct { type DNSNameConfig struct {
PluginType string `json:"type"` PluginType string `json:"type"`
DomainName string `json:"domainName"` DomainName string `json:"domainName"`
Capabilities map[string]bool `json:"capabilities"`
} }
// Bytes outputs the configuration as []byte // Bytes outputs the configuration as []byte

View File

@ -126,9 +126,12 @@ func NewFirewallPlugin() FirewallConfig {
// NewDNSNamePlugin creates the dnsname config with a given // NewDNSNamePlugin creates the dnsname config with a given
// domainname // domainname
func NewDNSNamePlugin(domainName string) DNSNameConfig { func NewDNSNamePlugin(domainName string) DNSNameConfig {
caps := make(map[string]bool, 1)
caps["aliases"] = true
return DNSNameConfig{ return DNSNameConfig{
PluginType: "dnsname", PluginType: "dnsname",
DomainName: domainName, DomainName: domainName,
Capabilities: caps,
} }
} }

View File

@ -105,6 +105,13 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
podName := getCNIPodName(ctr) podName := getCNIPodName(ctr)
podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC) podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP, requestedMAC)
aliases, err := ctr.runtime.state.GetAllNetworkAliases(ctr)
if err != nil {
return nil, err
}
if len(aliases) > 0 {
podNetwork.Aliases = aliases
}
results, err := r.netPlugin.SetUpPod(podNetwork) results, err := r.netPlugin.SetUpPod(podNetwork)
if err != nil { if err != nil {

View File

@ -32,6 +32,7 @@ type VolumeDeleteReport struct{ Report }
// pods and containers // pods and containers
type NetOptions struct { type NetOptions struct {
AddHosts []string AddHosts []string
Aliases []string
CNINetworks []string CNINetworks []string
UseImageResolvConf bool UseImageResolvConf bool
DNSOptions []string DNSOptions []string

View File

@ -133,6 +133,10 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
} }
options = append(options, libpod.WithExitCommand(exitCommandArgs)) options = append(options, libpod.WithExitCommand(exitCommandArgs))
if len(s.Aliases) > 0 {
options = append(options, libpod.WithNetworkAliases(s.Aliases))
}
runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command) runtimeSpec, err := SpecGenToOCI(ctx, s, rt, rtc, newImage, finalMounts, pod, command)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -328,6 +328,9 @@ type ContainerCgroupConfig struct {
// ContainerNetworkConfig contains information on a container's network // ContainerNetworkConfig contains information on a container's network
// configuration. // configuration.
type ContainerNetworkConfig struct { type ContainerNetworkConfig struct {
// Aliases are a list of network-scoped aliases for container
// Optional
Aliases map[string][]string `json:"aliases"`
// NetNS is the configuration to use for the container's network // NetNS is the configuration to use for the container's network
// namespace. // namespace.
// Mandatory. // Mandatory.

View File

@ -6,6 +6,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/containers/podman/v2/pkg/rootless" "github.com/containers/podman/v2/pkg/rootless"
. "github.com/containers/podman/v2/test/utils" . "github.com/containers/podman/v2/test/utils"
@ -351,4 +352,42 @@ var _ = Describe("Podman network", func() {
Expect(lines[0]).To(Equal(netName1)) Expect(lines[0]).To(Equal(netName1))
Expect(lines[1]).To(Equal(netName2)) Expect(lines[1]).To(Equal(netName2))
}) })
It("podman network with multiple aliases", func() {
Skip("Until DNSName is updated on our CI images")
var worked bool
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(BeZero())
defer podmanTest.removeCNINetwork(netName)
top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx})
top.WaitWithDefaultTimeout()
Expect(top.ExitCode()).To(BeZero())
interval := time.Duration(250 * time.Millisecond)
// Wait for the nginx service to be running
for i := 0; i < 6; i++ {
// Test curl against the container's name
c1 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web"})
c1.WaitWithDefaultTimeout()
worked = Expect(c1.ExitCode()).To(BeZero())
if worked {
break
}
time.Sleep(interval)
interval *= 2
}
Expect(worked).To(BeTrue())
// Nginx is now running so no need to do a loop
// Test against the first alias
c2 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web1"})
c2.WaitWithDefaultTimeout()
Expect(c2.ExitCode()).To(BeZero())
// Test against the second alias
c3 := podmanTest.Podman([]string{"run", "--network=" + netName, nginx, "curl", "web2"})
c3.WaitWithDefaultTimeout()
Expect(c3.ExitCode()).To(BeZero())
})
}) })

View File

@ -24,7 +24,6 @@ import (
type cniNetworkPlugin struct { type cniNetworkPlugin struct {
cniConfig *libcni.CNIConfig cniConfig *libcni.CNIConfig
loNetwork *cniNetwork
sync.RWMutex sync.RWMutex
defaultNetName netName defaultNetName netName
@ -217,7 +216,6 @@ func initCNI(exec cniinvoke.Exec, cacheDir, defaultNetName string, confDir strin
changeable: defaultNetName == "", changeable: defaultNetName == "",
}, },
networks: make(map[string]*cniNetwork), networks: make(map[string]*cniNetwork),
loNetwork: getLoNetwork(),
confDir: confDir, confDir: confDir,
binDirs: binDirs, binDirs: binDirs,
shutdownChan: make(chan struct{}), shutdownChan: make(chan struct{}),
@ -335,31 +333,9 @@ func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork
} }
const ( const (
loIfname string = "lo" 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: loIfname,
config: loConfig,
}
return loNetwork
}
func (plugin *cniNetworkPlugin) syncNetworkConfig() error { func (plugin *cniNetworkPlugin) syncNetworkConfig() error {
networks, defaultNetName, err := loadNetworks(plugin.confDir, plugin.cniConfig) networks, defaultNetName, err := loadNetworks(plugin.confDir, plugin.cniConfig)
if err != nil { if err != nil {
@ -525,16 +501,11 @@ func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, fromCache
return nil return nil
} }
func buildLoopbackRuntimeConf(cacheDir string, podNetwork *PodNetwork) *libcni.RuntimeConf { func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, error) {
return &libcni.RuntimeConf{ return plugin.SetUpPodWithContext(context.Background(), podNetwork)
ContainerID: podNetwork.ID,
NetNS: podNetwork.NetNS,
CacheDir: cacheDir,
IfName: loIfname,
}
} }
func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, error) { func (plugin *cniNetworkPlugin) SetUpPodWithContext(ctx context.Context, podNetwork PodNetwork) ([]NetResult, error) {
if err := plugin.networksAvailable(&podNetwork); err != nil { if err := plugin.networksAvailable(&podNetwork); err != nil {
return nil, err return nil, err
} }
@ -542,15 +513,15 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, er
plugin.podLock(podNetwork).Lock() plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork) defer plugin.podUnlock(podNetwork)
loRt := buildLoopbackRuntimeConf(plugin.cacheDir, &podNetwork) // Set up loopback interface
if _, err := plugin.loNetwork.addToNetwork(loRt, plugin.cniConfig); err != nil { if err := bringUpLoopback(podNetwork.NetNS); err != nil {
logrus.Errorf("Error while adding to cni lo network: %s", err) logrus.Errorf(err.Error())
return nil, err return nil, err
} }
results := make([]NetResult, 0) results := make([]NetResult, 0)
if err := plugin.forEachNetwork(&podNetwork, false, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error { if err := plugin.forEachNetwork(&podNetwork, false, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
result, err := network.addToNetwork(rt, plugin.cniConfig) result, err := network.addToNetwork(ctx, rt, plugin.cniConfig)
if err != nil { if err != nil {
logrus.Errorf("Error while adding pod to CNI network %q: %s", network.name, err) logrus.Errorf("Error while adding pod to CNI network %q: %s", network.name, err)
return err return err
@ -622,7 +593,7 @@ func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetA
continue continue
} }
// Ignore the loopback interface; it's handled separately // Ignore the loopback interface; it's handled separately
if cachedInfo.IfName == loIfname && cachedInfo.NetName == loNetname { if cachedInfo.IfName == loIfname && cachedInfo.NetName == "cni-loopback" {
continue continue
} }
if cachedInfo.IfName == "" || cachedInfo.NetName == "" { if cachedInfo.IfName == "" || cachedInfo.NetName == "" {
@ -641,6 +612,10 @@ func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetA
// TearDownPod tears down pod networks. Prefers cached pod attachment information // TearDownPod tears down pod networks. Prefers cached pod attachment information
// but falls back to given network attachment information. // but falls back to given network attachment information.
func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error { func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
return plugin.TearDownPodWithContext(context.Background(), podNetwork)
}
func (plugin *cniNetworkPlugin) TearDownPodWithContext(ctx context.Context, podNetwork PodNetwork) error {
if len(podNetwork.Networks) == 0 { if len(podNetwork.Networks) == 0 {
attachments, err := plugin.getCachedNetworkInfo(podNetwork.ID) attachments, err := plugin.getCachedNetworkInfo(podNetwork.ID)
if err == nil && len(attachments) > 0 { if err == nil && len(attachments) > 0 {
@ -652,17 +627,16 @@ func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
return err 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() plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork) defer plugin.podUnlock(podNetwork)
if err := tearDownLoopback(podNetwork.NetNS); err != nil {
// ignore error
logrus.Errorf("Ignoring error tearing down loopback interface: %v", err)
}
return plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error { return plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
if err := network.deleteFromNetwork(rt, plugin.cniConfig); err != nil { if err := network.deleteFromNetwork(ctx, rt, plugin.cniConfig); err != nil {
logrus.Errorf("Error while removing pod from CNI network %q: %s", network.name, err) logrus.Errorf("Error while removing pod from CNI network %q: %s", network.name, err)
return err return err
} }
@ -673,12 +647,23 @@ func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
// GetPodNetworkStatus returns IP addressing and interface details for all // GetPodNetworkStatus returns IP addressing and interface details for all
// networks attached to the pod. // networks attached to the pod.
func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]NetResult, error) { func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]NetResult, error) {
return plugin.GetPodNetworkStatusWithContext(context.Background(), podNetwork)
}
// GetPodNetworkStatusWithContext returns IP addressing and interface details for all
// networks attached to the pod.
func (plugin *cniNetworkPlugin) GetPodNetworkStatusWithContext(ctx context.Context, podNetwork PodNetwork) ([]NetResult, error) {
plugin.podLock(podNetwork).Lock() plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork) defer plugin.podUnlock(podNetwork)
if err := checkLoopback(podNetwork.NetNS); err != nil {
logrus.Errorf(err.Error())
return nil, err
}
results := make([]NetResult, 0) results := make([]NetResult, 0)
if err := plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error { 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) result, err := network.checkNetwork(ctx, rt, plugin.cniConfig, plugin.nsManager, podNetwork.NetNS)
if err != nil { if err != nil {
logrus.Errorf("Error while checking pod to CNI network %q: %s", network.name, err) logrus.Errorf("Error while checking pod to CNI network %q: %s", network.name, err)
return err return err
@ -700,9 +685,9 @@ func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]Ne
return results, nil return results, nil
} }
func (network *cniNetwork) addToNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) (cnitypes.Result, error) { func (network *cniNetwork) addToNetwork(ctx context.Context, 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) 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) res, err := cni.AddNetworkList(ctx, network.config, rt)
if err != nil { if err != nil {
logrus.Errorf("Error adding network: %v", err) logrus.Errorf("Error adding network: %v", err)
return nil, err return nil, err
@ -711,7 +696,7 @@ func (network *cniNetwork) addToNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIC
return res, nil return res, nil
} }
func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig, nsManager *nsManager, netns string) (cnitypes.Result, error) { func (network *cniNetwork) checkNetwork(ctx context.Context, 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) logrus.Infof("About to check CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type)
gtet, err := cniversion.GreaterThanOrEqualTo(network.config.CNIVersion, "0.4.0") gtet, err := cniversion.GreaterThanOrEqualTo(network.config.CNIVersion, "0.4.0")
@ -723,7 +708,7 @@ func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIC
// When CNIVersion supports Check, use it. Otherwise fall back on what was done initially. // When CNIVersion supports Check, use it. Otherwise fall back on what was done initially.
if gtet { if gtet {
err = cni.CheckNetworkList(context.Background(), network.config, rt) err = cni.CheckNetworkList(ctx, network.config, rt)
logrus.Infof("Checking CNI network %s (config version=%v)", network.name, network.config.CNIVersion) logrus.Infof("Checking CNI network %s (config version=%v)", network.name, network.config.CNIVersion)
if err != nil { if err != nil {
logrus.Errorf("Error checking network: %v", err) logrus.Errorf("Error checking network: %v", err)
@ -783,9 +768,9 @@ func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIC
return converted, nil return converted, nil
} }
func (network *cniNetwork) deleteFromNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) error { func (network *cniNetwork) deleteFromNetwork(ctx context.Context, 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) 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 { if err := cni.DelNetworkList(ctx, network.config, rt); err != nil {
logrus.Errorf("Error deleting network: %v", err) logrus.Errorf("Error deleting network: %v", err)
return err return err
} }
@ -848,6 +833,10 @@ func buildCNIRuntimeConf(cacheDir string, podNetwork *PodNetwork, ifName string,
rt.CapabilityArgs["ipRanges"] = runtimeConfig.IpRanges rt.CapabilityArgs["ipRanges"] = runtimeConfig.IpRanges
} }
// Set Aliases in Capabilities
if len(podNetwork.Aliases) > 0 {
rt.CapabilityArgs["aliases"] = podNetwork.Aliases
}
return rt, nil return rt, nil
} }

View File

@ -1,6 +1,8 @@
package ocicni package ocicni
import ( import (
"context"
"github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types"
) )
@ -87,6 +89,11 @@ type PodNetwork struct {
// It is optional, and can be omitted for some or all specified networks // It is optional, and can be omitted for some or all specified networks
// without issue. // without issue.
RuntimeConfig map[string]RuntimeConfig RuntimeConfig map[string]RuntimeConfig
// Aliases are network-scoped names for resolving a container
// by name. The key value is the network name and the value is
// is a string slice of aliases
Aliases map[string][]string
} }
// NetAttachment describes a container network attachment // NetAttachment describes a container network attachment
@ -122,12 +129,21 @@ type CNIPlugin interface {
// pod are launched. // pod are launched.
SetUpPod(network PodNetwork) ([]NetResult, error) SetUpPod(network PodNetwork) ([]NetResult, error)
// SetUpPodWithContext is the same as SetUpPod but takes a context
SetUpPodWithContext(ctx context.Context, network PodNetwork) ([]NetResult, error)
// TearDownPod is the method called before a pod's sandbox container will be deleted // TearDownPod is the method called before a pod's sandbox container will be deleted
TearDownPod(network PodNetwork) error TearDownPod(network PodNetwork) error
// Status is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox // TearDownPodWithContext is the same as TearDownPod but takes a context
TearDownPodWithContext(ctx context.Context, network PodNetwork) error
// GetPodNetworkStatus is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox
GetPodNetworkStatus(network PodNetwork) ([]NetResult, error) GetPodNetworkStatus(network PodNetwork) ([]NetResult, error)
// GetPodNetworkStatusWithContext is the same as GetPodNetworkStatus but takes a context
GetPodNetworkStatusWithContext(ctx context.Context, network PodNetwork) ([]NetResult, error)
// NetworkStatus returns error if the network plugin is in error state // NetworkStatus returns error if the network plugin is in error state
Status() error Status() error

View File

@ -7,6 +7,9 @@ import (
"net" "net"
"os/exec" "os/exec"
"strings" "strings"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
) )
var defaultNamespaceEnterCommandName = "nsenter" var defaultNamespaceEnterCommandName = "nsenter"
@ -69,3 +72,79 @@ func getContainerDetails(nsm *nsManager, netnsPath, interfaceName, addrType stri
return ipNet, &mac, nil return ipNet, &mac, nil
} }
func tearDownLoopback(netns string) error {
return ns.WithNetNSPath(netns, func(_ ns.NetNS) error {
link, err := netlink.LinkByName(loIfname)
if err != nil {
return err // not tested
}
err = netlink.LinkSetDown(link)
if err != nil {
return err // not tested
}
return nil
})
}
func bringUpLoopback(netns string) error {
if err := ns.WithNetNSPath(netns, func(_ ns.NetNS) error {
link, err := netlink.LinkByName(loIfname)
if err == nil {
err = netlink.LinkSetUp(link)
}
if err != nil {
return err
}
v4Addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
if err != nil {
return err
}
if len(v4Addrs) != 0 {
// sanity check that this is a loopback address
for _, addr := range v4Addrs {
if !addr.IP.IsLoopback() {
return fmt.Errorf("loopback interface found with non-loopback address %q", addr.IP)
}
}
}
v6Addrs, err := netlink.AddrList(link, netlink.FAMILY_V6)
if err != nil {
return err
}
if len(v6Addrs) != 0 {
// sanity check that this is a loopback address
for _, addr := range v6Addrs {
if !addr.IP.IsLoopback() {
return fmt.Errorf("loopback interface found with non-loopback address %q", addr.IP)
}
}
}
return nil
}); err != nil {
return fmt.Errorf("error adding loopback interface: %s", err)
}
return nil
}
func checkLoopback(netns string) error {
// Make sure loopback interface is up
if err := ns.WithNetNSPath(netns, func(_ ns.NetNS) error {
link, err := netlink.LinkByName(loIfname)
if err != nil {
return err
}
if link.Attrs().Flags&net.FlagUp != net.FlagUp {
return fmt.Errorf("loopback interface is down")
}
return nil
}); err != nil {
return fmt.Errorf("error checking loopback interface: %v", err)
}
return nil
}

View File

@ -3,17 +3,32 @@
package ocicni package ocicni
import ( import (
"fmt" "errors"
"net" "net"
) )
type nsManager struct { type nsManager struct {
} }
var errUnsupportedPlatform = errors.New("unsupported platform")
func (nsm *nsManager) init() error { func (nsm *nsManager) init() error {
return nil return nil
} }
func getContainerDetails(nsm *nsManager, netnsPath, interfaceName, addrType string) (*net.IPNet, *net.HardwareAddr, error) { func getContainerDetails(nsm *nsManager, netnsPath, interfaceName, addrType string) (*net.IPNet, *net.HardwareAddr, error) {
return nil, nil, fmt.Errorf("not supported yet") return nil, nil, errUnsupportedPlatform
}
func tearDownLoopback(netns string) error {
return errUnsupportedPlatform
}
func bringUpLoopback(netns string) error {
return errUnsupportedPlatform
}
func checkLoopback(netns string) error {
return errUnsupportedPlatform
} }

2
vendor/modules.txt vendored
View File

@ -216,7 +216,7 @@ github.com/coreos/go-systemd/v22/dbus
github.com/coreos/go-systemd/v22/internal/dlopen github.com/coreos/go-systemd/v22/internal/dlopen
github.com/coreos/go-systemd/v22/journal github.com/coreos/go-systemd/v22/journal
github.com/coreos/go-systemd/v22/sdjournal github.com/coreos/go-systemd/v22/sdjournal
# github.com/cri-o/ocicni v0.2.0 # github.com/cri-o/ocicni v0.2.1-0.20201102180012-75c612fda1a2 => github.com/cri-o/ocicni v0.2.1-0.20201109200316-afdc16ba66df
github.com/cri-o/ocicni/pkg/ocicni github.com/cri-o/ocicni/pkg/ocicni
# github.com/cyphar/filepath-securejoin v0.2.2 # github.com/cyphar/filepath-securejoin v0.2.2
github.com/cyphar/filepath-securejoin github.com/cyphar/filepath-securejoin