Implementing image update inside patchHandler
[icn.git] / cmd / bpa-restapi-agent / internal / app / image.go
1 package app
2
3 import (
4   //"encoding/base64"
5         "encoding/json"
6         "os"
7         "os/user"
8         "path"
9         //"io/ioutil"
10
11         "bpa-restapi-agent/internal/db"
12
13         pkgerrors "github.com/pkg/errors"
14 )
15
16 // Image contains the parameters needed for Image information
17 type Image struct {
18         Owner                           string               `json:"owner"`
19         ClusterName         string               `json:"cluster_name"`
20         Type                string               `json:"type"`
21         ImageName           string               `json:"image_name"`
22         ImageOffset                                     *int                                                       `json:"image_offset"`
23         ImageLength                                     int                                                                      `json:"image_length"`
24         UploadComplete                  *bool                                                            `json:"upload_complete"`
25         Description         ImageRecordList      `json:"description"`
26 }
27
28 type ImageRecordList struct {
29         ImageRecords []map[string]string `json:"image_records"`
30 }
31
32 // ImageKey is the key structure that is used in the database
33 type ImageKey struct {
34         ImageName        string     `json:"image_name"`
35 }
36
37 // We will use json marshalling to convert to string to
38 // preserve the underlying structure.
39 func (dk ImageKey) String() string {
40         out, err := json.Marshal(dk)
41         if err != nil {
42                 return ""
43         }
44
45         return string(out)
46 }
47
48 // ImageManager is an interface that exposes the Image functionality
49 type ImageManager interface {
50         Create(c Image) (Image, error)
51         Get(imageName string) (Image, error)
52         Delete(imageName string) error
53         Update(imageName string, c Image) (Image, error)
54         GetImageRecordByName(imgname, imageName string) (map[string]string, error)
55         GetDirPath(imageName string) (string, string, error)
56 }
57
58 // ImageClient implements the ImageManager
59 // It will also be used to maintain some localized state
60 type ImageClient struct {
61         storeName string
62         tagMeta   string
63 }
64
65 // To Do - Fix repetition in
66 // NewImageClient returns an instance of the ImageClient
67 // which implements the ImageManager
68 func NewBinaryImageClient() *ImageClient {
69         return &ImageClient{
70                 storeName: "binary_images",
71                 tagMeta:   "metadata",
72         }
73 }
74
75 func NewContainerImageClient() *ImageClient {
76         return &ImageClient{
77                 storeName: "container_images",
78                 tagMeta:   "metadata",
79         }
80 }
81
82 func NewOSImageClient() *ImageClient {
83         return &ImageClient{
84                 storeName: "os_images",
85                 tagMeta:   "metadata",
86         }
87 }
88
89 // Create an entry for the Image resource in the database`
90 func (v *ImageClient) Create(c Image) (Image, error) {
91
92         //Construct composite key consisting of name
93         key := ImageKey{
94                 ImageName: c.ImageName,
95         }
96
97         //Check if this Image already exists
98         _, err := v.Get(c.ImageName)
99         if err == nil {
100                 return Image{}, pkgerrors.New("Image already exists")
101         }
102
103         err = db.DBconn.Create(v.storeName, key, v.tagMeta, c)
104         if err != nil {
105                 return Image{}, pkgerrors.Wrap(err, "Creating DB Entry")
106         }
107
108         //Create file
109         err = v.CreateFile(v.storeName, c)
110         if err != nil {
111                 return Image{}, pkgerrors.Wrap(err, "Creating File in FS")
112         }
113
114         return c, nil
115 }
116
117
118 // Create file
119
120 func (v *ImageClient) CreateFile(dirName string, c Image) error {
121
122     filePath, dirPath, err := v.GetDirPath(c.ImageName)
123                 if err != nil {
124                         return pkgerrors.Wrap(err, "Get file path")
125                 }
126     err = os.MkdirAll(dirPath, 0744)
127     if err != nil {
128                         return pkgerrors.Wrap(err, "Make image directory")
129     }
130                 file1, err := os.Create(filePath)
131                 if err != nil {
132                         return pkgerrors.Wrap(err, "Create image file")
133                 }
134
135                 defer file1.Close()
136
137
138     return nil
139 }
140
141 // Get returns Image for corresponding to name
142 func (v *ImageClient) Get(imageName string) (Image, error) {
143
144         //Construct the composite key to select the entry
145         key := ImageKey{
146                 // Owner:       ownerName,
147                 // ClusterName: clusterName,
148                 ImageName: imageName,
149         }
150
151         value, err := db.DBconn.Read(v.storeName, key, v.tagMeta)
152         if err != nil {
153                 return Image{}, pkgerrors.Wrap(err, "Get Image")
154         }
155
156         //value is a byte array
157         if value != nil {
158                 c := Image{}
159                 err = db.DBconn.Unmarshal(value, &c)
160                 if err != nil {
161                         return Image{}, pkgerrors.Wrap(err, "Unmarshaling Value")
162                 }
163                 return c, nil
164         }
165
166         return Image{}, pkgerrors.New("Error getting Connection")
167 }
168
169 func (v *ImageClient) GetImageRecordByName(imgName string,
170         imageRecordName string) (map[string]string, error) {
171
172         img, err := v.Get(imgName)
173         if err != nil {
174                 return nil, pkgerrors.Wrap(err, "Error getting image")
175         }
176
177         for _, value := range img.Description.ImageRecords {
178                 if imageRecordName == value["image_record_name"] {
179                         return value, nil
180                 }
181         }
182
183         return nil, pkgerrors.New("Image record " + imageRecordName + " not found")
184 }
185
186 func (v *ImageClient) GetDirPath(imageName string) (string, string, error) {
187         u, err := user.Current()
188         if err != nil {
189                 return "", "", pkgerrors.Wrap(err, "Current user")
190         }
191         home := u.HomeDir
192         dirPath := path.Join(home, "images", v.storeName)
193         filePath := path.Join(dirPath, imageName)
194
195         return filePath, dirPath, err
196 }
197
198 // Delete the Image from database
199 func (v *ImageClient) Delete(imageName string) error {
200
201         //Construct the composite key to select the entry
202         key := ImageKey{
203                 ImageName: imageName,
204         }
205         err := db.DBconn.Delete(v.storeName, key, v.tagMeta)
206         if err != nil {
207                 return pkgerrors.Wrap(err, "Delete Image")
208         }
209         //Delete image from FS
210         filePath, _, err := v.GetDirPath(imageName)
211         if err != nil {
212                 return pkgerrors.Wrap(err, "Get file path")
213         }
214         err = os.Remove(filePath)
215         if err != nil {
216                 return pkgerrors.Wrap(err, "Delete image file")
217         }
218
219         return nil
220 }
221
222 // Update an entry for the image in the database
223 func (v *ImageClient) Update(imageName string, c Image) (Image, error) {
224
225         key := ImageKey{
226                 // Owner:       c.Owner,
227                 // ClusterName: c.ClusterName,
228                 ImageName: imageName,
229         }
230
231         //Check if this Image exists
232         _, err := v.Get(imageName)
233         if err != nil {
234                 return Image{}, pkgerrors.New("Update Error - Image doesn't exist")
235         }
236
237         err = db.DBconn.Update(v.storeName, key, v.tagMeta, c)
238         if err != nil {
239                 return Image{}, pkgerrors.Wrap(err, "Updating DB Entry")
240         }
241
242         return c, nil
243 }