func deletePeerHandler(w http.ResponseWriter, r *http.Request) { // FIXME: This is not txn based, yet. Behaviour when multiple simultaneous // delete peer requests are sent to same node is unknown. peerReq := mux.Vars(r) id := peerReq["peerid"] if id == "" { rest.SendHTTPError(w, http.StatusBadRequest, "peerid not present in the request") return } // Check whether the member exists p, e := peer.GetPeerF(id) if e != nil || p == nil { rest.SendHTTPError(w, http.StatusNotFound, "peer not found in cluster") return } // Removing self should be disallowed (like in glusterd1) if id == gdctx.MyUUID.String() { rest.SendHTTPError(w, http.StatusBadRequest, "Removing self is disallowed.") return } remotePeerAddress, err := utils.FormRemotePeerAddress(p.Addresses[0]) if err != nil { rest.SendHTTPError(w, http.StatusBadRequest, err.Error()) return } // Validate whether the peer can be deleted rsp, e := ValidateDeletePeer(remotePeerAddress, id) if e != nil { rest.SendHTTPError(w, http.StatusInternalServerError, rsp.OpError) return } // Remove the peer from the store if e := peer.DeletePeer(id); e != nil { log.WithFields(log.Fields{ "er": e, "peer": id, }).Error("Failed to remove peer from the store") rest.SendHTTPError(w, http.StatusInternalServerError, e.Error()) } else { rest.SendHTTPResponse(w, http.StatusNoContent, nil) } // Delete member from etcd cluster e = etcdmgmt.EtcdMemberRemove(p.MemberID) if e != nil { log.WithFields(log.Fields{ "er": e, "peer": id, }).Error("Failed to remove member from etcd cluster") rest.SendHTTPError(w, http.StatusInternalServerError, e.Error()) return } // Remove data dir of etcd on remote machine. Restart etcd on remote machine // in standalone (single cluster) mode. var etcdConf EtcdConfigReq etcdConf.DeletePeer = true etcdrsp, e := ConfigureRemoteETCD(remotePeerAddress, &etcdConf) if e != nil { log.WithField("err", e).Error("Failed to configure remote etcd.") rest.SendHTTPError(w, http.StatusInternalServerError, etcdrsp.OpError) return } }
func addPeerHandler(w http.ResponseWriter, r *http.Request) { // FIXME: This is not txn based, yet. Behaviour when multiple simultaneous // add peer requests are sent to same node is unknown. var req PeerAddReq if e := utils.GetJSONFromRequest(r, &req); e != nil { rest.SendHTTPError(w, http.StatusBadRequest, e.Error()) return } if len(req.Addresses) < 1 { rest.SendHTTPError(w, http.StatusBadRequest, errors.ErrNoHostnamesPresent.Error()) return } // A peer can have multiple addresses. For now, we use only the first // address present in the req.Addresses list. remotePeerAddress, err := utils.FormRemotePeerAddress(req.Addresses[0]) if err != nil { rest.SendHTTPError(w, http.StatusBadRequest, err.Error()) return } // This remote call will return the remote peer's ID (UUID), name // and etcd peer url. remotePeer, e := ValidateAddPeer(remotePeerAddress, &req) if e != nil { rest.SendHTTPError(w, http.StatusInternalServerError, remotePeer.OpError) return } // TODO: Parse addresses considering ports to figure this out. if isPeerInCluster(remotePeer.UUID) { rest.SendHTTPError(w, http.StatusInternalServerError, "Peer already in cluster") return } // If user hasn't specified peer name, use the name returned by remote // peer which defaults to it's hostname. if req.Name == "" { req.Name = remotePeer.PeerName } // Adding a member is a two step process: // 1. Add the new member to the cluster via the members API. This is // performed on this node i.e the one that just accepted peer add // request from the user. // 2. Start the new member on the target node (the new peer) with the new // cluster configuration, including a list of the updated members // (existing members + the new member). newMember, e := etcdmgmt.EtcdMemberAdd("http://" + remotePeer.EtcdPeerAddress) if e != nil { log.WithFields(log.Fields{ "error": e, "uuid": remotePeer.UUID, "name": req.Name, "address": remotePeer.EtcdPeerAddress, }).Error("Failed to add member to etcd cluster.") rest.SendHTTPError(w, http.StatusInternalServerError, e.Error()) return } log.WithField("member-id", newMember.ID).Info("Added new member to etcd cluster") mlist, e := etcdmgmt.EtcdMemberList() if e != nil { log.WithField("error", e).Error("Failed to list members in etcd cluster") rest.SendHTTPError(w, http.StatusInternalServerError, e.Error()) return } // Member name of the newly added etcd member has not been set at this point. conf := []string{} for _, memb := range mlist { for _, u := range memb.PeerURLs { n := memb.Name if memb.ID == newMember.ID { n = remotePeer.UUID } conf = append(conf, fmt.Sprintf("%s=%s", n, u)) } } var etcdConf EtcdConfigReq etcdConf.EtcdName = remotePeer.UUID etcdConf.InitialCluster = strings.Join(conf, ",") etcdConf.ClusterState = "existing" log.WithField("initial-cluster", etcdConf.InitialCluster).Debug("Reconfiguring etcd on remote peer") etcdrsp, e := ConfigureRemoteETCD(remotePeerAddress, &etcdConf) if e != nil { log.WithField("err", e).Error("Failed to configure remote etcd") rest.SendHTTPError(w, http.StatusInternalServerError, etcdrsp.OpError) return } // Create a new peer object and add it to the store. p := &peer.Peer{ ID: uuid.Parse(remotePeer.UUID), Name: req.Name, Addresses: req.Addresses, MemberID: newMember.ID, } if e = peer.AddOrUpdatePeer(p); e != nil { log.WithFields(log.Fields{ "error": e, "peer/node": p.Name, }).Error("Failed to add peer into the etcd store") rest.SendHTTPError(w, http.StatusInternalServerError, e.Error()) return } body := map[string]uuid.UUID{"id": p.ID} rest.SendHTTPResponse(w, http.StatusCreated, body) }
// RunStepOn will run the step on the specified node func RunStepOn(step string, node uuid.UUID, c TxnCtx) (TxnCtx, error) { // TODO: I'm creating connections on demand. This should be changed so that // we have long term connections. p, err := peer.GetPeerF(node.String()) if err != nil { c.Logger().WithFields(log.Fields{ "peerid": node.String(), "error": err, }).Error("peer not found") return nil, err } logger := c.Logger().WithField("remotepeer", p.ID.String()+"("+p.Name+")") var conn *grpc.ClientConn remote, err := utils.FormRemotePeerAddress(p.Addresses[0]) if err != nil { return nil, err } conn, err = grpc.Dial(remote, grpc.WithInsecure()) if err == nil && conn != nil { logger.WithFields(log.Fields{ "remote": remote, }).Debug("connected to remote") } if conn == nil { logger.WithFields(log.Fields{ "error": err, "remote": p.Addresses, }).Error("failed to grpc.Dial remote") return nil, err } defer conn.Close() client := NewTxnSvcClient(conn) req := &TxnStepReq{ StepFunc: step, } data, err := json.Marshal(c) if err != nil { logger.WithError(err).Error("failed to JSON marshal transaction context") return nil, err } req.Context = data var rsp *TxnStepResp rsp, err = client.RunStep(netctx.TODO(), req) if err != nil { logger.WithFields(log.Fields{ "error": err, "rpc": "TxnSvc.RunStep", }).Error("failed RPC call") return nil, err } if rsp.Error != "" { logger.WithError(errors.New(rsp.Error)).Error("TxnSvc.Runstep failed on peer") return nil, errors.New(rsp.Error) } rspCtx := new(Tctx) err = json.Unmarshal(rsp.Resp, rspCtx) if err != nil { logger.WithError(err).Error("failed to JSON unmarhsal transaction context") } return rspCtx, err }