package app
import (
- //"encoding/base64"
- "encoding/json"
- //"io/ioutil"
-
"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"`
- Config string `json:"config"`
- ImageOffset *int `json:"image_offset"`
- ImageLength int `json:"image_length"`
- UploadComplete *bool `json:"upload_complete"`
- Description ImageRecordList `json:"description"`
+ Owner string `json:"owner"`
+ ClusterName string `json:"cluster_name"`
+ Type string `json:"type"`
+ ImageName string `json:"image_name"`
+ ImageOffset *int `json:"image_offset"`
+ ImageLength int `json:"image_length"`
+ UploadComplete *bool `json:"upload_complete"`
+ Description ImageRecordList `json:"description"`
}
type ImageRecordList struct {
// ImageKey is the key structure that is used in the database
type ImageKey struct {
- // Owner string `json:"owner"`
- // ClusterName string `json:"cluster_name"`
- ImageName string `json:"image_name"`
+ ImageName string `json:"image_name"`
}
// We will use json marshalling to convert to string to
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)
+ OSMakeDir(dirpath string, perm int) error
+ OSCreateFile(filePath string) error
+ GetPath(user *user.User, imageName string, storeName string) (string, string)
+ DBDelete(storeName string, key ImageKey, meta string) error
+ OSRemove(filePath string) error
+ DBUpdate(storeName string, key ImageKey, tagMeta string, c Image) error
}
// ImageClient implements the ImageManager
// It will also be used to maintain some localized state
type ImageClient struct {
+ util Utility
storeName string
tagMeta string
}
+type DBService struct {
+}
+
// To Do - Fix repetition in
// NewImageClient returns an instance of the ImageClient
// which implements the ImageManager
func NewBinaryImageClient() *ImageClient {
+ service := DBService{}
return &ImageClient{
- storeName: "binary_image",
+ util: service,
+ storeName: "binary_images",
tagMeta: "metadata",
}
}
func NewContainerImageClient() *ImageClient {
+ service := DBService{}
return &ImageClient{
- storeName: "container_image",
+ util: service,
+ storeName: "container_images",
tagMeta: "metadata",
}
}
func NewOSImageClient() *ImageClient {
+ service := DBService{}
return &ImageClient{
- storeName: "os_image",
+ 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{
- // Owner: c.Owner,
- // ClusterName: c.ClusterName,
ImageName: c.ImageName,
}
return Image{}, pkgerrors.New("Image already exists")
}
- err = db.DBconn.Create(v.storeName, key, v.tagMeta, c)
+ err = v.util.DBCreate(v.storeName, key, v.tagMeta, c)
if err != nil {
return Image{}, pkgerrors.Wrap(err, "Creating DB Entry")
}
+ err = v.CreateFile(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 = v.util.OSMakeDir(dirPath, 0744)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Make image directory")
+ }
+ err = v.util.OSCreateFile(filePath)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Create image file")
+ }
+
+ return nil
+}
+
+func (d DBService) OSMakeDir(dirPath string, perm int) error {
+ err := os.MkdirAll(dirPath, 0744)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Make image directory")
+ }
+ return nil
+}
+
+func (d DBService) OSCreateFile(filePath string) error {
+ file1, err := os.Create(filePath)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Create image file")
+ }
+ defer file1.Close()
+
+ return nil
+}
+
// Get returns Image for corresponding to name
func (v *ImageClient) Get(imageName string) (Image, error) {
ImageName: imageName,
}
- value, err := db.DBconn.Read(v.storeName, key, v.tagMeta)
+ value, err := v.util.DBRead(v.storeName, key, v.tagMeta)
if err != nil {
return Image{}, pkgerrors.Wrap(err, "Get Image")
}
//value is a byte array
if value != nil {
- c := Image{}
- err = db.DBconn.Unmarshal(value, &c)
+ c, err := v.util.DBUnmarshal(value)
if err != nil {
return Image{}, pkgerrors.Wrap(err, "Unmarshaling Value")
}
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) {
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 {
// ClusterName: clusterName,
ImageName: imageName,
}
- err := db.DBconn.Delete(v.storeName, key, v.tagMeta)
+ 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 = v.util.OSRemove(filePath)
+
+ return nil
+}
+
+func (d DBService) OSRemove(filePath string) error {
+ err := os.Remove(filePath)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Delete image file")
+ }
+
+ return nil
+}
+
+func (d DBService) DBDelete(storeName string, key ImageKey, tagMeta string) error {
+ err := db.DBconn.Delete(storeName, key, tagMeta)
if err != nil {
return pkgerrors.Wrap(err, "Delete Image")
}
+
return nil
}
func (v *ImageClient) Update(imageName string, c Image) (Image, error) {
key := ImageKey{
- // Owner: c.Owner,
- // ClusterName: c.ClusterName,
ImageName: imageName,
}
return Image{}, pkgerrors.New("Update Error - Image doesn't exist")
}
- err = db.DBconn.Update(v.storeName, key, v.tagMeta, c)
+ err = v.util.DBUpdate(v.storeName, key, v.tagMeta, c)
+
+ return c, nil
+}
+
+func (d DBService) DBUpdate(storeName string, key ImageKey, tagMeta string, c Image) error {
+ err := db.DBconn.Update(storeName, key, tagMeta, c)
+ if err != nil {
+ return 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 Image{}, pkgerrors.Wrap(err, "Updating DB Entry")
+ return nil, pkgerrors.Wrap(err, "Current user")
}
- return c, nil
+ 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
}