diff --git a/Dockerfile.cnm b/Dockerfile.cnm deleted file mode 100644 index 98e978be2..000000000 --- a/Dockerfile.cnm +++ /dev/null @@ -1,14 +0,0 @@ -FROM mcr.microsoft.com/oss/mirror/docker.io/library/ubuntu:18.04 -ARG CNM_BUILD_DIR - -# Install dependencies. -RUN apt-get update && apt-get install -y ebtables - -# Create plugins directory. -RUN mkdir -p /run/docker/plugins - -# Install plugin. -COPY $CNM_BUILD_DIR/azure-vnet-plugin /usr/bin -WORKDIR /usr/bin - -CMD ["/usr/bin/azure-vnet-plugin"] diff --git a/Makefile b/Makefile index 4de3cb05d..bedd61f49 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ ZAPAI_VERSION ?= $(notdir $(shell git describe --match "zapai*" --tags --alway # Build directories. AZURE_IPAM_DIR = $(REPO_ROOT)/azure-ipam IPV6_HP_BPF_DIR = $(REPO_ROOT)/bpf-prog/ipv6-hp-bpf -CNM_DIR = $(REPO_ROOT)/cnm/plugin + CNI_NET_DIR = $(REPO_ROOT)/cni/network/plugin CNI_IPAM_DIR = $(REPO_ROOT)/cni/ipam/plugin STATELESS_CNI_NET_DIR = $(REPO_ROOT)/cni/network/stateless @@ -61,7 +61,7 @@ BUILD_DIR = $(OUTPUT_DIR)/$(GOOS)_$(GOARCH) AZURE_IPAM_BUILD_DIR = $(BUILD_DIR)/azure-ipam IPV6_HP_BPF_BUILD_DIR = $(BUILD_DIR)/bpf-prog/ipv6-hp-bpf IMAGE_DIR = $(OUTPUT_DIR)/images -CNM_BUILD_DIR = $(BUILD_DIR)/cnm + CNI_BUILD_DIR = $(BUILD_DIR)/cni ACNCLI_BUILD_DIR = $(BUILD_DIR)/acncli STATELESS_CNI_BUILD_DIR = $(CNI_BUILD_DIR)/stateless @@ -101,7 +101,7 @@ CNI_SWIFT_ARCHIVE_NAME = azure-vnet-cni-swift-$(GOOS)-$(GOARCH)-$(CNI_VERSION).$ CNI_OVERLAY_ARCHIVE_NAME = azure-vnet-cni-overlay-$(GOOS)-$(GOARCH)-$(CNI_VERSION).$(ARCHIVE_EXT) CNI_BAREMETAL_ARCHIVE_NAME = azure-vnet-cni-baremetal-$(GOOS)-$(GOARCH)-$(CNI_VERSION).$(ARCHIVE_EXT) CNI_DUALSTACK_ARCHIVE_NAME = azure-vnet-cni-overlay-dualstack-$(GOOS)-$(GOARCH)-$(CNI_VERSION).$(ARCHIVE_EXT) -CNM_ARCHIVE_NAME = azure-vnet-cnm-$(GOOS)-$(GOARCH)-$(ACN_VERSION).$(ARCHIVE_EXT) + CNS_ARCHIVE_NAME = azure-cns-$(GOOS)-$(GOARCH)-$(CNS_VERSION).$(ARCHIVE_EXT) NPM_ARCHIVE_NAME = azure-npm-$(GOOS)-$(GOARCH)-$(NPM_VERSION).$(ARCHIVE_EXT) AZURE_IPAM_ARCHIVE_NAME = azure-ipam-$(GOOS)-$(GOARCH)-$(AZURE_IPAM_VERSION).$(ARCHIVE_EXT) @@ -113,10 +113,6 @@ CNI_DROPGZ_IMAGE_INFO_FILE = cni-dropgz-$(CNI_DROPGZ_VERSION).txt CNS_IMAGE_INFO_FILE = azure-cns-$(CNS_VERSION).txt NPM_IMAGE_INFO_FILE = azure-npm-$(NPM_VERSION).txt -# Docker libnetwork (CNM) plugin v2 image parameters. -CNM_PLUGIN_IMAGE ?= microsoft/azure-vnet-plugin -CNM_PLUGIN_ROOTFS = azure-vnet-plugin-rootfs - # Default target all-binaries-platforms: ## Make all platform binaries @for goos in "$(GOOSES)"; do \ @@ -136,7 +132,6 @@ all-images: endif # Shorthand target names for convenience. -azure-cnm-plugin: cnm-binary cnm-archive azure-cni-plugin: azure-vnet-binary azure-vnet-stateless-binary azure-vnet-ipam-binary azure-vnet-ipamv6-binary azure-vnet-telemetry-binary cni-archive azure-cns: azure-cns-binary cns-archive acncli: acncli-binary acncli-archive @@ -197,10 +192,6 @@ else ifeq ($(GOARCH),arm64) for dir in /usr/include/aarch64-linux-gnu/*; do sudo ln -sfn "$$dir" /usr/include/$$(basename "$$dir"); done endif -# Build the Azure CNM binary. -cnm-binary: - cd $(CNM_DIR) && CGO_ENABLED=0 go build -v -o $(CNM_BUILD_DIR)/azure-vnet-plugin$(EXE_EXT) -ldflags "-X main.version=$(ACN_VERSION)" -gcflags="-dwarflocationlists=true" - # Build the Azure CNI network binary. azure-vnet-binary: cd $(CNI_NET_DIR) && CGO_ENABLED=0 go build -v -o $(CNI_BUILD_DIR)/azure-vnet$(EXE_EXT) -ldflags "-X main.version=$(CNI_VERSION)" -gcflags="-dwarflocationlists=true" @@ -551,40 +542,6 @@ npm-image-pull: ## pull cns container image. IMAGE=$(NPM_IMAGE) \ TAG=$(NPM_PLATFORM_TAG) - -## Legacy - -# Build the Azure CNM plugin image, installable with "docker plugin install". -azure-cnm-plugin-image: azure-cnm-plugin ## build the azure-cnm plugin container image. - docker images -q $(CNM_PLUGIN_ROOTFS):$(ACN_VERSION) > cid - docker build --no-cache \ - -f Dockerfile.cnm \ - -t $(CNM_PLUGIN_ROOTFS):$(ACN_VERSION) \ - --build-arg CNM_BUILD_DIR=$(CNM_BUILD_DIR) \ - . - $(eval CID := `cat cid`) - docker rmi $(CID) || true - - # Create a container using the image and export its rootfs. - docker create $(CNM_PLUGIN_ROOTFS):$(ACN_VERSION) > cid - $(eval CID := `cat cid`) - $(MKDIR) $(OUTPUT_DIR)/$(CID)/rootfs - docker export $(CID) | tar -x -C $(OUTPUT_DIR)/$(CID)/rootfs - docker rm -vf $(CID) - - # Copy the plugin configuration and set ownership. - cp cnm/config.json $(OUTPUT_DIR)/$(CID) - chgrp -R docker $(OUTPUT_DIR)/$(CID) - - # Create the plugin. - docker plugin rm $(CNM_PLUGIN_IMAGE):$(ACN_VERSION) || true - docker plugin create $(CNM_PLUGIN_IMAGE):$(ACN_VERSION) $(OUTPUT_DIR)/$(CID) - - # Cleanup temporary files. - rm -rf $(OUTPUT_DIR)/$(CID) - rm cid - - ## Reusable targets for building multiplat container image manifests. IMAGE_ARCHIVE_DIR ?= $(shell pwd) @@ -791,11 +748,6 @@ ifeq ($(GOOS),windows) cd $(CNI_BAREMETAL_BUILD_DIR) && $(ARCHIVE_CMD) $(CNI_BAREMETAL_ARCHIVE_NAME) azure-vnet$(EXE_EXT) 10-azure.conflist endif -# Create a CNM archive for the target platform. -.PHONY: cnm-archive -cnm-archive: cnm-binary - cd $(CNM_BUILD_DIR) && $(ARCHIVE_CMD) $(CNM_ARCHIVE_NAME) azure-vnet-plugin$(EXE_EXT) - # Create a cli archive for the target platform. .PHONY: acncli-archive acncli-archive: acncli-binary diff --git a/README.md b/README.md index 04041eac2..75630fdbb 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ This repository contains container networking services and plugins for Linux and Windows containers running on Azure: * [Azure CNI network and IPAM plugins](docs/cni.md) for Kubernetes. -* [Azure CNM (libnetwork) network and IPAM plugins](docs/cnm.md) for Docker Engine. **(MAINTENANCE MODE)** * [Azure NPM - Kubernetes Network Policy Manager](docs/npm.md) (Linux and (preview) Windows Server 2022) The `azure-vnet` network plugins connect containers to your [Azure VNET](https://docs.microsoft.com/en-us/azure/virtual-network/virtual-networks-overview), to take advantage of Azure SDN capabilities. The `azure-vnet-ipam` IPAM plugins provide address management functionality for container IP addresses allocated from Azure VNET address space. diff --git a/cnm/api.go b/cnm/api.go deleted file mode 100644 index 5c6a7c76d..000000000 --- a/cnm/api.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package cnm - -const ( - // Libnetwork remote plugin paths - activatePath = "/Plugin.Activate" - - // Libnetwork labels - genericData = "com.docker.network.generic" -) - -type OptionMap map[string]interface{} - -// -// Libnetwork remote plugin API -// - -// Error response sent by plugin when a request was decoded but failed. -type errorResponse struct { - Err string -} - -// Request sent by libnetwork for activation. -type activateRequest struct{} - -// Response sent by plugin for activation. -type ActivateResponse struct { - Err string - Implements []string -} diff --git a/cnm/config.json b/cnm/config.json deleted file mode 100644 index 39f079ddd..000000000 --- a/cnm/config.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "description": "Azure VNET plugin", - "documentation": "https://github.com/Azure/azure-container-networking/", - "entrypoint": ["/usr/bin/azure-vnet-plugin"], - "interface": { - "types": ["docker.networkdriver/1.0", "docker.ipamdriver/1.0"], - "socket": "azure-vnet.sock" - }, - "network": { - "type": "host" - }, - "mounts": [ - { - "name": "logs", - "description": "Mount /var/log to expose plugin logs to host", - "source": "/var/log", - "destination": "/var/log", - "type": "bind", - "options": ["rbind", "rw"] - }, - { - "name": "modules", - "description": "Mount /lib/modules to load ebtables kernel module on demand", - "source": "/lib/modules", - "destination": "/lib/modules", - "type": "bind", - "options": ["rbind", "r"] - } - ], - "linux": { - "capabilities": ["CAP_SYS_ADMIN", "CAP_NET_ADMIN", "CAP_SYS_MODULE"] - } -} diff --git a/cnm/ipam/api.go b/cnm/ipam/api.go deleted file mode 100644 index a5aa8d673..000000000 --- a/cnm/ipam/api.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package ipam - -const ( - // Libnetwork IPAM plugin endpoint type - EndpointType = "IpamDriver" - - // Libnetwork IPAM plugin remote API paths - GetCapabilitiesPath = "/IpamDriver.GetCapabilities" - GetAddressSpacesPath = "/IpamDriver.GetDefaultAddressSpaces" - RequestPoolPath = "/IpamDriver.RequestPool" - ReleasePoolPath = "/IpamDriver.ReleasePool" - GetPoolInfoPath = "/IpamDriver.GetPoolInfo" - RequestAddressPath = "/IpamDriver.RequestAddress" - ReleaseAddressPath = "/IpamDriver.ReleaseAddress" - - // Libnetwork IPAM plugin options - OptAddressType = "RequestAddressType" - OptAddressTypeGateway = "com.docker.network.gateway" -) - -// Request sent by libnetwork when querying plugin capabilities. -type GetCapabilitiesRequest struct{} - -// Response sent by plugin when registering its capabilities with libnetwork. -type GetCapabilitiesResponse struct { - Err string - RequiresMACAddress bool - RequiresRequestReplay bool -} - -// Request sent by libnetwork when querying the default address space names. -type GetDefaultAddressSpacesRequest struct{} - -// Response sent by plugin when returning the default address space names. -type GetDefaultAddressSpacesResponse struct { - Err string - LocalDefaultAddressSpace string - GlobalDefaultAddressSpace string -} - -// Request sent by libnetwork when acquiring a reference to an address pool. -type RequestPoolRequest struct { - AddressSpace string - Pool string - SubPool string - Options map[string]string - V6 bool -} - -// Response sent by plugin when an address pool is successfully referenced. -type RequestPoolResponse struct { - Err string - PoolID string - Pool string - Data map[string]string -} - -// Request sent by libnetwork when releasing a previously registered address pool. -type ReleasePoolRequest struct { - PoolID string -} - -// Response sent by plugin when an address pool is successfully released. -type ReleasePoolResponse struct { - Err string -} - -// Request sent when querying address pool information. -type GetPoolInfoRequest struct { - PoolID string -} - -// Response sent by plugin when returning address pool information. -type GetPoolInfoResponse struct { - Err string - Capacity int - Available int - UnhealthyAddresses []string -} - -// Request sent by libnetwork when reserving an address from a pool. -type RequestAddressRequest struct { - PoolID string - Address string - Options map[string]string -} - -// Response sent by plugin when an address is successfully reserved. -type RequestAddressResponse struct { - Err string - Address string - Data map[string]string -} - -// Request sent by libnetwork when releasing an address back to the pool. -type ReleaseAddressRequest struct { - PoolID string - Address string - Options map[string]string -} - -// Response sent by plugin when an address is successfully released. -type ReleaseAddressResponse struct { - Err string -} diff --git a/cnm/ipam/ipam.go b/cnm/ipam/ipam.go deleted file mode 100644 index 4a6d2fec9..000000000 --- a/cnm/ipam/ipam.go +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package ipam - -import ( - "net/http" - - "github.com/Azure/azure-container-networking/cnm" - "github.com/Azure/azure-container-networking/common" - "github.com/Azure/azure-container-networking/ipam" - "github.com/Azure/azure-container-networking/log" -) - -const ( - // Plugin name. - name = "azure-vnet-ipam" - - // Plugin capabilities reported to libnetwork. - requiresMACAddress = false - requiresRequestReplay = false - returnCode = 0 - returnStr = "Success" -) - -// IpamPlugin represents a CNM (libnetwork) IPAM plugin. -type ipamPlugin struct { - *cnm.Plugin - am ipam.AddressManager -} - -type IpamPlugin interface { - common.PluginApi -} - -// NewPlugin creates a new IpamPlugin object. -func NewPlugin(config *common.PluginConfig) (IpamPlugin, error) { - // Setup base plugin. - plugin, err := cnm.NewPlugin(name, config.Version, EndpointType) - 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 -} - -// Start 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. rehyrdration required on reboot for cnm ipam plugin - err = plugin.am.Initialize(config, true, plugin.Options) - if err != nil { - log.Printf("[ipam] Failed to initialize address manager, err:%v.", err) - return err - } - - // Add protocol handlers. - listener := plugin.Listener - listener.AddEndpoint(plugin.EndpointType) - listener.AddHandler(GetCapabilitiesPath, plugin.getCapabilities) - listener.AddHandler(GetAddressSpacesPath, plugin.getDefaultAddressSpaces) - listener.AddHandler(RequestPoolPath, plugin.requestPool) - listener.AddHandler(ReleasePoolPath, plugin.releasePool) - listener.AddHandler(GetPoolInfoPath, plugin.getPoolInfo) - listener.AddHandler(RequestAddressPath, plugin.requestAddress) - listener.AddHandler(ReleaseAddressPath, plugin.releaseAddress) - - // Plugin is ready to be discovered. - err = plugin.EnableDiscovery() - if err != nil { - log.Printf("[ipam] Failed to enable discovery: %v.", err) - return err - } - - log.Printf("[ipam] Plugin started.") - - return nil -} - -// Stop stops the plugin. -func (plugin *ipamPlugin) Stop() { - plugin.DisableDiscovery() - plugin.am.Uninitialize() - plugin.Uninitialize() - log.Printf("[ipam] Plugin stopped.") -} - -// -// Libnetwork remote IPAM API implementation -// https://github.com/docker/libnetwork/blob/master/docs/ipam.md -// - -// Handles GetCapabilities requests. -func (plugin *ipamPlugin) getCapabilities(w http.ResponseWriter, r *http.Request) { - var req GetCapabilitiesRequest - - log.Request(plugin.Name, &req, nil) - - resp := GetCapabilitiesResponse{ - RequiresMACAddress: requiresMACAddress, - RequiresRequestReplay: requiresRequestReplay, - } - - err := common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles GetDefaultAddressSpaces requests. -func (plugin *ipamPlugin) getDefaultAddressSpaces(w http.ResponseWriter, r *http.Request) { - var req GetDefaultAddressSpacesRequest - var resp GetDefaultAddressSpacesResponse - - log.Request(plugin.Name, &req, nil) - - localId, globalId := plugin.am.GetDefaultAddressSpaces() - - resp.LocalDefaultAddressSpace = localId - resp.GlobalDefaultAddressSpace = globalId - - err := common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles RequestPool requests. -func (plugin *ipamPlugin) requestPool(w http.ResponseWriter, r *http.Request) { - var req RequestPoolRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - poolId, subnet, err := plugin.am.RequestPool(req.AddressSpace, req.Pool, req.SubPool, req.Options, req.V6) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - data := make(map[string]string) - poolId = ipam.NewAddressPoolId(req.AddressSpace, poolId, "").String() - resp := RequestPoolResponse{PoolID: poolId, Pool: subnet, Data: data} - - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles ReleasePool requests. -func (plugin *ipamPlugin) releasePool(w http.ResponseWriter, r *http.Request) { - var req ReleasePoolRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - poolId, err := ipam.NewAddressPoolIdFromString(req.PoolID) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - err = plugin.am.ReleasePool(poolId.AsId, poolId.Subnet) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := ReleasePoolResponse{} - - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles GetPoolInfo requests. -func (plugin *ipamPlugin) getPoolInfo(w http.ResponseWriter, r *http.Request) { - var req GetPoolInfoRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - poolId, err := ipam.NewAddressPoolIdFromString(req.PoolID) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - apInfo, err := plugin.am.GetPoolInfo(poolId.AsId, poolId.Subnet) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := GetPoolInfoResponse{ - Capacity: apInfo.Capacity, - Available: apInfo.Available, - } - - for _, addr := range apInfo.UnhealthyAddrs { - resp.UnhealthyAddresses = append(resp.UnhealthyAddresses, addr.String()) - } - - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles RequestAddress requests. -func (plugin *ipamPlugin) requestAddress(w http.ResponseWriter, r *http.Request) { - var req RequestAddressRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - poolId, err := ipam.NewAddressPoolIdFromString(req.PoolID) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Convert libnetwork IPAM options to core IPAM options. - options := make(map[string]string) - if req.Options[OptAddressType] == OptAddressTypeGateway { - options[ipam.OptAddressType] = ipam.OptAddressTypeGateway - } - - options[ipam.OptAddressID] = req.Options[ipam.OptAddressID] - - addr, err := plugin.am.RequestAddress(poolId.AsId, poolId.Subnet, req.Address, options) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - data := make(map[string]string) - resp := RequestAddressResponse{Address: addr, Data: data} - - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles ReleaseAddress requests. -func (plugin *ipamPlugin) releaseAddress(w http.ResponseWriter, r *http.Request) { - var req ReleaseAddressRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - poolId, err := ipam.NewAddressPoolIdFromString(req.PoolID) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - err = plugin.am.ReleaseAddress(poolId.AsId, poolId.Subnet, req.Address, req.Options) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := ReleaseAddressResponse{} - - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} diff --git a/cnm/ipam/ipam_test.go b/cnm/ipam/ipam_test.go deleted file mode 100644 index 534fcbc63..000000000 --- a/cnm/ipam/ipam_test.go +++ /dev/null @@ -1,433 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package ipam - -import ( - "bytes" - "encoding/json" - "fmt" - "net" - "net/http" - "net/http/httptest" - "net/url" - "os" - "strconv" - "testing" - - "github.com/Azure/azure-container-networking/cnm" - "github.com/Azure/azure-container-networking/common" - "github.com/Azure/azure-container-networking/ipam" -) - -var ( - plugin IpamPlugin - mux *http.ServeMux -) - -var ( - ipamQueryUrl = "localhost:42424" - ipamQueryResponse = "" + - "" + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - "" - localAsId string - poolId1 string - address1 string -) - -// Wraps the test run with plugin setup and teardown. -func TestMain(m *testing.M) { - var config common.PluginConfig - - // Create a fake local agent to handle requests from IPAM plugin. - u, _ := url.Parse("tcp://" + ipamQueryUrl) - testAgent, err := common.NewListener(u) - if err != nil { - fmt.Printf("Failed to create agent, err:%v.\n", err) - return - } - testAgent.AddHandler("/", handleIpamQuery) - - err = testAgent.Start(make(chan error, 1)) - if err != nil { - fmt.Printf("Failed to start agent, err:%v.\n", err) - return - } - - // Create the plugin. - plugin, err = NewPlugin(&config) - if err != nil { - fmt.Printf("Failed to create IPAM plugin, err:%v.\n", err) - return - } - - // Configure test mode. - plugin.SetOption(common.OptEnvironment, common.OptEnvironmentAzure) - plugin.SetOption(common.OptAPIServerURL, "null") - plugin.SetOption(common.OptIpamQueryUrl, "http://"+ipamQueryUrl) - - // Start the plugin. - err = plugin.Start(&config) - if err != nil { - fmt.Printf("Failed to start IPAM plugin, err:%v.\n", err) - return - } - - // Get the internal http mux as test hook. - mux = plugin.(*ipamPlugin).Listener.GetMux() - - // Run tests. - exitCode := m.Run() - - // Cleanup. - plugin.Stop() - testAgent.Stop() - - os.Exit(exitCode) -} - -// Handles queries from IPAM source. -func handleIpamQuery(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(ipamQueryResponse)) -} - -// Decodes plugin's responses to test requests. -func decodeResponse(w *httptest.ResponseRecorder, response interface{}) error { - if w.Code != http.StatusOK { - return fmt.Errorf("Request failed with HTTP error %d", w.Code) - } - - if w.Body == nil { - return fmt.Errorf("Response body is empty") - } - - return json.NewDecoder(w.Body).Decode(&response) -} - -// -// Libnetwork remote IPAM API compliance tests -// https://github.com/docker/libnetwork/blob/master/docs/ipam.md -// - -// Tests Plugin.Activate functionality. -func TestActivate(t *testing.T) { - var resp cnm.ActivateResponse - - req, err := http.NewRequest(http.MethodGet, "/Plugin.Activate", nil) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" || resp.Implements[0] != "IpamDriver" { - t.Errorf("Activate response is invalid %+v", resp) - } -} - -// Tests IpamDriver.GetCapabilities functionality. -func TestGetCapabilities(t *testing.T) { - var resp GetCapabilitiesResponse - - req, err := http.NewRequest(http.MethodGet, GetCapabilitiesPath, nil) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" { - t.Errorf("GetCapabilities response is invalid %+v", resp) - } -} - -// Tests IpamDriver.GetDefaultAddressSpaces functionality. -func TestGetDefaultAddressSpaces(t *testing.T) { - var resp GetDefaultAddressSpacesResponse - - req, err := http.NewRequest(http.MethodGet, GetAddressSpacesPath, nil) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" || resp.LocalDefaultAddressSpace == "" { - t.Errorf("GetDefaultAddressSpaces response is invalid %+v", resp) - } - - localAsId = resp.LocalDefaultAddressSpace -} - -// Tests IpamDriver.RequestPool functionality. -func TestRequestPool(t *testing.T) { - var body bytes.Buffer - var resp RequestPoolResponse - - payload := &RequestPoolRequest{ - AddressSpace: localAsId, - } - - json.NewEncoder(&body).Encode(payload) - - req, err := http.NewRequest(http.MethodGet, RequestPoolPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" { - t.Errorf("RequestPool response is invalid %+v", resp) - } - - poolId1 = resp.PoolID -} - -// Tests IpamDriver.RequestAddress functionality. -func TestRequestAddress(t *testing.T) { - var body bytes.Buffer - var resp RequestAddressResponse - - payload := &RequestAddressRequest{ - PoolID: poolId1, - Address: "", - Options: nil, - } - - json.NewEncoder(&body).Encode(payload) - - req, err := http.NewRequest(http.MethodGet, RequestAddressPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" { - t.Errorf("RequestAddress response is invalid %+v", resp) - } - - address, _, _ := net.ParseCIDR(resp.Address) - address1 = address.String() -} - -// Tests IpamDriver.GetPoolInfo functionality. -func TestGetPoolInfo(t *testing.T) { - var body bytes.Buffer - var resp GetPoolInfoResponse - - payload := &GetPoolInfoRequest{ - PoolID: poolId1, - } - - json.NewEncoder(&body).Encode(payload) - - req, err := http.NewRequest(http.MethodGet, GetPoolInfoPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" { - t.Errorf("GetPoolInfo response is invalid %+v", resp) - } -} - -// Tests IpamDriver.ReleaseAddress functionality. -func TestReleaseAddress(t *testing.T) { - var body bytes.Buffer - var resp ReleaseAddressResponse - - payload := &ReleaseAddressRequest{ - PoolID: poolId1, - Address: address1, - } - - json.NewEncoder(&body).Encode(payload) - - req, err := http.NewRequest(http.MethodGet, ReleaseAddressPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" { - t.Errorf("ReleaseAddress response is invalid %+v", resp) - } -} - -// Tests IpamDriver.ReleasePool functionality. -func TestReleasePool(t *testing.T) { - var body bytes.Buffer - var resp ReleasePoolResponse - - payload := &ReleasePoolRequest{ - PoolID: poolId1, - } - - json.NewEncoder(&body).Encode(payload) - - req, err := http.NewRequest(http.MethodGet, ReleasePoolPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" { - t.Errorf("ReleasePool response is invalid %+v", resp) - } -} - -// Utility function to request address from IPAM. -func reqAddrInternal(payload *RequestAddressRequest) (string, error) { - var body bytes.Buffer - var resp RequestAddressResponse - json.NewEncoder(&body).Encode(payload) - - req, err := http.NewRequest(http.MethodGet, RequestAddressPath, &body) - if err != nil { - return "", err - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil { - return "", err - } - return resp.Address, nil -} - -// Utility function to release address from IPAM. -func releaseAddrInternal(payload *ReleaseAddressRequest) error { - var body bytes.Buffer - var resp ReleaseAddressResponse - - json.NewEncoder(&body).Encode(payload) - - req, err := http.NewRequest(http.MethodGet, ReleaseAddressPath, &body) - if err != nil { - return err - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil { - return err - } - return nil -} - -// Tests IpamDriver.RequestAddress with id. -func TestRequestAddressWithID(t *testing.T) { - var ipList [2]string - - for i := 0; i < 2; i++ { - payload := &RequestAddressRequest{ - PoolID: poolId1, - Address: "", - Options: make(map[string]string), - } - - payload.Options[ipam.OptAddressID] = "id" + strconv.Itoa(i) - - addr1, err := reqAddrInternal(payload) - if err != nil { - t.Errorf("RequestAddress response is invalid %+v", err) - } - - addr2, err := reqAddrInternal(payload) - if err != nil { - t.Errorf("RequestAddress response is invalid %+v", err) - } - - if addr1 != addr2 { - t.Errorf("RequestAddress with id %+v doesn't match with retrieved addr %+v ", addr1, addr2) - } - - address, _, _ := net.ParseCIDR(addr1) - ipList[i] = address.String() - } - - for i := 0; i < 2; i++ { - payload := &ReleaseAddressRequest{ - PoolID: poolId1, - Address: ipList[i], - } - err := releaseAddrInternal(payload) - if err != nil { - t.Errorf("ReleaseAddress response is invalid %+v", err) - } - } -} - -// Tests IpamDriver.ReleaseAddress with id. -func TestReleaseAddressWithID(t *testing.T) { - reqPayload := &RequestAddressRequest{ - PoolID: poolId1, - Address: "", - Options: make(map[string]string), - } - reqPayload.Options[ipam.OptAddressID] = "id1" - - _, err := reqAddrInternal(reqPayload) - if err != nil { - t.Errorf("RequestAddress response is invalid %+v", err) - } - - releasePayload := &ReleaseAddressRequest{ - PoolID: poolId1, - Address: "", - Options: make(map[string]string), - } - releasePayload.Options[ipam.OptAddressID] = "id1" - - err = releaseAddrInternal(releasePayload) - - if err != nil { - t.Errorf("ReleaseAddress response is invalid %+v", err) - } -} diff --git a/cnm/network/api.go b/cnm/network/api.go deleted file mode 100644 index d11f66712..000000000 --- a/cnm/network/api.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package network - -const ( - // Libnetwork network plugin endpoint type - endpointType = "NetworkDriver" - - // Libnetwork network plugin remote API paths - getCapabilitiesPath = "/NetworkDriver.GetCapabilities" - createNetworkPath = "/NetworkDriver.CreateNetwork" - deleteNetworkPath = "/NetworkDriver.DeleteNetwork" - createEndpointPath = "/NetworkDriver.CreateEndpoint" - deleteEndpointPath = "/NetworkDriver.DeleteEndpoint" - joinPath = "/NetworkDriver.Join" - leavePath = "/NetworkDriver.Leave" - endpointOperInfoPath = "/NetworkDriver.EndpointOperInfo" - - // Libnetwork network plugin options - modeOption = "com.microsoft.azure.network.mode" -) - -// Request sent by libnetwork when querying plugin capabilities. -type getCapabilitiesRequest struct{} - -// Response sent by plugin when registering its capabilities with libnetwork. -type getCapabilitiesResponse struct { - Err string - Scope string -} - -// Request sent by libnetwork when creating a new network. -type createNetworkRequest struct { - NetworkID string - Options map[string]interface{} - IPv4Data []ipamData - IPv6Data []ipamData -} - -// IPAMData represents the per-network IP operational information. -type ipamData struct { - AddressSpace string - Pool string - Gateway string - AuxAddresses map[string]string -} - -// Response sent by plugin when a network is created. -type createNetworkResponse struct { - Err string -} - -// Request sent by libnetwork when deleting an existing network. -type deleteNetworkRequest struct { - NetworkID string -} - -// Response sent by plugin when a network is deleted. -type deleteNetworkResponse struct { - Err string -} - -// Request sent by libnetwork when creating a new endpoint. -type createEndpointRequest struct { - NetworkID string - EndpointID string - Options map[string]interface{} - Interface endpointInterface -} - -// Represents a libnetwork endpoint interface. -type endpointInterface struct { - Address string - AddressIPv6 string - MacAddress string -} - -// Response sent by plugin when an endpoint is created. -type createEndpointResponse struct { - Err string - Interface endpointInterface -} - -// Request sent by libnetwork when deleting an existing endpoint. -type deleteEndpointRequest struct { - NetworkID string - EndpointID string -} - -// Response sent by plugin when an endpoint is deleted. -type deleteEndpointResponse struct { - Err string -} - -// Request sent by libnetwork when joining an endpoint to a sandbox. -type joinRequest struct { - NetworkID string - EndpointID string - SandboxKey string - Options map[string]interface{} -} - -// Response sent by plugin when an endpoint is joined to a sandbox. -type joinResponse struct { - Err string - InterfaceName interfaceName - Gateway string - GatewayIPv6 string - StaticRoutes []staticRoute -} - -// Represents naming information for a joined interface. -type interfaceName struct { - SrcName string - DstName string - DstPrefix string -} - -// Represents a static route to be added in a sandbox for a joined interface. -type staticRoute struct { - Destination string - RouteType int - NextHop string -} - -// Request sent by libnetwork when removing an endpoint from its sandbox. -type leaveRequest struct { - NetworkID string - EndpointID string -} - -// Response sent by plugin when an endpoint is removed from its sandbox. -type leaveResponse struct { - Err string -} - -// Request sent by libnetwork when querying operational info of an endpoint. -type endpointOperInfoRequest struct { - NetworkID string - EndpointID string -} - -// Response sent by plugin when returning operational info of an endpoint. -type endpointOperInfoResponse struct { - Err string - Value map[string]interface{} -} diff --git a/cnm/network/network.go b/cnm/network/network.go deleted file mode 100644 index 94fff34bf..000000000 --- a/cnm/network/network.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package network - -import ( - "net" - "net/http" - "time" - - "github.com/Azure/azure-container-networking/cnm" - cnsclient "github.com/Azure/azure-container-networking/cns/client" - "github.com/Azure/azure-container-networking/common" - "github.com/Azure/azure-container-networking/iptables" - "github.com/Azure/azure-container-networking/log" - "github.com/Azure/azure-container-networking/netio" - "github.com/Azure/azure-container-networking/netlink" - "github.com/Azure/azure-container-networking/network" - "github.com/Azure/azure-container-networking/platform" -) - -const ( - // Plugin name. - name = "azure-vnet" - - // Plugin capabilities. - scope = "local" - - // Prefix for container network interface names. - containerInterfacePrefix = "eth" - returnCode = 0 - returnStr = "Success" - defaultCNSTimeout = 15 * time.Second -) - -// NetPlugin represents a CNM (libnetwork) network plugin. -type netPlugin struct { - *cnm.Plugin - scope string - nm network.NetworkManager -} - -type NetPlugin interface { - common.PluginApi -} - -// NewPlugin creates a new NetPlugin object. -func NewPlugin(config *common.PluginConfig) (NetPlugin, error) { - // Setup base plugin. - plugin, err := cnm.NewPlugin(name, config.Version, endpointType) - if err != nil { - return nil, err - } - - nl := netlink.NewNetlink() - // Setup network manager. - nm, err := network.NewNetworkManager(nl, platform.NewExecClient(nil), &netio.NetIO{}, network.NewNamespaceClient(), iptables.NewClient()) - if err != nil { - return nil, err - } - - config.NetApi = nm - - return &netPlugin{ - Plugin: plugin, - scope: scope, - nm: nm, - }, nil -} - -// Start 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. rehyrdration required on reboot for cnm plugin - err = plugin.nm.Initialize(config, true) - if err != nil { - log.Printf("[net] Failed to initialize network manager, err:%v.", err) - return err - } - - // Add protocol handlers. - listener := plugin.Listener - listener.AddEndpoint(plugin.EndpointType) - listener.AddHandler(getCapabilitiesPath, plugin.getCapabilities) - listener.AddHandler(createNetworkPath, plugin.createNetwork) - listener.AddHandler(deleteNetworkPath, plugin.deleteNetwork) - listener.AddHandler(createEndpointPath, plugin.createEndpoint) - listener.AddHandler(deleteEndpointPath, plugin.deleteEndpoint) - listener.AddHandler(joinPath, plugin.join) - listener.AddHandler(leavePath, plugin.leave) - listener.AddHandler(endpointOperInfoPath, plugin.endpointOperInfo) - - // Plugin is ready to be discovered. - err = plugin.EnableDiscovery() - if err != nil { - log.Printf("[net] Failed to enable discovery: %v.", err) - return err - } - - log.Printf("[net] Plugin started.") - - return nil -} - -// Stop stops the plugin. -func (plugin *netPlugin) Stop() { - plugin.DisableDiscovery() - plugin.nm.Uninitialize() - plugin.Uninitialize() - log.Printf("[net] Plugin stopped.") -} - -// -// Libnetwork remote network API implementation -// https://github.com/docker/libnetwork/blob/master/docs/remote.md -// - -// Handles GetCapabilities requests. -func (plugin *netPlugin) getCapabilities(w http.ResponseWriter, r *http.Request) { - var req getCapabilitiesRequest - - log.Request(plugin.Name, &req, nil) - - resp := getCapabilitiesResponse{Scope: plugin.scope} - err := common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles CreateNetwork requests. -func (plugin *netPlugin) createNetwork(w http.ResponseWriter, r *http.Request) { - var req createNetworkRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - nwInfo := network.EndpointInfo{ - NetworkID: req.NetworkID, - Options: req.Options, - } - - // Parse network options. - options := plugin.ParseOptions(req.Options) - if options != nil { - nwInfo.Mode, _ = options[modeOption].(string) - } - - // Populate subnets. - for _, data := range [][]ipamData{req.IPv4Data, req.IPv6Data} { - for _, ipamData := range data { - _, prefix, err := net.ParseCIDR(ipamData.Pool) - if err != nil { - continue - } - - subnet := network.SubnetInfo{ - Family: platform.GetAddressFamily(&prefix.IP), - Prefix: *prefix, - Gateway: platform.ConvertStringToIPAddress(ipamData.Gateway), - } - - nwInfo.Subnets = append(nwInfo.Subnets, subnet) - } - } - - err = plugin.nm.CreateNetwork(&nwInfo) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := createNetworkResponse{} - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles DeleteNetwork requests. -func (plugin *netPlugin) deleteNetwork(w http.ResponseWriter, r *http.Request) { - var req deleteNetworkRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - err = plugin.nm.DeleteNetwork(req.NetworkID) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := deleteNetworkResponse{} - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles CreateEndpoint requests. -func (plugin *netPlugin) createEndpoint(w http.ResponseWriter, r *http.Request) { - var req createEndpointRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - var ipv4Address *net.IPNet - if req.Interface.Address != "" { - var ip net.IP - ip, ipv4Address, err = net.ParseCIDR(req.Interface.Address) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - ipv4Address.IP = ip - } - - epInfo := network.EndpointInfo{ - EndpointID: req.EndpointID, - IPAddresses: []net.IPNet{*ipv4Address}, - SkipHotAttachEp: true, // Skip hot attach endpoint as it's done in Join - } - - epInfo.Data = make(map[string]interface{}) - - cnscli, err := cnsclient.New("", defaultCNSTimeout) - if err != nil { - log.Errorf("failed to init CNS client", err) - } - err = plugin.nm.CreateEndpoint(cnscli, req.NetworkID, &epInfo) - // TODO: Because create endpoint no longer assigns to the map or saves to a file, you need to handle it in cnm right here! - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := createEndpointResponse{} - - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles DeleteEndpoint requests. -func (plugin *netPlugin) deleteEndpoint(w http.ResponseWriter, r *http.Request) { - var req deleteEndpointRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - err = plugin.nm.DeleteEndpoint(req.NetworkID, req.EndpointID, nil) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := deleteEndpointResponse{} - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles Join requests. -func (plugin *netPlugin) join(w http.ResponseWriter, r *http.Request) { - var req joinRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - ep, err := plugin.nm.AttachEndpoint(req.NetworkID, req.EndpointID, req.SandboxKey) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - ifname := interfaceName{ - SrcName: ep.IfName, - DstPrefix: containerInterfacePrefix, - } - - resp := joinResponse{ - InterfaceName: ifname, - Gateway: ep.Gateways[0].String(), - } - - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles Leave requests. -func (plugin *netPlugin) leave(w http.ResponseWriter, r *http.Request) { - var req leaveRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - err = plugin.nm.DetachEndpoint(req.NetworkID, req.EndpointID) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := leaveResponse{} - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} - -// Handles EndpointOperInfo requests. -func (plugin *netPlugin) endpointOperInfo(w http.ResponseWriter, r *http.Request) { - var req endpointOperInfoRequest - - // Decode request. - err := common.Decode(w, r, &req) - log.Request(plugin.Name, &req, err) - if err != nil { - return - } - - // Process request. - epInfo, err := plugin.nm.GetEndpointInfo(req.NetworkID, req.EndpointID) - if err != nil { - plugin.SendErrorResponse(w, err) - return - } - - // Encode response. - resp := endpointOperInfoResponse{Value: epInfo.Data} - err = common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, returnCode, returnStr, err) -} diff --git a/cnm/network/network_linux_test.go b/cnm/network/network_linux_test.go deleted file mode 100644 index 2cc4d27cf..000000000 --- a/cnm/network/network_linux_test.go +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package network - -import ( - "bytes" - "encoding/json" - "fmt" - "net" - "net/http" - "net/http/httptest" - "os" - "os/exec" - "testing" - - "github.com/Azure/azure-container-networking/cnm" - "github.com/Azure/azure-container-networking/common" - "github.com/Azure/azure-container-networking/log" - "github.com/Azure/azure-container-networking/netlink" - driverApi "github.com/docker/libnetwork/driverapi" - remoteApi "github.com/docker/libnetwork/drivers/remote/api" -) - -var ( - plugin NetPlugin - mux *http.ServeMux -) - -var ( - anyInterface = "dummy" - anySubnet = "192.168.1.0/24" - ipnet = net.IPNet{IP: net.ParseIP("192.168.1.0"), Mask: net.IPv4Mask(255, 255, 255, 0)} - networkID = "N1" - netns = "22212" -) - -// endpoint ID must contain 7 characters -var endpointID = "E1-xxxx" - -// Wraps the test run with plugin setup and teardown. -func TestMain(m *testing.M) { - var config common.PluginConfig - var err error - - // Create the plugin. - plugin, err = NewPlugin(&config) - if err != nil { - fmt.Printf("Failed to create network plugin %v\n", err) - os.Exit(1) - } - - // Configure test mode. - plugin.(*netPlugin).Name = "test" - - // Start the plugin. - err = plugin.Start(&config) - if err != nil { - fmt.Printf("Failed to start network plugin %v\n", err) - os.Exit(2) - } - nl := netlink.NewNetlink() - - // Create a dummy test network interface. - err = nl.AddLink(&netlink.DummyLink{ - LinkInfo: netlink.LinkInfo{ - Type: netlink.LINK_TYPE_DUMMY, - Name: anyInterface, - }, - }) - - if err != nil { - fmt.Printf("Failed to create test network interface, err:%v.\n", err) - os.Exit(3) - } - - err = plugin.(*netPlugin).nm.AddExternalInterface(anyInterface, anySubnet, "") - if err != nil { - fmt.Printf("Failed to add test network interface, err:%v.\n", err) - os.Exit(4) - } - - err = nl.AddIPAddress(anyInterface, net.ParseIP("192.168.1.4"), &ipnet) - if err != nil { - fmt.Printf("Failed to add test IP address, err:%v.\n", err) - os.Exit(5) - } - - // Get the internal http mux as test hook. - mux = plugin.(*netPlugin).Listener.GetMux() - - // Run tests. - exitCode := m.Run() - - // Cleanup. - err = nl.DeleteLink(anyInterface) - if err != nil { - fmt.Printf("Failed to delete link, err:%v.\n", err) - } - plugin.Stop() - - os.Exit(exitCode) -} - -// Decodes plugin's responses to test requests. -func decodeResponse(w *httptest.ResponseRecorder, response interface{}) error { - if w.Code != http.StatusOK { - return fmt.Errorf("Request failed with HTTP error %d", w.Code) - } - - if w.Body == nil { - return fmt.Errorf("Response body is empty") - } - - return json.NewDecoder(w.Body).Decode(&response) -} - -// -// Libnetwork remote API compliance tests -// https://github.com/docker/libnetwork/blob/master/docs/remote.md -// - -// Tests Plugin.Activate functionality. -func TestActivate(t *testing.T) { - var resp cnm.ActivateResponse - - req, err := http.NewRequest(http.MethodGet, "/Plugin.Activate", nil) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" || resp.Implements[0] != "NetworkDriver" { - t.Errorf("Activate response is invalid %+v", resp) - } -} - -// Tests NetworkDriver.GetCapabilities functionality. -func TestGetCapabilities(t *testing.T) { - var resp remoteApi.GetCapabilityResponse - - req, err := http.NewRequest(http.MethodGet, getCapabilitiesPath, nil) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" || resp.Scope != "local" { - t.Errorf("GetCapabilities response is invalid %+v", resp) - } -} - -func TestCNM(t *testing.T) { - cmd := exec.Command("ip", "netns", "add", netns) - log.Printf("%v", cmd) - output, err := cmd.Output() - if err != nil { - t.Fatalf("%v:%v", output, err.Error()) - return - } - - defer func() { - cmd = exec.Command("ip", "netns", "delete", netns) - _, err = cmd.Output() - - if err != nil { - t.Fatalf("%v:%v", output, err) - return - } - }() - - log.Printf("###CreateNetwork#####################################################################################") - createNetworkT(t) - log.Printf("###CreateEndpoint####################################################################################") - createEndpointT(t) - log.Printf("###EndpointOperInfo#####################################################################################") - endpointOperInfoT(t) - log.Printf("###DeleteEndpoint#####################################################################################") - deleteEndpointT(t) - log.Printf("###DeleteNetwork#####################################################################################") - // deleteNetworkT(t) -} - -// Tests NetworkDriver.CreateNetwork functionality. -func createNetworkT(t *testing.T) { - var body bytes.Buffer - var resp remoteApi.CreateNetworkResponse - - _, pool, _ := net.ParseCIDR(anySubnet) - - info := &remoteApi.CreateNetworkRequest{ - NetworkID: networkID, - IPv4Data: []driverApi.IPAMData{ - { - Pool: pool, - }, - }, - } - - json.NewEncoder(&body).Encode(info) - - req, err := http.NewRequest(http.MethodGet, createNetworkPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Response.Err != "" { - t.Errorf("CreateNetwork response is invalid %+v, received err %v", resp, err) - } -} - -// Tests NetworkDriver.CreateEndpoint functionality. -func createEndpointT(t *testing.T) { - var body bytes.Buffer - var resp remoteApi.CreateEndpointResponse - - info := &remoteApi.CreateEndpointRequest{ - NetworkID: networkID, - EndpointID: endpointID, - Interface: &remoteApi.EndpointInterface{Address: anySubnet}, - } - - json.NewEncoder(&body).Encode(info) - - req, err := http.NewRequest(http.MethodGet, createEndpointPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Response.Err != "" { - t.Errorf("CreateEndpoint response is invalid %+v, received err %v", resp, err) - } -} - -// Tests NetworkDriver.EndpointOperInfo functionality. -func endpointOperInfoT(t *testing.T) { - var body bytes.Buffer - var resp remoteApi.EndpointInfoResponse - - info := &remoteApi.EndpointInfoRequest{ - NetworkID: networkID, - EndpointID: endpointID, - } - - json.NewEncoder(&body).Encode(info) - - req, err := http.NewRequest(http.MethodGet, endpointOperInfoPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - if err != nil || resp.Err != "" { - t.Errorf("EndpointOperInfo response is invalid %+v, received err %v", resp, err) - } -} - -func deleteEndpointT(t *testing.T) { - var body bytes.Buffer - var resp remoteApi.DeleteEndpointResponse - - info := &remoteApi.DeleteEndpointRequest{ - NetworkID: networkID, - EndpointID: endpointID, - } - - json.NewEncoder(&body).Encode(info) - - req, err := http.NewRequest(http.MethodGet, deleteEndpointPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Response.Err != "" { - t.Errorf("DeleteEndpoint response is invalid %+v, received err %v", resp, err) - } -} - -// Tests NetworkDriver.DeleteNetwork functionality. -func deleteNetworkT(t *testing.T) { - var body bytes.Buffer - var resp remoteApi.DeleteNetworkResponse - - info := &remoteApi.DeleteNetworkRequest{ - NetworkID: networkID, - } - - json.NewEncoder(&body).Encode(info) - - req, err := http.NewRequest(http.MethodGet, deleteNetworkPath, &body) - if err != nil { - t.Fatal(err) - } - - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - err = decodeResponse(w, &resp) - - if err != nil || resp.Err != "" { - t.Errorf("DeleteNetwork response is invalid %+v, received err %v", resp, err) - } -} diff --git a/cnm/plugin.go b/cnm/plugin.go deleted file mode 100644 index 417552920..000000000 --- a/cnm/plugin.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package cnm - -import ( - "net/http" - "net/url" - "os" - - "github.com/Azure/azure-container-networking/common" - "github.com/Azure/azure-container-networking/log" -) - -// Plugin is the parent class for CNM plugins. -type Plugin struct { - *common.Plugin - EndpointType string - Listener *common.Listener -} - -// NewPlugin creates a new Plugin object. -func NewPlugin(name, version, endpointType string) (*Plugin, error) { - // Setup base plugin. - plugin, err := common.NewPlugin(name, version) - if err != nil { - return nil, err - } - - return &Plugin{ - Plugin: plugin, - EndpointType: endpointType, - }, nil -} - -// Initialize initializes the plugin and starts the listener. -func (plugin *Plugin) Initialize(config *common.PluginConfig) error { - // Initialize the base plugin. - plugin.Plugin.Initialize(config) - - // Initialize the shared listener. - if config.Listener == nil { - // Fetch and parse the API server URL. - u, err := url.Parse(plugin.getAPIServerURL()) - if err != nil { - return err - } - - // Create the listener. - listener, err := common.NewListener(u) - if err != nil { - return err - } - - // Add generic protocol handlers. - listener.AddHandler(activatePath, plugin.activate) - - // Start the listener. - err = listener.Start(config.ErrChan) - if err != nil { - return err - } - - config.Listener = listener - } - - plugin.Listener = config.Listener - - return nil -} - -// Uninitialize cleans up the plugin. -func (plugin *Plugin) Uninitialize() { - plugin.Listener.Stop() - plugin.Plugin.Uninitialize() -} - -// EnableDiscovery enables Docker to discover the plugin by creating the plugin spec file. -func (plugin *Plugin) EnableDiscovery() error { - // Plugins using unix domain sockets do not need a spec file. - if plugin.Listener.URL.Scheme == "unix" { - return nil - } - - // Create the spec directory. - path := plugin.getSpecPath() - os.MkdirAll(path, 0o755) - - // Write the listener URL to the spec file. - fileName := path + plugin.Name + ".spec" - url := plugin.Listener.URL.String() - err := os.WriteFile(fileName, []byte(url), 0o644) - return err -} - -// DisableDiscovery disables discovery by deleting the plugin spec file. -func (plugin *Plugin) DisableDiscovery() { - // Plugins using unix domain sockets do not need a spec file. - if plugin.Listener.URL.Scheme == "unix" { - return - } - - fileName := plugin.getSpecPath() + plugin.Name + ".spec" - os.Remove(fileName) -} - -// ParseOptions returns generic options from a libnetwork request. -func (plugin *Plugin) ParseOptions(options OptionMap) OptionMap { - opt, _ := options[genericData].(map[string]interface{}) - return opt -} - -// -// Libnetwork remote plugin API -// - -// Activate handles Activate requests. -func (plugin *Plugin) activate(w http.ResponseWriter, r *http.Request) { - var req activateRequest - - log.Request(plugin.Name, &req, nil) - - resp := ActivateResponse{Implements: plugin.Listener.GetEndpoints()} - err := common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, 0, "Success", err) -} - -// SendErrorResponse sends and logs an error response. -func (plugin *Plugin) SendErrorResponse(w http.ResponseWriter, errMsg error) { - resp := errorResponse{errMsg.Error()} - err := common.Encode(w, &resp) - - log.Response(plugin.Name, &resp, 0, "Success", err) -} diff --git a/cnm/plugin/main.go b/cnm/plugin/main.go deleted file mode 100644 index 227e588cf..000000000 --- a/cnm/plugin/main.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package main - -import ( - "fmt" - "os" - "os/signal" - "syscall" - - "github.com/Azure/azure-container-networking/cnm/ipam" - "github.com/Azure/azure-container-networking/cnm/network" - "github.com/Azure/azure-container-networking/common" - "github.com/Azure/azure-container-networking/log" - "github.com/Azure/azure-container-networking/platform" - "github.com/Azure/azure-container-networking/processlock" - "github.com/Azure/azure-container-networking/store" -) - -const ( - // Plugin name as used in socket, log and store names. - name = "azure-vnet" -) - -// Version is populated by make during build. -var version string - -// Command line arguments for CNM plugin. -var args = common.ArgumentList{ - { - Name: common.OptEnvironment, - Shorthand: common.OptEnvironmentAlias, - Description: "Set the operating environment", - Type: "string", - DefaultValue: common.OptEnvironmentAzure, - ValueMap: map[string]interface{}{ - common.OptEnvironmentAzure: 0, - common.OptEnvironmentMAS: 0, - common.OptEnvironmentFileIpam: 0, - }, - }, - { - Name: common.OptAPIServerURL, - Shorthand: common.OptAPIServerURLAlias, - Description: "Set the API server URL", - Type: "string", - DefaultValue: "", - }, - { - Name: common.OptLogLevel, - Shorthand: common.OptLogLevelAlias, - Description: "Set the logging level", - Type: "int", - DefaultValue: common.OptLogLevelInfo, - ValueMap: map[string]interface{}{ - common.OptLogLevelInfo: log.LevelInfo, - common.OptLogLevelDebug: log.LevelDebug, - }, - }, - { - Name: common.OptLogTarget, - Shorthand: common.OptLogTargetAlias, - Description: "Set the logging target", - Type: "int", - DefaultValue: common.OptLogTargetFile, - ValueMap: map[string]interface{}{ - common.OptLogTargetSyslog: log.TargetSyslog, - common.OptLogTargetStderr: log.TargetStderr, - common.OptLogTargetFile: log.TargetLogfile, - }, - }, - { - Name: common.OptLogLocation, - Shorthand: common.OptLogLocationAlias, - Description: "Set the logging directory", - Type: "string", - DefaultValue: "", - }, - { - Name: common.OptIpamQueryUrl, - Shorthand: common.OptIpamQueryUrlAlias, - Description: "Set the IPAM query URL", - Type: "string", - DefaultValue: "", - }, - { - Name: common.OptIpamQueryInterval, - Shorthand: common.OptIpamQueryIntervalAlias, - Description: "Set the IPAM plugin query interval", - Type: "int", - DefaultValue: "", - }, - { - Name: common.OptVersion, - Shorthand: common.OptVersionAlias, - Description: "Print version information", - Type: "bool", - DefaultValue: false, - }, - { - Name: common.OptStoreFileLocation, - Shorthand: common.OptStoreFileLocationAlias, - Description: "Set store file absolute path", - Type: "string", - DefaultValue: platform.CNMRuntimePath, - }, -} - -// Prints description and version information. -func printVersion() { - fmt.Printf("Azure CNM (libnetwork) plugin\n") - fmt.Printf("Version %v\n", version) -} - -// Main is the entry point for CNM plugin. -func main() { - // Initialize and parse command line arguments. - common.ParseArgs(&args, printVersion) - - environment := common.GetArg(common.OptEnvironment).(string) - url := common.GetArg(common.OptAPIServerURL).(string) - logLevel := common.GetArg(common.OptLogLevel).(int) - logTarget := common.GetArg(common.OptLogTarget).(int) - ipamQueryUrl, _ := common.GetArg(common.OptIpamQueryUrl).(string) - ipamQueryInterval, _ := common.GetArg(common.OptIpamQueryInterval).(int) - vers := common.GetArg(common.OptVersion).(bool) - storeFileLocation := common.GetArg(common.OptStoreFileLocation).(string) - - if vers { - printVersion() - os.Exit(0) - } - - // Initialize plugin common configuration. - var config common.PluginConfig - config.Version = version - - // Create a channel to receive unhandled errors from the plugins. - config.ErrChan = make(chan error, 1) - - // Create network plugin. - netPlugin, err := network.NewPlugin(&config) - if err != nil { - fmt.Printf("Failed to create network plugin, err:%v.\n", err) - return - } - - // Create IPAM plugin. - ipamPlugin, err := ipam.NewPlugin(&config) - if err != nil { - fmt.Printf("Failed to create IPAM plugin, err:%v.\n", err) - return - } - - err = platform.CreateDirectory(storeFileLocation) - if err != nil { - log.Errorf("Failed to create File Store directory %s, due to Error:%v", storeFileLocation, err.Error()) - return - } - - lockclient, err := processlock.NewFileLock(platform.CNILockPath + name + store.LockExtension) - if err != nil { - log.Printf("Error initializing file lock:%v", err) - return - } - - // Create the key value store. - storeFileName := storeFileLocation + name + ".json" - config.Store, err = store.NewJsonFileStore(storeFileName, lockclient, nil) - if err != nil { - log.Errorf("Failed to create store file: %s, due to error %v\n", storeFileName, err) - return - } - - // Create logging provider. - logDirectory := "" // Sets the current location as log directory - log.SetName(name) - log.SetLevel(logLevel) - err = log.SetTargetLogDirectory(logTarget, logDirectory) - if err != nil { - fmt.Printf("Failed to configure logging: %v\n", err) - return - } - - // Log platform information. - log.Printf("Running on %v", platform.GetOSInfo()) - common.LogNetworkInterfaces() - - // Set plugin options. - netPlugin.SetOption(common.OptAPIServerURL, url) - - ipamPlugin.SetOption(common.OptEnvironment, environment) - ipamPlugin.SetOption(common.OptAPIServerURL, url) - ipamPlugin.SetOption(common.OptIpamQueryUrl, ipamQueryUrl) - ipamPlugin.SetOption(common.OptIpamQueryInterval, ipamQueryInterval) - - // Start plugins. - if netPlugin != nil { - err = netPlugin.Start(&config) - if err != nil { - fmt.Printf("Failed to start network plugin, err:%v.\n", err) - return - } - } - - if ipamPlugin != nil { - err = ipamPlugin.Start(&config) - if err != nil { - fmt.Printf("Failed to start IPAM plugin, err:%v.\n", err) - return - } - } - - // Relay these incoming signals to OS signal channel. - osSignalChannel := make(chan os.Signal, 1) - signal.Notify(osSignalChannel, os.Interrupt, syscall.SIGTERM) - - // Wait until receiving a signal. - select { - case sig := <-osSignalChannel: - log.Printf("Received OS signal <" + sig.String() + ">, shutting down.") - case err := <-config.ErrChan: - log.Printf("Received unhandled plugin error %v, shutting down.", err) - } - - // Cleanup. - if netPlugin != nil { - netPlugin.Stop() - } - - if ipamPlugin != nil { - ipamPlugin.Stop() - } - - log.Close() -} diff --git a/cnm/plugin_linux.go b/cnm/plugin_linux.go deleted file mode 100644 index e552c98b4..000000000 --- a/cnm/plugin_linux.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -// +build linux - -package cnm - -import ( - "os" - - "github.com/Azure/azure-container-networking/common" -) - -const ( - // Default API server URL. - defaultAPIServerURL = "unix:///run/docker/plugins/" - - // Docker plugin paths. - pluginSpecPath = "/etc/docker/plugins/" - pluginSocketPath = "/run/docker/plugins/" -) - -// GetAPIServerURL returns the API server URL. -func (plugin *Plugin) getAPIServerURL() string { - urls, _ := plugin.GetOption(common.OptAPIServerURL).(string) - if urls == "" { - urls = defaultAPIServerURL + plugin.Name + ".sock" - } - - os.MkdirAll(pluginSocketPath, 0o755) - - return urls -} - -// GetSpecPath returns the Docker plugin spec path. -func (plugin *Plugin) getSpecPath() string { - return pluginSpecPath -} diff --git a/cnm/plugin_windows.go b/cnm/plugin_windows.go deleted file mode 100644 index b6ade5153..000000000 --- a/cnm/plugin_windows.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -// +build windows - -package cnm - -import ( - "os" - - "github.com/Azure/azure-container-networking/common" -) - -const ( - // Default API server URL. - defaultAPIServerURL = "tcp://localhost:48080" - - // Docker plugin paths. - pluginSpecPath = "\\docker\\plugins\\" -) - -// GetAPIServerURL returns the API server URL. -func (plugin *Plugin) getAPIServerURL() string { - urls, _ := plugin.GetOption(common.OptAPIServerURL).(string) - if urls == "" { - urls = defaultAPIServerURL - } - - return urls -} - -// GetSpecPath returns the Docker plugin spec path. -func (plugin *Plugin) getSpecPath() string { - return os.Getenv("programdata") + pluginSpecPath -} diff --git a/cns/api.go b/cns/api.go index 872b67c73..9c0f418b4 100644 --- a/cns/api.go +++ b/cns/api.go @@ -22,11 +22,7 @@ const ( DeleteNetworkPath = "/network/delete" CreateHnsNetworkPath = "/network/hns/create" DeleteHnsNetworkPath = "/network/hns/delete" - ReserveIPAddressPath = "/network/ip/reserve" - ReleaseIPAddressPath = "/network/ip/release" GetHostLocalIPPath = "/network/ip/hostlocal" - GetIPAddressUtilizationPath = "/network/ip/utilization" - GetUnhealthyIPAddressesPath = "/network/ipaddresses/unhealthy" GetHealthReportPath = "/network/health" NumberOfCPUCoresPath = "/hostcpucores" CreateHostNCApipaEndpointPath = "/network/createhostncapipaendpoint" diff --git a/cns/ipamclient/ipamclient.go b/cns/ipamclient/ipamclient.go deleted file mode 100644 index 369a3c419..000000000 --- a/cns/ipamclient/ipamclient.go +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -package ipamclient - -import ( - "bytes" - "encoding/json" - "fmt" - - cnmIpam "github.com/Azure/azure-container-networking/cnm/ipam" - ipam "github.com/Azure/azure-container-networking/ipam" - "github.com/Azure/azure-container-networking/log" -) - -// IpamClient specifies a client to connect to Ipam Plugin. -type IpamClient struct { - connectionURL string -} - -// NewIpamClient create a new ipam client. -func NewIpamClient(url string) (*IpamClient, error) { - if url == "" { - url = defaultIpamPluginURL - } - return &IpamClient{ - connectionURL: url, - }, nil -} - -// GetAddressSpace request to get address space ID. -func (ic *IpamClient) GetAddressSpace() (string, error) { - log.Printf("[Azure CNS] GetAddressSpace Request") - - client, err := getClient(ic.connectionURL) - if err != nil { - return "", err - } - - url := ic.connectionURL + cnmIpam.GetAddressSpacesPath - - res, err := client.Post(url, "application/json", nil) - if err != nil { - log.Printf("[Azure CNS] HTTP Post returned error %v", err.Error()) - return "", err - } - - defer res.Body.Close() - - if res.StatusCode == 200 { - var resp cnmIpam.GetDefaultAddressSpacesResponse - err := json.NewDecoder(res.Body).Decode(&resp) - if err != nil { - log.Printf("[Azure CNS] Error received while parsing GetAddressSpace response resp:%v err:%v", res.Body, err.Error()) - return "", err - } - - if resp.Err != "" { - log.Printf("[Azure CNS] GetAddressSpace received error response :%v", resp.Err) - return "", fmt.Errorf(resp.Err) - } - - return resp.LocalDefaultAddressSpace, nil - } - log.Printf("[Azure CNS] GetAddressSpace invalid http status code: %v err:%v", res.StatusCode, err.Error()) - return "", err -} - -// GetPoolID Request to get poolID. -func (ic *IpamClient) GetPoolID(asID, subnet string) (string, error) { - var body bytes.Buffer - log.Printf("[Azure CNS] GetPoolID Request") - - client, err := getClient(ic.connectionURL) - if err != nil { - return "", err - } - - url := ic.connectionURL + cnmIpam.RequestPoolPath - - payload := &cnmIpam.RequestPoolRequest{ - AddressSpace: asID, - Pool: subnet, - } - - json.NewEncoder(&body).Encode(payload) - - res, err := client.Post(url, "application/json", &body) - if err != nil { - log.Printf("[Azure CNS] HTTP Post returned error %v", err.Error()) - return "", err - } - - defer res.Body.Close() - - if res.StatusCode == 200 { - var resp cnmIpam.RequestPoolResponse - err := json.NewDecoder(res.Body).Decode(&resp) - if err != nil { - log.Printf("[Azure CNS] Error received while parsing GetPoolID response resp:%v err:%v", res.Body, err.Error()) - return "", err - } - - if resp.Err != "" { - log.Printf("[Azure CNS] GetPoolID received error response :%v", resp.Err) - return "", fmt.Errorf(resp.Err) - } - - return resp.PoolID, nil - } - log.Printf("[Azure CNS] GetPoolID invalid http status code: %v err:%v", res.StatusCode, err.Error()) - return "", err -} - -// ReserveIPAddress request an Ip address for the reservation id. -func (ic *IpamClient) ReserveIPAddress(poolID string, reservationID string) (string, error) { - var body bytes.Buffer - log.Printf("[Azure CNS] ReserveIpAddress") - - client, err := getClient(ic.connectionURL) - if err != nil { - return "", err - } - - url := ic.connectionURL + cnmIpam.RequestAddressPath - - payload := &cnmIpam.RequestAddressRequest{ - PoolID: poolID, - Address: "", - Options: make(map[string]string), - } - payload.Options[ipam.OptAddressID] = reservationID - json.NewEncoder(&body).Encode(payload) - - res, err := client.Post(url, "application/json", &body) - if err != nil { - log.Printf("[Azure CNS] HTTP Post returned error %v", err.Error()) - return "", err - } - - defer res.Body.Close() - - if res.StatusCode == 200 { - var reserveResp cnmIpam.RequestAddressResponse - - err = json.NewDecoder(res.Body).Decode(&reserveResp) - if err != nil { - log.Printf("[Azure CNS] Error received while parsing reserve response resp:%v err:%v", res.Body, err.Error()) - return "", err - } - - if reserveResp.Err != "" { - log.Printf("[Azure CNS] ReserveIP received error response :%v", reserveResp.Err) - return "", fmt.Errorf(reserveResp.Err) - } - - return reserveResp.Address, nil - } - - log.Printf("[Azure CNS] ReserveIp invalid http status code: %v err:%v", res.StatusCode, err.Error()) - return "", err -} - -// ReleaseIPAddress release an IP address for the reservation id. -func (ic *IpamClient) ReleaseIPAddress(poolID string, reservationID string) error { - var body bytes.Buffer - log.Printf("[Azure CNS] ReleaseIPAddress") - - client, err := getClient(ic.connectionURL) - if err != nil { - return err - } - - url := ic.connectionURL + cnmIpam.ReleaseAddressPath - - payload := &cnmIpam.ReleaseAddressRequest{ - PoolID: poolID, - Address: "", - Options: make(map[string]string), - } - - payload.Options[ipam.OptAddressID] = reservationID - - json.NewEncoder(&body).Encode(payload) - - res, err := client.Post(url, "application/json", &body) - if err != nil { - log.Printf("[Azure CNS] HTTP Post returned error %v", err.Error()) - return err - } - - defer res.Body.Close() - - if res.StatusCode == 200 { - var releaseResp cnmIpam.ReleaseAddressResponse - err := json.NewDecoder(res.Body).Decode(&releaseResp) - if err != nil { - log.Printf("[Azure CNS] Error received while parsing release response :%v err:%v", res.Body, err.Error()) - return err - } - - if releaseResp.Err != "" { - log.Printf("[Azure CNS] ReleaseIP received error response :%v", releaseResp.Err) - return fmt.Errorf(releaseResp.Err) - } - - return nil - } - log.Printf("[Azure CNS] ReleaseIP invalid http status code: %v", res.StatusCode) - return err -} - -// GetIPAddressUtilization - returns number of available, reserved and unhealthy addresses list. -func (ic *IpamClient) GetIPAddressUtilization(poolID string) (int, int, []string, error) { - var body bytes.Buffer - log.Printf("[Azure CNS] GetIPAddressUtilization") - - client, err := getClient(ic.connectionURL) - if err != nil { - return 0, 0, nil, err - } - url := ic.connectionURL + cnmIpam.GetPoolInfoPath - - payload := &cnmIpam.GetPoolInfoRequest{ - PoolID: poolID, - } - - json.NewEncoder(&body).Encode(payload) - - res, err := client.Post(url, "application/json", &body) - if err != nil { - log.Printf("[Azure CNS] HTTP Post returned error %v", err.Error()) - return 0, 0, nil, err - } - - defer res.Body.Close() - - if res.StatusCode == 200 { - var poolInfoResp cnmIpam.GetPoolInfoResponse - err := json.NewDecoder(res.Body).Decode(&poolInfoResp) - if err != nil { - log.Printf("[Azure CNS] Error received while parsing GetIPUtilization response :%v err:%v", res.Body, err.Error()) - return 0, 0, nil, err - } - - if poolInfoResp.Err != "" { - log.Printf("[Azure CNS] GetIPUtilization received error response :%v", poolInfoResp.Err) - return 0, 0, nil, fmt.Errorf(poolInfoResp.Err) - } - - return poolInfoResp.Capacity, poolInfoResp.Available, poolInfoResp.UnhealthyAddresses, nil - } - log.Printf("[Azure CNS] GetIPUtilization invalid http status code: %v err:%v", res.StatusCode, err.Error()) - return 0, 0, nil, err -} diff --git a/cns/ipamclient/ipamclient_linux.go b/cns/ipamclient/ipamclient_linux.go deleted file mode 100644 index cb3afbd30..000000000 --- a/cns/ipamclient/ipamclient_linux.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -// +build linux - -package ipamclient - -import ( - "context" - "net" - "net/http" - - "github.com/Azure/azure-container-networking/cns/logger" -) - -const ( - defaultIpamPluginURL = "http://unix" - pluginSockPath = "/run/docker/plugins/azure-vnet.sock" -) - -// getClient - returns unix http client -func getClient(url string) (*http.Client, error) { - var httpc *http.Client - if url == defaultIpamPluginURL { - dialContext, err := net.Dial("unix", pluginSockPath) - if err != nil { - logger.Errorf("[Azure CNS] Error.Dial context error %v", err.Error()) - return nil, err - } - - httpc = &http.Client{ - Transport: &http.Transport{ - DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { - return dialContext, nil - }, - }, - } - } else { - httpc = &http.Client{} - } - - return httpc, nil -} diff --git a/cns/ipamclient/ipamclient_test.go b/cns/ipamclient/ipamclient_test.go deleted file mode 100644 index 3aea70811..000000000 --- a/cns/ipamclient/ipamclient_test.go +++ /dev/null @@ -1,213 +0,0 @@ -package ipamclient - -import ( - "fmt" - "log" - "net/http" - "net/url" - "os" - "testing" - - "github.com/Azure/azure-container-networking/cnm/ipam" - "github.com/Azure/azure-container-networking/common" -) - -var ( - ipamQueryUrl = "localhost:42424" - ic *IpamClient -) - -// Wraps the test run with service setup and teardown. -func TestMain(m *testing.M) { - // Create a fake IPAM plugin to handle requests from CNS plugin. - u, _ := url.Parse("tcp://" + ipamQueryUrl) - ipamAgent, err := common.NewListener(u) - if err != nil { - fmt.Printf("Failed to create agent, err:%v.\n", err) - return - } - ipamAgent.AddHandler(ipam.GetAddressSpacesPath, handleIpamAsIDQuery) - ipamAgent.AddHandler(ipam.RequestPoolPath, handlePoolIDQuery) - ipamAgent.AddHandler(ipam.RequestAddressPath, handleReserveIPQuery) - ipamAgent.AddHandler(ipam.ReleasePoolPath, handleReleaseIPQuery) - ipamAgent.AddHandler(ipam.GetPoolInfoPath, handleIPUtilizationQuery) - - err = ipamAgent.Start(make(chan error, 1)) - if err != nil { - fmt.Printf("Failed to start agent, err:%v.\n", err) - return - } - ic, err = NewIpamClient("http://" + ipamQueryUrl) - if err != nil { - fmt.Printf("Ipam client creation failed %+v", err) - } - - // Run tests. - exitCode := m.Run() - - ipamAgent.Stop() - - os.Exit(exitCode) -} - -// Handles queries from GetAddressSpace. -func handleIpamAsIDQuery(w http.ResponseWriter, r *http.Request) { - addressSpaceResp := "{\"LocalDefaultAddressSpace\": \"local\", \"GlobalDefaultAddressSpace\": \"global\"}" - w.Write([]byte(addressSpaceResp)) -} - -// Handles queries from GetPoolID -func handlePoolIDQuery(w http.ResponseWriter, r *http.Request) { - requestPoolResp := "{\"PoolID\":\"10.0.0.0/16\", \"Pool\": \"\"}" - w.Write([]byte(requestPoolResp)) -} - -// Handles queries from ReserveIPAddress. -func handleReserveIPQuery(w http.ResponseWriter, r *http.Request) { - reserveIPResp := "{\"Address\":\"10.0.0.2/16\"}" - w.Write([]byte(reserveIPResp)) -} - -// Handles queries from ReleaseIPAddress. -func handleReleaseIPQuery(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("{}")) -} - -// Handles queries from GetIPAddressUtiltization. -func handleIPUtilizationQuery(w http.ResponseWriter, r *http.Request) { - ipUtilizationResp := "{\"Capacity\":10, \"Available\":7, \"UnhealthyAddresses\":[\"10.0.0.5\",\"10.0.0.6\",\"10.0.0.7\"]}" - w.Write([]byte(ipUtilizationResp)) -} - -// Tests IpamClient GetAddressSpace function to get AddressSpaceID. -func TestAddressSpaces(t *testing.T) { - asID, err := ic.GetAddressSpace() - if err != nil { - t.Errorf("GetAddressSpace failed with %v\n", err) - return - } - - if asID != "local" { - t.Errorf("GetAddressSpace failed with invalid as id %s", asID) - } -} - -// Tests IpamClient GetPoolID function to get PoolID. -func TestGetPoolID(t *testing.T) { - subnet := "10.0.0.0/16" - - asID, err := ic.GetAddressSpace() - if err != nil { - t.Errorf("GetAddressSpace failed with %v\n", err) - return - } - - poolID, err := ic.GetPoolID(asID, subnet) - if err != nil { - t.Errorf("GetPoolID failed with %v\n", err) - return - } - - if poolID != "10.0.0.0/16" { - t.Errorf("GetPoolId failed with invalid pool id %s", poolID) - } -} - -// Tests IpamClient ReserveIPAddress function to request IP for ID. -func TestReserveIP(t *testing.T) { - subnet := "10.0.0.0/16" - - asID, err := ic.GetAddressSpace() - if err != nil { - t.Errorf("GetAddressSpace failed with %v\n", err) - return - } - - poolID, err := ic.GetPoolID(asID, subnet) - if err != nil { - t.Errorf("GetPoolID failed with %v\n", err) - return - } - - addr1, err := ic.ReserveIPAddress(poolID, "id1") - if err != nil { - t.Errorf("GetReserveIP failed with %v\n", err) - return - } - if addr1 != "10.0.0.2/16" { - t.Errorf("GetReserveIP returned ivnvalid IP %s\n", addr1) - return - } - addr2, err := ic.ReserveIPAddress(poolID, "id1") - if err != nil { - t.Errorf("GetReserveIP failed with %v\n", err) - return - } - if addr1 != addr2 { - t.Errorf("GetReserveIP with id returned ivnvalid IP1 %s IP2 %s\n", addr1, addr2) - return - } -} - -// Tests IpamClient ReleaseIPAddress function to release IP associated with ID. -func TestReleaseIP(t *testing.T) { - subnet := "10.0.0.0/16" - - asID, err := ic.GetAddressSpace() - if err != nil { - t.Errorf("GetAddressSpace failed with %v\n", err) - return - } - - poolID, err := ic.GetPoolID(asID, subnet) - if err != nil { - t.Errorf("GetPoolID failed with %v\n", err) - return - } - - addr1, err := ic.ReserveIPAddress(poolID, "id1") - if err != nil { - t.Errorf("GetReserveIP failed with %v\n", err) - return - } - if addr1 != "10.0.0.2/16" { - t.Errorf("GetReserveIP returned ivnvalid IP %s\n", addr1) - return - } - - err = ic.ReleaseIPAddress(poolID, "id1") - if err != nil { - t.Errorf("Release reservation failed with %v\n", err) - return - } -} - -// Tests IpamClient GetIPAddressUtilization function to retrieve IP Utilization info. -func TestIPAddressUtilization(t *testing.T) { - subnet := "10.0.0.0/16" - - asID, err := ic.GetAddressSpace() - if err != nil { - t.Errorf("GetAddressSpace failed with %v\n", err) - return - } - - poolID, err := ic.GetPoolID(asID, subnet) - if err != nil { - t.Errorf("GetPoolID failed with %v\n", err) - return - } - - capacity, available, unhealthyAddrs, err := ic.GetIPAddressUtilization(poolID) - if err != nil { - t.Errorf("GetIPUtilization failed with %v\n", err) - return - } - - if capacity != 10 && available != 7 && len(unhealthyAddrs) == 3 { - t.Errorf("GetIPUtilization returned invalid either capacity %v / available %v count/ unhealthyaddrs %v \n", capacity, available, unhealthyAddrs) - return - } - - log.Printf("Capacity %v Available %v Unhealthy %v", capacity, available, unhealthyAddrs) -} diff --git a/cns/ipamclient/ipamclient_windows.go b/cns/ipamclient/ipamclient_windows.go deleted file mode 100644 index fac502a73..000000000 --- a/cns/ipamclient/ipamclient_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2017 Microsoft. All rights reserved. -// MIT License - -// +build windows - -package ipamclient - -import ( - "net/http" -) - -const ( - defaultIpamPluginURL = "http://localhost:48080" -) - -func getClient(url string) (http.Client, error) { - httpc := http.Client{} - return httpc, nil -} diff --git a/cns/restserver/api.go b/cns/restserver/api.go index a3e38fdc6..07cfc283c 100644 --- a/cns/restserver/api.go +++ b/cns/restserver/api.go @@ -8,7 +8,6 @@ import ( "encoding/json" "fmt" "io" - "net" "net/http" "net/url" "regexp" @@ -335,161 +334,6 @@ func (service *HTTPRestService) deleteHnsNetwork(w http.ResponseWriter, r *http. logger.Response(service.Name, resp, resp.ReturnCode, err) } -// Handles ip reservation requests. -func (service *HTTPRestService) reserveIPAddress(w http.ResponseWriter, r *http.Request) { - logger.Printf("[Azure CNS] reserveIPAddress") - - var req cns.ReserveIPAddressRequest - var returnCode types.ResponseCode - returnMessage := "" - addr := "" - address := "" - err := common.Decode(w, r, &req) - - logger.Request(service.Name, &req, err) - - if err != nil { - return - } - - if req.ReservationID == "" { - returnCode = types.ReservationNotFound - returnMessage = "[Azure CNS] Error. ReservationId is empty" - } - - switch r.Method { - case http.MethodPost: - ic := service.ipamClient - - var ifInfo *wireserver.InterfaceInfo - ifInfo, err = service.getPrimaryHostInterface(context.TODO()) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPrimaryIfaceInfo failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - asID, err := ic.GetAddressSpace() - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetAddressSpace failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - poolID, err := ic.GetPoolID(asID, ifInfo.Subnet) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPoolID failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - addr, err = ic.ReserveIPAddress(poolID, req.ReservationID) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] ReserveIpAddress failed with %+v", err.Error()) - returnCode = types.AddressUnavailable - break - } - - addressIP, _, err := net.ParseCIDR(addr) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] ParseCIDR failed with %+v", err.Error()) - returnCode = types.UnexpectedError - break - } - address = addressIP.String() - - default: - returnMessage = "[Azure CNS] Error. ReserveIP did not receive a POST." - returnCode = types.InvalidParameter - - } - - resp := cns.Response{ - ReturnCode: returnCode, - Message: returnMessage, - } - - if resp.ReturnCode == 0 { - // If Response is success i.e. code 0, then publish metrics. - publishIPStateMetrics(service.buildIPState()) - } - - reserveResp := &cns.ReserveIPAddressResponse{Response: resp, IPAddress: address} - err = common.Encode(w, &reserveResp) - logger.Response(service.Name, reserveResp, resp.ReturnCode, err) -} - -// Handles release ip reservation requests. -func (service *HTTPRestService) releaseIPAddress(w http.ResponseWriter, r *http.Request) { - logger.Printf("[Azure CNS] releaseIPAddress") - - var req cns.ReleaseIPAddressRequest - var returnCode types.ResponseCode - returnMessage := "" - - err := common.Decode(w, r, &req) - logger.Request(service.Name, &req, err) - - if err != nil { - return - } - - if req.ReservationID == "" { - returnCode = types.ReservationNotFound - returnMessage = "[Azure CNS] Error. ReservationId is empty" - } - - switch r.Method { - case http.MethodPost: - ic := service.ipamClient - - var ifInfo *wireserver.InterfaceInfo - ifInfo, err = service.getPrimaryHostInterface(context.TODO()) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPrimaryIfaceInfo failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - asID, err := ic.GetAddressSpace() - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetAddressSpace failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - poolID, err := ic.GetPoolID(asID, ifInfo.Subnet) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPoolID failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - err = ic.ReleaseIPAddress(poolID, req.ReservationID) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] ReleaseIpAddress failed with %+v", err.Error()) - returnCode = types.ReservationNotFound - } - - default: - returnMessage = "[Azure CNS] Error. ReleaseIP did not receive a POST." - returnCode = types.InvalidParameter - } - - resp := cns.Response{ - ReturnCode: returnCode, - Message: returnMessage, - } - - if resp.ReturnCode == 0 { - // If Response is success i.e. code 0, then publish metrics. - publishIPStateMetrics(service.buildIPState()) - } - - err = common.Encode(w, &resp) - logger.Response(service.Name, resp, resp.ReturnCode, err) -} - // Retrieves the host local ip address. Containers can talk to host using this IP address. func (service *HTTPRestService) getHostLocalIP(w http.ResponseWriter, r *http.Request) { logger.Printf("[Azure CNS] getHostLocalIP") @@ -542,71 +386,6 @@ func (service *HTTPRestService) getHostLocalIP(w http.ResponseWriter, r *http.Re logger.Response(service.Name, hostLocalIPResponse, resp.ReturnCode, err) } -// Handles ip address utilization requests. -func (service *HTTPRestService) getIPAddressUtilization(w http.ResponseWriter, r *http.Request) { - logger.Printf("[Azure CNS] getIPAddressUtilization") - logger.Request(service.Name, "getIPAddressUtilization", nil) - - var returnCode types.ResponseCode - returnMessage := "" - capacity := 0 - available := 0 - var unhealthyAddrs []string - - switch r.Method { - case http.MethodGet: - ic := service.ipamClient - - ifInfo, err := service.getPrimaryHostInterface(context.TODO()) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPrimaryIfaceInfo failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - asID, err := ic.GetAddressSpace() - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetAddressSpace failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - poolID, err := ic.GetPoolID(asID, ifInfo.Subnet) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPoolID failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - capacity, available, unhealthyAddrs, err = ic.GetIPAddressUtilization(poolID) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetIPUtilization failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - logger.Printf("[Azure CNS] Capacity %v Available %v UnhealthyAddrs %v", capacity, available, unhealthyAddrs) - - default: - returnMessage = "[Azure CNS] Error. GetIPUtilization did not receive a GET." - returnCode = types.InvalidParameter - } - - resp := cns.Response{ - ReturnCode: returnCode, - Message: returnMessage, - } - - utilResponse := &cns.IPAddressesUtilizationResponse{ - Response: resp, - Available: available, - Reserved: capacity - available, - Unhealthy: len(unhealthyAddrs), - } - - err := common.Encode(w, &utilResponse) - logger.Response(service.Name, utilResponse, resp.ReturnCode, err) -} - // Handles retrieval of ip addresses that are available to be reserved from ipam driver. func (service *HTTPRestService) getAvailableIPAddresses(w http.ResponseWriter, r *http.Request) { logger.Printf("[Azure CNS] getAvailableIPAddresses") @@ -631,69 +410,6 @@ func (service *HTTPRestService) getReservedIPAddresses(w http.ResponseWriter, r logger.Response(service.Name, ipResp, resp.ReturnCode, err) } -// Handles retrieval of ghost ip addresses from ipam driver. -func (service *HTTPRestService) getUnhealthyIPAddresses(w http.ResponseWriter, r *http.Request) { - logger.Printf("[Azure CNS] getUnhealthyIPAddresses") - logger.Request(service.Name, "getUnhealthyIPAddresses", nil) - - var returnCode types.ResponseCode - returnMessage := "" - capacity := 0 - available := 0 - var unhealthyAddrs []string - - switch r.Method { - case http.MethodGet: - ic := service.ipamClient - - ifInfo, err := service.getPrimaryHostInterface(context.TODO()) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPrimaryIfaceInfo failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - asID, err := ic.GetAddressSpace() - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetAddressSpace failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - poolID, err := ic.GetPoolID(asID, ifInfo.Subnet) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetPoolID failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - - capacity, available, unhealthyAddrs, err = ic.GetIPAddressUtilization(poolID) - if err != nil { - returnMessage = fmt.Sprintf("[Azure CNS] Error. GetIPUtilization failed %v", err.Error()) - returnCode = types.UnexpectedError - break - } - logger.Printf("[Azure CNS] Capacity %v Available %v UnhealthyAddrs %v", capacity, available, unhealthyAddrs) - - default: - returnMessage = "[Azure CNS] Error. GetUnhealthyIP did not receive a POST." - returnCode = types.InvalidParameter - } - - resp := cns.Response{ - ReturnCode: returnCode, - Message: returnMessage, - } - - ipResp := &cns.GetIPAddressesResponse{ - Response: resp, - IPAddresses: unhealthyAddrs, - } - - err := common.Encode(w, &ipResp) - logger.Response(service.Name, ipResp, resp.ReturnCode, err) -} - // getAllIPAddresses retrieves all ip addresses from ipam driver. func (service *HTTPRestService) getAllIPAddresses(w http.ResponseWriter, r *http.Request) { logger.Printf("[Azure CNS] getAllIPAddresses") diff --git a/cns/restserver/restserver.go b/cns/restserver/restserver.go index 1e39c9e8c..c74580f29 100644 --- a/cns/restserver/restserver.go +++ b/cns/restserver/restserver.go @@ -11,7 +11,6 @@ import ( "github.com/Azure/azure-container-networking/cns" "github.com/Azure/azure-container-networking/cns/common" "github.com/Azure/azure-container-networking/cns/dockerclient" - "github.com/Azure/azure-container-networking/cns/ipamclient" "github.com/Azure/azure-container-networking/cns/logger" "github.com/Azure/azure-container-networking/cns/networkcontainers" "github.com/Azure/azure-container-networking/cns/routes" @@ -58,7 +57,6 @@ type HTTPRestService struct { *cns.Service dockerClient *dockerclient.Client wscli interfaceGetter - ipamClient *ipamclient.IpamClient nma nmagentClient wsproxy wireserverProxy homeAzMonitor *HomeAzMonitor @@ -182,11 +180,6 @@ func NewHTTPRestService(config *common.ServiceConfig, wscli interfaceGetter, wsp return nil, err } - ic, err := ipamclient.NewIpamClient("") - if err != nil { - return nil, err - } - res, err := wscli.GetInterfaces(context.TODO()) // TODO(rbtr): thread context through this client if err != nil { return nil, errors.Wrap(err, "failed to get interfaces from IMDS") @@ -218,7 +211,6 @@ func NewHTTPRestService(config *common.ServiceConfig, wscli interfaceGetter, wsp store: service.Service.Store, dockerClient: dc, wscli: wscli, - ipamClient: ic, nma: nmagentClient, wsproxy: wsproxy, networkContainer: nc, @@ -256,11 +248,7 @@ func (service *HTTPRestService) Init(config *common.ServiceConfig) error { listener.AddHandler(cns.SetEnvironmentPath, service.setEnvironment) listener.AddHandler(cns.CreateNetworkPath, service.createNetwork) listener.AddHandler(cns.DeleteNetworkPath, service.deleteNetwork) - listener.AddHandler(cns.ReserveIPAddressPath, service.reserveIPAddress) - listener.AddHandler(cns.ReleaseIPAddressPath, service.releaseIPAddress) listener.AddHandler(cns.GetHostLocalIPPath, service.getHostLocalIP) - listener.AddHandler(cns.GetIPAddressUtilizationPath, service.getIPAddressUtilization) - listener.AddHandler(cns.GetUnhealthyIPAddressesPath, service.getUnhealthyIPAddresses) listener.AddHandler(cns.CreateOrUpdateNetworkContainer, service.createOrUpdateNetworkContainer) listener.AddHandler(cns.DeleteNetworkContainer, service.deleteNetworkContainer) listener.AddHandler(cns.GetInterfaceForContainer, service.getInterfaceForContainer) @@ -296,11 +284,7 @@ func (service *HTTPRestService) Init(config *common.ServiceConfig) error { listener.AddHandler(cns.V2Prefix+cns.SetEnvironmentPath, service.setEnvironment) listener.AddHandler(cns.V2Prefix+cns.CreateNetworkPath, service.createNetwork) listener.AddHandler(cns.V2Prefix+cns.DeleteNetworkPath, service.deleteNetwork) - listener.AddHandler(cns.V2Prefix+cns.ReserveIPAddressPath, service.reserveIPAddress) - listener.AddHandler(cns.V2Prefix+cns.ReleaseIPAddressPath, service.releaseIPAddress) listener.AddHandler(cns.V2Prefix+cns.GetHostLocalIPPath, service.getHostLocalIP) - listener.AddHandler(cns.V2Prefix+cns.GetIPAddressUtilizationPath, service.getIPAddressUtilization) - listener.AddHandler(cns.V2Prefix+cns.GetUnhealthyIPAddressesPath, service.getUnhealthyIPAddresses) listener.AddHandler(cns.V2Prefix+cns.CreateOrUpdateNetworkContainer, service.createOrUpdateNetworkContainer) listener.AddHandler(cns.V2Prefix+cns.DeleteNetworkContainer, service.deleteNetworkContainer) listener.AddHandler(cns.V2Prefix+cns.GetInterfaceForContainer, service.getInterfaceForContainer) diff --git a/cns/service/main.go b/cns/service/main.go index 50f2b53d4..81910cb22 100644 --- a/cns/service/main.go +++ b/cns/service/main.go @@ -19,8 +19,6 @@ import ( "time" "github.com/Azure/azure-container-networking/aitelemetry" - "github.com/Azure/azure-container-networking/cnm/ipam" - "github.com/Azure/azure-container-networking/cnm/network" "github.com/Azure/azure-container-networking/cns" cnsclient "github.com/Azure/azure-container-networking/cns/client" cnscli "github.com/Azure/azure-container-networking/cns/cmd/cli" @@ -212,13 +210,6 @@ var args = acn.ArgumentList{ Type: "string", DefaultValue: "", }, - { - Name: acn.OptStartAzureCNM, - Shorthand: acn.OptStartAzureCNMAlias, - Description: "Start Azure-CNM if flag is set", - Type: "bool", - DefaultValue: false, - }, { Name: acn.OptVersion, Shorthand: acn.OptVersionAlias, @@ -226,6 +217,13 @@ var args = acn.ArgumentList{ Type: "bool", DefaultValue: false, }, + { + Name: acn.OptStoreFileLocation, + Shorthand: acn.OptStoreFileLocationAlias, + Description: "Set store file absolute path", + Type: "string", + DefaultValue: platform.CNMRuntimePath, + }, { Name: acn.OptNetPluginPath, Shorthand: acn.OptNetPluginPathAlias, @@ -268,13 +266,6 @@ var args = acn.ArgumentList{ Type: "int", DefaultValue: "120", }, - { - Name: acn.OptStoreFileLocation, - Shorthand: acn.OptStoreFileLocationAlias, - Description: "Set store file absolute path", - Type: "string", - DefaultValue: platform.CNMRuntimePath, - }, { Name: acn.OptPrivateEndpoint, Shorthand: acn.OptPrivateEndpointAlias, @@ -497,8 +488,6 @@ func main() { // Initialize and parse command line arguments. acn.ParseArgs(&args, printVersion) - environment := acn.GetArg(acn.OptEnvironment).(string) - url := acn.GetArg(acn.OptAPIServerURL).(string) cniPath := acn.GetArg(acn.OptNetPluginPath).(string) cniConfigFile := acn.GetArg(acn.OptNetPluginConfigFile).(string) cnsURL := acn.GetArg(acn.OptCnsURL).(string) @@ -506,10 +495,7 @@ func main() { logLevel := acn.GetArg(acn.OptLogLevel).(int) logTarget := acn.GetArg(acn.OptLogTarget).(int) logDirectory := acn.GetArg(acn.OptLogLocation).(string) - ipamQueryUrl := acn.GetArg(acn.OptIpamQueryUrl).(string) - ipamQueryInterval := acn.GetArg(acn.OptIpamQueryInterval).(int) - startCNM := acn.GetArg(acn.OptStartAzureCNM).(bool) vers := acn.GetArg(acn.OptVersion).(bool) createDefaultExtNetworkType := acn.GetArg(acn.OptCreateDefaultExtNetworkType).(string) telemetryEnabled := acn.GetArg(acn.OptTelemetry).(bool) @@ -1024,65 +1010,6 @@ func main() { }(privateEndpoint, infravnet, nodeID) } - var ( - netPlugin network.NetPlugin - ipamPlugin ipam.IpamPlugin - lockclientCnm processlock.Interface - ) - - if startCNM { - var pluginConfig acn.PluginConfig - pluginConfig.Version = version - - // Create a channel to receive unhandled errors from the plugins. - pluginConfig.ErrChan = make(chan error, 1) - - // Create network plugin. - netPlugin, err = network.NewPlugin(&pluginConfig) - if err != nil { - logger.Errorf("Failed to create network plugin, err:%v.\n", err) - return - } - - // Create IPAM plugin. - ipamPlugin, err = ipam.NewPlugin(&pluginConfig) - if err != nil { - logger.Errorf("Failed to create IPAM plugin, err:%v.\n", err) - return - } - - lockclientCnm, err = processlock.NewFileLock(platform.CNILockPath + pluginName + store.LockExtension) - if err != nil { - log.Printf("Error initializing file lock:%v", err) - return - } - - // Create the key value store. - pluginStoreFile := storeFileLocation + pluginName + ".json" - pluginConfig.Store, err = store.NewJsonFileStore(pluginStoreFile, lockclientCnm, nil) - if err != nil { - logger.Errorf("Failed to create plugin store file %s, due to error : %v\n", pluginStoreFile, err) - return - } - - // Set plugin options. - netPlugin.SetOption(acn.OptAPIServerURL, url) - logger.Printf("Start netplugin\n") - if err := netPlugin.Start(&pluginConfig); err != nil { - logger.Errorf("Failed to create network plugin, err:%v.\n", err) - return - } - - ipamPlugin.SetOption(acn.OptEnvironment, environment) - ipamPlugin.SetOption(acn.OptAPIServerURL, url) - ipamPlugin.SetOption(acn.OptIpamQueryUrl, ipamQueryUrl) - ipamPlugin.SetOption(acn.OptIpamQueryInterval, ipamQueryInterval) - if err := ipamPlugin.Start(&pluginConfig); err != nil { - logger.Errorf("Failed to create IPAM plugin, err:%v.\n", err) - return - } - } - // mark the service as "ready" close(readyCh) // block until process exiting @@ -1102,22 +1029,6 @@ func main() { httpRemoteRestService.Stop() } - if startCNM { - logger.Printf("stop cnm plugin") - if netPlugin != nil { - netPlugin.Stop() - } - - if ipamPlugin != nil { - logger.Printf("stop ipam plugin") - ipamPlugin.Stop() - } - - if err = lockclientCnm.Unlock(); err != nil { - log.Errorf("lockclient cnm unlock error:%v", err) - } - } - if err = lockclient.Unlock(); err != nil { log.Errorf("lockclient cns unlock error:%v", err) } diff --git a/common/config.go b/common/config.go index 54e2dea27..3434c2e2e 100644 --- a/common/config.go +++ b/common/config.go @@ -49,10 +49,6 @@ const ( OptIpamQueryInterval = "ipam-query-interval" OptIpamQueryIntervalAlias = "i" - // Start CNM - OptStartAzureCNM = "start-azure-cnm" - OptStartAzureCNMAlias = "startcnm" - // Interval to send reports to host OptReportToHostInterval = "report-interval" OptReportToHostIntervalAlias = "hostinterval" diff --git a/docs/README.md b/docs/README.md index 1cb377b49..438ff3a58 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,6 @@ * [CNI plugin](cni.md) - describes how to setup Azure CNI plugins. * [Azure CNI Powered By Cilium](cilium.md) - describes the next generation of Azure CNI Plugin powered by Cilium dataplane. * [Azure CNI Overlay Mode for AKS](overlay-for-aks.md) - describes a mode of the Azure CNI Plugin to provide a Pod network from an overlay address space with no encapsulation. -* [CNM (libnetwork) plugin](cnm.md) - describes how to setup Azure CNM plugins. * [ACS](acs.md) - describes how to use the plugins with Azure Container Service. * [Network](network.md) - describes container networks created by plugins. * [IPAM](ipam.md) - describes how container IP address management is done by plugins. diff --git a/docs/cnm.md b/docs/cnm.md deleted file mode 100644 index 364dafa9a..000000000 --- a/docs/cnm.md +++ /dev/null @@ -1,95 +0,0 @@ -# Microsoft Azure Container Networking - -## Azure VNET CNM (libnetwork) Plugin -The `azure-vnet` libnetwork plugin implements the Docker libnetwork [network](https://github.com/docker/libnetwork/blob/master/docs/remote.md) and [IPAM](https://github.com/docker/libnetwork/blob/master/docs/ipam.md) remote plugin interfaces. - -The plugin is available on both Linux and Windows platforms. - -The network and IPAM plugins are designed to work together. The IPAM plugin can also be used by 3rd party software to manage IP addresses from Azure VNET space. - -This page describes how to setup the CNM plugin manually on Azure IaaS VMs. If you are planning to deploy an ACS cluster, see [ACS](acs.md) instead. - -## Install -Copy the plugin package from the [release](https://github.com/Azure/azure-container-networking/releases) share to your Azure VM, extract the contents and run the plugin in the background. - -```bash -# Get the last version from https://github.com/Azure/azure-container-networking/releases -$ PLUGIN_VERSION="v1.x.x" -$ curl -OsSL https://github.com/Azure/azure-container-networking/releases/download/${PLUGIN_VERSION}/azure-vnet-cnm-linux-amd64-${PLUGIN_VERSION}.tgz -$ tar xzvf azure-vnet-cnm-linux-amd64-${PLUGIN_VERSION}.tgz -# Might require sudo if not running as root -$ ./azure-cnm-plugin& -``` - -The `azure-vnet` plugin also requires the ebtables package when running on Linux. This step is not required on Windows. - -```bash -$ apt-get install -y ebtables -``` - -## Build -The plugin can also be built directly from the source code in this repository. - -```bash -$ git clone https://github.com/Azure/azure-container-networking -$ cd azure-container-networking -$ make azure-cnm-plugin -``` - -This builds the plugin and generates a tar archive. The binaries are placed in the `output` directory. - -## Usage -```bash -$ azure-cnm-plugin --help - -Usage: azure-cnm-plugin [OPTIONS] - -Options: - -e, --environment=azure Set the operating environment {azure,mas} - -u, --api-url Set the API server URL - -l, --log-level=info Set the logging level {info,debug} - -t, --log-target=logfile Set the logging target {syslog,stderr,logfile} - -o, --log-location Set the logging directory - -q, --ipam-query-url Set the IPAM query URL - -i, --ipam-query-interval Set the IPAM plugin query interval - -v, --version Print version information - -h, --help Print usage information -``` - -## Examples -To connect your containers to other resources on your Azure VNET, you need to first create a Docker network. A network is a group of uniquely addressable endpoints that can communicate with each other. Pass the plugin name as both the network and IPAM plugin. You also need to specify an Azure VNET subnet for your network. - -Create a network: - -```bash -$ docker network create --driver=azure-vnet --ipam-driver=azure-vnet --subnet=[subnet] azure -``` - -When the command succeeds, it will return the network ID. Confirm that the network was created successfully: - -```bash -$ docker network ls -NETWORK ID NAME DRIVER SCOPE -3159b0528a83 azure azure-vnet local -515779dadc8a bridge bridge local -ed6e704a74ef host host local -b35e3b663cc1 none null local -``` - -Connect containers to your network by specifying the `--net` argument with your network's name when running them: - -```bash -$ docker run -it --rm --net=azure ubuntu:latest /bin/bash -``` - -Finally, once all containers on the network exit, you can delete the network. - -```bash -$ docker network rm azure -``` - -## Outbound Connectivity from container -You have to add following iptable command to allow outbound(internet) connectivity from container -```bash -iptables -t nat -A POSTROUTING -m addrtype ! --dst-type local ! -d -j MASQUERADE -```