forked from rancher/giddyup
/
leader.go
158 lines (135 loc) · 3.15 KB
/
leader.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
package app
import (
"fmt"
"os"
"github.com/Sirupsen/logrus"
"github.com/cloudnautique/giddyup/election"
"github.com/rancher/go-rancher-metadata/metadata"
"github.com/urfave/cli"
)
var (
port = "proxy-tcp-port"
dstPort = "dst-port"
srcPort = "src-port"
check = "check"
)
func LeaderCommand() cli.Command {
return cli.Command{
Name: "leader",
Usage: "Provides a deterministic way to elect, route traffic, and get a leader of a service",
Subcommands: []cli.Command{
{
Name: "check",
Usage: "Check if we are leader and exit.",
Action: appActionCheck,
Flags: []cli.Flag{
cli.StringFlag{
Name: "service",
Usage: "Get the leader of another service in the stack",
},
},
},
{
Name: "elect",
Usage: "Simple leader election with Rancher",
Action: appActionElect,
Flags: []cli.Flag{
cli.IntFlag{
Name: port,
Usage: "Port to proxy to the leader",
},
},
},
{
Name: "forward",
Usage: "Listen and forward all port traffic to leader.",
Action: appActionForward,
Flags: []cli.Flag{
cli.IntFlag{
Name: dstPort,
Usage: "Leader destination port",
},
cli.IntFlag{
Name: srcPort,
Usage: "Local source port",
},
},
},
{
Name: "get",
Usage: "Get Rancher IP the leader of service. If you want, you can get can get underlying hostname or agent_ip",
Action: appActionGet,
},
},
}
}
func appActionCheck(cli *cli.Context) error {
client, err := metadata.NewClientAndWait(metadataURL)
if err != nil {
logrus.Fatal(err)
}
w := election.New(client, cli.Int(port), cli.Args())
if w.IsLeader() {
os.Exit(0)
} else {
os.Exit(1)
}
return nil
}
func appActionGet(cli *cli.Context) error {
client, err := metadata.NewClientAndWait(metadataURL)
if err != nil {
logrus.Fatal(err)
}
w := election.New(client, cli.Int(port), cli.Args())
leader, _, err := w.GetSelfServiceLeader()
if err != nil {
logrus.Fatalf("Could not get leader. %s", err)
}
switch {
case len(cli.Args()) == 0:
fmt.Printf("%s", leader.PrimaryIp)
os.Exit(0)
case cli.Args()[0] == "host":
host, err := client.GetHost(leader.HostUUID)
if err != nil {
return err
}
fmt.Printf("%s", host.Hostname)
os.Exit(0)
case cli.Args()[0] == "agent_ip":
host, err := client.GetHost(leader.HostUUID)
if err != nil {
return err
}
fmt.Printf("%s", host.AgentIP)
os.Exit(0)
}
return fmt.Errorf("Unrecognized arg: (%s) nothing, host and agent_ip are only allowed args", cli.Args()[0])
}
func appActionForward(cli *cli.Context) error {
client, err := metadata.NewClientAndWait(metadataURL)
if err != nil {
logrus.Fatal(err)
}
dst := cli.Int(dstPort)
if dst == 0 {
dst = cli.Int(srcPort)
}
w := election.NewSrcDstWatcher(client, cli.Int(srcPort), dst)
if err := w.Forwarder(); err != nil {
logrus.Fatal(err)
}
return nil
}
func appActionElect(cli *cli.Context) error {
client, err := metadata.NewClientAndWait(metadataURL)
if err != nil {
logrus.Fatal(err)
}
w := election.New(client, cli.Int(port), cli.Args())
if err := w.Watch(); err != nil {
logrus.Fatal(err)
}
return nil
}