This creates auth.go and adds tls authentication to main.go.
Also, containerization is introduced using Dockerfile.
It also fixes patch 1431 revert issues
Signed-off-by: Enyinna Ochulor <enyinna.ochulor@intel.com>
Change-Id: I7f6d8d210618e4630e9240c3596ced2f672df67e
-# 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
+# # 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:
+ go build -mod=vendor -o build/_output/bin/bpa-restapi-agent main.go
+
+docker:
+ docker build -t akraino.org/icn/bpa-restapi-agent:latest . -f build/Dockerfile
### 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
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.
-
import (
"bytes"
- "encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
- "os/user"
"log"
- "path"
"strconv"
image "bpa-restapi-agent/internal/app"
return
}
- //Create file directory
- dir, err := createFileDir(v.Type)
- if err != nil {
- log.Fatal("Error creating file server directory", err)
- }
-
//Read the file section and ignore the header
file, _, err := r.FormFile("file")
if err != nil {
defer file.Close()
- //Convert the file content to base64 for storage
- content, err := ioutil.ReadAll(file)
- if err != nil {
- http.Error(w, "Unable to read file", http.StatusUnprocessableEntity)
- return
- }
-
- v.Config = base64.StdEncoding.EncodeToString(content)
ret, err := h.client.Create(v)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- h.dirPath = dir
- filePath := path.Join(h.dirPath, v.ImageName)
- file1, err := os.Create(filePath)
- if err != nil {
- e := "Error creating file in filesystem"
- log.Printf("%s %s\n", e, err)
- w.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- defer file1.Close()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
}
}
-// Create file
-
-func createFileDir(dirName string) (string, error) {
- u, err := user.Current()
- if err != nil {
- log.Println("Error while fetching user home directory", err)
- return "", err
- }
- home := u.HomeDir
- dirPath := path.Join(home, "images", dirName)
- err = os.MkdirAll(dirPath, 0744)
- if err != nil {
- log.Println("Error while creating file server directory", err)
- return "", err
- }
- return dirPath, nil
-}
-
// 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)
- // ownerName := vars["owner"]
- // clusterName := vars["clustername"]
imageName := vars["imgname"]
ret, err := h.client.Get(imageName)
// deleteHandler handles DELETE operations on a particular record
func (h imageHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
- // ownerName := vars["owner"]
- // clusterName := vars["clustername"]
imageName := vars["imgname"]
err := h.client.Delete(imageName)
defer file.Close()
- //Convert the file content to base64 for storage
- content, err := ioutil.ReadAll(file)
- if err != nil {
- http.Error(w, "Unable to read file", http.StatusUnprocessableEntity)
- return
- }
-
- v.Config = base64.StdEncoding.EncodeToString(content)
-
ret, err := h.client.Update(imageName, v)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Println("Size of received file ", len(body))
}
- u, err := user.Current()
+ fp, _, err := h.client.GetDirPath(imageName)
if err != nil {
- log.Println("Error while fetching user home directory", err)
- return
+ log.Printf("unable to get file path %s\n", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
}
- home := u.HomeDir
- dir := path.Join(home, "images", file.Type)
- h.dirPath = dir
- fp := fmt.Sprintf("%s/%s", h.dirPath, imageName)
f, err := os.OpenFile(fp, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Printf("unable to open file %s\n", err)
*file.UploadComplete = true
}
- // err = h.updateFile(file)
- // if err != nil {
- // log.Println("Error while updating file", err)
- // w.WriteHeader(http.StatusInternalServerError)
- // return
- // }
+ _, 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
+FROM registry.svc.ci.openshift.org/openshift/release:golang-1.12 AS builder
+RUN mkdir /bpa-restapi-agent
+ADD . /bpa-restapi-agent
+WORKDIR /bpa-restapi-agent
+
+RUN make build
+
+FROM registry.svc.ci.openshift.org/openshift/release:golang-1.12
+
+COPY --from=builder /bpa-restapi-agent/build/_output/bin/bpa-restapi-agent /bpa-restapi-agent
+
+ENTRYPOINT ["/bpa-restapi-agent"]
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/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
github.com/xdg/stringprep v1.0.0 // indirect
+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/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/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/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+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=
package app
import (
- //"encoding/base64"
"encoding/json"
- //"io/ioutil"
-
+ "os"
+ "os/user"
+ "path"
"bpa-restapi-agent/internal/db"
pkgerrors "github.com/pkg/errors"
ClusterName string `json:"cluster_name"`
Type string `json:"type"`
ImageName string `json:"image_name"`
- Config string `json:"config"`
ImageOffset *int `json:"image_offset"`
ImageLength int `json:"image_length"`
UploadComplete *bool `json:"upload_complete"`
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)
}
// ImageClient implements the ImageManager
// which implements the ImageManager
func NewBinaryImageClient() *ImageClient {
return &ImageClient{
- storeName: "binary_image",
+ storeName: "binary_images",
tagMeta: "metadata",
}
}
func NewContainerImageClient() *ImageClient {
return &ImageClient{
- storeName: "container_image",
+ storeName: "container_images",
tagMeta: "metadata",
}
}
func NewOSImageClient() *ImageClient {
return &ImageClient{
- storeName: "os_image",
+ storeName: "os_images",
tagMeta: "metadata",
}
}
return Image{}, pkgerrors.Wrap(err, "Creating DB Entry")
}
+ err = v.CreateFile(v.storeName, c)
+ if err != nil {
+ return Image{}, pkgerrors.Wrap(err, "Creating File in FS")
+ }
+
return c, nil
}
+// Create file
+
+func (v *ImageClient) CreateFile(dirName string, 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")
+ }
+ 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) {
return nil, pkgerrors.New("Image record " + imageRecordName + " not found")
}
+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)
+
+ return filePath, dirPath, err
+}
+
// Delete the Image from database
func (v *ImageClient) Delete(imageName string) error {
if err != nil {
return pkgerrors.Wrap(err, "Delete Image")
}
+
+ //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 (v *ImageClient) Update(imageName string, c Image) (Image, error) {
key := ImageKey{
- // Owner: c.Owner,
- // ClusterName: c.ClusterName,
ImageName: imageName,
}
--- /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
+}
"os/signal"
"time"
- //To Do - Implement internal for checking config
+
"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() {
- // To Do - Implement initial settings
// check initial config
err := utils.CheckInitialSettings()
if err != nil{
// Create custom http server
httpServer := &http.Server{
Handler: loggedRouter,
- // To Do - Implement config
Addr: ":" + config.GetConfiguration().ServicePort,
}
connectionsClose := make(chan struct{})
}()
// Start server
- log.Fatal(httpServer.ListenAndServe())
-
+ 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("", "")
+ }
}