Merge pull request #433 from weaveworks/projected-configs

Track projected configmaps and secrets
This commit is contained in:
Stefan Prodan
2020-02-12 09:37:56 +02:00
committed by GitHub
4 changed files with 277 additions and 77 deletions
+45
View File
@@ -124,6 +124,32 @@ func (ct *ConfigTracker) GetTargetConfigs(cd *flaggerv1.Canary) (map[string]Conf
res[secret.GetName()] = *secret
}
}
if projected := volume.Projected; projected != nil {
for _, source := range projected.Sources {
if cmv := source.ConfigMap; cmv != nil {
config, err := ct.getRefFromConfigMap(cmv.Name, cd.Namespace)
if err != nil {
ct.Logger.Errorf("configMap %s.%s query error %v", cmv.Name, cd.Namespace, err)
continue
}
if config != nil {
res[config.GetName()] = *config
}
}
if sv := source.Secret; sv != nil {
secret, err := ct.getRefFromSecret(sv.Name, cd.Namespace)
if err != nil {
ct.Logger.Errorf("secret %s.%s query error %v", sv.Name, cd.Namespace, err)
continue
}
if secret != nil {
res[secret.GetName()] = *secret
}
}
}
}
}
// scan containers
for _, container := range targetDep.Spec.Template.Spec.Containers {
@@ -335,7 +361,26 @@ func (ct *ConfigTracker) ApplyPrimaryConfigs(spec corev1.PodSpec, refs map[strin
spec.Volumes[i].Secret.SecretName += "-primary"
}
}
if projected := volume.Projected; projected != nil {
for s, source := range projected.Sources {
if cmv := source.ConfigMap; cmv != nil {
name := fmt.Sprintf("%s/%s", ConfigRefMap, cmv.Name)
if _, exists := refs[name]; exists {
spec.Volumes[i].Projected.Sources[s].ConfigMap.Name += "-primary"
}
}
if sv := source.Secret; sv != nil {
name := fmt.Sprintf("%s/%s", ConfigRefSecret, sv.Name)
if _, exists := refs[name]; exists {
spec.Volumes[i].Projected.Sources[s].Secret.Name += "-primary"
}
}
}
}
}
// update containers
for _, container := range spec.Containers {
// update env
+131
View File
@@ -0,0 +1,131 @@
package canary
import (
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func TestConfigTracker_ConfigMaps(t *testing.T) {
mocks := newFixture()
configMap := newTestConfigMap()
configMapProjected := newTestConfigProjected()
err := mocks.deployer.Initialize(mocks.canary, true)
if err != nil {
t.Fatal(err.Error())
}
depPrimary, err := mocks.kubeClient.AppsV1().Deployments("default").Get("podinfo-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
configPrimaryVolName := depPrimary.Spec.Template.Spec.Volumes[0].VolumeSource.ConfigMap.LocalObjectReference.Name
if configPrimaryVolName != "podinfo-config-vol-primary" {
t.Errorf("Got config name %v wanted %v", configPrimaryVolName, "podinfo-config-vol-primary")
}
configPrimary, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimary.Data["color"] != configMap.Data["color"] {
t.Errorf("Got ConfigMap color %s wanted %s", configPrimary.Data["color"], configMap.Data["color"])
}
configPrimaryEnv, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-all-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimaryEnv.Data["color"] != configMap.Data["color"] {
t.Errorf("Got ConfigMap %s wanted %s", configPrimaryEnv.Data["a"], configMap.Data["color"])
}
configPrimaryVol, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-vol-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimaryVol.Data["color"] != configMap.Data["color"] {
t.Errorf("Got ConfigMap color %s wanted %s", configPrimary.Data["color"], configMap.Data["color"])
}
configProjectedName := depPrimary.Spec.Template.Spec.Volumes[2].VolumeSource.Projected.Sources[0].ConfigMap.Name
if configProjectedName != "podinfo-config-projected-primary" {
t.Errorf("Got config name %v wanted %v", configProjectedName, "podinfo-config-projected-primary")
}
configPrimaryProjected, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-vol-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimaryProjected.Data["color"] != configMapProjected.Data["color"] {
t.Errorf("Got ConfigMap color %s wanted %s", configPrimaryProjected.Data["color"], configMapProjected.Data["color"])
}
}
func TestConfigTracker_Secrets(t *testing.T) {
mocks := newFixture()
secret := newTestSecret()
secretProjected := newTestSecretProjected()
err := mocks.deployer.Initialize(mocks.canary, true)
if err != nil {
t.Fatal(err.Error())
}
depPrimary, err := mocks.kubeClient.AppsV1().Deployments("default").Get("podinfo-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
secretPrimaryVolName := depPrimary.Spec.Template.Spec.Volumes[1].VolumeSource.Secret.SecretName
if secretPrimaryVolName != "podinfo-secret-vol-primary" {
t.Errorf("Got config name %v wanted %v", secretPrimaryVolName, "podinfo-secret-vol-primary")
}
secretPrimary, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimary.Data["apiKey"]) != string(secret.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimary.Data["apiKey"], secret.Data["apiKey"])
}
secretPrimaryEnv, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-all-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimaryEnv.Data["apiKey"]) != string(secret.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimary.Data["apiKey"], secret.Data["apiKey"])
}
secretPrimaryVol, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-vol-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimaryVol.Data["apiKey"]) != string(secret.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimary.Data["apiKey"], secret.Data["apiKey"])
}
secretProjectedName := depPrimary.Spec.Template.Spec.Volumes[2].VolumeSource.Projected.Sources[1].Secret.Name
if secretProjectedName != "podinfo-secret-projected-primary" {
t.Errorf("Got config name %v wanted %v", secretProjectedName, "podinfo-secret-projected-primary")
}
secretPrimaryProjected, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-projected-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimaryProjected.Data["apiKey"]) != string(secretProjected.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimaryProjected.Data["apiKey"], secretProjected.Data["apiKey"])
}
}
+1 -62
View File
@@ -21,14 +21,7 @@ func TestCanaryDeployer_Sync(t *testing.T) {
t.Fatal(err.Error())
}
configName := depPrimary.Spec.Template.Spec.Volumes[0].VolumeSource.ConfigMap.LocalObjectReference.Name
if configName != "podinfo-config-vol-primary" {
t.Errorf("Got config name %v wanted %v", configName, "podinfo-config-vol-primary")
}
dep := newTestDeployment()
configMap := NewTestConfigMap()
secret := NewTestSecret()
primaryImage := depPrimary.Spec.Template.Spec.Containers[0].Image
sourceImage := dep.Spec.Template.Spec.Containers[0].Image
@@ -44,60 +37,6 @@ func TestCanaryDeployer_Sync(t *testing.T) {
if hpaPrimary.Spec.ScaleTargetRef.Name != depPrimary.Name {
t.Errorf("Got HPA target %s wanted %s", hpaPrimary.Spec.ScaleTargetRef.Name, depPrimary.Name)
}
configPrimary, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimary.Data["color"] != configMap.Data["color"] {
t.Errorf("Got ConfigMap color %s wanted %s", configPrimary.Data["color"], configMap.Data["color"])
}
configPrimaryEnv, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-all-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimaryEnv.Data["color"] != configMap.Data["color"] {
t.Errorf("Got ConfigMap %s wanted %s", configPrimaryEnv.Data["a"], configMap.Data["color"])
}
configPrimaryVol, err := mocks.kubeClient.CoreV1().ConfigMaps("default").Get("podinfo-config-vol-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if configPrimaryVol.Data["color"] != configMap.Data["color"] {
t.Errorf("Got ConfigMap color %s wanted %s", configPrimary.Data["color"], configMap.Data["color"])
}
secretPrimary, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimary.Data["apiKey"]) != string(secret.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimary.Data["apiKey"], secret.Data["apiKey"])
}
secretPrimaryEnv, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-all-env-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimaryEnv.Data["apiKey"]) != string(secret.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimary.Data["apiKey"], secret.Data["apiKey"])
}
secretPrimaryVol, err := mocks.kubeClient.CoreV1().Secrets("default").Get("podinfo-secret-vol-primary", metav1.GetOptions{})
if err != nil {
t.Fatal(err.Error())
}
if string(secretPrimaryVol.Data["apiKey"]) != string(secret.Data["apiKey"]) {
t.Errorf("Got primary secret %s wanted %s", secretPrimary.Data["apiKey"], secret.Data["apiKey"])
}
}
func TestCanaryDeployer_IsNewSpec(t *testing.T) {
@@ -284,7 +223,7 @@ func TestCanaryDeployer_SyncStatus(t *testing.T) {
t.Fatalf("Status tracking configs are empty")
}
configs := *res.Status.TrackedConfigs
secret := NewTestSecret()
secret := newTestSecret()
if _, exists := configs["secret/"+secret.GetName()]; !exists {
t.Errorf("Secret %s not found in status", secret.GetName())
}
+100 -15
View File
@@ -32,12 +32,14 @@ func newFixture() fixture {
kubeClient := fake.NewSimpleClientset(
newTestDeployment(),
newTestHPA(),
NewTestConfigMap(),
NewTestConfigMapEnv(),
NewTestConfigMapVol(),
NewTestSecret(),
NewTestSecretEnv(),
NewTestSecretVol(),
newTestConfigMap(),
newTestConfigMapEnv(),
newTestConfigMapVol(),
newTestConfigProjected(),
newTestSecret(),
newTestSecretEnv(),
newTestSecretVol(),
newTestSecretProjected(),
)
logger, _ := logger.NewLogger("debug")
@@ -63,7 +65,7 @@ func newFixture() fixture {
}
}
func NewTestConfigMap() *corev1.ConfigMap {
func newTestConfigMap() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -90,7 +92,20 @@ func NewTestConfigMapV2() *corev1.ConfigMap {
}
}
func NewTestConfigMapEnv() *corev1.ConfigMap {
func newTestConfigProjected() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-config-projected",
},
Data: map[string]string{
"color": "red",
},
}
}
func newTestConfigMapEnv() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -103,7 +118,7 @@ func NewTestConfigMapEnv() *corev1.ConfigMap {
}
}
func NewTestConfigMapVol() *corev1.ConfigMap {
func newTestConfigMapVol() *corev1.ConfigMap {
return &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -116,7 +131,7 @@ func NewTestConfigMapVol() *corev1.ConfigMap {
}
}
func NewTestSecret() *corev1.Secret {
func newTestSecret() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -130,21 +145,21 @@ func NewTestSecret() *corev1.Secret {
}
}
func NewTestSecretV2() *corev1.Secret {
func newTestSecretProjected() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
Name: "podinfo-secret-env",
Name: "podinfo-secret-projected",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"apiKey": []byte("test2"),
"apiKey": []byte("test"),
},
}
}
func NewTestSecretEnv() *corev1.Secret {
func newTestSecretEnv() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -158,7 +173,7 @@ func NewTestSecretEnv() *corev1.Secret {
}
}
func NewTestSecretVol() *corev1.Secret {
func newTestSecretVol() *corev1.Secret {
return &corev1.Secret{
TypeMeta: metav1.TypeMeta{APIVersion: corev1.SchemeGroupVersion.String()},
ObjectMeta: metav1.ObjectMeta{
@@ -311,6 +326,41 @@ func newTestDeployment() *appsv1.Deployment {
},
},
},
{
Name: "projected",
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{
{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-projected",
},
Items: []corev1.KeyToPath{
{
Key: "color",
Path: "my-group/my-color",
},
},
},
},
{
Secret: &corev1.SecretProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-secret-projected",
},
Items: []corev1.KeyToPath{
{
Key: "apiKey",
Path: "my-group/my-api-key",
},
},
},
},
},
},
},
},
},
},
},
@@ -421,6 +471,41 @@ func newTestDeploymentV2() *appsv1.Deployment {
},
},
},
{
Name: "projected",
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{
{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-config-projected",
},
Items: []corev1.KeyToPath{
{
Key: "color",
Path: "my-group/my-color",
},
},
},
},
{
Secret: &corev1.SecretProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "podinfo-secret-projected",
},
Items: []corev1.KeyToPath{
{
Key: "apiKey",
Path: "my-group/my-api-key",
},
},
},
},
},
},
},
},
},
},
},