Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cd34616
ETSI MEC gap analysis
alebellu Oct 21, 2025
8401045
feat(mec-010-2): add comprehensive implementation plan for MEC 010-2 …
alebellu Oct 21, 2025
49eabcf
Add feasibility study and implementation plan for Nuvla as MEC Orches…
alebellu Oct 21, 2025
2363ef4
MEC-003 Implementation Phase 1
alebellu Oct 21, 2025
87bc9e8
feat(mepm): add MEC Platform Manager resource and lifecycle tests
alebellu Oct 21, 2025
e42fb40
Implement Mm5 Interface and MEPM Resource Integration
alebellu Oct 21, 2025
5d8e136
feat(mec-003): add Phase 2 completion report with MEPM resource and M…
alebellu Oct 21, 2025
ad35355
feat(mm5): add integration tests and mock MEPM server for Mm5 interface
alebellu Oct 21, 2025
d0af9d3
feat(mec): add end-to-end orchestration tests for MEC MEO functionality
alebellu Oct 21, 2025
3106dbb
Add Mm5 API Reference and Quick Start Guide for MEC MEO Implementation
alebellu Oct 21, 2025
9419b69
Implement MEC 010-2 Application Lifecycle Management API
alebellu Oct 21, 2025
266cbf9
feat(mec): implement lifecycle operation handler and tests for app in…
alebellu Oct 21, 2025
eb90233
fix(mm5): update URL paths in resource queries to include mm5 prefix
alebellu Oct 21, 2025
883f848
feat(lifecycle): implement job-based operation tracking and state syn…
alebellu Oct 21, 2025
2f256b6
Add MEC 010-2 Notification Dispatcher and related tests
alebellu Oct 21, 2025
e879668
docs: update MEC 010-2 implementation progress to reflect completion …
alebellu Oct 21, 2025
a7d329e
docs: add MEC 010-2 implementation summary detailing project status, …
alebellu Oct 21, 2025
619984b
Implement MEC 010-2 Query Filters and Pagination
alebellu Oct 21, 2025
1c448a8
feat(error-handler): implement RFC 7807 ProblemDetails error handling…
alebellu Oct 21, 2025
c6e9d92
Add MEC 010-2 Application Lifecycle Management API specification
alebellu Oct 21, 2025
fd45df0
feat(tests): add integration tests for MEC 010-2 Application Lifecycl…
alebellu Oct 21, 2025
bcfe10b
feat(docs): add MEC 010-2 Standards Compliance Matrix detailing imple…
alebellu Oct 21, 2025
b5384fd
feat(docs): update MEC 010-2 implementation summary and progress to r…
alebellu Oct 21, 2025
92e6fb6
Add presentation slides for Nuvla MEC Orchestrator: Standards Complia…
alebellu Oct 23, 2025
d49300f
Refactor documentation and code references from Mm5 to Mm3 interface
alebellu Oct 24, 2025
89e659e
Implement ETSI MEC 010-2 Mm1 Application Package Management
alebellu Oct 24, 2025
b96e083
3GPP compliance study
alebellu Oct 24, 2025
4494c74
Add ETSI MEC compliance presentation and gap analysis documentation
alebellu Nov 26, 2025
3f2d031
Enhance compliance study with detailed mapping of MEC orchestrator re…
alebellu Nov 27, 2025
e31d5f1
Clarify MEC compliance document by updating relevant specifications f…
alebellu Nov 27, 2025
53d56fe
Add assessment of compliance with 3GPP
alebellu Dec 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ This repository contains the code and configuration for the Nuvla API
server, packaged as a Docker container. The API is inspired by the
CIMI specification from DMTF.

## MEC Orchestrator (MEO) Positioning

The Nuvla API Server functions as a **MEC Orchestrator (MEO)** as defined in
[ETSI GS MEC 003](https://www.etsi.org/deliver/etsi_gs/MEC/001_099/003/).
It provides system-level orchestration for edge applications across distributed
Multi-access Edge Computing (MEC) infrastructure.

**Key MEC Capabilities:**
- **System Orchestration** - Multi-host application lifecycle management
- **Application Package Management** - On-boarding, validation, and distribution
- **Resource Management** - Placement decisions and infrastructure coordination
- **Standard Interfaces** - MEC-compliant APIs (Mm2, Mm3, Mm5, Mm9)

For detailed MEC architecture mapping and implementation documentation, see:
- [MEC 003 Architectural Mapping](docs/5g-emerge/MEC-003-architectural-mapping.md)
- [MEC Terminology Guide](docs/5g-emerge/MEC-terminology-guide.md)
- [MEC Implementation Plans](docs/5g-emerge/)

## Artifacts

- `nuvla/api:<version>`. A Docker container that can be obtained from
Expand Down
1 change: 1 addition & 0 deletions code/project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
[org.testcontainers/testcontainers "1.20.4"]
[peridot "0.5.4"]
[clj-test-containers "0.7.4"]
[ring/ring-jetty-adapter "1.12.2"]
[org.clojure/test.check "1.1.1"]
[com.cemerick/url "0.1.1"]
[org.clojars.konstan/kinsky-test-jar ~kinsky-version]
Expand Down
172 changes: 172 additions & 0 deletions code/src/com/sixsq/nuvla/server/resources/mec/app_instance.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
(ns com.sixsq.nuvla.server.resources.mec.app-instance
"MEC 010-2 Application Instance Management (MEO Level)

This namespace implements ETSI GS MEC 010-2 Application Lifecycle Management
APIs at the MEO (MEC Orchestrator) level. It provides a facade over Nuvla's
existing deployment resources to expose MEC-compliant endpoints.

Scope: MEO-level orchestration only
Standard: ETSI GS MEC 010-2 v2.2.1"
(:require
[clojure.string :as str]
[clojure.tools.logging :as log]
[com.sixsq.nuvla.server.resources.deployment :as deployment]
[com.sixsq.nuvla.server.resources.module :as module]
[com.sixsq.nuvla.server.resources.nuvlabox :as nuvlabox]
[com.sixsq.nuvla.server.resources.spec.deployment :as deployment-spec]
[com.sixsq.nuvla.server.util.time :as time-utils]))


;;
;; State Mapping: Nuvla <-> MEC 010-2
;;

(def nuvla-to-mec-instantiation-state
"Maps Nuvla deployment states to MEC instantiation states"
{:CREATED :NOT_INSTANTIATED
:STARTING :INSTANTIATED
:STARTED :INSTANTIATED
:STOPPING :INSTANTIATED
:STOPPED :INSTANTIATED
:ERROR :INSTANTIATED
:PENDING :NOT_INSTANTIATED
:UNKNOWN :NOT_INSTANTIATED})


(def nuvla-to-mec-operational-state
"Maps Nuvla deployment states to MEC operational states"
{:STARTED :STARTED
:STOPPED :STOPPED
:STARTING nil
:STOPPING nil
:ERROR nil
:CREATED nil
:PENDING nil
:UNKNOWN nil})


(def mec-to-nuvla-state
"Reverse mapping for state translation"
{:NOT_INSTANTIATED :CREATED
:INSTANTIATED :STARTED})


;;
;; Schema Definitions (MEC 010-2)
;;

;; Note: Using simple predicates instead of specs for flexibility
;; MEC 010-2 data validation is done at the translation layer

(defn valid-app-instance-id? [id]
(and (string? id) (str/starts-with? id "deployment/")))

(defn valid-app-d-id? [id]
(and (string? id) (str/starts-with? id "module/")))

(defn valid-instantiation-state? [state]
(contains? #{:NOT_INSTANTIATED :INSTANTIATED} (keyword state)))

(defn valid-operational-state? [state]
(contains? #{:STARTED :STOPPED} (keyword state)))


;;
;; Translation Functions
;;

(defn deployment->app-instance-info
"Translates a Nuvla deployment resource to MEC AppInstanceInfo"
[deployment]
(let [deployment-id (:id deployment)
module-id (:module deployment)
state (keyword (:state deployment))
parent (:parent deployment)
instantiation (get nuvla-to-mec-instantiation-state state :NOT_INSTANTIATED)
operational (get nuvla-to-mec-operational-state state)]
(cond-> {:appInstanceId deployment-id
:appDId module-id
:instantiationState (name instantiation)}

;; Add appName from module if available
(:module/content deployment)
(assoc :appName (get-in deployment [:module/content :name]))

;; Add appProvider if available
(:module/author deployment)
(assoc :appProvider (:module/author deployment))

;; Add operational state if applicable
operational
(assoc :operationalState (name operational))

;; Add MEC host information if deployed
parent
(assoc :mecHostInformation {:hostId parent
:hostName parent})

;; Add HATEOAS links
true
(assoc :_links {:self {:href (str "/app_lcm/v2/app_instances/" deployment-id)}
:instantiate {:href (str "/app_lcm/v2/app_instances/" deployment-id "/instantiate")}
:terminate {:href (str "/app_lcm/v2/app_instances/" deployment-id "/terminate")}
:operate {:href (str "/app_lcm/v2/app_instances/" deployment-id "/operate")}}))))


(defn app-instance-info->deployment
"Translates MEC AppInstanceInfo to Nuvla deployment resource (partial)"
[app-instance-info]
(let [instantiation-state (keyword (:instantiationState app-instance-info))
nuvla-state (get mec-to-nuvla-state instantiation-state :CREATED)]
{:id (:appInstanceId app-instance-info)
:module (:appDId app-instance-info)
:state (name nuvla-state)
:parent (get-in app-instance-info [:mecHostInformation :hostId])}))


;;
;; Query Functions (placeholders for integration with Nuvla CRUD)
;; These will be implemented when integrated with the actual deployment resource
;;

(comment
"Integration points with Nuvla deployment resource:
- get-app-instance: Call deployment CRUD read
- list-app-instances: Call deployment CRUD query
- create-app-instance: Call deployment CRUD create
- delete-app-instance: Call deployment CRUD delete")


;;
;; Validation Functions
;;

(defn validate-app-instance-info
"Validates AppInstanceInfo against MEC 010-2 requirements"
[app-instance-info]
(when-not (:appInstanceId app-instance-info)
(throw (ex-info "appInstanceId is required" {:app-instance-info app-instance-info})))
(when-not (:appDId app-instance-info)
(throw (ex-info "appDId is required" {:app-instance-info app-instance-info})))
(when-not (:instantiationState app-instance-info)
(throw (ex-info "instantiationState is required" {:app-instance-info app-instance-info})))
(when-not (valid-instantiation-state? (:instantiationState app-instance-info))
(throw (ex-info "Invalid instantiationState" {:state (:instantiationState app-instance-info)})))
app-instance-info)


;;
;; Lifecycle Hooks
;;

(defn on-app-instance-created
"Hook called when an app instance is created"
[app-instance-info]
(log/info "MEC app instance created:" (:appInstanceId app-instance-info))
app-instance-info)


(defn on-app-instance-deleted
"Hook called when an app instance is deleted"
[app-instance-id]
(log/info "MEC app instance deleted:" app-instance-id))
171 changes: 171 additions & 0 deletions code/src/com/sixsq/nuvla/server/resources/mec/app_lcm_op_occ.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
(ns com.sixsq.nuvla.server.resources.mec.app-lcm-op-occ
"MEC 010-2 Application Lifecycle Operation Occurrence Tracking

Tracks lifecycle operations (instantiate, terminate, operate) and their status.
Maps to Nuvla's job resource with MEC-specific state tracking.

Standard: ETSI GS MEC 010-2 v2.2.1 Section 6.2.3"
(:require
[clojure.string :as str]
[clojure.tools.logging :as log]
[com.sixsq.nuvla.server.resources.job :as job]
[com.sixsq.nuvla.server.util.time :as time-utils]))


;;
;; State Mapping: Nuvla Job <-> MEC Operation
;;

(def nuvla-job-to-mec-operation-state
"Maps Nuvla job states to MEC operation states"
{:QUEUED :STARTING
:RUNNING :PROCESSING
:SUCCESS :COMPLETED
:FAILED :FAILED
:STOPPING :PROCESSING
:STOPPED :FAILED_TEMP
:CANCELED :ROLLED_BACK})


(def mec-to-nuvla-job-state
"Reverse mapping for state translation"
{:STARTING :QUEUED
:PROCESSING :RUNNING
:COMPLETED :SUCCESS
:FAILED :FAILED
:FAILED_TEMP :STOPPED
:ROLLED_BACK :CANCELED})


;;
;; Schema Definitions (using predicates for flexibility)
;;

(defn valid-lcm-op-occ-id? [id]
(and (string? id) (str/starts-with? id "job/")))

(defn valid-operation-type? [op-type]
(contains? #{:INSTANTIATE :TERMINATE :OPERATE} (keyword op-type)))

(defn valid-operation-state? [state]
(contains? #{:STARTING :PROCESSING :COMPLETED :FAILED :FAILED_TEMP :ROLLED_BACK} (keyword state)))


;;
;; Translation Functions
;;

(defn job->app-lcm-op-occ
"Translates a Nuvla job to MEC AppLcmOpOcc"
[job]
(let [job-id (:id job)
job-state (keyword (:state job))
operation-type (keyword (or (:operation-type job) "INSTANTIATE"))
mec-state (get nuvla-job-to-mec-operation-state job-state :STARTING)
target-id (:target-resource job)]
(cond-> {:lcmOpOccId job-id
:operationType (name operation-type)
:operationState (name mec-state)
:stateEnteredTime (or (:state-entered-time job)
(:updated job)
(time-utils/now-str))
:startTime (or (:start-time job)
(:created job)
(time-utils/now-str))
:appInstanceId target-id}

;; Add error information if job failed
(#{:FAILED :STOPPED} job-state)
(assoc :error {:type "about:blank"
:title "Operation Failed"
:status 500
:detail (or (:status-message job) "Operation failed")
:instance job-id})

;; Add HATEOAS links
true
(assoc :_links {:self {:href (str "/app_lcm/v2/app_lcm_op_occs/" job-id)}
:appInstance {:href (str "/app_lcm/v2/app_instances/" target-id)}}))))


(defn app-lcm-op-occ->job
"Translates MEC AppLcmOpOcc to Nuvla job (partial)"
[app-lcm-op-occ]
(let [operation-state (keyword (:operationState app-lcm-op-occ))
nuvla-state (get mec-to-nuvla-job-state operation-state :QUEUED)]
{:id (:lcmOpOccId app-lcm-op-occ)
:state (name nuvla-state)
:operation-type (:operationType app-lcm-op-occ)
:target-resource (:appInstanceId app-lcm-op-occ)
:start-time (:startTime app-lcm-op-occ)
:state-entered-time (:stateEnteredTime app-lcm-op-occ)}))


;;
;; Query Functions (placeholders for integration with Nuvla CRUD)
;; These will be implemented when integrated with the actual job resource
;;

(comment
"Integration points with Nuvla job resource:
- get-app-lcm-op-occ: Call job CRUD read
- list-app-lcm-op-occs: Call job CRUD query with filters
- create-app-lcm-op-occ: Call job CRUD create
- update-operation-state: Call job CRUD update")


;;
;; Operation State Transitions (placeholders)
;;

(comment
"State transition functions to be implemented when integrated with job resource:
- update-operation-state: Updates job state
- complete-operation: Marks job as SUCCESS
- fail-operation: Marks job as FAILED")


;;
;; Validation
;;

(defn validate-app-lcm-op-occ
"Validates AppLcmOpOcc against MEC 010-2 requirements"
[app-lcm-op-occ]
(when-not (:lcmOpOccId app-lcm-op-occ)
(throw (ex-info "lcmOpOccId is required" {:app-lcm-op-occ app-lcm-op-occ})))
(when-not (:operationType app-lcm-op-occ)
(throw (ex-info "operationType is required" {:app-lcm-op-occ app-lcm-op-occ})))
(when-not (:operationState app-lcm-op-occ)
(throw (ex-info "operationState is required" {:app-lcm-op-occ app-lcm-op-occ})))
(when-not (valid-operation-type? (:operationType app-lcm-op-occ))
(throw (ex-info "Invalid operationType" {:type (:operationType app-lcm-op-occ)})))
(when-not (valid-operation-state? (:operationState app-lcm-op-occ))
(throw (ex-info "Invalid operationState" {:state (:operationState app-lcm-op-occ)})))
app-lcm-op-occ)


;;
;; Lifecycle Hooks
;;

(defn on-operation-started
"Hook called when an operation starts"
[app-lcm-op-occ]
(log/info "MEC operation started:"
(:operationType app-lcm-op-occ)
"for app instance"
(:appInstanceId app-lcm-op-occ))
app-lcm-op-occ)


(defn on-operation-completed
"Hook called when an operation completes"
[lcm-op-occ-id]
(log/info "MEC operation completed:" lcm-op-occ-id))


(defn on-operation-failed
"Hook called when an operation fails"
[lcm-op-occ-id error-detail]
(log/error "MEC operation failed:" lcm-op-occ-id error-detail))
Loading
Loading