diff --git a/cns/NetworkContainerContract.go b/cns/NetworkContainerContract.go index b2185096c2..8b8b12fe32 100644 --- a/cns/NetworkContainerContract.go +++ b/cns/NetworkContainerContract.go @@ -189,13 +189,25 @@ type GetNetworkContainerResponse struct { } type GetIPConfigRequest struct { - DesiredIPConfig IPSubnet + DesiredIPAddress string OrchestratorContext json.RawMessage } type GetIPConfigResponse struct { - IPConfiguration IPConfiguration - Response Response + PodIpInfo PodIpInfo + Response Response +} + +// DeleteNetworkContainerRequest specifies the details about the request to delete a specifc network container. +type PodIpInfo struct { + PodIPConfig IPSubnet + NetworkContainerPrimaryIPConfig IPConfiguration + HostPrimaryIPInfo HostIPInfo +} + +// DeleteNetworkContainerRequest specifies the details about the request to delete a specifc network container. +type HostIPInfo struct { + IPConfig IPSubnet } // DeleteNetworkContainerRequest specifies the details about the request to delete a specifc network container. diff --git a/cns/cnsclient/cnsclient_test.go b/cns/cnsclient/cnsclient_test.go index 256c46721b..df58661ebc 100644 --- a/cns/cnsclient/cnsclient_test.go +++ b/cns/cnsclient/cnsclient_test.go @@ -27,6 +27,7 @@ var ( const ( primaryIp = "10.0.0.5" gatewayIp = "10.0.0.1" + subnetPrfixLength = 24 dockerContainerType = cns.Docker ) @@ -40,7 +41,7 @@ func addTestStateToRestServer(t *testing.T, secondaryIps []string) { ipConfig.GatewayIPAddress = gatewayIp var ipSubnet cns.IPSubnet ipSubnet.IPAddress = primaryIp - ipSubnet.PrefixLength = 32 + ipSubnet.PrefixLength = subnetPrfixLength ipConfig.IPSubnet = ipSubnet secondaryIPConfigs := make(map[string]cns.SecondaryIPConfig) @@ -72,8 +73,8 @@ func getIPNetFromResponse(resp *cns.GetIPConfigResponse) (net.IPNet, error) { ) // set result ipconfig from CNS Response Body - prefix := strconv.Itoa(int(resp.IPConfiguration.IPSubnet.PrefixLength)) - ip, ipnet, err := net.ParseCIDR(resp.IPConfiguration.IPSubnet.IPAddress + "/" + prefix) + prefix := strconv.Itoa(int(resp.PodIpInfo.PodIPConfig.PrefixLength)) + ip, ipnet, err := net.ParseCIDR(resp.PodIpInfo.PodIPConfig.IPAddress + "/" + prefix) if err != nil { return resultIPnet, err } @@ -155,7 +156,7 @@ func TestCNSClientRequestAndRelease(t *testing.T) { podNamespace := "testpodnamespace" desiredIpAddress := "10.0.0.5" ip := net.ParseIP(desiredIpAddress) - _, ipnet, _ := net.ParseCIDR("10.0.0.5/32") + _, ipnet, _ := net.ParseCIDR("10.0.0.5/24") desired := net.IPNet{ IP: ip, Mask: ipnet.Mask, @@ -185,13 +186,22 @@ func TestCNSClientRequestAndRelease(t *testing.T) { t.Fatalf("get IP from CNS failed with %+v", err) } - // 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) + podIPInfo := resp.PodIpInfo + if reflect.DeepEqual(podIPInfo.NetworkContainerPrimaryIPConfig.IPSubnet.IPAddress, primaryIp) != true { + t.Fatalf("PrimarIP is not added as expected ipConfig %+v, expected primaryIP: %+v", podIPInfo.NetworkContainerPrimaryIPConfig, primaryIp) } - if reflect.DeepEqual(resp.IPConfiguration.GatewayIPAddress, gatewayIp) != true { - t.Fatalf("Gateway is not added as expected ipConfig %+v, expected GatewayIp: %+v", resp.IPConfiguration, gatewayIp) + if podIPInfo.NetworkContainerPrimaryIPConfig.IPSubnet.PrefixLength != subnetPrfixLength { + t.Fatalf("Primary IP Prefix length is not added as expected ipConfig %+v, expected: %+v", podIPInfo.NetworkContainerPrimaryIPConfig, subnetPrfixLength) + } + + // validate DnsServer and Gateway Ip as the same configured for Primary IP + if reflect.DeepEqual(podIPInfo.NetworkContainerPrimaryIPConfig.DNSServers, dnsservers) != true { + t.Fatalf("DnsServer is not added as expected ipConfig %+v, expected dnsServers: %+v", podIPInfo.NetworkContainerPrimaryIPConfig, dnsservers) + } + + if reflect.DeepEqual(podIPInfo.NetworkContainerPrimaryIPConfig.GatewayIPAddress, gatewayIp) != true { + t.Fatalf("Gateway is not added as expected ipConfig %+v, expected GatewayIp: %+v", podIPInfo.NetworkContainerPrimaryIPConfig, gatewayIp) } resultIPnet, err := getIPNetFromResponse(resp) diff --git a/cns/restserver/internalapi.go b/cns/restserver/internalapi.go index de9a689a57..03dfac4885 100644 --- a/cns/restserver/internalapi.go +++ b/cns/restserver/internalapi.go @@ -170,11 +170,6 @@ func (service *HTTPRestService) ReconcileNCState(ncRequest *cns.CreateNetworkCon if podInfo, exists := podInfoByIp[secIpConfig.IPAddress]; exists { log.Logf("SecondaryIP %+v is allocated to Pod. %+v, ncId: %s", secIpConfig, podInfo, ncRequest.NetworkContainerid) - desiredIPConfig := cns.IPSubnet{ - IPAddress: secIpConfig.IPAddress, - PrefixLength: 32, //todo: remove PrefixLenght in - } - kubernetesPodInfo := cns.KubernetesPodInfo{ PodName: podInfo.PodName, PodNamespace: podInfo.PodNamespace, @@ -182,7 +177,7 @@ func (service *HTTPRestService) ReconcileNCState(ncRequest *cns.CreateNetworkCon jsonContext, _ := json.Marshal(kubernetesPodInfo) ipconfigRequest := cns.GetIPConfigRequest{ - DesiredIPConfig: desiredIPConfig, + DesiredIPAddress: secIpConfig.IPAddress, OrchestratorContext: jsonContext, } diff --git a/cns/restserver/internalapi_test.go b/cns/restserver/internalapi_test.go index 0ab0eb0aad..c8c3631de1 100644 --- a/cns/restserver/internalapi_test.go +++ b/cns/restserver/internalapi_test.go @@ -17,6 +17,7 @@ import ( const ( primaryIp = "10.0.0.5" gatewayIp = "10.0.0.1" + subnetPrfixLength = 24 dockerContainerType = cns.Docker ) @@ -256,7 +257,7 @@ func generateNetworkContainerRequest(secondaryIps map[string]cns.SecondaryIPConf ipConfig.GatewayIPAddress = gatewayIp var ipSubnet cns.IPSubnet ipSubnet.IPAddress = primaryIp - ipSubnet.PrefixLength = 32 + ipSubnet.PrefixLength = subnetPrfixLength ipConfig.IPSubnet = ipSubnet req := cns.CreateNetworkContainerRequest{ diff --git a/cns/restserver/ipam.go b/cns/restserver/ipam.go index 362a8d0071..a22227762c 100644 --- a/cns/restserver/ipam.go +++ b/cns/restserver/ipam.go @@ -18,7 +18,7 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r var ( err error ipconfigRequest cns.GetIPConfigRequest - ipconfiguration cns.IPConfiguration + podIpInfo cns.PodIpInfo returnCode int returnMessage string ) @@ -32,7 +32,7 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r // retrieve ipconfig from nc _, returnCode, returnMessage = service.validateIpConfigRequest(ipconfigRequest) if returnCode == Success { - if ipconfiguration, err = requestIPConfigHelper(service, ipconfigRequest); err != nil { + if podIpInfo, err = requestIPConfigHelper(service, ipconfigRequest); err != nil { returnCode = FailedToAllocateIpConfig returnMessage = fmt.Sprintf("AllocateIPConfig failed: %v", err) } @@ -46,7 +46,7 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r reserveResp := &cns.GetIPConfigResponse{ Response: resp, } - reserveResp.IPConfiguration = ipconfiguration + reserveResp.PodIpInfo = podIpInfo err = service.Listener.Encode(w, &reserveResp) logger.Response(service.Name, reserveResp, resp.ReturnCode, ReturnCodeToString(resp.ReturnCode), err) @@ -158,10 +158,10 @@ func (service *HTTPRestService) releaseIPConfig(podInfo cns.KubernetesPodInfo) e return nil } -func (service *HTTPRestService) GetExistingIPConfig(podInfo cns.KubernetesPodInfo) (cns.IPConfiguration, bool, error) { +func (service *HTTPRestService) GetExistingIPConfig(podInfo cns.KubernetesPodInfo) (cns.PodIpInfo, bool, error) { var ( - ipConfiguration cns.IPConfiguration - isExist bool + podIpInfo cns.PodIpInfo + isExist bool ) service.RLock() @@ -170,19 +170,19 @@ func (service *HTTPRestService) GetExistingIPConfig(podInfo cns.KubernetesPodInf ipID := service.PodIPIDByOrchestratorContext[podInfo.GetOrchestratorContextKey()] if ipID != "" { if ipState, isExist := service.PodIPConfigState[ipID]; isExist { - err := service.populateIpConfigInfoUntransacted(ipState, &ipConfiguration) - return ipConfiguration, isExist, err + err := service.populateIpConfigInfoUntransacted(ipState, &podIpInfo) + return podIpInfo, 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 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 podIpInfo, 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, nil + return podIpInfo, isExist, nil } -func (service *HTTPRestService) AllocateDesiredIPConfig(podInfo cns.KubernetesPodInfo, desiredIPAddress string, orchestratorContext json.RawMessage) (cns.IPConfiguration, error) { - var ipConfiguration cns.IPConfiguration +func (service *HTTPRestService) AllocateDesiredIPConfig(podInfo cns.KubernetesPodInfo, desiredIPAddress string, orchestratorContext json.RawMessage) (cns.PodIpInfo, error) { + var podIpInfo cns.PodIpInfo service.Lock() defer service.Unlock() @@ -197,62 +197,62 @@ func (service *HTTPRestService) AllocateDesiredIPConfig(podInfo cns.KubernetesPo } 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) + return podIpInfo, 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) + return podIpInfo, fmt.Errorf("Desired IP is not available %+v", ipState) } if found { - err := service.populateIpConfigInfoUntransacted(ipState, &ipConfiguration) - return ipConfiguration, err + err := service.populateIpConfigInfoUntransacted(ipState, &podIpInfo) + return podIpInfo, err } } } - return ipConfiguration, fmt.Errorf("Requested IP not found in pool") + return podIpInfo, fmt.Errorf("Requested IP not found in pool") } -func (service *HTTPRestService) AllocateAnyAvailableIPConfig(podInfo cns.KubernetesPodInfo, orchestratorContext json.RawMessage) (cns.IPConfiguration, error) { - var ipConfiguration cns.IPConfiguration +func (service *HTTPRestService) AllocateAnyAvailableIPConfig(podInfo cns.KubernetesPodInfo, orchestratorContext json.RawMessage) (cns.PodIpInfo, error) { + var podIpInfo cns.PodIpInfo service.Lock() defer service.Unlock() for _, ipState := range service.PodIPConfigState { if ipState.State == cns.Available { - err := service.populateIpConfigInfoUntransacted(ipState, &ipConfiguration) + err := service.populateIpConfigInfoUntransacted(ipState, &podIpInfo) if err == nil { service.setIPConfigAsAllocated(ipState, podInfo, orchestratorContext) } - return ipConfiguration, err + return podIpInfo, err } } - return ipConfiguration, fmt.Errorf("No more free IP's available, trigger batch") + return podIpInfo, 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) (cns.IPConfiguration, error) { +func requestIPConfigHelper(service *HTTPRestService, req cns.GetIPConfigRequest) (cns.PodIpInfo, error) { var ( - podInfo cns.KubernetesPodInfo - ipConfiguration cns.IPConfiguration - isExist bool - err error + podInfo cns.KubernetesPodInfo + podIpInfo cns.PodIpInfo + isExist bool + err error ) // 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 json.Unmarshal(req.OrchestratorContext, &podInfo) - if ipConfiguration, isExist, err = service.GetExistingIPConfig(podInfo); err != nil || isExist { - return ipConfiguration, err + if podIpInfo, isExist, err = service.GetExistingIPConfig(podInfo); err != nil || isExist { + return podIpInfo, err } // return desired IPConfig - if req.DesiredIPConfig.IPAddress != "" { - return service.AllocateDesiredIPConfig(podInfo, req.DesiredIPConfig.IPAddress, req.OrchestratorContext) + if req.DesiredIPAddress != "" { + return service.AllocateDesiredIPConfig(podInfo, req.DesiredIPAddress, req.OrchestratorContext) } // return any free IPConfig diff --git a/cns/restserver/ipam_test.go b/cns/restserver/ipam_test.go index c14470950e..6e4cc4326f 100644 --- a/cns/restserver/ipam_test.go +++ b/cns/restserver/ipam_test.go @@ -66,24 +66,36 @@ 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 + podInfo cns.KubernetesPodInfo + ipState ipConfigurationStatus + PodIpInfo cns.PodIpInfo + err error ) - ipConfig, err = requestIPConfigHelper(svc, req) + PodIpInfo, err = requestIPConfigHelper(svc, req) if err != nil { return ipState, err } + if reflect.DeepEqual(PodIpInfo.NetworkContainerPrimaryIPConfig.IPSubnet.IPAddress, primaryIp) != true { + t.Fatalf("PrimarIP is not added as expected ipConfig %+v, expected primaryIP: %+v", PodIpInfo.NetworkContainerPrimaryIPConfig, primaryIp) + } + + if PodIpInfo.NetworkContainerPrimaryIPConfig.IPSubnet.PrefixLength != subnetPrfixLength { + t.Fatalf("Primary IP Prefix length is not added as expected ipConfig %+v, expected: %+v", PodIpInfo.NetworkContainerPrimaryIPConfig, subnetPrfixLength) + } + // 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(PodIpInfo.NetworkContainerPrimaryIPConfig.DNSServers, dnsservers) != true { + t.Fatalf("DnsServer is not added as expected ipConfig %+v, expected dnsServers: %+v", PodIpInfo.NetworkContainerPrimaryIPConfig, dnsservers) + } + + if reflect.DeepEqual(PodIpInfo.NetworkContainerPrimaryIPConfig.GatewayIPAddress, gatewayIp) != true { + t.Fatalf("Gateway is not added as expected ipConfig %+v, expected GatewayIp: %+v", PodIpInfo.NetworkContainerPrimaryIPConfig, gatewayIp) } - if reflect.DeepEqual(ipConfig.GatewayIPAddress, gatewayIp) != true { - t.Fatalf("Gateway is not added as expected ipConfig %+v, expected GatewayIp: %+v", ipConfig, gatewayIp) + if PodIpInfo.PodIPConfig.PrefixLength != subnetPrfixLength { + t.Fatalf("Pod IP Prefix length is not added as expected ipConfig %+v, expected: %+v", PodIpInfo.PodIPConfig, subnetPrfixLength) } // retrieve podinfo from orchestrator context @@ -247,10 +259,7 @@ func TestIPAMAttemptToRequestIPNotFoundInPool(t *testing.T) { req := cns.GetIPConfigRequest{} b, _ := json.Marshal(testPod2Info) req.OrchestratorContext = b - req.DesiredIPConfig = cns.IPSubnet{ - IPAddress: testIP2, - PrefixLength: 24, - } + req.DesiredIPAddress = testIP2 _, err = requestIpAddressAndGetState(t, req) if err == nil { @@ -275,10 +284,7 @@ func TestIPAMGetDesiredIPConfigWithSpecfiedIP(t *testing.T) { req := cns.GetIPConfigRequest{} b, _ := json.Marshal(testPod1Info) req.OrchestratorContext = b - req.DesiredIPConfig = cns.IPSubnet{ - IPAddress: testIP1, - PrefixLength: 24, - } + req.DesiredIPAddress = testIP1 actualstate, err := requestIpAddressAndGetState(t, req) if err != nil { @@ -310,10 +316,7 @@ func TestIPAMFailToGetDesiredIPConfigWithAlreadyAllocatedSpecfiedIP(t *testing.T req := cns.GetIPConfigRequest{} b, _ := json.Marshal(testPod2Info) req.OrchestratorContext = b - req.DesiredIPConfig = cns.IPSubnet{ - IPAddress: testIP1, - PrefixLength: 24, - } + req.DesiredIPAddress = testIP1 _, err = requestIpAddressAndGetState(t, req) if err == nil { @@ -366,16 +369,13 @@ func TestIPAMRequestThenReleaseThenRequestAgain(t *testing.T) { t.Fatalf("Expected to not fail adding IP's to state: %+v", err) } - desiredIPConfig := cns.IPSubnet{ - IPAddress: testIP1, - PrefixLength: 24, - } + desiredIpAddress := testIP1 // Use TestPodInfo2 to request TestIP1, which has already been allocated req := cns.GetIPConfigRequest{} b, _ := json.Marshal(testPod2Info) req.OrchestratorContext = b - req.DesiredIPConfig = desiredIPConfig + req.DesiredIPAddress = desiredIpAddress _, err = requestIpAddressAndGetState(t, req) if err == nil { @@ -392,7 +392,7 @@ func TestIPAMRequestThenReleaseThenRequestAgain(t *testing.T) { req = cns.GetIPConfigRequest{} b, _ = json.Marshal(testPod2Info) req.OrchestratorContext = b - req.DesiredIPConfig = desiredIPConfig + req.DesiredIPAddress = desiredIpAddress actualstate, err := requestIpAddressAndGetState(t, req) if err != nil { @@ -401,7 +401,7 @@ func TestIPAMRequestThenReleaseThenRequestAgain(t *testing.T) { desiredState, _ := NewPodStateWithOrchestratorContext(testIP1, 24, testPod1GUID, testNCID, cns.Allocated, testPod1Info) // want first available Pod IP State - desiredState.IPAddress = desiredIPConfig.IPAddress + desiredState.IPAddress = desiredIpAddress desiredState.OrchestratorContext = b if reflect.DeepEqual(desiredState, actualstate) != true { @@ -484,10 +484,7 @@ func TestAvailableIPConfigs(t *testing.T) { req := cns.GetIPConfigRequest{} b, _ := json.Marshal(testPod1Info) req.OrchestratorContext = b - req.DesiredIPConfig = cns.IPSubnet{ - IPAddress: state1.IPAddress, - PrefixLength: 32, - } + req.DesiredIPAddress = state1.IPAddress _, err := requestIpAddressAndGetState(t, req) if err != nil { diff --git a/cns/restserver/util.go b/cns/restserver/util.go index 839580f07d..806763e81b 100644 --- a/cns/restserver/util.go +++ b/cns/restserver/util.go @@ -641,7 +641,7 @@ func (service *HTTPRestService) validateIpConfigRequest(ipConfigRequest cns.GetI return podInfo, Success, "" } -func (service *HTTPRestService) populateIpConfigInfoUntransacted(ipConfigStatus ipConfigurationStatus, ipConfiguration *cns.IPConfiguration) error { +func (service *HTTPRestService) populateIpConfigInfoUntransacted(ipConfigStatus ipConfigurationStatus, podIpInfo *cns.PodIpInfo) error { var ( ncStatus containerstatus exists bool @@ -654,13 +654,15 @@ func (service *HTTPRestService) populateIpConfigInfoUntransacted(ipConfigStatus primaryIpConfiguration = ncStatus.CreateNetworkContainerRequest.IPConfiguration - ipConfiguration.DNSServers = primaryIpConfiguration.DNSServers - ipConfiguration.GatewayIPAddress = primaryIpConfiguration.GatewayIPAddress - - ipConfiguration.IPSubnet = cns.IPSubnet{ + podIpInfo.PodIPConfig = cns.IPSubnet{ IPAddress: ipConfigStatus.IPAddress, PrefixLength: primaryIpConfiguration.IPSubnet.PrefixLength, } + + podIpInfo.NetworkContainerPrimaryIPConfig = primaryIpConfiguration + + // TODO Add Host Primary ipinfo + return nil }