Revert "Support for XApp configuration update" 30/130/1
authorAbukar Mohamed <abukar.mohamed@nokia.com>
Thu, 9 May 2019 14:40:34 +0000 (14:40 +0000)
committerAbukar Mohamed <abukar.mohamed@nokia.com>
Thu, 9 May 2019 14:40:34 +0000 (14:40 +0000)
Merged by mistake!

This reverts commit 10d3c67188dd2db001e0fd196b0acbad7d9bb37d.

Change-Id: I3a036d4403c5c991c5be2a6f70993c3810d28286
Signed-off-by: Mohamed Abukar <abukar.mohamed@nokia.com>
25 files changed:
.gitignore [deleted file]
api/appmgr_rest_api.json
api/appmgr_rest_api.yaml [deleted file]
cmd/appmgr/api.go
cmd/appmgr/api_test.go
cmd/appmgr/desc.go
cmd/appmgr/desc_test.go [deleted file]
cmd/appmgr/helm.go
cmd/appmgr/helm_test.go [deleted file]
cmd/appmgr/main.go
cmd/appmgr/types.go
docker/Dockerfile [new file with mode: 0755]
docker/docker-entrypoint.sh [new file with mode: 0755]
go.mod [changed mode: 0644->0755]
go.sum [changed mode: 0644->0755]
internal/sdlgo/LICENSE.txt [new file with mode: 0644]
internal/sdlgo/README [new file with mode: 0644]
internal/sdlgo/bench_test.go [new file with mode: 0644]
internal/sdlgo/go.mod [new file with mode: 0644]
internal/sdlgo/go.sum [new file with mode: 0644]
internal/sdlgo/internal/sdlgoredis/sdlgoredis.go [new file with mode: 0644]
internal/sdlgo/sdl.go [new file with mode: 0644]
internal/sdlgo/sdl_test.go [new file with mode: 0644]
scripts/appmgrcli
test/schema.json [deleted file]

diff --git a/.gitignore b/.gitignore
deleted file mode 100644 (file)
index fa8d028..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-build/cache/*
-cache/*
index 92cc418..66250ae 100644 (file)
@@ -2,7 +2,7 @@
   "swagger": "2.0",
   "info": {
     "description": "This is a draft API for RIC appmgr",
-    "version": "0.1.2",
+    "version": "0.0.11",
     "title": "RIC appmgr",
     "license": {
       "name": "Apache 2.0",
@@ -19,9 +19,6 @@
     "/health": {
       "get": {
         "summary": "Health check of xApp Manager",
-        "tags": [
-          "health"
-        ],
         "operationId": "getHealth",
         "responses": {
           "200": {
@@ -33,9 +30,6 @@
     "/xapps": {
       "post": {
         "summary": "Deploy a xapp",
-        "tags": [
-          "xapp"
-        ],
         "operationId": "deployXapp",
         "consumes": [
           "application/json"
@@ -80,9 +74,6 @@
       },
       "get": {
         "summary": "Returns the status of all xapps",
-        "tags": [
-          "xapp"
-        ],
         "operationId": "getAllXapps",
         "produces": [
           "application/json"
     "/xapps/{xAppName}": {
       "get": {
         "summary": "Returns the status of a given xapp",
-        "tags": [
-          "xapp"
-        ],
         "operationId": "getXappByName",
         "produces": [
           "application/json"
       },
       "delete": {
         "summary": "Undeploy an existing xapp",
-        "tags": [
-          "xapp"
-        ],
         "operationId": "undeployXapp",
         "parameters": [
           {
     "/xapps/{xAppName}/instances/{xAppInstanceName}": {
       "get": {
         "summary": "Returns the status of a given xapp",
-        "tags": [
-          "xapp"
-        ],
         "operationId": "getXappInstanceByName",
         "produces": [
           "application/json"
         }
       }
     },
-    "/config": {
-      "post": {
-        "summary": "Create xApp config",
-        "tags": [
-          "xapp"
-        ],
-        "operationId": "createXappConfig",
-        "consumes": [
-          "application/json"
-        ],
-        "produces": [
-          "application/json"
-        ],
-        "parameters": [
-          {
-            "name": "xAppConfig",
-            "in": "body",
-            "description": "xApp config",
-            "schema": {
-              "$ref": "#/definitions/xAppConfig"
-            }
-          }
-        ],
-        "responses": {
-          "201": {
-            "description": "xApp config successfully created",
-            "schema": {
-              "$ref": "#/definitions/xAppConfig"
-            }
-          },
-          "400": {
-            "description": "Invalid input"
-          },
-          "422": {
-            "description": "Validation of configuration failed"
-          },
-          "500": {
-            "description": "Internal error"
-          }
-        }
-      },
-      "put": {
-        "summary": "Modify xApp config",
-        "tags": [
-          "xapp"
-        ],
-        "operationId": "ModifyXappConfig",
-        "consumes": [
-          "application/json"
-        ],
-        "produces": [
-          "application/json"
-        ],
-        "parameters": [
-          {
-            "name": "xAppConfig",
-            "in": "body",
-            "description": "xApp config",
-            "schema": {
-              "$ref": "#/definitions/xAppConfig"
-            }
-          }
-        ],
-        "responses": {
-          "200": {
-            "description": "xApp config successfully modified",
-            "schema": {
-              "$ref": "#/definitions/xAppConfig"
-            }
-          },
-          "400": {
-            "description": "Invalid input"
-          },
-          "422": {
-            "description": "Validation of configuration failed"
-          },
-          "500": {
-            "description": "Internal error"
-          }
-        }
-      },
-      "get": {
-        "summary": "Returns the configuration of all xapps",
-        "tags": [
-          "xapp"
-        ],
-        "operationId": "getAllXappConfig",
-        "produces": [
-          "application/json"
-        ],
-        "responses": {
-          "200": {
-            "description": "successful query of xApp config",
-            "schema": {
-              "$ref": "#/definitions/AllXappConfig"
-            }
-          },
-          "500": {
-            "description": "Internal error"
-          }
-        }
-      },
-      "delete": {
-        "summary": "Delete xApp configuration",
-        "tags": [
-          "xapp"
-        ],
-        "operationId": "deleteXappConfig",
-        "parameters": [
-          {
-            "name": "xAppConfigInfo",
-            "in": "body",
-            "description": "xApp configuration information",
-            "schema": {
-              "$ref": "#/definitions/xAppConfigInfo"
-            }
-          }
-        ],
-        "responses": {
-          "204": {
-            "description": "Successful deletion of xApp"
-          },
-          "400": {
-            "description": "Invalid parameters supplied"
-          },
-          "500": {
-            "description": "Internal error"
-          }
-        }
-      }
-    },
     "/subscriptions": {
       "post": {
         "summary": "Subscribe event",
-        "tags": [
-          "xapp",
-          "subscriptions"
-        ],
         "operationId": "addSubscription",
         "consumes": [
           "application/json"
       },
       "get": {
         "summary": "Returns all subscriptions",
-        "tags": [
-          "xapp",
-          "subscriptions"
-        ],
         "operationId": "getSubscriptions",
         "produces": [
           "application/json"
     "/subscriptions/{subscriptionId}": {
       "get": {
         "summary": "Returns the information of subscription",
-        "tags": [
-          "xapp",
-          "subscriptions"
-        ],
         "operationId": "getSubscriptionById",
         "produces": [
           "application/json"
       },
       "put": {
         "summary": "Modify event subscription",
-        "tags": [
-          "xapp",
-          "subscriptions"
-        ],
         "operationId": "modifySubscription",
         "consumes": [
           "application/json"
       },
       "delete": {
         "summary": "Unsubscribe event",
-        "tags": [
-          "xapp",
-          "subscriptions"
-        ],
         "description": "",
         "operationId": "deleteSubscription",
         "parameters": [
         }
       }
     },
-    "xAppConfigInfo": {
-      "type": "object",
-      "required": [
-        "xAppName",
-        "configMapName",
-        "namespace"
-      ],
-      "properties": {
-        "xAppName": {
-          "type":"string",
-          "description":"Name of the xApp",
-          "example": "xapp-dummy"
-        },
-        "configMapName": {
-          "type":"string",
-          "description":"Name of the config map",
-          "example": "xapp-dummy-config-map"
-        },
-        "namespace": {
-          "type":"string",
-          "description":"Name of the namespace",
-          "example": "ricxapp"
-        }
-      }
-    },
-    "xAppConfig": {
-      "type": "object",
-      "required": [
-        "xAppConfigInfo",
-        "configSchema",
-        "configMap"
-      ],
-      "properties": {
-        "xAppConfigInfo": {
-          "$ref": "#/definitions/xAppConfigInfo"
-        },
-        "configSchema": {
-          "type":"object",
-          "description":"Schema of configuration in JSON format"
-        },
-        "configMap": {
-          "type":"object",
-          "description":"Configuration in JSON format"
-        }
-      }
-    },
-    "AllXappConfig": {
-      "type": "array",
-      "items": {
-        "$ref": "#/definitions/xAppConfig"
-      }
-    },
     "subscriptionRequest": {
       "type": "object",
       "required": [
diff --git a/api/appmgr_rest_api.yaml b/api/appmgr_rest_api.yaml
deleted file mode 100644 (file)
index 0a5cf73..0000000
+++ /dev/null
@@ -1,529 +0,0 @@
-swagger: '2.0'
-info:
-  description: This is a draft API for RIC appmgr
-  version: 0.1.2
-  title: RIC appmgr
-  license:
-    name: Apache 2.0
-    url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
-host: hostname
-basePath: /ric/v1
-schemes:
-  - https
-  - http
-paths:
-  /health:
-    get:
-      summary: Health check of xApp Manager
-      tags:
-        - health
-      operationId: getHealth
-      responses:
-        '200':
-          description: Status of xApp Manager is ok
-  /xapps:
-    post:
-      summary: Deploy a xapp
-      tags:
-        - xapp
-      operationId: deployXapp
-      consumes:
-        - application/json
-      produces:
-        - application/json
-      parameters:
-        - name: xAppInfo
-          in: body
-          description: xApp information
-          schema:
-            type: object
-            required:
-              - xAppName
-            properties:
-              xAppName:
-                type: string
-                description: Name of the xApp
-                example: xapp-dummy
-      responses:
-        '201':
-          description: xApp successfully created
-          schema:
-            $ref: '#/definitions/Xapp'
-        '400':
-          description: Invalid input
-        '500':
-          description: Internal error
-    get:
-      summary: Returns the status of all xapps
-      tags:
-        - xapp
-      operationId: getAllXapps
-      produces:
-        - application/json
-      responses:
-        '200':
-          description: successful query of xApps
-          schema:
-            $ref: '#/definitions/AllXapps'
-        '500':
-          description: Internal error
-  '/xapps/{xAppName}':
-    get:
-      summary: Returns the status of a given xapp
-      tags:
-        - xapp
-      operationId: getXappByName
-      produces:
-        - application/json
-      parameters:
-        - name: xAppName
-          in: path
-          description: Name of xApp
-          required: true
-          type: string
-      responses:
-        '200':
-          description: successful operation
-          schema:
-            $ref: '#/definitions/Xapp'
-        '400':
-          description: Invalid ID supplied
-        '404':
-          description: Xapp not found
-        '500':
-          description: Internal error
-    delete:
-      summary: Undeploy an existing xapp
-      tags:
-        - xapp
-      operationId: undeployXapp
-      parameters:
-        - name: xAppName
-          in: path
-          description: Xapp to be undeployed
-          required: true
-          type: string
-      responses:
-        '204':
-          description: Successful deletion of xApp
-        '400':
-          description: Invalid xApp name supplied
-        '500':
-          description: Internal error
-  '/xapps/{xAppName}/instances/{xAppInstanceName}':
-    get:
-      summary: Returns the status of a given xapp
-      tags:
-        - xapp
-      operationId: getXappInstanceByName
-      produces:
-        - application/json
-      parameters:
-        - name: xAppName
-          in: path
-          description: Name of xApp
-          required: true
-          type: string
-        - name: xAppInstanceName
-          in: path
-          description: Name of xApp instance to get information
-          required: true
-          type: string
-      responses:
-        '200':
-          description: successful operation
-          schema:
-            $ref: '#/definitions/XappInstance'
-        '400':
-          description: Invalid name supplied
-        '404':
-          description: Xapp not found
-        '500':
-          description: Internal error
-  /config:
-    post:
-      summary: Create xApp config
-      tags:
-        - xapp
-      operationId: createXappConfig
-      consumes:
-        - application/json
-      produces:
-        - application/json
-      parameters:
-        - name: xAppConfig
-          in: body
-          description: xApp config
-          schema:
-            $ref: '#/definitions/xAppConfig'
-      responses:
-        '201':
-          description: xApp config successfully created
-          schema:
-            $ref: '#/definitions/xAppConfig'
-        '400':
-          description: Invalid input
-        '422':
-          description: Validation of configuration failed
-        '500':
-          description: Internal error
-    put:
-      summary: Modify xApp config
-      tags:
-        - xapp
-      operationId: ModifyXappConfig
-      consumes:
-        - application/json
-      produces:
-        - application/json
-      parameters:
-        - name: xAppConfig
-          in: body
-          description: xApp config
-          schema:
-            $ref: '#/definitions/xAppConfig'
-      responses:
-        '200':
-          description: xApp config successfully modified
-          schema:
-            $ref: '#/definitions/xAppConfig'
-        '400':
-          description: Invalid input
-        '422':
-          description: Validation of configuration failed
-        '500':
-          description: Internal error
-    get:
-      summary: Returns the configuration of all xapps
-      tags:
-        - xapp
-      operationId: getAllXappConfig
-      produces:
-        - application/json
-      responses:
-        '200':
-          description: successful query of xApp config
-          schema:
-            $ref: '#/definitions/AllXappConfig'
-        '500':
-          description: Internal error
-    delete:
-      summary: Delete xApp configuration
-      tags:
-        - xapp
-      operationId: deleteXappConfig
-      parameters:
-        - name: xAppConfigInfo
-          in: body
-          description: xApp configuration information
-          schema:
-            $ref: '#/definitions/xAppConfigInfo'
-      responses:
-        '204':
-          description: Successful deletion of xApp
-        '400':
-          description: Invalid parameters supplied
-        '500':
-          description: Internal error
-  /subscriptions:
-    post:
-      summary: Subscribe event
-      tags:
-        - xapp
-        - subscriptions
-      operationId: addSubscription
-      consumes:
-        - application/json
-      produces:
-        - application/json
-      parameters:
-        - name: subscriptionRequest
-          in: body
-          description: New subscription
-          required: true
-          schema:
-            $ref: '#/definitions/subscriptionRequest'
-      responses:
-        '200':
-          description: Subscription successful
-          schema:
-            $ref: '#/definitions/subscriptionResponse'
-        '400':
-          description: Invalid input
-    get:
-      summary: Returns all subscriptions
-      tags:
-        - xapp
-        - subscriptions
-      operationId: getSubscriptions
-      produces:
-        - application/json
-      responses:
-        '200':
-          description: successful query of subscriptions
-          schema:
-            $ref: '#/definitions/allSubscriptions'
-  '/subscriptions/{subscriptionId}':
-    get:
-      summary: Returns the information of subscription
-      tags:
-        - xapp
-        - subscriptions
-      operationId: getSubscriptionById
-      produces:
-        - application/json
-      parameters:
-        - name: subscriptionId
-          in: path
-          description: ID of subscription
-          required: true
-          type: integer
-      responses:
-        '200':
-          description: successful operation
-          schema:
-            $ref: '#/definitions/subscription'
-        '400':
-          description: Invalid ID supplied
-        '404':
-          description: Subscription not found
-    put:
-      summary: Modify event subscription
-      tags:
-        - xapp
-        - subscriptions
-      operationId: modifySubscription
-      consumes:
-        - application/json
-      produces:
-        - application/json
-      parameters:
-        - name: subscriptionId
-          in: path
-          description: ID of subscription
-          required: true
-          type: integer
-        - in: body
-          name: subscriptionRequest
-          description: Modified subscription
-          required: true
-          schema:
-            $ref: '#/definitions/subscriptionRequest'
-      responses:
-        '200':
-          description: Subscription modification successful
-          schema:
-            $ref: '#/definitions/subscriptionResponse'
-        '400':
-          description: Invalid input
-    delete:
-      summary: Unsubscribe event
-      tags:
-        - xapp
-        - subscriptions
-      description: ''
-      operationId: deleteSubscription
-      parameters:
-        - name: subscriptionId
-          in: path
-          description: ID of subscription
-          required: true
-          type: integer
-      responses:
-        '204':
-          description: Successful deletion of subscription
-        '400':
-          description: Invalid subscription supplied
-definitions:
-  AllXapps:
-    type: array
-    items:
-      $ref: '#/definitions/Xapp'
-  Xapp:
-    type: object
-    required:
-      - name
-    properties:
-      name:
-        type: string
-        example: xapp-dummy
-      status:
-        type: string
-        description: xapp status in the RIC
-        enum:
-          - unknown
-          - deployed
-          - deleted
-          - superseded
-          - failed
-          - deleting
-      version:
-        type: string
-        example: 1.2.3
-      instances:
-        type: array
-        items:
-          $ref: '#/definitions/XappInstance'
-  XappInstance:
-    type: object
-    required:
-      - name
-    properties:
-      name:
-        type: string
-        example: xapp-dummy-6cd577d9-4v255
-      status:
-        type: string
-        description: xapp instance status
-        enum:
-          - pending
-          - running
-          - succeeded
-          - failed
-          - unknown
-          - completed
-          - crashLoopBackOff
-      ip:
-        type: string
-        example: 192.168.0.1
-      port:
-        type: integer
-        example: 32300
-      txMessages:
-        type: array
-        items:
-          type: string
-          example: ControlIndication
-      rxMessages:
-        type: array
-        items:
-          type: string
-          example: LoadIndication
-  xAppConfigInfo:
-    type: object
-    required:
-      - xAppName
-      - configMapName
-      - namespace
-    properties:
-      xAppName:
-        type: string
-        description: Name of the xApp
-        example: xapp-dummy
-      configMapName:
-        type: string
-        description: Name of the config map
-        example: xapp-dummy-config-map
-      namespace:
-        type: string
-        description: Name of the namespace
-        example: ricxapp
-  xAppConfig:
-    type: object
-    required:
-      - xAppConfigInfo
-      - configSchema
-      - configMap
-    properties:
-      xAppConfigInfo:
-        $ref: '#/definitions/xAppConfigInfo'
-      configSchema:
-        type: object
-        description: Schema of configuration in JSON format
-      configMap:
-        type: object
-        description: Configuration in JSON format
-  AllXappConfig:
-    type: array
-    items:
-      $ref: '#/definitions/xAppConfig'
-  subscriptionRequest:
-    type: object
-    required:
-      - targetUrl
-      - eventType
-      - maxRetries
-      - retryTimer
-    properties:
-      targetUrl:
-        type: string
-        example: 'http://localhost:11111/apps/webhook/'
-      eventType:
-        type: string
-        description: Event which is subscribed
-        enum:
-          - created
-          - deleted
-          - all
-      maxRetries:
-        type: integer
-        description: Maximum number of retries
-        example: 11
-      retryTimer:
-        type: integer
-        description: Time in seconds to wait before next retry
-        example: 22
-  subscriptionResponse:
-    type: object
-    properties:
-      id:
-        type: string
-        example: 1ILBltYYzEGzWRrVPZKmuUmhwcc
-      version:
-        type: integer
-        example: 2
-      eventType:
-        type: string
-        description: Event which is subscribed
-        enum:
-          - created
-          - deleted
-          - updated
-          - all
-  allSubscriptions:
-    type: array
-    items:
-      $ref: '#/definitions/subscription'
-  subscription:
-    type: object
-    properties:
-      id:
-        type: string
-        example: 1ILBltYYzEGzWRrVPZKmuUmhwcc
-      targetUrl:
-        type: string
-        example: 'http://localhost:11111/apps/webhook/'
-      eventType:
-        type: string
-        description: Event which is subscribed
-        enum:
-          - created
-          - deleted
-          - updated
-          - all
-      maxRetries:
-        type: integer
-        description: Maximum number of retries
-        example: 11
-      retryTimer:
-        type: integer
-        description: Time in seconds to wait before next retry
-        example: 22
-  subscriptionNotification:
-    type: object
-    properties:
-      id:
-        type: string
-        example: 1ILBltYYzEGzWRrVPZKmuUmhwcc
-      version:
-        type: integer
-        example: 2
-      eventType:
-        type: string
-        description: Event to be notified
-        enum:
-          - created
-          - deleted
-          - updated
-      xApps:
-        $ref: '#/definitions/AllXapps'
index 8450d02..2e7ddc7 100755 (executable)
@@ -30,11 +30,7 @@ import (
 
 // API functions
 
-func (m *XappManager) Initialize(h Helmer, cm ConfigMapper) {
-       m.cm = cm
-       m.helm = h
-       m.helm.SetCM(cm)
-
+func (m *XappManager) Initialize(h Helmer) {
        m.router = mux.NewRouter().StrictSlash(true)
 
        resources := []Resource{
@@ -55,7 +51,6 @@ func (m *XappManager) Initialize(h Helmer, cm ConfigMapper) {
 
                {"GET", "/ric/v1/config", m.getConfig},
                {"POST", "/ric/v1/config", m.createConfig},
-               {"PUT", "/ric/v1/config", m.updateConfig},
                {"DELETE", "/ric/v1/config", m.deleteConfig},
        }
 
@@ -72,6 +67,7 @@ func (m *XappManager) finalize(h Helmer) {
        m.sd = SubscriptionDispatcher{}
        m.sd.Initialize()
 
+       m.helm = h
        m.helm.Initialize()
 
        m.notifyClients()
@@ -161,7 +157,7 @@ func (m *XappManager) deployXapp(w http.ResponseWriter, r *http.Request) {
                return
        }
 
-       var cm XappDeploy
+       var cm ConfigMetadata
        if err := json.NewDecoder(r.Body).Decode(&cm); err != nil {
                mdclog(MdclogErr, "Invalid xapp data in request body - url="+r.URL.RequestURI())
                respondWithError(w, http.StatusMethodNotAllowed, "Invalid xapp data!")
@@ -266,8 +262,7 @@ func (m *XappManager) notifyClients() {
 }
 
 func (m *XappManager) getConfig(w http.ResponseWriter, r *http.Request) {
-       cfg := m.cm.UploadConfig()
-       respondWithJSON(w, http.StatusOK, cfg)
+       respondWithJSON(w, http.StatusOK, UploadConfig())
 }
 
 func (m *XappManager) createConfig(w http.ResponseWriter, r *http.Request) {
@@ -276,41 +271,20 @@ func (m *XappManager) createConfig(w http.ResponseWriter, r *http.Request) {
                return
        }
 
-       if errList, err := m.cm.CreateConfigMap(c); err != nil {
-               if err.Error() != "Validation failed!" {
-                       respondWithError(w, http.StatusInternalServerError, err.Error())
-               } else {
-                       respondWithJSON(w, http.StatusUnprocessableEntity, errList)
-               }
+       if err := CreateConfigMap(c); err != nil {
+               respondWithError(w, http.StatusInternalServerError, err.Error())
                return
        }
        respondWithJSON(w, http.StatusCreated, nil)
 }
 
-func (m *XappManager) updateConfig(w http.ResponseWriter, r *http.Request) {
-       var c XAppConfig
-       if parseConfig(w, r, &c) != nil {
-               return
-       }
-
-       if errList, err := m.cm.UpdateConfigMap(c); err != nil {
-               if err.Error() != "Validation failed!" {
-                       respondWithError(w, http.StatusInternalServerError, err.Error())
-               } else {
-                       respondWithJSON(w, http.StatusUnprocessableEntity, errList)
-               }
-               return
-       }
-       respondWithJSON(w, http.StatusOK, nil)
-}
-
 func (m *XappManager) deleteConfig(w http.ResponseWriter, r *http.Request) {
        var c XAppConfig
        if parseConfig(w, r, &c) != nil {
                return
        }
 
-       if _, err := m.cm.DeleteConfigMap(c); err != nil {
+       if _, err := DeleteConfigMap(c); err != nil {
                respondWithError(w, http.StatusInternalServerError, err.Error())
                return
        }
index 89e4a08..2648dee 100755 (executable)
@@ -41,9 +41,6 @@ var helmError error
 type MockedHelmer struct {
 }
 
-func (h *MockedHelmer) SetCM(cm ConfigMapper) {
-}
-
 func (sd *MockedHelmer) Initialize() {
 }
 
@@ -59,7 +56,7 @@ func (h *MockedHelmer) List() (names []string, err error) {
        return names, helmError
 }
 
-func (h *MockedHelmer) Install(m XappDeploy) (Xapp, error) {
+func (h *MockedHelmer) Install(m ConfigMetadata) (Xapp, error) {
        return xapp, helmError
 }
 
@@ -74,10 +71,9 @@ func TestMain(m *testing.M) {
        xapp = Xapp{}
        xapps = []Xapp{}
 
-       cm := MockedConfigMapper{}
        h := MockedHelmer{}
        x = XappManager{}
-       x.Initialize(&h, &cm)
+       x.Initialize(&h)
 
        // Just run on the background (for coverage)
        go x.Run()
@@ -158,36 +154,6 @@ func TestDeleteAppRemovesGivenXapp(t *testing.T) {
        checkResponseCode(t, http.StatusNotFound, response.Code)
 }
 
-func TestGetConfigReturnsEmpty(t *testing.T) {
-       req, _ := http.NewRequest("GET", "/ric/v1/config", nil)
-       response := executeRequest(req)
-
-       checkResponseCode(t, http.StatusOK, response.Code)
-}
-
-func TestCreateConfigFailsWithMethodNotAllowed(t *testing.T) {
-       req, _ := http.NewRequest("POST", "/ric/v1/config", nil)
-       response := executeRequest(req)
-
-       checkResponseCode(t, http.StatusMethodNotAllowed, response.Code)
-}
-
-func TestCreateConfigOk(t *testing.T) {
-       payload := []byte(`{"name":"dummy-xapp"}`)
-       req, _ := http.NewRequest("POST", "/ric/v1/config", bytes.NewBuffer(payload))
-       response := executeRequest(req)
-
-       checkResponseCode(t, http.StatusCreated, response.Code)
-}
-
-func TestDeleteConfigOk(t *testing.T) {
-       payload := []byte(`{"name":"dummy-xapp"}`)
-       req, _ := http.NewRequest("DELETE", "/ric/v1/config", bytes.NewBuffer(payload))
-       response := executeRequest(req)
-
-       checkResponseCode(t, http.StatusNotFound, response.Code)
-}
-
 // Error handling
 func TestGetXappReturnsError(t *testing.T) {
        helmError = errors.New("Not found")
@@ -292,15 +258,13 @@ func generateXapp(name, status, ver, iname, istatus, ip, port string) (x Xapp) {
        x.Status = status
        x.Version = ver
        p, _ := strconv.Atoi(port)
-       var msgs MessageTypes
-
        instance := XappInstance{
                Name:       iname,
                Status:     istatus,
                Ip:         ip,
                Port:       p,
-               TxMessages: msgs.TxMessages,
-               RxMessages: msgs.RxMessages,
+               TxMessages: []string{"RIC_E2_TERMINATION_HC_REQUEST", "RIC_E2_MANAGER_HC_REQUEST"},
+               RxMessages: []string{"RIC_E2_TERMINATION_HC_RESPONSE", "RIC_E2_MANAGER_HC_RESPONSE"},
        }
        x.Instances = append(x.Instances, instance)
 
index 2f55460..c3a27a3 100755 (executable)
@@ -58,13 +58,8 @@ type CMMetadata struct {
        Namespace string `json:"namespace"`
 }
 
-type CMError struct {
-       Field       string `json:"field"`
-       Description string `json:"description"`
-}
-
-func (cm *ConfigMap) UploadConfig() (cfg []XAppConfig) {
-       for _, name := range cm.GetNamesFromHelmRepo() {
+func UploadConfig() (cfg []XAppConfig) {
+       for _, name := range GetNamesFromHelmRepo() {
                if name == "appmgr" {
                        continue
                }
@@ -73,12 +68,12 @@ func (cm *ConfigMap) UploadConfig() (cfg []XAppConfig) {
                        Metadata: ConfigMetadata{Name: name, Namespace: "ricxapp", ConfigName: name + "-appconfig"},
                }
 
-               err := cm.ReadSchema(name, &c)
+               err := ReadSchema(name, &c)
                if err != nil {
                        continue
                }
 
-               err = cm.ReadConfigMap(c.Metadata.ConfigName, "ricxapp", &c.Configuration)
+               err = ReadConfigMap(name, "ricxapp", &c.Configuration)
                if err != nil {
                        log.Println("No active configMap found, using default!")
                }
@@ -88,18 +83,18 @@ func (cm *ConfigMap) UploadConfig() (cfg []XAppConfig) {
        return
 }
 
-func (cm *ConfigMap) ReadSchema(name string, c *XAppConfig) (err error) {
-       if err = cm.FetchChart(name); err != nil {
+func ReadSchema(name string, c *XAppConfig) (err error) {
+       if err = FetchChart(name); err != nil {
                return
        }
 
        tarDir := viper.GetString("xapp.tarDir")
-       err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor)
+       err = ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor)
        if err != nil {
                return
        }
 
-       err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Configuration)
+       err = ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Configuration)
        if err != nil {
                return
        }
@@ -111,8 +106,8 @@ func (cm *ConfigMap) ReadSchema(name string, c *XAppConfig) (err error) {
        return
 }
 
-func (cm *ConfigMap) ReadConfigMap(ConfigName string, ns string, c *interface{}) (err error) {
-       args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, ConfigName)
+func ReadConfigMap(name string, ns string, c *interface{}) (err error) {
+       args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s-appconfig", ns, name)
        configMapJson, err := KubectlExec(args)
        if err != nil {
                return
@@ -126,15 +121,15 @@ func (cm *ConfigMap) ReadConfigMap(ConfigName string, ns string, c *interface{})
        return
 }
 
-func (cm *ConfigMap) ApplyConfigMap(r XAppConfig, action string) (err error) {
-       c := ConfigMap{
+func ApplyConfigMap(r XAppConfig) (err error) {
+       cm := ConfigMap{
                Kind:       "ConfigMap",
                ApiVersion: "v1",
                Metadata:   CMMetadata{Name: r.Metadata.Name, Namespace: r.Metadata.Namespace},
                Data:       r.Configuration,
        }
 
-       cmJson, err := json.Marshal(c)
+       cmJson, err := json.Marshal(cm)
        if err != nil {
                log.Println("Config marshalling failed: ", err)
                return
@@ -147,37 +142,26 @@ func (cm *ConfigMap) ApplyConfigMap(r XAppConfig, action string) (err error) {
                return
        }
 
-       cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl %s -f -"
-       args := fmt.Sprintf(cmd, r.Metadata.Namespace, r.Metadata.ConfigName, cmFile, action)
+       cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl apply -f -"
+       args := fmt.Sprintf(cmd, r.Metadata.Namespace, r.Metadata.ConfigName, cmFile)
        _, err = KubectlExec(args)
        if err != nil {
                return
        }
-       log.Println("Configmap changes done!")
-
-       return
-}
+       log.Println("Configmap changes created!")
 
-func (cm *ConfigMap) CreateConfigMap(r XAppConfig) (errList []CMError, err error) {
-       if errList, err = cm.Validate(r); err != nil {
-               return
-       }
-       err = cm.ApplyConfigMap(r, "create")
        return
 }
 
-func (cm *ConfigMap) UpdateConfigMap(r XAppConfig) (errList []CMError, err error) {
-       if errList, err = cm.Validate(r); err != nil {
+func CreateConfigMap(r XAppConfig) (err error) {
+       if err = Validate(r); err != nil {
                return
        }
-
-       // Re-create the configmap with the new parameters
-       err = cm.ApplyConfigMap(r, "apply")
-       return
+       return ApplyConfigMap(r)
 }
 
-func (cm *ConfigMap) DeleteConfigMap(r XAppConfig) (c interface{}, err error) {
-       err = cm.ReadConfigMap(r.Metadata.ConfigName, r.Metadata.Namespace, &c)
+func DeleteConfigMap(r XAppConfig) (cm interface{}, err error) {
+       err = ReadConfigMap(r.Metadata.Name, r.Metadata.Namespace, &cm)
        if err == nil {
                args := fmt.Sprintf(" delete configmap --namespace=%s %s", r.Metadata.Namespace, r.Metadata.ConfigName)
                _, err = KubectlExec(args)
@@ -185,26 +169,23 @@ func (cm *ConfigMap) DeleteConfigMap(r XAppConfig) (c interface{}, err error) {
        return
 }
 
-func (cm *ConfigMap) PurgeConfigMap(m XappDeploy) (c interface{}, err error) {
+func PurgeConfigMap(m ConfigMetadata) (cm interface{}, err error) {
        if m.ConfigName == "" {
                m.ConfigName = m.Name + "-appconfig"
        }
-       md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
-
-       return cm.DeleteConfigMap(XAppConfig{Metadata: md})
+       return DeleteConfigMap(XAppConfig{Metadata: m})
 }
 
-func (cm *ConfigMap) RestoreConfigMap(m XappDeploy, c interface{}) (err error) {
+func RestoreConfigMap(m ConfigMetadata, cm interface{}) (err error) {
        if m.ConfigName == "" {
                m.ConfigName = m.Name + "-appconfig"
        }
-       md := ConfigMetadata{Name: m.Name, Namespace: m.Namespace, ConfigName: m.ConfigName}
        time.Sleep(time.Duration(10 * time.Second))
 
-       return cm.ApplyConfigMap(XAppConfig{Metadata: md, Configuration: c}, "create")
+       return ApplyConfigMap(XAppConfig{Metadata: m, Configuration: cm})
 }
 
-func (cm *ConfigMap) GetNamesFromHelmRepo() (names []string) {
+func GetNamesFromHelmRepo() (names []string) {
        rname := viper.GetString("helm.repo-name")
 
        cmdArgs := strings.Join([]string{"search ", rname}, "")
@@ -225,37 +206,37 @@ func (cm *ConfigMap) GetNamesFromHelmRepo() (names []string) {
        return names
 }
 
-func (cm *ConfigMap) Validate(req XAppConfig) (errList []CMError, err error) {
+func Validate(req XAppConfig) (err error) {
        c := XAppConfig{}
-       err = cm.ReadSchema(req.Metadata.Name, &c)
+       err = ReadSchema(req.Metadata.Name, &c)
        if err != nil {
                log.Printf("No schema file found for '%s', aborting ...", req.Metadata.Name)
-               return
+               return err
        }
-       return cm.doValidate(c.Descriptor, req.Configuration)
-}
 
-func (cm *ConfigMap) doValidate(schema, cfg interface{}) (errList []CMError, err error) {
-       schemaLoader := gojsonschema.NewGoLoader(schema)
-       documentLoader := gojsonschema.NewGoLoader(cfg)
+       schemaLoader := gojsonschema.NewGoLoader(c.Descriptor)
+       documentLoader := gojsonschema.NewGoLoader(req.Configuration)
 
+       log.Println("Starting validation ...")
        result, err := gojsonschema.Validate(schemaLoader, documentLoader)
        if err != nil {
                log.Println("Validation failed: ", err)
                return
        }
 
+       log.Println("validation done ...", err, result.Valid())
        if result.Valid() == false {
                log.Println("The document is not valid, Errors: ", result.Errors())
-               for _, desc := range result.Errors() {
-                       errList = append(errList, CMError{Field: desc.Field(), Description: desc.Description()})
+               s := make([]string, 3)
+               for i, desc := range result.Errors() {
+                       s = append(s, fmt.Sprintf(" (%d): %s.\n", i, desc.String()))
                }
-               return errList, errors.New("Validation failed!")
+               return errors.New(strings.Join(s, " "))
        }
        return
 }
 
-func (cm *ConfigMap) ReadFile(name string, data interface{}) (err error) {
+func ReadFile(name string, data interface{}) (err error) {
        f, err := ioutil.ReadFile(name)
        if err != nil {
                log.Printf("Reading '%s' file failed: %v", name, err)
@@ -271,7 +252,7 @@ func (cm *ConfigMap) ReadFile(name string, data interface{}) (err error) {
        return
 }
 
-func (cm *ConfigMap) FetchChart(name string) (err error) {
+func FetchChart(name string) (err error) {
        tarDir := viper.GetString("xapp.tarDir")
        repo := viper.GetString("helm.repo-name")
        fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name)
@@ -280,7 +261,7 @@ func (cm *ConfigMap) FetchChart(name string) (err error) {
        return
 }
 
-func (cm *ConfigMap) GetMessages(name string) (msgs MessageTypes) {
+func GetMessages(name string) (msgs MessageTypes, err error) {
        log.Println("Fetching tx/rx messages for: ", name)
        return
 }
diff --git a/cmd/appmgr/desc_test.go b/cmd/appmgr/desc_test.go
deleted file mode 100755 (executable)
index 36b6c72..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
-==================================================================================
-  Copyright (c) 2019 AT&T Intellectual Property.
-  Copyright (c) 2019 Nokia
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================================
-*/
-
-package main
-
-import (
-       "testing"
-       "reflect"
-       "errors"
-       "encoding/json"
-       "log"
-)
-
-var helmSearchOutput = `
-helm-repo/anr           0.0.1           1.0             Helm Chart for Nokia ANR (Automatic Neighbour Relation) xAPP
-helm-repo/appmgr        0.0.2           1.0             Helm Chart for xAppManager
-helm-repo/dualco        0.0.1           1.0             Helm Chart for Nokia dualco xAPP
-helm-repo/reporter      0.0.1           1.0             Helm Chart for Reporting xAPP
-helm-repo/uemgr         0.0.1           1.0             Helm Chart for Nokia uemgr xAPP
-`
-type ConfigSample struct {
-       Level   int
-       Host    string
-}
-
-type MockedConfigMapper struct {
-}
-
-func (cm *MockedConfigMapper) UploadConfig() (cfg []XAppConfig) {
-       return
-}
-
-func (cm *MockedConfigMapper) CreateConfigMap(r XAppConfig) (errList []CMError, err error){
-       return
-}
-
-func (cm *MockedConfigMapper) UpdateConfigMap(r XAppConfig) (errList []CMError, err error){
-       return
-}
-
-func (cm *MockedConfigMapper) DeleteConfigMap(r XAppConfig) (c interface{}, err error){
-       return
-}
-
-func (cm *MockedConfigMapper) PurgeConfigMap(m XappDeploy) (c interface{}, err error){
-       return
-}
-
-func (cm *MockedConfigMapper) RestoreConfigMap(m XappDeploy, c interface{}) (err error) {
-       return
-}
-
-func (cm *MockedConfigMapper) ReadConfigMap(name string, ns string, c *interface{}) (err error) {
-       return
-}
-
-func (cm *MockedConfigMapper) ApplyConfigMap(r XAppConfig, action string) (err error) {
-       return
-}
-
-func (cm *MockedConfigMapper) FetchChart(name string) (err error) {
-       return
-}
-
-func (cm *MockedConfigMapper) GetMessages(name string) (msgs MessageTypes) {
-       return
-}
-
-// Test cases
-func TestGetMessages(t *testing.T) {
-       cm := ConfigMap{}
-       expectedMsgs := MessageTypes{}
-
-       if !reflect.DeepEqual(cm.GetMessages("dummy-xapp"), expectedMsgs) {
-               t.Errorf("TestGetMessages failed!")
-       }
-}
-
-func TestFetchChartFails(t *testing.T) {
-       cm := ConfigMap{}
-
-       if cm.FetchChart("dummy-xapp") == nil {
-               t.Errorf("TestFetchChart failed!")
-       }
-}
-
-func TestFetchChartSuccess(t *testing.T) {
-       cm := ConfigMap{}
-
-       HelmExec = func(args string) (out []byte, err error) {
-               return
-       }
-
-       if cm.FetchChart("dummy-xapp") != nil {
-               t.Errorf("TestFetchChart failed!")
-       }
-}
-
-func TestGetNamesFromHelmRepoSuccess(t *testing.T) {
-       cm := ConfigMap{}
-       expectedResult := []string{"anr", "appmgr", "dualco", "reporter", "uemgr"}
-       HelmExec = func(args string) (out []byte, err error) {
-               return []byte(helmSearchOutput), nil
-       }
-
-       names := cm.GetNamesFromHelmRepo()
-       if !reflect.DeepEqual(names, expectedResult) {
-               t.Errorf("GetNamesFromHelmRepo failed: expected %v, got %v", expectedResult, names)
-       }
-}
-
-func TestGetNamesFromHelmRepoFailure(t *testing.T) {
-       cm := ConfigMap{}
-       expectedResult := []string{}
-       HelmExec = func(args string) (out []byte, err error) {
-               return []byte(helmSearchOutput), errors.New("Command failed!")
-       }
-
-       names := cm.GetNamesFromHelmRepo()
-       if names != nil {
-               t.Errorf("GetNamesFromHelmRepo failed: expected %v, got %v", expectedResult, names)
-       }
-}
-
-func TestApplyConfigMapSuccess(t *testing.T) {
-       cm := ConfigMap{}
-       m := ConfigMetadata{Name: "dummy-xapp", Namespace: "ricxapp"}
-       s := ConfigSample{5, "localhost"}
-
-       KubectlExec = func(args string) (out []byte, err error) {
-               log.Println("TestApplyConfigMapSuccess: ", args)
-               return []byte(`{"logger": {"level": 2}}`), nil
-       }
-
-       err := cm.ApplyConfigMap(XAppConfig{Metadata: m, Configuration: s}, "create")
-       if err != nil {
-               t.Errorf("ApplyConfigMap failed: %v", err)
-       }
-}
-
-func TestRestoreConfigMapSuccess(t *testing.T) {
-       cm := ConfigMap{}
-       m := XappDeploy{Name: "dummy-xapp", Namespace: "ricxapp"}
-       s := ConfigSample{5, "localhost"}
-
-       KubectlExec = func(args string) (out []byte, err error) {
-               log.Println("TestRestoreConfigMapSuccess: ", args)
-               return []byte(`{"logger": {"level": 2}}`), nil
-       }
-
-       err := cm.RestoreConfigMap(m, s)
-       if err != nil {
-               t.Errorf("RestoreConfigMap failed: %v", err)
-       }
-}
-
-func TestDeleteConfigMapSuccess(t *testing.T) {
-       cm := ConfigMap{}
-
-       HelmExec = func(args string) (out []byte, err error) {
-               return []byte("ok"), nil
-       }
-
-       KubectlExec = func(args string) (out []byte, err error) {
-               log.Println("TestDeleteConfigMapSuccess: ", args)
-               return []byte(`{"logger": {"level": 2}}`), nil
-       }
-
-       c, err := cm.DeleteConfigMap(XAppConfig{})
-       if err != nil {
-               t.Errorf("DeleteConfigMap failed: %v -> %v", err, c)
-       }
-}
-
-func TestPurgeConfigMapSuccess(t *testing.T) {
-       cm := ConfigMap{}
-
-       HelmExec = func(args string) (out []byte, err error) {
-               return []byte("ok"), nil
-       }
-
-       KubectlExec = func(args string) (out []byte, err error) {
-               return []byte(`{"logger": {"level": 2}}`), nil
-       }
-
-       c, err := cm.PurgeConfigMap(XappDeploy{})
-       if err != nil {
-               t.Errorf("PurgeConfigMap failed: %v -> %v", err, c)
-       }
-}
-
-func TestCreateConfigMapFails(t *testing.T) {
-       cm := ConfigMap{}
-
-       c, err := cm.CreateConfigMap(XAppConfig{})
-       if err == nil {
-               t.Errorf("CreateConfigMap failed: %v -> %v", err, c)
-       }
-}
-
-func TestUpdateConfigMapFails(t *testing.T) {
-       cm := ConfigMap{}
-
-       c, err := cm.UpdateConfigMap(XAppConfig{})
-       if err == nil {
-               t.Errorf("CreateConfigMap failed: %v -> %v", err, c)
-       }
-}
-
-func TestValidationSuccess(t *testing.T) {
-       cm := ConfigMap{}
-       var d interface{}
-       var cfg map[string]interface{}
-
-       err := json.Unmarshal([]byte(`{"local": {"host": ":8080"}, "logger": {"level": 3}}`), &cfg)
-
-       err = cm.ReadFile("./test/schema.json", &d)
-       if err != nil {
-               t.Errorf("ReadFile failed: %v -> %v", err, d)
-       }
-
-       feedback, err := cm.doValidate(d, cfg)
-       if err != nil {
-               t.Errorf("doValidate failed: %v -> %v", err, feedback)
-       }
-}
-
-func TestValidationFails(t *testing.T) {
-       cm := ConfigMap{}
-       var d interface{}
-       var cfg map[string]interface{}
-
-       err := json.Unmarshal([]byte(`{"local": {"host": ":8080"}, "logger": {"level": "INVALID"}}`), &cfg)
-
-       err = cm.ReadFile("./test/schema.json", &d)
-       if err != nil {
-               t.Errorf("ConfigMetadata failed: %v -> %v", err, d)
-       }
-
-       feedback, err := cm.doValidate(d, cfg)
-       if err == nil {
-               t.Errorf("doValidate should faile but didn't: %v -> %v", err, feedback)
-       }
-
-       log.Println("Feedbacks: ", feedback)
-}
\ No newline at end of file
index 388fb5c..0f463d2 100755 (executable)
@@ -63,18 +63,14 @@ func Exec(args string) (out []byte, err error) {
        return stdout.Bytes(), errors.New(stderr.String())
 }
 
-var HelmExec = func(args string) (out []byte, err error) {
+func HelmExec(args string) (out []byte, err error) {
        return Exec(strings.Join([]string{"helm", args}, " "))
 }
 
-var KubectlExec = func(args string) (out []byte, err error) {
+func KubectlExec(args string) (out []byte, err error) {
        return Exec(strings.Join([]string{"kubectl", args}, " "))
 }
 
-func (h *Helm) SetCM(cm ConfigMapper) {
-       h.cm = cm
-}
-
 func (h *Helm) Initialize() {
        if h.initDone == true {
                return
@@ -107,6 +103,7 @@ func (h *Helm) Run(args string) (out []byte, err error) {
 
 // API functions
 func (h *Helm) Init() (out []byte, err error) {
+
        // Add Tiller address as environment variable
        if err := addTillerEnv(); err != nil {
                return out, err
@@ -116,6 +113,7 @@ func (h *Helm) Init() (out []byte, err error) {
 }
 
 func (h *Helm) AddRepo() (out []byte, err error) {
+
        // Get helm repo user name and password from files mounted by secret object
        credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
        if err != nil {
@@ -142,40 +140,30 @@ func (h *Helm) AddRepo() (out []byte, err error) {
        return HelmExec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
 }
 
-func (h *Helm) Install(m XappDeploy) (xapp Xapp, err error) {
+func (h *Helm) Install(m ConfigMetadata) (xapp Xapp, err error) {
        out, err := h.Run(strings.Join([]string{"repo update "}, ""))
        if err != nil {
                return
        }
 
-       var cm interface{}
-       if err = h.cm.ReadConfigMap(m.Name, m.Namespace, &cm); err != nil {
-               out, err = h.Run(getInstallArgs(m, false))
-               if err != nil {
-                       return
-               }
-               return h.ParseStatus(m.Name, string(out))
-       }
-
-       // ConfigMap exists, try to override
-       out, err = h.Run(getInstallArgs(m, true))
-       if err == nil {
-               return h.ParseStatus(m.Name, string(out))
-       }
+       m.Namespace = getNamespace(m.Namespace)
+       cm, cmErr := PurgeConfigMap(m)
 
-       cm, cmErr := h.cm.PurgeConfigMap(m)
-       out, err = h.Run(getInstallArgs(m, false))
+       ns := " --namespace=" + m.Namespace
+       rname := viper.GetString("helm.repo-name")
+       out, err = h.Run(strings.Join([]string{"install ", rname, "/", m.Name, " --name ", m.Name, ns}, ""))
        if err != nil {
                return
        }
 
        if cmErr == nil {
-               cmErr = h.cm.RestoreConfigMap(m, cm)
+               cmErr = RestoreConfigMap(m, cm)
        }
        return h.ParseStatus(m.Name, string(out))
 }
 
 func (h *Helm) Status(name string) (xapp Xapp, err error) {
+
        out, err := h.Run(strings.Join([]string{"status ", name}, ""))
        if err != nil {
                mdclog(MdclogErr, formatLog("Getting xapps status", "", err.Error()))
@@ -196,6 +184,7 @@ func (h *Helm) StatusAll() (xapps []Xapp, err error) {
 }
 
 func (h *Helm) List() (names []string, err error) {
+
        ns := getNamespace("")
        out, err := h.Run(strings.Join([]string{"list --all --output yaml --namespace=", ns}, ""))
        if err != nil {
@@ -230,6 +219,7 @@ func (h *Helm) Fetch(name, tarDir string) error {
 
 // Helper functions
 func (h *Helm) GetVersion(name string) (version string) {
+
        ns := getNamespace("")
        out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
        if err != nil {
@@ -293,7 +283,7 @@ func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs Messag
                return
        }
 
-       re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
+       re := regexp.MustCompile(name + "-(\\d+).*")
        resources := re.FindAllStringSubmatch(string(result[0]), -1)
        if resources != nil {
                for _, v := range resources {
@@ -310,11 +300,21 @@ func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs Messag
 }
 
 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
+
        xapp.Name = name
        xapp.Version = h.GetVersion(name)
        xapp.Status = h.GetState(out)
 
-       h.FillInstanceData(name, out, &xapp, h.cm.GetMessages(name))
+       types, err := GetMessages(name)
+       if err != nil {
+               // xAPP can still be deployed if the msg_type file is missing.
+               mdclog(MdclogWarn, formatLog("GetMessages Failed....", "", err.Error()))
+
+               //Set err back to nil, so it does not cause issues in called functions.
+               err = nil
+       }
+
+       h.FillInstanceData(name, out, &xapp, types)
 
        return
 }
@@ -333,6 +333,7 @@ func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
 }
 
 func addTillerEnv() (err error) {
+
        service := viper.GetString("helm.tiller-service")
        namespace := viper.GetString("helm.tiller-namespace")
        port := viper.GetString("helm.tiller-port")
@@ -356,30 +357,6 @@ func getNamespace(namespace string) string {
        return ns
 }
 
-func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
-       x.Namespace = getNamespace(x.Namespace)
-       args = args + " --namespace=" + x.Namespace
-
-       if x.ImageRepo != "" {
-               args = args + " --set image.repository=" + x.ImageRepo
-       }
-
-       if x.ServiceName != "" {
-               args = args + " --set service.name=" + x.ServiceName
-       }
-
-       if x.Hostname != "" {
-               args = args + " --set hostname=" + x.Hostname
-       }
-
-       if cmOverride == true {
-               args = args + " --set appconfig.override=true"
-       }
-
-       rname := viper.GetString("helm.repo-name")
-       return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)
-}
-
 func formatLog(text string, args string, err string) string {
        return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)
 }
diff --git a/cmd/appmgr/helm_test.go b/cmd/appmgr/helm_test.go
deleted file mode 100755 (executable)
index c3ac3c5..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
-==================================================================================
-  Copyright (c) 2019 AT&T Intellectual Property.
-  Copyright (c) 2019 Nokia
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================================
-*/
-
-package main
-
-import (
-    "testing"
-    "reflect"
-)
-
-
-var helmStatusOutput = `
-LAST DEPLOYED: Sat Mar  9 06:50:45 2019
-NAMESPACE: default
-STATUS: DEPLOYED
-
-RESOURCES:
-==> v1/Pod(related)
-NAME                        READY  STATUS   RESTARTS  AGE
-dummy-xapp-8984fc9fd-bkcbp  1/1    Running  0         55m
-dummy-xapp-8984fc9fd-l6xch  1/1    Running  0         55m
-dummy-xapp-8984fc9fd-pp4hg  1/1    Running  0         55m
-
-==> v1/Service
-NAME                         TYPE       CLUSTER-IP      EXTERNAL-IP  PORT(S)  AGE
-dummy-xapp-dummy-xapp-chart  ClusterIP  10.102.184.212  <none>       80/TCP   55m
-
-==> v1beta1/Deployment
-NAME        READY  UP-TO-DATE  AVAILABLE  AGE
-dummy-xapp  3/3    3           3          55m
-`
-
-var helListOutput = `Next: ""
-Releases:
-- AppVersion: "1.0"
-  Chart: dummy-xapp-chart-0.1.0
-  Name: dummy-xapp
-  Namespace: default
-  Revision: 1
-  Status: DEPLOYED
-  Updated: Mon Mar 11 06:55:05 2019
-- AppVersion: "2.0"
-  Chart: dummy-xapp-chart-0.1.0
-  Name: dummy-xapp2
-  Namespace: default
-  Revision: 1
-  Status: DEPLOYED
-  Updated: Mon Mar 11 06:55:05 2019
-- AppVersion: "1.0"
-  Chart: appmgr-0.0.1
-  Name: appmgr
-  Namespace: default
-  Revision: 1
-  Status: DEPLOYED
-  Updated: Sun Mar 24 07:17:00 2019`
-
-
-var h = Helm{}
-
-func TestHelmStatus(t *testing.T) {
-       h.SetCM(&ConfigMap{})
-       xapp, err := h.ParseStatus("dummy-xapp", helmStatusOutput)
-    if err != nil {
-        t.Errorf("Helm install failed: %v", err)
-       }
-
-    x := getXappData()
-    xapp.Version = "1.0"
-
-    if !reflect.DeepEqual(xapp, x) {
-        t.Errorf("\n%v \n%v", xapp, x)
-    }
-}
-
-func TestHelmLists(t *testing.T) {
-    names, err := h.GetNames(helListOutput)
-    if err != nil {
-        t.Errorf("Helm status failed: %v", err)
-       }
-
-    if !reflect.DeepEqual(names, []string{"dummy-xapp", "dummy-xapp2"}) {
-        t.Errorf("Helm status failed: %v", err)
-    }
-}
-
-func TestHelmNamespace(t *testing.T) {
-    if getNamespace("pltxapp") != "pltxapp" {
-        t.Errorf("getNamespace failed!")
-       }
-
-    if getNamespace("") != "ricxapp" {
-        t.Errorf("getNamespace failed!")
-       }
-}
-
-func TestAddTillerEnv(t *testing.T) {
-    if addTillerEnv() != nil {
-        t.Errorf("TestAddTillerEnv failed!")
-       }
-}
-
-func TestGetInstallArgs(t *testing.T) {
-       x := XappDeploy{Name: "dummy-xapp"}
-
-       expectedArgs := "install helm-repo/dummy-xapp --name=dummy-xapp  --namespace=ricxapp"
-       if args := getInstallArgs(x, false); args != expectedArgs {
-        t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
-       }
-
-       x.ImageRepo = "localhost:5000"
-       expectedArgs = expectedArgs + " --set image.repository=" + "localhost:5000"
-       if args := getInstallArgs(x, false); args != expectedArgs {
-        t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
-       }
-
-       x.ServiceName = "xapp"
-       expectedArgs = expectedArgs + " --set service.name=" + "xapp"
-       if args := getInstallArgs(x, false); args != expectedArgs {
-        t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
-       }
-
-       x.ServiceName = "xapp"
-       expectedArgs = expectedArgs + " --set appconfig.override=true"
-       if args := getInstallArgs(x, true); args != expectedArgs {
-        t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
-       }
-}
-
-func getXappData() (x Xapp) {
-    x = generateXapp("dummy-xapp", "deployed", "1.0", "dummy-xapp-8984fc9fd-bkcbp", "running", "10.102.184.212", "80")
-    x.Instances = append(x.Instances, x.Instances[0])
-    x.Instances = append(x.Instances, x.Instances[0])
-    x.Instances[1].Name = "dummy-xapp-8984fc9fd-l6xch"
-    x.Instances[2].Name = "dummy-xapp-8984fc9fd-pp4hg"
-
-    return x
-}
-
index 9b9eebb..da50681 100755 (executable)
@@ -25,7 +25,7 @@ func main() {
        loadConfig()
 
        m := XappManager{}
-       m.Initialize(&Helm{}, &ConfigMap{})
+       m.Initialize(&Helm{})
 
        m.Run()
 }
index 2e0f547..243179d 100755 (executable)
@@ -38,10 +38,12 @@ type Resource struct {
 }
 
 type Xapp struct {
-       Name      string         `json:"name"`
-       Status    string         `json:"status"`
-       Version   string         `json:"version"`
-       Instances []XappInstance `json:"instances"`
+       Name       string         `json:"name"`
+       ConfigName string         `json:"configName, omitempty"`
+       Namespace  string         `json:"namespace, omitempty"`
+       Status     string         `json:"status"`
+       Version    string         `json:"version"`
+       Instances  []XappInstance `json:"instances"`
 }
 
 type XappInstance struct {
@@ -53,40 +55,17 @@ type XappInstance struct {
        RxMessages []string `json:"rxMessages"`
 }
 
-type XappDeploy struct {
-       Name        string `json:"name"`
-       ConfigName  string `json:"configName, omitempty"`
-       Namespace   string `json:"namespace, omitempty"`
-       ServiceName string `json:"serviceName, omitempty"`
-       ImageRepo   string `json:"imageRepo, omitempty"`
-       Hostname    string `json:"hostname, omitempty"`
-}
-
 type XappManager struct {
        router *mux.Router
        helm   Helmer
-       cm     ConfigMapper
        sd     SubscriptionDispatcher
        opts   CmdOptions
        ready  bool
 }
 
-type ConfigMapper interface {
-       UploadConfig() (cfg []XAppConfig)
-       CreateConfigMap(r XAppConfig) (errList []CMError, err error)
-       UpdateConfigMap(r XAppConfig) (errList []CMError, err error)
-       DeleteConfigMap(r XAppConfig) (cm interface{}, err error)
-       PurgeConfigMap(m XappDeploy) (cm interface{}, err error)
-       RestoreConfigMap(m XappDeploy, cm interface{}) (err error)
-       ReadConfigMap(name string, ns string, c *interface{}) (err error)
-       ApplyConfigMap(r XAppConfig, action string) (err error)
-       GetMessages(name string) (msgs MessageTypes)
-}
-
 type Helmer interface {
-       SetCM(ConfigMapper)
        Initialize()
-       Install(m XappDeploy) (xapp Xapp, err error)
+       Install(m ConfigMetadata) (xapp Xapp, err error)
        Status(name string) (xapp Xapp, err error)
        StatusAll() (xapps []Xapp, err error)
        List() (xapps []string, err error)
@@ -97,7 +76,6 @@ type Helm struct {
        host      string
        chartPath string
        initDone  bool
-       cm        ConfigMapper
 }
 
 type SubscriptionReq struct {
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100755 (executable)
index 0000000..3277037
--- /dev/null
@@ -0,0 +1,171 @@
+#   Copyright (c) 2019 AT&T Intellectual Property.
+#   Copyright (c) 2019 Nokia.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+#----------------------------------------------------------
+#
+#----------------------------------------------------------
+FROM ubuntu:16.04 as ubuntubase
+
+RUN apt-get update -y && \
+    apt-get install -y wget
+
+
+RUN sed -i -e "s,http://archive.ubuntu.com/ubuntu,$(wget -qO - mirrors.ubuntu.com/mirrors.txt | head -1)," /etc/apt/sources.list
+RUN sed -i -e "s,http://security.ubuntu.com/ubuntu,$(wget -qO - mirrors.ubuntu.com/mirrors.txt | head -1)," /etc/apt/sources.list
+
+#
+# packages
+#
+RUN apt-get update -y && \
+    apt-get upgrade -y && \
+    apt-get install -y \
+    build-essential \
+    apt-utils \
+    cmake \
+    make \
+    autoconf \
+    autoconf-archive \
+    gawk \
+    libtool \
+    automake \
+    pkg-config \
+    sudo \
+    wget \
+    nano \
+    git \
+    jq
+
+#
+# go
+#
+RUN wget https://dl.google.com/go/go1.12.linux-amd64.tar.gz && \
+       tar -C /usr/local -xvf ./go1.12.linux-amd64.tar.gz
+
+ENV PATH="/usr/local/go/bin:${PATH}"
+
+#
+# rancodev libs
+#
+RUN mkdir -p /opt/build \
+    && cd /opt/build && git clone https://gerrit.oran-osc.org/r/com/log \
+    && cd log/ ; ./autogen.sh ; ./configure ; make ; make install \
+    && ldconfig
+
+#----------------------------------------------------------
+#
+#----------------------------------------------------------
+FROM ubuntubase as builder
+
+ARG PACKAGEURL=gerrit.oran-osc.org/r/ric-plt/appmgr
+ARG HELMVERSION=v2.13.0-rc.1
+
+#
+# helm
+#
+RUN wget https://storage.googleapis.com/kubernetes-helm/helm-${HELMVERSION}-linux-amd64.tar.gz \
+    && tar -zxvf helm-${HELMVERSION}-linux-amd64.tar.gz \
+    && cp linux-amd64/helm /usr/bin/helm \
+    && rm -rf helm-${HELMVERSION}-linux-amd64.tar.gz \
+    && rm -rf linux-amd64
+
+
+#
+# appmgr codes
+#
+RUN mkdir -p /go/src/${PACKAGEURL}
+ENV GOPATH="/go"
+
+#
+# Speed up things by generating layer with needed go packages
+#
+RUN go get github.com/gorilla/mux \
+    && go get github.com/spf13/viper \
+    && go get github.com/gorilla/mux \
+    && go get github.com/orcaman/concurrent-map \
+    && go get github.com/segmentio/ksuid \
+    && go get gopkg.in/yaml.v2
+
+
+COPY . /go/src/${PACKAGEURL}
+
+
+#
+# build
+#
+RUN make -C /go/src/${PACKAGEURL} build
+
+
+#----------------------------------------------------------
+#
+#----------------------------------------------------------
+FROM builder as test_unit
+ARG PACKAGEURL=gerrit.oran-osc.org/r/ric-plt/appmgr
+WORKDIR "/go/src/${PACKAGEURL}"
+CMD ["make","test"]
+
+
+#----------------------------------------------------------
+#
+#----------------------------------------------------------
+FROM builder as test_fmt
+ARG PACKAGEURL=gerrit.oran-osc.org/r/ric-plt/appmgr
+WORKDIR "/go/src/${PACKAGEURL}"
+CMD ["make","test-fmt"]
+
+#----------------------------------------------------------
+#
+#----------------------------------------------------------
+FROM builder as test_sanity
+ARG PACKAGEURL=gerrit.oran-osc.org/r/ric-plt/appmgr
+WORKDIR "/go/src/${PACKAGEURL}"
+CMD ["jq","-s",".", "api/appmgr_rest_api.json"]
+
+
+#----------------------------------------------------------
+#
+#----------------------------------------------------------
+FROM ubuntu:16.04 as release
+ARG PACKAGEURL=gerrit.oran-osc.org/r/ric-plt/appmgr
+
+RUN apt-get update -y \
+    && apt-get install -y sudo openssl ca-certificates ca-cacert \
+    && apt-get clean
+
+
+#
+# libraries and helm
+#
+COPY --from=builder /usr/local/include/ /usr/local/include/
+COPY --from=builder /usr/local/lib/ /usr/local/lib/
+COPY --from=builder /usr/bin/helm /usr/bin/helm
+
+RUN ldconfig
+
+#
+# xApp
+#
+RUN mkdir -p /opt/xAppManager \
+    && chmod -R 755 /opt/xAppManager
+
+COPY --from=builder /go/src/${PACKAGEURL}/build/appmgr /opt/xAppManager/appmgr
+#COPY --from=builder /go/src/${PACKAGEURL}/config/appmgr.yaml /opt/etc/xAppManager/config-file.yaml
+
+
+COPY docker/docker-entrypoint.sh /opt/xAppManager/
+
+WORKDIR /opt/xAppManager
+
+ENTRYPOINT ["/opt/xAppManager/docker-entrypoint.sh"]
diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh
new file mode 100755 (executable)
index 0000000..80e99df
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+#   Copyright (c) 2019 AT&T Intellectual Property.
+#   Copyright (c) 2019 Nokia.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+
+cp /opt/ric/config/appmgr.yaml /opt/xAppManager/config-file.yaml
+
+# Copy all certificates from mounted folder to root system
+cp /opt/ric/certificates/* /etc/ssl/certs
+
+# Start services, etc.
+/opt/xAppManager/appmgr -f /opt/xAppManager/config-file.yaml
diff --git a/go.mod b/go.mod
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/go.sum b/go.sum
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/internal/sdlgo/LICENSE.txt b/internal/sdlgo/LICENSE.txt
new file mode 100644 (file)
index 0000000..f886a1f
--- /dev/null
@@ -0,0 +1,204 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright (c) 2019 AT&T Intellectual Property.
+
+   Copyright (c) 2019 Nokia.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/internal/sdlgo/README b/internal/sdlgo/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/internal/sdlgo/bench_test.go b/internal/sdlgo/bench_test.go
new file mode 100644 (file)
index 0000000..9f70fe6
--- /dev/null
@@ -0,0 +1,173 @@
+package sdlgo_test
+
+import (
+       "fmt"
+       "strconv"
+       "strings"
+       "testing"
+
+       "gitlabe1.ext.net.nokia.com/ric_dev/sdlgo"
+)
+
+type singleBenchmark struct {
+       key       string
+       keySize   int
+       valueSize int
+}
+
+type multiBenchmark struct {
+       keyBase   string
+       keyCount  int
+       keySize   int
+       valueSize int
+}
+
+func (bm singleBenchmark) String(oper string) string {
+       return fmt.Sprintf("op = %s key=%d value=%d", oper, bm.keySize, bm.valueSize)
+}
+
+func (bm multiBenchmark) String(oper string) string {
+       return fmt.Sprintf("op = %s keycnt=%d key=%d value=%d", oper, bm.keyCount, bm.keySize, bm.valueSize)
+}
+func BenchmarkSet(b *testing.B) {
+       benchmarks := []singleBenchmark{
+               {"a", 10, 64},
+               {"b", 10, 1024},
+               {"c", 10, 64 * 1024},
+               {"d", 10, 1024 * 1024},
+               {"e", 10, 10 * 1024 * 1024},
+
+               {"f", 100, 64},
+               {"g", 100, 1024},
+               {"h", 100, 64 * 1024},
+               {"i", 100, 1024 * 1024},
+               {"j", 100, 10 * 1024 * 1024},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("set"), func(b *testing.B) {
+                       key := strings.Repeat(bm.key, bm.keySize)
+                       value := strings.Repeat("1", bm.valueSize)
+                       sdl := sdlgo.Create("namespace")
+
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       err := sdl.Set(key, value)
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
+func BenchmarkGet(b *testing.B) {
+       benchmarks := []singleBenchmark{
+               {"a", 10, 64},
+               {"b", 10, 1024},
+               {"c", 10, 64 * 1024},
+               {"d", 10, 1024 * 1024},
+               {"e", 10, 10 * 1024 * 1024},
+
+               {"f", 100, 64},
+               {"g", 100, 1024},
+               {"h", 100, 64 * 1024},
+               {"i", 100, 1024 * 1024},
+               {"j", 100, 10 * 1024 * 1024},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("Get"), func(b *testing.B) {
+                       key := strings.Repeat(bm.key, bm.keySize)
+                       value := strings.Repeat("1", bm.valueSize)
+                       sdl := sdlgo.Create("namespace")
+                       if err := sdl.Set(key, value); err != nil {
+                               b.Fatal(err)
+                       }
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       _, err := sdl.Get([]string{key})
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
+func BenchmarkMultiSet(b *testing.B) {
+       benchmarks := []multiBenchmark{
+               {"a", 2, 10, 64},
+               {"b", 10, 10, 64},
+               {"c", 100, 10, 64},
+               {"d", 1000, 10, 64},
+               {"e", 5000, 10, 64},
+
+               {"f", 2, 100, 64},
+               {"g", 10, 100, 64},
+               {"h", 100, 100, 64},
+               {"i", 1000, 100, 64},
+               {"j", 5000, 100, 64},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("mset"), func(b *testing.B) {
+                       sdl := sdlgo.Create("namespace")
+                       value := strings.Repeat("1", bm.valueSize)
+                       keyVals := make([]string, 0)
+                       for i := 0; i < bm.keyCount; i++ {
+                               key := strings.Repeat(bm.keyBase+strconv.Itoa(i), bm.keySize)
+                               keyVals = append(keyVals, key, value)
+                       }
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       err := sdl.Set(keyVals)
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
+func BenchmarkMultiGet(b *testing.B) {
+       benchmarks := []multiBenchmark{
+               {"a", 2, 10, 64},
+               {"b", 10, 10, 64},
+               {"c", 100, 10, 64},
+               {"d", 1000, 10, 64},
+               {"e", 5000, 10, 64},
+
+               {"f", 2, 100, 64},
+               {"g", 10, 100, 64},
+               {"h", 100, 100, 64},
+               {"i", 1000, 100, 64},
+               {"j", 5000, 100, 64},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("gset"), func(b *testing.B) {
+                       sdl := sdlgo.Create("namespace")
+                       keyVals := make([]string, 0)
+                       for i := 0; i < bm.keyCount; i++ {
+                               key := strings.Repeat(bm.keyBase+strconv.Itoa(i), bm.keySize)
+                               keyVals = append(keyVals, key)
+                       }
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       _, err := sdl.Get(keyVals)
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
diff --git a/internal/sdlgo/go.mod b/internal/sdlgo/go.mod
new file mode 100644 (file)
index 0000000..d46db31
--- /dev/null
@@ -0,0 +1,12 @@
+module gerrit.oran-osc.org/r/ric-plt/sdlgo
+
+go 1.12
+
+require (
+       github.com/go-redis/redis v6.15.2+incompatible
+       github.com/onsi/ginkgo v1.8.0 // indirect
+       github.com/onsi/gomega v1.5.0 // indirect
+       github.com/stretchr/testify v1.3.0
+)
+
+replace gerrit.oran-osc.org/r/ric-plt/sdlgo/internal/sdlgoredis => ./internal/sdlgoredis
diff --git a/internal/sdlgo/go.sum b/internal/sdlgo/go.sum
new file mode 100644 (file)
index 0000000..a6e2f77
--- /dev/null
@@ -0,0 +1,37 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
+github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
+github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/sdlgo/internal/sdlgoredis/sdlgoredis.go b/internal/sdlgo/internal/sdlgoredis/sdlgoredis.go
new file mode 100644 (file)
index 0000000..2037496
--- /dev/null
@@ -0,0 +1,58 @@
+package sdlgoredis
+
+import (
+       "os"
+
+       "github.com/go-redis/redis"
+)
+
+type DB struct {
+       client *redis.Client
+}
+
+func Create() *DB {
+       hostname := os.Getenv("DBAAS_SERVICE_HOST")
+       if hostname == "" {
+               hostname = "localhost"
+       }
+       port := os.Getenv("DBAAS_SERVICE_PORT")
+       if port == "" {
+               port = "6379"
+       }
+       redisAddress := hostname + ":" + port
+       client := redis.NewClient(&redis.Options{
+               Addr:     redisAddress,
+               Password: "", // no password set
+               DB:       0,  // use default DB
+               PoolSize: 20,
+       })
+
+       db := DB{
+               client: client,
+       }
+
+       return &db
+}
+
+func (db *DB) Close() error {
+       return db.Close()
+}
+
+func (db *DB) MSet(pairs ...interface{}) error {
+       return db.client.MSet(pairs...).Err()
+}
+
+func (db *DB) MGet(keys []string) ([]interface{}, error) {
+       val, err := db.client.MGet(keys...).Result()
+       return val, err
+}
+
+func (db *DB) Del(keys []string) error {
+       _, err := db.client.Del(keys...).Result()
+       return err
+}
+
+func (db *DB) Keys(pattern string) ([]string, error) {
+       val, err := db.client.Keys(pattern).Result()
+       return val, err
+}
diff --git a/internal/sdlgo/sdl.go b/internal/sdlgo/sdl.go
new file mode 100644 (file)
index 0000000..cdf50f9
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package sdlgo
+
+import (
+       "reflect"
+       "strings"
+
+       "gerrit.oran-osc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
+)
+
+type Idatabase interface {
+       MSet(pairs ...interface{}) error
+       MGet(keys []string) ([]interface{}, error)
+       Close() error
+       Del(keys []string) error
+       Keys(key string) ([]string, error)
+}
+
+type SdlInstance struct {
+       NameSpace string
+       NsPrefix  string
+       Idatabase
+}
+
+func Create(NameSpace string) *SdlInstance {
+       db := sdlgoredis.Create()
+       s := SdlInstance{
+               NameSpace: NameSpace,
+               NsPrefix:  "{" + NameSpace + "},",
+               Idatabase: db,
+       }
+
+       return &s
+}
+
+func (s *SdlInstance) Close() error {
+       return s.Close()
+}
+
+func (s *SdlInstance) setNamespaceToKeys(pairs ...interface{}) []interface{} {
+       var retVal []interface{}
+       for i, v := range pairs {
+               if i%2 == 0 {
+                       reflectType := reflect.TypeOf(v)
+                       switch reflectType.Kind() {
+                       case reflect.Slice:
+                               x := reflect.ValueOf(v)
+                               for i2 := 0; i2 < x.Len(); i2++ {
+                                       if i2%2 == 0 {
+                                               retVal = append(retVal, s.NsPrefix+x.Index(i2).Interface().(string))
+                                       } else {
+                                               retVal = append(retVal, x.Index(i2).Interface())
+                                       }
+                               }
+                       case reflect.Array:
+                               x := reflect.ValueOf(v)
+                               for i2 := 0; i2 < x.Len(); i2++ {
+                                       if i2%2 == 0 {
+                                               retVal = append(retVal, s.NsPrefix+x.Index(i2).Interface().(string))
+                                       } else {
+                                               retVal = append(retVal, x.Index(i2).Interface())
+                                       }
+                               }
+                       default:
+                               retVal = append(retVal, s.NsPrefix+v.(string))
+                       }
+               } else {
+                       retVal = append(retVal, v)
+               }
+       }
+       return retVal
+}
+
+func (s *SdlInstance) Set(pairs ...interface{}) error {
+       if len(pairs) == 0 {
+               return nil
+       }
+
+       keyAndData := s.setNamespaceToKeys(pairs...)
+       err := s.MSet(keyAndData...)
+       return err
+}
+
+func (s *SdlInstance) Get(keys []string) (map[string]interface{}, error) {
+       m := make(map[string]interface{})
+       if len(keys) == 0 {
+               return m, nil
+       }
+
+       var keysWithNs []string
+       for _, v := range keys {
+               keysWithNs = append(keysWithNs, s.NsPrefix+v)
+       }
+       val, err := s.MGet(keysWithNs)
+       if err != nil {
+               return m, err
+       }
+       for i, v := range val {
+               m[keys[i]] = v
+       }
+       return m, err
+}
+
+func (s *SdlInstance) SetIf(key string, oldData, newData interface{}) {
+       panic("SetIf not implemented\n")
+}
+
+func (s *SdlInstance) SetIfiNotExists(key string, data interface{}) {
+       panic("SetIfiNotExists not implemented\n")
+}
+
+func (s *SdlInstance) Remove(keys []string) error {
+       if len(keys) == 0 {
+               return nil
+       }
+
+       var keysWithNs []string
+       for _, v := range keys {
+               keysWithNs = append(keysWithNs, s.NsPrefix+v)
+       }
+       err := s.Del(keysWithNs)
+       return err
+}
+
+func (s *SdlInstance) RemoveIf(key string, data interface{}) {
+       panic("RemoveIf not implemented\n")
+}
+
+func (s *SdlInstance) GetAll() ([]string, error) {
+       keys, err := s.Keys(s.NsPrefix + "*")
+       var retVal []string = nil
+       if err != nil {
+               return retVal, err
+       }
+       for _, v := range keys {
+               retVal = append(retVal, strings.Split(v, s.NsPrefix)[1])
+       }
+       return retVal, err
+}
+
+func (s *SdlInstance) RemoveAll() error {
+       keys, err := s.Keys(s.NsPrefix + "*")
+       if err != nil {
+               return err
+       }
+       if keys != nil {
+               err = s.Del(keys)
+       }
+       return err
+}
diff --git a/internal/sdlgo/sdl_test.go b/internal/sdlgo/sdl_test.go
new file mode 100644 (file)
index 0000000..8c64d05
--- /dev/null
@@ -0,0 +1,297 @@
+package sdlgo_test
+
+import (
+       "errors"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/mock"
+       "gerrit.oran-osc.org/r/ric-plt/sdlgo"
+)
+
+type mockDB struct {
+       mock.Mock
+}
+
+func (m *mockDB) MSet(pairs ...interface{}) error {
+       a := m.Called(pairs)
+       return a.Error(0)
+}
+
+func (m *mockDB) MGet(keys []string) ([]interface{}, error) {
+       a := m.Called(keys)
+       return a.Get(0).([]interface{}), a.Error(1)
+}
+
+func (m *mockDB) Close() error {
+       a := m.Called()
+       return a.Error(0)
+}
+
+func (m *mockDB) Del(keys []string) error {
+       a := m.Called(keys)
+       return a.Error(0)
+}
+
+func (m *mockDB) Keys(pattern string) ([]string, error) {
+       a := m.Called(pattern)
+       return a.Get(0).([]string), a.Error(1)
+}
+
+func setup() (*mockDB, *sdlgo.SdlInstance) {
+       m := new(mockDB)
+       i := &sdlgo.SdlInstance{
+               NameSpace: "namespace",
+               NsPrefix:  "{namespace},",
+               Idatabase: m,
+       }
+       return m, i
+}
+
+func TestGetOneKey(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key"}
+       mReturn := []interface{}{"somevalue"}
+       mReturnExpected := make(map[string]interface{})
+       mReturnExpected["key"] = "somevalue"
+
+       m.On("MGet", mgetExpected).Return(mReturn, nil)
+       retVal, err := i.Get([]string{"key"})
+       assert.Nil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetSeveralKeys(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key1", "{namespace},key2", "{namespace},key3"}
+       mReturn := []interface{}{"somevalue1", 2, "someothervalue"}
+       mReturnExpected := make(map[string]interface{})
+       mReturnExpected["key1"] = "somevalue1"
+       mReturnExpected["key2"] = 2
+       mReturnExpected["key3"] = "someothervalue"
+
+       m.On("MGet", mgetExpected).Return(mReturn, nil)
+       retVal, err := i.Get([]string{"key1", "key2", "key3"})
+       assert.Nil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetSeveralKeysSomeFail(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key1", "{namespace},key2", "{namespace},key3"}
+       mReturn := []interface{}{"somevalue1", nil, "someothervalue"}
+       mReturnExpected := make(map[string]interface{})
+       mReturnExpected["key1"] = "somevalue1"
+       mReturnExpected["key2"] = nil
+       mReturnExpected["key3"] = "someothervalue"
+
+       m.On("MGet", mgetExpected).Return(mReturn, nil)
+       retVal, err := i.Get([]string{"key1", "key2", "key3"})
+       assert.Nil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetKeyReturnError(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key"}
+       mReturn := []interface{}{nil}
+       mReturnExpected := make(map[string]interface{})
+
+       m.On("MGet", mgetExpected).Return(mReturn, errors.New("Some error"))
+       retVal, err := i.Get([]string{"key"})
+       assert.NotNil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetEmptyList(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{}
+
+       retval, err := i.Get([]string{})
+       assert.Nil(t, err)
+       assert.Len(t, retval, 0)
+       m.AssertNotCalled(t, "MGet", mgetExpected)
+}
+
+func TestWriteOneKey(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1"}
+
+       m.On("MSet", msetExpected).Return(nil)
+       err := i.Set("key1", "data1")
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestWriteSeveralKeysSlice(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1", "{namespace},key2", 22}
+
+       m.On("MSet", msetExpected).Return(nil)
+       err := i.Set([]interface{}{"key1", "data1", "key2", 22})
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+
+}
+
+func TestWriteSeveralKeysArray(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1", "{namespace},key2", "data2"}
+
+       m.On("MSet", msetExpected).Return(nil)
+       err := i.Set([4]string{"key1", "data1", "key2", "data2"})
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestWriteFail(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1"}
+
+       m.On("MSet", msetExpected).Return(errors.New("Some error"))
+       err := i.Set("key1", "data1")
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestWriteEmptyList(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{}
+       err := i.Set()
+       assert.Nil(t, err)
+       m.AssertNotCalled(t, "MSet", msetExpected)
+}
+
+func TestRemoveSuccessfully(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []string{"{namespace},key1", "{namespace},key2"}
+       m.On("Del", msetExpected).Return(nil)
+
+       err := i.Remove([]string{"key1", "key2"})
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveFail(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []string{"{namespace},key"}
+       m.On("Del", msetExpected).Return(errors.New("Some error"))
+
+       err := i.Remove([]string{"key"})
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveEmptyList(t *testing.T) {
+       m, i := setup()
+
+       err := i.Remove([]string{})
+       assert.Nil(t, err)
+       m.AssertNotCalled(t, "Del", []string{})
+}
+
+func TestGetAllSuccessfully(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mReturnExpected := []string{"{namespace},key1", "{namespace},key2"}
+       expectedReturn := []string{"key1", "key2"}
+       m.On("Keys", mKeysExpected).Return(mReturnExpected, nil)
+       retVal, err := i.GetAll()
+       assert.Nil(t, err)
+       assert.Equal(t, expectedReturn, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetAllFail(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mReturnExpected := []string{}
+       m.On("Keys", mKeysExpected).Return(mReturnExpected, errors.New("some error"))
+       retVal, err := i.GetAll()
+       assert.NotNil(t, err)
+       assert.Nil(t, retVal)
+       assert.Equal(t, len(retVal), 0)
+       m.AssertExpectations(t)
+}
+
+func TestGetAllReturnEmpty(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       var mReturnExpected []string = nil
+       m.On("Keys", mKeysExpected).Return(mReturnExpected, nil)
+       retVal, err := i.GetAll()
+       assert.Nil(t, err)
+       assert.Nil(t, retVal)
+       assert.Equal(t, len(retVal), 0)
+       m.AssertExpectations(t)
+
+}
+
+func TestRemoveAllSuccessfully(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mKeysReturn := []string{"{namespace},key1", "{namespace},key2"}
+       mDelExpected := mKeysReturn
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, nil)
+       m.On("Del", mDelExpected).Return(nil)
+       err := i.RemoveAll()
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveAllNoKeysFound(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       var mKeysReturn []string = nil
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, nil)
+       m.AssertNumberOfCalls(t, "Del", 0)
+       err := i.RemoveAll()
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveAllKeysReturnError(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       var mKeysReturn []string = nil
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, errors.New("Some error"))
+       m.AssertNumberOfCalls(t, "Del", 0)
+       err := i.RemoveAll()
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveAllDelReturnError(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mKeysReturn := []string{"{namespace},key1", "{namespace},key2"}
+       mDelExpected := mKeysReturn
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, nil)
+       m.On("Del", mDelExpected).Return(errors.New("Some Error"))
+       err := i.RemoveAll()
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
index 22f0677..ac00485 100755 (executable)
@@ -125,9 +125,6 @@ case $1 in
   (health|heal)
     cmd=health
     ;;
-  (config|upload)
-    cmd=config
-    ;;
   (help)
     usage
     exit 0
@@ -170,7 +167,6 @@ rest() {
   if [ "x$3" != "x" ]; then
     data="--data $3"
   fi
-
   if curl --silent --show-error --connect-timeout 20 --header "Content-Type: application/json" -X $1 -o $resultfile "http://${host}:${port}$2" $data 2> $errfile ;then
     status=0
   else
@@ -192,7 +188,6 @@ base=/ric/v1
 base_xapps=$base/xapps
 base_health=$base/health
 base_subs=$base/subscriptions
-base_config=$base/config
 
 do_deploy() {
   if [ "x$1" != "x" ]; then
@@ -338,40 +333,6 @@ do_subscriptions() {
   esac
 }
 
-do_config() {
-  local urlpath
-  urlpath=$base_config
-  case $1 in
-    (get|list)
-      if [ "x$2" != "x" ]; then
-        urlpath="$urlpath/$2"
-      fi
-      if rest GET $urlpath; then
-        json_reformat < $resultfile
-      else
-        status=1
-      fi
-    ;;
-    (add|update)
-      if rest POST $urlpath "@$2" ; then
-        cat $resultfile
-      else
-        status=1
-    fi
-    ;;
-    (del|delete|remove|rem)
-      if rest DELETE $urlpath "@$2" ; then
-        cat $resultfile
-      else
-        status=1
-    fi
-    ;;
-    (*)
-      echo "$myname: unrecognized config subcommand $1"
-      status=1
-  esac
-}
-
 case $cmd in
   (deploy)
     do_deploy "$2"
@@ -385,9 +346,6 @@ case $cmd in
   (subscriptions)
     do_subscriptions "$2" "$3" "$4" "$5" "$6" "$7"
     ;;
-  (config)
-    do_config "$2" "$3"
-    ;;
   (health)
     if rest GET $base_health ; then
       echo OK
diff --git a/test/schema.json b/test/schema.json
deleted file mode 100755 (executable)
index bc89da8..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-{
-  "definitions": {},
-  "$schema": "http://json-schema.org/draft-07/schema#",
-  "$id": "http://example.com/root.json",
-  "type": "object",
-  "title": "The Root Schema",
-  "required": [
-    "local",
-    "logger"
-  ],
-  "properties": {
-    "local": {
-      "$id": "#/properties/local",
-      "type": "object",
-      "title": "The Local Schema",
-      "required": [
-        "host"
-      ],
-      "properties": {
-        "host": {
-          "$id": "#/properties/local/properties/host",
-          "type": "string",
-          "title": "The Host Schema",
-          "default": "",
-          "pattern": "^(.*)$"
-        }
-      }
-    },
-    "logger": {
-      "$id": "#/properties/logger",
-      "type": "object",
-      "title": "The Logger Schema",
-      "required": [
-        "level"
-      ],
-      "properties": {
-        "level": {
-          "$id": "#/properties/logger/properties/level",
-          "type": "integer",
-          "title": "The Level Schema",
-          "default": 0
-        }
-      }
-    }
-  }
-}
\ No newline at end of file