Support --local parameter for Status[Local] and Sync[Local] operations
This allows to call the Rest API's status and sync endpoints with a "?local=true" parameter. This will trigger operations but only on the local peer. Cluster *Local and RPC-*Local methods have been accordingly, although they are aliases for the PinTracker methods (but otherwise they would not be exposed in external APIs). ipfs-cluster-ctl has been updated to support the new flag. The rationaly behind this feature is that sometimes, a single cluster peer (or the ipfs daemon in it) is misbehaving. The user then wants to Sync, Recover, or see Status for that single peer. This is specially relevant when working with big pinsets in larger clusters, as a Status() call will be considerably more expensive when broadcasted everywhere. Note that the Rest API keeps returning GlobalPinInfo objects even on local=true calls. This ensures that the user always gets the same datatype from an endpoint. License: MIT Signed-off-by: Hector Sanjuan <code@hector.link>
This commit is contained in:
parent
e824aea55e
commit
4922c95589
|
@ -426,46 +426,98 @@ func (api *API) allocationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) statusAllHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) statusAllHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var pinInfos []types.GlobalPinInfoSerial
|
queryValues := r.URL.Query()
|
||||||
err := api.rpcClient.Call("",
|
local := queryValues.Get("local")
|
||||||
"Cluster",
|
|
||||||
"StatusAll",
|
if local == "true" {
|
||||||
struct{}{},
|
var pinInfos []types.PinInfoSerial
|
||||||
&pinInfos)
|
err := api.rpcClient.Call("",
|
||||||
sendResponse(w, err, pinInfos)
|
"Cluster",
|
||||||
|
"StatusAllLocal",
|
||||||
|
struct{}{},
|
||||||
|
&pinInfos)
|
||||||
|
sendResponse(w, err, pinInfosToGlobal(pinInfos))
|
||||||
|
} else {
|
||||||
|
var pinInfos []types.GlobalPinInfoSerial
|
||||||
|
err := api.rpcClient.Call("",
|
||||||
|
"Cluster",
|
||||||
|
"StatusAll",
|
||||||
|
struct{}{},
|
||||||
|
&pinInfos)
|
||||||
|
sendResponse(w, err, pinInfos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) statusHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) statusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
queryValues := r.URL.Query()
|
||||||
|
local := queryValues.Get("local")
|
||||||
|
|
||||||
if c := parseCidOrError(w, r); c.Cid != "" {
|
if c := parseCidOrError(w, r); c.Cid != "" {
|
||||||
var pinInfo types.GlobalPinInfoSerial
|
if local == "true" {
|
||||||
err := api.rpcClient.Call("",
|
var pinInfo types.PinInfoSerial
|
||||||
"Cluster",
|
err := api.rpcClient.Call("",
|
||||||
"Status",
|
"Cluster",
|
||||||
c,
|
"StatusLocal",
|
||||||
&pinInfo)
|
c,
|
||||||
sendResponse(w, err, pinInfo)
|
&pinInfo)
|
||||||
|
sendResponse(w, err, pinInfoToGlobal(pinInfo))
|
||||||
|
} else {
|
||||||
|
var pinInfo types.GlobalPinInfoSerial
|
||||||
|
err := api.rpcClient.Call("",
|
||||||
|
"Cluster",
|
||||||
|
"Status",
|
||||||
|
c,
|
||||||
|
&pinInfo)
|
||||||
|
sendResponse(w, err, pinInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) syncAllHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) syncAllHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var pinInfos []types.GlobalPinInfoSerial
|
queryValues := r.URL.Query()
|
||||||
err := api.rpcClient.Call("",
|
local := queryValues.Get("local")
|
||||||
"Cluster",
|
|
||||||
"SyncAll",
|
if local == "true" {
|
||||||
struct{}{},
|
var pinInfos []types.PinInfoSerial
|
||||||
&pinInfos)
|
err := api.rpcClient.Call("",
|
||||||
sendResponse(w, err, pinInfos)
|
"Cluster",
|
||||||
|
"SyncAllLocal",
|
||||||
|
struct{}{},
|
||||||
|
&pinInfos)
|
||||||
|
sendResponse(w, err, pinInfosToGlobal(pinInfos))
|
||||||
|
} else {
|
||||||
|
var pinInfos []types.GlobalPinInfoSerial
|
||||||
|
err := api.rpcClient.Call("",
|
||||||
|
"Cluster",
|
||||||
|
"SyncAll",
|
||||||
|
struct{}{},
|
||||||
|
&pinInfos)
|
||||||
|
sendResponse(w, err, pinInfos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) syncHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) syncHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
queryValues := r.URL.Query()
|
||||||
|
local := queryValues.Get("local")
|
||||||
|
|
||||||
if c := parseCidOrError(w, r); c.Cid != "" {
|
if c := parseCidOrError(w, r); c.Cid != "" {
|
||||||
var pinInfo types.GlobalPinInfoSerial
|
if local == "true" {
|
||||||
err := api.rpcClient.Call("",
|
var pinInfo types.PinInfoSerial
|
||||||
"Cluster",
|
err := api.rpcClient.Call("",
|
||||||
"Sync",
|
"Cluster",
|
||||||
c,
|
"SyncLocal",
|
||||||
&pinInfo)
|
c,
|
||||||
sendResponse(w, err, pinInfo)
|
&pinInfo)
|
||||||
|
sendResponse(w, err, pinInfoToGlobal(pinInfo))
|
||||||
|
} else {
|
||||||
|
var pinInfo types.GlobalPinInfoSerial
|
||||||
|
err := api.rpcClient.Call("",
|
||||||
|
"Cluster",
|
||||||
|
"Sync",
|
||||||
|
c,
|
||||||
|
&pinInfo)
|
||||||
|
sendResponse(w, err, pinInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,21 +531,17 @@ func (api *API) recoverAllHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
"RecoverAllLocal",
|
"RecoverAllLocal",
|
||||||
struct{}{},
|
struct{}{},
|
||||||
&pinInfos)
|
&pinInfos)
|
||||||
sendResponse(w, err, pinInfos)
|
sendResponse(w, err, pinInfosToGlobal(pinInfos))
|
||||||
} else {
|
} else {
|
||||||
sendErrorResponse(w, 400, "only requests with parameter local=true are supported")
|
sendErrorResponse(w, 400, "only requests with parameter local=true are supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) recoverHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *API) recoverHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
queryValues := r.URL.Query()
|
||||||
|
local := queryValues.Get("local")
|
||||||
|
|
||||||
if c := parseCidOrError(w, r); c.Cid != "" {
|
if c := parseCidOrError(w, r); c.Cid != "" {
|
||||||
queryValues := r.URL.Query()
|
|
||||||
local := queryValues.Get("local")
|
|
||||||
|
|
||||||
// Is it RESTful to return two different types
|
|
||||||
// depending on a flag? Should PinInfo
|
|
||||||
// be converted to a GlobalPinInfo ?
|
|
||||||
|
|
||||||
if local == "true" {
|
if local == "true" {
|
||||||
var pinInfo types.PinInfoSerial
|
var pinInfo types.PinInfoSerial
|
||||||
err := api.rpcClient.Call("",
|
err := api.rpcClient.Call("",
|
||||||
|
@ -501,7 +549,7 @@ func (api *API) recoverHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
"RecoverLocal",
|
"RecoverLocal",
|
||||||
c,
|
c,
|
||||||
&pinInfo)
|
&pinInfo)
|
||||||
sendResponse(w, err, pinInfo)
|
sendResponse(w, err, pinInfoToGlobal(pinInfo))
|
||||||
} else {
|
} else {
|
||||||
var pinInfo types.GlobalPinInfoSerial
|
var pinInfo types.GlobalPinInfoSerial
|
||||||
err := api.rpcClient.Call("",
|
err := api.rpcClient.Call("",
|
||||||
|
@ -548,6 +596,23 @@ func parsePidOrError(w http.ResponseWriter, r *http.Request) peer.ID {
|
||||||
return pid
|
return pid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pinInfoToGlobal(pInfo types.PinInfoSerial) types.GlobalPinInfoSerial {
|
||||||
|
return types.GlobalPinInfoSerial{
|
||||||
|
Cid: pInfo.Cid,
|
||||||
|
PeerMap: map[string]types.PinInfoSerial{
|
||||||
|
pInfo.Peer: pInfo,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pinInfosToGlobal(pInfos []types.PinInfoSerial) []types.GlobalPinInfoSerial {
|
||||||
|
gPInfos := make([]types.GlobalPinInfoSerial, len(pInfos), len(pInfos))
|
||||||
|
for i, p := range pInfos {
|
||||||
|
gPInfos[i] = pinInfoToGlobal(p)
|
||||||
|
}
|
||||||
|
return gPInfos
|
||||||
|
}
|
||||||
|
|
||||||
func sendResponse(w http.ResponseWriter, rpcErr error, resp interface{}) {
|
func sendResponse(w http.ResponseWriter, rpcErr error, resp interface{}) {
|
||||||
if checkRPCErr(w, rpcErr) {
|
if checkRPCErr(w, rpcErr) {
|
||||||
sendJSONResponse(w, 200, resp)
|
sendJSONResponse(w, 200, resp)
|
||||||
|
|
|
@ -232,7 +232,14 @@ func TestAPIStatusAllEndpoint(t *testing.T) {
|
||||||
if len(resp) != 3 ||
|
if len(resp) != 3 ||
|
||||||
resp[0].Cid != test.TestCid1 ||
|
resp[0].Cid != test.TestCid1 ||
|
||||||
resp[1].PeerMap[test.TestPeerID1.Pretty()].Status != "pinning" {
|
resp[1].PeerMap[test.TestPeerID1.Pretty()].Status != "pinning" {
|
||||||
t.Errorf("unexpected statusResp:\n %+v", resp)
|
t.Errorf("unexpected statusAll resp:\n %+v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test local=true
|
||||||
|
var resp2 []api.GlobalPinInfoSerial
|
||||||
|
makeGet(t, "/pins?local=true", &resp2)
|
||||||
|
if len(resp2) != 2 {
|
||||||
|
t.Errorf("unexpected statusAll+local resp:\n %+v", resp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +260,21 @@ func TestAPIStatusEndpoint(t *testing.T) {
|
||||||
if info.Status != "pinned" {
|
if info.Status != "pinned" {
|
||||||
t.Error("expected different status")
|
t.Error("expected different status")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test local=true
|
||||||
|
var resp2 api.GlobalPinInfoSerial
|
||||||
|
makeGet(t, "/pins/"+test.TestCid1+"?local=true", &resp2)
|
||||||
|
|
||||||
|
if resp2.Cid != test.TestCid1 {
|
||||||
|
t.Error("expected the same cid")
|
||||||
|
}
|
||||||
|
info, ok = resp2.PeerMap[test.TestPeerID2.Pretty()]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected info for test.TestPeerID2")
|
||||||
|
}
|
||||||
|
if info.Status != "pinned" {
|
||||||
|
t.Error("expected different status")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPISyncAllEndpoint(t *testing.T) {
|
func TestAPISyncAllEndpoint(t *testing.T) {
|
||||||
|
@ -265,7 +287,15 @@ func TestAPISyncAllEndpoint(t *testing.T) {
|
||||||
if len(resp) != 3 ||
|
if len(resp) != 3 ||
|
||||||
resp[0].Cid != test.TestCid1 ||
|
resp[0].Cid != test.TestCid1 ||
|
||||||
resp[1].PeerMap[test.TestPeerID1.Pretty()].Status != "pinning" {
|
resp[1].PeerMap[test.TestPeerID1.Pretty()].Status != "pinning" {
|
||||||
t.Errorf("unexpected statusResp:\n %+v", resp)
|
t.Errorf("unexpected syncAll resp:\n %+v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test local=true
|
||||||
|
var resp2 []api.GlobalPinInfoSerial
|
||||||
|
makePost(t, "/pins/sync?local=true", []byte{}, &resp2)
|
||||||
|
|
||||||
|
if len(resp2) != 2 {
|
||||||
|
t.Errorf("unexpected syncAll+local resp:\n %+v", resp2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +316,21 @@ func TestAPISyncEndpoint(t *testing.T) {
|
||||||
if info.Status != "pinned" {
|
if info.Status != "pinned" {
|
||||||
t.Error("expected different status")
|
t.Error("expected different status")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test local=true
|
||||||
|
var resp2 api.GlobalPinInfoSerial
|
||||||
|
makePost(t, "/pins/"+test.TestCid1+"/sync?local=true", []byte{}, &resp2)
|
||||||
|
|
||||||
|
if resp2.Cid != test.TestCid1 {
|
||||||
|
t.Error("expected the same cid")
|
||||||
|
}
|
||||||
|
info, ok = resp2.PeerMap[test.TestPeerID2.Pretty()]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected info for test.TestPeerID2")
|
||||||
|
}
|
||||||
|
if info.Status != "pinned" {
|
||||||
|
t.Error("expected different status")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIRecoverEndpoint(t *testing.T) {
|
func TestAPIRecoverEndpoint(t *testing.T) {
|
||||||
|
@ -311,7 +356,7 @@ func TestAPIRecoverAllEndpoint(t *testing.T) {
|
||||||
rest := testAPI(t)
|
rest := testAPI(t)
|
||||||
defer rest.Shutdown()
|
defer rest.Shutdown()
|
||||||
|
|
||||||
var resp []api.PinInfoSerial
|
var resp []api.GlobalPinInfoSerial
|
||||||
makePost(t, "/pins/recover?local=true", []byte{}, &resp)
|
makePost(t, "/pins/recover?local=true", []byte{}, &resp)
|
||||||
|
|
||||||
if len(resp) != 0 {
|
if len(resp) != 0 {
|
||||||
|
|
60
cluster.go
60
cluster.go
|
@ -835,20 +835,40 @@ func (c *Cluster) StateSync() ([]api.PinInfo, error) {
|
||||||
return infos, nil
|
return infos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatusAll returns the GlobalPinInfo for all tracked Cids. If an error
|
// StatusAll returns the GlobalPinInfo for all tracked Cids in all peers.
|
||||||
// happens, the slice will contain as much information as could be fetched.
|
// If an error happens, the slice will contain as much information as
|
||||||
|
// could be fetched from other peers.
|
||||||
func (c *Cluster) StatusAll() ([]api.GlobalPinInfo, error) {
|
func (c *Cluster) StatusAll() ([]api.GlobalPinInfo, error) {
|
||||||
return c.globalPinInfoSlice("TrackerStatusAll")
|
return c.globalPinInfoSlice("TrackerStatusAll")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status returns the GlobalPinInfo for a given Cid. If an error happens,
|
// StatusAllLocal returns the PinInfo for all the tracked Cids in this peer.
|
||||||
// the GlobalPinInfo should contain as much information as could be fetched.
|
func (c *Cluster) StatusAllLocal() []api.PinInfo {
|
||||||
|
return c.tracker.StatusAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns the GlobalPinInfo for a given Cid as fetched from all
|
||||||
|
// current peers. If an error happens, the GlobalPinInfo should contain
|
||||||
|
// as much information as could be fetched from the other peers.
|
||||||
func (c *Cluster) Status(h *cid.Cid) (api.GlobalPinInfo, error) {
|
func (c *Cluster) Status(h *cid.Cid) (api.GlobalPinInfo, error) {
|
||||||
return c.globalPinInfoCid("TrackerStatus", h)
|
return c.globalPinInfoCid("TrackerStatus", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatusLocal returns this peer's PinInfo for a given Cid.
|
||||||
|
func (c *Cluster) StatusLocal(h *cid.Cid) api.PinInfo {
|
||||||
|
return c.tracker.Status(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncAll triggers SyncAllLocal() operations in all cluster peers, making sure
|
||||||
|
// that the state of tracked items matches the state reported by the IPFS daemon
|
||||||
|
// and returning the results as GlobalPinInfo. If an error happens, the slice
|
||||||
|
// will contain as much information as could be fetched from the peers.
|
||||||
|
func (c *Cluster) SyncAll() ([]api.GlobalPinInfo, error) {
|
||||||
|
return c.globalPinInfoSlice("SyncAllLocal")
|
||||||
|
}
|
||||||
|
|
||||||
// SyncAllLocal makes sure that the current state for all tracked items
|
// SyncAllLocal makes sure that the current state for all tracked items
|
||||||
// matches the state reported by the IPFS daemon.
|
// in this peer matches the state reported by the IPFS daemon.
|
||||||
//
|
//
|
||||||
// SyncAllLocal returns the list of PinInfo that where updated because of
|
// SyncAllLocal returns the list of PinInfo that where updated because of
|
||||||
// the operation, along with those in error states.
|
// the operation, along with those in error states.
|
||||||
|
@ -863,6 +883,12 @@ func (c *Cluster) SyncAllLocal() ([]api.PinInfo, error) {
|
||||||
return syncedItems, err
|
return syncedItems, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sync triggers a LocalSyncCid() operation for a given Cid
|
||||||
|
// in all cluster peers.
|
||||||
|
func (c *Cluster) Sync(h *cid.Cid) (api.GlobalPinInfo, error) {
|
||||||
|
return c.globalPinInfoCid("SyncLocal", h)
|
||||||
|
}
|
||||||
|
|
||||||
// SyncLocal performs a local sync operation for the given Cid. This will
|
// SyncLocal performs a local sync operation for the given Cid. This will
|
||||||
// tell the tracker to verify the status of the Cid against the IPFS daemon.
|
// tell the tracker to verify the status of the Cid against the IPFS daemon.
|
||||||
// It returns the updated PinInfo for the Cid.
|
// It returns the updated PinInfo for the Cid.
|
||||||
|
@ -878,23 +904,7 @@ func (c *Cluster) SyncLocal(h *cid.Cid) (api.PinInfo, error) {
|
||||||
return pInfo, err
|
return pInfo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncAll triggers LocalSync() operations in all cluster peers.
|
// RecoverAllLocal triggers a RecoverLocal operation for all Cids tracked
|
||||||
func (c *Cluster) SyncAll() ([]api.GlobalPinInfo, error) {
|
|
||||||
return c.globalPinInfoSlice("SyncAllLocal")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync triggers a LocalSyncCid() operation for a given Cid
|
|
||||||
// in all cluster peers.
|
|
||||||
func (c *Cluster) Sync(h *cid.Cid) (api.GlobalPinInfo, error) {
|
|
||||||
return c.globalPinInfoCid("SyncLocal", h)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecoverLocal triggers a recover operation for a given Cid.
|
|
||||||
func (c *Cluster) RecoverLocal(h *cid.Cid) (api.PinInfo, error) {
|
|
||||||
return c.tracker.Recover(h)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RecoverAllLocal triggers a recover operation for all Cids tracked
|
|
||||||
// by this peer.
|
// by this peer.
|
||||||
func (c *Cluster) RecoverAllLocal() ([]api.PinInfo, error) {
|
func (c *Cluster) RecoverAllLocal() ([]api.PinInfo, error) {
|
||||||
return c.tracker.RecoverAll()
|
return c.tracker.RecoverAll()
|
||||||
|
@ -906,6 +916,12 @@ func (c *Cluster) Recover(h *cid.Cid) (api.GlobalPinInfo, error) {
|
||||||
return c.globalPinInfoCid("TrackerRecover", h)
|
return c.globalPinInfoCid("TrackerRecover", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RecoverLocal triggers a recover operation for a given Cid in this peer only.
|
||||||
|
// It returns the updated PinInfo, after recovery.
|
||||||
|
func (c *Cluster) RecoverLocal(h *cid.Cid) (api.PinInfo, error) {
|
||||||
|
return c.tracker.Recover(h)
|
||||||
|
}
|
||||||
|
|
||||||
// Pins returns the list of Cids managed by Cluster and which are part
|
// Pins returns the list of Cids managed by Cluster and which are part
|
||||||
// of the current global state. This is the source of truth as to which
|
// of the current global state. This is the source of truth as to which
|
||||||
// pins are managed and their allocation, but does not indicate if
|
// pins are managed and their allocation, but does not indicate if
|
||||||
|
|
|
@ -327,16 +327,27 @@ item.
|
||||||
|
|
||||||
The status of a CID may not be accurate. A manual sync can be triggered
|
The status of a CID may not be accurate. A manual sync can be triggered
|
||||||
with "sync".
|
with "sync".
|
||||||
|
|
||||||
|
When the --local flag is passed, it will only fetch the status from the
|
||||||
|
contacted cluster peer. By default, status will be fetched from all peers.
|
||||||
`,
|
`,
|
||||||
ArgsUsage: "[CID]",
|
ArgsUsage: "[CID]",
|
||||||
Flags: []cli.Flag{parseFlag(formatGPInfo)},
|
Flags: []cli.Flag{
|
||||||
|
parseFlag(formatGPInfo),
|
||||||
|
localFlag(),
|
||||||
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
|
local := "false"
|
||||||
|
if c.Bool("local") {
|
||||||
|
local = "true"
|
||||||
|
}
|
||||||
|
|
||||||
cidStr := c.Args().First()
|
cidStr := c.Args().First()
|
||||||
if cidStr != "" {
|
if cidStr != "" {
|
||||||
_, err := cid.Decode(cidStr)
|
_, err := cid.Decode(cidStr)
|
||||||
checkErr("parsing cid", err)
|
checkErr("parsing cid", err)
|
||||||
}
|
}
|
||||||
resp := request("GET", "/pins/"+cidStr, nil)
|
resp := request("GET", "/pins/"+cidStr+"?local="+local, nil)
|
||||||
formatResponse(c, resp)
|
formatResponse(c, resp)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -355,18 +366,28 @@ have changed status because of the sync or are in error state in some node,
|
||||||
therefore, the output should be empty if no operations were performed.
|
therefore, the output should be empty if no operations were performed.
|
||||||
|
|
||||||
CIDs in error state may be manually recovered with "recover".
|
CIDs in error state may be manually recovered with "recover".
|
||||||
|
|
||||||
|
When the --local flag is passed, it will only trigger sync
|
||||||
|
operations on the contacted peer. By default, all peers will sync.
|
||||||
`,
|
`,
|
||||||
ArgsUsage: "[CID]",
|
ArgsUsage: "[CID]",
|
||||||
Flags: []cli.Flag{parseFlag(formatGPInfo)},
|
Flags: []cli.Flag{
|
||||||
|
parseFlag(formatGPInfo),
|
||||||
|
localFlag(),
|
||||||
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
|
local := "false"
|
||||||
|
if c.Bool("local") {
|
||||||
|
local = "true"
|
||||||
|
}
|
||||||
cidStr := c.Args().First()
|
cidStr := c.Args().First()
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
if cidStr != "" {
|
if cidStr != "" {
|
||||||
_, err := cid.Decode(cidStr)
|
_, err := cid.Decode(cidStr)
|
||||||
checkErr("parsing cid", err)
|
checkErr("parsing cid", err)
|
||||||
resp = request("POST", "/pins/"+cidStr+"/sync", nil)
|
resp = request("POST", "/pins/"+cidStr+"/sync?local="+local, nil)
|
||||||
} else {
|
} else {
|
||||||
resp = request("POST", "/pins/sync", nil)
|
resp = request("POST", "/pins/sync?local="+local, nil)
|
||||||
}
|
}
|
||||||
formatResponse(c, resp)
|
formatResponse(c, resp)
|
||||||
return nil
|
return nil
|
||||||
|
@ -383,22 +404,18 @@ The command will wait for any operations to succeed and will return the status
|
||||||
of the item upon completion. Note that, when running on the full sets of tracked
|
of the item upon completion. Note that, when running on the full sets of tracked
|
||||||
CIDs (without argument), it may take considerable long time.
|
CIDs (without argument), it may take considerable long time.
|
||||||
|
|
||||||
A --local flag must be passed. This will only trigger recover
|
When the --local flag is passed, it will only trigger recover
|
||||||
operations on the contacted peer (and not on every peer).
|
operations on the contacted peer (as opposed to on every peer).
|
||||||
`,
|
`,
|
||||||
ArgsUsage: "[CID]",
|
ArgsUsage: "[CID]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
parseFlag(formatGPInfo),
|
parseFlag(formatGPInfo),
|
||||||
cli.BoolFlag{
|
localFlag(),
|
||||||
Name: "local",
|
|
||||||
Usage: "recover only on the contacted peer",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
local := "false"
|
local := "false"
|
||||||
if c.Bool("local") {
|
if c.Bool("local") {
|
||||||
local = "true"
|
local = "true"
|
||||||
c.Set("parseAs", fmt.Sprintf("%d", formatPInfo))
|
|
||||||
}
|
}
|
||||||
cidStr := c.Args().First()
|
cidStr := c.Args().First()
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
|
@ -453,6 +470,13 @@ func parseFlag(t int) cli.IntFlag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func localFlag() cli.BoolFlag {
|
||||||
|
return cli.BoolFlag{
|
||||||
|
Name: "local",
|
||||||
|
Usage: "run operation only on the contacted peer",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func walkCommands(cmds []cli.Command, parentHelpName string) {
|
func walkCommands(cmds []cli.Command, parentHelpName string) {
|
||||||
for _, c := range cmds {
|
for _, c := range cmds {
|
||||||
h := c.HelpName
|
h := c.HelpName
|
||||||
|
|
63
rpc_api.go
63
rpc_api.go
|
@ -108,6 +108,13 @@ func (rpcapi *RPCAPI) StatusAll(in struct{}, out *[]api.GlobalPinInfoSerial) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatusAllLocal runs Cluster.StatusAllLocal().
|
||||||
|
func (rpcapi *RPCAPI) StatusAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
pinfos := rpcapi.c.StatusAllLocal()
|
||||||
|
*out = pinInfoSliceToSerial(pinfos)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Status runs Cluster.Status().
|
// Status runs Cluster.Status().
|
||||||
func (rpcapi *RPCAPI) Status(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
func (rpcapi *RPCAPI) Status(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
||||||
c := in.ToPin().Cid
|
c := in.ToPin().Cid
|
||||||
|
@ -116,19 +123,12 @@ func (rpcapi *RPCAPI) Status(in api.PinSerial, out *api.GlobalPinInfoSerial) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncAllLocal runs Cluster.SyncAllLocal().
|
// StatusLocal runs Cluster.StatusLocal().
|
||||||
func (rpcapi *RPCAPI) SyncAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
func (rpcapi *RPCAPI) StatusLocal(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
pinfos, err := rpcapi.c.SyncAllLocal()
|
|
||||||
*out = pinInfoSliceToSerial(pinfos)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncLocal runs Cluster.SyncLocal().
|
|
||||||
func (rpcapi *RPCAPI) SyncLocal(in api.PinSerial, out *api.PinInfoSerial) error {
|
|
||||||
c := in.ToPin().Cid
|
c := in.ToPin().Cid
|
||||||
pinfo, err := rpcapi.c.SyncLocal(c)
|
pinfo := rpcapi.c.StatusLocal(c)
|
||||||
*out = pinfo.ToSerial()
|
*out = pinfo.ToSerial()
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncAll runs Cluster.SyncAll().
|
// SyncAll runs Cluster.SyncAll().
|
||||||
|
@ -138,6 +138,13 @@ func (rpcapi *RPCAPI) SyncAll(in struct{}, out *[]api.GlobalPinInfoSerial) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SyncAllLocal runs Cluster.SyncAllLocal().
|
||||||
|
func (rpcapi *RPCAPI) SyncAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
pinfos, err := rpcapi.c.SyncAllLocal()
|
||||||
|
*out = pinInfoSliceToSerial(pinfos)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Sync runs Cluster.Sync().
|
// Sync runs Cluster.Sync().
|
||||||
func (rpcapi *RPCAPI) Sync(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
func (rpcapi *RPCAPI) Sync(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
||||||
c := in.ToPin().Cid
|
c := in.ToPin().Cid
|
||||||
|
@ -146,9 +153,17 @@ func (rpcapi *RPCAPI) Sync(in api.PinSerial, out *api.GlobalPinInfoSerial) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateSync runs Cluster.StateSync().
|
// SyncLocal runs Cluster.SyncLocal().
|
||||||
func (rpcapi *RPCAPI) StateSync(in struct{}, out *[]api.PinInfoSerial) error {
|
func (rpcapi *RPCAPI) SyncLocal(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
pinfos, err := rpcapi.c.StateSync()
|
c := in.ToPin().Cid
|
||||||
|
pinfo, err := rpcapi.c.SyncLocal(c)
|
||||||
|
*out = pinfo.ToSerial()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecoverAllLocal runs Cluster.RecoverAllLocal().
|
||||||
|
func (rpcapi *RPCAPI) RecoverAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
pinfos, err := rpcapi.c.RecoverAllLocal()
|
||||||
*out = pinInfoSliceToSerial(pinfos)
|
*out = pinInfoSliceToSerial(pinfos)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -169,9 +184,9 @@ func (rpcapi *RPCAPI) RecoverLocal(in api.PinSerial, out *api.PinInfoSerial) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecoverAllLocal runs Cluster.RecoverAllLocal().
|
// StateSync runs Cluster.StateSync().
|
||||||
func (rpcapi *RPCAPI) RecoverAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
func (rpcapi *RPCAPI) StateSync(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
pinfos, err := rpcapi.c.RecoverAllLocal()
|
pinfos, err := rpcapi.c.StateSync()
|
||||||
*out = pinInfoSliceToSerial(pinfos)
|
*out = pinInfoSliceToSerial(pinfos)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -205,6 +220,13 @@ func (rpcapi *RPCAPI) TrackerStatus(in api.PinSerial, out *api.PinInfoSerial) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TrackerRecoverAll runs PinTracker.RecoverAll().
|
||||||
|
func (rpcapi *RPCAPI) TrackerRecoverAll(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
pinfos, err := rpcapi.c.tracker.RecoverAll()
|
||||||
|
*out = pinInfoSliceToSerial(pinfos)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// TrackerRecover runs PinTracker.Recover().
|
// TrackerRecover runs PinTracker.Recover().
|
||||||
func (rpcapi *RPCAPI) TrackerRecover(in api.PinSerial, out *api.PinInfoSerial) error {
|
func (rpcapi *RPCAPI) TrackerRecover(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
c := in.ToPin().Cid
|
c := in.ToPin().Cid
|
||||||
|
@ -213,13 +235,6 @@ func (rpcapi *RPCAPI) TrackerRecover(in api.PinSerial, out *api.PinInfoSerial) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrackerRecoverAll runs PinTracker.RecoverAll().
|
|
||||||
func (rpcapi *RPCAPI) TrackerRecoverAll(in struct{}, out *[]api.PinInfoSerial) error {
|
|
||||||
pinfos, err := rpcapi.c.tracker.RecoverAll()
|
|
||||||
*out = pinInfoSliceToSerial(pinfos)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
IPFS Connector component methods
|
IPFS Connector component methods
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -118,15 +118,6 @@ func (mock *mockService) PeerRemove(in peer.ID, out *struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: dup from util.go
|
|
||||||
func globalPinInfoSliceToSerial(gpi []api.GlobalPinInfo) []api.GlobalPinInfoSerial {
|
|
||||||
gpis := make([]api.GlobalPinInfoSerial, len(gpi), len(gpi))
|
|
||||||
for i, v := range gpi {
|
|
||||||
gpis[i] = v.ToSerial()
|
|
||||||
}
|
|
||||||
return gpis
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mock *mockService) StatusAll(in struct{}, out *[]api.GlobalPinInfoSerial) error {
|
func (mock *mockService) StatusAll(in struct{}, out *[]api.GlobalPinInfoSerial) error {
|
||||||
c1, _ := cid.Decode(TestCid1)
|
c1, _ := cid.Decode(TestCid1)
|
||||||
c2, _ := cid.Decode(TestCid2)
|
c2, _ := cid.Decode(TestCid2)
|
||||||
|
@ -169,6 +160,10 @@ func (mock *mockService) StatusAll(in struct{}, out *[]api.GlobalPinInfoSerial)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) StatusAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
return mock.TrackerStatusAll(in, out)
|
||||||
|
}
|
||||||
|
|
||||||
func (mock *mockService) Status(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
func (mock *mockService) Status(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
||||||
if in.Cid == ErrorCid {
|
if in.Cid == ErrorCid {
|
||||||
return ErrBadCid
|
return ErrBadCid
|
||||||
|
@ -188,24 +183,95 @@ func (mock *mockService) Status(in api.PinSerial, out *api.GlobalPinInfoSerial)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) StatusLocal(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
|
return mock.TrackerStatus(in, out)
|
||||||
|
}
|
||||||
|
|
||||||
func (mock *mockService) SyncAll(in struct{}, out *[]api.GlobalPinInfoSerial) error {
|
func (mock *mockService) SyncAll(in struct{}, out *[]api.GlobalPinInfoSerial) error {
|
||||||
return mock.StatusAll(in, out)
|
return mock.StatusAll(in, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) SyncAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
return mock.StatusAllLocal(in, out)
|
||||||
|
}
|
||||||
|
|
||||||
func (mock *mockService) Sync(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
func (mock *mockService) Sync(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
||||||
return mock.Status(in, out)
|
return mock.Status(in, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) SyncLocal(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
|
return mock.StatusLocal(in, out)
|
||||||
|
}
|
||||||
|
|
||||||
func (mock *mockService) StateSync(in struct{}, out *[]api.PinInfoSerial) error {
|
func (mock *mockService) StateSync(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
*out = make([]api.PinInfoSerial, 0, 0)
|
*out = make([]api.PinInfoSerial, 0, 0)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) RecoverAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
return mock.TrackerRecoverAll(in, out)
|
||||||
|
}
|
||||||
|
|
||||||
func (mock *mockService) Recover(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
func (mock *mockService) Recover(in api.PinSerial, out *api.GlobalPinInfoSerial) error {
|
||||||
return mock.Status(in, out)
|
return mock.Status(in, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mock *mockService) RecoverLocal(in api.PinSerial, out *api.PinInfoSerial) error {
|
func (mock *mockService) RecoverLocal(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
|
return mock.TrackerRecover(in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tracker methods */
|
||||||
|
|
||||||
|
func (mock *mockService) Track(in api.PinSerial, out *struct{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) Untrack(in api.PinSerial, out *struct{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) TrackerStatusAll(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
c1, _ := cid.Decode(TestCid1)
|
||||||
|
c3, _ := cid.Decode(TestCid3)
|
||||||
|
|
||||||
|
*out = pinInfoSliceToSerial([]api.PinInfo{
|
||||||
|
{
|
||||||
|
Cid: c1,
|
||||||
|
Peer: TestPeerID1,
|
||||||
|
Status: api.TrackerStatusPinned,
|
||||||
|
TS: time.Now(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Cid: c3,
|
||||||
|
Peer: TestPeerID1,
|
||||||
|
Status: api.TrackerStatusPinError,
|
||||||
|
TS: time.Now(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) TrackerStatus(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
|
if in.Cid == ErrorCid {
|
||||||
|
return ErrBadCid
|
||||||
|
}
|
||||||
|
c1, _ := cid.Decode(TestCid1)
|
||||||
|
|
||||||
|
*out = api.PinInfo{
|
||||||
|
Cid: c1,
|
||||||
|
Peer: TestPeerID2,
|
||||||
|
Status: api.TrackerStatusPinned,
|
||||||
|
TS: time.Now(),
|
||||||
|
}.ToSerial()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) TrackerRecoverAll(in struct{}, out *[]api.PinInfoSerial) error {
|
||||||
|
*out = make([]api.PinInfoSerial, 0, 0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mock *mockService) TrackerRecover(in api.PinSerial, out *api.PinInfoSerial) error {
|
||||||
in2 := in.ToPin()
|
in2 := in.ToPin()
|
||||||
*out = api.PinInfo{
|
*out = api.PinInfo{
|
||||||
Cid: in2.Cid,
|
Cid: in2.Cid,
|
||||||
|
@ -216,19 +282,6 @@ func (mock *mockService) RecoverLocal(in api.PinSerial, out *api.PinInfoSerial)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mock *mockService) RecoverAllLocal(in struct{}, out *[]api.PinInfoSerial) error {
|
|
||||||
*out = make([]api.PinInfoSerial, 0, 0)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mock *mockService) Track(in api.PinSerial, out *struct{}) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mock *mockService) Untrack(in api.PinSerial, out *struct{}) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PeerManager methods */
|
/* PeerManager methods */
|
||||||
|
|
||||||
func (mock *mockService) PeerManagerAddPeer(in api.MultiaddrSerial, out *struct{}) error {
|
func (mock *mockService) PeerManagerAddPeer(in api.MultiaddrSerial, out *struct{}) error {
|
||||||
|
@ -301,3 +354,21 @@ func (mock *mockService) ConsensusPeers(in struct{}, out *[]peer.ID) error {
|
||||||
*out = []peer.ID{TestPeerID1, TestPeerID2, TestPeerID3}
|
*out = []peer.ID{TestPeerID1, TestPeerID2, TestPeerID3}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: dup from util.go
|
||||||
|
func globalPinInfoSliceToSerial(gpi []api.GlobalPinInfo) []api.GlobalPinInfoSerial {
|
||||||
|
gpis := make([]api.GlobalPinInfoSerial, len(gpi), len(gpi))
|
||||||
|
for i, v := range gpi {
|
||||||
|
gpis[i] = v.ToSerial()
|
||||||
|
}
|
||||||
|
return gpis
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: dup from util.go
|
||||||
|
func pinInfoSliceToSerial(pi []api.PinInfo) []api.PinInfoSerial {
|
||||||
|
pis := make([]api.PinInfoSerial, len(pi), len(pi))
|
||||||
|
for i, v := range pi {
|
||||||
|
pis[i] = v.ToSerial()
|
||||||
|
}
|
||||||
|
return pis
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user