| | |
| | | package service |
| | | |
| | | import ( |
| | | "basic.com/valib/bhomeclient.git" |
| | | "basic.com/valib/bhomedbapi.git" |
| | | "basic.com/valib/serf.git/serf" |
| | | "encoding/json" |
| | | "errors" |
| | | "github.com/satori/go.uuid" |
| | | "time" |
| | | "vamicro/config" |
| | | "vamicro/system-service/models" |
| | | sc "vamicro/system-service/serf" |
| | | dvo "vamicro/devicemanage-service/vo" |
| | | "vamicro/system-service/sys" |
| | | "vamicro/system-service/vo" |
| | | ) |
| | | |
| | | func init() { |
| | | sc.RegisterRpcHandles( |
| | | DevAuthApply, |
| | | RemoteCreateCluster, |
| | | RemoteSearchCluster, |
| | | RemoteGetSearchNodes, |
| | | RemoteJoinCluster, |
| | | RemoteReboot, |
| | | RemoteUninstall, |
| | | RemoteUpgrade, |
| | | RemoteSysUpdate, |
| | | ) |
| | | } |
| | | |
| | | func DevAuthApply(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | type applyArg struct { |
| | | Key string `json:"key"` |
| | | FromDevId string `json:"fromDevId"` |
| | | FromIp string `json:"fromIp"` |
| | | } |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var reqBody applyArg |
| | | if err := json.Unmarshal(arg.Data, &reqBody); err == nil && reqBody.Key != "" && reqBody.FromIp != "" && reqBody.FromDevId != "" { |
| | | //1.验证请求的key是否匹配 |
| | | var config models.AuthConfig |
| | | ic, _ := config.Select() |
| | | if ic > 0 { |
| | | if config.AuthType == models.AuthType_Key && reqBody.Key != config.Password { |
| | | ret.Msg = "申请密钥不匹配" |
| | | } |
| | | } |
| | | |
| | | //2.写入authDevice |
| | | var da models.AuthDevice |
| | | i, _ := da.FindByDevId(reqBody.FromDevId) |
| | | if i == 0 { //未申请过 |
| | | tmp := models.AuthDevice{ |
| | | Id: uuid.NewV4().String(), |
| | | DevId: reqBody.FromDevId, |
| | | DevIp: reqBody.FromIp, |
| | | ApplyKey: reqBody.Key, |
| | | CreateTime: time.Now().Format("2006-01-02 15:04:05"), |
| | | } |
| | | if tmp.Insert() { |
| | | ret.Success = true |
| | | ret.Msg = "添加成功,待审核" |
| | | } else { |
| | | ret.Msg = "添加失败" |
| | | } |
| | | } else { //已申请过 |
| | | if da.Status == models.AuthStatus_Agreed { |
| | | ret.Success = true |
| | | ret.Msg = "已通过,无需重复申请" |
| | | } else if da.Status == models.AuthStatus_AuthCanceled { |
| | | ret.Msg = "已取消授权" |
| | | } else { |
| | | ret.Msg = "请等候审核" |
| | | } |
| | | } |
| | | } else { |
| | | ret.Msg = "参数有误" |
| | | } |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteCreateCluster(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var param dvo.CreateClusterArg |
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil { |
| | | retErr = err |
| | | } |
| | | if len(param.Password) != 6 || param.ClusterName == "" { |
| | | ret.Msg = "参数有误" |
| | | } else { |
| | | sv := NewClusterService(sc.GetBusHandle()) |
| | | b, newCluterId := sv.Create(param.ClusterName, param.Password, param.VirtualIp) |
| | | if b { |
| | | param.ClusterId = newCluterId |
| | | ret.Data = param |
| | | } else { |
| | | retErr = errors.New("创建集群失败") |
| | | } |
| | | } |
| | | |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteSearchCluster(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var param dvo.SearchClusterArg |
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil { |
| | | retErr = err |
| | | } |
| | | if len(param.Password) != 6 { |
| | | retErr = errors.New("密码错误") |
| | | } else { |
| | | searchNum := uuid.NewV4().String() |
| | | sv := NewClusterService(sc.GetBusHandle()) |
| | | retErr = sv.SearchByPwd(param.Password) |
| | | if retErr !=nil { |
| | | ret.Success = true |
| | | ret.Msg = "搜索中..." |
| | | } else { |
| | | ret.Success = true |
| | | ret.Data = searchNum |
| | | } |
| | | } |
| | | |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteGetSearchNodes(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | sv := NewClusterService(sc.GetBusHandle()) |
| | | nodes := sv.SearchNodes() |
| | | if nodes !=nil && len(nodes)>0 { |
| | | var nodeArr []interface{} |
| | | for _,n :=range nodes { |
| | | nodeArr = append(nodeArr, n) |
| | | } |
| | | |
| | | ret.Data = nodeArr |
| | | } else { |
| | | ret.Data = []interface{}{} |
| | | } |
| | | ret.Success = true |
| | | ret.Msg = "查询成功" |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteJoinCluster(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var param dvo.JoinClusterArg |
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil { |
| | | retErr = err |
| | | } else { |
| | | sv := NewClusterService(sc.GetBusHandle()) |
| | | cj := vo.ClusterJoinVo{ |
| | | ClusterId: param.ClusterId, |
| | | Password: param.Password, |
| | | NodeIps: param.NodeIps, |
| | | } |
| | | if b,err := sv.JoinCluster(&cj); b{ |
| | | ret.Success = true |
| | | ret.Msg = "加入成功" |
| | | } else { |
| | | ret.Success = false |
| | | retErr = err |
| | | } |
| | | } |
| | | |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteReboot(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var param dvo.RebootArg |
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil { |
| | | retErr = err |
| | | } else { |
| | | if isOk, msg := sys.Reboot(); !isOk { |
| | | ret.Msg = msg |
| | | } else { |
| | | ret.Success = true |
| | | ret.Msg = "正在重启..." |
| | | } |
| | | } |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteUninstall(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var param dvo.UninstallArg |
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil { |
| | | retErr = err |
| | | } else { |
| | | if param.Type ==1 { //卸载算法 |
| | | api := bhomedbapi.SdkApi{} |
| | | b, d := api.Delete(param.Id) |
| | | ret.Success = b |
| | | ret.Data = d |
| | | } else if param.Type == 2 { //卸载应用 |
| | | api := bhomedbapi.AppApi{} |
| | | b, d := api.Delete(param.Id) |
| | | ret.Success = b |
| | | ret.Data = d |
| | | } |
| | | } |
| | | |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteUpgrade(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var param dvo.UpgradeArg |
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil { |
| | | retErr = err |
| | | } else { |
| | | api := bhomedbapi.AppApi{} |
| | | b, d := api.Upgrade(param.Id) |
| | | ret.Success = b |
| | | ret.Data = d |
| | | } |
| | | |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | } |
| | | |
| | | func RemoteSysUpdate(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) { |
| | | var ret bhomeclient.Reply |
| | | var retErr error |
| | | var param dvo.SysUpdateArg |
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil { |
| | | retErr = err |
| | | } else { |
| | | //调用version-control的接口,执行升级操作 |
| | | ret.Msg = "build..." |
| | | } |
| | | |
| | | nr := serf.NodeResponse{ |
| | | From: config.Server.AnalyServerId, |
| | | } |
| | | if data, err := json.Marshal(ret); err != nil { |
| | | retErr = err |
| | | } else { |
| | | nr.Payload = data |
| | | } |
| | | |
| | | return append([]serf.NodeResponse{}, nr), retErr |
| | | package service
|
| | |
|
| | | import (
|
| | | "basic.com/valib/bhomeclient.git"
|
| | | "basic.com/valib/bhomedbapi.git"
|
| | | "basic.com/valib/serf.git/serf"
|
| | | "encoding/json"
|
| | | "errors"
|
| | | "github.com/satori/go.uuid"
|
| | | "time"
|
| | | "vamicro/config"
|
| | | "vamicro/system-service/models"
|
| | | sc "vamicro/system-service/serf"
|
| | | dvo "vamicro/devicemanage-service/vo"
|
| | | "vamicro/system-service/sys"
|
| | | "vamicro/system-service/vo"
|
| | | )
|
| | |
|
| | | func init() {
|
| | | sc.RegisterRpcHandles(
|
| | | DevAuthApply,
|
| | | RemoteCreateCluster,
|
| | | RemoteSearchCluster,
|
| | | RemoteGetSearchNodes,
|
| | | RemoteJoinCluster,
|
| | | RemoteReboot,
|
| | | RemoteUninstall,
|
| | | RemoteUpgrade,
|
| | | RemoteSysUpdate,
|
| | | )
|
| | | }
|
| | |
|
| | | func DevAuthApply(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | type applyArg struct {
|
| | | Key string `json:"key"`
|
| | | FromDevId string `json:"fromDevId"`
|
| | | FromIp string `json:"fromIp"`
|
| | | }
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var reqBody applyArg
|
| | | if err := json.Unmarshal(arg.Data, &reqBody); err == nil && reqBody.Key != "" && reqBody.FromIp != "" && reqBody.FromDevId != "" {
|
| | | //1.验证请求的key是否匹配
|
| | | var config models.AuthConfig
|
| | | ic, _ := config.Select()
|
| | | if ic > 0 {
|
| | | if config.AuthType == models.AuthType_Key && reqBody.Key != config.Password {
|
| | | ret.Msg = "申请密钥不匹配"
|
| | | }
|
| | | }
|
| | |
|
| | | //2.写入authDevice
|
| | | var da models.AuthDevice
|
| | | i, _ := da.FindByDevId(reqBody.FromDevId)
|
| | | if i == 0 { //未申请过
|
| | | tmp := models.AuthDevice{
|
| | | Id: uuid.NewV4().String(),
|
| | | DevId: reqBody.FromDevId,
|
| | | DevIp: reqBody.FromIp,
|
| | | ApplyKey: reqBody.Key,
|
| | | CreateTime: time.Now().Format("2006-01-02 15:04:05"),
|
| | | }
|
| | | if tmp.Insert() {
|
| | | ret.Success = true
|
| | | ret.Msg = "添加成功,待审核"
|
| | | } else {
|
| | | ret.Msg = "添加失败"
|
| | | }
|
| | | } else { //已申请过
|
| | | if da.Status == models.AuthStatus_Agreed {
|
| | | ret.Success = true
|
| | | ret.Msg = "已通过,无需重复申请"
|
| | | } else if da.Status == models.AuthStatus_AuthCanceled {
|
| | | ret.Msg = "已取消授权"
|
| | | } else {
|
| | | ret.Msg = "请等候审核"
|
| | | }
|
| | | }
|
| | | } else {
|
| | | ret.Msg = "参数有误"
|
| | | }
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteCreateCluster(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var param dvo.CreateClusterArg
|
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil {
|
| | | retErr = err
|
| | | }
|
| | | if len(param.Password) != 6 || param.ClusterName == "" {
|
| | | ret.Msg = "参数有误"
|
| | | } else {
|
| | | sv := NewClusterService(sc.GetBusHandle())
|
| | | b, newCluterId := sv.Create(param.ClusterName, param.Password, param.VirtualIp)
|
| | | if b {
|
| | | param.ClusterId = newCluterId
|
| | | ret.Data = param
|
| | | } else {
|
| | | retErr = errors.New("创建集群失败")
|
| | | }
|
| | | }
|
| | |
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteSearchCluster(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var param dvo.SearchClusterArg
|
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil {
|
| | | retErr = err
|
| | | }
|
| | | if len(param.Password) != 6 {
|
| | | retErr = errors.New("密码错误")
|
| | | } else {
|
| | | searchNum := uuid.NewV4().String()
|
| | | sv := NewClusterService(sc.GetBusHandle())
|
| | | retErr = sv.SearchByPwd(param.Password)
|
| | | if retErr !=nil {
|
| | | ret.Success = true
|
| | | ret.Msg = "搜索中..."
|
| | | } else {
|
| | | ret.Success = true
|
| | | ret.Data = searchNum
|
| | | }
|
| | | }
|
| | |
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteGetSearchNodes(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | sv := NewClusterService(sc.GetBusHandle())
|
| | | nodes := sv.SearchNodes()
|
| | | if nodes !=nil && len(nodes)>0 {
|
| | | var nodeArr []interface{}
|
| | | for _,n :=range nodes {
|
| | | nodeArr = append(nodeArr, n)
|
| | | }
|
| | |
|
| | | ret.Data = nodeArr
|
| | | } else {
|
| | | ret.Data = []interface{}{}
|
| | | }
|
| | | ret.Success = true
|
| | | ret.Msg = "查询成功"
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteJoinCluster(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var param dvo.JoinClusterArg
|
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | sv := NewClusterService(sc.GetBusHandle())
|
| | | cj := vo.ClusterJoinVo{
|
| | | ClusterId: param.ClusterId,
|
| | | Password: param.Password,
|
| | | NodeIps: param.NodeIps,
|
| | | }
|
| | | if b,err := sv.JoinCluster(&cj); b{
|
| | | ret.Success = true
|
| | | ret.Msg = "加入成功"
|
| | | } else {
|
| | | ret.Success = false
|
| | | retErr = err
|
| | | }
|
| | | }
|
| | |
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteReboot(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var param dvo.RebootArg
|
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | if isOk, msg := sys.Reboot(); !isOk {
|
| | | ret.Msg = msg
|
| | | } else {
|
| | | ret.Success = true
|
| | | ret.Msg = "正在重启..."
|
| | | }
|
| | | }
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteUninstall(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var param dvo.UninstallArg
|
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | if param.Type ==1 { //卸载算法
|
| | | api := bhomedbapi.SdkApi{}
|
| | | b, d := api.Delete(param.Id)
|
| | | ret.Success = b
|
| | | ret.Data = d
|
| | | } else if param.Type == 2 { //卸载应用
|
| | | api := bhomedbapi.AppApi{}
|
| | | b, d := api.Delete(param.Id)
|
| | | ret.Success = b
|
| | | ret.Data = d
|
| | | }
|
| | | }
|
| | |
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteUpgrade(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var param dvo.UpgradeArg
|
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | api := bhomedbapi.AppApi{}
|
| | | b, d := api.Upgrade(param.Id)
|
| | | ret.Success = b
|
| | | ret.Data = d
|
| | | }
|
| | |
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | }
|
| | |
|
| | | func RemoteSysUpdate(arg sc.RpcParamTopic) ([]serf.NodeResponse, error) {
|
| | | var ret bhomeclient.Reply
|
| | | var retErr error
|
| | | var param dvo.SysUpdateArg
|
| | | if err := json.Unmarshal(arg.Data, ¶m);err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | //调用version-control的接口,执行升级操作
|
| | | ret.Msg = "build..."
|
| | | }
|
| | |
|
| | | nr := serf.NodeResponse{
|
| | | From: config.Server.AnalyServerId,
|
| | | }
|
| | | if data, err := json.Marshal(ret); err != nil {
|
| | | retErr = err
|
| | | } else {
|
| | | nr.Payload = data
|
| | | }
|
| | |
|
| | | return append([]serf.NodeResponse{}, nr), retErr
|
| | | } |