Commit f4620e62 authored by Simon Pastor's avatar Simon Pastor
Browse files

1st merge

parent 97ac5d5e
Loading
Loading
Loading
Loading
+299 −0
Original line number Diff line number Diff line
swagger: '2.0'
info:
  title: AdvantEDGE Application Information API
  version: 1.0.0
  description: AdvantEDGE implementation to create an Application Instance information using OpenAPI. Developed as an extension to Application Enablement API.
  license:
    name: Apache 2.0
    url: 'https://github.com/InterDigitalInc/AdvantEDGE/blob/master/LICENSE'
  contact:
    name: InterDigital AdvantEDGE Support
    email: AdvantEDGE@InterDigital.com
basePath: "/sandboxname/app_info/v1"
externalDocs:
  description: GitHub Wiki
  url: 'https://github.com/InterDigitalInc/AdvantEDGE/wiki'
tags:
  - name: apps
consumes:
  - application/json
produces:
  - application/json
parameters:
  Path.AppInstanceId:
    name: appInstanceId
    description: >-
      Represents a MEC application instance. Note that the
      appInstanceId is allocated by the MEC application manager POST method.
    in: path
    required: true
    type: string
  Query.App_name:
    name: app_name
    description: >-
      A MEC application manager may use app_name as an input
      parameter to query the existence of a list of MEC application
      instances with the same name.
    in: query
    required: false
    type: string
  Query.App_state:
    name: app_state
    description: >-
      A MEC application manager may use app_state as an input
      parameter to query the state of a list of MEC application
      instances with the same state.
    in: query
    required: false
    type: string
  Body.ApplicationInfo:
    name: applicationInfo
    in: body
    description: Application information
    required: true
    schema:
      $ref: '#/definitions/ApplicationInfo'  
paths:
  '/applications':
    get:
      description: This method retrieves information about a list of mec application resources.
      operationId: Applications_GET
      tags:
        - apps
      parameters:
        - $ref: '#/parameters/Query.App_name'
        - $ref: '#/parameters/Query.App_state'
      responses:
        '200':
          $ref: '#/responses/Applications.200'
        '400':
          $ref: '#/responses/Error.400'
        '403':
          $ref: '#/responses/Error.403'
        '404':
          $ref: '#/responses/Error.404'
        '414':
          $ref: '#/responses/Error.414'
    post:
      description: This method is used to create a mec application resource.
      operationId: Applications_POST
      tags:
        - apps
      responses:
        '201':
          $ref: '#/responses/Application.201'
        '400':
          $ref: '#/responses/Error.400'
        '403':
          $ref: '#/responses/Error.403'
        '404':
          $ref: '#/responses/Error.404'
      parameters:
        - $ref: '#/parameters/Body.ApplicationInfo'
  '/applications/{appInstanceId}':
    parameters:
      - $ref: '#/parameters/Path.AppInstanceId'
    get:
      description: This method retrieves information about a mec application resource.
      operationId: ApplicationsAppInstanceId_GET
      tags:
        - apps
      responses:
        '200':
          $ref: '#/responses/ApplicationAppInstanceId.200'
        '400':
          $ref: '#/responses/Error.400'
        '403':
          $ref: '#/responses/Error.403'
        '404':
          $ref: '#/responses/Error.404'
    put:
      description: This method updates the information about a mec application resource.
      operationId: ApplicationsAppInstanceId_PUT
      tags:
        - apps
      responses:
        '200':
          $ref: '#/responses/ApplicationAppInstanceId.200'
        '400':
          $ref: '#/responses/Error.400'
        '403':
          $ref: '#/responses/Error.403'
        '404':
          $ref: '#/responses/Error.404'
        '412':
          $ref: '#/responses/Error.412'
      parameters:
        - $ref: '#/parameters/Body.ApplicationInfo'
    delete:
      description: This method deletes a mec application resource.
      operationId: ApplicationsAppInstanceId_DELETE
      tags:
        - apps
      responses:
        '204':
          description: No Content
        '403':
          $ref: '#/responses/Error.403'
        '404':
          $ref: '#/responses/Error.404'
definitions:
  ProblemDetails:
    type: object
    properties:
      type:
        $ref: '#/definitions/Problem.type'
      title:
        $ref: '#/definitions/Problem.title'
      status:
        $ref: '#/definitions/Problem.status'
      detail:
        $ref: '#/definitions/Problem.detail'
      instance:
        $ref: '#/definitions/Problem.instance'
  Problem.detail:
    type: string
    description: A human-readable explanation specific to this occurrence of the problem
  Problem.instance:
    type: string
    format: uri
    description: A URI reference that identifies the specific occurrence of the problem
  Problem.status:
    type: integer
    format: uint32
    description: The HTTP status code for this occurrence of the problem
  Problem.title:
    type: string
    description: 'A short, human-readable summary of the problem type'
  Problem.type:
    type: string
    format: uri
    description: >-
      A URI reference according to IETF RFC 3986 that identifies the problem
      type
  LocalityType:
    description: The scope of locality as expressed by "consumedLocalOnly" and "isLocal". If absent, defaults to MEC_HOST
    type: string
    enum:
      - MEC_SYSTEM
      - MEC_HOST
      - NFVI_POP
      - ZONE
      - ZONE_GROUP
      - NFVI_NODE
    example: 'MEC_SYSTEM'
  ApplicationState:
    description: This enumeration defines the possible states of an application.
    type: string
    enum:
      - ACTIVE
      - INACTIVE
    example: 'ACTIVE'
  ApplicationInfo:
    description: This type represents the general information of a MEC application.
    type: object
    required:
      - appInstanceId
      - state
    properties:
      appInstanceId:
        description: Application Instance Id
        type: string
      appName:
        description: Application Name
        type: string
      appLocality:
        description: Application Locality
        type: string
      mepName:
        description: Mep Name on which the application is running
        type: string
      version:
        description: Application Version
        type: string
      state:
        $ref: '#/definitions/ApplicationState'
    example:
      appInstanceId: 'ApplicationInstance123'
      appName: 'MyAppName'
      version: 'ApplicationVersion1'
      state: 'ACTIVE'        
responses:
  Applications.200:
    description: >-
      It is used to indicate nonspecific success. The response body
      contains a representation of the resource.
    schema:
      type: array
      minItems: 0
      items:
        $ref: '#/definitions/ApplicationInfo'
  Application.201:
    description: >-
      Upon success, the HTTP response shall include a Location HTTP header
      that contains the resource URI of the created resource.
    headers:
      location:
        description: The resource URI of the created resource
        type: string
        format: uri
    schema:
      $ref: '#/definitions/ApplicationInfo'
  ApplicationAppInstanceId.200:
    description: >-
      It is used to indicate nonspecific success. The response body
      contains a representation of the resource.
    schema:
      $ref: '#/definitions/ApplicationInfo'
  Error.400:
    description: >-
      Bad Request.
      It is used to indicate that incorrect parameters were passed to the request.
    schema:
      $ref: '#/definitions/ProblemDetails'
  Error.401:
    description: >-
      Unauthorized.
      It is used when the client did not submit the appropriate credentials.
    schema:
      $ref: '#/definitions/ProblemDetails'
  Error.403:
    description: >-
      Forbidden.
      The operation is not allowed given the current status of the resource.
    schema:
      $ref: '#/definitions/ProblemDetails'
  Error.404:
    description: >-
      Not Found.
      It is used when a client provided a URI that cannot be mapped
      to a valid resource URI.
    schema:
      $ref: '#/definitions/ProblemDetails'
  Error.409:
    description: >-
      Conflict.
      The operation cannot be executed currently, due to a conflict with
      the state of the resource. Typically, this is because the application
      instance resource is in NOT_INSTANTIATED state.
    schema:
      $ref: '#/definitions/ProblemDetails'
  Error.412:
    description: >-
      Precondition Failed.
      It is used when a condition has failed during conditional requests,
      e.g. when using ETags to avoid write conflicts.
    schema:
      $ref: '#/definitions/ProblemDetails'
  Error.414:
    description: >-
      It is used to indicate that the server is refusing to process the request because the request URI is longer than the server is willing or able to process.
    schema:
      $ref: '#/definitions/ProblemDetails'
  Error.429:
    description: >-
      Too Many Requests.
      It is used when a rate limiter has triggered.
    schema:
      $ref: '#/definitions/ProblemDetails'
+96 −0
Original line number Diff line number Diff line
@@ -1652,6 +1652,33 @@ paths:
        '429':
          $ref: '#/components/responses/429'
      x-swagger-router-controller: 'subscriptions'
  /notifications/mec011/appTermination:
    post:
      tags:
      - 'location'
      summary: 'MEC011 Application Termination notification for self termination'
      description: 'Terminates itself.'
      operationId: mec011AppTerminationPOST
      requestBody:
        description: 'Termination notification details'
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AppTerminationNotification'
            example:
                notificationType: 'AppTerminationNotification'
                operationAction: 'TERMINATING'
                maxGracefulTimeout: 10
                links:
                  subscription:
                    href: 'http://mec011Server.example.com/mec_app_support/v1/applications/appId1234/subscriptions/sub123'
                  confirmTermination:
                    href: 'http://mec011Server.example.com/mec_app_support/v1/confirm_termination' 
      responses:
        '204':
          description: No Content
      x-swagger-router-controller: 'notifications'
components:
  responses:
    200:
@@ -2988,3 +3015,72 @@ components:
      properties:
        problemDetails:
          $ref: '#/components/schemas/ProblemDetails'
    AppTerminationNotification.Links:
      description: >-
        Object containing hyperlinks related to the resource.
      type: object
      required:
        - subscription
      properties:
        subscription:
          $ref: '#/components/schemas/LinkType'
        confirmTermination:
          $ref: '#/components/schemas/LinkType.ConfirmTermination'
    AppTerminationNotification.MaxGracefulTimeout:
      description: >-
        Maximum timeout value in seconds for graceful termination or graceful
        stop of an application instance.
      type: integer
      format: uint32
      example: 10
    AppTerminationNotification.NotificationType:
      description: Shall be set to AppTerminationNotification.
      type: string
      example: 'AppTerminationNotification'
    AppTerminationNotification:
      description: >-
        This type represents the information that the MEC platform
        notifies the subscribed application instance about  the corresponding
        application instance termination/stop.
      type: object
      required:
        - notificationType
        - operationAction
        - maxGracefulTimeout
        - _links
      properties:
        notificationType:
          $ref: '#/components/schemas/AppTerminationNotification.NotificationType'
        operationAction:
          $ref: '#/components/schemas/OperationActionType'
        maxGracefulTimeout:
          $ref: '#/components/schemas/AppTerminationNotification.MaxGracefulTimeout'
        _links:
          $ref: '#/components/schemas/AppTerminationNotification.Links'
    LinkType:
      description: This type represents a type of link and may be referenced from data structures
      type: object
      properties:
        href:
          $ref: '#/components/schemas/Href'
    LinkType.ConfirmTermination:
      description: >-
        Link to the task resource where to confirm termination in case the
        application is ready to be terminated before expiry of the timeout.
      type: object
      properties:
        href:
          $ref: '#/components/schemas/Href'
    Href:
      description: URI referring to a resource
      type: string
      format: uri
      example: '/mecAppSuptApi/example'
    OperationActionType:
      description: Operation that is being performed on the MEC application instance.
      type: string
      enum:
        - STOPPING
        - TERMINATING
      example: 'TERMINATING'
+2 −0
Original line number Diff line number Diff line
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-sandbox-ctrl-client v0.0.0-20210505162607-cc887b7a0c0a h1:2aY//J49Jo+U//MDa9kr/lC2KmKm6hLH/mKkT9tEKh0=
github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-sandbox-ctrl-client v0.0.0-20210505162607-cc887b7a0c0a/go.mod h1:RlTJLiOIOlQ1IRl/un3Ut1tch5NqxNdIaV4HMuFOdr0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/RyanCarrier/dijkstra v0.0.0-20190726134004-b51cadb5ae52 h1:trnwuu/Q8T59kgRjXcSDBODnyZP9wes+bnLn0lx4PgM=
github.com/RyanCarrier/dijkstra v0.0.0-20190726134004-b51cadb5ae52/go.mod h1:DdR6ymcLl8+sN/XOVNjnYO1NDYfgHskGjreZUDuQCTY=
+5 −0
Original line number Diff line number Diff line
@@ -79,6 +79,10 @@ func DistanceSubPUT(w http.ResponseWriter, r *http.Request) {
	distanceSubPut(w, r)
}

func Mec011AppTerminationPOST(w http.ResponseWriter, r *http.Request) {
        mec011AppTerminationPost(w, r)
}

func PeriodicSubDELETE(w http.ResponseWriter, r *http.Request) {
	periodicSubDelete(w, r)
}
@@ -170,3 +174,4 @@ func ZonesGET(w http.ResponseWriter, r *http.Request) {
func ZonesGetById(w http.ResponseWriter, r *http.Request) {
	zonesByIdGet(w, r)
}
+141 −43
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@ const serviceName = "Location Service"
const defaultMepName = "global"
const defaultScopeOfLocality = "MEC_SYSTEM"
const defaultConsumedLocalOnly = true
const appTerminationPath = "notifications/mec011/appTermination"

const sboxCtrlBasepath = "http://meep-sandbox-ctrl/sandbox-ctrl/v1"

const typeZone = "zone"
const typeAccessPoint = "accessPoint"
@@ -169,12 +172,15 @@ var serviceAppInstanceId string
var appEnablementUrl string
var appEnablementEnabled bool
var sendAppTerminationWhenDone bool = false
var appEnablementServiceId string
var appSupportClient *asc.APIClient
var svcMgmtClient *smc.APIClient
var sbxCtrlClient *scc.APIClient

var registrationTicker *time.Ticker

var sandboxCtrlClient *scc.APIClient

// Init - Location Service initialization
func Init() (err error) {

@@ -335,6 +341,14 @@ func Init() (err error) {
		if svcMgmtClient == nil {
			return errors.New("Failed to create App Enablement Service Management REST API client")
		}

		// Create Sandbox Ctrl client
		sandboxCtrlClientCfg := scc.NewConfiguration()
		sandboxCtrlClientCfg.BasePath = sboxCtrlBasepath
		sandboxCtrlClient = scc.NewAPIClient(sandboxCtrlClientCfg)
		if sandboxCtrlClient == nil {
			return errors.New("Failed to create Sandbox Ctrl REST API client")
		}
	}

	log.Info("Location Service successfully initialized")
@@ -366,12 +380,6 @@ func Stop() (err error) {
	// Stop MEC Service registration ticker
	if appEnablementEnabled {
		stopRegistrationTicker()
		if sendAppTerminationWhenDone {
			err = sendTerminationConfirmation(serviceAppInstanceId)
			if err != nil {
				return err
			}
		}
	}

	periodicTicker.Stop()
@@ -399,7 +407,9 @@ func startRegistrationTicker() {
	registrationTicker = time.NewTicker(5 * time.Second)
	go func() {
		mecAppReadySent := false
		// registrationSent := false
		registrationSent := false
		subscriptionSent := false

		for range registrationTicker.C {
			// Get Application instance ID if not already available
			if serviceAppInstanceId == "" {
@@ -421,31 +431,34 @@ func startRegistrationTicker() {
			}

			// Register service instance
			// if !registrationSent {
			err := registerService(serviceAppInstanceId)
			if !registrationSent {
				err := registerService(serviceAppInstanceId, serviceAppName, serviceAppVersion)
				if err != nil {
					log.Error("Failed to register to appEnablement DB, keep trying. Error: ", err)
					continue
				}
			// 	registrationSent = true
			// }
				registrationSent = true
			}

			// // Register for graceful termination
			// if !subscriptionSent {
			// 	err = subscribeAppTermination(serviceAppInstanceId)
			// 	if err != nil {
			// 		log.Error("Failed to subscribe to graceful termination. Error: ", err)
			// 		continue
			// 	}
			// 	sendAppTerminationWhenDone = true
			// 	subscriptionSent = true
			// }
			// Register for graceful termination
			if !subscriptionSent {
				err := subscribeAppTermination(serviceAppInstanceId)
				if err != nil {
					log.Error("Failed to subscribe to graceful termination. Error: ", err)
					continue
				}
				sendAppTerminationWhenDone = true
				subscriptionSent = true
			}

			if mecAppReadySent && registrationSent && subscriptionSent {

				// Registration complete
				log.Info("Successfully registered with App Enablement Service")
				stopRegistrationTicker()
				return
			}
		}
	}()
}

@@ -475,7 +488,16 @@ func getAppInstanceId() (id string, err error) {
	return response.Id, nil
}

func registerService(appInstanceId string) error {
func deregisterService(appInstanceId string, serviceId string) error {
	_, err := appEnablementSrvMgmtClient.AppServicesApi.AppServicesServiceIdDELETE(context.TODO(), appInstanceId, serviceId)
	if err != nil {
		log.Error("Failed to unregister the service to app enablement registry: ", err)
		return err
	}
	return nil
}

func registerService(appInstanceId string, appName string, appVersion string) error {
	var srvInfo smc.ServiceInfoPost
	//serName
	srvInfo.SerName = instanceName
@@ -523,6 +545,7 @@ func registerService(appInstanceId string) error {
		return err
	}
	log.Info("Application Enablement Service instance Id: ", appServicesPostResponse.SerInstanceId)
	appEnablementServiceId = appServicesPostResponse.SerInstanceId
	return nil
}

@@ -550,18 +573,28 @@ func sendTerminationConfirmation(appInstanceId string) error {
	return nil
}

// func subscribeAppTermination(appInstanceId string) error {
// 	var subscription asc.AppTerminationNotificationSubscription
// 	subscription.SubscriptionType = "AppTerminationNotificationSubscription"
// 	subscription.AppInstanceId = appInstanceId
// 	subscription.CallbackReference = hostUrl.String() + basePath
// 	_, _, err := appSupportClient.AppSubscriptionsApi.ApplicationsSubscriptionsPOST(context.TODO(), subscription, appInstanceId)
// 	if err != nil {
// 		log.Error("Failed to register to App Support subscription: ", err)
// 		return err
// 	}
// 	return nil
// }
func subscribeAppTermination(appInstanceId string) error {
	var subscription appSupportClient.AppTerminationNotificationSubscription
	subscription.SubscriptionType = "AppTerminationNotificationSubscription"
	subscription.AppInstanceId = appInstanceId
	subscription.CallbackReference = hostUrl.String() + basePath + appTerminationPath
	_, _, err := appEnablementAppSupportClient.AppSubscriptionsApi.ApplicationsSubscriptionsPOST(context.TODO(), subscription, appInstanceId)
	if err != nil {
		log.Error("Failed to register to App Support subscription: ", err)
		return err
	}
	return nil
}

func unsubscribeAppTermination(appInstanceId string) error {
	//only subscribe to one subscription, so we force number to be one, couldn't be anything else
	_, err := appEnablementAppSupportClient.AppSubscriptionsApi.ApplicationsSubscriptionDELETE(context.TODO(), appInstanceId, "1")
	if err != nil {
		log.Error("Failed to unregister to App Support subscription: ", err)
		return err
	}
	return nil
}

func deregisterZoneStatus(subsIdStr string) {
	subsId, err := strconv.Atoi(subsIdStr)
@@ -3810,3 +3843,68 @@ func distanceGet(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintf(w, string(jsonResponse))
}

func mec011AppTerminationPost(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")

	var notification AppTerminationNotification
	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&notification)
	if err != nil {
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if !appEnablementEnabled {
		//just ignore the message
		w.WriteHeader(http.StatusNoContent)
		return
	}

	stopRegistrationTicker()

	//delete any registration it made
	_ = unsubscribeAppTermination(serviceAppInstanceId)
	_ = deregisterService(serviceAppInstanceId, appEnablementServiceId)

	if sendAppTerminationWhenDone {
		err = sendTerminationConfirmation(serviceAppInstanceId)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)

			return
		}
	}

	//send scenario update with a deletion
	var event scc.Event
	var eventScenarioUpdate scc.EventScenarioUpdate
	var physicalLocation scc.PhysicalLocation
	var nodeDataUnion scc.NodeDataUnion
	var node scc.ScenarioNode

	physicalLocation.Name = "elementName"
	physicalLocation.Type_ = "EDGE-APP"

	nodeDataUnion.PhysicalLocation = &physicalLocation

	node.Type_ = "EDGE-APP"
	node.Parent = "parentName"
	node.NodeDataUnion = &nodeDataUnion

	eventScenarioUpdate.Node = &node
	eventScenarioUpdate.Action = "REMOVE"

	event.EventScenarioUpdate = &eventScenarioUpdate
	event.Type_ = "SCENARIO-UPDATE"

	go func() {
		_, err := sandboxCtrlClient.EventsApi.SendEvent(context.TODO(), event.Type_, event)
		if err != nil {
			log.Error(err)
		}
	}()

	w.WriteHeader(http.StatusNoContent)
}
Loading