package services import ( "context" "net/http" "strings" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/gin-gonic/gin" "edge-infra.dev/pkg/edge/device-registrar/config" api "edge-infra.dev/pkg/edge/device-registrar/api/v1alpha1" ) // DiscoverServiceResponse contains the name and discovery URL of the workload // swagger:model DiscoverServiceResponse type DiscoverServiceResponse struct { // example: jarvis Name string `json:"name"` // example: https://jarvis.store.ncr.corp/config URL *string `json:"url"` } // DiscoverInput contains the name of the workload // swagger:model DiscoverInput type DiscoverInput struct { Name string `uri:"serviceName" binding:"required"` } // swagger:route GET /discover/{serviceName} additional discover // Discovers an endpoint // // Returns the name and discovery URL of the workload // parameters: // - name: X-Client-DN // in: header // type: string // required: true // description: the header is formatted as: `OU=urn:storeID:[STORE-ID]+OU=urn:deviceName:[DEVICE-NAME]+OU=urn:SN:[SERIAL-NUMBER]` // // responses: // // 200: DiscoverServiceResponse Success // 500: description:Internal Server Error func DiscoverService(c *gin.Context) { k8sClient, ctx, cancel := config.GetClientandContext(c) defer cancel() // check header exists clientDN := c.GetHeader("X-Client-DN") if clientDN == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "X-Client-DN is required"}) return } // Parse the DN to extract the SN serialNumber := parseSerialNumber(clientDN) if serialNumber == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Serial Number is required in X-Client-DN"}) return } // Verify the SN against devices if !isSNAuthorized(ctx, k8sClient, serialNumber) { c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized Serial Number"}) return } var serviceName DiscoverInput if err := c.ShouldBindUri(&serviceName); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "serviceName is required"}) return } discoveryList := &api.DiscoveryList{} err := k8sClient.List(ctx, discoveryList) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } configURL := "" for i := range discoveryList.Items { service := discoveryList.Items[i] if service.Spec.Name == serviceName.Name { configURL = service.Spec.URL break } } resp := DiscoverServiceResponse{ Name: serviceName.Name, URL: &configURL, } if configURL == "" { resp.URL = nil } c.JSON(http.StatusOK, resp) } // OU=urn:storeID:my-store-id+OU=urn:deviceName:test-device-name+OU=urn:SN:a1b2c3d4 func parseSerialNumber(dn string) string { parts := strings.Split(dn, "+") for _, part := range parts { if strings.HasPrefix(part, "OU=urn:SN:") { return strings.TrimSpace(strings.TrimPrefix(part, "OU=urn:SN:")) } } return "" } // compares the serial number against the list of devices serial numbers func isSNAuthorized(ctx context.Context, k8sClient client.Client, sn string) bool { // get list of devices deviceList := &api.ExternalDeviceList{} err := k8sClient.List(ctx, deviceList) if err != nil { return false } // no serial numbers, return early if len(deviceList.Items) == 0 { return false } // check if SN is in the list of devices' serial numbers for _, device := range deviceList.Items { if sn == device.Spec.SN { return true } } return false }