func fileStoreHandler(w http.ResponseWriter, r *http.Request) { /* We *don't* always set the the content-type to application/json here, * for obvious reasons. Still do for the PUT/POST though. */ chksum := r.URL.Path[12:] /* Eventually, both local storage (in-memory or on disk, depending) or * uploading to s3 or a similar cloud storage provider needs to be * supported. */ switch r.Method { case "GET": w.Header().Set("Content-Type", "application/x-binary") fileStore, err := filestore.Get(chksum) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } w.Write(*fileStore.Data) case "PUT", "POST": /* Seems like for file uploads we ought to * support POST too. */ w.Header().Set("Content-Type", "application/json") /* Need to distinguish file already existing and some * sort of error with uploading the file. */ if fileStore, _ := filestore.Get(chksum); fileStore != nil { fileErr := fmt.Errorf("File with checksum %s already exists.", chksum) /* Send status OK. It seems chef-pedant at least * tries to upload files twice for some reason. */ jsonErrorReport(w, r, fileErr.Error(), http.StatusOK) return } fileStore, err := filestore.New(chksum, r.Body, r.ContentLength) if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } err = fileStore.Save() if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } fileResponse := make(map[string]string) fileResponse[fileStore.Chksum] = fmt.Sprintf("File with checksum %s uploaded.", fileStore.Chksum) enc := json.NewEncoder(w) if err := enc.Encode(&fileResponse); err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) } /* Add DELETE later? */ default: jsonErrorReport(w, r, "Unrecognized method!", http.StatusMethodNotAllowed) } }
// IsComplete returns true if the sandbox is complete. func (s *Sandbox) IsComplete() error { for _, chk := range s.Checksums { k, _ := filestore.Get(chk) if k == nil { err := fmt.Errorf("Checksum %s not uploaded yet, %s not complete, cannot commit yet.", chk, s.ID) return err } } return nil }
// UploadChkList builds the list of file checksums and whether or not they need // to be uploaded. If they do, the upload URL is also provided. func (s *Sandbox) UploadChkList() map[string]map[string]interface{} { /* Uh... */ chksumStats := make(map[string]map[string]interface{}) for _, chk := range s.Checksums { chksumStats[chk] = make(map[string]interface{}) k, _ := filestore.Get(chk) if k != nil { chksumStats[chk]["needs_upload"] = false } else { itemURL := fmt.Sprintf("/file_store/%s", chk) chksumStats[chk]["url"] = util.CustomURL(itemURL) chksumStats[chk]["needs_upload"] = true } } return chksumStats }
func ValidateCookbookDivision(dname string, div interface{}) ([]map[string]interface{}, Gerror) { switch div := div.(type) { case []interface{}: var d []map[string]interface{} err := Errorf("Invalid element in array value of '%s'.", dname) for _, v := range div { switch v := v.(type) { case map[string]interface{}: if len(v) < 4 { return nil, err } /* validate existence of file * in sandbox */ chksum, cherr := ValidateAsString(v["checksum"]) if cherr == nil { if _, ferr := filestore.Get(chksum); ferr != nil { var merr Gerror /* This is nuts. */ if dname == "recipes" { merr = Errorf("Manifest has a checksum that hasn't been uploaded.") } else { merr = Errorf("Manifest has checksum %s but it hasn't yet been uploaded", chksum) } return nil, merr } itemURL := fmt.Sprintf("/file_store/%s", chksum) v["url"] = CustomURL(itemURL) d = append(d, v) } default: return nil, err } } return d, nil case nil: /* This the way? */ // d := make([]map[string]interface{}, 0) return nil, nil default: err := Errorf("Field '%s' invalid", dname) return nil, err } }