func volumeStartHandler(w http.ResponseWriter, r *http.Request) { p := mux.Vars(r) volname := p["volname"] log.Info("In Volume start API") vol, e := volume.GetVolume(volname) if e != nil { rest.SendHTTPError(w, http.StatusBadRequest, errors.ErrVolNotFound.Error()) return } if vol.Status == volume.VolStarted { rest.SendHTTPError(w, http.StatusBadRequest, errors.ErrVolAlreadyStarted.Error()) return } // A simple one-step transaction to start the brick processes txn := transaction.NewTxn() defer txn.Cleanup() lock, unlock, err := transaction.CreateLockSteps(volname) if err != nil { rest.SendHTTPError(w, http.StatusInternalServerError, err.Error()) return } txn.Nodes = vol.Nodes() txn.Steps = []*transaction.Step{ lock, &transaction.Step{ DoFunc: "vol-start.Commit", UndoFunc: "vol-start.Undo", Nodes: txn.Nodes, }, unlock, } txn.Ctx.Set("volname", volname) _, e = txn.Do() if e != nil { log.WithFields(log.Fields{ "error": e.Error(), "volume": volname, }).Error("failed to start volume") rest.SendHTTPError(w, http.StatusInternalServerError, e.Error()) return } vol.Status = volume.VolStarted e = volume.AddOrUpdateVolumeFunc(vol) if e != nil { rest.SendHTTPError(w, http.StatusInternalServerError, e.Error()) return } log.WithField("volume", vol.Name).Debug("Volume updated into the store") rest.SendHTTPResponse(w, http.StatusOK, vol) }
func volumeStatusHandler(w http.ResponseWriter, r *http.Request) { p := mux.Vars(r) volname := p["volname"] // Ensure that the volume exists. vol, err := volume.GetVolume(volname) if err != nil { rest.SendHTTPError(w, http.StatusNotFound, errors.ErrVolNotFound.Error()) } // A very simple free-form transaction to query each node for brick // status. Fetching volume status does not modify state/data on the // remote node. So there's no need for locks. txn := transaction.NewTxn() defer txn.Cleanup() txn.Nodes = vol.Nodes() txn.Steps = []*transaction.Step{ &transaction.Step{ DoFunc: "vol-status.Check", Nodes: txn.Nodes, }, } // The remote nodes get args it needs from the transaction context. txn.Ctx.Set("volname", volname) // As all key-value pairs stored in transaction context ends up in etcd // store, using either the old txn context reference or the one // returned by txn.Do() is one and the same. The transaction context is // a way for the nodes store the results of the step runs. rtxn, err := txn.Do() if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "volume": volname, }).Error("volumeStatusHandler: Failed to get volume status.") rest.SendHTTPError(w, http.StatusInternalServerError, err.Error()) return } // Example of how an aggregate function will make sense from results of // run of a step on multiple nodes. The transaction context will have // results from each node, seggregated by the node's UUID. result, err := aggregateVolumeStatus(rtxn, txn.Nodes) if err != nil { errMsg := "Failed to aggregate brick status results from multiple nodes." log.WithField("error", err.Error()).Error("volumeStatusHandler:" + errMsg) rest.SendHTTPError(w, http.StatusInternalServerError, errMsg) return } // Send aggregated result back to the client. rest.SendHTTPResponse(w, http.StatusOK, result) }