Skip to content

Commit

Permalink
Switched from shell commands to netlink commands
Browse files Browse the repository at this point in the history
  • Loading branch information
darxkies committed Dec 16, 2018
1 parent 57282d9 commit fd49b16
Show file tree
Hide file tree
Showing 469 changed files with 232,609 additions and 90 deletions.
13 changes: 8 additions & 5 deletions cmd/virtual-ip/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"os"
"os/signal"
"strings"
"time"

"github.com/darxkies/virtual-ip/pkg"
"github.com/darxkies/virtual-ip/version"
Expand All @@ -19,12 +18,16 @@ func main() {
id := flag.String("id", "vip", "ID of this node")
bind := flag.String("bind", "0.0.0.0", "RAFT bind addreess")
virtualIP := flag.String("virtual-ip", "192.168.0.25", "Virtual/Floating IP")
timeout := flag.Int("timeout", 10, "Shell command timeout")
peersList := flag.String("peers", "", "Peers as a comma separated list of peer-id=peer-address:peer-port including the id and the bind of this instance")
_interface := flag.String("interface", "enp3s0:1", "Network interface")
_interface := flag.String("interface", "lo", "Network interface")
flag.Parse()

commandRunner := pkg.NewShellCommandRunner(time.Duration(*timeout))
netlinkNetworkConfigurator, error := pkg.NewNetlinkNetworkConfigurator(*virtualIP, *_interface)
if error != nil {
log.WithFields(log.Fields{"error": error}).Error("Network failure")

os.Exit(-1)
}

peers := pkg.Peers{}

Expand All @@ -44,7 +47,7 @@ func main() {

logger := pkg.Logger{}

vipManager := pkg.NewVIPManager(*id, *bind, *virtualIP, peers, logger, *_interface, commandRunner)
vipManager := pkg.NewVIPManager(*id, *bind, peers, logger, netlinkNetworkConfigurator)
if error := vipManager.Start(); error != nil {
log.WithFields(log.Fields{"error": error}).Error("Start failed")

Expand Down
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
module github.com/darxkies/virtual-ip

require (
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da
github.com/cespare/reflex v0.2.0 // indirect
github.com/fsnotify/fsnotify v1.4.7 // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c // indirect
github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c
github.com/hashicorp/raft v1.0.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kr/pty v1.1.3 // indirect
github.com/ogier/pflag v0.0.1 // indirect
github.com/pkg/errors v0.8.0
github.com/sirupsen/logrus v1.2.0
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06 // indirect
github.com/vishvananda/netlink v1.0.0
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc
golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@ github.com/hashicorp/raft v1.0.0 h1:htBVktAOtGs4Le5Z7K8SF5H2+oWsQFYVmOgH5loro7Y=
github.com/hashicorp/raft v1.0.0/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pty v1.1.3 h1:/Um6a/ZmD5tF7peoOJ5oN5KMQ0DrGVQSXLNwyckutPk=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/ogier/pflag v0.0.1 h1:RW6JSWSu/RkSatfcLtogGfFgpim5p7ARQ10ECk5O750=
github.com/ogier/pflag v0.0.1/go.mod h1:zkFki7tvTa0tafRvTBIZTvzYyAu6kQhPZFnshFFPE+g=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
42 changes: 0 additions & 42 deletions pkg/command.go

This file was deleted.

103 changes: 63 additions & 40 deletions pkg/manager.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package pkg

import (
"fmt"
"net"
"time"

Expand All @@ -10,43 +9,18 @@ import (
)

type VIPManager struct {
id string
bind string
virtualIP string
fsm FSM
peers Peers
logger Logger
_interface string
stop chan bool
commandRunner CommandRunner
id string
bind string
fsm FSM
peers Peers
logger Logger
stop chan bool
finished chan bool
networkConfigurator NetworkConfigurator
}

func NewVIPManager(id, bind string, virtualIP string, peers Peers, logger Logger, _interface string, commandRunner CommandRunner) *VIPManager {
return &VIPManager{id: id, peers: peers, bind: bind, virtualIP: virtualIP, fsm: FSM{}, logger: logger, _interface: _interface, commandRunner: commandRunner}
}

func (manager *VIPManager) updateNetworkConfiguration(action string) error {
command := fmt.Sprintf("ip addr %s %s/32 dev %s", action, manager.virtualIP, manager._interface)

if error := manager.commandRunner.Run(command); error != nil {
log.WithFields(log.Fields{"action": action, "error": error}).Error("Network update failed")

return error
}

return nil
}

func (manager *VIPManager) addIP() error {
log.Info("Add virtual ip")

return manager.updateNetworkConfiguration("add")
}

func (manager *VIPManager) deleteIP() error {
log.Info("Delete virtual ip")

return manager.updateNetworkConfiguration("delete")
func NewVIPManager(id, bind string, peers Peers, logger Logger, networkConfigurator NetworkConfigurator) *VIPManager {
return &VIPManager{id: id, peers: peers, bind: bind, fsm: FSM{}, logger: logger, networkConfigurator: networkConfigurator}
}

func (manager *VIPManager) Start() error {
Expand Down Expand Up @@ -91,21 +65,68 @@ func (manager *VIPManager) Start() error {
}

manager.stop = make(chan bool, 1)
manager.finished = make(chan bool, 1)
ticker := time.NewTicker(time.Second)
isLeader := false

_ = manager.deleteIP()
if error = manager.networkConfigurator.DeleteIP(); error != nil {
log.WithFields(log.Fields{"error": error}).Error("Could not delete ip")
}

go func() {
for {
select {
case leader := <-raftServer.LeaderCh():
if leader {
_ = manager.addIP()
isLeader = true

log.Info("Leading")

if error = manager.networkConfigurator.AddIP(); error != nil {
log.WithFields(log.Fields{"error": error}).Error("Could not set ip")
} else {
log.Info("Added IP")
}
} else {
_ = manager.deleteIP()
isLeader = false

log.Info("Following")

if error = manager.networkConfigurator.DeleteIP(); error != nil {
log.WithFields(log.Fields{"error": error}).Error("Could not delete ip")
} else {
log.Info("Deleted IP")
}
}

case <-ticker.C:
if isLeader {
result, error := manager.networkConfigurator.IsSet()
if error != nil {
log.WithFields(log.Fields{"error": error}).Error("Could not check ip")
}

if result == false {
log.Error("Lost IP")

if error = manager.networkConfigurator.AddIP(); error != nil {
log.WithFields(log.Fields{"error": error}).Error("Could not set ip")
} else {
log.Info("Added IP again")
}
}
}

case <-manager.stop:
_ = manager.deleteIP()
log.Info("Stopping")

if error = manager.networkConfigurator.DeleteIP(); error != nil {
log.WithFields(log.Fields{"error": error}).Error("Could not delete ip")
}

close(manager.finished)

return
}
}
}()
Expand All @@ -118,5 +139,7 @@ func (manager *VIPManager) Start() error {
func (manager *VIPManager) Stop() {
close(manager.stop)

<-manager.finished

log.Info("Stopped")
}
92 changes: 92 additions & 0 deletions pkg/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package pkg

import (
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
)

type NetworkConfigurator interface {
AddIP() error
DeleteIP() error
IsSet() (bool, error)
}

type NetlinkNetworkConfigurator struct {
address *netlink.Addr
link netlink.Link
}

func NewNetlinkNetworkConfigurator(_address, _interface string) (result NetlinkNetworkConfigurator, error error) {
result = NetlinkNetworkConfigurator{}

result.address, error = netlink.ParseAddr(_address + "/32")
if error != nil {
error = errors.Wrapf(error, "could not parse address '%s'", _address)

return
}

result.link, error = netlink.LinkByName(_interface)
if error != nil {
error = errors.Wrapf(error, "could not get link for interface '%s'", _interface)

return
}

return
}

func (configurator NetlinkNetworkConfigurator) AddIP() error {
result, error := configurator.IsSet()
if error != nil {
return errors.Wrap(error, "ip check in AddIP failed")
}

// Already set
if result {
return nil
}

if error = netlink.AddrAdd(configurator.link, configurator.address); error != nil {
return errors.Wrap(error, "could not add ip")
}

return nil
}

func (configurator NetlinkNetworkConfigurator) DeleteIP() error {
result, error := configurator.IsSet()
if error != nil {
return errors.Wrap(error, "ip check in DeleteIP failed")
}

// Nothing to delete
if !result {
return nil
}

if error = netlink.AddrDel(configurator.link, configurator.address); error != nil {
return errors.Wrap(error, "could not delete ip")
}

return nil
}

func (configurator NetlinkNetworkConfigurator) IsSet() (result bool, error error) {
var addresses []netlink.Addr

addresses, error = netlink.AddrList(configurator.link, 0)
if error != nil {
error = errors.Wrap(error, "could not list addresses")

return
}

for _, address := range addresses {
if address.Equal(*configurator.address) {
return true, nil
}
}

return false, nil
}
24 changes: 24 additions & 0 deletions vendor/github.com/armon/go-metrics/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit fd49b16

Please sign in to comment.