Skip to content

Commit

Permalink
Assume configMap without version is compatible with initial release v…
Browse files Browse the repository at this point in the history
…ersion

The version number was added at the end of the re-design of the versioned
secrets mechanism, and is also used as a marker if the configmap needs to
be created or updated.

This change allows updates from pre-release versions missing the config-version,
but otherwise compatible with the version 1 format.

Ref #21
  • Loading branch information
jandubois committed May 7, 2018
1 parent a600c8b commit 0fc4fc5
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 30 deletions.
35 changes: 23 additions & 12 deletions secrets/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,27 @@ import (
"k8s.io/client-go/rest"
)

// The name of the secrets configmap
const defaultSecretsConfigMapName = "secrets-config"

// The unversioned name of the secret used by legacy versions of the secrets generator
const legacySecretName = "secret"

// The name of the secrets configmap
const secretsConfigMapName = "secrets-config"

const currentSecretName = "current-secrets-name"
const currentSecretGeneration = "current-secrets-generation"
const previousSecretName = "previous-secrets-name"
const configVersion = "config-version"

const currentConfigVersion = "1"

// SecretGenerator contains all global state for creating new secrets
type SecretGenerator struct {
Domain string
Namespace string
ServiceDomainSuffix string
SecretsName string
SecretsGeneration string
Domain string
Namespace string
ServiceDomainSuffix string
SecretsName string
SecretsGeneration string
SecretsConfigMapName string
}

// Generate will fetch the current secrets, generate any missing values, and writes the new secrets
Expand All @@ -48,7 +51,9 @@ func (sg *SecretGenerator) Generate(manifestReader io.Reader) error {
if err != nil {
return err
}

if sg.SecretsConfigMapName == "" {
sg.SecretsConfigMapName = defaultSecretsConfigMapName
}
configMap := sg.getSecretConfig(c)
secret, err := sg.getSecret(s, configMap)
if err != nil {
Expand Down Expand Up @@ -117,11 +122,17 @@ func (sg *SecretGenerator) getSecretInterface() (secretInterface, error) {

// GetSecretConfig returns the configmap containing the secrets configuration
func (sg *SecretGenerator) getSecretConfig(c configMapInterface) *v1.ConfigMap {
configMap, err := c.Get(secretsConfigMapName, metav1.GetOptions{})
configMap, err := c.Get(sg.SecretsConfigMapName, metav1.GetOptions{})
if err == nil && configMap.Data[configVersion] == "" {
// Assume pre-release configMap without version is compatible with initial release
// Setting configVersion here also tells updateSecret() that the configMap
// needs to be updated and not created
configMap.Data[configVersion] = currentConfigVersion
}
if err != nil {
configMap = &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: secretsConfigMapName,
Name: sg.SecretsConfigMapName,
},
Data: map[string]string{},
}
Expand Down Expand Up @@ -247,7 +258,7 @@ func (sg *SecretGenerator) updateSecret(s secretInterface, secrets *v1.Secret, c

// update configmap
if configMap.Data[configVersion] == "" {
configMap.Data[configVersion] = "1"
configMap.Data[configVersion] = currentConfigVersion
_, err = c.Create(configMap)
if err != nil {
delete(configMap.Data, configVersion)
Expand Down
94 changes: 76 additions & 18 deletions secrets/secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,23 @@ func (m *MockConfigMapInterface) Delete(name string, options *metav1.DeleteOptio

func (m *MockConfigMapInterface) Get(name string, options metav1.GetOptions) (*v1.ConfigMap, error) {
m.Called(name, options)
return nil, errors.New("not found")
if name == defaultSecretsConfigMapName {
return nil, errors.New("not found")
}

configMap := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Data: map[string]string{},
}
// Set to non-default values
configMap.Data[currentSecretName] = "my-secret-name"
configMap.Data[currentSecretGeneration] = "5"
if name != "legacy" {
configMap.Data[configVersion] = "2"
}
return configMap, nil
}

func (m *MockConfigMapInterface) Update(configMap *v1.ConfigMap) (*v1.ConfigMap, error) {
Expand All @@ -81,27 +97,69 @@ func (m *MockConfigMapInterface) Update(configMap *v1.ConfigMap) (*v1.ConfigMap,

func testingSecretGenerator() SecretGenerator {
return SecretGenerator{
Namespace: "namespace",
ServiceDomainSuffix: "suffix",
SecretsName: "new-secret",
SecretsGeneration: "1",
Namespace: "namespace",
ServiceDomainSuffix: "suffix",
SecretsName: "new-secret",
SecretsGeneration: "1",
SecretsConfigMapName: defaultSecretsConfigMapName,
}
}

func TestGetSecretConfig(t *testing.T) {
t.Parallel()

sg := testingSecretGenerator()
t.Run("ConfigMap doesn't exist yet", func(t *testing.T) {
t.Parallel()

var c MockConfigMapInterface
c.On("Get", secretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)
sg := testingSecretGenerator()

if assert.NotNil(t, configMap) {
assert.Equal(t, secretsConfigMapName, configMap.Name)
assert.Equal(t, legacySecretName, configMap.Data[currentSecretName])
assert.Equal(t, "0", configMap.Data[currentSecretGeneration])
}
var c MockConfigMapInterface
c.On("Get", sg.SecretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)

if assert.NotNil(t, configMap) {
assert.Equal(t, sg.SecretsConfigMapName, configMap.Name)
assert.Equal(t, legacySecretName, configMap.Data[currentSecretName])
assert.Equal(t, "0", configMap.Data[currentSecretGeneration])
assert.Empty(t, configMap.Data[configVersion])
}
})

t.Run("ConfigMap already exists", func(t *testing.T) {
t.Parallel()

sg := testingSecretGenerator()
sg.SecretsConfigMapName = "non-default-name"

var c MockConfigMapInterface
c.On("Get", sg.SecretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)

if assert.NotNil(t, configMap) {
assert.Equal(t, sg.SecretsConfigMapName, configMap.Name)
assert.Equal(t, "my-secret-name", configMap.Data[currentSecretName])
assert.Equal(t, "5", configMap.Data[currentSecretGeneration])
assert.Equal(t, "2", configMap.Data[configVersion])
}
})

t.Run("ConfigMap exists but has no config-version", func(t *testing.T) {
t.Parallel()

sg := testingSecretGenerator()
sg.SecretsConfigMapName = "legacy"

var c MockConfigMapInterface
c.On("Get", sg.SecretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)

if assert.NotNil(t, configMap) {
assert.Equal(t, sg.SecretsConfigMapName, configMap.Name)
assert.Equal(t, "my-secret-name", configMap.Data[currentSecretName])
assert.Equal(t, "5", configMap.Data[currentSecretGeneration])
assert.Equal(t, currentConfigVersion, configMap.Data[configVersion])
}
})
}

func TestGetSecret(t *testing.T) {
Expand All @@ -113,7 +171,7 @@ func TestGetSecret(t *testing.T) {
sg := testingSecretGenerator()

var c MockConfigMapInterface
c.On("Get", secretsConfigMapName, metav1.GetOptions{})
c.On("Get", sg.SecretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)

var s MockSecretInterface
Expand All @@ -133,7 +191,7 @@ func TestGetSecret(t *testing.T) {
sg := testingSecretGenerator()

var c MockConfigMapInterface
c.On("Get", secretsConfigMapName, metav1.GetOptions{})
c.On("Get", sg.SecretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)
configMap.Data[currentSecretName] = "missing"

Expand All @@ -151,7 +209,7 @@ func TestGetSecret(t *testing.T) {
sg := testingSecretGenerator()

var c MockConfigMapInterface
c.On("Get", secretsConfigMapName, metav1.GetOptions{})
c.On("Get", sg.SecretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)
configMap.Data[currentSecretName] = "current-secret"

Expand All @@ -173,7 +231,7 @@ func TestGetSecret(t *testing.T) {
sg.SecretsName = "current-secret"

var c MockConfigMapInterface
c.On("Get", secretsConfigMapName, metav1.GetOptions{})
c.On("Get", sg.SecretsConfigMapName, metav1.GetOptions{})
configMap := sg.getSecretConfig(&c)
configMap.Data[currentSecretName] = "current-secret"

Expand Down

0 comments on commit 0fc4fc5

Please sign in to comment.