func reindexAll() { reindexObjs := make([]indexer.Indexable, 0, 100) // We clear the index, *then* do the fetch because if // something comes in between the time we fetch the // objects to reindex and when it gets done, they'll // just be added naturally indexer.ClearIndex() for _, v := range client.AllClients() { reindexObjs = append(reindexObjs, v) } for _, v := range node.AllNodes() { reindexObjs = append(reindexObjs, v) } for _, v := range role.AllRoles() { reindexObjs = append(reindexObjs, v) } for _, v := range environment.AllEnvironments() { reindexObjs = append(reindexObjs, v) } defaultEnv, _ := environment.Get("_default") reindexObjs = append(reindexObjs, defaultEnv) // data bags have to be done separately dbags := databag.GetList() for _, db := range dbags { dbag, err := databag.Get(db) if err != nil { continue } dbis := make([]indexer.Indexable, dbag.NumDBItems()) i := 0 allDBItems, derr := dbag.AllDBItems() if derr != nil { logger.Errorf(derr.Error()) continue } for _, k := range allDBItems { n := k dbis[i] = n i++ } reindexObjs = append(reindexObjs, dbis...) } indexer.ReIndex(reindexObjs) return }
func getResults(variety string, toGet []string) []indexer.Indexable { var results []indexer.Indexable if len(toGet) > 0 { switch variety { case "node": ns, _ := node.GetMulti(toGet) // .... results = make([]indexer.Indexable, 0, len(ns)) for _, n := range ns { results = append(results, n) } case "role": rs, _ := role.GetMulti(toGet) results = make([]indexer.Indexable, 0, len(rs)) for _, r := range rs { results = append(results, r) } case "client": cs, _ := client.GetMulti(toGet) results = make([]indexer.Indexable, 0, len(cs)) for _, c := range cs { results = append(results, c) } case "environment": es, _ := environment.GetMulti(toGet) results = make([]indexer.Indexable, 0, len(es)) for _, e := range es { results = append(results, e) } default: // It's a data bag /* These may require further processing later. */ dbag, _ := databag.Get(variety) if dbag != nil { ds, _ := dbag.GetMultiDBItems(toGet) results = make([]indexer.Indexable, 0, len(ds)) for _, d := range ds { results = append(results, d) } } } } return results }
func dataHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") pathArray := splitPath(r.URL.Path) dbResponse := make(map[string]interface{}) opUser, oerr := actor.GetReqUser(r.Header.Get("X-OPS-USERID")) if oerr != nil { jsonErrorReport(w, r, oerr.Error(), oerr.Status()) return } if len(pathArray) == 1 { /* Either a list of data bags, or a POST to create a new one */ switch r.Method { case "GET": if opUser.IsValidator() { jsonErrorReport(w, r, "You are not allowed to perform this action", http.StatusForbidden) return } /* The list */ dbList := databag.GetList() for _, k := range dbList { dbResponse[k] = util.CustomURL(fmt.Sprintf("/data/%s", k)) } case "POST": if !opUser.IsAdmin() { jsonErrorReport(w, r, "You are not allowed to perform this action", http.StatusForbidden) return } dbData, jerr := parseObjJSON(r.Body) if jerr != nil { jsonErrorReport(w, r, jerr.Error(), http.StatusBadRequest) return } /* check that the name exists */ switch t := dbData["name"].(type) { case string: if t == "" { jsonErrorReport(w, r, "Field 'name' missing", http.StatusBadRequest) return } default: jsonErrorReport(w, r, "Field 'name' missing", http.StatusBadRequest) return } chefDbag, _ := databag.Get(dbData["name"].(string)) if chefDbag != nil { httperr := fmt.Errorf("Data bag %s already exists.", dbData["name"].(string)) jsonErrorReport(w, r, httperr.Error(), http.StatusConflict) return } chefDbag, nerr := databag.New(dbData["name"].(string)) if nerr != nil { jsonErrorReport(w, r, nerr.Error(), nerr.Status()) return } serr := chefDbag.Save() if serr != nil { jsonErrorReport(w, r, serr.Error(), http.StatusInternalServerError) return } if lerr := loginfo.LogEvent(opUser, chefDbag, "create"); lerr != nil { jsonErrorReport(w, r, lerr.Error(), http.StatusInternalServerError) return } dbResponse["uri"] = util.ObjURL(chefDbag) w.WriteHeader(http.StatusCreated) default: /* The chef-pedant spec wants this response for * some reason. Mix it up, I guess. */ w.Header().Set("Allow", "GET, POST") jsonErrorReport(w, r, "GET, POST", http.StatusMethodNotAllowed) return } } else { dbName := pathArray[1] /* chef-pedant is unhappy about not reporting the HTTP status * as 404 by fetching the data bag before we see if the method * is allowed, so do a quick check for that here. */ if (len(pathArray) == 2 && r.Method == "PUT") || (len(pathArray) == 3 && r.Method == "POST") { var allowed string if len(pathArray) == 2 { allowed = "GET, POST, DELETE" } else { allowed = "GET, PUT, DELETE" } w.Header().Set("Allow", allowed) jsonErrorReport(w, r, "Method not allowed", http.StatusMethodNotAllowed) return } if opUser.IsValidator() || (!opUser.IsAdmin() && r.Method != "GET") { jsonErrorReport(w, r, "You are not allowed to perform this action", http.StatusForbidden) return } chefDbag, err := databag.Get(dbName) if err != nil { var errMsg string status := err.Status() if r.Method == "POST" { /* Posts get a special snowflake message */ errMsg = fmt.Sprintf("No data bag '%s' could be found. Please create this data bag before adding items to it.", dbName) } else { if len(pathArray) == 3 { /* This is nuts. */ if r.Method == "DELETE" { errMsg = fmt.Sprintf("Cannot load data bag %s item %s", dbName, pathArray[2]) } else { errMsg = fmt.Sprintf("Cannot load data bag item %s for data bag %s", pathArray[2], dbName) } } else { errMsg = err.Error() } } jsonErrorReport(w, r, errMsg, status) return } if len(pathArray) == 2 { /* getting list of data bag items and creating data bag * items. */ switch r.Method { case "GET": for _, k := range chefDbag.ListDBItems() { dbResponse[k] = util.CustomObjURL(chefDbag, k) } case "DELETE": /* The chef API docs don't say anything * about this existing, but it does, * and without it you can't delete data * bags at all. */ dbResponse["chef_type"] = "data_bag" dbResponse["json_class"] = "Chef::DataBag" dbResponse["name"] = chefDbag.Name err := chefDbag.Delete() if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } if lerr := loginfo.LogEvent(opUser, chefDbag, "delete"); lerr != nil { jsonErrorReport(w, r, lerr.Error(), http.StatusInternalServerError) return } case "POST": rawData := databag.RawDataBagJSON(r.Body) dbitem, nerr := chefDbag.NewDBItem(rawData) if nerr != nil { jsonErrorReport(w, r, nerr.Error(), nerr.Status()) return } if lerr := loginfo.LogEvent(opUser, dbitem, "create"); lerr != nil { jsonErrorReport(w, r, lerr.Error(), http.StatusInternalServerError) return } /* The data bag return values are all * kinds of weird. Sometimes it sends * just the raw data, sometimes it sends * the whole object, sometimes a special * snowflake version. Ugh. Have to loop * through to avoid updating the pointer * in the cache by just assigning * dbitem.RawData to dbResponse. Urk. */ for k, v := range dbitem.RawData { dbResponse[k] = v } dbResponse["data_bag"] = dbitem.DataBagName dbResponse["chef_type"] = dbitem.ChefType w.WriteHeader(http.StatusCreated) default: w.Header().Set("Allow", "GET, DELETE, POST") jsonErrorReport(w, r, "GET, DELETE, POST", http.StatusMethodNotAllowed) return } } else { /* getting, editing, and deleting existing data bag items. */ dbItemName := pathArray[2] if _, err := chefDbag.GetDBItem(dbItemName); err != nil { var httperr string if r.Method != "DELETE" { httperr = fmt.Sprintf("Cannot load data bag item %s for data bag %s", dbItemName, chefDbag.Name) } else { httperr = fmt.Sprintf("Cannot load data bag %s item %s", chefDbag.Name, dbItemName) } jsonErrorReport(w, r, httperr, http.StatusNotFound) return } switch r.Method { case "GET": dbi, err := chefDbag.GetDBItem(dbItemName) if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } dbResponse = dbi.RawData case "DELETE": dbi, err := chefDbag.GetDBItem(dbItemName) if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } /* Gotta short circuit this */ enc := json.NewEncoder(w) if err := enc.Encode(&dbi); err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } err = chefDbag.DeleteDBItem(dbItemName) if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } if lerr := loginfo.LogEvent(opUser, dbi, "delete"); lerr != nil { jsonErrorReport(w, r, lerr.Error(), http.StatusInternalServerError) return } return case "PUT": rawData := databag.RawDataBagJSON(r.Body) if rawID, ok := rawData["id"]; ok { switch rawID := rawID.(type) { case string: if rawID != dbItemName { jsonErrorReport(w, r, "DataBagItem name mismatch.", http.StatusBadRequest) return } default: jsonErrorReport(w, r, "Bad request", http.StatusBadRequest) return } } dbitem, err := chefDbag.UpdateDBItem(dbItemName, rawData) if err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) return } if lerr := loginfo.LogEvent(opUser, dbitem, "modify"); lerr != nil { jsonErrorReport(w, r, lerr.Error(), http.StatusInternalServerError) return } /* Another weird data bag item response * which isn't at all unusual. */ for k, v := range dbitem.RawData { dbResponse[k] = v } dbResponse["data_bag"] = dbitem.DataBagName dbResponse["chef_type"] = dbitem.ChefType dbResponse["id"] = dbItemName default: w.Header().Set("Allow", "GET, DELETE, PUT") jsonErrorReport(w, r, "GET, DELETE, PUT", http.StatusMethodNotAllowed) return } } } enc := json.NewEncoder(w) if err := enc.Encode(&dbResponse); err != nil { jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError) } }