Skip to content

Commit

Permalink
Merge pull request #302 from keel-hq/feature/policy_from_annotations
Browse files Browse the repository at this point in the history
Feature/policy from annotations
  • Loading branch information
rusenask authored Nov 7, 2018
2 parents 1dccced + 27814f2 commit ed97bc1
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 12 deletions.
15 changes: 10 additions & 5 deletions internal/policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,20 @@ func (np *NilPolicy) ShouldUpdate(c, n string) (bool, error) { return false, nil
func (np *NilPolicy) Name() string { return "nil policy" }
func (np *NilPolicy) Type() PolicyType { return PolicyTypeNone }

// GetPolicyFromLabels - gets policy from k8s labels
func GetPolicyFromLabels(labels map[string]string) Policy {
// GetPolicyFromLabelsOrAnnotations - gets policy from k8s labels or annotations
func GetPolicyFromLabelsOrAnnotations(labels map[string]string, annotations map[string]string) Policy {

policyName, ok := getPolicyFromLabels(labels)
policyNameA, ok := getPolicyFromLabels(annotations)
if ok {
return GetPolicy(policyNameA, &Options{MatchTag: getMatchTag(annotations)})
}

policyNameL, ok := getPolicyFromLabels(labels)
if !ok {
return &NilPolicy{}
}

return GetPolicy(policyName, &Options{MatchTag: getMatchTag(labels)})
return GetPolicy(policyNameL, &Options{MatchTag: getMatchTag(labels)})

// switch policyName {
// case "all", "major", "minor", "patch":
Expand Down Expand Up @@ -89,7 +94,7 @@ func GetPolicy(policyName string, options *Options) Policy {
return NewForcePolicy(options.MatchTag)
}

log.Infof("unknown policy '%s'", policyName)
log.Infof("policy.GetPolicy: unknown policy '%s', please check your configuration", policyName)

return &NilPolicy{}
}
Expand Down
36 changes: 36 additions & 0 deletions internal/policy/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,39 @@ func TestGetPolicy(t *testing.T) {
})
}
}

func TestGetPolicyFromLabelsOrAnnotations(t *testing.T) {
type args struct {
labels map[string]string
annotations map[string]string
}
tests := []struct {
name string
args args
want Policy
}{
{
name: "annotations policy",
args: args{
labels: map[string]string{"foo": "bar"},
annotations: map[string]string{types.KeelPolicyLabel: "all"},
},
want: NewSemverPolicy(SemverPolicyTypeAll),
},
{
name: "annotations overides labels",
args: args{
labels: map[string]string{types.KeelPolicyLabel: "patch"},
annotations: map[string]string{types.KeelPolicyLabel: "all"},
},
want: NewSemverPolicy(SemverPolicyTypeAll),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetPolicyFromLabelsOrAnnotations(tt.args.labels, tt.args.annotations); !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetPolicyFromLabelsOrAnnotations() = %v, want %v", got, tt.want)
}
})
}
}
2 changes: 1 addition & 1 deletion provider/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (p *Provider) TrackedImages() ([]*types.TrackedImage, error) {
"error": err,
"release": release.Name,
"namespace": release.Namespace,
}).Error("provider.helm: failed to get config for release")
}).Debug("provider.helm: failed to get config for release")
continue
}

Expand Down
11 changes: 6 additions & 5 deletions provider/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,14 @@ func (p *Provider) TrackedImages() ([]*types.TrackedImage, error) {

for _, gr := range p.cache.Values() {
labels := gr.GetLabels()
annotations := gr.GetAnnotations()

// ignoring unlabelled deployments
plc := policy.GetPolicyFromLabels(labels)
plc := policy.GetPolicyFromLabelsOrAnnotations(labels, annotations)
if plc.Type() == policy.PolicyTypeNone {
continue
}

annotations := gr.GetAnnotations()
schedule, ok := annotations[types.KeelPollScheduleAnnotation]
if ok {
_, err := cron.Parse(schedule)
Expand All @@ -156,7 +156,7 @@ func (p *Provider) TrackedImages() ([]*types.TrackedImage, error) {
}

// trigger type, we only care for "poll" type triggers
trigger := policies.GetTriggerPolicy(labels)
trigger := policies.GetTriggerPolicy(labels, annotations)
secrets := gr.GetImagePullSecrets()
images := gr.GetImages()
for _, img := range images {
Expand Down Expand Up @@ -343,10 +343,11 @@ func (p *Provider) createUpdatePlans(repo *types.Repository) ([]*UpdatePlan, err
for _, resource := range p.cache.Values() {

labels := resource.GetLabels()
annotations := resource.GetAnnotations()

plc := policy.GetPolicyFromLabels(labels)
plc := policy.GetPolicyFromLabelsOrAnnotations(labels, annotations)
if plc.Type() == policy.PolicyTypeNone {
log.Debugf("no policy defined, skipping: %s, labels: %s", resource.Identifier, labels)
log.Debugf("no policy defined, skipping: %s, labels: %s, annotations: %s", resource.Identifier, labels, annotations)
continue
}

Expand Down
96 changes: 96 additions & 0 deletions provider/kubernetes/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,102 @@ func TestGetImpacted(t *testing.T) {
t.Errorf("couldn't find expected deployment in impacted deployment list")
}

}
func TestGetImpactedPolicyAnnotations(t *testing.T) {
fp := &fakeImplementer{}
fp.namespaces = &v1.NamespaceList{
Items: []v1.Namespace{
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.KeelPolicyLabel: "all"},
Labels: map[string]string{"foo": "all"},
},
apps_v1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{
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",
Labels: map[string]string{"whatever": "all"},
},
apps_v1.DeploymentSpec{
Template: v1.PodTemplateSpec{
Spec: v1.PodSpec{
Containers: []v1.Container{
v1.Container{
Image: "gcr.io/v2-namespace/hello-world:1.1.1",
},
},
},
},
},
apps_v1.DeploymentStatus{},
},
}

grs := MustParseGRS(deps)
grc := &k8s.GenericResourceCache{}
grc.Add(grs...)

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.Containers() {

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 TestPrereleaseGetImpactedA(t *testing.T) {
// test scenario when we have two deployments, one with pre-release tag
Expand Down
10 changes: 9 additions & 1 deletion util/policies/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ import (

// GetTriggerPolicy - checks for trigger label, if not set - returns
// default trigger type
func GetTriggerPolicy(labels map[string]string) types.TriggerType {
func GetTriggerPolicy(labels map[string]string, annotations map[string]string) types.TriggerType {

triggerAnn, ok := annotations[types.KeelTriggerLabel]
if ok {
return types.ParseTrigger(triggerAnn)
}

// checking labels
trigger, ok := labels[types.KeelTriggerLabel]
if ok {
return types.ParseTrigger(trigger)
}

return types.TriggerTypeDefault
}

0 comments on commit ed97bc1

Please sign in to comment.