Merge pull request #825 from abhi/cni_config

Change to keep in sync with latest cni config
This commit is contained in:
Lantao Liu 2018-06-21 16:14:31 -07:00 committed by GitHub
commit 4eb4a29577
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 122 additions and 131 deletions

View File

@ -148,7 +148,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi
// Try to load the config if it exists. Just log the error if load fails // Try to load the config if it exists. Just log the error if load fails
// This is not disruptive for containerd to panic // This is not disruptive for containerd to panic
if err := c.netPlugin.Load(cni.WithLoNetwork(), cni.WithDefaultConf()); err != nil { if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err != nil {
logrus.WithError(err).Error("Failed to load cni during init, please check CRI plugin status before setting up network for pods") logrus.WithError(err).Error("Failed to load cni during init, please check CRI plugin status before setting up network for pods")
} }
// prepare streaming server // prepare streaming server

View File

@ -22,6 +22,7 @@ import (
goruntime "runtime" goruntime "runtime"
cni "github.com/containerd/go-cni" cni "github.com/containerd/go-cni"
"github.com/sirupsen/logrus"
"golang.org/x/net/context" "golang.org/x/net/context"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
) )
@ -41,14 +42,16 @@ func (c *criService) Status(ctx context.Context, r *runtime.StatusRequest) (*run
Type: runtime.NetworkReady, Type: runtime.NetworkReady,
Status: true, Status: true,
} }
// Load the latest cni configuration to be in sync with the latest network configuration
if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err != nil {
logrus.WithError(err).Errorf("Failed to load cni configuration")
}
// Check the status of the cni initialization // Check the status of the cni initialization
if err := c.netPlugin.Status(); err != nil { if err := c.netPlugin.Status(); err != nil {
// If it is not initialized, then load the config and retry networkCondition.Status = false
if err = c.netPlugin.Load(cni.WithLoNetwork(), cni.WithDefaultConf()); err != nil { networkCondition.Reason = networkNotReadyReason
networkCondition.Status = false networkCondition.Message = fmt.Sprintf("Network plugin returns error: %v", err)
networkCondition.Reason = networkNotReadyReason
networkCondition.Message = fmt.Sprintf("Network plugin returns error: %v", err)
}
} }
resp := &runtime.StatusResponse{ resp := &runtime.StatusResponse{

View File

@ -47,6 +47,6 @@ func (f *FakeCNIPlugin) Status() error {
} }
// Load loads the network config. // Load loads the network config.
func (f *FakeCNIPlugin) Load(opts ...cni.LoadOption) error { func (f *FakeCNIPlugin) Load(opts ...cni.CNIOpt) error {
return f.LoadErr return f.LoadErr
} }

View File

@ -52,7 +52,7 @@ func (c *criService) UpdateRuntimeConfig(ctx context.Context, r *runtime.UpdateR
if err := c.netPlugin.Status(); err == nil { if err := c.netPlugin.Status(); err == nil {
logrus.Infof("Network plugin is ready, skip generating cni config from template %q", confTemplate) logrus.Infof("Network plugin is ready, skip generating cni config from template %q", confTemplate)
return &runtime.UpdateRuntimeConfigResponse{}, nil return &runtime.UpdateRuntimeConfigResponse{}, nil
} else if err := c.netPlugin.Load(cni.WithLoNetwork(), cni.WithDefaultConf()); err == nil { } else if err := c.netPlugin.Load(cni.WithLoNetwork, cni.WithDefaultConf); err == nil {
logrus.Infof("CNI config is successfully loaded, skip generating cni config from template %q", confTemplate) logrus.Infof("CNI config is successfully loaded, skip generating cni config from template %q", confTemplate)
return &runtime.UpdateRuntimeConfigResponse{}, nil return &runtime.UpdateRuntimeConfigResponse{}, nil
} }

View File

@ -7,7 +7,7 @@ github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
github.com/containerd/containerd 84bebdd91d347c99069d1705b7d4e6d6f746160c github.com/containerd/containerd 84bebdd91d347c99069d1705b7d4e6d6f746160c
github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/go-cni f2d7272f12d045b16ed924f50e91f9f9cecc55a7 github.com/containerd/go-cni 5882530828ecf62032409b298a3e8b19e08b6534
github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5 github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/containernetworking/cni v0.6.0 github.com/containernetworking/cni v0.6.0

View File

@ -1,7 +1,10 @@
[![Build Status](https://travis-ci.org/containerd/go-cni.svg?branch=master)](https://travis-ci.org/containerd/go-cni)
# go-cni # go-cni
A generic CNI library to provide APIs for CNI plugin interactions. The library provides APIs to: A generic CNI library to provide APIs for CNI plugin interactions. The library provides APIs to:
- Load CNI network config from different sources
- Setup networks for container namespace - Setup networks for container namespace
- Remove networks from container namespace - Remove networks from container namespace
- Query status of CNI network plugin initialization - Query status of CNI network plugin initialization
@ -16,11 +19,17 @@ func main() {
defaultIfName := "eth0" defaultIfName := "eth0"
// Initialize library // Initialize library
l = gocni.New(gocni.WithMinNetworkCount(2), l = gocni.New(gocni.WithMinNetworkCount(2),
gocni.WithLoNetwork(),
gocni.WithPluginConfDir("/etc/mycni/net.d"), gocni.WithPluginConfDir("/etc/mycni/net.d"),
gocni.WithPluginDir([]string{"/opt/mycni/bin", "/opt/cni/bin"}), gocni.WithPluginDir([]string{"/opt/mycni/bin", "/opt/cni/bin"}),
gocni.WithDefaultIfName(defaultIfName)) gocni.WithDefaultIfName(defaultIfName))
// Load the cni configuration
err:= l.Load(gocni.WithLoNetwork,gocni.WithDefaultConf)
if err != nil{
log.Errorf("failed to load cni configuration: %v", err)
return
}
// Setup network for namespace. // Setup network for namespace.
labels := map[string]string{ labels := map[string]string{
"K8S_POD_NAMESPACE": "namespace1", "K8S_POD_NAMESPACE": "namespace1",
@ -29,16 +38,10 @@ func main() {
} }
result, err := l.Setup(id, netns, gocni.WithLabels(labels)) result, err := l.Setup(id, netns, gocni.WithLabels(labels))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to setup network for namespace %q: %v", id, err) log.Errorf("failed to setup network for namespace %q: %v",id, err)
return
} }
defer func() {
if retErr != nil {
// Teardown network if an error is returned.
if err := l.Remove(id, netns, gocni.WithLabels(labels)); err != nil {
fmt.Errorf("Failed to destroy network for namespace %q", id)
}
}
}()
// Get IP of the default interface // Get IP of the default interface
IP := result.Interfaces[defaultIfName].IPConfigs[0].IP.String() IP := result.Interfaces[defaultIfName].IPConfigs[0].IP.String()
fmt.Printf("IP of the default interface %s:%s", defaultIfName, IP) fmt.Printf("IP of the default interface %s:%s", defaultIfName, IP)

View File

@ -31,7 +31,7 @@ type CNI interface {
// Remove tears down the network of the namespace. // Remove tears down the network of the namespace.
Remove(id string, path string, opts ...NamespaceOpts) error Remove(id string, path string, opts ...NamespaceOpts) error
// Load loads the cni network config // Load loads the cni network config
Load(opts ...LoadOption) error Load(opts ...CNIOpt) error
// Status checks the status of the cni initialization // Status checks the status of the cni initialization
Status() error Status() error
} }
@ -59,7 +59,7 @@ func defaultCNIConfig() *libcni {
} }
} }
func New(config ...ConfigOption) (CNI, error) { func New(config ...CNIOpt) (CNI, error) {
cni := defaultCNIConfig() cni := defaultCNIConfig()
var err error var err error
for _, c := range config { for _, c := range config {
@ -70,8 +70,10 @@ func New(config ...ConfigOption) (CNI, error) {
return cni, nil return cni, nil
} }
func (c *libcni) Load(opts ...LoadOption) error { func (c *libcni) Load(opts ...CNIOpt) error {
var err error var err error
c.Lock()
defer c.Unlock()
// Reset the networks on a load operation to ensure // Reset the networks on a load operation to ensure
// config happens on a clean slate // config happens on a clean slate
c.reset() c.reset()
@ -81,30 +83,27 @@ func (c *libcni) Load(opts ...LoadOption) error {
return errors.Wrapf(ErrLoad, fmt.Sprintf("cni config load failed: %v", err)) return errors.Wrapf(ErrLoad, fmt.Sprintf("cni config load failed: %v", err))
} }
} }
return c.Status() return nil
} }
func (c *libcni) Status() error { func (c *libcni) Status() error {
c.RLock() c.RLock()
defer c.RUnlock() defer c.RUnlock()
if len(c.networks) < c.networkCount { return c.status()
return ErrCNINotInitialized
}
return nil
} }
// Setup setups the network in the namespace // Setup setups the network in the namespace
func (c *libcni) Setup(id string, path string, opts ...NamespaceOpts) (*CNIResult, error) { func (c *libcni) Setup(id string, path string, opts ...NamespaceOpts) (*CNIResult, error) {
if err:=c.Status();err!=nil{ c.RLock()
return nil,err defer c.RUnlock()
if err := c.status(); err != nil {
return nil, err
} }
ns, err := newNamespace(id, path, opts...) ns, err := newNamespace(id, path, opts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var results []*current.Result var results []*current.Result
c.RLock()
defer c.RUnlock()
for _, network := range c.networks { for _, network := range c.networks {
r, err := network.Attach(ns) r, err := network.Attach(ns)
if err != nil { if err != nil {
@ -117,15 +116,15 @@ func (c *libcni) Setup(id string, path string, opts ...NamespaceOpts) (*CNIResul
// Remove removes the network config from the namespace // Remove removes the network config from the namespace
func (c *libcni) Remove(id string, path string, opts ...NamespaceOpts) error { func (c *libcni) Remove(id string, path string, opts ...NamespaceOpts) error {
if err:=c.Status();err!=nil{ c.RLock()
return err defer c.RUnlock()
} if err := c.status(); err != nil {
return err
}
ns, err := newNamespace(id, path, opts...) ns, err := newNamespace(id, path, opts...)
if err != nil { if err != nil {
return err return err
} }
c.RLock()
defer c.RUnlock()
for _, network := range c.networks { for _, network := range c.networks {
if err := network.Remove(ns); err != nil { if err := network.Remove(ns); err != nil {
return err return err
@ -135,7 +134,12 @@ func (c *libcni) Remove(id string, path string, opts ...NamespaceOpts) error {
} }
func (c *libcni) reset() { func (c *libcni) reset() {
c.Lock()
defer c.Unlock()
c.networks = nil c.networks = nil
} }
func (c *libcni) status() error {
if len(c.networks) < c.networkCount {
return ErrCNINotInitialized
}
return nil
}

View File

@ -24,11 +24,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
type ConfigOption func(c *libcni) error type CNIOpt func(c *libcni) error
// WithInterfacePrefix sets the prefix for network interfaces // WithInterfacePrefix sets the prefix for network interfaces
// e.g. eth or wlan // e.g. eth or wlan
func WithInterfacePrefix(prefix string) ConfigOption { func WithInterfacePrefix(prefix string) CNIOpt {
return func(c *libcni) error { return func(c *libcni) error {
c.prefix = prefix c.prefix = prefix
return nil return nil
@ -37,7 +37,7 @@ func WithInterfacePrefix(prefix string) ConfigOption {
// WithPluginDir can be used to set the locations of // WithPluginDir can be used to set the locations of
// the cni plugin binaries // the cni plugin binaries
func WithPluginDir(dirs []string) ConfigOption { func WithPluginDir(dirs []string) CNIOpt {
return func(c *libcni) error { return func(c *libcni) error {
c.pluginDirs = dirs c.pluginDirs = dirs
c.cniConfig = &cnilibrary.CNIConfig{Path: dirs} c.cniConfig = &cnilibrary.CNIConfig{Path: dirs}
@ -47,7 +47,7 @@ func WithPluginDir(dirs []string) ConfigOption {
// WithPluginConfDir can be used to configure the // WithPluginConfDir can be used to configure the
// cni configuration directory. // cni configuration directory.
func WithPluginConfDir(dir string) ConfigOption { func WithPluginConfDir(dir string) CNIOpt {
return func(c *libcni) error { return func(c *libcni) error {
c.pluginConfDir = dir c.pluginConfDir = dir
return nil return nil
@ -57,23 +57,17 @@ func WithPluginConfDir(dir string) ConfigOption {
// WithMinNetworkCount can be used to configure the // WithMinNetworkCount can be used to configure the
// minimum networks to be configured and initalized // minimum networks to be configured and initalized
// for the status to report success. By default its 1. // for the status to report success. By default its 1.
func WithMinNetworkCount(count int) ConfigOption { func WithMinNetworkCount(count int) CNIOpt {
return func(c *libcni) error { return func(c *libcni) error {
c.networkCount = count c.networkCount = count
return nil return nil
} }
} }
// LoadOption can be used with Load API
// to load network configuration from different
// sources.
type LoadOption func(c *libcni) error
// WithLoNetwork can be used to load the loopback // WithLoNetwork can be used to load the loopback
// network config. // network config.
func WithLoNetwork() LoadOption { func WithLoNetwork(c *libcni) error {
return func(c *libcni) error { loConfig, _ := cnilibrary.ConfListFromBytes([]byte(`{
loConfig, _ := cnilibrary.ConfListFromBytes([]byte(`{
"cniVersion": "0.3.1", "cniVersion": "0.3.1",
"name": "cni-loopback", "name": "cni-loopback",
"plugins": [{ "plugins": [{
@ -81,20 +75,17 @@ func WithLoNetwork() LoadOption {
}] }]
}`)) }`))
c.Lock() c.networks = append(c.networks, &Network{
defer c.Unlock() cni: c.cniConfig,
c.networks = append(c.networks,&Network{ config: loConfig,
cni: c.cniConfig, ifName: "lo",
config: loConfig, })
ifName: "lo", return nil
})
return nil
}
} }
// WithConf can be used to load config directly // WithConf can be used to load config directly
// from byte. // from byte.
func WithConf(bytes []byte) LoadOption { func WithConf(bytes []byte) CNIOpt {
return func(c *libcni) error { return func(c *libcni) error {
conf, err := cnilibrary.ConfFromBytes(bytes) conf, err := cnilibrary.ConfFromBytes(bytes)
if err != nil { if err != nil {
@ -104,8 +95,6 @@ func WithConf(bytes []byte) LoadOption {
if err != nil { if err != nil {
return err return err
} }
c.Lock()
defer c.Unlock()
c.networks = append(c.networks, &Network{ c.networks = append(c.networks, &Network{
cni: c.cniConfig, cni: c.cniConfig,
config: confList, config: confList,
@ -118,7 +107,7 @@ func WithConf(bytes []byte) LoadOption {
// WithConfFile can be used to load network config // WithConfFile can be used to load network config
// from an .conf file. Supported with absolute fileName // from an .conf file. Supported with absolute fileName
// with path only. // with path only.
func WithConfFile(fileName string) LoadOption { func WithConfFile(fileName string) CNIOpt {
return func(c *libcni) error { return func(c *libcni) error {
conf, err := cnilibrary.ConfFromFile(fileName) conf, err := cnilibrary.ConfFromFile(fileName)
if err != nil { if err != nil {
@ -129,8 +118,6 @@ func WithConfFile(fileName string) LoadOption {
if err != nil { if err != nil {
return err return err
} }
c.Lock()
defer c.Unlock()
c.networks = append(c.networks, &Network{ c.networks = append(c.networks, &Network{
cni: c.cniConfig, cni: c.cniConfig,
config: confList, config: confList,
@ -143,15 +130,13 @@ func WithConfFile(fileName string) LoadOption {
// WithConfListFile can be used to load network config // WithConfListFile can be used to load network config
// from an .conflist file. Supported with absolute fileName // from an .conflist file. Supported with absolute fileName
// with path only. // with path only.
func WithConfListFile(fileName string) LoadOption { func WithConfListFile(fileName string) CNIOpt {
return func(c *libcni) error { return func(c *libcni) error {
confList, err := cnilibrary.ConfListFromFile(fileName) confList, err := cnilibrary.ConfListFromFile(fileName)
if err != nil { if err != nil {
return err return err
} }
c.Lock() c.networks = append(c.networks, &Network{
defer c.Unlock()
c.networks = append(c.networks,&Network{
cni: c.cniConfig, cni: c.cniConfig,
config: confList, config: confList,
ifName: getIfName(c.prefix, 0), ifName: getIfName(c.prefix, 0),
@ -163,64 +148,60 @@ func WithConfListFile(fileName string) LoadOption {
// WithDefaultConf can be used to detect network config // WithDefaultConf can be used to detect network config
// files from the configured cni config directory and load // files from the configured cni config directory and load
// them. // them.
func WithDefaultConf() LoadOption { func WithDefaultConf(c *libcni) error {
return func(c *libcni) error { files, err := cnilibrary.ConfFiles(c.pluginConfDir, []string{".conf", ".conflist", ".json"})
files, err := cnilibrary.ConfFiles(c.pluginConfDir, []string{".conf", ".conflist", ".json"}) switch {
switch { case err != nil:
case err != nil: return errors.Wrapf(ErrRead, "failed to read config file: %v", err)
return errors.Wrapf(ErrRead, "failed to read config file: %v", err) case len(files) == 0:
case len(files) == 0: return errors.Wrapf(ErrCNINotInitialized, "no network config found in %s", c.pluginConfDir)
return errors.Wrapf(ErrCNINotInitialized, "no network config found in %s", c.pluginConfDir)
}
// files contains the network config files associated with cni network.
// Use lexicographical way as a defined order for network config files.
sort.Strings(files)
// Since the CNI spec does not specify a way to detect default networks,
// the convention chosen is - the first network configuration in the sorted
// list of network conf files as the default network and choose the default
// interface provided during init as the network interface for this default
// network. For every other network use a generated interface id.
i := 0
c.Lock()
defer c.Unlock()
for _, confFile := range files {
var confList *cnilibrary.NetworkConfigList
if strings.HasSuffix(confFile, ".conflist") {
confList, err = cnilibrary.ConfListFromFile(confFile)
if err != nil {
return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config list file %s: %v", confFile, err)
}
} else {
conf, err := cnilibrary.ConfFromFile(confFile)
if err != nil {
return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config file %s: %v", confFile, err)
}
// Ensure the config has a "type" so we know what plugin to run.
// Also catches the case where somebody put a conflist into a conf file.
if conf.Network.Type == "" {
return errors.Wrapf(ErrInvalidConfig, "network type not found in %s", confFile)
}
confList, err = cnilibrary.ConfListFromConf(conf)
if err != nil {
return errors.Wrapf(ErrInvalidConfig, "failed to convert CNI config file %s to list: %v", confFile, err)
}
}
if len(confList.Plugins) == 0 {
return errors.Wrapf(ErrInvalidConfig, "CNI config list %s has no networks, skipping", confFile)
}
c.networks = append(c.networks, &Network{
cni: c.cniConfig,
config: confList,
ifName: getIfName(c.prefix, i),
})
i++
}
if len(c.networks) == 0 {
return errors.Wrapf(ErrCNINotInitialized, "no valid networks found in %s", c.pluginDirs)
}
return nil
} }
// files contains the network config files associated with cni network.
// Use lexicographical way as a defined order for network config files.
sort.Strings(files)
// Since the CNI spec does not specify a way to detect default networks,
// the convention chosen is - the first network configuration in the sorted
// list of network conf files as the default network and choose the default
// interface provided during init as the network interface for this default
// network. For every other network use a generated interface id.
i := 0
for _, confFile := range files {
var confList *cnilibrary.NetworkConfigList
if strings.HasSuffix(confFile, ".conflist") {
confList, err = cnilibrary.ConfListFromFile(confFile)
if err != nil {
return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config list file %s: %v", confFile, err)
}
} else {
conf, err := cnilibrary.ConfFromFile(confFile)
if err != nil {
return errors.Wrapf(ErrInvalidConfig, "failed to load CNI config file %s: %v", confFile, err)
}
// Ensure the config has a "type" so we know what plugin to run.
// Also catches the case where somebody put a conflist into a conf file.
if conf.Network.Type == "" {
return errors.Wrapf(ErrInvalidConfig, "network type not found in %s", confFile)
}
confList, err = cnilibrary.ConfListFromConf(conf)
if err != nil {
return errors.Wrapf(ErrInvalidConfig, "failed to convert CNI config file %s to list: %v", confFile, err)
}
}
if len(confList.Plugins) == 0 {
return errors.Wrapf(ErrInvalidConfig, "CNI config list %s has no networks, skipping", confFile)
}
c.networks = append(c.networks, &Network{
cni: c.cniConfig,
config: confList,
ifName: getIfName(c.prefix, i),
})
i++
}
if len(c.networks) == 0 {
return errors.Wrapf(ErrCNINotInitialized, "no valid networks found in %s", c.pluginDirs)
}
return nil
} }