diff --git a/cns/cnsclient/cnsclient_test.go b/cns/cnsclient/cnsclient_test.go index 3b3e2137ef..2b7747f1af 100644 --- a/cns/cnsclient/cnsclient_test.go +++ b/cns/cnsclient/cnsclient_test.go @@ -30,9 +30,13 @@ const ( dockerContainerType = cns.Docker ) +var ( + dnsservers = []string{"8.8.8.8", "8.8.4.4"} +) + func addTestStateToRestServer(t *testing.T, secondaryIps []string) { var ipConfig cns.IPConfiguration - ipConfig.DNSServers = []string{"8.8.8.8", "8.8.4.4"} + ipConfig.DNSServers = dnsservers ipConfig.GatewayIPAddress = gatewayIp var ipSubnet cns.IPSubnet ipSubnet.IPAddress = primaryIp @@ -64,7 +68,7 @@ func addTestStateToRestServer(t *testing.T, secondaryIps []string) { } } -func getIPConfigFromGetNetworkContainerResponse(resp *cns.GetIPConfigResponse) (net.IPNet, error) { +func getIPNetFromResponse(resp *cns.GetIPConfigResponse) (net.IPNet, error) { var ( resultIPnet net.IPNet err error @@ -180,7 +184,16 @@ func TestCNSClientRequestAndRelease(t *testing.T) { t.Fatalf("get IP from CNS failed with %+v", err) } - resultIPnet, err := getIPConfigFromGetNetworkContainerResponse(resp) + // validate gateway and dnsservers + if reflect.DeepEqual(resp.IPConfiguration.DNSServers, dnsservers) != true { + t.Fatalf("DnsServer is not added as expected ipConfig %+v, expected dnsServers: %+v", resp.IPConfiguration, dnsservers) + } + + if reflect.DeepEqual(resp.IPConfiguration.GatewayIPAddress, gatewayIp) != true { + t.Fatalf("Gateway is not added as expected ipConfig %+v, expected GatewayIp: %+v", resp.IPConfiguration, gatewayIp) + } + + resultIPnet, err := getIPNetFromResponse(resp) if reflect.DeepEqual(desired, resultIPnet) != true { t.Fatalf("Desired result not matching actual result, expected: %+v, actual: %+v", desired, resultIPnet) diff --git a/cns/restserver/const.go b/cns/restserver/const.go index e9efe62ae1..0beda46f19 100644 --- a/cns/restserver/const.go +++ b/cns/restserver/const.go @@ -33,6 +33,8 @@ const ( InvalidSecondaryIPConfig = 30 NetworkContainerPendingStatePropagation = 31 FailedToAllocateIpConfig = 32 + EmptyOrchestratorContext = 33 + UnsupportedOrchestratorContext = 34 UnexpectedError = 99 ) diff --git a/cns/restserver/internalapi_test.go b/cns/restserver/internalapi_test.go index 14fef64a05..4114a46851 100644 --- a/cns/restserver/internalapi_test.go +++ b/cns/restserver/internalapi_test.go @@ -20,6 +20,10 @@ const ( dockerContainerType = cns.Docker ) +var ( + dnsservers = []string{"8.8.8.8", "8.8.4.4"} +) + func TestCreateOrUpdateNetworkContainerInternal(t *testing.T) { restartService() @@ -181,11 +185,11 @@ func createAndValidateNCRequest(t *testing.T, secondaryIPConfigs map[string]cns. if returnCode != 0 { t.Fatalf("Failed to createNetworkContainerRequest, req: %+v, err: %d", req, returnCode) } - validateNetworkRequest(t, req, false) + validateNetworkRequest(t, req) } // Validate the networkRequest is persisted. -func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest, skipAvailableCheck bool) { +func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest) { containerStatus := svc.state.ContainerStatus[req.NetworkContainerid] if containerStatus.ID != req.NetworkContainerid { @@ -217,8 +221,21 @@ func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest, } // Validate IP state - if !skipAvailableCheck && - ipStatus.State != cns.Available { + if ipStatus.OrchestratorContext != nil { + var podInfo cns.KubernetesPodInfo + if err := json.Unmarshal(ipStatus.OrchestratorContext, &podInfo); err != nil { + t.Fatalf("Failed to add IPConfig to state: %+v with error: %v", ipStatus, err) + } + + if _, exists := svc.PodIPIDByOrchestratorContext[podInfo.GetOrchestratorContextKey()]; exists { + if ipStatus.State != cns.Allocated { + t.Fatalf("IPId: %s State is not Allocated, ipStatus: %+v", ipid, ipStatus) + } + } else { + t.Fatalf("Failed to find podContext for allocated ip: %+v, podinfo :%+v", ipStatus, podInfo) + } + } else if ipStatus.State != cns.Available { + // Todo: Validate for pendingRelease as well t.Fatalf("IPId: %s State is not Available, ipStatus: %+v", ipid, ipStatus) } @@ -235,7 +252,7 @@ func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest, func generateNetworkContainerRequest(secondaryIps map[string]cns.SecondaryIPConfig, ncId string) cns.CreateNetworkContainerRequest { var ipConfig cns.IPConfiguration - ipConfig.DNSServers = []string{"8.8.8.8", "8.8.4.4"} + ipConfig.DNSServers = dnsservers ipConfig.GatewayIPAddress = gatewayIp var ipSubnet cns.IPSubnet ipSubnet.IPAddress = primaryIp @@ -265,7 +282,7 @@ func validateNCStateAfterReconcile(t *testing.T, ncRequest *cns.CreateNetworkCon t.Fatalf("CNS has some stale ContainerStatus, count: %d, state: %+v", len(svc.state.ContainerStatus), svc.state.ContainerStatus) } } else { - validateNetworkRequest(t, *ncRequest, true) + validateNetworkRequest(t, *ncRequest) } if len(expectedAllocatedPods) != len(svc.PodIPIDByOrchestratorContext) { diff --git a/cns/restserver/ipam.go b/cns/restserver/ipam.go index ff50a13596..4ae8eebb45 100644 --- a/cns/restserver/ipam.go +++ b/cns/restserver/ipam.go @@ -4,6 +4,7 @@ package restserver import ( + "bytes" "encoding/json" "fmt" "net/http" @@ -17,7 +18,7 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r var ( err error ipconfigRequest cns.GetIPConfigRequest - ipState ipConfigurationStatus + ipconfiguration cns.IPConfiguration returnCode int returnMessage string ) @@ -29,9 +30,12 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r } // retrieve ipconfig from nc - if ipState, err = requestIPConfigHelper(service, ipconfigRequest); err != nil { - returnCode = FailedToAllocateIpConfig - returnMessage = fmt.Sprintf("AllocateIPConfig failed: %v", err) + returnCode, returnMessage = service.validateIpConfigRequest(ipconfigRequest) + if returnCode == Success { + if ipconfiguration, err = requestIPConfigHelper(service, ipconfigRequest); err != nil { + returnCode = FailedToAllocateIpConfig + returnMessage = fmt.Sprintf("AllocateIPConfig failed: %v", err) + } } resp := cns.Response{ @@ -42,7 +46,7 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r reserveResp := &cns.GetIPConfigResponse{ Response: resp, } - reserveResp.IPConfiguration.IPSubnet = ipState.IPSubnet + reserveResp.IPConfiguration = ipconfiguration err = service.Listener.Encode(w, &reserveResp) logger.Response(service.Name, reserveResp, resp.ReturnCode, ReturnCodeToString(resp.ReturnCode), err) @@ -50,9 +54,10 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r func (service *HTTPRestService) releaseIPConfigHandler(w http.ResponseWriter, r *http.Request) { var ( - podInfo cns.KubernetesPodInfo - req cns.GetIPConfigRequest - statusCode int + podInfo cns.KubernetesPodInfo + req cns.GetIPConfigRequest + statusCode int + returnMessage string ) statusCode = UnexpectedError @@ -60,6 +65,7 @@ func (service *HTTPRestService) releaseIPConfigHandler(w http.ResponseWriter, r err := service.Listener.Decode(w, r, &req) logger.Request(service.Name, &req, err) if err != nil { + returnMessage = err.Error() return } @@ -68,25 +74,18 @@ func (service *HTTPRestService) releaseIPConfigHandler(w http.ResponseWriter, r if err != nil { resp.ReturnCode = statusCode - resp.Message = err.Error() + resp.Message = returnMessage } err = service.Listener.Encode(w, &resp) logger.Response(service.Name, resp, resp.ReturnCode, ReturnCodeToString(resp.ReturnCode), err) }() - if service.state.OrchestratorType != cns.KubernetesCRD { - err = fmt.Errorf("ReleaseIPConfig API supported only for kubernetes orchestrator") - return - } - - // retrieve podinfo from orchestrator context - if err = json.Unmarshal(req.OrchestratorContext, &podInfo); err != nil { - return - } + statusCode, returnMessage = service.validateIpConfigRequest(req) - if err = service.ReleaseIPConfig(podInfo); err != nil { + if err = service.releaseIPConfig(podInfo); err != nil { statusCode = NotFound + returnMessage = err.Error() return } return @@ -139,7 +138,7 @@ func (service *HTTPRestService) setIPConfigAsAvailable(ipconfig ipConfigurationS ////SetIPConfigAsAllocated takes a lock of the service, and sets the ipconfig in the CNS stateas Available // Todo - CNI should also pass the IPAddress which needs to be released to validate if that is the right IP allcoated // in the first place. -func (service *HTTPRestService) ReleaseIPConfig(podInfo cns.KubernetesPodInfo) error { +func (service *HTTPRestService) releaseIPConfig(podInfo cns.KubernetesPodInfo) error { service.Lock() defer service.Unlock() @@ -149,7 +148,7 @@ func (service *HTTPRestService) ReleaseIPConfig(podInfo cns.KubernetesPodInfo) e service.setIPConfigAsAvailable(ipconfig, podInfo) } else { logger.Errorf("Failed to get release ipconfig. Pod to IPID exists, but IPID to IPConfig doesn't exist, CNS State potentially corrupt") - return fmt.Errorf("ReleaseIPConfig failed. Pod to IPID exists, but IPID to IPConfig doesn't exist, CNS State potentially corrupt") + return fmt.Errorf("releaseIPConfig failed. Pod to IPID exists, but IPID to IPConfig doesn't exist, CNS State potentially corrupt") } } else { logger.Printf("SetIPConfigAsAvailable failed to release, no allocation found for pod") @@ -158,10 +157,10 @@ func (service *HTTPRestService) ReleaseIPConfig(podInfo cns.KubernetesPodInfo) e return nil } -func (service *HTTPRestService) GetExistingIPConfig(podInfo cns.KubernetesPodInfo) (ipConfigurationStatus, bool, error) { +func (service *HTTPRestService) GetExistingIPConfig(podInfo cns.KubernetesPodInfo) (cns.IPConfiguration, bool, error) { var ( - ipState ipConfigurationStatus - isExist bool + ipConfiguration cns.IPConfiguration + isExist bool ) service.RLock() @@ -169,70 +168,91 @@ func (service *HTTPRestService) GetExistingIPConfig(podInfo cns.KubernetesPodInf ipID := service.PodIPIDByOrchestratorContext[podInfo.GetOrchestratorContextKey()] if ipID != "" { - if ipState, isExist = service.PodIPConfigState[ipID]; isExist { - return ipState, isExist, nil + if ipState, isExist := service.PodIPConfigState[ipID]; isExist { + ipConfiguration.IPSubnet = ipState.IPSubnet + err := service.populateIpConfigInfoFromNCUntransacted(ipState.NCID, &ipConfiguration) + return ipConfiguration, isExist, err } + logger.Errorf("Failed to get existing ipconfig. Pod to IPID exists, but IPID to IPConfig doesn't exist, CNS State potentially corrupt") - return ipState, isExist, fmt.Errorf("Failed to get existing ipconfig. Pod to IPID exists, but IPID to IPConfig doesn't exist, CNS State potentially corrupt") + return ipConfiguration, isExist, fmt.Errorf("Failed to get existing ipconfig. Pod to IPID exists, but IPID to IPConfig doesn't exist, CNS State potentially corrupt") } - return ipState, isExist, nil + return ipConfiguration, isExist, nil } -func (service *HTTPRestService) AllocateDesiredIPConfig(podInfo cns.KubernetesPodInfo, desiredIPAddress string, orchestratorContext json.RawMessage) (ipConfigurationStatus, error) { - var ipState ipConfigurationStatus - +func (service *HTTPRestService) AllocateDesiredIPConfig(podInfo cns.KubernetesPodInfo, desiredIPAddress string, orchestratorContext json.RawMessage) (cns.IPConfiguration, error) { + var ipConfiguration cns.IPConfiguration service.Lock() defer service.Unlock() + found := false for _, ipState := range service.PodIPConfigState { if ipState.IPSubnet.IPAddress == desiredIPAddress { - if ipState.State == cns.Available { - return service.setIPConfigAsAllocated(ipState, podInfo, orchestratorContext), nil + if ipState.State == cns.Allocated { + // This IP has already been allocated, if it is allocated to same pod, then return the same + // IPconfiguration + if bytes.Equal(orchestratorContext, ipState.OrchestratorContext) == true { + found = true + } else { + var pInfo cns.KubernetesPodInfo + json.Unmarshal(ipState.OrchestratorContext, &pInfo) + return ipConfiguration, fmt.Errorf("Desired IP is already allocated %+v to Pod: %+v, requested for pod %+v", ipState, pInfo, podInfo) + } + } else if ipState.State == cns.Available { + service.setIPConfigAsAllocated(ipState, podInfo, orchestratorContext) + found = true + } else { + return ipConfiguration, fmt.Errorf("Desired IP is not available %+v", ipState) + } + + if found { + err := service.populateIpConfigInfoFromNCUntransacted(ipState.NCID, &ipConfiguration) + if err != nil { + return ipConfiguration, err + } + + ipConfiguration.IPSubnet = ipState.IPSubnet + return ipConfiguration, nil } - return ipState, fmt.Errorf("Desired IP has already been allocated") } } - return ipState, fmt.Errorf("Requested IP not found in pool") + return ipConfiguration, fmt.Errorf("Requested IP not found in pool") } -func (service *HTTPRestService) AllocateAnyAvailableIPConfig(podInfo cns.KubernetesPodInfo, orchestratorContext json.RawMessage) (ipConfigurationStatus, error) { - var ipState ipConfigurationStatus +func (service *HTTPRestService) AllocateAnyAvailableIPConfig(podInfo cns.KubernetesPodInfo, orchestratorContext json.RawMessage) (cns.IPConfiguration, error) { + var ipConfiguration cns.IPConfiguration service.Lock() defer service.Unlock() - for _, ipState = range service.PodIPConfigState { + for _, ipState := range service.PodIPConfigState { if ipState.State == cns.Available { - return service.setIPConfigAsAllocated(ipState, podInfo, orchestratorContext), nil + service.setIPConfigAsAllocated(ipState, podInfo, orchestratorContext) + + ipConfiguration.IPSubnet = ipState.IPSubnet + err := service.populateIpConfigInfoFromNCUntransacted(ipState.NCID, &ipConfiguration) + return ipConfiguration, err } } - return ipState, fmt.Errorf("No more free IP's available, trigger batch") + + return ipConfiguration, fmt.Errorf("No more free IP's available, trigger batch") } // If IPConfig is already allocated for pod, it returns that else it returns one of the available ipconfigs. -func requestIPConfigHelper(service *HTTPRestService, req cns.GetIPConfigRequest) (ipConfigurationStatus, error) { +func requestIPConfigHelper(service *HTTPRestService, req cns.GetIPConfigRequest) (cns.IPConfiguration, error) { var ( - podInfo cns.KubernetesPodInfo - ipState ipConfigurationStatus - isExist bool - err error + podInfo cns.KubernetesPodInfo + ipConfiguration cns.IPConfiguration + isExist bool + err error ) - // todo - change it to - if service.state.OrchestratorType != cns.KubernetesCRD { - return ipState, fmt.Errorf("AllocateIPconfig API supported only for kubernetes orchestrator") - } - - // retrieve podinfo from orchestrator context - if err := json.Unmarshal(req.OrchestratorContext, &podInfo); err != nil { - return ipState, err - } - // check if ipconfig already allocated for this pod and return if exists or error // if error, ipstate is nil, if exists, ipstate is not nil and error is nil - if ipState, isExist, err = service.GetExistingIPConfig(podInfo); err != nil || isExist { - return ipState, err + json.Unmarshal(req.OrchestratorContext, &podInfo) + if ipConfiguration, isExist, err = service.GetExistingIPConfig(podInfo); err != nil || isExist { + return ipConfiguration, err } // return desired IPConfig diff --git a/cns/restserver/ipam_test.go b/cns/restserver/ipam_test.go index 217eef76c7..a88792dfbd 100644 --- a/cns/restserver/ipam_test.go +++ b/cns/restserver/ipam_test.go @@ -41,8 +41,8 @@ var ( func getTestService() *HTTPRestService { var config common.ServiceConfig httpsvc, _ := NewHTTPRestService(&config) - svc := httpsvc.(*HTTPRestService) - svc.state.OrchestratorType = cns.KubernetesCRD + svc = httpsvc.(*HTTPRestService) + setOrchestratorTypeInternal(cns.KubernetesCRD) return svc } @@ -67,6 +67,38 @@ func NewPodState(ipaddress string, prefixLength uint8, id, ncid, state string) i } } +func requestIpAddressAndGetState(t *testing.T, req cns.GetIPConfigRequest) (ipConfigurationStatus, error) { + var ( + podInfo cns.KubernetesPodInfo + ipState ipConfigurationStatus + ipConfig cns.IPConfiguration + err error + ) + + ipConfig, err = requestIPConfigHelper(svc, req) + if err != nil { + return ipState, err + } + + // validate DnsServer and Gateway Ip as the same configured for Primary IP + if reflect.DeepEqual(ipConfig.DNSServers, dnsservers) != true { + t.Fatalf("DnsServer is not added as expected ipConfig %+v, expected dnsServers: %+v", ipConfig, dnsservers) + } + + if reflect.DeepEqual(ipConfig.GatewayIPAddress, gatewayIp) != true { + t.Fatalf("Gateway is not added as expected ipConfig %+v, expected GatewayIp: %+v", ipConfig, gatewayIp) + } + // retrieve podinfo from orchestrator context + if err := json.Unmarshal(req.OrchestratorContext, &podInfo); err != nil { + return ipState, err + } + + ipId := svc.PodIPIDByOrchestratorContext[podInfo.GetOrchestratorContextKey()] + ipState = svc.PodIPConfigState[ipId] + + return ipState, err +} + func NewPodStateWithOrchestratorContext(ipaddress string, prefixLength uint8, id, ncid, state string, orchestratorContext cns.KubernetesPodInfo) (ipConfigurationStatus, error) { ipconfig := newSecondaryIPConfig(ipaddress, prefixLength) b, err := json.Marshal(orchestratorContext) @@ -80,11 +112,25 @@ func NewPodStateWithOrchestratorContext(ipaddress string, prefixLength uint8, id } // Test function to populate the IPConfigState -func UpdatePodIpConfigState(svc *HTTPRestService, ipconfigs map[string]ipConfigurationStatus) error { - // add ipconfigs to state - for ipId, ipconfig := range ipconfigs { +func UpdatePodIpConfigState(t *testing.T, svc *HTTPRestService, ipconfigs map[string]ipConfigurationStatus) error { + // Create NC + secondaryIPConfigs := make(map[string]cns.SecondaryIPConfig) + for _, ipconfig := range ipconfigs { + secIpConfig := cns.SecondaryIPConfig{ + IPSubnet: cns.IPSubnet{ + IPAddress: ipconfig.IPSubnet.IPAddress, + PrefixLength: ipconfig.IPSubnet.PrefixLength, + }, + } - svc.PodIPConfigState[ipId] = ipconfig + ipId := ipconfig.ID + secondaryIPConfigs[ipId] = secIpConfig + } + + createAndValidateNCRequest(t, secondaryIPConfigs, testNCID) + + // update ipconfigs to expected state + for ipId, ipconfig := range ipconfigs { if ipconfig.State == cns.Allocated { var podInfo cns.KubernetesPodInfo @@ -93,6 +139,7 @@ func UpdatePodIpConfigState(svc *HTTPRestService, ipconfigs map[string]ipConfigu } svc.PodIPIDByOrchestratorContext[podInfo.GetOrchestratorContextKey()] = ipId + svc.PodIPConfigState[ipId] = ipconfig } } return nil @@ -106,13 +153,13 @@ func TestIPAMGetAvailableIPConfig(t *testing.T) { ipconfigs := map[string]ipConfigurationStatus{ testState.ID: testState, } - UpdatePodIpConfigState(svc, ipconfigs) + UpdatePodIpConfigState(t, svc, ipconfigs) req := cns.GetIPConfigRequest{} b, _ := json.Marshal(testPod1Info) req.OrchestratorContext = b - actualstate, err := requestIPConfigHelper(svc, req) + actualstate, err := requestIpAddressAndGetState(t, req) if err != nil { t.Fatal("Expected IP retrieval to be nil") } @@ -138,7 +185,7 @@ func TestIPAMGetNextAvailableIPConfig(t *testing.T) { state1.ID: state1, state2.ID: state2, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -147,7 +194,7 @@ func TestIPAMGetNextAvailableIPConfig(t *testing.T) { b, _ := json.Marshal(testPod2Info) req.OrchestratorContext = b - actualstate, err := requestIPConfigHelper(svc, req) + actualstate, err := requestIpAddressAndGetState(t, req) if err != nil { t.Fatalf("Expected IP retrieval to be nil: %+v", err) } @@ -167,7 +214,7 @@ func TestIPAMGetAlreadyAllocatedIPConfigForSamePod(t *testing.T) { ipconfigs := map[string]ipConfigurationStatus{ testState.ID: testState, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -176,7 +223,7 @@ func TestIPAMGetAlreadyAllocatedIPConfigForSamePod(t *testing.T) { b, _ := json.Marshal(testPod1Info) req.OrchestratorContext = b - actualstate, err := requestIPConfigHelper(svc, req) + actualstate, err := requestIpAddressAndGetState(t, req) if err != nil { t.Fatalf("Expected not error: %+v", err) } @@ -197,7 +244,7 @@ func TestIPAMAttemptToRequestIPNotFoundInPool(t *testing.T) { testState.ID: testState, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -210,7 +257,7 @@ func TestIPAMAttemptToRequestIPNotFoundInPool(t *testing.T) { PrefixLength: 24, } - _, err = requestIPConfigHelper(svc, req) + _, err = requestIpAddressAndGetState(t, req) if err == nil { t.Fatalf("Expected to fail as IP not found in pool") } @@ -225,7 +272,7 @@ func TestIPAMGetDesiredIPConfigWithSpecfiedIP(t *testing.T) { testState.ID: testState, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -238,7 +285,7 @@ func TestIPAMGetDesiredIPConfigWithSpecfiedIP(t *testing.T) { PrefixLength: 24, } - actualstate, err := requestIPConfigHelper(svc, req) + actualstate, err := requestIpAddressAndGetState(t, req) if err != nil { t.Fatalf("Expected IP retrieval to be nil: %+v", err) } @@ -259,7 +306,7 @@ func TestIPAMFailToGetDesiredIPConfigWithAlreadyAllocatedSpecfiedIP(t *testing.T ipconfigs := map[string]ipConfigurationStatus{ testState.ID: testState, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -273,9 +320,9 @@ func TestIPAMFailToGetDesiredIPConfigWithAlreadyAllocatedSpecfiedIP(t *testing.T PrefixLength: 24, } - _, err = requestIPConfigHelper(svc, req) + _, err = requestIpAddressAndGetState(t, req) if err == nil { - t.Fatalf("Expected failure requesting already IP: %+v", err) + t.Fatalf("Expected failure requesting already allocated IP: %+v", err) } } @@ -290,7 +337,7 @@ func TestIPAMFailToGetIPWhenAllIPsAreAllocated(t *testing.T) { state1.ID: state1, state2.ID: state2, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -300,7 +347,7 @@ func TestIPAMFailToGetIPWhenAllIPsAreAllocated(t *testing.T) { b, _ := json.Marshal(testPod3Info) req.OrchestratorContext = b - _, err = requestIPConfigHelper(svc, req) + _, err = requestIpAddressAndGetState(t, req) if err == nil { t.Fatalf("Expected failure requesting IP when there are no more IP's: %+v", err) } @@ -319,7 +366,7 @@ func TestIPAMRequestThenReleaseThenRequestAgain(t *testing.T) { state1.ID: state1, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -335,13 +382,13 @@ func TestIPAMRequestThenReleaseThenRequestAgain(t *testing.T) { req.OrchestratorContext = b req.DesiredIPConfig = desiredIPConfig - _, err = requestIPConfigHelper(svc, req) + _, err = requestIpAddressAndGetState(t, req) if err == nil { t.Fatal("Expected failure requesting IP when there are no more IP's") } // Release Test Pod 1 - err = svc.ReleaseIPConfig(testPod1Info) + err = svc.releaseIPConfig(testPod1Info) if err != nil { t.Fatalf("Unexpected failure releasing IP: %+v", err) } @@ -352,7 +399,7 @@ func TestIPAMRequestThenReleaseThenRequestAgain(t *testing.T) { req.OrchestratorContext = b req.DesiredIPConfig = desiredIPConfig - actualstate, err := requestIPConfigHelper(svc, req) + actualstate, err := requestIpAddressAndGetState(t, req) if err != nil { t.Fatalf("Expected IP retrieval to be nil: %+v", err) } @@ -375,19 +422,19 @@ func TestIPAMReleaseIPIdempotency(t *testing.T) { state1.ID: state1, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } // Release Test Pod 1 - err = svc.ReleaseIPConfig(testPod1Info) + err = svc.releaseIPConfig(testPod1Info) if err != nil { t.Fatalf("Unexpected failure releasing IP: %+v", err) } // Call release again, should be fine - err = svc.ReleaseIPConfig(testPod1Info) + err = svc.releaseIPConfig(testPod1Info) if err != nil { t.Fatalf("Unexpected failure releasing IP: %+v", err) } @@ -402,12 +449,12 @@ func TestIPAMAllocateIPIdempotency(t *testing.T) { state1.ID: state1, } - err := UpdatePodIpConfigState(svc, ipconfigs) + err := UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } - err = UpdatePodIpConfigState(svc, ipconfigs) + err = UpdatePodIpConfigState(t, svc, ipconfigs) if err != nil { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } @@ -425,7 +472,7 @@ func TestAvailableIPConfigs(t *testing.T) { state2.ID: state2, state3.ID: state3, } - UpdatePodIpConfigState(svc, ipconfigs) + UpdatePodIpConfigState(t, svc, ipconfigs) desiredAvailableIps := map[string]ipConfigurationStatus{ state1.ID: state1, @@ -444,7 +491,7 @@ func TestAvailableIPConfigs(t *testing.T) { req.OrchestratorContext = b req.DesiredIPConfig = state1.IPSubnet - _, err := requestIPConfigHelper(svc, req) + _, err := requestIpAddressAndGetState(t, req) if err != nil { t.Fatal("Expected IP retrieval to be nil") } diff --git a/cns/restserver/util.go b/cns/restserver/util.go index abee12e6b1..836cab42dc 100644 --- a/cns/restserver/util.go +++ b/cns/restserver/util.go @@ -622,6 +622,40 @@ func (service *HTTPRestService) SendNCSnapShotPeriodically(ncSnapshotIntervalInM } } +func (service *HTTPRestService) validateIpConfigRequest(ipConfigRequest cns.GetIPConfigRequest) (int, string) { + if service.state.OrchestratorType != cns.KubernetesCRD { + return UnsupportedOrchestratorType, fmt.Sprintf("ReleaseIPConfig API supported only for kubernetes orchestrator") + } + + if ipConfigRequest.OrchestratorContext == nil { + return EmptyOrchestratorContext, fmt.Sprintf("OrchastratorContext is not set in the req: %+v", ipConfigRequest) + } + + // retrieve podinfo from orchestrator context + var podInfo cns.KubernetesPodInfo + if err := json.Unmarshal(ipConfigRequest.OrchestratorContext, &podInfo); err != nil { + return UnsupportedOrchestratorContext, err.Error() + } + + return Success, "" +} + +func (service *HTTPRestService) populateIpConfigInfoFromNCUntransacted(ncId string, ipConfiguration *cns.IPConfiguration) error { + var ( + ncStatus containerstatus + exists bool + ) + + if ncStatus, exists = service.state.ContainerStatus[ncId]; !exists { + return fmt.Errorf("Failed to get NC Configuration for NcId: %s", ncId) + } + + ipConfiguration.DNSServers = ncStatus.CreateNetworkContainerRequest.IPConfiguration.DNSServers + ipConfiguration.GatewayIPAddress = ncStatus.CreateNetworkContainerRequest.IPConfiguration.GatewayIPAddress + + return nil +} + // isNCWaitingForUpdate :- Determine whether NC version on NMA matches programmed version func isNCWaitingForUpdate(ncVersion, ncid string) (waitingForUpdate bool, returnCode int, message string) { getNCVersionURL, ok := ncVersionURLs.Load(ncid)