diff --git a/cns/client/client.go b/cns/client/client.go index 1021d6f412..38bf19d23f 100644 --- a/cns/client/client.go +++ b/cns/client/client.go @@ -1089,7 +1089,38 @@ func (c *Client) UpdateEndpoint(ctx context.Context, endpointID string, ipInfo m var response cns.Response err = json.NewDecoder(res.Body).Decode(&response) + if err != nil { + return nil, errors.Wrap(err, "failed to decode CNS Response") + } + + if response.ReturnCode != 0 { + return nil, errors.New(response.Message) + } + return &response, nil +} + +func (c *Client) DeleteEndpointState(ctx context.Context, endpointID string) (*cns.Response, error) { + // build the request + u := c.routes[cns.EndpointAPI] + uString := u.String() + endpointID + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uString, http.NoBody) + if err != nil { + return nil, errors.Wrap(err, "failed to build request") + } + req.Header.Set(headerContentType, contentTypeJSON) + res, err := c.client.Do(req) + if err != nil { + return nil, &ConnectionFailureErr{cause: err} + } + + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + return nil, errors.Errorf("http response %d", res.StatusCode) + } + + var response cns.Response + err = json.NewDecoder(res.Body).Decode(&response) if err != nil { return nil, errors.Wrap(err, "failed to decode CNS Response") } diff --git a/cns/restserver/ipam.go b/cns/restserver/ipam.go index 7c1366149d..3e87d8a714 100644 --- a/cns/restserver/ipam.go +++ b/cns/restserver/ipam.go @@ -1151,6 +1151,8 @@ func (service *HTTPRestService) EndpointHandlerAPI(w http.ResponseWriter, r *htt service.GetEndpointHandler(w, r) case http.MethodPatch: service.UpdateEndpointHandler(w, r) + case http.MethodDelete: + service.DeleteEndpointStateHandler(w, r) default: logger.Errorf("[EndpointHandlerAPI] EndpointHandler API expect http Get or Patch method") } @@ -1393,3 +1395,69 @@ func (service *HTTPRestService) getIPFamiliesMap() map[cns.IPFamily]struct{} { func (service *HTTPRestService) GetIPFamilyCount() int { return len(service.getIPFamiliesMap()) } + +func (service *HTTPRestService) DeleteEndpointStateHandler(w http.ResponseWriter, r *http.Request) { + opName := "DeleteEndpointStateHandler" + logger.Printf("[DeleteEndpointStateHandler] DeleteEndpointState for %s", r.URL.Path) //nolint:staticcheck // reason: using deprecated call until migration to new API + endpointID := strings.TrimPrefix(r.URL.Path, cns.EndpointPath) + + if service.EndpointStateStore == nil { + response := cns.Response{ + ReturnCode: types.UnexpectedError, + Message: "[DeleteEndpointStateHandler] EndpointStateStore is not initialized", + } + err := common.Encode(w, &response) + logger.Response(opName, response, response.ReturnCode, err) //nolint:staticcheck // reason: using deprecated call until migration to new API + return + } + + // Decode the request body to get ipInfo if needed + var req map[string]*IPInfo + err := common.Decode(w, r, &req) + if err != nil { + logger.Printf("[DeleteEndpointStateHandler] Failed to decode request body: %v", err) //nolint:staticcheck // reason: using deprecated call until migration to new API + // Continue with deletion even if decode fails, as ipInfo might not be needed + } + + // Delete the endpoint from state + err = service.DeleteEndpointStateHelper(endpointID) + if err != nil { + response := cns.Response{ + ReturnCode: types.UnexpectedError, + Message: fmt.Sprintf("[DeleteEndpointStateHandler] Failed to delete endpoint state for %s with error: %s", endpointID, err.Error()), + } + err = common.Encode(w, &response) + logger.Response(opName, response, response.ReturnCode, err) //nolint:staticcheck // reason: using deprecated call until migration to new API + return + } + + response := cns.Response{ + ReturnCode: types.Success, + Message: "[DeleteEndpointStateHandler] Endpoint state deleted successfully", + } + err = common.Encode(w, &response) + logger.Response(opName, response, response.ReturnCode, err) //nolint:staticcheck // reason: using deprecated call until migration to new API +} + +func (service *HTTPRestService) DeleteEndpointStateHelper(endpointID string) error { + if service.EndpointStateStore == nil { + return ErrStoreEmpty + } + logger.Printf("[deleteEndpointState] Deleting Endpoint state from state file %s", endpointID) //nolint:staticcheck // reason: using deprecated call until migration to new API + _, endpointExist := service.EndpointState[endpointID] + if !endpointExist { + logger.Printf("[deleteEndpointState] endpoint could not be found in the statefile %s", endpointID) //nolint:staticcheck // reason: using deprecated call until migration to new API + return fmt.Errorf("[deleteEndpointState] endpoint %s: %w", endpointID, ErrEndpointStateNotFound) + } + + // Delete the endpoint from the state + delete(service.EndpointState, endpointID) + + // Write the updated state back to the store + err := service.EndpointStateStore.Write(EndpointStoreKey, service.EndpointState) + if err != nil { + return fmt.Errorf("[deleteEndpointState] failed to write endpoint state to store: %w", err) + } + logger.Printf("[deleteEndpointState] successfully deleted endpoint %s from state file", endpointID) //nolint:staticcheck // reason: using deprecated call until migration to new API + return nil +} diff --git a/network/manager.go b/network/manager.go index 7bc1441fea..90bc5fcc78 100644 --- a/network/manager.go +++ b/network/manager.go @@ -761,7 +761,7 @@ func (nm *networkManager) SaveState(eps []*endpoint) error { return nm.save() } -func (nm *networkManager) DeleteState(_ []*EndpointInfo) error { +func (nm *networkManager) DeleteState(epInfos []*EndpointInfo) error { nm.Lock() defer nm.Unlock() @@ -771,6 +771,15 @@ func (nm *networkManager) DeleteState(_ []*EndpointInfo) error { // For stateless cni, plugin.ipamInvoker.Delete takes care of removing the state in the main Delete function if nm.IsStatelessCNIMode() { + for _, epInfo := range epInfos { + if epInfo.NICType == cns.NodeNetworkInterfaceFrontendNIC { + response, err := nm.CnsClient.DeleteEndpointState(context.TODO(), epInfo.EndpointID) + if err != nil { + return errors.Wrapf(err, "Delete endpoint API returned with error for endpoint %s", epInfo.EndpointID) + } + logger.Info("Delete endpoint API returned", zap.String("endpointID", epInfo.EndpointID), zap.String("returnCode", response.ReturnCode.String())) + } + } return nil }