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