Adds unit tests and K8s artifacts 53/1753/21
authorenyinna1234 <enyinna.ochulor@intel.com>
Wed, 9 Oct 2019 17:18:22 +0000 (10:18 -0700)
committerKuralamudhan Ramakrishnan <kuralamudhan.ramakrishnan@intel.com>
Wed, 30 Oct 2019 23:39:56 +0000 (23:39 +0000)
This adds unit tests, a Kubernetes Service, and
Deployment to create objects that enable the RESTful API as
a Kubenetes service, and adds end to end testing.

Change-Id: I0439ff51931ac0abe7c5bff8b7d75e8ced19a06f
Signed-off-by: Enyinna Ochulor <enyinna.ochulor@intel.com>
Signed-off-by: Chen, Tingjie <tingjie.chen@intel.com>
19 files changed:
Makefile
cmd/bpa-restapi-agent/Makefile
cmd/bpa-restapi-agent/bpa_api_cluster_role.yml [new file with mode: 0644]
cmd/bpa-restapi-agent/bpa_api_cluster_role_binding.yml [new file with mode: 0644]
cmd/bpa-restapi-agent/bpa_api_install.sh [new file with mode: 0755]
cmd/bpa-restapi-agent/create-service-account.yml [new file with mode: 0644]
cmd/bpa-restapi-agent/e2e_test.sh [new file with mode: 0755]
cmd/bpa-restapi-agent/go.mod
cmd/bpa-restapi-agent/go.sum
cmd/bpa-restapi-agent/install_go.sh [new file with mode: 0755]
cmd/bpa-restapi-agent/internal/app/image.go
cmd/bpa-restapi-agent/internal/app/image_test.go [new file with mode: 0644]
cmd/bpa-restapi-agent/sample.json [deleted file]
cmd/bpa-restapi-agent/service.yml [new file with mode: 0644]
cmd/bpa-restapi-agent/vendor.tar.gz [new file with mode: 0644]
deploy/kud-plugin-addons/minio/install.sh
deploy/kud-plugin-addons/minio/local-pv.yaml
deploy/kud-plugin-addons/minio/local-pvc.yaml
deploy/kud-plugin-addons/minio/local-sc.yaml

index 9260307..950ba51 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,8 @@ BPA_OPERATOR:=$(CURDIR)/cmd/bpa-operator/
 KUD_PATH:=$(CURDIR)/deploy/kud
 SDWAN_VERIFIER_PATH:=$(CURDIR)/sdwan/test
 BPA_E2E_SETUP:=https://raw.githubusercontent.com/onap/multicloud-k8s/master/kud/hosting_providers/vagrant/setup.sh
+BPA_REST_API:=$(CURDIR)/cmd/bpa-restapi-agent
+
 
 help:
        @echo "  Targets:"
@@ -57,6 +59,12 @@ bpa_op_verifier: bpa_op_install bpa_op_e2e
 
 bpa_op_all: bm_all bpa_op_install
 
+bpa_rest_api_install:
+       pushd $(BPA_REST_API) && make deploy && popd
+
+bpa_rest_api_verifier:
+       pushd $(BPA_REST_API) && make e2e_test && popd
+
 bashate:
        bashate -i E006,E003,E002,E010,E011,E042,E043 `find . -type f -not -path './cmd/bpa-operator/vendor/*' -name *.sh`
 
@@ -66,7 +74,8 @@ prerequisite:
 verify_all: prerequisite \
        metal3_prerequisite \
        kud_bm_deploy_mini \
-       metal3_vm
+       metal3_vm \
+       bpa_rest_api_verifier
 
 verifier: verify_all
 
index 2e70365..6b41947 100644 (file)
@@ -1,32 +1,22 @@
-
-# # The name of the executable (default is current directory name)
-# TARGET := $(shell echo $${PWD\#\#*/})
-# .DEFAULT_GOAL: $(TARGET)
-#
-# # These will be provided to the target
-# VERSION := 1.0.0
-# BUILD := `git rev-parse HEAD`
-#
-# # Use linker flags to provide version/build settings to the target
-# LDFLAGS=-ldflags "-X=main.Version=$(VERSION) -X=main.Build=$(BUILD)"
-#
-# # go source files, ignore vendor directory
-# SRC = $(shell find . -type f -name '*.go' -not -path "./vendor/*")
-#
-# .PHONY: all build
-#
-# all: build
-#
-# $(TARGET): $(SRC)
-#      @go build $(LDFLAGS) -o $(TARGET)
-#
-# build: $(TARGET)
-#      @true
-
 .PHONY: build
 
-build:
+build: untar
        go build -mod=vendor -o build/_output/bin/bpa-restapi-agent main.go
 
-docker:
+docker:        
        docker build -t akraino.org/icn/bpa-restapi-agent:latest . -f build/Dockerfile
+
+untar:
+       tar -xzvf vendor.tar.gz
+
+deploy: docker
+       ./bpa_api_install.sh
+
+test:  go_install
+       go test ./... -v
+
+go_install:
+       install_go.sh
+
+e2e_test: deploy
+       ./e2e_test.sh
diff --git a/cmd/bpa-restapi-agent/bpa_api_cluster_role.yml b/cmd/bpa-restapi-agent/bpa_api_cluster_role.yml
new file mode 100644 (file)
index 0000000..e8171ec
--- /dev/null
@@ -0,0 +1,8 @@
+apiVersion: rbac.authorization.k8s.io/v1\r
+kind: ClusterRole\r
+metadata:\r
+  name: do-all\r
+rules:\r
+- apiGroups: ["*"]\r
+  resources: ["*"]\r
+  verbs: ["*"]\r
diff --git a/cmd/bpa-restapi-agent/bpa_api_cluster_role_binding.yml b/cmd/bpa-restapi-agent/bpa_api_cluster_role_binding.yml
new file mode 100644 (file)
index 0000000..eb9649d
--- /dev/null
@@ -0,0 +1,12 @@
+apiVersion: rbac.authorization.k8s.io/v1\r
+kind: ClusterRoleBinding\r
+metadata:\r
+  name: do-all-global\r
+subjects:\r
+- kind: ServiceAccount\r
+  name: bpa-restapi-agent\r
+  namespace: default\r
+roleRef:\r
+  kind: ClusterRole\r
+  name: do-all\r
+  apiGroup: rbac.authorization.k8s.io\r
diff --git a/cmd/bpa-restapi-agent/bpa_api_install.sh b/cmd/bpa-restapi-agent/bpa_api_install.sh
new file mode 100755 (executable)
index 0000000..843727a
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+ICN_DIR=$(dirname "$(dirname "$PWD")")
+
+kubectl apply -f create-service-account.yml
+
+kubectl apply -f bpa_api_cluster_role.yml
+
+kubectl apply -f bpa_api_cluster_role_binding.yml
+
+pushd $ICN_DIR/deploy/kud-plugin-addons/minio
+
+./install.sh
+
+popd
+
+kubectl apply -f service.yml
diff --git a/cmd/bpa-restapi-agent/create-service-account.yml b/cmd/bpa-restapi-agent/create-service-account.yml
new file mode 100644 (file)
index 0000000..3764bb9
--- /dev/null
@@ -0,0 +1,4 @@
+apiVersion: v1\r
+kind: ServiceAccount\r
+metadata:\r
+  name: bpa-restapi-agent\r
diff --git a/cmd/bpa-restapi-agent/e2e_test.sh b/cmd/bpa-restapi-agent/e2e_test.sh
new file mode 100755 (executable)
index 0000000..09c4582
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+ICN_DIR=$(dirname "$(dirname "$PWD")")
+
+source "$ICN_DIR/env/lib/common.sh"
+
+#create sample image
+if true ; then
+    cat <<- EOF > /tmp/sample_image
+    This is a dummy file for testing.
+EOF
+fi
+
+IMAGE_SIZE=$(ls -al /tmp/sample_image | awk '{print $5}')
+
+if true ; then
+    cat <<- EOF > /tmp/sample.json
+    {
+        "owner":  "alpha",
+        "cluster_name": "beta",
+        "type": "container",
+        "image_name": "qwerty123",
+        "image_length": $IMAGE_SIZE,
+        "image_offset": 0,
+        "upload_complete":  false,
+        "description": {
+        "image_records":  [
+            {
+                "image_record_name": "iuysdi1234",
+                "repo": "icn",
+                "tag":  "2"
+            }
+            ]
+        }
+    }
+EOF
+fi
+
+curr_status=""
+
+while [[ $curr_status != "Running" ]]; do
+
+    new_status=$(kubectl get pods | grep bpa-api-deployment | awk '{print $3}')
+    if [[ $new_status != $curr_status ]]; then
+        echo "$(date +%H:%M:%S) - BPA-RESTful-API Pod status: $new_status"
+        curr_status=$new_status
+        if [[ $new_status == "Running" ]]; then
+            break
+        fi
+    fi
+    if [[ $new_status == "Err"* ]]; then
+        exit 1
+    fi
+    sleep 10
+done
+
+
+#Get CLusterIP
+IP=$(kubectl get services | grep bpa-api-service | awk '{print $3}')
+
+call_api -i -F "metadata=</tmp/sample.json;type=application/json" -F \
+file=@/tmp/sample.json -X POST \
+http://$IP:9015/v1/baremetalcluster/alpha/beta/container_images
+
+call_api -i -X GET \
+http://$IP:9015/v1/baremetalcluster/alpha/beta/container_images/qwerty123
+
+call_api --request PATCH --data-binary "@/tmp/sample_image" \
+http://$IP:9015/v1/baremetalcluster/alpha/beta/container_images/qwerty123 \
+--header "Upload-Offset: 0" --header "Expect:" -i
+
+call_api -i -X DELETE \
+http://$IP:9015/v1/baremetalcluster/alpha/beta/container_images/qwerty123
index 4ed8ccb..4cb7124 100644 (file)
@@ -9,6 +9,7 @@ require (
        github.com/gorilla/mux v1.7.3
        github.com/minio/minio-go/v6 v6.0.35
        github.com/pkg/errors v0.8.1
+       github.com/stretchr/testify v1.2.2
        github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
        github.com/xdg/stringprep v1.0.0 // indirect
        go.mongodb.org/mongo-driver v1.0.4
index 0bd1467..877a2c8 100644 (file)
@@ -1,5 +1,6 @@
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/a8m/mark v0.1.1-0.20170507133748-44f2db618845/go.mod h1:c8Mh99Cw82nrsAnPgxQSZHkswVOJF7/MqZb1ZdvriLM=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/gernest/wow v0.1.0/go.mod h1:dEPabJRi5BneI1Nev1VWo0ZlcTWibHWp43qxKms4elY=
@@ -21,11 +22,14 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
 github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
diff --git a/cmd/bpa-restapi-agent/install_go.sh b/cmd/bpa-restapi-agent/install_go.sh
new file mode 100755 (executable)
index 0000000..944a58b
--- /dev/null
@@ -0,0 +1,5 @@
+#1/bin/bash
+
+if which go > /dev/null; then
+    sudo apt-get -yq install golang-go
+fi
index 28cda77..2c117a3 100644 (file)
@@ -1,25 +1,25 @@
 package app
 
 import (
+       "bpa-restapi-agent/internal/db"
        "encoding/json"
        "os"
        "os/user"
        "path"
-       "bpa-restapi-agent/internal/db"
 
        pkgerrors "github.com/pkg/errors"
 )
 
 // Image contains the parameters needed for Image information
 type Image struct {
-       Owner                           string               `json:"owner"`
-       ClusterName         string               `json:"cluster_name"`
-       Type                string               `json:"type"`
-       ImageName           string               `json:"image_name"`
-       ImageOffset                                     *int                                                       `json:"image_offset"`
-       ImageLength                                     int                                                                      `json:"image_length"`
-       UploadComplete                  *bool                                                            `json:"upload_complete"`
-       Description         ImageRecordList      `json:"description"`
+       Owner          string          `json:"owner"`
+       ClusterName    string          `json:"cluster_name"`
+       Type           string          `json:"type"`
+       ImageName      string          `json:"image_name"`
+       ImageOffset    *int            `json:"image_offset"`
+       ImageLength    int             `json:"image_length"`
+       UploadComplete *bool           `json:"upload_complete"`
+       Description    ImageRecordList `json:"description"`
 }
 
 type ImageRecordList struct {
@@ -28,9 +28,7 @@ type ImageRecordList struct {
 
 // ImageKey is the key structure that is used in the database
 type ImageKey struct {
-       // Owner            string     `json:"owner"`
-       // ClusterName      string     `json:"cluster_name"`
-       ImageName        string     `json:"image_name"`
+       ImageName string `json:"image_name"`
 }
 
 // We will use json marshalling to convert to string to
@@ -54,32 +52,56 @@ type ImageManager interface {
        GetDirPath(imageName string) (string, string, error)
 }
 
+// Interface to aid unit test by mocking third party packages
+type Utility interface {
+       GetCurrentUser() (*user.User, error)
+       DBCreate(storeName string, key ImageKey, meta string, c Image) error
+       DBRead(storeName string, key ImageKey, meta string) ([]byte, error)
+       DBUnmarshal(value []byte) (Image, error)
+       OSMakeDir(dirpath string, perm int) error
+       OSCreateFile(filePath string) error
+       GetPath(user *user.User, imageName string, storeName string) (string, string)
+       DBDelete(storeName string, key ImageKey, meta string) error
+       OSRemove(filePath string) error
+       DBUpdate(storeName string, key ImageKey, tagMeta string, c Image) error
+}
+
 // ImageClient implements the ImageManager
 // It will also be used to maintain some localized state
 type ImageClient struct {
+       util      Utility
        storeName string
        tagMeta   string
 }
 
+type DBService struct {
+}
+
 // To Do - Fix repetition in
 // NewImageClient returns an instance of the ImageClient
 // which implements the ImageManager
 func NewBinaryImageClient() *ImageClient {
+    service := DBService{}
        return &ImageClient{
+        util: service,
                storeName: "binary_images",
                tagMeta:   "metadata",
        }
 }
 
 func NewContainerImageClient() *ImageClient {
+    service := DBService{}
        return &ImageClient{
+        util: service,
                storeName: "container_images",
                tagMeta:   "metadata",
        }
 }
 
 func NewOSImageClient() *ImageClient {
+    service := DBService{}
        return &ImageClient{
+        util: service,
                storeName: "os_images",
                tagMeta:   "metadata",
        }
@@ -87,11 +109,8 @@ func NewOSImageClient() *ImageClient {
 
 // Create an entry for the Image resource in the database`
 func (v *ImageClient) Create(c Image) (Image, error) {
-
        //Construct composite key consisting of name
        key := ImageKey{
-               // Owner:       c.Owner,
-               // ClusterName: c.ClusterName,
                ImageName: c.ImageName,
        }
 
@@ -101,12 +120,12 @@ func (v *ImageClient) Create(c Image) (Image, error) {
                return Image{}, pkgerrors.New("Image already exists")
        }
 
-       err = db.DBconn.Create(v.storeName, key, v.tagMeta, c)
+       err = v.util.DBCreate(v.storeName, key, v.tagMeta, c)
        if err != nil {
                return Image{}, pkgerrors.Wrap(err, "Creating DB Entry")
        }
 
-       err = v.CreateFile(v.storeName, c)
+       err = v.CreateFile(c)
        if err != nil {
                return Image{}, pkgerrors.Wrap(err, "Creating File in FS")
        }
@@ -114,28 +133,53 @@ func (v *ImageClient) Create(c Image) (Image, error) {
        return c, nil
 }
 
+func (d DBService) DBCreate(storeName string, key ImageKey, meta string, c Image) error {
+
+       //Construct composite key consisting of name
+       err := db.DBconn.Create(storeName, key, meta, c)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Creating DB Entry")
+       }
+
+       return nil
+}
+
 // Create file
 
-func (v *ImageClient) CreateFile(dirName string, c Image) error {
+func (v *ImageClient) CreateFile(c Image) error {
        filePath, dirPath, err := v.GetDirPath(c.ImageName)
        if err != nil {
                return pkgerrors.Wrap(err, "Get file path")
        }
-  err = os.MkdirAll(dirPath, 0744)
-  if err != nil {
+       err = v.util.OSMakeDir(dirPath, 0744)
+       if err != nil {
                return pkgerrors.Wrap(err, "Make image directory")
-  }
-       file1, err := os.Create(filePath)
+       }
+       err = v.util.OSCreateFile(filePath)
        if err != nil {
                return pkgerrors.Wrap(err, "Create image file")
        }
 
-       defer file1.Close()
-
+       return nil
+}
 
-  return nil
+func (d DBService) OSMakeDir(dirPath string, perm int) error {
+       err := os.MkdirAll(dirPath, 0744)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Make image directory")
+       }
+       return nil
 }
 
+func (d DBService) OSCreateFile(filePath string) error {
+       file1, err := os.Create(filePath)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Create image file")
+       }
+       defer file1.Close()
+
+       return nil
+}
 
 // Get returns Image for corresponding to name
 func (v *ImageClient) Get(imageName string) (Image, error) {
@@ -147,15 +191,14 @@ func (v *ImageClient) Get(imageName string) (Image, error) {
                ImageName: imageName,
        }
 
-       value, err := db.DBconn.Read(v.storeName, key, v.tagMeta)
+       value, err := v.util.DBRead(v.storeName, key, v.tagMeta)
        if err != nil {
                return Image{}, pkgerrors.Wrap(err, "Get Image")
        }
 
        //value is a byte array
        if value != nil {
-               c := Image{}
-               err = db.DBconn.Unmarshal(value, &c)
+               c, err := v.util.DBUnmarshal(value)
                if err != nil {
                        return Image{}, pkgerrors.Wrap(err, "Unmarshaling Value")
                }
@@ -165,6 +208,25 @@ func (v *ImageClient) Get(imageName string) (Image, error) {
        return Image{}, pkgerrors.New("Error getting Connection")
 }
 
+func (d DBService) DBRead(storeName string, key ImageKey, meta string) ([]byte, error) {
+       value, err := db.DBconn.Read(storeName, key, meta)
+       if err != nil {
+               return []byte{}, pkgerrors.Wrap(err, "Get Image")
+       }
+
+       return value, nil
+}
+
+func (d DBService) DBUnmarshal(value []byte) (Image, error) {
+       c := Image{}
+       err := db.DBconn.Unmarshal(value, &c)
+       if err != nil {
+               return Image{}, pkgerrors.Wrap(err, "Unmarshaling Value")
+       }
+
+       return c, nil
+}
+
 func (v *ImageClient) GetImageRecordByName(imgName string,
        imageRecordName string) (map[string]string, error) {
 
@@ -183,13 +245,8 @@ func (v *ImageClient) GetImageRecordByName(imgName string,
 }
 
 func (v *ImageClient) GetDirPath(imageName string) (string, string, error) {
-       u, err := user.Current()
-       if err != nil {
-               return "", "", pkgerrors.Wrap(err, "Current user")
-       }
-       home := u.HomeDir
-       dirPath := path.Join(home, "images", v.storeName)
-       filePath := path.Join(dirPath, imageName)
+       u, err := v.util.GetCurrentUser()
+       filePath, dirPath := v.util.GetPath(u, imageName, v.storeName)
 
        return filePath, dirPath, err
 }
@@ -203,20 +260,33 @@ func (v *ImageClient) Delete(imageName string) error {
                // ClusterName: clusterName,
                ImageName: imageName,
        }
-       err := db.DBconn.Delete(v.storeName, key, v.tagMeta)
-       if err != nil {
-               return pkgerrors.Wrap(err, "Delete Image")
-       }
+       err := v.util.DBDelete(v.storeName, key, v.tagMeta)
 
        //Delete image from FS
        filePath, _, err := v.GetDirPath(imageName)
        if err != nil {
                return pkgerrors.Wrap(err, "Get file path")
        }
-       err = os.Remove(filePath)
+       err = v.util.OSRemove(filePath)
+
+       return nil
+}
+
+func (d DBService) OSRemove(filePath string) error {
+       err := os.Remove(filePath)
        if err != nil {
                return pkgerrors.Wrap(err, "Delete image file")
        }
+
+       return nil
+}
+
+func (d DBService) DBDelete(storeName string, key ImageKey, tagMeta string) error {
+       err := db.DBconn.Delete(storeName, key, tagMeta)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Delete Image")
+       }
+
        return nil
 }
 
@@ -233,10 +303,34 @@ func (v *ImageClient) Update(imageName string, c Image) (Image, error) {
                return Image{}, pkgerrors.New("Update Error - Image doesn't exist")
        }
 
-       err = db.DBconn.Update(v.storeName, key, v.tagMeta, c)
+       err = v.util.DBUpdate(v.storeName, key, v.tagMeta, c)
+
+       return c, nil
+}
+
+func (d DBService) DBUpdate(storeName string, key ImageKey, tagMeta string, c Image) error {
+       err := db.DBconn.Update(storeName, key, tagMeta, c)
        if err != nil {
-               return Image{}, pkgerrors.Wrap(err, "Updating DB Entry")
+               return pkgerrors.Wrap(err, "Updating DB Entry")
        }
 
-       return c, nil
+       return nil
+}
+
+// Define GetCurrentUser
+func (d DBService) GetCurrentUser() (*user.User, error) {
+       u, err := user.Current()
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Current user")
+       }
+
+       return u, nil
+}
+
+func (d DBService) GetPath(user *user.User, imageName string, storeName string) (string, string) {
+       home := user.HomeDir
+       dirPath := path.Join(home, "images", storeName)
+       filePath := path.Join(dirPath, imageName)
+
+       return filePath, dirPath
 }
diff --git a/cmd/bpa-restapi-agent/internal/app/image_test.go b/cmd/bpa-restapi-agent/internal/app/image_test.go
new file mode 100644 (file)
index 0000000..f90a5b3
--- /dev/null
@@ -0,0 +1,164 @@
+package app\r
+\r
+import (\r
+  "fmt"\r
+  "os/user"\r
+  "testing"\r
+\r
+  "github.com/stretchr/testify/mock"\r
+  "github.com/pkg/errors"\r
+\r
+)\r
+\r
+type mockValues struct {\r
+  mock.Mock\r
+}\r
+\r
+func (m *mockValues) GetCurrentUser() (*user.User, error) {\r
+  fmt.Println("Mocked Get User")\r
+  args := m.Called()\r
+\r
+  return args.Get(0).(*user.User), args.Error(1)\r
+}\r
+\r
+func TestGetDirPath(t *testing.T) {\r
+  fakeUser := user.User{}\r
+  u := &fakeUser\r
+\r
+  myMocks := new(mockValues)\r
+\r
+  myMocks.On("GetCurrentUser").Return(&fakeUser, nil)\r
+  myMocks.On("GetPath", u, "", "test_image").Return("", "")\r
+\r
+  imageClient := ImageClient{myMocks, "test_image", "test_meta"}\r
+  _, dir, err := imageClient.GetDirPath("")\r
+  if err != nil {\r
+    t.Errorf("Path was incorrect, got: %q, want: %q.", dir, "some_path")\r
+  }\r
+}\r
+\r
+func (m *mockValues) DBCreate(name string, key ImageKey, meta string, c Image) error{\r
+    fmt.Println("Mocked Create image in Mongo")\r
+    args := m.Called(name, key, meta, c)\r
+\r
+    return args.Error(0)\r
+}\r
+\r
+func (m *mockValues) DBRead(name string, key ImageKey, meta string) ([]byte, error) {\r
+    fmt.Println("Mocked Mongo DB Read Operations")\r
+    args := m.Called(name, key, meta)\r
+\r
+    return args.Get(0).([]byte), args.Error(1)\r
+}\r
+\r
+func (m *mockValues) DBUnmarshal(value []byte, c Image) error {\r
+    fmt.Println("Mocked Mongo DB Unmarshal Operation")\r
+    args := m.Called(value, c)\r
+\r
+    return args.Error(0)\r
+}\r
+\r
+func (m *mockValues) GetPath(u *user.User, imageName string, storeName string) (string, string) {\r
+    args := m.Called(u, "", "test_image")\r
+\r
+    return args.String(0), args.String(1)\r
+}\r
+\r
+func (m *mockValues) OSMakeDir(dirPath string, perm int) error {\r
+    fmt.Println("Mocked OS Create Directory Operation")\r
+    args := m.Called(dirPath, perm)\r
+    \r
+    return args.Error(0)\r
+}\r
+\r
+func (m *mockValues) OSCreateFile(filePath string) error {\r
+    fmt.Println("Mocked Create File Operation")\r
+    args := m.Called(filePath)\r
+\r
+    return args.Error(0)\r
+}\r
+\r
+func (m *mockValues) DBDelete(name string, key ImageKey, meta string) error {\r
+    fmt.Println("Mocked Mongo DB Delete")\r
+    args := m.Called(name, key, meta)\r
+\r
+    return args.Error(0)\r
+\r
+}\r
+\r
+func (m *mockValues) OSRemove(filePath string) error {\r
+    fmt.Println("Mocked OS File Remove")\r
+    args := m.Called(filePath)\r
+\r
+    return args.Error(0)\r
+}\r
+\r
+func (m *mockValues) DBUpdate(s string, k ImageKey, t string, c Image) error {\r
+    fmt.Println("Mocked Mongo DB Update")\r
+    args := m.Called(s, k, t, c)\r
+\r
+    return args.Error(0)\r
+}\r
+\r
+func TestCreate(t *testing.T) {\r
+    image := Image{}\r
+    arr_data := []byte{}\r
+    key := ImageKey{}\r
+    myMocks := new(mockValues)\r
+    // just to get an error value\r
+    err1 := errors.New("math: square root of negative number")\r
+\r
+    fakeUser := user.User{}\r
+    u := &fakeUser\r
+\r
+    myMocks.On("DBCreate", "test_image", key, "test_meta", image).Return(nil)\r
+    myMocks.On("DBRead", "test_image", key, "test_meta").Return(arr_data, err1)\r
+    myMocks.On("DBUnmarshal", arr_data, image).Return(nil)\r
+    myMocks.On("GetCurrentUser").Return(&fakeUser, nil)\r
+    myMocks.On("GetPath", u, "", "test_image").Return("", "")\r
+    myMocks.On("OSMakeDir", "", 0744).Return(nil)\r
+    myMocks.On("OSCreateFile", "").Return(nil)\r
+\r
+    imageClient := ImageClient{myMocks, "test_image", "test_meta"}\r
+    _, err := imageClient.Create(image)\r
+    if err != nil {\r
+        t.Errorf("Some error occured!")\r
+    }\r
+}\r
+\r
+func TestDelete(t *testing.T) {\r
+    key := ImageKey{}\r
+    fakeUser := user.User{}\r
+    u := &fakeUser\r
+\r
+    myMocks := new(mockValues)\r
+\r
+    myMocks.On("DBDelete", "test_image", key, "test_meta").Return(nil)\r
+    myMocks.On("GetCurrentUser").Return(&fakeUser, nil)\r
+    myMocks.On("GetPath", u, "", "test_image").Return("", "")\r
+    myMocks.On("OSRemove", "").Return(nil)\r
+\r
+    imageClient := ImageClient{myMocks, "test_image", "test_meta"}\r
+    err := imageClient.Delete("")\r
+    if err != nil {\r
+        t.Errorf("Some error occured!")\r
+    }\r
+\r
+}\r
+\r
+func TestUpdate(t *testing.T) {\r
+    image := Image{}\r
+    key := ImageKey{}\r
+    arr_data := []byte{} \r
+\r
+    myMocks := new(mockValues)\r
+\r
+    myMocks.On("DBRead", "test_image", key, "test_meta").Return(arr_data, nil)\r
+    myMocks.On("DBUnmarshal", arr_data, image).Return(nil)\r
+    myMocks.On("DBUpdate", "test_image", key, "test_meta", image).Return(nil)\r
+    imageClient := ImageClient{myMocks, "test_image", "test_meta"}\r
+    _, err := imageClient.Update("", image)\r
+    if err != nil {\r
+        t.Errorf("Some error occured!")\r
+    }\r
+}\r
diff --git a/cmd/bpa-restapi-agent/sample.json b/cmd/bpa-restapi-agent/sample.json
deleted file mode 100644 (file)
index 97c2125..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "owner":  "alpha",
-  "cluster_name": "beta",
-  "type": "container",
-  "image_name": "asdf246",
-  "image_length": 21579557,
-  "image_offset": 0,
-  "upload_complete":  false,
-  "description": {
-    "image_records":  [
-      {
-        "image_record_name": "iuysdi1234",
-        "repo": "java",
-        "tag":  "8"
-      }
-    ]
-  }
-}
diff --git a/cmd/bpa-restapi-agent/service.yml b/cmd/bpa-restapi-agent/service.yml
new file mode 100644 (file)
index 0000000..db3163b
--- /dev/null
@@ -0,0 +1,64 @@
+apiVersion: v1\r
+kind: Service\r
+metadata:\r
+  name: bpa-api-service\r
+spec:\r
+  selector:\r
+    app: bpa-api1\r
+  ports:\r
+    - port: 9015\r
+      targetPort: 9015\r
+      protocol: TCP\r
+  type: NodePort\r
+---\r
+apiVersion: apps/v1\r
+kind: Deployment\r
+metadata:\r
+  name: bpa-api-deployment\r
+spec:\r
+  replicas: 1\r
+  selector:\r
+    matchLabels:\r
+      app: bpa-api1\r
+  strategy:\r
+    type: Recreate\r
+  template:\r
+    metadata:\r
+      labels:\r
+        app: bpa-api1\r
+    spec:\r
+      serviceAccount: bpa-restapi-agent\r
+      # Refer to the PVC created earlier\r
+      volumes:\r
+      - name: storage\r
+        persistentVolumeClaim:\r
+          # Name of the PVC created earlier\r
+          claimName: minio-local-claim\r
+      containers:\r
+      - name: bpa-api1\r
+        image: akraino.org/icn/bpa-restapi-agent:latest\r
+        imagePullPolicy: IfNotPresent\r
+        ports:\r
+        - containerPort: 9015\r
+      - name: mongo\r
+        image: mongo\r
+        ports:\r
+        - containerPort: 27017\r
+      - name: minio\r
+        # Pulls the default Minio image from Docker Hub\r
+        image: minio/minio:latest\r
+        args:\r
+        - server\r
+        - /storage\r
+        env:\r
+        # Minio access key and secret key\r
+        - name: MINIO_ACCESS_KEY\r
+          value: "ICN-ACCESSKEYID"\r
+        - name: MINIO_SECRET_KEY\r
+          value: "ICN-SECRETACCESSKEY"\r
+        ports:\r
+        - containerPort: 9000\r
+        # Mount the volume into the pod\r
+        volumeMounts:\r
+        - name: storage # must match the volume name, above\r
+          mountPath: "/storage"\r
diff --git a/cmd/bpa-restapi-agent/vendor.tar.gz b/cmd/bpa-restapi-agent/vendor.tar.gz
new file mode 100644 (file)
index 0000000..74490a2
Binary files /dev/null and b/cmd/bpa-restapi-agent/vendor.tar.gz differ
index f1a61ea..b81d8b1 100755 (executable)
@@ -1,21 +1,23 @@
 #!/bin/bash
 
+ICN_DIR=$(dirname "$(dirname "$(dirname "$PWD")")")
+
 # Make sure 64GB+ free space.
 
 echo "s"|sudo -S mkdir /mnt/minio
 
-# Create local-storage persistent volume first since not support dynamic provisioning.
-kubectl create -f local-pv.yaml
+# Create local-sc persistent volume first since not support dynamic provisioning.
+kubectl apply -f $ICN_DIR/deploy/kud-plugin-addons/minio/local-pv.yaml
 
-# Create storage class for local-storage
-kubectl create -f local-sc.yaml
+# Create storage class for local-sc
+kubectl apply -f $ICN_DIR/deploy/kud-plugin-addons/minio/local-sc.yaml
 
 # Create persistent volume claim for minio server
-kubectl create -f local-pvc.yaml
+kubectl apply -f $ICN_DIR/deploy/kud-plugin-addons/minio/local-pvc.yaml
 
 # Create deployment of MinIO server
-kubectl create -f minio-deployment.yaml
+kubectl apply -f $ICN_DIR/deploy/kud-plugin-addons/minio/minio-deployment.yaml
 
 # Create service for MinIO
-kubectl create -f minio-service.yaml
+kubectl create -f minio-service.yaml
 
index d273a0f..448622a 100644 (file)
@@ -9,7 +9,7 @@ spec:
   accessModes:
   - ReadWriteOnce
   persistentVolumeReclaimPolicy: Delete
-  storageClassName: local-storage
+  storageClassName: local-sc
   local:
     path: /mnt/minio
   nodeAffinity:
index 923dd61..8fb630f 100644 (file)
@@ -8,5 +8,5 @@ spec:
   resources:
     requests:
       storage: 64Gi
-  storageClassName: local-storage
+  storageClassName: local-sc
 
index b442e77..65bc293 100644 (file)
@@ -1,7 +1,7 @@
 kind: StorageClass
 apiVersion: storage.k8s.io/v1
 metadata:
-  name: local-storage
+  name: local-sc
 provisioner: kubernetes.io/no-provisioner
 volumeBindingMode: WaitForFirstConsumer