This commit is contained in:
Onur Filiz 2016-11-30 18:00:08 -08:00
Родитель 8a9e48265c
Коммит bae7072fa4
4 изменённых файлов: 685 добавлений и 0 удалений

54
cni/cni.go Normal file
Просмотреть файл

@ -0,0 +1,54 @@
// Copyright Microsoft Corp.
// All rights reserved.
package cni
import (
"encoding/json"
cniSkel "github.com/containernetworking/cni/pkg/skel"
cniTypes "github.com/containernetworking/cni/pkg/types"
)
// Plugin is the interface implemented by CNI plugins.
type Plugin interface {
Add(args *cniSkel.CmdArgs) error
Delete(args *cniSkel.CmdArgs) error
AddImpl(args *cniSkel.CmdArgs, nwCfg *NetworkConfig) (*cniTypes.Result, error)
DeleteImpl(args *cniSkel.CmdArgs, nwCfg *NetworkConfig) (*cniTypes.Result, error)
}
// NetworkConfig represents the Azure CNI plugin's network configuration.
type NetworkConfig struct {
CniVersion string `json:"cniVersion"`
Name string `json:"name"`
Type string `json:"type"`
Bridge string `json:"bridge"`
IfName string `json:"ifName"`
Ipam struct {
Type string `json:"type"`
AddrSpace string `json:"addressSpace"`
Subnet string `json:"subnet"`
Address string `json:"ipAddress"`
Result string `json:"result"`
}
}
// ParseNetworkConfig unmarshals network configuration from bytes.
func ParseNetworkConfig(b []byte) (*NetworkConfig, error) {
nwCfg := NetworkConfig{}
err := json.Unmarshal(b, &nwCfg)
if err != nil {
return nil, err
}
return &nwCfg, nil
}
// Serialize marshals a network configuration to bytes.
func (nwcfg *NetworkConfig) Serialize() []byte {
bytes, _ := json.Marshal(nwcfg)
return bytes
}

253
cni/ipam/ipam.go Normal file
Просмотреть файл

@ -0,0 +1,253 @@
// Copyright Microsoft Corp.
// All rights reserved.
package ipam
import (
"net"
"github.com/Azure/azure-container-networking/cni"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/ipam"
"github.com/Azure/azure-container-networking/log"
cniSkel "github.com/containernetworking/cni/pkg/skel"
cniTypes "github.com/containernetworking/cni/pkg/types"
)
const (
// Plugin name.
name = "ipam"
// The default address space ID used when an explicit ID is not specified.
defaultAddressSpaceId = "LocalDefaultAddressSpace"
)
// IpamPlugin represents a CNI IPAM plugin.
type ipamPlugin struct {
*common.Plugin
am ipam.AddressManager
}
// NewPlugin creates a new ipamPlugin object.
func NewPlugin(config *common.PluginConfig) (*ipamPlugin, error) {
// Setup base plugin.
plugin, err := common.NewPlugin(name, config.Version)
if err != nil {
return nil, err
}
// Setup address manager.
am, err := ipam.NewAddressManager()
if err != nil {
return nil, err
}
config.IpamApi = am
return &ipamPlugin{
Plugin: plugin,
am: am,
}, nil
}
// Starts the plugin.
func (plugin *ipamPlugin) Start(config *common.PluginConfig) error {
// Initialize base plugin.
err := plugin.Initialize(config)
if err != nil {
log.Printf("[ipam] Failed to initialize base plugin, err:%v.", err)
return err
}
// Initialize address manager.
environment := plugin.GetOption(common.OptEnvironmentKey)
err = plugin.am.Initialize(config, environment)
if err != nil {
log.Printf("[ipam] Failed to initialize address manager, err:%v.", err)
return err
}
log.Printf("[ipam] Plugin started.")
return nil
}
// Stops the plugin.
func (plugin *ipamPlugin) Stop() {
plugin.am.Uninitialize()
plugin.Uninitialize()
log.Printf("[ipam] Plugin stopped.")
}
//
// CNI implementation
// https://github.com/containernetworking/cni/blob/master/SPEC.md
//
// Add handles CNI add commands.
func (plugin *ipamPlugin) Add(args *cniSkel.CmdArgs) error {
log.Printf("[ipam] Processing ADD command with args {ContainerID:%v Netns:%v IfName:%v Args:%v Path:%v}.",
args.ContainerID, args.Netns, args.IfName, args.Args, args.Path)
// Parse network configuration from stdin.
nwCfg, err := cni.ParseNetworkConfig(args.StdinData)
if err != nil {
log.Printf("[ipam] Failed to parse network configuration: %v.", err)
return nil
}
log.Printf("[ipam] Read network configuration %+v.", nwCfg)
// Assume default address space if not specified.
if nwCfg.Ipam.AddrSpace == "" {
nwCfg.Ipam.AddrSpace = defaultAddressSpaceId
}
// Check if an address pool is specified.
if nwCfg.Ipam.Subnet == "" {
// Allocate an address pool.
poolId, subnet, err := plugin.am.RequestPool(nwCfg.Ipam.AddrSpace, "", "", nil, false)
if err != nil {
log.Printf("[ipam] Failed to allocate pool, err:%v.", err)
return nil
}
nwCfg.Ipam.Subnet = subnet
log.Printf("[ipam] Allocated address poolId %v with subnet %v.", poolId, subnet)
}
// Allocate an address for the endpoint.
address, err := plugin.am.RequestAddress(nwCfg.Ipam.AddrSpace, nwCfg.Ipam.Subnet, nwCfg.Ipam.Address, nil)
if err != nil {
log.Printf("[ipam] Failed to allocate address, err:%v.", err)
return nil
}
log.Printf("[ipam] Allocated address %v.", address)
// Output the result.
ip, cidr, err := net.ParseCIDR(address)
cidr.IP = ip
if err != nil {
log.Printf("[ipam] Failed to parse address, err:%v.", err)
return nil
}
result := &cniTypes.Result{
IP4: &cniTypes.IPConfig{IP: *cidr},
}
// Output response.
if nwCfg.Ipam.Result == "" {
result.Print()
} else {
args.Args = result.String()
}
log.Printf("[ipam] ADD succeeded with output %+v.", result)
return err
}
// Delete handles CNI delete commands.
func (plugin *ipamPlugin) Delete(args *cniSkel.CmdArgs) error {
log.Printf("[ipam] Processing DEL command with args {ContainerID:%v Netns:%v IfName:%v Args:%v Path:%v}.",
args.ContainerID, args.Netns, args.IfName, args.Args, args.Path)
// Parse network configuration from stdin.
nwCfg, err := cni.ParseNetworkConfig(args.StdinData)
if err != nil {
log.Printf("[ipam] Failed to parse network configuration: %v.", err)
return nil
}
log.Printf("[ipam] Read network configuration %+v.", nwCfg)
// Process command.
result, err := plugin.DeleteImpl(args, nwCfg)
if err != nil {
log.Printf("[ipam] Failed to process command: %v.", err)
return nil
}
// Output response.
if result != nil {
result.Print()
}
log.Printf("[ipam] DEL succeeded with output %+v.", result)
return err
}
// AddImpl handles CNI add commands.
func (plugin *ipamPlugin) AddImpl(args *cniSkel.CmdArgs, nwCfg *cni.NetworkConfig) (*cniTypes.Result, error) {
// Assume default address space if not specified.
if nwCfg.Ipam.AddrSpace == "" {
nwCfg.Ipam.AddrSpace = defaultAddressSpaceId
}
// Check if an address pool is specified.
if nwCfg.Ipam.Subnet == "" {
// Allocate an address pool.
poolId, subnet, err := plugin.am.RequestPool(nwCfg.Ipam.AddrSpace, "", "", nil, false)
if err != nil {
log.Printf("[ipam] Failed to allocate pool, err:%v.", err)
return nil, err
}
nwCfg.Ipam.Subnet = subnet
log.Printf("[ipam] Allocated address poolId %v with subnet %v.", poolId, subnet)
}
// Allocate an address for the endpoint.
address, err := plugin.am.RequestAddress(nwCfg.Ipam.AddrSpace, nwCfg.Ipam.Subnet, nwCfg.Ipam.Address, nil)
if err != nil {
log.Printf("[ipam] Failed to allocate address, err:%v.", err)
return nil, err
}
log.Printf("[ipam] Allocated address %v.", address)
// Output the result.
ip, cidr, err := net.ParseCIDR(address)
cidr.IP = ip
if err != nil {
log.Printf("[ipam] Failed to parse address, err:%v.", err)
return nil, err
}
result := &cniTypes.Result{
IP4: &cniTypes.IPConfig{IP: *cidr},
}
return result, nil
}
// DeleteImpl handles CNI delete commands.
func (plugin *ipamPlugin) DeleteImpl(args *cniSkel.CmdArgs, nwCfg *cni.NetworkConfig) (*cniTypes.Result, error) {
// Assume default address space if not specified.
if nwCfg.Ipam.AddrSpace == "" {
nwCfg.Ipam.AddrSpace = defaultAddressSpaceId
}
// If an address is specified, release that address. Otherwise, release the pool.
if nwCfg.Ipam.Address != "" {
// Release the address.
err := plugin.am.ReleaseAddress(nwCfg.Ipam.AddrSpace, nwCfg.Ipam.Subnet, nwCfg.Ipam.Address)
if err != nil {
log.Printf("[cni] Failed to release address, err:%v.", err)
return nil, err
}
} else {
// Release the pool.
err := plugin.am.ReleasePool(nwCfg.Ipam.AddrSpace, nwCfg.Ipam.Subnet)
if err != nil {
log.Printf("[cni] Failed to release pool, err:%v.", err)
return nil, err
}
}
return nil, nil
}

250
cni/network/network.go Normal file
Просмотреть файл

@ -0,0 +1,250 @@
// Copyright Microsoft Corp.
// All rights reserved.
package network
import (
"net"
"github.com/Azure/azure-container-networking/cni"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/ipam"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/network"
cniSkel "github.com/containernetworking/cni/pkg/skel"
cniTypes "github.com/containernetworking/cni/pkg/types"
)
const (
// Plugin name.
name = "net"
// The default address space ID used when an explicit ID is not specified.
defaultAddressSpaceId = "LocalDefaultAddressSpace"
)
// NetPlugin object and its interface
type netPlugin struct {
*common.Plugin
nm network.NetworkManager
am ipam.AddressManager
}
// NewPlugin creates a new netPlugin object.
func NewPlugin(config *common.PluginConfig) (*netPlugin, error) {
// Setup base plugin.
plugin, err := common.NewPlugin(name, config.Version)
if err != nil {
return nil, err
}
// Setup network manager.
nm, err := network.NewNetworkManager()
if err != nil {
return nil, err
}
config.NetApi = nm
return &netPlugin{
Plugin: plugin,
nm: nm,
}, nil
}
// Starts the plugin.
func (plugin *netPlugin) Start(config *common.PluginConfig) error {
// Initialize base plugin.
err := plugin.Initialize(config)
if err != nil {
log.Printf("[net] Failed to initialize base plugin, err:%v.", err)
return err
}
// Initialize network manager.
err = plugin.nm.Initialize(config)
if err != nil {
log.Printf("[net] Failed to initialize network manager, err:%v.", err)
return err
}
plugin.am, _ = config.IpamApi.(ipam.AddressManager)
log.Printf("[net] Plugin started.")
return nil
}
// Stops the plugin.
func (plugin *netPlugin) Stop() {
plugin.nm.Uninitialize()
plugin.Uninitialize()
log.Printf("[net] Plugin stopped.")
}
//
// CNI implementation
// https://github.com/containernetworking/cni/blob/master/SPEC.md
//
// Add handles CNI add commands.
func (plugin *netPlugin) Add(args *cniSkel.CmdArgs) error {
log.Printf("[cni] Processing ADD command with args {ContainerID:%v Netns:%v IfName:%v Args:%v Path:%v}.",
args.ContainerID, args.Netns, args.IfName, args.Args, args.Path)
// Parse network configuration from stdin.
nwCfg, err := cni.ParseNetworkConfig(args.StdinData)
if err != nil {
log.Printf("[cni] Failed to parse network configuration, err:%v.", err)
return nil
}
log.Printf("[cni] Read network configuration %+v.", nwCfg)
// Assume default address space if not specified.
if nwCfg.Ipam.AddrSpace == "" {
nwCfg.Ipam.AddrSpace = defaultAddressSpaceId
}
// Initialize values from network config.
var poolId string
var subnet string
networkId := nwCfg.Name
endpointId := args.ContainerID
// Check whether the network already exists.
nwInfo, err := plugin.nm.GetNetworkInfo(networkId)
if err != nil {
// Network does not exist.
log.Printf("[cni] Creating network.")
// Allocate an address pool for the network.
poolId, subnet, err = plugin.am.RequestPool(nwCfg.Ipam.AddrSpace, "", "", nil, false)
if err != nil {
log.Printf("[cni] Failed to allocate pool, err:%v.", err)
return nil
}
log.Printf("[cni] Allocated address pool %v with subnet %v.", poolId, subnet)
// Create the network.
nwInfo := network.NetworkInfo{
Id: networkId,
Subnets: []string{subnet},
BridgeName: nwCfg.Bridge,
}
err = plugin.nm.CreateNetwork(&nwInfo)
if err != nil {
log.Printf("[cni] Failed to create network, err:%v.", err)
return nil
}
log.Printf("[cni] Created network %v with subnet %v.", networkId, subnet)
} else {
// Network already exists.
log.Printf("[cni] Reusing network and pool.")
// Query address pool.
poolId = nwInfo.Subnets[0]
subnet = nwInfo.Subnets[0]
}
// Allocate an address for the endpoint.
address, err := plugin.am.RequestAddress(nwCfg.Ipam.AddrSpace, poolId, "", nil)
if err != nil {
log.Printf("[cni] Failed to request address, err:%v.", err)
return nil
}
log.Printf("[cni] Allocated address: %v", address)
// Create the endpoint.
epInfo := network.EndpointInfo{
Id: endpointId,
IfName: args.IfName,
IPv4Address: address,
NetNsPath: args.Netns,
}
err = plugin.nm.CreateEndpoint(networkId, &epInfo)
if err != nil {
log.Printf("[cni] Failed to create endpoint, err:%v.", err)
return nil
}
// Output the result.
ip, cidr, err := net.ParseCIDR(address)
cidr.IP = ip
if err != nil {
log.Printf("[cni] Failed to parse address, err:%v.", err)
return nil
}
result := &cniTypes.Result{
IP4: &cniTypes.IPConfig{IP: *cidr},
}
result.Print()
log.Printf("[cni] ADD succeeded with output %+v.", result)
return nil
}
// Delete handles CNI delete commands.
func (plugin *netPlugin) Delete(args *cniSkel.CmdArgs) error {
log.Printf("[cni] Processing DEL command with args {ContainerID:%v Netns:%v IfName:%v Args:%v Path:%v}.",
args.ContainerID, args.Netns, args.IfName, args.Args, args.Path)
// Parse network configuration from stdin.
nwCfg, err := cni.ParseNetworkConfig(args.StdinData)
if err != nil {
log.Printf("[cni] Failed to parse network configuration, err:%v.", err)
return nil
}
log.Printf("[cni] Read network configuration %+v.", nwCfg)
// Assume default address space if not specified.
if nwCfg.Ipam.AddrSpace == "" {
nwCfg.Ipam.AddrSpace = defaultAddressSpaceId
}
// Initialize values from network config.
networkId := nwCfg.Name
endpointId := args.ContainerID
// Query the network.
nwInfo, err := plugin.nm.GetNetworkInfo(networkId)
if err != nil {
log.Printf("[cni] Failed to query network, err:%v.", err)
return nil
}
// Query the endpoint.
epInfo, err := plugin.nm.GetEndpointInfo(networkId, endpointId)
if err != nil {
log.Printf("[cni] Failed to query endpoint, err:%v.", err)
return nil
}
// Delete the endpoint.
err = plugin.nm.DeleteEndpoint(networkId, endpointId)
if err != nil {
log.Printf("[cni] Failed to delete endpoint, err:%v.", err)
return nil
}
// Release the address.
err = plugin.am.ReleaseAddress(nwCfg.Ipam.AddrSpace, nwInfo.Subnets[0], epInfo.IPv4Address)
if err != nil {
log.Printf("[cni] Failed to release address, err:%v.", err)
return nil
}
log.Printf("[cni] DEL succeeded.")
return nil
}

128
cni/plugin/main.go Normal file
Просмотреть файл

@ -0,0 +1,128 @@
// Copyright Microsoft Corp.
// All rights reserved.
package main
import (
"fmt"
"github.com/Azure/azure-container-networking/cni/ipam"
"github.com/Azure/azure-container-networking/cni/network"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/store"
cniSkel "github.com/containernetworking/cni/pkg/skel"
cniVers "github.com/containernetworking/cni/pkg/version"
)
const (
// Plugin name.
name = "azure-cni-plugin"
// CNI version supported by this plugin.
cniVersion = "0.2.0"
// Plugin execution environment.
environment = "azure"
// JSON file for storing state.
storeFileName = "/etc/cni/azure-container-networking.json"
)
// Version is populated by make during build.
var version string
// Main is the entry point for CNI plugin.
func main() {
// Initialize plugin common configuration.
var config common.PluginConfig
config.Name = name
config.Version = version
// Create network plugin.
netPlugin, err := network.NewPlugin(&config)
if err != nil {
fmt.Printf("[cni] Failed to create network plugin, err:%v.\n", err)
return
}
// Create IPAM plugin.
ipamPlugin, err := ipam.NewPlugin(&config)
if err != nil {
fmt.Printf("[cni] Failed to create IPAM plugin, err:%v.\n", err)
return
}
// Create a channel to receive unhandled errors from the plugins.
config.ErrChan = make(chan error, 1)
// Create the key value store.
config.Store, err = store.NewJsonFileStore(storeFileName)
if err != nil {
log.Printf("[cni] Failed to create store, err:%v.", err)
return
}
// Acquire store lock.
err = config.Store.Lock(true)
if err != nil {
log.Printf("[cni] Timed out on locking store, err:%v.", err)
return
}
// Create logging provider.
log.SetLevel(log.LevelInfo)
err = log.SetTarget(log.TargetLogfile)
if err != nil {
fmt.Printf("[cni] Failed to configure logging, err:%v.\n", err)
return
}
// Log platform information.
log.Printf("[cni] Plugin enter.")
common.LogPlatformInfo()
common.LogNetworkInterfaces()
// Set plugin options.
ipamPlugin.SetOption(common.OptEnvironmentKey, environment)
// Start plugins.
if netPlugin != nil {
err = netPlugin.Start(&config)
if err != nil {
fmt.Printf("[cni] Failed to start network plugin, err:%v.\n", err)
return
}
}
if ipamPlugin != nil {
err = ipamPlugin.Start(&config)
if err != nil {
fmt.Printf("[cni] Failed to start IPAM plugin, err:%v.\n", err)
return
}
}
// Set supported CNI versions.
pluginInfo := cniVers.PluginSupports(cniVersion)
// Parse args and call the appropriate cmd handler.
cniSkel.PluginMain(netPlugin.Add, netPlugin.Delete, pluginInfo)
// Cleanup.
if netPlugin != nil {
netPlugin.Stop()
}
if ipamPlugin != nil {
ipamPlugin.Stop()
}
err = config.Store.Unlock()
if err != nil {
log.Printf("[cni] Failed to unlock store, err:%v.", err)
}
log.Printf("[cni] Plugin exit.")
}