2 * Copyright 2020 Intel Corporation, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
30 "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation"
31 moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module"
33 "github.com/gorilla/mux"
34 pkgerrors "github.com/pkg/errors"
37 /* Used to store backend implementation objects
38 Also simplifies mocking for unit testing purposes
40 type appProfileHandler struct {
41 client moduleLib.AppProfileManager
44 // createAppProfileHandler handles the create operation
45 func (h appProfileHandler) createAppProfileHandler(w http.ResponseWriter, r *http.Request) {
48 project := vars["project-name"]
49 compositeApp := vars["composite-app-name"]
50 compositeAppVersion := vars["composite-app-version"]
51 compositeProfile := vars["composite-profile-name"]
53 var ap moduleLib.AppProfile
54 var ac moduleLib.AppProfileContent
56 // Implemenation using multipart form
57 // Review and enable/remove at a later date
58 // Set Max size to 16mb here
59 err := r.ParseMultipartForm(16777216)
61 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
65 jsn := bytes.NewBuffer([]byte(r.FormValue("metadata")))
66 err = json.NewDecoder(jsn).Decode(&ap)
69 http.Error(w, "Empty body", http.StatusBadRequest)
72 http.Error(w, err.Error(), http.StatusUnprocessableEntity)
76 //Read the file section and ignore the header
77 file, _, err := r.FormFile("file")
79 http.Error(w, "Unable to process file", http.StatusUnprocessableEntity)
85 //Convert the file content to base64 for storage
86 content, err := ioutil.ReadAll(file)
88 http.Error(w, "Unable to read file", http.StatusUnprocessableEntity)
92 err = validation.IsTarGz(bytes.NewBuffer(content))
94 http.Error(w, "Error in file format", http.StatusUnprocessableEntity)
98 ac.Profile = base64.StdEncoding.EncodeToString(content)
101 if ap.Metadata.Name == "" {
102 http.Error(w, "Missing name in POST request", http.StatusBadRequest)
106 ret, err := h.client.CreateAppProfile(project, compositeApp, compositeAppVersion, compositeProfile, ap, ac)
108 http.Error(w, err.Error(), http.StatusInternalServerError)
112 w.WriteHeader(http.StatusCreated)
113 err = json.NewEncoder(w).Encode(ret)
115 http.Error(w, err.Error(), http.StatusInternalServerError)
120 // getHandler handles the GET operations on AppProfile
121 func (h appProfileHandler) getAppProfileHandler(w http.ResponseWriter, r *http.Request) {
123 project := vars["project-name"]
124 compositeApp := vars["composite-app-name"]
125 compositeAppVersion := vars["composite-app-version"]
126 compositeProfile := vars["composite-profile-name"]
127 name := vars["app-profile"]
128 appName := r.URL.Query().Get("app-name")
130 if len(name) != 0 && len(appName) != 0 {
131 http.Error(w, pkgerrors.New("Invalid query").Error(), http.StatusInternalServerError)
135 // handle the get all app profiles case - return a list of only the json parts
136 if len(name) == 0 && len(appName) == 0 {
137 var retList []moduleLib.AppProfile
139 ret, err := h.client.GetAppProfiles(project, compositeApp, compositeAppVersion, compositeProfile)
141 http.Error(w, err.Error(), http.StatusInternalServerError)
145 for _, ap := range ret {
146 retList = append(retList, ap)
149 w.Header().Set("Content-Type", "application/json")
150 w.WriteHeader(http.StatusOK)
151 err = json.NewEncoder(w).Encode(retList)
153 http.Error(w, err.Error(), http.StatusInternalServerError)
159 accepted, _, err := mime.ParseMediaType(r.Header.Get("Accept"))
161 http.Error(w, err.Error(), http.StatusNotAcceptable)
165 var retAppProfile moduleLib.AppProfile
166 var retAppProfileContent moduleLib.AppProfileContent
168 if len(appName) != 0 {
169 retAppProfile, err = h.client.GetAppProfileByApp(project, compositeApp, compositeAppVersion, compositeProfile, appName)
171 http.Error(w, err.Error(), http.StatusInternalServerError)
175 retAppProfileContent, err = h.client.GetAppProfileContentByApp(project, compositeApp, compositeAppVersion, compositeProfile, appName)
177 http.Error(w, err.Error(), http.StatusInternalServerError)
181 retAppProfile, err = h.client.GetAppProfile(project, compositeApp, compositeAppVersion, compositeProfile, name)
183 http.Error(w, err.Error(), http.StatusInternalServerError)
187 retAppProfileContent, err = h.client.GetAppProfileContent(project, compositeApp, compositeAppVersion, compositeProfile, name)
189 http.Error(w, err.Error(), http.StatusInternalServerError)
195 case "multipart/form-data":
196 mpw := multipart.NewWriter(w)
197 w.Header().Set("Content-Type", mpw.FormDataContentType())
198 w.WriteHeader(http.StatusOK)
199 pw, err := mpw.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/json"}, "Content-Disposition": {"form-data; name=metadata"}})
201 http.Error(w, err.Error(), http.StatusInternalServerError)
204 if err := json.NewEncoder(pw).Encode(retAppProfile); err != nil {
205 http.Error(w, err.Error(), http.StatusInternalServerError)
208 pw, err = mpw.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"form-data; name=file"}})
210 http.Error(w, err.Error(), http.StatusInternalServerError)
213 kcBytes, err := base64.StdEncoding.DecodeString(retAppProfileContent.Profile)
215 http.Error(w, err.Error(), http.StatusInternalServerError)
218 _, err = pw.Write(kcBytes)
220 http.Error(w, err.Error(), http.StatusInternalServerError)
223 case "application/json":
224 w.Header().Set("Content-Type", "application/json")
225 w.WriteHeader(http.StatusOK)
226 err = json.NewEncoder(w).Encode(retAppProfile)
228 http.Error(w, err.Error(), http.StatusInternalServerError)
231 case "application/octet-stream":
232 w.Header().Set("Content-Type", "application/octet-stream")
233 w.WriteHeader(http.StatusOK)
234 kcBytes, err := base64.StdEncoding.DecodeString(retAppProfileContent.Profile)
236 http.Error(w, err.Error(), http.StatusInternalServerError)
239 _, err = w.Write(kcBytes)
241 http.Error(w, err.Error(), http.StatusInternalServerError)
245 http.Error(w, "set Accept: multipart/form-data, application/json or application/octet-stream", http.StatusMultipleChoices)
250 // deleteHandler handles the delete operations on AppProfile
251 func (h appProfileHandler) deleteAppProfileHandler(w http.ResponseWriter, r *http.Request) {
253 project := vars["project-name"]
254 compositeApp := vars["composite-app-name"]
255 compositeAppVersion := vars["composite-app-version"]
256 compositeProfile := vars["composite-profile-name"]
257 name := vars["app-profile"]
259 err := h.client.DeleteAppProfile(project, compositeApp, compositeAppVersion, compositeProfile, name)
261 http.Error(w, err.Error(), http.StatusInternalServerError)
265 w.WriteHeader(http.StatusNoContent)