
- Adds stackube proxy which listens on endpoints, services and namespaces, creates load balancer rules for clusterIP service - Switch to govendor for managing vendors - Add hack scripts for verifying govet and gofmt Change-Id: I8594c16d294f46ae0d3dec6dae6fa491e7891b8b Implements: blueprint stackube-proxy
132 lines
2.9 KiB
Go
132 lines
2.9 KiB
Go
package proxy
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os/exec"
|
|
"syscall"
|
|
|
|
"github.com/golang/glog"
|
|
)
|
|
|
|
const (
|
|
TableNAT = "nat"
|
|
|
|
ChainPrerouting = "PREROUTING"
|
|
ChainSKPrerouting = "STACKUBE-PREROUTING"
|
|
|
|
opCreateChain = "-N"
|
|
opFlushChain = "-F"
|
|
opAddpendRule = "-A"
|
|
opCheckRule = "-C"
|
|
opDeleteRule = "-D"
|
|
)
|
|
|
|
type Iptables struct {
|
|
namespace string
|
|
}
|
|
|
|
func NewIptables(namespace string) *Iptables {
|
|
return &Iptables{
|
|
namespace: namespace,
|
|
}
|
|
}
|
|
|
|
// runInNat executes iptables command in nat table.
|
|
func (r *Iptables) runInNat(op, chain string, args []string) ([]byte, error) {
|
|
fullArgs := []string{"netns", "exec", r.namespace, "iptables", "-t", TableNAT, op, chain}
|
|
fullArgs = append(fullArgs, args...)
|
|
return exec.Command("ip", fullArgs...).CombinedOutput()
|
|
}
|
|
|
|
func (r *Iptables) restoreAll(data []byte) error {
|
|
glog.V(3).Infof("running iptables-restore with data %s", data)
|
|
|
|
fullArgs := []string{"netns", "exec", r.namespace, "iptables-restore", "--noflush", "--counters"}
|
|
cmd := exec.Command("ip", fullArgs...)
|
|
cmd.Stdin = bytes.NewBuffer(data)
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("iptables-restore failed: %s: %v", output, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ensureChain ensures chain STACKUBE-PREROUTING is created.
|
|
func (r *Iptables) ensureChain() error {
|
|
output, err := r.runInNat(opCreateChain, ChainSKPrerouting, nil)
|
|
if err != nil {
|
|
if ee, ok := err.(*exec.ExitError); ok {
|
|
if status, ok := ee.Sys().(syscall.WaitStatus); ok {
|
|
if status.ExitStatus() == 1 {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("ensure rule failed: %v: %s", err, output)
|
|
}
|
|
|
|
func (r *Iptables) checkRule(chain string, args []string) (bool, error) {
|
|
out, err := r.runInNat(opCheckRule, chain, args)
|
|
if err == nil {
|
|
return true, nil
|
|
}
|
|
|
|
if err != nil {
|
|
if ee, ok := err.(*exec.ExitError); ok {
|
|
if status, ok := ee.Sys().(syscall.WaitStatus); ok {
|
|
if status.ExitStatus() == 1 {
|
|
return false, nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false, fmt.Errorf("error checking rule: %v: %s", err, out)
|
|
}
|
|
|
|
func (r *Iptables) ensureRule(op, chain string, args []string) error {
|
|
exists, err := r.checkRule(chain, args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if exists {
|
|
return nil
|
|
}
|
|
|
|
out, err := r.runInNat(op, chain, args)
|
|
if err != nil {
|
|
return fmt.Errorf("error ensuring rule: %v: %s", err, out)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Join all words with spaces, terminate with newline and write to buf.
|
|
func writeLine(buf *bytes.Buffer, words ...string) {
|
|
// We avoid strings.Join for performance reasons.
|
|
for i := range words {
|
|
buf.WriteString(words[i])
|
|
if i < len(words)-1 {
|
|
buf.WriteByte(' ')
|
|
} else {
|
|
buf.WriteByte('\n')
|
|
}
|
|
}
|
|
}
|
|
|
|
func netnsExist(netns string) bool {
|
|
args := []string{"netns", "pids", netns}
|
|
out, err := exec.Command("ip", args...).CombinedOutput()
|
|
if err != nil {
|
|
glog.V(5).Infof("Checking netns %q failed: %s: %v", netns, out, err)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|