+++ /dev/null
-.PHONY: build
-
-build:
- go build -o build/_output/bin/bpa-restapi-agent main.go
-
-docker:
- docker build -t akraino.org/icn/bpa-restapi-agent:latest . -f build/Dockerfile
-
-deploy: docker
- ./bpa_api_install.sh
-
-unit_test: go_install
- go test ./internal/app
-
-go_install:
- ./install_go.sh
-
-e2e_test: deploy
- ./e2e_test.sh
-
-clean:
- ./bpa_api_uninstall.sh
+++ /dev/null
-### Running the server
-To run the server, follow these simple steps:
-
-Integrated Cloud Native (ICN) RESTful API
-
-This is a Golang application providing a RESTful API to interact with and upload image objects.
-
-The API application source files are in the icn/cmd/bpa-restapi-agent directory.
-
-While the database back-end is extensible, this initial release requires mongodb.
-
-Install
-
-Install and start mongodb. For instructions: https://docs.mongodb.com/manual/installation/
-
-git clone "https://gerrit.akraino.org/r/icn"
-cd icn/cmd/bpa-restapi-agent
-
-Run the application
-go run main.go
-
-Output without a config file:
-
-2019/08/22 14:08:41 Error loading config file. Using defaults
-2019/08/22 14:08:41 Starting Integrated Cloud Native API
-
-RESTful API usage examples
-
-Sample Post Request
-
-curl -i -F "metadata=<jsonfile;type=application/json" -F file=@/home/<username>/<dir>/jsonfile -X POST http://NODE_IP:9015//baremetalcluster/{owner}/{clustername}/<image_type>
-
-#image type can be binary_image, container_image, or os_image
-
-Example requests and responses:
-
-Create image - POST
-
-#Using a json file called sample.json
-#image_length in sample.json can be determined with the command
-ls -al <image_file>
-
-Request
-
-curl -i -F "metadata=<sample.json;type=application/json" -F file=@/home/enyi/workspace/icn/cmd/bpa-restapi-agent/sample.json -X POST http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images
-
-Response
-
-HTTP/1.1 100 Continue
-
-HTTP/1.1 201 Created
-Content-Type: application/json
-Date: Thu, 22 Aug 2019 22:56:16 GMT
-Content-Length: 239
-
-{"owner":"alpha","cluster_name":"beta","type":"container","image_name":"asdf246","image_offset":0,"image_length":29718177,"upload_complete":false,"description":{"image_records":[{"image_record_name":"iuysdi1234","repo":"icn","tag":"1"}]}}
-
-#this creates a database entry for the image, and an empty file in the file system
-
-List image - GET
-
-curl -i -X GET http://localhost:9015/v1/baremetalcluster/{owner}/{clustername}/<image_type>/{imgname}
-
-
-example:
-#continuing with our container image from above
-
-Request
-
-curl -i -X GET http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246
-
-Response
-
-HTTP/1.1 200 OK
-Content-Type: application/json
-Date: Thu, 22 Aug 2019 22:57:10 GMT
-Content-Length: 239
-
-{"owner":"alpha","cluster_name":"beta","type":"container","image_name":"asdf246","image_offset":0,"image_length":29718177,"upload_complete":false,"description":{"image_records":[{"image_record_name":"iuysdi1234","repo":"icn","tag":"1"}]}}
-
-Upload container image - PATCH
-Request
-
-curl --request PATCH --data-binary "@/home/enyi/workspace/icn/cmd/bpa-restapi-agent/sample_image" http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246 --header "Upload-Offset: 0" --header "Expect:" -i
-
-
-Response
-
-HTTP/1.1 204 No Content
-Upload-Offset: 29718177
-Date: Thu, 22 Aug 2019 23:19:44 GMT
-
-Check uploaded image - GET
-
-Request
-
-curl -i -X GET http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246
-
-Response
-
-HTTP/1.1 200 OK
-Content-Type: application/json
-Date: Fri, 23 Aug 2019 17:12:07 GMT
-Content-Length: 245
-
-{"owner":"alpha","cluster_name":"beta","type":"container","image_name":"asdf246","image_offset":29718177,"image_length":29718177,"upload_complete":true,"description":{"image_records":[{"image_record_name":"iuysdi1234","repo":"icn","tag":"1"}]}}
-
-#after the upload, the image_offset is now the same as image_length and upload_complete changed to true
-#if upload was incomplete
-
-Resumable upload instructions
-
-Resumable upload -PATCH
-
-#this is the current resumable upload mechanism
-
-Request
-
-curl --request PATCH --data-binary "@/home/enyi/workspace/icn/cmd/bpa-restapi-agent/sample_image" http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246 --header "Upload-Offset: 0" --header "Expect:" -i --limit-rate 200K
-
-#the above request limits transfer for testing purposes
-#'ctl c' out after a few seconds, to stop file transfer
-#check image_offset with a GET
-
-Check upload - GET
-
-Request
-
-curl -i -X GET http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246
-
-Response
-
-HTTP/1.1 200 OK
-Content-Type: application/json
-Date: Sat, 24 Aug 2019 00:30:00 GMT
-Content-Length: 245
-
-{"owner":"alpha","cluster_name":"beta","type":"container","image_name":"asdf246","image_offset":4079616,"image_length":29718177,"upload_complete":false,"description":{"image_records":[{"image_record_name":"iuysdi1234","repo":"icn","tag":"2"}]}}
-
-#from our response you can see that image_offset is still less than image_length and #upload_complete is still false
-#next we use the dd command (no limiting this time)
-
-Request
-
-dd if=/home/enyi/workspace/icn/cmd/bpa-restapi-agent/sample_image skip=4079616 bs=1 | curl --request PATCH --data-binary @- http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246 --header "Upload-Offset: 4079616" --header "Expect:" -i
-
-#the request skips already uploaded 4079616 bytes of data
-
-Response
-
-25638561+0 records in
-25638561+0 records out
-25638561 bytes (26 MB, 24 MiB) copied, 207.954 s, 123 kB/s
-HTTP/1.1 204 No Content
-Upload-Offset: 29718177
-Date: Sat, 24 Aug 2019 00:43:18 GMT
-
-Update image description - PUT
-
-# let's change the tag in description from 1 to latest
-# once the change is made in sample.json (or your json file)
-
-Request
-
-curl -i -F "metadata=<sample.json;type=application/json" -F file=@/home/enyi/workspace/icn/cmd/bpa-restapi-agent/sample.json -X PUT http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246
-
-Response
-
-HTTP/1.1 100 Continue
-
-HTTP/1.1 201 Created
-Content-Type: application/json
-Date: Fri, 23 Aug 2019 17:21:01 GMT
-Content-Length: 239
-
-{"owner":"alpha","cluster_name":"beta","type":"container","image_name":"asdf246","image_offset":0,"image_length":29718177,"upload_complete":false,"description":{"image_records":[{"image_record_name":"iuysdi1234","repo":"icn","tag":"2"}]}}
-
-Delete an image - DELETE
-
-Request
-
-curl -i -X DELETE http://localhost:9015/v1/baremetalcluster/alpha/beta/container_images/asdf246
-
-Response
-
-# Cloud Storage with MinIO
-
-Start MinIO server daemon with docker command before running REST API agent,
-default settings in config/config.go.
-AccessKeyID: ICN-ACCESSKEYID
-SecretAccessKey: ICN-SECRETACCESSKEY
-MinIO Port: 9000
-
-You can setup MinIO server my the following command with default credentials.
-```
-$ docker run -p 9000:9000 --name minio1 \
- -e "MINIO_ACCESS_KEY=ICN-ACCESSKEYID" \
- -e "MINIO_SECRET_KEY=ICN-SECRETACCESSKEY" \
- -v /mnt/data:/data \
- minio/minio server /data
-```
-Also there is a Kubernetes deployment for MinIO server in standalone mode.
-```
-$ cd deploy/kud-plugin-addons/minio
-$ ./install.sh
-```
-You can check the status by opening a browser: http://127.0.0.1:9000/
-
-MinIO Client implementation integrated in REST API agent and will automatically
-initialize in main.go, and create 3 buckets: binary, container, operatingsystem.
-The Upload image will "PUT" to corresponding buckets by HTTP PATCH request url.
+++ /dev/null
-// api/api_images.go
-
-
-package api
-
-import (
- "log"
-
- image "bpa-restapi-agent/internal/app"
- minio "bpa-restapi-agent/internal/storage"
-
- "github.com/gorilla/mux"
-)
-
-// NewRouter creates a router that registers the various urls that are supported
-func NewRouter(binaryClient image.ImageManager,
- containerClient image.ImageManager,
- osClient image.ImageManager) *mux.Router {
-
- router := mux.NewRouter()
-
- minioInfo, err := minio.Initialize()
- if err != nil {
- log.Println("Error while initialize minio client: %s", err)
- }
-
- //Setup the image uploaad api handler here
- if binaryClient == nil {
- binaryClient = image.NewBinaryImageClient()
- }
- binaryHandler := imageHandler{client: binaryClient, minioI: minioInfo, storeName: "binary"}
- imgRouter := router.PathPrefix("/v1").Subrouter()
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/binary_images", binaryHandler.createHandler).Methods("POST")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/binary_images/{imgname}", binaryHandler.getHandler).Methods("GET")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/binary_images/{imgname}", binaryHandler.deleteHandler).Methods("DELETE")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/binary_images/{imgname}", binaryHandler.updateHandler).Methods("PUT")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/binary_images/{imgname}", binaryHandler.patchHandler).Methods("PATCH")
-
- //Setup the _image upload api handler here
- if containerClient == nil {
- containerClient = image.NewContainerImageClient()
- }
- containerHandler := imageHandler{client: containerClient, minioI: minioInfo, storeName: "container"}
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/container_images", containerHandler.createHandler).Methods("POST")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/container_images/{imgname}", containerHandler.getHandler).Methods("GET")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/container_images/{imgname}", containerHandler.deleteHandler).Methods("DELETE")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/container_images/{imgname}", containerHandler.updateHandler).Methods("PUT")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/container_images/{imgname}", containerHandler.patchHandler).Methods("PATCH")
-
- //Setup the os_image upload api handler here
- if osClient == nil {
- osClient = image.NewOSImageClient()
- }
- osHandler := imageHandler{client: osClient, minioI: minioInfo, storeName: "operatingsystem"}
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/os_images", osHandler.createHandler).Methods("POST")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/os_images/{imgname}", osHandler.getHandler).Methods("GET")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/os_images/{imgname}", osHandler.deleteHandler).Methods("DELETE")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/os_images/{imgname}", osHandler.updateHandler).Methods("PUT")
- imgRouter.HandleFunc("/baremetalcluster/{owner}/{clustername}/os_images/{imgname}", osHandler.patchHandler).Methods("PATCH")
-
- return router
-}
+++ /dev/null
-package api
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "os"
- "log"
- "strconv"
-
- image "bpa-restapi-agent/internal/app"
- minioc "bpa-restapi-agent/internal/storage"
-
- "github.com/gorilla/mux"
-)
-
-// imageHandler is used to store backend implementations objects
-// Also simplifies mocking for unit testing purposes
-type imageHandler struct {
- // Interface that implements Image operations
- // We will set this variable with a mock interface for testing
- client image.ImageManager
- dirPath string
- minioI minioc.MinIOInfo
- storeName string // as minio client bucketname
-}
-
-// CreateHandler handles creation of the image entry in the database
-
-func (h imageHandler) createHandler(w http.ResponseWriter, r *http.Request) {
- var v image.Image
-
- // Implemenation using multipart form
- // Review and enable/remove at a later date
- // Set Max size to 16mb here
- err := r.ParseMultipartForm(16777216)
- if err != nil {
- http.Error(w, err.Error(), http.StatusUnprocessableEntity)
- return
- }
-
- jsn := bytes.NewBuffer([]byte(r.FormValue("metadata")))
- err = json.NewDecoder(jsn).Decode(&v)
- switch {
- case err == io.EOF:
- http.Error(w, "Empty body", http.StatusBadRequest)
- return
- case err != nil:
- http.Error(w, err.Error(), http.StatusUnprocessableEntity)
- return
- }
-
- // Name is required.
- if v.ImageName == "" {
- http.Error(w, "Missing name in POST request", http.StatusBadRequest)
- return
- }
-
- // Owner is required.
- if v.Owner == "" {
- http.Error(w, "Missing Owner in POST request", http.StatusBadRequest)
- return
- }
-
- if v.ImageLength == 0 {
- e := "Improper upload length"
- w.WriteHeader(http.StatusBadRequest)
- w.Write([]byte(e))
- return
- }
-
- //Read the file section and ignore the header
- file, _, err := r.FormFile("file")
- if err != nil {
- http.Error(w, "Unable to process file", http.StatusUnprocessableEntity)
- return
- }
-
- defer file.Close()
-
-
- ret, err := h.client.Create(v)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusCreated)
- err = json.NewEncoder(w).Encode(ret)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-}
-
-// getHandler handles GET operations on a particular name
-// Returns an Image
-func (h imageHandler) getHandler(w http.ResponseWriter, r *http.Request) {
- vars := mux.Vars(r)
- imageName := vars["imgname"]
-
- ret, err := h.client.Get(imageName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusOK)
- err = json.NewEncoder(w).Encode(ret)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-}
-
-// deleteHandler handles DELETE operations on a particular record
-func (h imageHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
- vars := mux.Vars(r)
- imageName := vars["imgname"]
-
- err := h.client.Delete(imageName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- h.minioI.DeleteImage(h.storeName, imageName)
-
- w.WriteHeader(http.StatusNoContent)
-}
-
-// UpdateHandler handles Update operations on a particular image
-func (h imageHandler) updateHandler(w http.ResponseWriter, r *http.Request) {
- var v image.Image
- vars := mux.Vars(r)
- imageName := vars["imgname"]
-
- err := r.ParseMultipartForm(16777216)
- if err != nil {
- http.Error(w, err.Error(), http.StatusUnprocessableEntity)
- return
- }
-
- jsn := bytes.NewBuffer([]byte(r.FormValue("metadata")))
- err = json.NewDecoder(jsn).Decode(&v)
- switch {
- case err == io.EOF:
- http.Error(w, "Empty body", http.StatusBadRequest)
- return
- case err != nil:
- http.Error(w, err.Error(), http.StatusUnprocessableEntity)
- return
- }
-
- // Name is required.
- if v.ImageName == "" {
- http.Error(w, "Missing name in PUT request", http.StatusBadRequest)
- return
- }
-
- // Owner is required.
- if v.Owner == "" {
- http.Error(w, "Missing Owner in PUT request", http.StatusBadRequest)
- return
- }
-
- //Read the file section and ignore the header
- file, _, err := r.FormFile("file")
- if err != nil {
- http.Error(w, "Unable to process file", http.StatusUnprocessableEntity)
- return
- }
-
- defer file.Close()
-
- ret, err := h.client.Update(imageName, v)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusCreated)
- err = json.NewEncoder(w).Encode(ret)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
-}
-
-// File upload is handled by the patchHandler
-
-func (h imageHandler) patchHandler(w http.ResponseWriter, r *http.Request) {
- log.Println("going to patch file")
- vars := mux.Vars(r)
- imageName := vars["imgname"]
- file, err := h.client.Get(imageName)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- if *file.UploadComplete == true {
- e := "Upload already completed"
- w.WriteHeader(http.StatusUnprocessableEntity)
- w.Write([]byte(e))
- log.Println("Upload already completed")
- return
- }
- off, err := strconv.Atoi(r.Header.Get("Upload-Offset"))
- if err != nil {
- log.Println("Improper upload offset", err)
- w.WriteHeader(http.StatusBadRequest)
- return
- }
- log.Printf("Upload offset %d\n", off)
- if *file.ImageOffset != off {
- e := fmt.Sprintf("Expected Offset %d, actual offset %d", *file.ImageOffset, off)
- w.WriteHeader(http.StatusConflict)
- w.Write([]byte(e))
- log.Printf("Expected Offset:%d doesn't match got offset:%d\n", *file.ImageOffset, off)
- return
- }
-
- log.Println("Content length is", r.Header.Get("Content-Length"))
- clh := r.Header.Get("Content-Length")
- cl, err := strconv.Atoi(clh)
- if err != nil {
- log.Println("unknown content length")
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- if cl != (file.ImageLength - *file.ImageOffset) {
- e := fmt.Sprintf("Content length doesn't match upload length. Expected content length %d got %d", file.ImageLength-*file.ImageOffset, cl)
- log.Println(e)
- w.WriteHeader(http.StatusBadRequest)
- w.Write([]byte(e))
- return
- }
-
- body, err := ioutil.ReadAll(r.Body)
- if err != nil {
- log.Printf("Received file partially %s\n", err)
- log.Println("Size of received file ", len(body))
- }
-
- fp, _, err := h.client.GetDirPath(imageName)
- if err != nil {
- log.Printf("unable to get file path %s\n", err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- f, err := os.OpenFile(fp, os.O_WRONLY, 0644)
- if err != nil {
- log.Printf("unable to open file %s\n", err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- defer f.Close()
-
- n, err := f.WriteAt(body, int64(off))
- if err != nil {
- log.Printf("unable to write %s", err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- log.Printf("Start to Patch image, bucket: %s, image: %s, dirpath: %s, offset: %d, n: %d\n",
- h.storeName, imageName, fp, *file.ImageOffset, n)
- uploadbytes, err := h.minioI.PatchImage(h.storeName, imageName, fp, int64(*file.ImageOffset), int64(n))
- if err != nil || uploadbytes == 0 {
- log.Printf("MinIO upload with offset %d failed: %s", *file.ImageOffset, err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- log.Println("number of bytes written ", n)
- no := *file.ImageOffset + n
- file.ImageOffset = &no
-
- uo := strconv.Itoa(*file.ImageOffset)
- w.Header().Set("Upload-Offset", uo)
- if *file.ImageOffset == file.ImageLength {
- log.Println("upload completed successfully")
- *file.UploadComplete = true
- }
-
- _, err = h.client.Update(imageName, file)
- if err != nil {
- log.Println("Error while updating file", err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
- w.WriteHeader(http.StatusNoContent)
-
- return
-
-}
+++ /dev/null
-apiVersion: rbac.authorization.k8s.io/v1\r
-kind: ClusterRole\r
-metadata:\r
- name: do-all\r
-rules:\r
-- apiGroups: ["*"]\r
- resources: ["*"]\r
- verbs: ["*"]\r
+++ /dev/null
-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
+++ /dev/null
-#!/usr/bin/env bash
-set -eu -o pipefail
-
-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/yaml
-
-./install.sh
-
-popd
-
-kubectl apply -f service.yml
+++ /dev/null
-#!/usr/bin/env bash
-set -eu -o pipefail
-
-ICN_DIR=$(dirname "$(dirname "$PWD")")
-
-kubectl delete -f service.yml
-
-pushd $ICN_DIR/deploy/kud-plugin-addons/minio/yaml
-
-./uninstall.sh
-
-popd
-
-kubectl delete -f bpa_api_cluster_role_binding.yml
-
-kubectl delete -f bpa_api_cluster_role.yml
-
-kubectl delete -f create-service-account.yml
-
-sleep 10
-
-sudo docker rmi akraino.org/icn/bpa-restapi-agent:latest
-
-sudo docker rmi mongo:latest
-
-sudo docker rmi minio/minio:latest
+++ /dev/null
-FROM golang:1.13 AS builder
-RUN mkdir /bpa-restapi-agent
-ADD . /bpa-restapi-agent
-WORKDIR /bpa-restapi-agent
-
-RUN make build
-
-FROM golang:1.13
-
-COPY --from=builder /bpa-restapi-agent/build/_output/bin/bpa-restapi-agent /bpa-restapi-agent
-
-ENTRYPOINT ["/bpa-restapi-agent"]
+++ /dev/null
-apiVersion: v1\r
-kind: ServiceAccount\r
-metadata:\r
- name: bpa-restapi-agent\r
+++ /dev/null
----
-swagger: "2.0"
-info:
- description: "Addresses deployment of workloads in the edge"
- version: "1.0.0"
- title: "ICN application"
-schemes:
-- "http"
-consumes:
-- "application/json"
-produces:
-- "application/json"
-paths:
- /:
- get:
- tags:
- - "container_images"
- operationId: "find_images"
- parameters:
- - name: "since"
- in: "query"
- required: false
- type: "integer"
- format: "int64"
- x-exportParamName: "Since"
- x-optionalDataType: "Int64"
- - name: "limit"
- in: "query"
- required: false
- type: "integer"
- default: 20
- format: "int32"
- x-exportParamName: "Limit"
- x-optionalDataType: "Int32"
- responses:
- 200:
- description: "list the ICN operations"
- schema:
- type: "array"
- items:
- $ref: "#/definitions/Request"
- default:
- description: "generic error response"
- schema:
- $ref: "#/definitions/error"
- post:
- tags:
- - "container_images"
- operationId: "addContainer"
- parameters:
- - in: "body"
- name: "body"
- required: false
- schema:
- $ref: "#/definitions/Request"
- x-exportParamName: "Body"
- responses:
- 201:
- description: "Created"
- schema:
- $ref: "#/definitions/Request"
- default:
- description: "error"
- schema:
- $ref: "#/definitions/error"
- /{id}:
- put:
- tags:
- - "container_images"
- operationId: "updateImage"
- parameters:
- - name: "id"
- in: "path"
- required: true
- type: "integer"
- format: "int64"
- x-exportParamName: "Id"
- - in: "body"
- name: "body"
- required: false
- schema:
- $ref: "#/definitions/Request"
- x-exportParamName: "Body"
- responses:
- 200:
- description: "OK"
- schema:
- $ref: "#/definitions/Request"
- default:
- description: "error"
- schema:
- $ref: "#/definitions/error"
- delete:
- tags:
- - "container_images"
- operationId: "destroyImage"
- parameters:
- - name: "id"
- in: "path"
- required: true
- type: "integer"
- format: "int64"
- x-exportParamName: "Id"
- responses:
- 204:
- description: "Deleted"
- default:
- description: "error"
- schema:
- $ref: "#/definitions/error"
-definitions:
- Request:
- type: "object"
- properties:
- image_id:
- type: "string"
- repo:
- type: "string"
- tag:
- type: "string"
- installed:
- type: "boolean"
- example:
- installed: true
- repo: "repo"
- tag: "tag"
- image_id: "image_id"
- error:
- type: "object"
- required:
- - "message"
- properties:
- code:
- type: "integer"
- format: "int64"
- message:
- type: "string"
+++ /dev/null
-#!/usr/bin/env bash
-set -eu -o pipefail
-
-ICN_DIR=$(dirname "$(dirname "$PWD")")
-
-source "$ICN_DIR/env/lib/common.sh"
-source "$ICN_DIR/deploy/kud-plugin-addons/minio/lib/minio.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
-
-cur_status=""
-
-while [[ $cur_status != "Running" ]]; do
-
- cur_status=$(kubectl get pods | grep bpa-api-deployment | awk '{print $3}')
- if [[ $cur_status != "Running" ]]; then
- echo "$(date +%H:%M:%S) - BPA-RESTful-API Pod status: $cur_status"
- else
- echo "$(date +%H:%M:%S) - BPA-RESTful-API Pod status: $cur_status"
- break
-
- fi
- if [[ $cur_status == "Err"* ]]; then
- exit 1
- fi
- sleep 10
-done
-
-sleep 30
-
-#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
-
-MINIO_IP=$(kubectl get services | grep minio-service | awk '{print $3}')
-setup_mc $MINIO_IP
-obj_size=$(get_object_size container qwerty123)
-echo "Got obj size: $obj_size"
-if [[ $obj_size != $IMAGE_SIZE ]]; then
- exit 1
-fi
-
-call_api -i -X DELETE \
-http://$IP:9015/v1/baremetalcluster/alpha/beta/container_images/qwerty123
+++ /dev/null
-module bpa-restapi-agent
-
-go 1.12
-
-require (
- github.com/go-stack/stack v1.8.0 // indirect
- github.com/golang/snappy v0.0.1 // indirect
- github.com/gorilla/handlers v1.4.2
- 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
- golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
- golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
-)
+++ /dev/null
-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=
-github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
-github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
-github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
-github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/minio/cli v1.20.0/go.mod h1:bYxnK0uS629N3Bq+AOZZ+6lwF77Sodk4+UL9vNuXhOY=
-github.com/minio/minio-go/v6 v6.0.35 h1:D0WTTfDvXfYaz3/LKr13M9D+SZdf+in6eYVF8FPuQWw=
-github.com/minio/minio-go/v6 v6.0.35/go.mod h1:vaNT59cWULS37E+E9zkuN/BVnKHyXtVGS+b04Boc66Y=
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
-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=
-github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
-github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
-go.mongodb.org/mongo-driver v1.0.4 h1:bHxbjH6iwh1uInchXadI6hQR107KEbgYsMzoblDONmQ=
-go.mongodb.org/mongo-driver v1.0.4/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
-golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
-gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+++ /dev/null
-#!/usr/bin/env bash
-set -eu -o pipefail
-
-if which go > /dev/null; then
- sudo apt-get -yq install golang-go
-fi
+++ /dev/null
-package app
-
-import (
- "bpa-restapi-agent/internal/db"
- "encoding/json"
- "os"
- "os/user"
- "path"
-
- 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"`
-}
-
-type ImageRecordList struct {
- ImageRecords []map[string]string `json:"image_records"`
-}
-
-// ImageKey is the key structure that is used in the database
-type ImageKey struct {
- ImageName string `json:"image_name"`
-}
-
-// We will use json marshalling to convert to string to
-// preserve the underlying structure.
-func (dk ImageKey) String() string {
- out, err := json.Marshal(dk)
- if err != nil {
- return ""
- }
-
- return string(out)
-}
-
-// ImageManager is an interface that exposes the Image functionality
-type ImageManager interface {
- Create(c Image) (Image, error)
- Get(imageName string) (Image, error)
- Delete(imageName string) error
- Update(imageName string, c Image) (Image, error)
- GetImageRecordByName(imgname, imageName string) (map[string]string, error)
- 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)
- GetPath(user *user.User, imageName string, storeName string) (string, string)
- DBDelete(storeName string, key ImageKey, meta 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",
- }
-}
-
-// 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{
- ImageName: c.ImageName,
- }
-
- //Check if this Image already exists
- _, err := v.Get(c.ImageName)
- if err == nil {
- return Image{}, pkgerrors.New("Image already exists")
- }
-
- err = v.util.DBCreate(v.storeName, key, v.tagMeta, c)
- if err != nil {
- return Image{}, pkgerrors.Wrap(err, "Creating DB Entry")
- }
-
- err = v.CreateFile(c)
- if err != nil {
- return Image{}, pkgerrors.Wrap(err, "Creating File in FS")
- }
-
- 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(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 {
- return pkgerrors.Wrap(err, "Make image directory")
- }
- file, err := os.Create(filePath)
- if err != nil {
- return pkgerrors.Wrap(err, "Create image file")
- }
- defer file.Close()
-
- return nil
-}
-
-// Get returns Image for corresponding to name
-func (v *ImageClient) Get(imageName string) (Image, error) {
-
- //Construct the composite key to select the entry
- key := ImageKey{
- // Owner: ownerName,
- // ClusterName: clusterName,
- ImageName: imageName,
- }
-
- 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, err := v.util.DBUnmarshal(value)
- if err != nil {
- return Image{}, pkgerrors.Wrap(err, "Unmarshaling Value")
- }
- return c, nil
- }
-
- 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) {
-
- img, err := v.Get(imgName)
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Error getting image")
- }
-
- for _, value := range img.Description.ImageRecords {
- if imageRecordName == value["image_record_name"] {
- return value, nil
- }
- }
-
- return nil, pkgerrors.New("Image record " + imageRecordName + " not found")
-}
-
-func (v *ImageClient) GetDirPath(imageName string) (string, string, error) {
- u, err := v.util.GetCurrentUser()
- filePath, dirPath := v.util.GetPath(u, imageName, v.storeName)
-
- return filePath, dirPath, err
-}
-
-// Delete the Image from database
-func (v *ImageClient) Delete(imageName string) error {
-
- //Construct the composite key to select the entry
- key := ImageKey{
- // Owner: ownerName,
- // ClusterName: clusterName,
- ImageName: imageName,
- }
- 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)
- 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
-}
-
-// Update an entry for the image in the database
-func (v *ImageClient) Update(imageName string, c Image) (Image, error) {
-
- key := ImageKey{
- ImageName: imageName,
- }
-
- //Check if this Image exists
- _, err := v.Get(imageName)
- if err != nil {
- return Image{}, pkgerrors.New("Update Error - Image doesn't exist")
- }
-
- 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 pkgerrors.Wrap(err, "Updating DB Entry")
- }
-
- 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
-}
+++ /dev/null
-package app\r
-\r
-import (\r
- "fmt"\r
- "io/ioutil"\r
- "log"\r
- "os"\r
- "os/user"\r
- "path"\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) (Image, error) {\r
- fmt.Println("Mocked Mongo DB Unmarshal Operation")\r
- args := m.Called(value)\r
-\r
- return args.Get(0).(Image), args.Error(1)\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) 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) 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
- dir, err := ioutil.TempDir("", "test_images")\r
- if err != nil {\r
- log.Fatal(err)\r
- }\r
- defer os.RemoveAll(dir)\r
-\r
- image := Image{\r
- ImageName: "test_asdf",\r
- }\r
- arr_data := []byte{}\r
- key := ImageKey{ImageName:"test_asdf"}\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
- file_path := path.Join(dir, "test_asdf")\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).Return(image, nil)\r
- myMocks.On("GetCurrentUser").Return(&fakeUser, nil)\r
- myMocks.On("GetPath", u, "", "test_image").Return(file_path, dir)\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
- tmpfile, err := ioutil.TempFile("", "test_images")\r
- if err != nil {\r
- log.Fatal(err)\r
- }\r
- defer os.Remove(tmpfile.Name())\r
-\r
- key := ImageKey{ImageName: "test_asdf"}\r
- fakeUser := user.User{}\r
- u := &fakeUser\r
- file_path := tmpfile.Name()\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(file_path, "")\r
-\r
- imageClient := ImageClient{myMocks, "test_image", "test_meta"}\r
- err = imageClient.Delete("test_asdf")\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).Return(image, 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
+++ /dev/null
-/*
- * Copyright 2018 Intel Corporation, Inc
- *
- * 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 auth
-
-import (
- "crypto/tls"
- "crypto/x509"
- "encoding/base64"
- "encoding/pem"
- "io/ioutil"
- "log"
-
- pkgerrors "github.com/pkg/errors"
-)
-
-// GetTLSConfig initializes a tlsConfig using the CA's certificate
-// This config is then used to enable the server for mutual TLS
-func GetTLSConfig(caCertFile string, certFile string, keyFile string) (*tls.Config, error) {
-
- // Initialize tlsConfig once
- caCert, err := ioutil.ReadFile(caCertFile)
-
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Read CA Cert file")
- }
-
- caCertPool := x509.NewCertPool()
- caCertPool.AppendCertsFromPEM(caCert)
-
- tlsConfig := &tls.Config{
- // Change to RequireAndVerify once we have mandatory certs
- ClientAuth: tls.VerifyClientCertIfGiven,
- ClientCAs: caCertPool,
- MinVersion: tls.VersionTLS12,
- }
-
- certPEMBlk, err := readPEMBlock(certFile)
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Read Cert File")
- }
-
- keyPEMBlk, err := readPEMBlock(keyFile)
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Read Key File")
- }
-
- tlsConfig.Certificates = make([]tls.Certificate, 1)
- tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlk, keyPEMBlk)
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Load x509 cert and key")
- }
-
- tlsConfig.BuildNameToCertificate()
- return tlsConfig, nil
-}
-
-func readPEMBlock(filename string) ([]byte, error) {
-
- pemData, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Read PEM File")
- }
-
- pemBlock, rest := pem.Decode(pemData)
- if len(rest) > 0 {
- log.Println("Pemfile has extra data")
- }
-
- if x509.IsEncryptedPEMBlock(pemBlock) {
- password, err := ioutil.ReadFile(filename + ".pass")
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Read Password File")
- }
-
- pByte, err := base64.StdEncoding.DecodeString(string(password))
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Decode PEM Password")
- }
-
- pemData, err = x509.DecryptPEMBlock(pemBlock, pByte)
- if err != nil {
- return nil, pkgerrors.Wrap(err, "Decrypt PEM Data")
- }
- var newPEMBlock pem.Block
- newPEMBlock.Type = pemBlock.Type
- newPEMBlock.Bytes = pemData
- // Converting back to PEM from DER data you get from
- // DecryptPEMBlock
- pemData = pem.EncodeToMemory(&newPEMBlock)
- }
-
- return pemData, nil
-}
+++ /dev/null
-package config
-
-import (
- "encoding/json"
- "log"
- "os"
-)
-
-type Configuration struct {
- Password string `json: "password"`
- DatabaseAddress string `json: "database-address"`
- DatabaseType string `json: "database-type"`
- ServicePort string `json: "service-port"`
- MinIOAddress string `json: "minio-address"`
- MinIOPort string `json: "minio-port"`
- AccessKeyID string `json: "access-key-id"`
- SecretAccessKey string `json: "secret-access-key"`
-}
-
-var gConfig *Configuration
-
-func readConfigFile(file string) (*Configuration, error) {
- f, err := os.Open(file)
- if err != nil {
- return defaultConfiguration(), err
- }
- defer f.Close()
-
- conf := defaultConfiguration()
-
- decoder := json.NewDecoder(f)
- err = decoder.Decode(conf)
- if err != nil {
- return conf, err
- }
-
- return conf, nil
-}
-
-func defaultConfiguration() *Configuration {
- return &Configuration {
- Password: "",
- DatabaseAddress: "127.0.0.1",
- DatabaseType: "mongo",
- ServicePort: "9015",
- MinIOAddress: "127.0.0.1",
- MinIOPort: "9000",
- AccessKeyID: "ICN-ACCESSKEYID",
- SecretAccessKey: "ICN-SECRETACCESSKEY",
- }
-}
-
-func GetConfiguration() *Configuration {
- if gConfig == nil {
- conf, err := readConfigFile("ICNconfig.json")
- if err != nil {
- log.Println("Error loading config file. Using defaults")
- }
-
- gConfig = conf
- }
-
- return gConfig
-}
+++ /dev/null
-package db
-
-import (
- "golang.org/x/net/context"
- "log"
-
- "bpa-restapi-agent/internal/config"
-
- pkgerrors "github.com/pkg/errors"
- "go.mongodb.org/mongo-driver/bson"
- "go.mongodb.org/mongo-driver/bson/primitive"
- "go.mongodb.org/mongo-driver/mongo"
- "go.mongodb.org/mongo-driver/mongo/options"
-)
-
-// MongoCollection defines the a subset of MongoDB operations
-// Note: This interface is defined mainly for mock testing
-type MongoCollection interface {
- InsertOne(ctx context.Context, document interface{},
- opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
- FindOne(ctx context.Context, filter interface{},
- opts ...*options.FindOneOptions) *mongo.SingleResult
- FindOneAndUpdate(ctx context.Context, filter interface{},
- update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult
- DeleteOne(ctx context.Context, filter interface{},
- opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
- Find(ctx context.Context, filter interface{},
- opts ...*options.FindOptions) (*mongo.Cursor, error)
-}
-
-// MongoStore is an implementation of the db.Store interface
-type MongoStore struct {
- db *mongo.Database
-}
-
-// This exists only for allowing us to mock the collection object
-// for testing purposes
-var getCollection = func(coll string, m *MongoStore) MongoCollection {
- return m.db.Collection(coll)
-}
-
-// This exists only for allowing us to mock the DecodeBytes function
-// Mainly because we cannot construct a SingleResult struct from our
-// tests. All fields in that struct are private.
-var decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) {
- return sr.DecodeBytes()
-}
-
-// These exists only for allowing us to mock the cursor.Next function
-// Mainly because we cannot construct a mongo.Cursor struct from our
-// tests. All fields in that struct are private and there is no public
-// constructor method.
-var cursorNext = func(ctx context.Context, cursor *mongo.Cursor) bool {
- return cursor.Next(ctx)
-}
-var cursorClose = func(ctx context.Context, cursor *mongo.Cursor) error {
- return cursor.Close(ctx)
-}
-
-// NewMongoStore initializes a Mongo Database with the name provided
-// If a database with that name exists, it will be returned
-func NewMongoStore(name string, store *mongo.Database) (Store, error) {
- if store == nil {
- ip := "mongodb://" + config.GetConfiguration().DatabaseAddress + ":27017"
- clientOptions := options.Client()
- clientOptions.ApplyURI(ip)
- mongoClient, err := mongo.NewClient(clientOptions)
- if err != nil {
- return nil, err
- }
-
- err = mongoClient.Connect(context.Background())
- if err != nil {
- return nil, err
- }
- store = mongoClient.Database(name)
- }
-
- return &MongoStore{
- db: store,
- }, nil
-}
-
-// HealthCheck verifies if the database is up and running
-func (m *MongoStore) HealthCheck() error {
-
- _, err := decodeBytes(m.db.RunCommand(context.Background(), bson.D{{"serverStatus", 1}}))
- if err != nil {
- return pkgerrors.Wrap(err, "Error getting server status")
- }
-
- return nil
-}
-
-// validateParams checks to see if any parameters are empty
-func (m *MongoStore) validateParams(args ...interface{}) bool {
- for _, v := range args {
- val, ok := v.(string)
- if ok {
- if val == "" {
- return false
- }
- } else {
- if v == nil {
- return false
- }
- }
- }
-
- return true
-}
-
-// Create is used to create a DB entry
-func (m *MongoStore) Create(coll string, key Key, tag string, data interface{}) error {
- if data == nil || !m.validateParams(coll, key, tag) {
- return pkgerrors.New("No Data to store")
- }
-
- c := getCollection(coll, m)
- ctx := context.Background()
-
- //Insert the data and then add the objectID to the masterTable
- res, err := c.InsertOne(ctx, bson.D{
- {tag, data},
- })
- if err != nil {
- return pkgerrors.Errorf("Error inserting into database: %s", err.Error())
- }
-
- //Add objectID of created data to masterKey document
- //Create masterkey document if it does not exist
- filter := bson.D{{"key", key}}
-
- _, err = decodeBytes(
- c.FindOneAndUpdate(
- ctx,
- filter,
- bson.D{
- {"$set", bson.D{
- {tag, res.InsertedID},
- }},
- },
- options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)))
-
- if err != nil {
- return pkgerrors.Errorf("Error updating master table: %s", err.Error())
- }
-
- return nil
-}
-
-// Update is used to update a DB entry
-func (m *MongoStore) Update(coll string, key Key, tag string, data interface{}) error {
- if data == nil || !m.validateParams(coll, key, tag) {
- return pkgerrors.New("No Data to update")
- }
-
- c := getCollection(coll, m)
- ctx := context.Background()
-
- //Get the masterkey document based on given key
- filter := bson.D{{"key", key}}
- keydata, err := decodeBytes(c.FindOne(context.Background(), filter))
- if err != nil {
- return pkgerrors.Errorf("Error finding master table: %s", err.Error())
- }
-
- //Read the tag objectID from document
- tagoid, ok := keydata.Lookup(tag).ObjectIDOK()
- if !ok {
- return pkgerrors.Errorf("Error finding objectID for tag %s", tag)
- }
-
- //Update the document with new data
- filter = bson.D{{"_id", tagoid}}
-
- _, err = decodeBytes(
- c.FindOneAndUpdate(
- ctx,
- filter,
- bson.D{
- {"$set", bson.D{
- {tag, data},
- }},
- },
- options.FindOneAndUpdate().SetReturnDocument(options.After)))
-
- if err != nil {
- return pkgerrors.Errorf("Error updating record: %s", err.Error())
- }
-
- return nil
-}
-
-// Unmarshal implements an unmarshaler for bson data that
-// is produced from the mongo database
-func (m *MongoStore) Unmarshal(inp []byte, out interface{}) error {
- err := bson.Unmarshal(inp, out)
- if err != nil {
- return pkgerrors.Wrap(err, "Unmarshaling bson")
- }
- return nil
-}
-
-// Read method returns the data stored for this key and for this particular tag
-func (m *MongoStore) Read(coll string, key Key, tag string) ([]byte, error) {
- if !m.validateParams(coll, key, tag) {
- return nil, pkgerrors.New("Mandatory fields are missing")
- }
-
- c := getCollection(coll, m)
- ctx := context.Background()
-
- //Get the masterkey document based on given key
- filter := bson.D{{"key", key}}
- keydata, err := decodeBytes(c.FindOne(context.Background(), filter))
- if err != nil {
- return nil, pkgerrors.Errorf("Error finding master table: %s", err.Error())
- }
-
- //Read the tag objectID from document
- tagoid, ok := keydata.Lookup(tag).ObjectIDOK()
- if !ok {
- return nil, pkgerrors.Errorf("Error finding objectID for tag %s", tag)
- }
-
- //Use tag objectID to read the data from store
- filter = bson.D{{"_id", tagoid}}
- tagdata, err := decodeBytes(c.FindOne(ctx, filter))
- if err != nil {
- return nil, pkgerrors.Errorf("Error reading found object: %s", err.Error())
- }
-
- //Return the data as a byte array
- //Convert string data to byte array using the built-in functions
- switch tagdata.Lookup(tag).Type {
- case bson.TypeString:
- return []byte(tagdata.Lookup(tag).StringValue()), nil
- default:
- return tagdata.Lookup(tag).Value, nil
- }
-}
-
-// Helper function that deletes an object by its ID
-func (m *MongoStore) deleteObjectByID(coll string, objID primitive.ObjectID) error {
-
- c := getCollection(coll, m)
- ctx := context.Background()
-
- _, err := c.DeleteOne(ctx, bson.D{{"_id", objID}})
- if err != nil {
- return pkgerrors.Errorf("Error Deleting from database: %s", err.Error())
- }
-
- log.Printf("Deleted Obj with ID %s", objID.String())
- return nil
-}
-
-// Delete method removes a document from the Database that matches key
-// TODO: delete all referenced docs if tag is empty string
-func (m *MongoStore) Delete(coll string, key Key, tag string) error {
- if !m.validateParams(coll, key, tag) {
- return pkgerrors.New("Mandatory fields are missing")
- }
-
- c := getCollection(coll, m)
- ctx := context.Background()
-
- //Get the masterkey document based on given key
- filter := bson.D{{"key", key}}
- //Remove the tag ID entry from masterkey table
- update := bson.D{
- {
- "$unset", bson.D{
- {tag, ""},
- },
- },
- }
- keydata, err := decodeBytes(c.FindOneAndUpdate(ctx, filter, update,
- options.FindOneAndUpdate().SetReturnDocument(options.Before)))
- if err != nil {
- //No document was found. Return nil.
- if err == mongo.ErrNoDocuments {
- return nil
- }
- //Return any other error that was found.
- return pkgerrors.Errorf("Error decoding master table after update: %s",
- err.Error())
- }
-
- //Read the tag objectID from document
- elems, err := keydata.Elements()
- if err != nil {
- return pkgerrors.Errorf("Error reading elements from database: %s", err.Error())
- }
-
- tagoid, ok := keydata.Lookup(tag).ObjectIDOK()
- if !ok {
- return pkgerrors.Errorf("Error finding objectID for tag %s", tag)
- }
-
- //Use tag objectID to read the data from store
- err = m.deleteObjectByID(coll, tagoid)
- if err != nil {
- return pkgerrors.Errorf("Error deleting from database: %s", err.Error())
- }
-
- //Delete master table if no more tags left
- //_id, key and tag should be elements in before doc
- //if master table needs to be removed too
- if len(elems) == 3 {
- keyid, ok := keydata.Lookup("_id").ObjectIDOK()
- if !ok {
- return pkgerrors.Errorf("Error finding objectID for key %s", key)
- }
- err = m.deleteObjectByID(coll, keyid)
- if err != nil {
- return pkgerrors.Errorf("Error deleting master table from database: %s", err.Error())
- }
- }
-
- return nil
-}
-
-// ReadAll is used to get all documents in db of a particular tag
-func (m *MongoStore) ReadAll(coll, tag string) (map[string][]byte, error) {
- if !m.validateParams(coll, tag) {
- return nil, pkgerrors.New("Missing collection or tag name")
- }
-
- c := getCollection(coll, m)
- ctx := context.Background()
-
- //Get all master tables in this collection
- filter := bson.D{
- {"key", bson.D{
- {"$exists", true},
- }},
- }
- cursor, err := c.Find(ctx, filter)
- if err != nil {
- return nil, pkgerrors.Errorf("Error reading from database: %s", err.Error())
- }
- defer cursorClose(ctx, cursor)
-
- //Iterate over all the master tables
- result := make(map[string][]byte)
- for cursorNext(ctx, cursor) {
- d := cursor.Current
-
- //Read key of each master table
- key, ok := d.Lookup("key").DocumentOK()
- if !ok {
- //Throw error if key is not found
- pkgerrors.New("Unable to read key from mastertable")
- }
-
- //Get objectID of tag document
- tid, ok := d.Lookup(tag).ObjectIDOK()
- if !ok {
- log.Printf("Did not find tag: %s", tag)
- continue
- }
-
- //Find tag document and unmarshal it into []byte
- tagData, err := decodeBytes(c.FindOne(ctx, bson.D{{"_id", tid}}))
- if err != nil {
- log.Printf("Unable to decode tag data %s", err.Error())
- continue
- }
- result[key.String()] = tagData.Lookup(tag).Value
- }
-
- if len(result) == 0 {
- return result, pkgerrors.Errorf("Did not find any objects with tag: %s", tag)
- }
-
- return result, nil
-}
+++ /dev/null
-package db
-
-import (
- "encoding/json"
- "reflect"
-
- pkgerrors "github.com/pkg/errors"
-)
-
-// DBconn interface used to talk to a concrete Database connection
-var DBconn Store
-
-// Key is an interface that will be implemented by anypackage
-// that wants to use the Store interface. This allows various
-// db backends and key types.
-type Key interface {
- String() string
-}
-
-// Store is an interface for accessing a database
-type Store interface {
- // Returns nil if db health is good
- HealthCheck() error
-
- // Unmarshal implements any unmarshaling needed for the database
- Unmarshal(inp []byte, out interface{}) error
-
- // Creates a new master table with key and links data with tag and
- // creates a pointer to the newly added data in the master table
- Create(table string, key Key, tag string, data interface{}) error
-
- // Reads data for a particular key with specific tag.
- Read(table string, key Key, tag string) ([]byte, error)
-
- // Update data for particular key with specific tag
- Update(table string, key Key, tag string, data interface{}) error
-
- // Deletes a specific tag data for key.
- // TODO: If tag is empty, it will delete all tags under key.
- Delete(table string, key Key, tag string) error
-
- // Reads all master tables and data from the specified tag in table
- ReadAll(table string, tag string) (map[string][]byte, error)
-}
-
-// CreateDBClient creates the DB client
-func CreateDBClient(dbType string) error {
- var err error
- switch dbType {
- case "mongo":
- // create a mongodb database with ICN as the name
- DBconn, err = NewMongoStore("icn", nil)
- default:
- return pkgerrors.New(dbType + "DB not supported")
- }
- return err
-}
-
-// Serialize converts given data into a JSON string
-func Serialize(v interface{}) (string, error) {
- out, err := json.Marshal(v)
- if err != nil {
- return "", pkgerrors.Wrap(err, "Error serializing "+reflect.TypeOf(v).String())
- }
- return string(out), nil
-}
-
-// DeSerialize converts string to a json object specified by type
-func DeSerialize(str string, v interface{}) error {
- err := json.Unmarshal([]byte(str), &v)
- if err != nil {
- return pkgerrors.Wrap(err, "Error deSerializing "+str)
- }
- return nil
-}
+++ /dev/null
-package storage
-
-import (
- "github.com/minio/minio-go/v6"
- "bpa-restapi-agent/internal/config"
-
- "log"
- "os"
-)
-
-type MinIOInfo struct {
- minioC *minio.Client `json:"minio client"`
-}
-
-// Initialize the MinIO server, create buckets
-func Initialize() (MinIOInfo, error) {
- endpoint := config.GetConfiguration().MinIOAddress + ":" + config.GetConfiguration().MinIOPort
- accessKeyID := config.GetConfiguration().AccessKeyID
- secretAccessKey := config.GetConfiguration().SecretAccessKey
- useSSL := false
-
- minioInfo := MinIOInfo{}
- // Initialize minio client object.
- minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL)
- if err != nil {
- log.Fatalln(err)
- return minioInfo, err
- }
-
- // Make a new bucket.
- bucketNames := []string{"binary", "container", "operatingsystem"}
- location := "us-west-1"
-
- for _, bucketName := range bucketNames {
- err := minioClient.MakeBucket(bucketName, location)
- if err != nil {
- // Check to see if we already own this bucket (which happens if you run this twice)
- exists, errBucketExists := minioClient.BucketExists(bucketName)
- if errBucketExists == nil && exists {
- log.Printf("We already own %s\n", bucketName)
- } else {
- log.Fatalln(err)
- return minioInfo, err
- }
- } else {
- log.Printf("Successfully created %s\n", bucketName)
- }
- }
-
- minioInfo.minioC = minioClient
- return minioInfo, nil
-}
-
-func (m MinIOInfo) PutImage(bucketName string, objName string, localPath string) (int64, error) {
-
- //contentType := "multipart/form-data"
- contentType := "application/octet-stream"
-
- // Upload the zip file with FPutObject
- n, err := m.minioC.FPutObject(bucketName, objName, localPath, minio.PutObjectOptions{ContentType:contentType})
- if err != nil {
- log.Fatalln(err)
- return n, err
- }
-
- fileInfo, _ := os.Stat(localPath)
- fileSize := fileInfo.Size()
-
- if n != int64(fileSize) {
- log.Printf("FPutObject failed %s of size %d\n", objName, n)
- return n, err
- }
-
- log.Printf("Successfully uploaded %s of size %d\n", objName, n)
- return n, nil
-}
-
-func (m MinIOInfo) PatchImage(bucketName string, objName string, localPath string, offset int64, objSize int64) (int64, error) {
-
- var n = int64(0)
-
- tempFile, err := os.Open(localPath)
- if err != nil {
- log.Fatalln(err)
- return n, err
- }
-
- defer tempFile.Close()
-
- if _, err := tempFile.Seek(offset, 0); err != nil {
- log.Printf("PatchImage seek %s failed: %s", tempFile.Name(), err)
- return n, err
- }
-
- objInfo, err := m.minioC.StatObject(bucketName, objName, minio.StatObjectOptions{})
- var objHealthy = true
- if err != nil {
- objHealthy = false
- } else if objInfo.Size != offset || objInfo.Size == 0 {
- objHealthy = false
- }
-
- var objNameTemp = objName
- if objHealthy {
- objNameTemp = objName + ".tmp"
- }
-
- contentType := "application/octet-stream"
- n, err = m.minioC.PutObject(bucketName, objNameTemp, tempFile, objSize, minio.PutObjectOptions{ContentType:contentType})
- if err != nil {
- log.Fatalln(err)
- return n, err
- }
-
- if n != objSize {
- log.Printf("PatchImage PutObject %s failed with bytes: %d", tempFile.Name(), n)
- return n, err
- }
-
- if objHealthy {
- src1 := minio.NewSourceInfo(bucketName, objName, nil)
- src2 := minio.NewSourceInfo(bucketName, objNameTemp, nil)
- srcs := []minio.SourceInfo{src1, src2}
-
- dst, err := minio.NewDestinationInfo(bucketName, objName, nil, nil)
- if err != nil {
- log.Printf("NewDestinationInfo failed", err)
- return n, err
- }
-
- // There is issue, the last src should be the smallest obj size
- err = m.minioC.ComposeObject(dst, srcs)
- if err != nil {
- log.Printf("ComposeObject failed", err)
- return n, err
- }
- }
-
- log.Printf("Successfully PatchImage %s of size %d\n", objName, n)
- return n, nil
-}
-
-func (m MinIOInfo) DeleteImage(bucketName string, objName string) (error) {
-
- err := m.minioC.RemoveObject(bucketName, objName)
- if err != nil {
- log.Printf("MinIO Remove object %s failed\n", bucketName)
- return err
- }
-
- return nil
-}
-
-func (m MinIOInfo) CleanupImages(bucketName string) (error) {
- // create a done channel to control 'ListObjectsV2' go routine.
- doneCh := make(chan struct{})
- defer close(doneCh)
-
- for objCh := range m.minioC.ListObjectsV2(bucketName, "", true, doneCh) {
- if objCh.Err != nil {
- return objCh.Err
- }
- if objCh.Key != "" {
- err := m.minioC.RemoveObject(bucketName, objCh.Key)
- if err != nil {
- return err
- }
- }
- }
- for objPartInfo := range m.minioC.ListIncompleteUploads(bucketName, "", true, doneCh) {
- if objPartInfo.Err != nil {
- return objPartInfo.Err
- }
- if objPartInfo.Key != "" {
- err := m.minioC.RemoveIncompleteUpload(bucketName, objPartInfo.Key)
- if err != nil {
- return err
- }
- }
- }
-
- return nil
-}
+++ /dev/null
-package utils
-
-import(
- //"log"
- "bpa-restapi-agent/internal/db"
- "bpa-restapi-agent/internal/config"
- pkgerrors "github.com/pkg/errors"
-)
-
-func CheckDatabaseConnection() error {
-// To Do - Implement db and config
-
- err := db.CreateDBClient(config.GetConfiguration().DatabaseType)
- if err != nil {
- return pkgerrors.Cause(err)
- }
-
- err = db.DBconn.HealthCheck()
- if err != nil {
- return pkgerrors.Cause(err)
- }
-
- return nil
-}
-
-func CheckInitialSettings() error {
- err := CheckDatabaseConnection()
- if err != nil {
- return pkgerrors.Cause(err)
- }
-
- return nil
-}
+++ /dev/null
-// main.go
-package main
-
-import (
- "context"
- "log"
- "math/rand"
- "net/http"
- "os"
- "os/signal"
- "time"
-
-
- "github.com/gorilla/handlers"
-
- "bpa-restapi-agent/api"
- utils "bpa-restapi-agent/internal"
- "bpa-restapi-agent/internal/auth"
- "bpa-restapi-agent/internal/config"
-)
-
-func main() {
- // check initial config
- err := utils.CheckInitialSettings()
- if err != nil{
- log.Fatal(err)
- }
-
- rand.Seed(time.Now().UnixNano())
-
- httpRouter := api.NewRouter(nil, nil, nil)
- // Return http.handler and log requests to Stdout
- loggedRouter := handlers.LoggingHandler(os.Stdout, httpRouter)
- log.Println("Starting Integrated Cloud Native API")
-
- // Create custom http server
- httpServer := &http.Server{
- Handler: loggedRouter,
- Addr: ":" + config.GetConfiguration().ServicePort,
- }
- connectionsClose := make(chan struct{})
- go func() {
- c := make(chan os.Signal, 1) // create c channel to receive notifications
- signal.Notify(c, os.Interrupt) // register c channel to run concurrently
- <-c
- httpServer.Shutdown(context.Background())
- close(connectionsClose)
- }()
-
- // Start server
- tlsConfig, err := auth.GetTLSConfig("ca.cert", "server.cert", "server.key")
- if err != nil {
- log.Println("Error Getting TLS Configuration. Starting without TLS...")
- log.Fatal(httpServer.ListenAndServe())
- } else {
- httpServer.TLSConfig = tlsConfig
- // empty strings because tlsconfig already has this information
- err = httpServer.ListenAndServeTLS("", "")
- }
-}
+++ /dev/null
-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-pvc\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