forked from therealbill/redskull
/
rpcserver.go
203 lines (184 loc) · 5.12 KB
/
rpcserver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package main
import (
"encoding/gob"
"errors"
"fmt"
"log"
"net"
"net/rpc"
"strings"
"sync"
"time"
"github.com/therealbill/libredis/client"
"github.com/therealbill/redskull/actions"
"github.com/therealbill/redskull/handlers"
"github.com/therealbill/redskull/rpcclient"
)
type Item struct {
key string
Item interface{}
}
type RPC struct {
constellation *actions.Constellation
mu *sync.RWMutex
}
func badContextError(err error) {
if err != nil {
panic("Constellation is not initialized")
}
}
// AddSlaveToPod is used for adding a new slave to an existing pod.
// TODO: technically the actual implementation should be moved into the actions
// package and the UI's handlers package can then also call it. As it is, it is
// also implemented there.
func (r *RPC) AddSlaveToPod(nsr rsclient.AddSlaveToPodRequest, resp *bool) error {
pod, err := r.constellation.GetPod(nsr.Pod)
if err != nil {
return errors.New("Pod not found")
}
name := fmt.Sprintf("%s:%d", nsr.SlaveIP, nsr.SlavePort)
new_slave, err := client.DialWithConfig(&client.DialConfig{Address: name, Password: nsr.SlaveAuth})
defer new_slave.ClosePool()
if err != nil {
log.Print("ERR: Dialing slave -", err)
return errors.New("Server was unable to connect to slave")
}
err = new_slave.SlaveOf(pod.Info.IP, fmt.Sprintf("%d", pod.Info.Port))
if err != nil {
log.Printf("Err: %v", err)
if strings.Contains(err.Error(), "Already connected to specified master") {
return errors.New("Already connected to specified master")
}
}
new_slave.ConfigSet("masterauth", pod.AuthToken)
new_slave.ConfigSet("requirepass", pod.AuthToken)
pod.Master.LastUpdateValid = false
r.constellation.PodMap[pod.Name] = pod
*resp = true
return err
}
func (r *RPC) CheckPodAuth(podname string, resp *map[string]bool) error {
pod, err := r.constellation.GetPod(podname)
if err != nil || pod == nil {
log.Print("No pod. Error: ", err)
return err
}
psresults := make(map[string]bool)
if pod.Master == nil {
mnode, err := actions.LoadNodeFromHostPort(pod.Master.Address, pod.Master.Port, pod.AuthToken)
if err != nil {
log.Print("Connection error: ", err)
return errors.New("Unable to connect to master nod at all. Check server logs for why")
}
pod.Master = mnode
}
mres := pod.Master.Ping()
psresults[pod.Master.Name] = mres
for _, slave := range pod.Master.Slaves {
log.Printf("Checking ping/auth for slave %s", slave.Name)
sres := slave.Ping()
psresults[slave.Name] = sres
}
*resp = psresults
return nil
}
func (r *RPC) GetSentinelsForPod(podname string, resp *[]string) error {
sentinels := r.constellation.GetSentinelsForPod(podname)
var snames []string
for _, s := range sentinels {
snames = append(snames, s.Name)
}
*resp = snames
return nil
}
func (r *RPC) AddPod(pr rsclient.NewPodRequest, resp *actions.RedisPod) (err error) {
gob.Register(actions.RedisPod{})
ok, err := r.constellation.MonitorPod(pr.Name, pr.IP, pr.Port, pr.Quorum, pr.Auth)
if err != nil {
log.Printf("MonitorPod call ('%+v') Failed. Error: %s", pr, err.Error())
return err
}
if !ok {
log.Printf("MonitorPod call ('%+v') Failed. No Error", pr)
err = errors.New("MonitorPod call returned false, no error")
}
time.Sleep(time.Second * 2)
pod, err := r.constellation.GetPod(pr.Name)
if pod == nil || pod.Name == "" {
err = errors.New("New Pod Not found")
return err
}
*resp = *pod
return err
}
func (r *RPC) GetPod(podname string, resp *actions.RedisPod) (err error) {
gob.Register(actions.RedisPod{})
pod, err := r.constellation.GetPod(podname)
if pod == nil || pod.Name == "" {
err = errors.New("Pod Not found")
return err
}
*resp = *pod
return err
}
func (r *RPC) RemovePod(podname string, resp *bool) (err error) {
ok, err := r.constellation.RemovePod(podname)
*resp = ok
return err
}
func (r *RPC) AddSentinel(address string, resp *bool) (err error) {
err = r.constellation.AddSentinelByAddress(address)
if err == nil {
*resp = true
}
return err
}
func (r *RPC) BalancePod(podname string, resp *bool) (err error) {
pod, err := r.constellation.GetPod(podname)
if pod == nil || pod.Name == "" {
err = errors.New("Pod Not found")
*resp = false
}
r.constellation.BalancePod(pod)
*resp = true
return err
}
func (r *RPC) ValidatePodSentinels(podname string, resp *map[string]bool) error {
pod, err := r.constellation.GetPod(podname)
res := make(map[string]bool)
if pod == nil || pod.Name == "" {
err = errors.New("Pod Not found")
*resp = res
return err
}
results, err := r.constellation.ValidatePodSentinels(podname)
*resp = results
return err
}
func NewRPC() *RPC {
context, err := handlers.NewPageContext()
badContextError(err)
return &RPC{
constellation: context.Constellation,
}
}
func (r *RPC) GetPodList(verbose bool, resp *[]string) (err error) {
var podlist []string
for k, _ := range r.constellation.PodMap {
if verbose {
log.Printf("found pod %s", k)
}
podlist = append(podlist, k)
}
*resp = podlist
return nil
}
func ServeRPC() {
rpc.Register(NewRPC())
rpc_on := fmt.Sprintf("%s:%d", config.BindAddress, config.RPCPort)
l, e := net.Listen("tcp", rpc_on)
if e != nil {
log.Fatal("listen error:", e)
}
rpc.Accept(l)
}