Commit 84493528 authored by Mudassar Khan's avatar Mudassar Khan
Browse files

fix(meep-ipe): resolve same name subscription issue and handle oneM2M RSC codes

- Use X-M2M-RSC for resource creation; treat 2001/4105/4117 as success
- Name node/subscription after AE-ID to avoid conflicts between IPEs
- Require MEEP_AE_ID for standalone IPE
parent 3728c704
Loading
Loading
Loading
Loading
+3 −1
Changes for go-apps/meep-ipe/MEC/init.go: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -446,6 +446,7 @@ func InitMEC(cfg map[string]interface{}) {
	// Step # 7: Create a Node on the oneM2M platform to represent the MEC IPE service
	// nodeName := "mec_ipe_node"
	nodeID := uuid.NewString()
	
	err = onem2m.CreateNode(onem2m.NodeName(), nodeID)
	if err != nil {
		log.Printf("Failed to create a Node on the oneM2M platform: %v", err)
@@ -496,7 +497,8 @@ func InitMEC(cfg map[string]interface{}) {
	// -> Create a flex container for each service and publish it onto the CSE
	url = fmt.Sprintf("%s:%s/~/%s/%s", config["CSE-URL"], config["CSE-PORT"], config["CSE-ID"], config["CSE-NAME"])
	for _, service := range responseData {
		containerName := fmt.Sprintf("%s-%s", service.SerName, config["sandboxName"])
		// Containers live under this IPE's node, so the service name alone is unique
		containerName := service.SerName
		// Sent Get request to service endpoint
		fullUrl, err := fetchAndAppendHref(fmt.Sprintf("%suser-api/", service.TransportInfo.Endpoint.Uris[0]))
		if err != nil {
+7 −3
Changes for go-apps/meep-ipe/MEC/mec_iot_pltf_notification.go: 7 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import (
	"io"
	"log"
	"net/http"
	"strconv"

	oneM2M "meep-ipe/oneM2M"
	// utils "meep-ipe/utils"
@@ -21,7 +22,10 @@ func MecIotPltfNotificationHandler(w http.ResponseWriter, r *http.Request) {
	}
	log.Printf("Request Body: %s", string(body))

	statusCode, respBody, err := oneM2M.CreateAE(body)
	rsc, statusCode, respBody, err := oneM2M.CreateAE(body)
	if rsc != 0 {
		w.Header().Set("X-M2M-RSC", strconv.Itoa(rsc))
	}
	if err != nil {
		log.Printf("Error creating AE: %v", err)
		// Still relay whatever the CSE said, if we have anything
@@ -34,9 +38,9 @@ func MecIotPltfNotificationHandler(w http.ResponseWriter, r *http.Request) {
		return
	}

	log.Printf("Response from oneM2M: status %d, body: %s", statusCode, string(respBody))
	log.Printf("Response from oneM2M: RSC %d, body: %s", rsc, string(respBody))

	// Relay the CSE's actual status code and body back to the sandbox
	// Relay the CSE's RSC, status code and body back to the sandbox
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	w.Write(respBody)
+7 −0
Changes for go-apps/meep-ipe/config.env: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -80,9 +80,16 @@ MEEP_CSE_NAME=laboai-cse-in
# (or "S") per oneM2M originator rules. MEEP_LOCATION_NAME and
# MEEP_SANDBOX_NAME are appended automatically, e.g.
#   CMecIPE -> CMecIPE-mep1-sbxoon0fww
# Allowed characters: A-Z a-z 0-9 _ -
# Default if empty: "CMecIPE"
MEEP_AE_ID=CMecIPE

# Set to "true" to append MEEP_LOCATION_NAME and MEEP_SANDBOX_NAME to
# MEEP_CSE_ID and MEEP_CSE_NAME, matching meep-acme-mn-cse naming, e.g.
#   acme-mep-id-mn-cse -> acme-mep-id-mn-cse-mep1-sbxoon0fww
# Empty parts are skipped. Default if empty: false (IDs used as-is).
MEEP_INITIATED_MN_CSE=false

# HTTP Basic auth credentials for the CSE. Leave both empty if the CSE has
# no authorization enabled (no Authorization header is sent).
MEEP_CSE_USER=
+10 −0
Changes for go-apps/meep-ipe/entrypoint.sh: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -117,6 +117,16 @@ if [ -z "${MEEP_AE_ID}" ]; then
else
    AE_ID="${MEEP_AE_ID}"
fi
if [[ ! "${AE_ID}" =~ ^[A-Za-z0-9_-]+$ ]]; then
    echo "$0: MEEP_AE_ID '${AE_ID}' is invalid, only [A-Za-z0-9_-] is allowed"
    exit 1
fi
# A standalone (outside sandbox) IPE must set its own base AE-ID; falling back to
# the default would share node/subscription names with the in-sandbox IPE on the same CSE.
if [ "${MEEP_STANDALONE}" == "true" ] && [ -z "${MEEP_AE_ID}" ]; then
    echo "$0: MEEP_STANDALONE=true requires MEEP_AE_ID to be set"
    exit 1
fi
if [ -n "${MECPLATFORM}" ]; then
    AE_ID="${AE_ID}-${MECPLATFORM}"
fi
+19 −13
Changes for go-apps/meep-ipe/oneM2M/createAE.go: 19 added lines, 13 removed lines.
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ import (
	"fmt"
	"io"
	"log"
	"net/http"

	"meep-ipe/utils"
)
@@ -49,15 +48,17 @@ type outgoingAE struct {

// CreateAE creates an Application Entity (AE) on the oneM2M platform,
// using rn/api extracted from the incoming notification body.
func CreateAE(body []byte) (int, []byte, error) {
// It returns the oneM2M Response Status Code (X-M2M-RSC), the CSE's HTTP status
// and the CSE response body. RSC 2001, 4105 and 4117 are treated as success.
func CreateAE(body []byte) (int, int, []byte, error) {
	log.Println("Creating Application Entity (AE)...")

	var incoming incomingAE
	if err := json.Unmarshal(body, &incoming); err != nil {
		return 0, nil, fmt.Errorf("failed to parse incoming AE body: %w", err)
		return 0, 0, nil, fmt.Errorf("failed to parse incoming AE body: %w", err)
	}
	if incoming.M2MAE.RN == "" || incoming.M2MAE.API == "" {
		return 0, nil, fmt.Errorf("incoming body missing rn/api: %s", string(body))
		return 0, 0, nil, fmt.Errorf("incoming body missing rn/api: %s", string(body))
	}

	var outgoing outgoingAE
@@ -71,7 +72,7 @@ func CreateAE(body []byte) (int, []byte, error) {
	log.Printf("Config[MEC App name]: %+v", config["mecAppName"])
	reqBodyBytes, err := json.Marshal(outgoing)
	if err != nil {
		return 0, nil, fmt.Errorf("failed to build outgoing AE body: %w", err)
		return 0, 0, nil, fmt.Errorf("failed to build outgoing AE body: %w", err)
	}
	reqBody := string(reqBodyBytes)

@@ -82,20 +83,25 @@ func CreateAE(body []byte) (int, []byte, error) {

	resp, err := utils.MakeOneM2MRequest("POST", url, reqBody, 2, config["AE-ID"].(string))
	if err != nil {
		return 0, nil, err
		return 0, 0, nil, err
	}
	defer resp.Body.Close()

	respBody, _ := io.ReadAll(resp.Body)
	log.Printf("Response from CSE: status %d, body: %s", resp.StatusCode, string(respBody))
	rsc, err := responseRSC(resp)
	if err != nil {
		return 0, resp.StatusCode, respBody, fmt.Errorf("failed to create AE: %v, body: %s", err, string(respBody))
	}
	log.Printf("Response from CSE: RSC %d, body: %s", rsc, string(respBody))

	if resp.StatusCode == http.StatusCreated {
	if isCreateSuccess(rsc) {
		if rsc == RscCreated {
			log.Println("✓ Application Entity (AE) created successfully")
		return resp.StatusCode, respBody, nil
	} else if resp.StatusCode == http.StatusConflict || resp.StatusCode == http.StatusForbidden {
		log.Println("⚠ AE already exists")
		return 0, nil, fmt.Errorf("AE already exists")
		} else {
			log.Printf("⚠ AE already exists (RSC %d)", rsc)
		}
		return rsc, resp.StatusCode, respBody, nil
	}

	return 0, nil, fmt.Errorf("failed to create AE: status %d, body: %s", resp.StatusCode, string(respBody))
	return rsc, resp.StatusCode, respBody, fmt.Errorf("failed to create AE: RSC %d, body: %s", rsc, string(respBody))
}
Loading