17 image "bpa-restapi-agent/internal/app"
19 "github.com/gorilla/mux"
22 // imageHandler is used to store backend implementations objects
23 // Also simplifies mocking for unit testing purposes
24 type imageHandler struct {
25 // Interface that implements Image operations
26 // We will set this variable with a mock interface for testing
27 client image.ImageManager
31 // CreateHandler handles creation of the image entry in the database
33 func (h imageHandler) createHandler(w http.ResponseWriter, r *http.Request) {
36 // Implemenation using multipart form
37 // Review and enable/remove at a later date
38 // Set Max size to 16mb here
39 err := r.ParseMultipartForm(16777216)
41 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
45 jsn := bytes.NewBuffer([]byte(r.FormValue("metadata")))
46 err = json.NewDecoder(jsn).Decode(&v)
49 http.Error(w, "Empty body", http.StatusBadRequest)
52 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
57 if v.ImageName == "" {
58 http.Error(w, "Missing name in POST request", http.StatusBadRequest)
64 http.Error(w, "Missing Owner in POST request", http.StatusBadRequest)
68 if v.ImageLength == 0 {
69 e := "Improper upload length"
70 w.WriteHeader(http.StatusBadRequest)
75 //Create file directory
76 dir, err := createFileDir(v.Type)
78 log.Fatal("Error creating file server directory", err)
81 //Read the file section and ignore the header
82 file, _, err := r.FormFile("file")
84 http.Error(w, "Unable to process file", http.StatusUnprocessableEntity)
90 //Convert the file content to base64 for storage
91 content, err := ioutil.ReadAll(file)
93 http.Error(w, "Unable to read file", http.StatusUnprocessableEntity)
97 v.Config = base64.StdEncoding.EncodeToString(content)
99 ret, err := h.client.Create(v)
101 http.Error(w, err.Error(), http.StatusInternalServerError)
105 filePath := path.Join(h.dirPath, v.ImageName)
106 file1, err := os.Create(filePath)
108 e := "Error creating file in filesystem"
109 log.Printf("%s %s\n", e, err)
110 w.WriteHeader(http.StatusInternalServerError)
116 w.Header().Set("Content-Type", "application/json")
117 w.WriteHeader(http.StatusCreated)
118 err = json.NewEncoder(w).Encode(ret)
120 http.Error(w, err.Error(), http.StatusInternalServerError)
127 func createFileDir(dirName string) (string, error) {
128 u, err := user.Current()
130 log.Println("Error while fetching user home directory", err)
134 dirPath := path.Join(home, "images", dirName)
135 err = os.MkdirAll(dirPath, 0744)
137 log.Println("Error while creating file server directory", err)
143 // getHandler handles GET operations on a particular name
145 func (h imageHandler) getHandler(w http.ResponseWriter, r *http.Request) {
147 // ownerName := vars["owner"]
148 // clusterName := vars["clustername"]
149 imageName := vars["imgname"]
151 ret, err := h.client.Get(imageName)
153 http.Error(w, err.Error(), http.StatusInternalServerError)
157 w.Header().Set("Content-Type", "application/json")
158 w.WriteHeader(http.StatusOK)
159 err = json.NewEncoder(w).Encode(ret)
161 http.Error(w, err.Error(), http.StatusInternalServerError)
166 // deleteHandler handles DELETE operations on a particular record
167 func (h imageHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
169 // ownerName := vars["owner"]
170 // clusterName := vars["clustername"]
171 imageName := vars["imgname"]
173 err := h.client.Delete(imageName)
175 http.Error(w, err.Error(), http.StatusInternalServerError)
179 w.WriteHeader(http.StatusNoContent)
182 // UpdateHandler handles Update operations on a particular image
183 func (h imageHandler) updateHandler(w http.ResponseWriter, r *http.Request) {
186 imageName := vars["imgname"]
188 err := r.ParseMultipartForm(16777216)
190 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
194 jsn := bytes.NewBuffer([]byte(r.FormValue("metadata")))
195 err = json.NewDecoder(jsn).Decode(&v)
198 http.Error(w, "Empty body", http.StatusBadRequest)
201 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
206 if v.ImageName == "" {
207 http.Error(w, "Missing name in PUT request", http.StatusBadRequest)
211 // Owner is required.
213 http.Error(w, "Missing Owner in PUT request", http.StatusBadRequest)
217 //Read the file section and ignore the header
218 file, _, err := r.FormFile("file")
220 http.Error(w, "Unable to process file", http.StatusUnprocessableEntity)
226 //Convert the file content to base64 for storage
227 content, err := ioutil.ReadAll(file)
229 http.Error(w, "Unable to read file", http.StatusUnprocessableEntity)
233 v.Config = base64.StdEncoding.EncodeToString(content)
235 ret, err := h.client.Update(imageName, v)
237 http.Error(w, err.Error(), http.StatusInternalServerError)
241 w.Header().Set("Content-Type", "application/json")
242 w.WriteHeader(http.StatusCreated)
243 err = json.NewEncoder(w).Encode(ret)
245 http.Error(w, err.Error(), http.StatusInternalServerError)
250 // File upload is handled by the patchHandler
252 func (h imageHandler) patchHandler(w http.ResponseWriter, r *http.Request) {
253 log.Println("going to patch file")
255 imageName := vars["imgname"]
256 file, err := h.client.Get(imageName)
258 http.Error(w, err.Error(), http.StatusInternalServerError)
261 if *file.UploadComplete == true {
262 e := "Upload already completed"
263 w.WriteHeader(http.StatusUnprocessableEntity)
267 off, err := strconv.Atoi(r.Header.Get("Upload-Offset"))
269 log.Println("Improper upload offset", err)
270 w.WriteHeader(http.StatusBadRequest)
273 log.Printf("Upload offset %d\n", off)
274 if *file.ImageOffset != off {
275 e := fmt.Sprintf("Expected Offset %d got offset %d", *file.ImageOffset, off)
276 w.WriteHeader(http.StatusConflict)
281 log.Println("Content length is", r.Header.Get("Content-Length"))
282 clh := r.Header.Get("Content-Length")
283 cl, err := strconv.Atoi(clh)
285 log.Println("unknown content length")
286 w.WriteHeader(http.StatusInternalServerError)
290 if cl != (file.ImageLength - *file.ImageOffset) {
291 e := fmt.Sprintf("Content length doesn't match upload length. Expected content length %d got %d", file.ImageLength-*file.ImageOffset, cl)
293 w.WriteHeader(http.StatusBadRequest)
298 body, err := ioutil.ReadAll(r.Body)
300 log.Printf("Received file partially %s\n", err)
301 log.Println("Size of received file ", len(body))
304 u, err := user.Current()
306 log.Println("Error while fetching user home directory", err)
310 dir := path.Join(home, "images", file.Type)
312 fp := fmt.Sprintf("%s/%s", h.dirPath, imageName)
313 f, err := os.OpenFile(fp, os.O_APPEND|os.O_WRONLY, 0644)
315 log.Printf("unable to open file %s\n", err)
316 w.WriteHeader(http.StatusInternalServerError)
321 n, err := f.WriteAt(body, int64(off))
323 log.Printf("unable to write %s", err)
324 w.WriteHeader(http.StatusInternalServerError)
327 log.Println("number of bytes written ", n)
328 no := *file.ImageOffset + n
329 file.ImageOffset = &no
331 uo := strconv.Itoa(*file.ImageOffset)
332 w.Header().Set("Upload-Offset", uo)
333 if *file.ImageOffset == file.ImageLength {
334 log.Println("upload completed successfully")
335 *file.UploadComplete = true
338 // err = h.updateFile(file)
340 // log.Println("Error while updating file", err)
341 // w.WriteHeader(http.StatusInternalServerError)
344 w.WriteHeader(http.StatusNoContent)