//UpdateEndpointGroup updates the endpointgroups func UpdateEndpointGroup(bandwidth, groupName, tenantName string, Dscp, burst int) error { // Get the state driver - get the etcd driver state stateDriver, err := utils.GetStateDriver() if err != nil { return err } key := mastercfg.GetEndpointGroupKey(groupName, tenantName) if key == "" { return errors.New("Error finding endpointGroup key ") } // Read etcd driver epCfg := mastercfg.EndpointGroupState{} epCfg.StateDriver = stateDriver err = epCfg.Read(key) if err != nil { log.Errorf("Error finding endpointgroup %s. Err: %v", key, err) return err } //update the epGroup state epCfg.DSCP = Dscp epCfg.Bandwidth = bandwidth epCfg.Burst = burst //Write to etcd err = epCfg.Write() if err != nil { return err } return nil }
// DeleteEndpointGroup handles endpoint group deletes func DeleteEndpointGroup(tenantName, groupName string) error { // Get the state driver stateDriver, err := utils.GetStateDriver() if err != nil { return err } epgKey := mastercfg.GetEndpointGroupKey(groupName, tenantName) epgCfg := &mastercfg.EndpointGroupState{} epgCfg.StateDriver = stateDriver err = epgCfg.Read(epgKey) if err != nil { log.Errorf("error reading EPG key %s. Error: %s", epgKey, err) return err } if epgCfg.EpCount != 0 { return core.Errorf("Error: EPG %s has active endpoints", groupName) } // Delete the endpoint group state gstate.GlobalMutex.Lock() defer gstate.GlobalMutex.Unlock() gCfg := gstate.Cfg{} gCfg.StateDriver = stateDriver err = gCfg.Read(epgCfg.TenantName) if err != nil { log.Errorf("error reading tenant cfg state. Error: %s", err) return err } // if aci mode we allocate per-epg vlan. free it here. aciMode, aErr := IsAciConfigured() if aErr != nil { return aErr } if aciMode { if epgCfg.PktTagType == "vlan" { err = gCfg.FreeVLAN(uint(epgCfg.PktTag)) if err != nil { return err } log.Debugf("Freed vlan %v\n", epgCfg.PktTag) } } // Delete endpoint group err = epgCfg.Clear() if err != nil { log.Errorf("error writing epGroup config. Error: %v", err) return err } if GetClusterMode() == "docker" { return docknet.DeleteDockNet(epgCfg.TenantName, epgCfg.NetworkName, epgCfg.GroupName) } return nil }
// CreateEndpoint creates an endpoint func CreateEndpoint(stateDriver core.StateDriver, nwCfg *mastercfg.CfgNetworkState, ep *intent.ConfigEP) (*mastercfg.CfgEndpointState, error) { epCfg := &mastercfg.CfgEndpointState{} epCfg.StateDriver = stateDriver epCfg.ID = getEpName(nwCfg.ID, ep) err := epCfg.Read(epCfg.ID) if err == nil { // TODO: check for diffs and possible updates return epCfg, nil } epCfg.NetID = nwCfg.ID epCfg.ContName = ep.Container epCfg.AttachUUID = ep.AttachUUID epCfg.HomingHost = ep.Host epCfg.ServiceName = ep.ServiceName // Allocate addresses err = allocSetEpAddress(ep, epCfg, nwCfg) if err != nil { log.Errorf("error allocating and/or reserving IP. Error: %s", err) return nil, err } // Set endpoint group // Skip for infra nw if nwCfg.NwType != "infra" { epCfg.EndpointGroupKey = mastercfg.GetEndpointGroupKey(ep.ServiceName, nwCfg.Tenant) epCfg.EndpointGroupID, err = mastercfg.GetEndpointGroupID(stateDriver, ep.ServiceName, nwCfg.Tenant) if err != nil { log.Errorf("Error getting endpoint group for %s.%s. Err: %v", ep.ServiceName, nwCfg.ID, err) return nil, err } } err = nwCfg.IncrEpCount() if err != nil { log.Errorf("Error incrementing ep count. Err: %v", err) return nil, err } err = epCfg.Write() if err != nil { log.Errorf("error writing ep config. Error: %s", err) return nil, err } return epCfg, nil }
// CreateEndpointGroup handles creation of endpoint group func CreateEndpointGroup(tenantName, networkName, groupName string) error { var epgID int // Get the state driver stateDriver, err := utils.GetStateDriver() if err != nil { return err } // Read global config gCfg := gstate.Cfg{} gCfg.StateDriver = stateDriver err = gCfg.Read(tenantName) if err != nil { log.Errorf("error reading tenant cfg state. Error: %s", err) return err } // read the network config networkID := networkName + "." + tenantName nwCfg := &mastercfg.CfgNetworkState{} nwCfg.StateDriver = stateDriver err = nwCfg.Read(networkID) if err != nil { log.Errorf("Could not find network %s. Err: %v", networkID, err) return err } // params for docker network if GetClusterMode() == "docker" { // Create each EPG as a docker network err = docknet.CreateDockNet(tenantName, networkName, groupName, nwCfg) if err != nil { log.Errorf("Error creating docker network for group %s.%s. Err: %v", networkName, groupName, err) return err } } // assign unique endpoint group ids // FIXME: This is a hack. need to add a epgID resource for i := 0; i < maxEpgID; i++ { epgID = globalEpgID globalEpgID = globalEpgID + 1 if globalEpgID > maxEpgID { globalEpgID = 1 } epgCfg := &mastercfg.EndpointGroupState{} epgCfg.StateDriver = stateDriver err = epgCfg.Read(strconv.Itoa(epgID)) if err != nil { break } } // Create epGroup state epgCfg := &mastercfg.EndpointGroupState{ GroupName: groupName, TenantName: tenantName, NetworkName: networkName, EndpointGroupID: epgID, PktTagType: nwCfg.PktTagType, PktTag: nwCfg.PktTag, ExtPktTag: nwCfg.ExtPktTag, } epgCfg.StateDriver = stateDriver epgCfg.ID = mastercfg.GetEndpointGroupKey(groupName, tenantName) log.Debugf("##Create EpGroup %v network %v tagtype %v", groupName, networkName, nwCfg.PktTagType) // if aci mode allocate per-epg vlan. otherwise, stick to per-network vlan aciMode, rErr := IsAciConfigured() if rErr != nil { return rErr } // Special handling for ACI mode if aciMode { if epgCfg.PktTagType != "vlan" { log.Errorf("Network type must be VLAN for ACI mode") return errors.New("Network type must be VLAN for ACI mode") } pktTag, err := gCfg.AllocVLAN(0) if err != nil { return err } epgCfg.PktTag = int(pktTag) log.Debugf("ACI -- Allocated vlan %v for epg %v", pktTag, groupName) } err = epgCfg.Write() if err != nil { return err } return nil }
// CreateEndpoint creates an endpoint func CreateEndpoint(stateDriver core.StateDriver, nwCfg *mastercfg.CfgNetworkState, epReq *CreateEndpointRequest) (*mastercfg.CfgEndpointState, error) { ep := &epReq.ConfigEP epCfg := &mastercfg.CfgEndpointState{} epCfg.StateDriver = stateDriver epCfg.ID = getEpName(nwCfg.ID, ep) err := epCfg.Read(epCfg.ID) if err == nil { // TODO: check for diffs and possible updates return epCfg, nil } epCfg.NetID = nwCfg.ID epCfg.EndpointID = ep.Container epCfg.HomingHost = ep.Host epCfg.ServiceName = ep.ServiceName epCfg.EPCommonName = epReq.EPCommonName // Allocate addresses err = allocSetEpAddress(ep, epCfg, nwCfg) if err != nil { log.Errorf("error allocating and/or reserving IP. Error: %s", err) return nil, err } // cleanup relies on var err being used for all error checking defer freeAddrOnErr(nwCfg, epCfg.IPAddress, &err) // Set endpoint group // Skip for infra nw if nwCfg.NwType != "infra" { epCfg.EndpointGroupKey = mastercfg.GetEndpointGroupKey(ep.ServiceName, nwCfg.Tenant) epCfg.EndpointGroupID, err = mastercfg.GetEndpointGroupID(stateDriver, ep.ServiceName, nwCfg.Tenant) if err != nil { log.Errorf("Error getting endpoint group ID for %s.%s. Err: %v", ep.ServiceName, nwCfg.ID, err) return nil, err } if epCfg.EndpointGroupKey != "" { epgCfg := &mastercfg.EndpointGroupState{} epgCfg.StateDriver = stateDriver err = epgCfg.Read(epCfg.EndpointGroupKey) if err != nil { log.Errorf("Error reading Epg info for EP: %+v. Error: %v", ep, err) return nil, err } epgCfg.EpCount++ err = epgCfg.Write() if err != nil { log.Errorf("Error saving epg state: %+v", epgCfg) return nil, err } } } err = nwCfg.IncrEpCount() if err != nil { log.Errorf("Error incrementing ep count. Err: %v", err) return nil, err } err = epCfg.Write() if err != nil { log.Errorf("error writing ep config. Error: %s", err) return nil, err } return epCfg, nil }
// Extract relevant info from epg obj and append to application nw spec func appendEpgInfo(eMap *epgMap, epgObj *contivModel.EndpointGroup, stateDriver core.StateDriver) error { epg := epgSpec{} epg.Name = epgObj.GroupName log.Infof("Processing EPG: %+v", epgObj) // Get EPG key for the endpoint group epgKey := mastercfg.GetEndpointGroupKey(epgObj.GroupName, epgObj.TenantName) // update vlantag from EpGroupState epgCfg := &mastercfg.EndpointGroupState{} epgCfg.StateDriver = stateDriver eErr := epgCfg.Read(epgKey) if eErr != nil { log.Errorf("Error reading epg %v %v", epgKey, eErr) return eErr } // get the network name and gw cidr and update. epg.NwName = epgObj.NetworkName gwCIDR, nErr := getGwCIDR(epgObj, stateDriver) if nErr != nil { return nErr } epg.GwCIDR = gwCIDR epg.VlanTag = strconv.Itoa(epgCfg.PktTag) epg.epgID = epgCfg.EndpointGroupID // get all the policy details for _, policy := range epgObj.Policies { log.Debugf("==Processing policy %v", policy) policyKey := epgObj.TenantName + ":" + policy pObj := contivModel.FindPolicy(policyKey) if pObj == nil { errStr := fmt.Sprintf("Policy %v not found epg: %v", policy, epg.Name) return errors.New(errStr) } nErr = addPolicyContracts(eMap.Contracts, &epg, pObj) if nErr != nil { return nErr } } // Add linked contracts based on rules that refer this epg for _, ruleLink := range epgObj.LinkSets.MatchRules { rule := contivModel.FindRule(ruleLink.ObjKey) if rule == nil { errStr := fmt.Sprintf("Rule %s referring to epg %s not found", ruleLink.ObjKey, epg.Name) return errors.New(errStr) } cn := getContractName(rule.PolicyName, rule.FromEndpointGroup, rule.ToEndpointGroup) lKind := "" if rule.FromEndpointGroup != "" { lKind = cConsume } else { lKind = cProvide } cLink := contrLink{LinkKind: lKind, ContractName: cn, ContractKind: cInternal, } epg.ContractLinks = append(epg.ContractLinks, cLink) } // Append links for external contracts. tenant := epgObj.TenantName for _, contractsGrp := range epgObj.ExtContractsGrps { contractsGrpKey := tenant + ":" + contractsGrp contractsGrpObj := contivModel.FindExtContractsGroup(contractsGrpKey) if contractsGrpObj == nil { errStr := fmt.Sprintf("Contracts %v not found for epg: %v", contractsGrp, epg.Name) return errors.New(errStr) } lKind := "" if contractsGrpObj.ContractsType == "consumed" { lKind = cConsume } else if contractsGrpObj.ContractsType == "provided" { lKind = cProvide } else { // Should not be here. errStr := fmt.Sprintf("Invalid contracts type %v", contractsGrp) return errors.New(errStr) } for _, dn := range contractsGrpObj.Contracts { cLink := contrLink{LinkKind: lKind, ContractDN: dn, ContractKind: cExternal, } epg.ContractLinks = append(epg.ContractLinks, cLink) } } eMap.Specs[epg.Name] = epg return nil }
// Extract relevant info from epg obj and append to application nw spec func appendEpgInfo(eMap *epgMap, epgObj *contivModel.EndpointGroup, stateDriver core.StateDriver) error { epg := epgSpec{} epg.Name = epgObj.GroupName log.Infof("Processing EPG: %+v", epgObj) // Get EPG key for the endpoint group epgKey := mastercfg.GetEndpointGroupKey(epgObj.GroupName, epgObj.TenantName) // update vlantag from EpGroupState epgCfg := &mastercfg.EndpointGroupState{} epgCfg.StateDriver = stateDriver eErr := epgCfg.Read(epgKey) if eErr != nil { log.Errorf("Error reading epg %v %v", epgKey, eErr) return eErr } epg.VlanTag = strconv.Itoa(epgCfg.PktTag) // get all the service link details for _, policy := range epgObj.Policies { log.Debugf("==Processing policy %v", policy) policyKey := epgObj.TenantName + ":" + policy pObj := contivModel.FindPolicy(policyKey) if pObj == nil { errStr := fmt.Sprintf("Policy %v not found epg: %v", policy, epg.Name) return errors.New(errStr) } for ruleName := range pObj.LinkSets.Rules { log.Debugf("==Processing rule %v", ruleName) rule := contivModel.FindRule(ruleName) if rule == nil { errStr := fmt.Sprintf("rule %v not found", ruleName) return errors.New(errStr) } if rule.Action == "deny" { log.Debugf("==Ignoring deny rule %v", ruleName) continue } singleFilter := filterInfo{Protocol: rule.Protocol, ServPort: strconv.Itoa(rule.Port)} epg.Filters = append(epg.Filters, singleFilter) log.Debugf("Filter information: %v", singleFilter) if rule.FromEndpointGroup == "" { log.Debugf("User unspecified %v == exposed contract", ruleName) continue } // rule.FromEndpointGroup uses this epg uEpg, ok := eMap.Specs[rule.FromEndpointGroup] if ok { uEpg.Uses = append(uEpg.Uses, epg.Name) eMap.Specs[rule.FromEndpointGroup] = uEpg } else { //not in the map - need to add userEpg := epgSpec{} userEpg.Uses = append(userEpg.Uses, epg.Name) eMap.Specs[rule.FromEndpointGroup] = userEpg } log.Debugf("==Used by %v", rule.FromEndpointGroup) } } // Append external contracts. tenant := epgObj.TenantName for _, contractsGrp := range epgObj.ExtContractsGrps { contractsGrpKey := tenant + ":" + contractsGrp contractsGrpObj := contivModel.FindExtContractsGroup(contractsGrpKey) if contractsGrpObj == nil { errStr := fmt.Sprintf("Contracts %v not found for epg: %v", contractsGrp, epg.Name) return errors.New(errStr) } if contractsGrpObj.ContractsType == "consumed" { epg.ConsContracts = append(epg.ConsContracts, contractsGrpObj.Contracts...) } else if contractsGrpObj.ContractsType == "provided" { epg.ProvContracts = append(epg.ProvContracts, contractsGrpObj.Contracts...) } else { // Should not be here. errStr := fmt.Sprintf("Invalid contracts type %v", contractsGrp) return errors.New(errStr) } } log.Debugf("Copied over %d externally defined consumed contracts", len(epg.ConsContracts)) log.Debugf("Copied over %d externally defined provided contracts", len(epg.ProvContracts)) // add any saved uses info before overwriting savedEpg, ok := eMap.Specs[epg.Name] if ok { epg.Uses = append(epg.Uses, savedEpg.Uses...) } eMap.Specs[epg.Name] = epg return nil }
//UpdateEndpointHandler handles update event from netplugin func UpdateEndpointHandler(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) { var epUpdReq UpdateEndpointRequest // Get object from the request err := json.NewDecoder(r.Body).Decode(&epUpdReq) if err != nil { log.Errorf("Error decoding EndpointUpdateRequest. Err %v", err) return nil, err } log.Infof("Received EndpointUpdateRequest {%+v}", epUpdReq) stateDriver, err := utils.GetStateDriver() if err != nil { return nil, err } if epUpdReq.Event == "start" { //Received container start event from netplugin. Check if the Provider //matches any service and perform service provider update if there is a matching //service. epCfg := &mastercfg.CfgEndpointState{} epCfg.StateDriver = stateDriver nwCfg := &mastercfg.CfgNetworkState{} nwCfg.StateDriver = stateDriver //check if networkname is epg name or network name key := mastercfg.GetNwCfgKey(epUpdReq.Network, epUpdReq.Tenant) err := nwCfg.Read(key) if err != nil { if !strings.Contains(err.Error(), "Key not found") { return nil, err } //If network is not found then networkname is epg epgCfg := &mastercfg.EndpointGroupState{} epgCfg.StateDriver = stateDriver key = mastercfg.GetEndpointGroupKey(epUpdReq.Network, epUpdReq.Tenant) err := epgCfg.Read(key) if err != nil { return nil, err } //get the network associated with the endpoint group key = mastercfg.GetNwCfgKey(epgCfg.NetworkName, epUpdReq.Tenant) } epCfg.ID = getEpName(key, &intent.ConfigEP{Container: epUpdReq.EndpointID}) err = epCfg.Read(epCfg.ID) if err != nil { return nil, err } provider := &mastercfg.Provider{} provider.IPAddress = epUpdReq.IPAddress provider.Tenant = epUpdReq.Tenant provider.Network = epUpdReq.Network provider.ContainerID = epUpdReq.ContainerID provider.Labels = make(map[string]string) if epCfg.Labels == nil { //endpoint cfg doesnt have labels epCfg.Labels = make(map[string]string) } for k, v := range epUpdReq.Labels { provider.Labels[k] = v epCfg.Labels[k] = v } provider.EpIDKey = epCfg.ID //maintain the containerId in endpointstat for recovery epCfg.ContainerID = epUpdReq.ContainerID epCfg.EPCommonName = epUpdReq.EPCommonName err = epCfg.Write() if err != nil { log.Errorf("error writing ep config. Error: %s", err) return nil, err } providerID := getProviderID(provider) providerDbID := getProviderDbID(provider) if providerID == "" || providerDbID == "" { return nil, fmt.Errorf("Invalid ProviderID from providerInfo:{%v}", provider) } //update provider db mastercfg.SvcMutex.Lock() mastercfg.ProviderDb[providerDbID] = provider for serviceID, service := range mastercfg.ServiceLBDb { count := 0 if service.Tenant == epUpdReq.Tenant { for key, value := range epUpdReq.Labels { if val := service.Selectors[key]; val == value { count++ } if count == len(service.Selectors) { //Container corresponds to the service since it //matches all service Selectors mastercfg.ProviderDb[providerDbID].Services = append(mastercfg.ProviderDb[providerDbID].Services, serviceID) //Update ServiceDB mastercfg.ServiceLBDb[serviceID].Providers[providerID] = provider serviceLbState := &mastercfg.CfgServiceLBState{} serviceLbState.StateDriver = stateDriver err = serviceLbState.Read(serviceID) if err != nil { mastercfg.SvcMutex.Unlock() return nil, err } serviceLbState.Providers[providerID] = provider serviceLbState.Write() SvcProviderUpdate(serviceID, false) break } } } } mastercfg.SvcMutex.Unlock() } else if epUpdReq.Event == "die" { //Received a container die event. If it was a service provider - //clear the provider db and the service db and change the etcd state providerDbID := epUpdReq.ContainerID if providerDbID == "" { return nil, fmt.Errorf("Invalid containerID in UpdateEndpointRequest:(nil)") } mastercfg.SvcMutex.Lock() provider := mastercfg.ProviderDb[providerDbID] if provider == nil { mastercfg.SvcMutex.Unlock() // It is not a provider . Ignore event return nil, nil } for _, serviceID := range provider.Services { service := mastercfg.ServiceLBDb[serviceID] providerID := getProviderID(provider) if providerID == "" { mastercfg.SvcMutex.Unlock() return nil, fmt.Errorf("Invalid ProviderID from providerInfo:{%v}", provider) } if service.Providers[providerID] != nil { delete(service.Providers, providerID) serviceLbState := &mastercfg.CfgServiceLBState{} serviceLbState.StateDriver = stateDriver err = serviceLbState.Read(serviceID) if err != nil { mastercfg.SvcMutex.Unlock() return nil, err } delete(serviceLbState.Providers, providerID) serviceLbState.Write() delete(mastercfg.ProviderDb, providerDbID) SvcProviderUpdate(serviceID, false) } } mastercfg.SvcMutex.Unlock() } epUpdResp := &UpdateEndpointResponse{ IPAddress: epUpdReq.IPAddress, } return epUpdResp, nil }