Commit 29483d06 authored by Brad Davidson's avatar Brad Davidson Committed by Brad Davidson

Initial update of netpol and utils from upstream

parent 740b654d
package netpol
import (
"reflect"
"github.com/golang/glog"
api "k8s.io/api/core/v1"
"k8s.io/client-go/tools/cache"
)
func (npc *NetworkPolicyController) newNamespaceEventHandler() cache.ResourceEventHandler {
return cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
npc.handleNamespaceAdd(obj.(*api.Namespace))
},
UpdateFunc: func(oldObj, newObj interface{}) {
npc.handleNamespaceUpdate(oldObj.(*api.Namespace), newObj.(*api.Namespace))
},
DeleteFunc: func(obj interface{}) {
switch obj := obj.(type) {
case *api.Namespace:
npc.handleNamespaceDelete(obj)
return
case cache.DeletedFinalStateUnknown:
if namespace, ok := obj.Obj.(*api.Namespace); ok {
npc.handleNamespaceDelete(namespace)
return
}
default:
glog.Errorf("unexpected object type: %v", obj)
}
},
}
}
func (npc *NetworkPolicyController) handleNamespaceAdd(obj *api.Namespace) {
if obj.Labels == nil {
return
}
glog.V(2).Infof("Received update for namespace: %s", obj.Name)
npc.RequestFullSync()
}
func (npc *NetworkPolicyController) handleNamespaceUpdate(oldObj, newObj *api.Namespace) {
if reflect.DeepEqual(oldObj.Labels, newObj.Labels) {
return
}
glog.V(2).Infof("Received update for namespace: %s", newObj.Name)
npc.RequestFullSync()
}
func (npc *NetworkPolicyController) handleNamespaceDelete(obj *api.Namespace) {
if obj.Labels == nil {
return
}
glog.V(2).Infof("Received namespace: %s delete event", obj.Name)
npc.RequestFullSync()
}
// Apache License v2.0 (copyright Cloud Native Labs & Rancher Labs) package utils
// - modified from https://github.com/cloudnativelabs/kube-router/tree/d6f9f31a7b/pkg/utils
// +build !windows
package netpol
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"net"
"os/exec" "os/exec"
"strings" "strings"
"time"
apiv1 "k8s.io/api/core/v1"
"k8s.io/client-go/informers"
) )
var ( var (
...@@ -31,7 +21,7 @@ const ( ...@@ -31,7 +21,7 @@ const (
// DefaultMaxElem Default OptionMaxElem value. // DefaultMaxElem Default OptionMaxElem value.
DefaultMaxElem = "65536" DefaultMaxElem = "65536"
// DefaultHasSize Default OptionHashSize value. // DefaultHasSize Defaul OptionHashSize value.
DefaultHasSize = "1024" DefaultHasSize = "1024"
// TypeHashIP The hash:ip set type uses a hash to store IP host addresses (default) or network addresses. Zero valued IP address cannot be stored in a hash:ip type of set. // TypeHashIP The hash:ip set type uses a hash to store IP host addresses (default) or network addresses. Zero valued IP address cannot be stored in a hash:ip type of set.
...@@ -96,7 +86,7 @@ type IPSet struct { ...@@ -96,7 +86,7 @@ type IPSet struct {
isIpv6 bool isIpv6 bool
} }
// Set represent a ipset set entry. // Set reprensent a ipset set entry.
type Set struct { type Set struct {
Parent *IPSet Parent *IPSet
Name string Name string
...@@ -156,8 +146,8 @@ func (ipset *IPSet) runWithStdin(stdin *bytes.Buffer, args ...string) (string, e ...@@ -156,8 +146,8 @@ func (ipset *IPSet) runWithStdin(stdin *bytes.Buffer, args ...string) (string, e
return stdout.String(), nil return stdout.String(), nil
} }
// NewSavedIPSet create a new IPSet with ipSetPath initialized. // NewIPSet create a new IPSet with ipSetPath initialized.
func NewSavedIPSet(isIpv6 bool) (*IPSet, error) { func NewIPSet(isIpv6 bool) (*IPSet, error) {
ipSetPath, err := getIPSetPath() ipSetPath, err := getIPSetPath()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -167,9 +157,6 @@ func NewSavedIPSet(isIpv6 bool) (*IPSet, error) { ...@@ -167,9 +157,6 @@ func NewSavedIPSet(isIpv6 bool) (*IPSet, error) {
Sets: make(map[string]*Set), Sets: make(map[string]*Set),
isIpv6: isIpv6, isIpv6: isIpv6,
} }
if err := ipSet.Save(); err != nil {
return nil, err
}
return ipSet, nil return ipSet, nil
} }
...@@ -221,11 +208,14 @@ func (ipset *IPSet) Add(set *Set) error { ...@@ -221,11 +208,14 @@ func (ipset *IPSet) Add(set *Set) error {
return err return err
} }
for _, entry := range set.Entries { options := make([][]string, len(set.Entries))
_, err := ipset.Get(set.Name).Add(entry.Options...) for index, entry := range set.Entries {
if err != nil { options[index] = entry.Options
return err }
}
err = ipset.Get(set.Name).BatchAdd(options)
if err != nil {
return err
} }
return nil return nil
...@@ -233,6 +223,8 @@ func (ipset *IPSet) Add(set *Set) error { ...@@ -233,6 +223,8 @@ func (ipset *IPSet) Add(set *Set) error {
// Add a given entry to the set. If the -exist option is specified, ipset // Add a given entry to the set. If the -exist option is specified, ipset
// ignores if the entry already added to the set. // ignores if the entry already added to the set.
// Note: if you need to add multiple entries (e.g., in a loop), use BatchAdd instead,
// as it’s much more performant.
func (set *Set) Add(addOptions ...string) (*Entry, error) { func (set *Set) Add(addOptions ...string) (*Entry, error) {
entry := &Entry{ entry := &Entry{
Set: set, Set: set,
...@@ -246,6 +238,35 @@ func (set *Set) Add(addOptions ...string) (*Entry, error) { ...@@ -246,6 +238,35 @@ func (set *Set) Add(addOptions ...string) (*Entry, error) {
return entry, nil return entry, nil
} }
// Adds given entries (with their options) to the set.
// For multiple items, this is much faster than Add().
func (set *Set) BatchAdd(addOptions [][]string) error {
newEntries := make([]*Entry, len(addOptions))
for index, options := range addOptions {
entry := &Entry{
Set: set,
Options: options,
}
newEntries[index] = entry
}
set.Entries = append(set.Entries, newEntries...)
// Build the `restore` command contents
var builder strings.Builder
for _, options := range addOptions {
line := strings.Join(append([]string{"add", "-exist", set.name()}, options...), " ")
builder.WriteString(line + "\n")
}
restoreContents := builder.String()
// Invoke the command
_, err := set.Parent.runWithStdin(bytes.NewBufferString(restoreContents), "restore")
if err != nil {
return err
}
return nil
}
// Del an entry from a set. If the -exist option is specified and the entry is // Del an entry from a set. If the -exist option is specified and the entry is
// not in the set (maybe already expired), then the command is ignored. // not in the set (maybe already expired), then the command is ignored.
func (entry *Entry) Del() error { func (entry *Entry) Del() error {
...@@ -253,11 +274,14 @@ func (entry *Entry) Del() error { ...@@ -253,11 +274,14 @@ func (entry *Entry) Del() error {
if err != nil { if err != nil {
return err return err
} }
err = entry.Set.Parent.Save()
return entry.Set.Parent.Save() if err != nil {
return err
}
return nil
} }
// Test whether an entry is in a set or not. Exit status number is zero if the // Test wether an entry is in a set or not. Exit status number is zero if the
// tested entry is in the set and nonzero if it is missing from the set. // tested entry is in the set and nonzero if it is missing from the set.
func (set *Set) Test(testOptions ...string) (bool, error) { func (set *Set) Test(testOptions ...string) (bool, error) {
_, err := set.Parent.run(append([]string{"test", set.name()}, testOptions...)...) _, err := set.Parent.run(append([]string{"test", set.name()}, testOptions...)...)
...@@ -388,7 +412,7 @@ func (ipset *IPSet) Save() error { ...@@ -388,7 +412,7 @@ func (ipset *IPSet) Save() error {
// stdin. Please note, existing sets and elements are not erased by restore // stdin. Please note, existing sets and elements are not erased by restore
// unless specified so in the restore file. All commands are allowed in restore // unless specified so in the restore file. All commands are allowed in restore
// mode except list, help, version, interactive mode and restore itself. // mode except list, help, version, interactive mode and restore itself.
// Send formatted ipset.sets into stdin of "ipset restore" command. // Send formated ipset.sets into stdin of "ipset restore" command.
func (ipset *IPSet) Restore() error { func (ipset *IPSet) Restore() error {
stdin := bytes.NewBufferString(buildIPSetRestore(ipset)) stdin := bytes.NewBufferString(buildIPSetRestore(ipset))
_, err := ipset.runWithStdin(stdin, "restore", "-exist") _, err := ipset.runWithStdin(stdin, "restore", "-exist")
...@@ -451,45 +475,22 @@ func (set *Set) Swap(setTo *Set) error { ...@@ -451,45 +475,22 @@ func (set *Set) Swap(setTo *Set) error {
// Refresh a Set with new entries. // Refresh a Set with new entries.
func (set *Set) Refresh(entries []string, extraOptions ...string) error { func (set *Set) Refresh(entries []string, extraOptions ...string) error {
var err error entriesWithOptions := make([][]string, len(entries))
// The set-name must be < 32 characters!
tempName := set.Name + "-"
newSet := &Set{
Parent: set.Parent,
Name: tempName,
Options: set.Options,
}
err = set.Parent.Add(newSet) for index, entry := range entries {
if err != nil { entriesWithOptions[index] = append([]string{entry}, extraOptions...)
return err
}
for _, entry := range entries {
_, err = newSet.Add(entry)
if err != nil {
return err
}
} }
err = set.Swap(newSet) return set.RefreshWithBuiltinOptions(entriesWithOptions)
if err != nil {
return err
}
err = set.Parent.Destroy(tempName)
if err != nil {
return err
}
return nil
} }
// Refresh a Set with new entries with built-in options. // Refresh a Set with new entries with built-in options.
func (set *Set) RefreshWithBuiltinOptions(entries [][]string) error { func (set *Set) RefreshWithBuiltinOptions(entries [][]string) error {
var err error var err error
tempName := set.Name + "-temp"
// The set-name must be < 32 characters!
tempName := set.Name + "-"
newSet := &Set{ newSet := &Set{
Parent: set.Parent, Parent: set.Parent,
Name: tempName, Name: tempName,
...@@ -501,11 +502,9 @@ func (set *Set) RefreshWithBuiltinOptions(entries [][]string) error { ...@@ -501,11 +502,9 @@ func (set *Set) RefreshWithBuiltinOptions(entries [][]string) error {
return err return err
} }
for _, entry := range entries { err = newSet.BatchAdd(entries)
_, err = newSet.Add(entry...) if err != nil {
if err != nil { return err
return err
}
} }
err = set.Swap(newSet) err = set.Swap(newSet)
...@@ -520,38 +519,3 @@ func (set *Set) RefreshWithBuiltinOptions(entries [][]string) error { ...@@ -520,38 +519,3 @@ func (set *Set) RefreshWithBuiltinOptions(entries [][]string) error {
return nil return nil
} }
// GetNodeIP returns the most valid external facing IP address for a node.
// Order of preference:
// 1. NodeInternalIP
// 2. NodeExternalIP (Only set on cloud providers usually)
func GetNodeIP(node *apiv1.Node) (net.IP, error) {
addresses := node.Status.Addresses
addressMap := make(map[apiv1.NodeAddressType][]apiv1.NodeAddress)
for i := range addresses {
addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i])
}
if addresses, ok := addressMap[apiv1.NodeInternalIP]; ok {
return net.ParseIP(addresses[0].Address), nil
}
if addresses, ok := addressMap[apiv1.NodeExternalIP]; ok {
return net.ParseIP(addresses[0].Address), nil
}
return nil, errors.New("host IP unknown")
}
// CacheSync performs cache synchronization under timeout limit
func CacheSyncOrTimeout(informerFactory informers.SharedInformerFactory, stopCh <-chan struct{}, cacheSyncTimeout time.Duration) error {
syncOverCh := make(chan struct{})
go func() {
informerFactory.WaitForCacheSync(stopCh)
close(syncOverCh)
}()
select {
case <-time.After(cacheSyncTimeout):
return errors.New(cacheSyncTimeout.String() + " timeout")
case <-syncOverCh:
return nil
}
}
package utils
import (
"context"
"errors"
"fmt"
"net"
"os"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
// GetNodeObject returns the node API object for the node
func GetNodeObject(clientset kubernetes.Interface, hostnameOverride string) (*apiv1.Node, error) {
// assuming kube-router is running as pod, first check env NODE_NAME
nodeName := os.Getenv("NODE_NAME")
if nodeName != "" {
node, err := clientset.CoreV1().Nodes().Get(context.Background(), nodeName, metav1.GetOptions{})
if err == nil {
return node, nil
}
}
// if env NODE_NAME is not set then check if node is register with hostname
hostName, _ := os.Hostname()
node, err := clientset.CoreV1().Nodes().Get(context.Background(), hostName, metav1.GetOptions{})
if err == nil {
return node, nil
}
// if env NODE_NAME is not set and node is not registered with hostname, then use host name override
if hostnameOverride != "" {
node, err = clientset.CoreV1().Nodes().Get(context.Background(), hostnameOverride, metav1.GetOptions{})
if err == nil {
return node, nil
}
}
return nil, fmt.Errorf("Failed to identify the node by NODE_NAME, hostname or --hostname-override")
}
// GetNodeIP returns the most valid external facing IP address for a node.
// Order of preference:
// 1. NodeInternalIP
// 2. NodeExternalIP (Only set on cloud providers usually)
func GetNodeIP(node *apiv1.Node) (net.IP, error) {
addresses := node.Status.Addresses
addressMap := make(map[apiv1.NodeAddressType][]apiv1.NodeAddress)
for i := range addresses {
addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i])
}
if addresses, ok := addressMap[apiv1.NodeInternalIP]; ok {
return net.ParseIP(addresses[0].Address), nil
}
if addresses, ok := addressMap[apiv1.NodeExternalIP]; ok {
return net.ParseIP(addresses[0].Address), nil
}
return nil, errors.New("host IP unknown")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment