...

Source file src/edge-infra.dev/pkg/edge/device-registrar/services/application_delete_service.go

Documentation: edge-infra.dev/pkg/edge/device-registrar/services

     1  package services
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  
     7  	"github.com/gin-gonic/gin"
     8  	"k8s.io/apimachinery/pkg/api/errors"
     9  	"sigs.k8s.io/controller-runtime/pkg/client"
    10  
    11  	api "edge-infra.dev/pkg/edge/device-registrar/api/v1alpha1"
    12  	config "edge-infra.dev/pkg/edge/device-registrar/config"
    13  )
    14  
    15  // swagger:operation DELETE /applications/{appID} additional deleteApplication
    16  // ---
    17  // summary: Delete an external application.
    18  // description: Deletes an external application and removes it from all device bindings.
    19  // parameters:
    20  //   - name: appID
    21  //     in: path
    22  //     description: ID of the external application to delete.
    23  //     required: true
    24  //     schema:
    25  //     type: string
    26  //
    27  // responses:
    28  //
    29  //		204:
    30  //	  		description: Application deleted successfully
    31  //		404:
    32  //	  		description: Application not found
    33  //		500:
    34  //	  		description: Internal server error
    35  func DeleteApplication(c *gin.Context) {
    36  	appID := c.Param("appID")
    37  	if appID == "" {
    38  		c.JSON(http.StatusBadRequest, gin.H{"error": "external application name is required"})
    39  		return
    40  	}
    41  
    42  	k8sClient, ctx, cancel := config.GetClientandContext(c)
    43  	defer cancel()
    44  
    45  	// get external application
    46  	extapp, err := getExternalApplicationByID(ctx, c, k8sClient, appID)
    47  	if err != nil {
    48  		if errors.IsNotFound(err) {
    49  			c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
    50  			return
    51  		}
    52  
    53  		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
    54  		return
    55  	}
    56  
    57  	// go through device bindings and remove the external application from it's spec.applications
    58  	err = removeApplicationFromDeviceBindings(ctx, k8sClient, extapp.Spec.ID)
    59  	if err != nil {
    60  		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
    61  		return
    62  	}
    63  
    64  	// now we can delete the external application
    65  	err = k8sClient.Delete(ctx, extapp)
    66  	if err != nil {
    67  		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
    68  		return
    69  	}
    70  
    71  	c.JSON(http.StatusNoContent, gin.H{})
    72  }
    73  
    74  // GetDeviceBindingsForApplication retrieves all device bindings associated with an application,
    75  // then updates or deletes those who have the external application.
    76  func removeApplicationFromDeviceBindings(ctx context.Context, k8sClient client.Client, appID string) error {
    77  	// retrieve all device bindings
    78  	deviceBindingList := &api.DeviceBindingList{}
    79  	err := k8sClient.List(ctx, deviceBindingList)
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	// go through each device binding and remove the application from it's spec.applications
    85  	for i := range deviceBindingList.Items {
    86  		device := deviceBindingList.Items[i] // Create a copy to avoid memory aliasing
    87  		// see if the application is in the device binding's applications
    88  		for _, extApp := range device.Spec.Applications {
    89  			if extApp.ID == appID {
    90  				//found
    91  				err = updateOrDeleteDeviceBinding(ctx, k8sClient, device, appID)
    92  				if err != nil {
    93  					return err
    94  				}
    95  			}
    96  		}
    97  	}
    98  	return nil
    99  }
   100  
   101  // updateOrDeleteDeviceBinding updates or deletes a device binding based on the number of applications it has.
   102  func updateOrDeleteDeviceBinding(ctx context.Context, k8sClient client.Client, device api.DeviceBinding, appID string) error {
   103  	// if length of device.Spec.Applications is 1, then remove the device binding
   104  	if len(device.Spec.Applications) == 1 {
   105  		err := k8sClient.Delete(ctx, &device)
   106  		if err != nil {
   107  			return err
   108  		}
   109  		return nil
   110  	}
   111  
   112  	// otherwise, update the device binding to remove it
   113  	device.Spec.Applications = removeApplication(device.Spec.Applications, appID)
   114  	err := k8sClient.Update(ctx, &device)
   115  	if err != nil {
   116  		return err
   117  	}
   118  	return nil
   119  }
   120  
   121  // removeApplication removes an application from a list of applications
   122  func removeApplication(apps []api.ApplicationSubject, appID string) []api.ApplicationSubject {
   123  	var newApps []api.ApplicationSubject
   124  	for _, app := range apps {
   125  		if app.ID != appID {
   126  			newApps = append(newApps, app)
   127  		}
   128  	}
   129  	return newApps
   130  }
   131  

View as plain text