// requestAddress func requestAddress() func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { var ( content []byte err error areq = api.RequestAddressRequest{} decoder = json.NewDecoder(r.Body) ) logEvent("requestAddress") // Decode the JSON message err = decoder.Decode(&areq) if err != nil { httpError(w, "Could not read and parse requestAddress request", err) return } log.Infof("Received RequestAddressRequest: %+v", areq) // Build an alloc request to be sent to master allocReq := master.AddressAllocRequest{ NetworkID: areq.PoolID, PreferredIPv4Address: areq.Address, } subnetLen := strings.Split(areq.PoolID, "/")[1] var addr string if areq.Address != "" { addr = areq.Address + "/" + subnetLen } else { // Make a REST call to master var allocResp master.AddressAllocResponse err = cluster.MasterPostReq("/plugin/allocAddress", &allocReq, &allocResp) if err != nil { httpError(w, "master failed to allocate address", err) return } addr = allocResp.IPv4Address } // build response aresp := api.RequestAddressResponse{ Address: addr, } log.Infof("Sending RequestAddressResponse: %+v", aresp) // build json content, err = json.Marshal(aresp) if err != nil { httpError(w, "Could not generate requestAddress response", err) return } w.Write(content) } }
// createEP creates the specified EP in contiv func createEP(req *epSpec) (*epAttr, error) { // if the ep already exists, treat as error for now. netID := req.Network + "." + req.Tenant ep, err := netdGetEndpoint(netID + "-" + req.EndpointID) if err == nil { return nil, fmt.Errorf("EP %s already exists", req.EndpointID) } // Build endpoint request mreq := master.CreateEndpointRequest{ TenantName: req.Tenant, NetworkName: req.Network, ServiceName: req.Group, EndpointID: req.EndpointID, EPCommonName: req.Name, ConfigEP: intent.ConfigEP{ Container: req.EndpointID, Host: pluginHost, ServiceName: req.Group, }, } var mresp master.CreateEndpointResponse err = cluster.MasterPostReq("/plugin/createEndpoint", &mreq, &mresp) if err != nil { epCleanUp(req) return nil, err } log.Infof("Got endpoint create resp from master: %+v", mresp) // Ask netplugin to create the endpoint err = netPlugin.CreateEndpoint(netID + "-" + req.EndpointID) if err != nil { log.Errorf("Endpoint creation failed. Error: %s", err) epCleanUp(req) return nil, err } ep, err = netdGetEndpoint(netID + "-" + req.EndpointID) if err != nil { epCleanUp(req) return nil, err } log.Debug(ep) // need to get the subnetlen from nw state. nw, err := netdGetNetwork(netID) if err != nil { return nil, err } epResponse := epAttr{} epResponse.PortName = ep.PortName epResponse.IPAddress = ep.IPAddress + "/" + strconv.Itoa(int(nw.SubnetLen)) epResponse.Gateway = nw.Gateway return &epResponse, nil }
// deleteEndpoint deletes an endpoint using netplugin api func (its *integTestSuite) deleteEndpoint(tenantName, netName, epgName string, epCfg *mastercfg.CfgEndpointState) error { // Build endpoint delete request delreq := master.DeleteEndpointRequest{ TenantName: tenantName, NetworkName: netName, ServiceName: epgName, EndpointID: epCfg.EndpointID, } var delResp master.DeleteEndpointResponse err := cluster.MasterPostReq("/plugin/deleteEndpoint", &delreq, &delResp) if err != nil { log.Errorf("master failed to delete endpoint. Err: %v", err) return err } // delete the endpoint err = its.npcluster.PluginAgent.Plugin().DeleteEndpoint(epCfg.ID) if err != nil { log.Errorf("Error deleting endpoint %s. Err: %v", epCfg.ID, err) return err } return nil }
func (cniReq *cniServer) deleteMasterEndPoint() error { // delete from master delReq := master.DeleteEndpointRequest{ TenantName: cniReq.endPointLabels[cniapi.LabelTenantName], NetworkName: cniReq.endPointLabels[cniapi.LabelNetworkName], ServiceName: cniReq.endPointLabels[cniapi.LabelNetworkGroup], EndpointID: cniReq.pluginArgs.CniContainerid, } delResp := master.DeleteEndpointResponse{} if err := cluster.MasterPostReq("/plugin/deleteEndpoint", &delReq, &delResp); err != nil { cniLog.Errorf("failed to delete endpoint %s from master %s ", cniReq.endpointID, err.Error()) return err } return nil }
// Process Infra Nw Create // Auto allocate an endpoint for this node func processInfraNwCreate(netPlugin *plugin.NetPlugin, nwCfg *mastercfg.CfgNetworkState, opts cliOpts) (err error) { pluginHost := opts.hostLabel // Build endpoint request mreq := master.CreateEndpointRequest{ TenantName: nwCfg.Tenant, NetworkName: nwCfg.NetworkName, EndpointID: pluginHost, ConfigEP: intent.ConfigEP{ Container: pluginHost, Host: pluginHost, }, } var mresp master.CreateEndpointResponse err = cluster.MasterPostReq("/plugin/createEndpoint", &mreq, &mresp) if err != nil { log.Errorf("master failed to create endpoint %s", err) return err } log.Infof("Got endpoint create resp from master: %+v", mresp) // Take lock to ensure netPlugin processes only one cmd at a time netPlugin.Lock() defer func() { netPlugin.Unlock() }() // Ask netplugin to create the endpoint netID := nwCfg.NetworkName + "." + nwCfg.Tenant err = netPlugin.CreateEndpoint(netID + "-" + pluginHost) if err != nil { log.Errorf("Endpoint creation failed. Error: %s", err) return err } // Assign IP to interface ipCIDR := fmt.Sprintf("%s/%d", mresp.EndpointConfig.IPAddress, nwCfg.SubnetLen) err = netutils.SetInterfaceIP(nwCfg.NetworkName, ipCIDR) if err != nil { log.Errorf("Could not assign ip: %s", err) return err } return nil }
// allocAddress gets an address from the master func (its *integTestSuite) allocAddress(addrPool, networkID, prefAddress string) (string, error) { // Build an alloc request to be sent to master allocReq := master.AddressAllocRequest{ AddressPool: addrPool, NetworkID: networkID, PreferredIPv4Address: prefAddress, } // Make a REST call to master var allocResp master.AddressAllocResponse err := cluster.MasterPostReq("/plugin/allocAddress", &allocReq, &allocResp) if err != nil { log.Errorf("master failed to allocate address. Err: %v", err) return "", err } return strings.Split(allocResp.IPv4Address, "/")[0], nil }
// epCleanUp deletes the ep from netplugin and netmaster func epCleanUp(req *epSpec) error { // first delete from netplugin // ignore any errors as this is best effort netID := req.Network + "." + req.Tenant err1 := netPlugin.DeleteEndpoint(netID + "-" + req.EndpointID) // now delete from master delReq := master.DeleteEndpointRequest{ TenantName: req.Tenant, NetworkName: req.Network, ServiceName: req.Group, EndpointID: req.EndpointID, } var delResp master.DeleteEndpointResponse err2 := cluster.MasterPostReq("/plugin/deleteEndpoint", &delReq, &delResp) if err1 != nil { return err1 } return err2 }
// Process Infra Nw Delete // Delete the auto allocated endpoint func processInfraNwDelete(netPlugin *plugin.NetPlugin, nwCfg *mastercfg.CfgNetworkState, opts cliOpts) (err error) { pluginHost := opts.hostLabel // Build endpoint request mreq := master.DeleteEndpointRequest{ TenantName: nwCfg.Tenant, NetworkName: nwCfg.NetworkName, EndpointID: pluginHost, } var mresp master.DeleteEndpointResponse err = cluster.MasterPostReq("/plugin/deleteEndpoint", &mreq, &mresp) if err != nil { log.Errorf("master failed to delete endpoint %s", err) return err } log.Infof("Got endpoint create resp from master: %+v", mresp) // Network delete will take care of infra nw EP delete in plugin return }
// createEndpoint creates an endpoint using netplugin api func (its *integTestSuite) createEndpoint(tenantName, netName, epgName, v4Addr, v6Addr string) (*mastercfg.CfgEndpointState, error) { its.uniqEPID++ epID := fmt.Sprintf("%s-%s-%s-%d", tenantName, netName, epgName, its.uniqEPID) // Build endpoint request mreq := master.CreateEndpointRequest{ TenantName: tenantName, NetworkName: netName, ServiceName: epgName, EndpointID: epID, ConfigEP: intent.ConfigEP{ Container: epID, Host: its.npcluster.HostLabel, IPAddress: v4Addr, IPv6Address: v6Addr, ServiceName: epgName, }, } var mresp master.CreateEndpointResponse err := cluster.MasterPostReq("/plugin/createEndpoint", &mreq, &mresp) if err != nil { log.Errorf("master failed to create endpoint. Err: %v", err) return nil, err } log.Infof("Got endpoint create resp from master: %+v", mresp) netID := netName + "." + tenantName // Ask netplugin to create the endpoint err = its.npcluster.PluginAgent.Plugin().CreateEndpoint(netID + "-" + epID) if err != nil { log.Errorf("Endpoint creation failed. Error: %s", err) return nil, err } return &mresp.EndpointConfig, nil }
/*** Copyright 2014 Cisco Systems Inc. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package agent import ( "strings" log "github.com/Sirupsen/logrus" "github.com/contiv/netplugin/mgmtfn/dockplugin" "github.com/contiv/netplugin/netmaster/master" "github.com/contiv/netplugin/netplugin/cluster" "github.com/docker/engine-api/client" "github.com/docker/engine-api/types" "github.com/samalba/dockerclient" "golang.org/x/net/context" ) // Handles docker events monitored by dockerclient. Currently we only handle // container start and die event*/ func handleDockerEvents(event *dockerclient.Event, ec chan error, args ...interface{}) { log.Debugf("Received Docker event: {%#v}\n", *event) endpointUpdReq := &master.UpdateEndpointRequest{} switch event.Status { case "start": defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"} cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.21", nil, defaultHeaders) if err != nil { panic(err) } containerInfo, err := cli.ContainerInspect(context.Background(), event.ID) if err != nil { log.Errorf("Container Inspect failed :%s", err) return } if event.ID != "" { labelMap := getLabelsFromContainerInspect(&containerInfo) containerTenant := getTenantFromContainerInspect(&containerInfo) networkName, ipAddress, err := getEpNetworkInfoFromContainerInspect(&containerInfo) if err != nil { log.Errorf("Error getting container network info for %v.Err:%s", event.ID, err) } endpoint := getEndpointFromContainerInspect(&containerInfo) if ipAddress != "" { //Create provider info endpointUpdReq.IPAddress = ipAddress endpointUpdReq.ContainerID = event.ID endpointUpdReq.Tenant = containerTenant endpointUpdReq.Network = networkName endpointUpdReq.Event = "start" endpointUpdReq.EndpointID = endpoint endpointUpdReq.EPCommonName = containerInfo.Name endpointUpdReq.Labels = make(map[string]string) for k, v := range labelMap { endpointUpdReq.Labels[k] = v } } var epUpdResp master.UpdateEndpointResponse log.Infof("Sending Endpoint update request to master: {%+v}", endpointUpdReq) err = cluster.MasterPostReq("/plugin/updateEndpoint", endpointUpdReq, &epUpdResp) if err != nil { log.Errorf("Event: 'start' , Http error posting endpoint update, Error:%s", err) } } else { log.Errorf("Unable to fetch container labels for container %s ", event.ID) } case "die": endpointUpdReq.ContainerID = event.ID endpointUpdReq.Event = "die" var epUpdResp master.UpdateEndpointResponse log.Infof("Sending Endpoint update request to master: {%+v} on container delete", endpointUpdReq) err := cluster.MasterPostReq("/plugin/updateEndpoint", endpointUpdReq, &epUpdResp) if err != nil { log.Errorf("Event:'die' Http error posting endpoint update, Error:%s", err) } } }
// requestAddress func requestAddress(w http.ResponseWriter, r *http.Request) { var ( content []byte err error areq = api.RequestAddressRequest{} decoder = json.NewDecoder(r.Body) ) logEvent("requestAddress") // Decode the JSON message err = decoder.Decode(&areq) if err != nil { httpError(w, "Could not read and parse requestAddress request", err) return } log.Infof("Received RequestAddressRequest: %+v", areq) networkID := "" addrPool := areq.PoolID subnetLen := strings.Split(areq.PoolID, "/")[1] // check if pool id contains address pool or network id // HACK alert: This is very fragile. Simplify this when we stop supporting docker 1.9 if strings.Contains(areq.PoolID, "|") { addrPool = strings.Split(areq.PoolID, "|")[1] networkID = strings.Split(areq.PoolID, "|")[0] } // Build an alloc request to be sent to master allocReq := master.AddressAllocRequest{ AddressPool: addrPool, NetworkID: networkID, PreferredIPv4Address: areq.Address, } var addr string // check if this request is for gateway reqType, ok := areq.Options["RequestAddressType"] if ok && reqType == netlabel.Gateway { if areq.Address != "" { addr = areq.Address + "/" + subnetLen } else { // simply return a dummy address addr = addrPool } } else if areq.Address != "" { // This is a special case for docker 1.9 gateway request which does not // come with 'RequestAddressType' label // FIXME: Remove this hack when we stop supporting docker 1.9 addr = areq.Address + "/" + subnetLen } else { // Make a REST call to master var allocResp master.AddressAllocResponse err = cluster.MasterPostReq("/plugin/allocAddress", &allocReq, &allocResp) if err != nil { httpError(w, "master failed to allocate address", err) return } addr = allocResp.IPv4Address } // build response aresp := api.RequestAddressResponse{ Address: addr, } log.Infof("Sending RequestAddressResponse: %+v", aresp) // build json content, err = json.Marshal(aresp) if err != nil { httpError(w, "Could not generate requestAddress response", err) return } w.Write(content) }
func createEndpoint(hostname string) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { logEvent("create endpoint") content, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, "Could not read endpoint create request", err) return } cereq := api.CreateEndpointRequest{} if err := json.Unmarshal(content, &cereq); err != nil { httpError(w, "Could not read endpoint create request", err) return } log.Infof("CreateEndpointRequest: %+v. Interface: %+v", cereq, cereq.Interface) tenantName, netName, serviceName, err := GetDockerNetworkName(cereq.NetworkID) if err != nil { log.Errorf("Error getting network name for UUID: %s. Err: %v", cereq.NetworkID, err) httpError(w, "Could not get network name", err) return } // Build endpoint request mreq := master.CreateEndpointRequest{ TenantName: tenantName, NetworkName: netName, ServiceName: serviceName, EndpointID: cereq.EndpointID, ConfigEP: intent.ConfigEP{ Container: cereq.EndpointID, Host: hostname, IPAddress: strings.Split(cereq.Interface.Address, "/")[0], ServiceName: serviceName, }, } var mresp master.CreateEndpointResponse err = cluster.MasterPostReq("/plugin/createEndpoint", &mreq, &mresp) if err != nil { httpError(w, "master failed to create endpoint", err) return } log.Infof("Got endpoint create resp from master: %+v", mresp) netID := netName + "." + tenantName // Ask netplugin to create the endpoint err = netPlugin.CreateEndpoint(netID + "-" + cereq.EndpointID) if err != nil { log.Errorf("Endpoint creation failed. Error: %s", err) httpError(w, "Could not create endpoint", err) return } ep, err := netdGetEndpoint(netID + "-" + cereq.EndpointID) if err != nil { httpError(w, "Could not find created endpoint", err) return } log.Debug(ep) epResponse := api.CreateEndpointResponse{ Interface: &api.EndpointInterface{}, } // Add the service information using Service plugin if serviceName != "" { log.Infof("Calling AddService with: ID: %s, Name: %s, Network: %s, Tenant: %s, IP: %s", cereq.EndpointID[len(cereq.EndpointID)-12:], serviceName, netName, tenantName, ep.IPAddress) dnsBridge.AddService(cereq.EndpointID[len(cereq.EndpointID)-12:], serviceName, netName, tenantName, ep.IPAddress) } log.Infof("Sending CreateEndpointResponse: {%+v}, IP Addr: %v", epResponse, ep.IPAddress) content, err = json.Marshal(epResponse) if err != nil { httpError(w, "Could not generate create endpoint response", err) return } w.Write(content) } }
func deleteEndpoint(hostname string) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { logEvent("delete endpoint") content, err := ioutil.ReadAll(r.Body) if err != nil { httpError(w, "Could not read delete endpoint request", err) return } der := api.DeleteEndpointRequest{} if err := json.Unmarshal(content, &der); err != nil { httpError(w, "Could not read delete endpoint request", err) return } log.Infof("Received DeleteEndpointRequest: %+v", der) tenantName, netName, serviceName, err := GetDockerNetworkName(der.NetworkID) if err != nil { log.Errorf("Error getting network name for UUID: %s. Err: %v", der.NetworkID, err) httpError(w, "Could not get network name", err) return } // Build endpoint delete request delreq := master.DeleteEndpointRequest{ TenantName: tenantName, NetworkName: netName, ServiceName: serviceName, EndpointID: der.EndpointID, } var delResp master.DeleteEndpointResponse err = cluster.MasterPostReq("/plugin/deleteEndpoint", &delreq, &delResp) if err != nil { httpError(w, "master failed to delete endpoint", err) return } // delete the endpoint netID := netName + "." + tenantName err = netPlugin.DeleteEndpoint(netID + "-" + delreq.EndpointID) if err != nil { log.Errorf("Error deleting endpoint %s. Err: %v", delreq.EndpointID, err) httpError(w, "failed to delete endpoint", err) return } ep, err := netdGetEndpoint(netID + "-" + delreq.EndpointID) if err != nil { httpError(w, "Could not find endpoint", err) return } // Remove the DNS entry for the service if serviceName != "" { log.Infof("Calling RemoveService with: ID: %s, Name: %s, Network: %s, Tenant: %s, IP: %s", delreq.EndpointID[len(delreq.EndpointID)-12:], serviceName, netName, tenantName, ep.IPAddress) dnsBridge.RemoveService(delreq.EndpointID[len(delreq.EndpointID)-12:], serviceName, netName, tenantName, ep.IPAddress) } // build response content, err = json.Marshal(api.DeleteEndpointResponse{}) if err != nil { httpError(w, "Could not generate delete endpoint response", err) return } w.Write(content) } }
/*Handles docker events monitored by dockerclient. Currently we only handle container start and die event*/ func handleDockerEvents(event *dockerclient.Event, ec chan error, args ...interface{}) { log.Printf("Received Docker event: {%#v}\n", *event) providerUpdReq := &master.SvcProvUpdateRequest{} switch event.Status { case "start": defaultHeaders := map[string]string{"User-Agent": "engine-api-cli-1.0"} cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.21", nil, defaultHeaders) if err != nil { panic(err) } containerInfo, err := cli.ContainerInspect(context.Background(), event.ID) if err != nil { log.Errorf("Container Inspect failed :%s", err) return } if event.ID != "" { labelMap := getLabelsFromContainerInspect(&containerInfo) containerTenant := getTenantFromContainerInspect(&containerInfo) network, ipAddress := getEpNetworkInfoFromContainerInspect(&containerInfo) container := getContainerFromContainerInspect(&containerInfo) if ipAddress != "" { //Create provider info networkname := strings.Split(network, "/")[0] providerUpdReq.IPAddress = ipAddress providerUpdReq.ContainerID = event.ID providerUpdReq.Tenant = containerTenant providerUpdReq.Network = networkname providerUpdReq.Event = "start" providerUpdReq.Container = container providerUpdReq.Labels = make(map[string]string) for k, v := range labelMap { providerUpdReq.Labels[k] = v } } if len(labelMap) == 0 { //Ignore container without labels return } var svcProvResp master.SvcProvUpdateResponse log.Infof("Sending Provider create request to master: {%+v}", providerUpdReq) err := cluster.MasterPostReq("/plugin/svcProviderUpdate", providerUpdReq, &svcProvResp) if err != nil { log.Errorf("Event: 'start' , Http error posting service provider update, Error:%s", err) } } else { log.Errorf("Unable to fetch container labels for container %s ", event.ID) } case "die": providerUpdReq.ContainerID = event.ID providerUpdReq.Event = "die" var svcProvResp master.SvcProvUpdateResponse log.Infof("Sending Provider delete request to master: {%+v}", providerUpdReq) err := cluster.MasterPostReq("/plugin/svcProviderUpdate", providerUpdReq, &svcProvResp) if err != nil { log.Errorf("Event:'die' Http error posting service provider update, Error:%s", err) } } }
func (cniReq *cniServer) createCniEndPoint() error { var err error ovsEpDriver := &drivers.OvsOperEndpointState{} ovsEpDriver.StateDriver = stateDriver nwState := &mastercfg.CfgNetworkState{} nwState.StateDriver = stateDriver // build endpoint request epReq := master.CreateEndpointRequest{ TenantName: cniReq.endPointLabels[cniapi.LabelTenantName], NetworkName: cniReq.endPointLabels[cniapi.LabelNetworkName], ServiceName: cniReq.endPointLabels[cniapi.LabelNetworkGroup], EndpointID: cniReq.pluginArgs.CniContainerid, ConfigEP: intent.ConfigEP{ Container: cniReq.pluginArgs.CniContainerid, Host: hostName, ServiceName: cniReq.endPointLabels[cniapi.LabelNetworkGroup], }, } cniLog.Infof("endpoint-req: epid:%s cont-id:%s ", epReq.EndpointID, epReq.ConfigEP.Container) epResp := master.CreateEndpointResponse{} if err = cluster.MasterPostReq("/plugin/createEndpoint", &epReq, &epResp); err != nil { cniLog.Errorf("failed to create endpoint in master: %s", err.Error()) return err } cniLog.Infof("endpoint created %+v", epResp) // create endpoint in netplugin if err = netPlugin.CreateEndpoint(cniReq.endpointID); err != nil { cniLog.Errorf("failed to create endpoint in netplugin: %s", err.Error()) goto cleanupMaster } // read end point if err = ovsEpDriver.Read(cniReq.endpointID); err != nil { cniLog.Errorf("failed to read endpoint: %s", err.Error()) goto cleanupNetplugin } if err = nwState.Read(cniReq.networkID); err != nil { cniLog.Errorf("failed to read network config : %s", err.Error()) goto cleanupNetplugin } cniLog.Debugf("read new network config +%v", nwState) if err = cniReq.configureNetNs(ovsEpDriver, &epResp, nwState); err != nil { goto cleanupNetplugin } // host access if strings.HasSuffix(cniReq.pluginArgs.CniIfname, "0") { if err = cniReq.createHostBrIntf(ovsEpDriver); err != nil { cniLog.Errorf("failed to configure host-br %s", err.Error()) goto cleanupNetns } } return nil // unwind the setup, ignore errors cleanupNetns: cniReq.unlinkNetNs() cleanupNetplugin: cniReq.deleteNetpluginEndPoint() cleanupMaster: cniReq.deleteMasterEndPoint() return err }