2016-12-01 05:00:08 +03:00
|
|
|
// 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.
|
2016-12-06 22:17:47 +03:00
|
|
|
err = plugin.am.Initialize(config, plugin.Options)
|
2016-12-01 05:00:08 +03:00
|
|
|
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},
|
|
|
|
}
|
|
|
|
|
2016-12-02 00:29:23 +03:00
|
|
|
result.Print()
|
2016-12-01 05:00:08 +03:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
// 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)
|
2016-12-02 00:29:23 +03:00
|
|
|
return nil
|
2016-12-01 05:00:08 +03:00
|
|
|
}
|
|
|
|
} 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)
|
2016-12-02 00:29:23 +03:00
|
|
|
return nil
|
2016-12-01 05:00:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-02 00:29:23 +03:00
|
|
|
log.Printf("[ipam] DEL succeeded.")
|
|
|
|
|
|
|
|
return err
|
2016-12-01 05:00:08 +03:00
|
|
|
}
|