Skip to content
This repository has been archived by the owner on Jan 13, 2021. It is now read-only.

Commit

Permalink
Merge pull request #397 from atlassian/enqueue-bundle-on-secret-confi…
Browse files Browse the repository at this point in the history
…gmap-change

Enqueue Bundle on ConfigMap/Secret event
  • Loading branch information
ash2k authored Jan 30, 2019
2 parents fd5931a + 9d2ba54 commit f7b5065
Show file tree
Hide file tree
Showing 7 changed files with 398 additions and 11 deletions.
10 changes: 7 additions & 3 deletions cmd/smith/app/bundle_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ func (c *BundleControllerConstructor) New(config *ctrl.Config, cctx *ctrl.Contex
if err != nil {
return nil, err
}
crdGVK := apiext_v1b1.SchemeGroupVersion.WithKind("CustomResourceDefinition")
crdInf, err := apiExtensionsInformer(config, cctx, apiExtClient,
apiext_v1b1.SchemeGroupVersion.WithKind("CustomResourceDefinition"),
crdGVK,
apiext_v1b1inf.NewCustomResourceDefinitionInformer)
if err != nil {
return nil, err
Expand Down Expand Up @@ -148,7 +149,7 @@ func (c *BundleControllerConstructor) New(config *ctrl.Config, cctx *ctrl.Contex
if err != nil {
return nil, err
}
resourceInfs[apiext_v1b1.SchemeGroupVersion.WithKind("CustomResourceDefinition")] = crdInf
resourceInfs[crdGVK] = crdInf
resourceInfs[smith_v1.BundleGVK] = bundleInf
for gvk, inf := range resourceInfs {
if err = multiStore.AddInformer(gvk, inf); err != nil {
Expand Down Expand Up @@ -226,7 +227,10 @@ func (c *BundleControllerConstructor) New(config *ctrl.Config, cctx *ctrl.Contex
Broadcaster: broadcaster,
Recorder: recorder,
}
cntrlr.Prepare(crdInf, resourceInfs)
err = cntrlr.Prepare(crdInf, resourceInfs)
if err != nil {
return nil, err
}

return &ctrl.Constructed{
Interface: cntrlr,
Expand Down
7 changes: 7 additions & 0 deletions it/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ go_library(
"//vendor/github.com/stretchr/testify/require:go_default_library",
"//vendor/go.uber.org/zap:go_default_library",
"//vendor/go.uber.org/zap/zaptest:go_default_library",
"//vendor/k8s.io/api/apps/v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1:go_default_library",
Expand All @@ -34,6 +35,7 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
Expand All @@ -51,6 +53,7 @@ go_test(
srcs = [
"adoption_test.go",
"crd_attribute_test.go",
"deployment_dependencies_test.go",
"deployment_ready_test.go",
"main_test.go",
"resource_deletion_test.go",
Expand All @@ -67,6 +70,7 @@ go_test(
"//examples/sleeper:go_default_library",
"//examples/sleeper/pkg/apis/sleeper/v1:go_default_library",
"//pkg/apis/smith/v1:go_default_library",
"//pkg/specchecker/builtin:go_default_library",
"//pkg/util/testing:go_default_library",
"//vendor/github.com/ash2k/stager:go_default_library",
"//vendor/github.com/atlassian/ctrl/apis/condition/v1:go_default_library",
Expand All @@ -76,7 +80,10 @@ go_test(
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/tools/watch:go_default_library",
],
)
196 changes: 196 additions & 0 deletions it/deployment_dependencies_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package it

import (
"context"
"testing"

smith_v1 "github.com/atlassian/smith/pkg/apis/smith/v1"
"github.com/atlassian/smith/pkg/specchecker/builtin"
"github.com/stretchr/testify/require"
apps_v1 "k8s.io/api/apps/v1"
core_v1 "k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/tools/cache"
toolswatch "k8s.io/client-go/tools/watch"
)

const (
deploymentDependenciesConfigMapName = "map1"
deploymentDependenciesSecretName = "secret1"
)

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

bundle := constructDeploymentDependenciesBundle()
SetupApp(t, bundle, false, true, assertConfigMapAndSecretToDeploymentToBundleIndex)
}

func assertConfigMapAndSecretToDeploymentToBundleIndex(ctx context.Context, t *testing.T, cfg *Config, args ...interface{}) {
// initial create of ConfigMap and Secret
cm, err := cfg.MainClient.CoreV1().ConfigMaps(cfg.Namespace).Create(deploymentDependenciesConfigMap())
require.NoError(cfg.T, err)
secret, err := cfg.MainClient.CoreV1().Secrets(cfg.Namespace).Create(deploymentDependenciesSecret())
require.NoError(cfg.T, err)

// Wait for stable state
deploymentName := cfg.Bundle.Spec.Resources[0].Spec.Object.(meta_v1.Object).GetName()
lw := cache.NewListWatchFromClient(cfg.MainClient.AppsV1().RESTClient(), "deployments", cfg.Namespace, fields.Everything())
cond := IsPodSpecAnnotationCond(t, cfg.Namespace, deploymentName, builtin.EnvRefHashAnnotation, "97b5461821487e047e760880764dd9b31a5b7f39e8961b98b809c6d3f5b3cf3a")
_, err = toolswatch.UntilWithSync(ctx, lw, &apps_v1.Deployment{}, nil, cond)
require.NoError(cfg.T, err)

// Update ConfigMap
cm.Data["b"] = "a"
_, err = cfg.MainClient.CoreV1().ConfigMaps(cfg.Namespace).Update(cm)
require.NoError(cfg.T, err)

// Wait for updated annotation
cond = IsPodSpecAnnotationCond(t, cfg.Namespace, deploymentName, builtin.EnvRefHashAnnotation, "5fb60505d125dd42160a9ef237873345020a90e8d607861ced50a641c3a800a9")
_, err = toolswatch.UntilWithSync(ctx, lw, &apps_v1.Deployment{}, nil, cond)
require.NoError(cfg.T, err)

// Update Secret
secret.StringData = map[string]string{
"z": "c",
}
_, err = cfg.MainClient.CoreV1().Secrets(cfg.Namespace).Update(secret)
require.NoError(cfg.T, err)

// Wait for updated annotation
cond = IsPodSpecAnnotationCond(t, cfg.Namespace, deploymentName, builtin.EnvRefHashAnnotation, "20ed86a5106aab7e892f498f38dc1b713405d864878e6a074377fbdcba129599")
_, err = toolswatch.UntilWithSync(ctx, lw, &apps_v1.Deployment{}, nil, cond)
require.NoError(cfg.T, err)
}

func constructDeploymentDependenciesBundle() *smith_v1.Bundle {
var (
replicas int32 = 1
minReadySeconds int32 = 1
revisionHistoryLimit int32 = 10
progressDeadlineSeconds int32 = 5
terminationGracePeriodSeconds int64 = 30
labelMap = map[string]string{
"name": string(deploymentResourceName),
}
)
return &smith_v1.Bundle{
TypeMeta: meta_v1.TypeMeta{
Kind: smith_v1.BundleResourceKind,
APIVersion: smith_v1.BundleResourceGroupVersion,
},
ObjectMeta: meta_v1.ObjectMeta{
Name: "bundle-dt",
},
Spec: smith_v1.BundleSpec{
Resources: []smith_v1.Resource{
{
Name: deploymentResourceName,
Spec: smith_v1.ResourceSpec{
Object: &apps_v1.Deployment{
TypeMeta: meta_v1.TypeMeta{
Kind: "Deployment",
APIVersion: apps_v1.SchemeGroupVersion.String(),
},
ObjectMeta: meta_v1.ObjectMeta{
Name: string(deploymentResourceName),
},
Spec: apps_v1.DeploymentSpec{
Selector: &meta_v1.LabelSelector{
MatchLabels: labelMap,
},
Replicas: &replicas,
Template: core_v1.PodTemplateSpec{
ObjectMeta: meta_v1.ObjectMeta{
Labels: labelMap,
},
Spec: core_v1.PodSpec{
Containers: []core_v1.Container{
{
Name: "container1",
Image: "roaanv/k8sti",
EnvFrom: []core_v1.EnvFromSource{
{
ConfigMapRef: &core_v1.ConfigMapEnvSource{
LocalObjectReference: core_v1.LocalObjectReference{
Name: deploymentDependenciesConfigMapName,
},
},
},
{
SecretRef: &core_v1.SecretEnvSource{
LocalObjectReference: core_v1.LocalObjectReference{
Name: deploymentDependenciesSecretName,
},
},
},
},
ImagePullPolicy: core_v1.PullAlways,
TerminationMessagePath: "/dev/termination-log",
TerminationMessagePolicy: core_v1.TerminationMessageReadFile,
},
},
DNSPolicy: core_v1.DNSClusterFirst,
RestartPolicy: core_v1.RestartPolicyAlways,
SchedulerName: "default-scheduler",
SecurityContext: &core_v1.PodSecurityContext{},
TerminationGracePeriodSeconds: &terminationGracePeriodSeconds,
},
},
MinReadySeconds: minReadySeconds,
ProgressDeadlineSeconds: &progressDeadlineSeconds,
RevisionHistoryLimit: &revisionHistoryLimit,

Strategy: apps_v1.DeploymentStrategy{
Type: apps_v1.RollingUpdateDeploymentStrategyType,
RollingUpdate: &apps_v1.RollingUpdateDeployment{
MaxUnavailable: &intstr.IntOrString{
Type: intstr.String,
StrVal: "25%",
},
MaxSurge: &intstr.IntOrString{
Type: intstr.String,
StrVal: "25%",
},
},
},
},
},
},
},
},
},
}
}

func deploymentDependenciesConfigMap() *core_v1.ConfigMap {
return &core_v1.ConfigMap{
TypeMeta: meta_v1.TypeMeta{
Kind: "ConfigMap",
APIVersion: core_v1.SchemeGroupVersion.String(),
},
ObjectMeta: meta_v1.ObjectMeta{
Name: deploymentDependenciesConfigMapName,
},
Data: map[string]string{
"a": "b",
},
}
}

func deploymentDependenciesSecret() *core_v1.Secret {
return &core_v1.Secret{
TypeMeta: meta_v1.TypeMeta{
Kind: "Secret",
APIVersion: core_v1.SchemeGroupVersion.String(),
},
ObjectMeta: meta_v1.ObjectMeta{
Name: deploymentDependenciesSecretName,
},
StringData: map[string]string{
"x": "b",
},
}
}
35 changes: 35 additions & 0 deletions it/utils_for_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zaptest"
apps_v1 "k8s.io/api/apps/v1"
core_v1 "k8s.io/api/core/v1"
apiExtClientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
apiext_v1b1inf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1beta1"
Expand All @@ -36,6 +37,7 @@ import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
Expand All @@ -45,6 +47,14 @@ import (
toolswatch "k8s.io/client-go/tools/watch"
)

var (
appsV1Scheme = runtime.NewScheme()
)

func init() {
utilruntime.Must(apps_v1.SchemeBuilder.AddToScheme(appsV1Scheme))
}

type TestFunc func(context.Context, *testing.T, *Config, ...interface{})

type Config struct {
Expand Down Expand Up @@ -161,6 +171,31 @@ func IsBundleObservedGenerationCond(namespace, name string) toolswatch.Condition
}
}

func IsPodSpecAnnotationCond(t *testing.T, namespace, name, annotation, value string) toolswatch.ConditionFunc {
return func(event watch.Event) (bool, error) {
metaObj := event.Object.(meta_v1.Object)
if metaObj.GetNamespace() != namespace || metaObj.GetName() != name {
return false, nil
}
deployment := &apps_v1.Deployment{}
err := util.ConvertType(appsV1Scheme, event.Object, deployment)
if err != nil {
return false, err
}
annotations := deployment.Spec.Template.Annotations
actual, ok := annotations[annotation]
if !ok {
t.Logf("Pod Spec annotation %s is not set", annotation)
return false, nil
}
if actual != value {
t.Logf("Ignoring Pod Spec annotation %s value %s. Expecting %s", annotation, actual, value)
return false, nil
}
return true, nil
}
}

func TestSetup(t *testing.T) (*rest.Config, *kubernetes.Clientset, *smithClientset.Clientset) {
config, err := options.LoadRestClientConfig("voyager-test", options.RestClientOptions{
APIQPS: 10,
Expand Down
1 change: 1 addition & 0 deletions pkg/controller/bundlec/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ go_library(
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/go.uber.org/zap:go_default_library",
"//vendor/k8s.io/api/apps/v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
Expand Down
Loading

0 comments on commit f7b5065

Please sign in to comment.