commit
6defcfcad8
internal/k8s
provider/kubernetes
types
|
@ -33,7 +33,12 @@ func updateDeploymentContainer(d *apps_v1.Deployment, index int, image string) {
|
|||
d.Spec.Template.Spec.Containers[index].Image = image
|
||||
}
|
||||
|
||||
func updateDeploymentInitContainer(d *apps_v1.Deployment, index int, image string) {
|
||||
d.Spec.Template.Spec.InitContainers[index].Image = image
|
||||
}
|
||||
|
||||
// stateful sets https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/
|
||||
|
||||
func getStatefulSetIdentifier(ss *apps_v1.StatefulSet) string {
|
||||
return "statefulset/" + ss.Namespace + "/" + ss.Name
|
||||
}
|
||||
|
@ -42,6 +47,10 @@ func updateStatefulSetContainer(ss *apps_v1.StatefulSet, index int, image string
|
|||
ss.Spec.Template.Spec.Containers[index].Image = image
|
||||
}
|
||||
|
||||
func updateStatefulSetInitContainer(ss *apps_v1.StatefulSet, index int, image string) {
|
||||
ss.Spec.Template.Spec.InitContainers[index].Image = image
|
||||
}
|
||||
|
||||
// daemonsets
|
||||
|
||||
func getDaemonsetSetIdentifier(s *apps_v1.DaemonSet) string {
|
||||
|
@ -52,6 +61,10 @@ func updateDaemonsetSetContainer(s *apps_v1.DaemonSet, index int, image string)
|
|||
s.Spec.Template.Spec.Containers[index].Image = image
|
||||
}
|
||||
|
||||
func updateDaemonsetSetInitContainer(s *apps_v1.DaemonSet, index int, image string) {
|
||||
s.Spec.Template.Spec.InitContainers[index].Image = image
|
||||
}
|
||||
|
||||
// cron
|
||||
|
||||
func getCronJobIdentifier(s *batch_v1.CronJob) string {
|
||||
|
@ -61,3 +74,8 @@ func getCronJobIdentifier(s *batch_v1.CronJob) string {
|
|||
func updateCronJobContainer(s *batch_v1.CronJob, index int, image string) {
|
||||
s.Spec.JobTemplate.Spec.Template.Spec.Containers[index].Image = image
|
||||
}
|
||||
|
||||
func updateCronJobInitContainer(s *batch_v1.CronJob, index int, image string) {
|
||||
s.Spec.JobTemplate.Spec.Template.Spec.InitContainers[index].Image = image
|
||||
}
|
||||
|
|
@ -275,6 +275,21 @@ func (r *GenericResource) GetImages() (images []string) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetInitImages - returns init images used by this resource
|
||||
func (r *GenericResource) GetInitImages() (images []string) {
|
||||
switch obj := r.obj.(type) {
|
||||
case *apps_v1.Deployment:
|
||||
return getContainerImages(obj.Spec.Template.Spec.InitContainers)
|
||||
case *apps_v1.StatefulSet:
|
||||
return getContainerImages(obj.Spec.Template.Spec.InitContainers)
|
||||
case *apps_v1.DaemonSet:
|
||||
return getContainerImages(obj.Spec.Template.Spec.InitContainers)
|
||||
case *batch_v1.CronJob:
|
||||
return getContainerImages(obj.Spec.JobTemplate.Spec.Template.Spec.InitContainers)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Containers - returns containers managed by this resource
|
||||
func (r *GenericResource) Containers() (containers []core_v1.Container) {
|
||||
switch obj := r.obj.(type) {
|
||||
|
@ -290,6 +305,21 @@ func (r *GenericResource) Containers() (containers []core_v1.Container) {
|
|||
return
|
||||
}
|
||||
|
||||
// InitContainers - returns init containers managed by this resource
|
||||
func (r *GenericResource) InitContainers() (containers []core_v1.Container) {
|
||||
switch obj := r.obj.(type) {
|
||||
case *apps_v1.Deployment:
|
||||
return obj.Spec.Template.Spec.InitContainers
|
||||
case *apps_v1.StatefulSet:
|
||||
return obj.Spec.Template.Spec.InitContainers
|
||||
case *apps_v1.DaemonSet:
|
||||
return obj.Spec.Template.Spec.InitContainers
|
||||
case *batch_v1.CronJob:
|
||||
return obj.Spec.JobTemplate.Spec.Template.Spec.InitContainers
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateContainer - updates container image
|
||||
func (r *GenericResource) UpdateContainer(index int, image string) {
|
||||
switch obj := r.obj.(type) {
|
||||
|
@ -304,6 +334,20 @@ func (r *GenericResource) UpdateContainer(index int, image string) {
|
|||
}
|
||||
}
|
||||
|
||||
// UpdateInitContainer - updates init container image
|
||||
func (r *GenericResource) UpdateInitContainer(index int, image string) {
|
||||
switch obj := r.obj.(type) {
|
||||
case *apps_v1.Deployment:
|
||||
updateDeploymentInitContainer(obj, index, image)
|
||||
case *apps_v1.StatefulSet:
|
||||
updateStatefulSetInitContainer(obj, index, image)
|
||||
case *apps_v1.DaemonSet:
|
||||
updateDaemonsetSetInitContainer(obj, index, image)
|
||||
case *batch_v1.CronJob:
|
||||
updateCronJobInitContainer(obj, index, image)
|
||||
}
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
// Total number of non-terminated pods targeted by this deployment (their labels match the selector).
|
||||
// +optional
|
||||
|
|
|
@ -48,6 +48,56 @@ func TestDeployment(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDeploymentInitContainer(t *testing.T) {
|
||||
d := &apps_v1.Deployment{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-1",
|
||||
Namespace: "xxxx",
|
||||
Annotations: map[string]string{},
|
||||
Labels: map[string]string{},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: core_v1.PodTemplateSpec{
|
||||
Spec: core_v1.PodSpec{
|
||||
Containers: []core_v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:1.1.1",
|
||||
},
|
||||
},
|
||||
InitContainers: []core_v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:1.1.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
}
|
||||
|
||||
gr, err := NewGenericResource(d)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create generic resource: %s", err)
|
||||
}
|
||||
|
||||
gr.UpdateContainer(0, "hey/there")
|
||||
gr.UpdateInitContainer(0, "over/here")
|
||||
|
||||
updated, ok := gr.GetResource().(*apps_v1.Deployment)
|
||||
if !ok {
|
||||
t.Fatalf("conversion failed")
|
||||
}
|
||||
|
||||
if updated.Spec.Template.Spec.Containers[0].Image != "hey/there" {
|
||||
t.Errorf("unexpected image: %s", updated.Spec.Template.Spec.Containers[0].Image)
|
||||
}
|
||||
|
||||
if updated.Spec.Template.Spec.InitContainers[0].Image != "over/here" {
|
||||
t.Errorf("unexpected image: %s", updated.Spec.Template.Spec.InitContainers[0].Image)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeploymentMultipleContainers(t *testing.T) {
|
||||
d := &apps_v1.Deployment{
|
||||
meta_v1.TypeMeta{},
|
||||
|
|
|
@ -145,6 +145,25 @@ func getImagePullSecretFromMeta(labels map[string]string, annotations map[string
|
|||
return ""
|
||||
}
|
||||
|
||||
func getInitContainerTrackingFromMeta(labels map[string]string, annotations map[string]string) bool {
|
||||
|
||||
searchKey := strings.ToLower(types.KeelInitContainerAnnotation)
|
||||
|
||||
for k, v := range labels {
|
||||
if strings.ToLower(k) == searchKey {
|
||||
return v == "true"
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range annotations {
|
||||
if strings.ToLower(k) == searchKey {
|
||||
return v == "true"
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// TrackedImages returns a list of tracked images.
|
||||
func (p *Provider) TrackedImages() ([]*types.TrackedImage, error) {
|
||||
var trackedImages []*types.TrackedImage
|
||||
|
@ -187,6 +206,9 @@ func (p *Provider) TrackedImages() ([]*types.TrackedImage, error) {
|
|||
secrets = append(secrets, gr.GetImagePullSecrets()...)
|
||||
|
||||
images := gr.GetImages()
|
||||
if getInitContainerTrackingFromMeta(labels, annotations) {
|
||||
images = append(images, gr.GetInitImages()...)
|
||||
}
|
||||
for _, img := range images {
|
||||
ref, err := image.Parse(img)
|
||||
if err != nil {
|
||||
|
|
|
@ -296,6 +296,107 @@ func TestGetImpacted(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetImpactedInit(t *testing.T) {
|
||||
fp := &fakeImplementer{}
|
||||
fp.namespaces = &v1.NamespaceList{
|
||||
Items: []v1.Namespace{
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{Name: "xxxx"},
|
||||
v1.NamespaceSpec{},
|
||||
v1.NamespaceStatus{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
deps := []*apps_v1.Deployment{
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-1",
|
||||
Namespace: "xxxx",
|
||||
Annotations: map[string]string{types.KeelInitContainerAnnotation: "true"},
|
||||
Labels: map[string]string{types.KeelPolicyLabel: "all"},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:1.1.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
},
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-2",
|
||||
Namespace: "xxxx",
|
||||
Annotations: map[string]string{types.KeelInitContainerAnnotation: "false"},
|
||||
Labels: map[string]string{"whatever": "all"},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:1.1.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
},
|
||||
}
|
||||
|
||||
grs := MustParseGRS(deps)
|
||||
grc := &k8s.GenericResourceCache{}
|
||||
grc.Add(grs...)
|
||||
|
||||
approver, teardown := approver()
|
||||
defer teardown()
|
||||
provider, err := NewProvider(fp, &fakeSender{}, approver, grc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get provider: %s", err)
|
||||
}
|
||||
|
||||
// creating "new version" event
|
||||
repo := &types.Repository{
|
||||
Name: "gcr.io/v2-namespace/hello-world",
|
||||
Tag: "1.1.2",
|
||||
}
|
||||
|
||||
plans, err := provider.createUpdatePlans(repo)
|
||||
if err != nil {
|
||||
t.Errorf("failed to get deployments: %s", err)
|
||||
}
|
||||
|
||||
if len(plans) != 1 {
|
||||
t.Fatalf("expected to find 1 deployment update plan but found %d", len(plans))
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, c := range plans[0].Resource.InitContainers() {
|
||||
|
||||
containerImageName := versionreg.ReplaceAllString(c.Image, "")
|
||||
|
||||
if containerImageName == repo.Name {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("couldn't find expected deployment in impacted deployment list")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetImpactedPolicyAnnotations(t *testing.T) {
|
||||
fp := &fakeImplementer{}
|
||||
fp.namespaces = &v1.NamespaceList{
|
||||
|
@ -1010,6 +1111,107 @@ func TestGetImpactedTwoContainersInSameDeployment(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
// Test to check how many deployments are "impacted" if we have two init containers
|
||||
func TestGetImpactedTwoInitContainersInSameDeployment(t *testing.T) {
|
||||
fp := &fakeImplementer{}
|
||||
fp.namespaces = &v1.NamespaceList{
|
||||
Items: []v1.Namespace{
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{Name: "xxxx"},
|
||||
v1.NamespaceSpec{},
|
||||
v1.NamespaceStatus{},
|
||||
},
|
||||
},
|
||||
}
|
||||
deps := []*apps_v1.Deployment{
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-1",
|
||||
Namespace: "xxxx",
|
||||
Labels: map[string]string{types.KeelPolicyLabel: "all"},
|
||||
Annotations: map[string]string{types.KeelInitContainerAnnotation: "true"},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:1.1.1",
|
||||
},
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/greetings-world:1.1.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
},
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-2",
|
||||
Namespace: "xxxx",
|
||||
Labels: map[string]string{"whatever": "all"},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:1.1.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
},
|
||||
}
|
||||
grs := MustParseGRS(deps)
|
||||
grc := &k8s.GenericResourceCache{}
|
||||
grc.Add(grs...)
|
||||
|
||||
approver, teardown := approver()
|
||||
defer teardown()
|
||||
provider, err := NewProvider(fp, &fakeSender{}, approver, grc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get provider: %s", err)
|
||||
}
|
||||
|
||||
// creating "new version" event
|
||||
repo := &types.Repository{
|
||||
Name: "gcr.io/v2-namespace/hello-world",
|
||||
Tag: "1.1.2",
|
||||
}
|
||||
|
||||
plans, err := provider.createUpdatePlans(repo)
|
||||
if err != nil {
|
||||
t.Errorf("failed to get deployments: %s", err)
|
||||
}
|
||||
|
||||
if len(plans) != 1 {
|
||||
t.Errorf("expected to find 1 deployment but found %d", len(plans))
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, c := range plans[0].Resource.InitContainers() {
|
||||
|
||||
containerImageName := versionreg.ReplaceAllString(c.Image, "")
|
||||
|
||||
if containerImageName == repo.Name {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Errorf("couldn't find expected deployment in impacted deployment list")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetImpactedTwoSameContainersInSameDeployment(t *testing.T) {
|
||||
|
||||
fp := &fakeImplementer{}
|
||||
|
@ -1445,3 +1647,74 @@ func TestTrackedImagesWithSecrets(t *testing.T) {
|
|||
t.Errorf("expected very-secret, got: %s", imgs[0].Secrets[1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrackedInitImagesWithSecrets(t *testing.T) {
|
||||
fp := &fakeImplementer{}
|
||||
fp.namespaces = &v1.NamespaceList{
|
||||
Items: []v1.Namespace{
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{Name: "xxxx"},
|
||||
v1.NamespaceSpec{},
|
||||
v1.NamespaceStatus{},
|
||||
},
|
||||
},
|
||||
}
|
||||
deps := []*apps_v1.Deployment{
|
||||
{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-1",
|
||||
Namespace: "xxxx",
|
||||
Labels: map[string]string{
|
||||
types.KeelPolicyLabel: "all",
|
||||
types.KeelImagePullSecretAnnotation: "foo-bar",
|
||||
types.KeelInitContainerAnnotation: "true",
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
Spec: v1.PodSpec{
|
||||
ImagePullSecrets: []v1.LocalObjectReference{
|
||||
{
|
||||
Name: "very-secret",
|
||||
},
|
||||
},
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:1.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
},
|
||||
}
|
||||
|
||||
grs := MustParseGRS(deps)
|
||||
grc := &k8s.GenericResourceCache{}
|
||||
grc.Add(grs...)
|
||||
|
||||
approver, teardown := approver()
|
||||
defer teardown()
|
||||
provider, err := NewProvider(fp, &fakeSender{}, approver, grc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get provider: %s", err)
|
||||
}
|
||||
|
||||
imgs, err := provider.TrackedImages()
|
||||
if err != nil {
|
||||
t.Errorf("failed to get image: %s", err)
|
||||
}
|
||||
if len(imgs) != 1 {
|
||||
t.Errorf("expected to find 1 image, got: %d", len(imgs))
|
||||
}
|
||||
|
||||
if imgs[0].Secrets[0] != "foo-bar" {
|
||||
t.Errorf("expected foo-bar, got: %s", imgs[0].Secrets[0])
|
||||
}
|
||||
if imgs[0].Secrets[1] != "very-secret" {
|
||||
t.Errorf("expected very-secret, got: %s", imgs[0].Secrets[1])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,68 @@ func checkForUpdate(plc policy.Policy, repo *types.Repository, resource *k8s.Gen
|
|||
"policy": plc.Name(),
|
||||
}).Debug("provider.kubernetes.checkVersionedDeployment: keel policy found, checking resource...")
|
||||
shouldUpdateDeployment = false
|
||||
if schedule, ok := resource.GetAnnotations()[types.KeelInitContainerAnnotation]; ok && schedule == "true" {
|
||||
for idx, c := range resource.InitContainers() {
|
||||
containerImageRef, err := image.Parse(c.Image)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image_name": c.Image,
|
||||
}).Error("provider.kubernetes: failed to parse image name")
|
||||
continue
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"name": resource.Name,
|
||||
"namespace": resource.Namespace,
|
||||
"kind": resource.Kind(),
|
||||
"parsed_image_name": containerImageRef.Remote(),
|
||||
"target_image_name": repo.Name,
|
||||
"target_tag": repo.Tag,
|
||||
"policy": plc.Name(),
|
||||
"image": c.Image,
|
||||
}).Debug("provider.kubernetes: checking image")
|
||||
|
||||
if containerImageRef.Repository() != eventRepoRef.Repository() {
|
||||
log.WithFields(log.Fields{
|
||||
"parsed_image_name": containerImageRef.Remote(),
|
||||
"target_image_name": repo.Name,
|
||||
}).Debug("provider.kubernetes: images do not match, ignoring")
|
||||
continue
|
||||
}
|
||||
|
||||
shouldUpdateContainer, err := plc.ShouldUpdate(containerImageRef.Tag(), eventRepoRef.Tag())
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"parsed_image_name": containerImageRef.Remote(),
|
||||
"target_image_name": repo.Name,
|
||||
"policy": plc.Name(),
|
||||
}).Error("provider.kubernetes: failed to check whether init container should be updated")
|
||||
continue
|
||||
}
|
||||
|
||||
if !shouldUpdateContainer {
|
||||
continue
|
||||
}
|
||||
|
||||
// updating spec template annotations
|
||||
setUpdateTime(resource)
|
||||
|
||||
// updating image
|
||||
if containerImageRef.Registry() == image.DefaultRegistryHostname {
|
||||
resource.UpdateInitContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.ShortName(), repo.Tag))
|
||||
} else {
|
||||
resource.UpdateInitContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.Repository(), repo.Tag))
|
||||
}
|
||||
|
||||
shouldUpdateDeployment = true
|
||||
|
||||
updatePlan.CurrentVersion = containerImageRef.Tag()
|
||||
updatePlan.NewVersion = repo.Tag
|
||||
updatePlan.Resource = resource
|
||||
}
|
||||
}
|
||||
for idx, c := range resource.Containers() {
|
||||
containerImageRef, err := image.Parse(c.Image)
|
||||
if err != nil {
|
||||
|
|
|
@ -627,6 +627,111 @@ func TestProvider_checkForUpdate(t *testing.T) {
|
|||
wantShouldUpdateDeployment: true,
|
||||
wantErr: false,
|
||||
},
|
||||
|
||||
{
|
||||
name: "update init container if tracking is enabled",
|
||||
args: args{
|
||||
policy: policy.NewForcePolicy(false),
|
||||
repo: &types.Repository{Name: "gcr.io/v2-namespace/hello-world", Tag: "latest"},
|
||||
resource: MustParseGR(&apps_v1.Deployment{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-1",
|
||||
Namespace: "xxxx",
|
||||
Annotations: map[string]string{types.KeelInitContainerAnnotation: "true"},
|
||||
Labels: map[string]string{types.KeelPolicyLabel: "all"},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
"this": "that",
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
}),
|
||||
},
|
||||
wantUpdatePlan: &UpdatePlan{
|
||||
Resource: MustParseGR(&apps_v1.Deployment{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-1",
|
||||
Namespace: "xxxx",
|
||||
Annotations: map[string]string{types.KeelInitContainerAnnotation: "true"},
|
||||
Labels: map[string]string{types.KeelPolicyLabel: "all"},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
"this": "that",
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world:latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
}),
|
||||
NewVersion: "latest",
|
||||
CurrentVersion: "latest",
|
||||
},
|
||||
wantShouldUpdateDeployment: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "do not update init container if tracking is disabled (default)",
|
||||
args: args{
|
||||
policy: policy.NewForcePolicy(false),
|
||||
repo: &types.Repository{Name: "gcr.io/v2-namespace/hello-world", Tag: "latest"},
|
||||
resource: MustParseGR(&apps_v1.Deployment{
|
||||
meta_v1.TypeMeta{},
|
||||
meta_v1.ObjectMeta{
|
||||
Name: "dep-1",
|
||||
Namespace: "xxxx",
|
||||
Annotations: map[string]string{},
|
||||
Labels: map[string]string{types.KeelPolicyLabel: "all"},
|
||||
},
|
||||
apps_v1.DeploymentSpec{
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: meta_v1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
"this": "that",
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{
|
||||
{
|
||||
Image: "gcr.io/v2-namespace/hello-world",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps_v1.DeploymentStatus{},
|
||||
}),
|
||||
},
|
||||
wantUpdatePlan: &UpdatePlan{
|
||||
// Resource: &k8s.GenericResource{},
|
||||
Resource: nil,
|
||||
},
|
||||
wantShouldUpdateDeployment: false,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
@ -39,6 +39,9 @@ const KeelMatchPreReleaseAnnotation = "keel.sh/matchPreRelease"
|
|||
// KeelPollScheduleAnnotation - optional variable to setup custom schedule for polling, defaults to @every 10m
|
||||
const KeelPollScheduleAnnotation = "keel.sh/pollSchedule"
|
||||
|
||||
// KeelInitContainerAnnotation - label or annotation to track init containers, defaults to false for backward compatibility
|
||||
const KeelInitContainerAnnotation = "keel.sh/initContainers"
|
||||
|
||||
// KeelPollDefaultSchedule - defaul polling schedule
|
||||
var KeelPollDefaultSchedule = "@every 1m"
|
||||
|
||||
|
|
Loading…
Reference in New Issue