* Implement ReconcileNCState api
This commit is contained in:
neaggarwMS 2020-07-27 20:53:49 -07:00 коммит произвёл GitHub
Родитель e03248d9e5
Коммит 568e3dc177
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 312 добавлений и 85 удалений

Просмотреть файл

@ -4,6 +4,6 @@ import "github.com/Azure/azure-container-networking/cns"
// APIClient interface to update cns state
type APIClient interface {
InitCNSState(*cns.CreateNetworkContainerRequest, map[string]*cns.KubernetesPodInfo) error
ReconcileNCState(*cns.CreateNetworkContainerRequest, map[string]cns.KubernetesPodInfo) error
CreateOrUpdateNC(cns.CreateNetworkContainerRequest) error
}

Просмотреть файл

@ -23,12 +23,13 @@ func (client *Client) CreateOrUpdateNC(ncRequest cns.CreateNetworkContainerReque
return nil
}
// InitCNSState initializes cns state
func (client *Client) InitCNSState(ncRequest *cns.CreateNetworkContainerRequest, podInfoByIP map[string]*cns.KubernetesPodInfo) error {
// client.RestService.Lock()
// client.RestService.ReadyToIPAM = true
// client.RestService.Unlock()
// ReconcileNCState initializes cns state
func (client *Client) ReconcileNCState(ncRequest *cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.KubernetesPodInfo) error {
returnCode := client.RestService.ReconcileNCState(ncRequest, podInfoByIP)
if returnCode != 0 {
return fmt.Errorf("Failed to Reconcile ncState: ncRequest %+v, podInfoMap: %+v, errorCode: %d", *ncRequest, podInfoByIP, returnCode)
}
// return client.RestService.AddIPConfigsToState(ipConfigs)
return nil
}

Просмотреть файл

@ -171,9 +171,9 @@ func (crdRC *crdRequestController) initCNS() error {
var (
pods *corev1.PodList
pod corev1.Pod
podInfo *cns.KubernetesPodInfo
podInfo cns.KubernetesPodInfo
nodeNetConfig *nnc.NodeNetworkConfig
podInfoByIP map[string]*cns.KubernetesPodInfo
podInfoByIP map[string]cns.KubernetesPodInfo
cntxt context.Context
ncRequest cns.CreateNetworkContainerRequest
err error
@ -191,7 +191,7 @@ func (crdRC *crdRequestController) initCNS() error {
// If instance of crd is not found, pass nil to CNSClient
if client.IgnoreNotFound(err) == nil {
return crdRC.CNSClient.InitCNSState(nil, nil)
return crdRC.CNSClient.ReconcileNCState(nil, nil)
}
// If it's any other error, log it and return
@ -201,7 +201,7 @@ func (crdRC *crdRequestController) initCNS() error {
// If there are no NCs, pass nil to CNSClient
if len(nodeNetConfig.Status.NetworkContainers) == 0 {
return crdRC.CNSClient.InitCNSState(nil, nil)
return crdRC.CNSClient.ReconcileNCState(nil, nil)
}
// Convert to CreateNetworkContainerRequest
@ -218,11 +218,11 @@ func (crdRC *crdRequestController) initCNS() error {
// Convert pod list to map of pod ip -> kubernetes pod info
if len(pods.Items) != 0 {
podInfoByIP = make(map[string]*cns.KubernetesPodInfo)
podInfoByIP = make(map[string]cns.KubernetesPodInfo)
for _, pod = range pods.Items {
//Only add pods that aren't on the host network
if !pod.Spec.HostNetwork {
podInfo = &cns.KubernetesPodInfo{
podInfo = cns.KubernetesPodInfo{
PodName: pod.Name,
PodNamespace: pod.Namespace,
}
@ -231,7 +231,9 @@ func (crdRC *crdRequestController) initCNS() error {
}
}
return crdRC.CNSClient.InitCNSState(&ncRequest, podInfoByIP)
// Call cnsclient init cns passing those two things
return crdRC.CNSClient.ReconcileNCState(&ncRequest, podInfoByIP)
}
// UpdateCRDSpec updates the CRD spec

Просмотреть файл

@ -93,7 +93,7 @@ func (mc MockKubeClient) Update(ctx context.Context, obj runtime.Object, opts ..
type MockCNSClient struct {
MockCNSUpdated bool
MockCNSInitialized bool
Pods map[string]*cns.KubernetesPodInfo
Pods map[string]cns.KubernetesPodInfo
NCRequest *cns.CreateNetworkContainerRequest
}
@ -103,7 +103,7 @@ func (mi *MockCNSClient) CreateOrUpdateNC(ncRequest cns.CreateNetworkContainerRe
return nil
}
func (mi *MockCNSClient) InitCNSState(ncRequest *cns.CreateNetworkContainerRequest, podInfoByIP map[string]*cns.KubernetesPodInfo) error {
func (mi *MockCNSClient) ReconcileNCState(ncRequest *cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.KubernetesPodInfo) error {
mi.MockCNSInitialized = true
mi.Pods = podInfoByIP
mi.NCRequest = ncRequest

Просмотреть файл

@ -99,29 +99,7 @@ func TestMain(m *testing.M) {
logger.InitLogger("testlogs", 0, 0, "./")
// Create the service.
config := common.ServiceConfig{}
service, err = NewHTTPRestService(&config)
if err != nil {
fmt.Printf("Failed to create CNS object %v\n", err)
os.Exit(1)
}
svc = service.(*HTTPRestService)
svc.Name = "cns-test-server"
if err != nil {
logger.Errorf("Failed to create CNS object, err:%v.\n", err)
return
}
if service != nil {
err = service.Start(&config)
if err != nil {
logger.Errorf("Failed to start CNS, err:%v.\n", err)
return
}
}
// Get the internal http mux as test hook.
mux = service.(*HTTPRestService).Listener.GetMux()
startService()
// Setup mock nmagent server
u, err := url.Parse("tcp://" + nmagentEndpoint)
@ -276,34 +254,34 @@ func TestGetNetworkContainerByOrchestratorContext(t *testing.T) {
}
}
func TestGetNetworkContainerStatus(t *testing.T) {
// requires more than 30 seconds to run
fmt.Println("Test: TestCreateNetworkContainer")
// func TestGetNetworkContainerStatus(t *testing.T) {
// // requires more than 30 seconds to run
// fmt.Println("Test: TestCreateNetworkContainer")
setEnv(t)
setOrchestratorType(t, cns.Kubernetes)
// setEnv(t)
// setOrchestratorType(t, cns.Kubernetes)
err := creatOrUpdateNetworkContainerWithName(t, "ethWebApp", "11.0.0.5", cns.AzureContainerInstance)
if err != nil {
t.Errorf("creatOrUpdateWebAppContainerWithName failed Err:%+v", err)
t.Fatal(err)
}
// err := creatOrUpdateNetworkContainerWithName(t, "ethWebApp", "11.0.0.5", cns.AzureContainerInstance)
// if err != nil {
// t.Errorf("creatOrUpdateWebAppContainerWithName failed Err:%+v", err)
// t.Fatal(err)
// }
fmt.Println("Now calling getNetworkContainerStatus")
err = getNetworkContainerStatus(t, "ethWebApp")
if err != nil {
t.Errorf("getNetworkContainerStatus failed Err:%+v", err)
t.Fatal(err)
}
// fmt.Println("Now calling getNetworkContainerStatus")
// err = getNetworkContainerStatus(t, "ethWebApp")
// if err != nil {
// t.Errorf("getNetworkContainerStatus failed Err:%+v", err)
// t.Fatal(err)
// }
fmt.Println("Now calling DeleteNetworkContainer")
// fmt.Println("Now calling DeleteNetworkContainer")
err = deleteNetworkAdapterWithName(t, "ethWebApp")
if err != nil {
t.Errorf("Deleting interface failed Err:%+v", err)
t.Fatal(err)
}
}
// err = deleteNetworkAdapterWithName(t, "ethWebApp")
// if err != nil {
// t.Errorf("Deleting interface failed Err:%+v", err)
// t.Fatal(err)
// }
// }
func TestGetInterfaceForNetworkContainer(t *testing.T) {
// requires more than 30 seconds to run
@ -674,6 +652,34 @@ func setEnv(t *testing.T) *httptest.ResponseRecorder {
return w
}
func startService() {
var err error
// Create the service.
config := common.ServiceConfig{}
service, err = NewHTTPRestService(&config)
if err != nil {
fmt.Printf("Failed to create CNS object %v\n", err)
os.Exit(1)
}
svc = service.(*HTTPRestService)
svc.Name = "cns-test-server"
if err != nil {
logger.Errorf("Failed to create CNS object, err:%v.\n", err)
return
}
if service != nil {
err = service.Start(&config)
if err != nil {
logger.Errorf("Failed to start CNS, err:%v.\n", err)
return
}
}
// Get the internal http mux as test hook.
mux = service.(*HTTPRestService).Listener.GetMux()
}
// IGNORE TEST AS IT IS FAILING. TODO:- Fix it https://msazure.visualstudio.com/One/_workitems/edit/7720083
// // Tests CreateNetwork functionality.

Просмотреть файл

@ -32,6 +32,7 @@ const (
InconsistentIPConfigState = 29
InvalidSecondaryIPConfig = 30
NetworkContainerPendingStatePropagation = 31
FailedToAllocateIpConfig = 32
UnexpectedError = 99
)

Просмотреть файл

@ -15,6 +15,7 @@ import (
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/nmagentclient"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/log"
)
// This file contains the internal functions called by either HTTP APIs (api.go) or
@ -149,6 +150,54 @@ func (service *HTTPRestService) SyncNodeStatus(dncEP, infraVnet, nodeID string,
return
}
// This API will be called by CNS RequestController on CRD update.
func (service *HTTPRestService) ReconcileNCState(ncRequest *cns.CreateNetworkContainerRequest, podInfoByIp map[string]cns.KubernetesPodInfo) int {
// check if ncRequest is null, then return as there is no CRD state yet
if ncRequest == nil {
log.Logf("CNS starting with no NC state, podInfoMap count %d", len(podInfoByIp))
return Success
}
returnCode := service.CreateOrUpdateNetworkContainerInternal(*ncRequest)
// If the NC was created successfully, then reconcile the allocated pod state
if returnCode != Success {
return returnCode
}
// now parse the secondaryIP list, if it exists in PodInfo list, then allocate that ip
for _, secIpConfig := range ncRequest.SecondaryIPConfigs {
if podInfo, exists := podInfoByIp[secIpConfig.IPSubnet.IPAddress]; exists {
log.Logf("SecondaryIP %+v is allocated to Pod. %+v, ncId: %s", secIpConfig, podInfo, ncRequest.NetworkContainerid)
desiredIPConfig := cns.IPSubnet{
IPAddress: secIpConfig.IPSubnet.IPAddress,
PrefixLength: secIpConfig.IPSubnet.PrefixLength,
}
kubernetesPodInfo := cns.KubernetesPodInfo{
PodName: podInfo.PodName,
PodNamespace: podInfo.PodNamespace,
}
jsonContext, _ := json.Marshal(kubernetesPodInfo)
ipconfigRequest := cns.GetIPConfigRequest{
DesiredIPConfig: desiredIPConfig,
OrchestratorContext: jsonContext,
}
if _, err := requestIPConfigHelper(service, ipconfigRequest); err != nil {
log.Errorf("AllocateIPConfig failed for SecondaryIP %+v, podInfo %+v, ncId %s, error: %v", secIpConfig, podInfo, ncRequest.NetworkContainerid, err)
return FailedToAllocateIpConfig
}
} else {
log.Logf("SecondaryIP %+v is not allocated. ncId: %s", secIpConfig, ncRequest.NetworkContainerid)
}
}
return 0
}
// This API will be called by CNS RequestController on CRD update.
func (service *HTTPRestService) CreateOrUpdateNetworkContainerInternal(req cns.CreateNetworkContainerRequest) int {
if req.NetworkContainerid == "" {

Просмотреть файл

@ -4,9 +4,11 @@
package restserver
import (
"encoding/json"
"fmt"
"testing"
"reflect"
"strconv"
"testing"
"github.com/Azure/azure-container-networking/cns"
"github.com/google/uuid"
@ -19,7 +21,7 @@ const (
)
func TestCreateOrUpdateNetworkContainerInternal(t *testing.T) {
fmt.Println("Test: TestCreateOrUpdateNetworkContainerInternal")
restartService()
setEnv(t)
setOrchestratorTypeInternal(cns.KubernetesCRD)
@ -27,6 +29,97 @@ func TestCreateOrUpdateNetworkContainerInternal(t *testing.T) {
validateCreateOrUpdateNCInternal(t, 2)
}
func TestReconcileNCWithEmptyState(t *testing.T) {
restartService()
setEnv(t)
setOrchestratorTypeInternal(cns.KubernetesCRD)
expectedNcCount := len(svc.state.ContainerStatus)
expectedAllocatedPods := make(map[string]cns.KubernetesPodInfo)
returnCode := svc.ReconcileNCState(nil, expectedAllocatedPods)
if returnCode != Success {
t.Errorf("Unexpected failure on reconcile with no state %d", returnCode)
}
validateNCStateAfterReconcile(t, nil, expectedNcCount, expectedAllocatedPods)
}
func TestReconcileNCWithExistingState(t *testing.T) {
restartService()
setEnv(t)
setOrchestratorTypeInternal(cns.KubernetesCRD)
secondaryIPConfigs := make(map[string]cns.SecondaryIPConfig)
var startingIndex = 6
for i := 0; i < 4; i++ {
ipaddress := "10.0.0." + strconv.Itoa(startingIndex)
secIpConfig := newSecondaryIPConfig(ipaddress, 32)
ipId := uuid.New()
secondaryIPConfigs[ipId.String()] = secIpConfig
startingIndex++
}
req := generateNetworkContainerRequest(secondaryIPConfigs, "reconcileNc1")
expectedAllocatedPods := make(map[string]cns.KubernetesPodInfo)
expectedAllocatedPods["10.0.0.6"] = cns.KubernetesPodInfo{
PodName: "reconcilePod1",
PodNamespace: "PodNS1",
}
expectedAllocatedPods["10.0.0.7"] = cns.KubernetesPodInfo{
PodName: "reconcilePod2",
PodNamespace: "PodNS1",
}
expectedNcCount := len(svc.state.ContainerStatus)
returnCode := svc.ReconcileNCState(&req, expectedAllocatedPods)
if returnCode != Success {
t.Errorf("Unexpected failure on reconcile with no state %d", returnCode)
}
validateNCStateAfterReconcile(t, &req, expectedNcCount+1, expectedAllocatedPods)
}
func TestReconcileNCWithSystemPods(t *testing.T) {
restartService()
setEnv(t)
setOrchestratorTypeInternal(cns.KubernetesCRD)
secondaryIPConfigs := make(map[string]cns.SecondaryIPConfig)
var startingIndex = 6
for i := 0; i < 4; i++ {
ipaddress := "10.0.0." + strconv.Itoa(startingIndex)
secIpConfig := newSecondaryIPConfig(ipaddress, 32)
ipId := uuid.New()
secondaryIPConfigs[ipId.String()] = secIpConfig
startingIndex++
}
req := generateNetworkContainerRequest(secondaryIPConfigs, uuid.New().String())
expectedAllocatedPods := make(map[string]cns.KubernetesPodInfo)
expectedAllocatedPods["10.0.0.6"] = cns.KubernetesPodInfo{
PodName: "customerpod1",
PodNamespace: "PodNS1",
}
// Allocate non-vnet IP for system pod
expectedAllocatedPods["192.168.0.1"] = cns.KubernetesPodInfo{
PodName: "systempod",
PodNamespace: "kube-system",
}
expectedNcCount := len(svc.state.ContainerStatus)
returnCode := svc.ReconcileNCState(&req, expectedAllocatedPods)
if returnCode != Success {
t.Errorf("Unexpected failure on reconcile with no state %d", returnCode)
}
delete(expectedAllocatedPods, "192.168.0.1")
validateNCStateAfterReconcile(t, &req, expectedNcCount, expectedAllocatedPods)
}
func setOrchestratorTypeInternal(orchestratorType string) {
fmt.Println("setOrchestratorTypeInternal")
svc.state.OrchestratorType = orchestratorType
@ -34,6 +127,7 @@ func setOrchestratorTypeInternal(orchestratorType string) {
func validateCreateOrUpdateNCInternal(t *testing.T, secondaryIpCount int) {
secondaryIPConfigs := make(map[string]cns.SecondaryIPConfig)
ncId := "testNc1"
var startingIndex = 6
for i := 0; i < secondaryIpCount; i++ {
@ -44,7 +138,7 @@ func validateCreateOrUpdateNCInternal(t *testing.T, secondaryIpCount int) {
startingIndex++
}
createAndValidateNCRequest(t, secondaryIPConfigs)
createAndValidateNCRequest(t, secondaryIPConfigs, ncId)
// now Validate Update, add more secondaryIpConfig and it should handle the update
fmt.Println("Validate Scaleup")
@ -56,7 +150,7 @@ func validateCreateOrUpdateNCInternal(t *testing.T, secondaryIpCount int) {
startingIndex++
}
createAndValidateNCRequest(t, secondaryIPConfigs)
createAndValidateNCRequest(t, secondaryIPConfigs, ncId)
// now Scale down, delete 3 ipaddresses from secondaryIpConfig req
fmt.Println("Validate Scale down")
@ -70,7 +164,7 @@ func validateCreateOrUpdateNCInternal(t *testing.T, secondaryIpCount int) {
}
}
createAndValidateNCRequest(t, secondaryIPConfigs)
createAndValidateNCRequest(t, secondaryIPConfigs, ncId)
// Cleanup all SecondaryIps
fmt.Println("Validate no SecondaryIpconfigs")
@ -78,20 +172,20 @@ func validateCreateOrUpdateNCInternal(t *testing.T, secondaryIpCount int) {
delete(secondaryIPConfigs, ipid)
}
createAndValidateNCRequest(t, secondaryIPConfigs)
createAndValidateNCRequest(t, secondaryIPConfigs, ncId)
}
func createAndValidateNCRequest(t *testing.T, secondaryIPConfigs map[string]cns.SecondaryIPConfig) {
req := generateNetworkContainerRequest(secondaryIPConfigs)
func createAndValidateNCRequest(t *testing.T, secondaryIPConfigs map[string]cns.SecondaryIPConfig, ncId string) {
req := generateNetworkContainerRequest(secondaryIPConfigs, ncId)
returnCode := svc.CreateOrUpdateNetworkContainerInternal(req)
if returnCode != 0 {
t.Fatalf("Failed to createNetworkContainerRequest, req: %+v, err: %d", req, returnCode)
}
validateNetworkRequest(t, req)
validateNetworkRequest(t, req, false)
}
// Validate the networkRequest is persisted.
func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest) {
func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest, skipAvailableCheck bool) {
containerStatus := svc.state.ContainerStatus[req.NetworkContainerid]
if containerStatus.ID != req.NetworkContainerid {
@ -123,7 +217,8 @@ func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest)
}
// Validate IP state
if ipStatus.State != cns.Available {
if !skipAvailableCheck &&
ipStatus.State != cns.Available {
t.Fatalf("IPId: %s State is not Available, ipStatus: %+v", ipid, ipStatus)
}
@ -138,7 +233,7 @@ func validateNetworkRequest(t *testing.T, req cns.CreateNetworkContainerRequest)
}
}
func generateNetworkContainerRequest(secondaryIps map[string]cns.SecondaryIPConfig) 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.GatewayIPAddress = gatewayIp
@ -149,7 +244,7 @@ func generateNetworkContainerRequest(secondaryIps map[string]cns.SecondaryIPConf
req := cns.CreateNetworkContainerRequest{
NetworkContainerType: dockerContainerType,
NetworkContainerid: "testNcId1",
NetworkContainerid: ncId,
IPConfiguration: ipConfig,
}
@ -158,5 +253,74 @@ func generateNetworkContainerRequest(secondaryIps map[string]cns.SecondaryIPConf
req.SecondaryIPConfigs[k] = v
}
fmt.Printf("NC Request %+v", req)
return req
}
func validateNCStateAfterReconcile(t *testing.T, ncRequest *cns.CreateNetworkContainerRequest, expectedNcCount int, expectedAllocatedPods map[string]cns.KubernetesPodInfo) {
if ncRequest == nil {
// check svc ContainerStatus will be empty
if len(svc.state.ContainerStatus) != expectedNcCount {
t.Fatalf("CNS has some stale ContainerStatus, count: %d, state: %+v", len(svc.state.ContainerStatus), svc.state.ContainerStatus)
}
} else {
validateNetworkRequest(t, *ncRequest, true)
}
if len(expectedAllocatedPods) != len(svc.PodIPIDByOrchestratorContext) {
t.Fatalf("Unexpected allocated pods, actual: %d, expected: %d", len(svc.PodIPIDByOrchestratorContext), len(expectedAllocatedPods))
}
for ipaddress, podInfo := range expectedAllocatedPods {
ipId := svc.PodIPIDByOrchestratorContext[podInfo.GetOrchestratorContextKey()]
ipConfigstate := svc.PodIPConfigState[ipId]
if ipConfigstate.State != cns.Allocated {
t.Fatalf("IpAddress %s is not marked as allocated for Pod: %+v, ipState: %+v", ipaddress, podInfo, ipConfigstate)
}
// Validate if IPAddress matches
if ipConfigstate.IPSubnet.IPAddress != ipaddress {
t.Fatalf("IpAddress %s is not same, for Pod: %+v, actual ipState: %+v", ipaddress, podInfo, ipConfigstate)
}
// Valdate pod context
var expectedPodInfo cns.KubernetesPodInfo
json.Unmarshal(ipConfigstate.OrchestratorContext, &expectedPodInfo)
if reflect.DeepEqual(expectedPodInfo, podInfo) != true {
t.Fatalf("OrchestrationContext: is not same, expected: %+v, actual %+v", expectedPodInfo, podInfo)
}
// Validate this IP belongs to a valid NCRequest
nc := svc.state.ContainerStatus[ipConfigstate.NCID]
if _, exists := nc.CreateNetworkContainerRequest.SecondaryIPConfigs[ipConfigstate.ID]; !exists {
t.Fatalf("Secondary IP config doest exist in NC, ncid: %s, ipId %s", ipConfigstate.NCID, ipConfigstate.ID)
}
}
// validate rest of Secondary IPs in Available state
if ncRequest != nil {
for secIpId, secIpConfig := range ncRequest.SecondaryIPConfigs {
if _, exists := expectedAllocatedPods[secIpConfig.IPSubnet.IPAddress]; exists {
continue
}
// Validate IP state
if secIpConfigState, found := svc.PodIPConfigState[secIpId]; found {
if secIpConfigState.State != cns.Available {
t.Fatalf("IPId: %s State is not Available, ipStatus: %+v", secIpId, secIpConfigState)
}
} else {
t.Fatalf("IPId: %s, IpAddress: %+v State doesnt exists in PodIp Map", secIpId, secIpConfig)
}
}
}
}
func restartService() {
fmt.Println("Restart Service")
service.Stop()
startService()
}

Просмотреть файл

@ -30,7 +30,7 @@ func (service *HTTPRestService) requestIPConfigHandler(w http.ResponseWriter, r
// retrieve ipconfig from nc
if ipState, err = requestIPConfigHelper(service, ipconfigRequest); err != nil {
returnCode = UnexpectedError
returnCode = FailedToAllocateIpConfig
returnMessage = fmt.Sprintf("AllocateIPConfig failed: %v", err)
}

Просмотреть файл

@ -217,7 +217,11 @@ func (service *HTTPRestService) updateIpConfigsStateUntransacted(req cns.CreateN
if exists {
// pod ip exists, validate if state is not allocated, else fail
if ipConfigStatus.State == cns.Allocated {
errMsg := fmt.Sprintf("Failed to delete an Allocated IP %v", ipConfigStatus)
var expectedPodInfo cns.KubernetesPodInfo
if len(ipConfigStatus.OrchestratorContext) != 0 {
json.Unmarshal(ipConfigStatus.OrchestratorContext, &expectedPodInfo)
}
errMsg := fmt.Sprintf("Failed to delete an Allocated IP %v, PodInfo %+v", ipConfigStatus, expectedPodInfo)
return InconsistentIPConfigState, errMsg
}
}