First stab at extending the "uid" configmap to store firewall
rule information.
This commit is contained in:
parent
fb8e2d7373
commit
b259c9b349
8 changed files with 217 additions and 91 deletions
|
|
@ -19,6 +19,7 @@ package storage
|
|||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
|
@ -27,73 +28,86 @@ import (
|
|||
client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
)
|
||||
|
||||
// UIDVault stores UIDs.
|
||||
type UIDVault interface {
|
||||
Get() (string, bool, error)
|
||||
Put(string) error
|
||||
Delete() error
|
||||
}
|
||||
|
||||
// uidDataKey is the key used in config maps to store the UID.
|
||||
const uidDataKey = "uid"
|
||||
const (
|
||||
// UidDataKey is the key used in config maps to store the UID.
|
||||
UidDataKey = "uid"
|
||||
// ProviderDataKey is the key used in config maps to store the Provider
|
||||
// UID which we use to ensure unique firewalls.
|
||||
ProviderDataKey = "providerUid"
|
||||
)
|
||||
|
||||
// ConfigMapVault stores cluster UIDs in config maps.
|
||||
// It's a layer on top of ConfigMapStore that just implements the utils.uidVault
|
||||
// interface.
|
||||
type ConfigMapVault struct {
|
||||
storeLock sync.Mutex
|
||||
ConfigMapStore cache.Store
|
||||
namespace string
|
||||
name string
|
||||
}
|
||||
|
||||
// Get retrieves the cluster UID from the cluster config map.
|
||||
// Get retrieves the value associated to the provided 'key' from the cluster config map.
|
||||
// If this method returns an error, it's guaranteed to be apiserver flake.
|
||||
// If the error is a not found error it sets the boolean to false and
|
||||
// returns and error of nil instead.
|
||||
func (c *ConfigMapVault) Get() (string, bool, error) {
|
||||
key := fmt.Sprintf("%v/%v", c.namespace, c.name)
|
||||
item, found, err := c.ConfigMapStore.GetByKey(key)
|
||||
func (c *ConfigMapVault) Get(key string) (string, bool, error) {
|
||||
keyStore := fmt.Sprintf("%v/%v", c.namespace, c.name)
|
||||
item, found, err := c.ConfigMapStore.GetByKey(keyStore)
|
||||
if err != nil || !found {
|
||||
return "", false, err
|
||||
}
|
||||
cfg := item.(*api.ConfigMap)
|
||||
if k, ok := cfg.Data[uidDataKey]; ok {
|
||||
data := item.(*api.ConfigMap).Data
|
||||
c.storeLock.Lock()
|
||||
defer c.storeLock.Unlock()
|
||||
if k, ok := data[key]; ok {
|
||||
return k, true, nil
|
||||
}
|
||||
return "", false, fmt.Errorf("Found config map %v but it doesn't contain uid key: %+v", key, cfg.Data)
|
||||
glog.Infof("Found config map %v but it doesn't contain key %v: %+v", keyStore, key, data)
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
// Put stores the given UID in the cluster config map.
|
||||
func (c *ConfigMapVault) Put(uid string) error {
|
||||
// Put inserts a key/value pair in the cluster config map.
|
||||
// If the key already exists, the value provided is stored.
|
||||
func (c *ConfigMapVault) Put(key, val string) error {
|
||||
c.storeLock.Lock()
|
||||
defer c.storeLock.Unlock()
|
||||
apiObj := &api.ConfigMap{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: c.name,
|
||||
Namespace: c.namespace,
|
||||
},
|
||||
Data: map[string]string{uidDataKey: uid},
|
||||
}
|
||||
cfgMapKey := fmt.Sprintf("%v/%v", c.namespace, c.name)
|
||||
|
||||
item, exists, err := c.ConfigMapStore.GetByKey(cfgMapKey)
|
||||
if err == nil && exists {
|
||||
data := item.(*api.ConfigMap).Data
|
||||
if k, ok := data[uidDataKey]; ok && k == uid {
|
||||
existingVal, ok := data[key]
|
||||
if ok && existingVal == val {
|
||||
// duplicate, no need to update.
|
||||
return nil
|
||||
} else if ok {
|
||||
glog.Infof("Configmap %v has key %v but wrong value %v, updating", cfgMapKey, k, uid)
|
||||
}
|
||||
|
||||
data[key] = val
|
||||
apiObj.Data = data
|
||||
if existingVal != val {
|
||||
glog.Infof("Configmap %v has key %v but wrong value %v, updating to %v", cfgMapKey, key, existingVal, val)
|
||||
} else {
|
||||
glog.Infof("Configmap %v will be updated with %v = %v", cfgMapKey, key, val)
|
||||
}
|
||||
if err := c.ConfigMapStore.Update(apiObj); err != nil {
|
||||
return fmt.Errorf("Failed to update %v: %v", cfgMapKey, err)
|
||||
}
|
||||
} else if err := c.ConfigMapStore.Add(apiObj); err != nil {
|
||||
return fmt.Errorf("Failed to add %v: %v", cfgMapKey, err)
|
||||
} else {
|
||||
apiObj.Data = map[string]string{key: val}
|
||||
if err := c.ConfigMapStore.Add(apiObj); err != nil {
|
||||
return fmt.Errorf("Failed to add %v: %v", cfgMapKey, err)
|
||||
}
|
||||
}
|
||||
glog.Infof("Successfully stored uid %q in config map %v", uid, cfgMapKey)
|
||||
glog.Infof("Successfully stored key %v = %v in config map %v", key, val, cfgMapKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes the cluster UID storing config map.
|
||||
// Delete deletes the ConfigMapStore.
|
||||
func (c *ConfigMapVault) Delete() error {
|
||||
cfgMapKey := fmt.Sprintf("%v/%v", c.namespace, c.name)
|
||||
item, _, err := c.ConfigMapStore.GetByKey(cfgMapKey)
|
||||
|
|
@ -108,13 +122,19 @@ func (c *ConfigMapVault) Delete() error {
|
|||
// This client is essentially meant to abstract out the details of
|
||||
// configmaps and the API, and just store/retrieve a single value, the cluster uid.
|
||||
func NewConfigMapVault(c client.Interface, uidNs, uidConfigMapName string) *ConfigMapVault {
|
||||
return &ConfigMapVault{NewConfigMapStore(c), uidNs, uidConfigMapName}
|
||||
return &ConfigMapVault{
|
||||
ConfigMapStore: NewConfigMapStore(c),
|
||||
namespace: uidNs,
|
||||
name: uidConfigMapName}
|
||||
}
|
||||
|
||||
// NewFakeConfigMapVault is an implementation of the ConfigMapStore that doesn't
|
||||
// persist configmaps. Only used in testing.
|
||||
func NewFakeConfigMapVault(ns, name string) *ConfigMapVault {
|
||||
return &ConfigMapVault{cache.NewStore(cache.MetaNamespaceKeyFunc), ns, name}
|
||||
return &ConfigMapVault{
|
||||
ConfigMapStore: cache.NewStore(cache.MetaNamespaceKeyFunc),
|
||||
namespace: ns,
|
||||
name: name}
|
||||
}
|
||||
|
||||
// ConfigMapStore wraps the store interface. Implementations usually persist
|
||||
|
|
|
|||
|
|
@ -24,31 +24,51 @@ import (
|
|||
|
||||
func TestConfigMapUID(t *testing.T) {
|
||||
vault := NewFakeConfigMapVault(api.NamespaceSystem, "ingress-uid")
|
||||
uid := ""
|
||||
k, exists, err := vault.Get()
|
||||
// Get value from an empty vault.
|
||||
val, exists, err := vault.Get(UidDataKey)
|
||||
if exists {
|
||||
t.Errorf("Got a key from an empyt vault")
|
||||
t.Errorf("Got value from an empty vault")
|
||||
}
|
||||
vault.Put(uid)
|
||||
k, exists, err = vault.Get()
|
||||
|
||||
// Store empty value for UidDataKey.
|
||||
uid := ""
|
||||
vault.Put(UidDataKey, uid)
|
||||
val, exists, err = vault.Get(UidDataKey)
|
||||
if !exists || err != nil {
|
||||
t.Errorf("Failed to retrieve value from vault")
|
||||
t.Errorf("Failed to retrieve value from vault: %v", err)
|
||||
}
|
||||
if k != "" {
|
||||
if val != "" {
|
||||
t.Errorf("Failed to store empty string as a key in the vault")
|
||||
}
|
||||
vault.Put("newuid")
|
||||
k, exists, err = vault.Get()
|
||||
|
||||
// Store actual value in key.
|
||||
storedVal := "newuid"
|
||||
vault.Put(UidDataKey, storedVal)
|
||||
val, exists, err = vault.Get(UidDataKey)
|
||||
if !exists || err != nil {
|
||||
t.Errorf("Failed to retrieve value from vault")
|
||||
} else if val != storedVal {
|
||||
t.Errorf("Failed to store empty string as a key in the vault")
|
||||
}
|
||||
if k != "newuid" {
|
||||
t.Errorf("Failed to modify uid")
|
||||
|
||||
// Store second value which will have the affect of updating to Store
|
||||
// rather than adding.
|
||||
secondVal := "bar"
|
||||
vault.Put("foo", secondVal)
|
||||
val, exists, err = vault.Get("foo")
|
||||
if !exists || err != nil || val != secondVal {
|
||||
t.Errorf("Failed to retrieve second value from vault")
|
||||
}
|
||||
val, exists, err = vault.Get(UidDataKey)
|
||||
if !exists || err != nil || val != storedVal {
|
||||
t.Errorf("Failed to retrieve first value from vault")
|
||||
}
|
||||
|
||||
// Delete value.
|
||||
if err := vault.Delete(); err != nil {
|
||||
t.Errorf("Failed to delete uid %v", err)
|
||||
}
|
||||
if uid, exists, _ := vault.Get(); exists {
|
||||
t.Errorf("Found uid %v, expected none", uid)
|
||||
if _, exists, _ := vault.Get(UidDataKey); exists {
|
||||
t.Errorf("Found uid but expected none after deletion")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue