diff --git a/provider/kubernetes/unversioned_updates.go b/provider/kubernetes/unversioned_updates.go index a5506a92..79b7e20a 100644 --- a/provider/kubernetes/unversioned_updates.go +++ b/provider/kubernetes/unversioned_updates.go @@ -2,16 +2,16 @@ package kubernetes import ( "fmt" + "time" - "k8s.io/api/extensions/v1beta1" - + "github.com/keel-hq/keel/internal/k8s" "github.com/keel-hq/keel/types" "github.com/keel-hq/keel/util/image" log "github.com/sirupsen/logrus" ) -func (p *Provider) checkUnversionedDeployment(policy types.PolicyType, repo *types.Repository, deployment v1beta1.Deployment) (updatePlan *UpdatePlan, shouldUpdateDeployment bool, err error) { +func (p *Provider) checkUnversionedDeployment(policy types.PolicyType, repo *types.Repository, resource *k8s.GenericResource) (updatePlan *UpdatePlan, shouldUpdateDeployment bool, err error) { updatePlan = &UpdatePlan{} eventRepoRef, err := image.Parse(repo.Name) @@ -19,22 +19,21 @@ func (p *Provider) checkUnversionedDeployment(policy types.PolicyType, repo *typ return } - labels := deployment.GetLabels() + labels := resource.GetLabels() log.WithFields(log.Fields{ "labels": labels, - "name": deployment.Name, - "namespace": deployment.Namespace, + "name": resource.Name, + "namespace": resource.Namespace, + "kind": resource.Kind(), "policy": policy, - }).Info("provider.kubernetes.checkVersionedDeployment: keel policy found, checking deployment...") + }).Info("provider.kubernetes.checkVersionedDeployment: keel policy found, checking resource...") - annotations := deployment.GetAnnotations() + annotations := resource.GetAnnotations() shouldUpdateDeployment = false - for idx, c := range deployment.Spec.Template.Spec.Containers { - // Remove version if any - // containerImageName := versionreg.ReplaceAllString(c.Image, "") - + // for idx, c := range deployment.Spec.Template.Spec.Containers { + for idx, c := range resource.Containers() { containerImageRef, err := image.Parse(c.Image) if err != nil { log.WithFields(log.Fields{ @@ -45,8 +44,9 @@ func (p *Provider) checkUnversionedDeployment(policy types.PolicyType, repo *typ } log.WithFields(log.Fields{ - "name": deployment.Name, - "namespace": deployment.Namespace, + "name": resource.Name, + "namespace": resource.Namespace, + "kind": resource.Kind(), "parsed_image_name": containerImageRef.Remote(), "target_image_name": repo.Name, "target_tag": repo.Tag, @@ -72,31 +72,35 @@ func (p *Provider) checkUnversionedDeployment(policy types.PolicyType, repo *typ // updating image if containerImageRef.Registry() == image.DefaultRegistryHostname { - c.Image = fmt.Sprintf("%s:%s", containerImageRef.ShortName(), repo.Tag) + // c.Image = fmt.Sprintf("%s:%s", containerImageRef.ShortName(), repo.Tag) + resource.UpdateContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.ShortName(), repo.Tag)) } else { - c.Image = fmt.Sprintf("%s:%s", containerImageRef.Repository(), repo.Tag) + // c.Image = fmt.Sprintf("%s:%s", containerImageRef.Repository(), repo.Tag) + resource.UpdateContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.Repository(), repo.Tag)) } - deployment.Spec.Template.Spec.Containers[idx] = c + // deployment.Spec.Template.Spec.Containers[idx] = c // marking this deployment for update shouldUpdateDeployment = true // updating annotations - annotations := deployment.GetAnnotations() + annotations := resource.GetAnnotations() // updating digest if available - if repo.Digest != "" { + // if repo.Digest != "" { - // annotations[types.KeelDigestAnnotation+"/"+containerImageRef.Remote()] = repo.Digest - } + // annotations[types.KeelDigestAnnotation+"/"+containerImageRef.Remote()] = repo.Digest + // } // adding image for updates - annotations = addImageToPull(annotations, c.Image) + // annotations = addImageToPull(annotations, c.Image) - deployment.SetAnnotations(annotations) + annotations["keel.sh/update-time"] = time.Now().String() + + resource.SetAnnotations(annotations) updatePlan.CurrentVersion = containerImageRef.Tag() updatePlan.NewVersion = repo.Tag - updatePlan.Deployment = deployment + updatePlan.Resource = resource log.WithFields(log.Fields{ "parsed_image": containerImageRef.Remote(), diff --git a/provider/kubernetes/versioned_updates.go b/provider/kubernetes/versioned_updates.go index 1e375f25..e6b57b0a 100644 --- a/provider/kubernetes/versioned_updates.go +++ b/provider/kubernetes/versioned_updates.go @@ -2,14 +2,13 @@ package kubernetes import ( "fmt" + "time" // "k8s.io/api/core/v1" - "k8s.io/api/core/v1" - // "k8s.io/api/extensions/v1beta1" - "k8s.io/api/extensions/v1beta1" + "github.com/keel-hq/keel/internal/k8s" "github.com/keel-hq/keel/types" "github.com/keel-hq/keel/util/image" @@ -19,7 +18,7 @@ import ( ) // func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy types.PolicyType, repo *types.Repository, deployment v1beta1.Deployment) (updated v1beta1.Deployment, shouldUpdateDeployment bool, err error) { -func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy types.PolicyType, repo *types.Repository, deployment v1beta1.Deployment) (updatePlan *UpdatePlan, shouldUpdateDeployment bool, err error) { +func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy types.PolicyType, repo *types.Repository, resource *k8s.GenericResource) (updatePlan *UpdatePlan, shouldUpdateDeployment bool, err error) { updatePlan = &UpdatePlan{} eventRepoRef, err := image.Parse(repo.Name) @@ -27,22 +26,24 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty return } - labels := deployment.GetLabels() + labels := resource.GetLabels() log.WithFields(log.Fields{ "labels": labels, - "name": deployment.Name, - "namespace": deployment.Namespace, + "name": resource.Name, + "namespace": resource.Namespace, + "kind": resource.Kind(), "policy": policy, - }).Info("provider.kubernetes.checkVersionedDeployment: keel policy found, checking deployment...") + }).Info("provider.kubernetes.checkVersionedDeployment: keel policy found, checking resource...") shouldUpdateDeployment = false - for idx, c := range deployment.Spec.Template.Spec.Containers { + // for idx, c := range deployment.Spec.Template.Spec.Containers { + for idx, c := range resource.Containers() { // Remove version if any // containerImageName := versionreg.ReplaceAllString(c.Image, "") - conatinerImageRef, err := image.Parse(c.Image) + containerImageRef, err := image.Parse(c.Image) if err != nil { log.WithFields(log.Fields{ "error": err, @@ -52,18 +53,19 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty } log.WithFields(log.Fields{ - "name": deployment.Name, - "namespace": deployment.Namespace, - "parsed_image_name": conatinerImageRef.Remote(), + "name": resource.Name, + "namespace": resource.Namespace, + "parsed_image_name": containerImageRef.Remote(), + "kind": resource.Kind(), "target_image_name": repo.Name, "target_tag": repo.Tag, "policy": policy, "image": c.Image, }).Info("provider.kubernetes: checking image") - if conatinerImageRef.Repository() != eventRepoRef.Repository() { + if containerImageRef.Repository() != eventRepoRef.Repository() { log.WithFields(log.Fields{ - "parsed_image_name": conatinerImageRef.Remote(), + "parsed_image_name": containerImageRef.Remote(), "target_image_name": repo.Name, }).Info("provider.kubernetes: images do not match, ignoring") continue @@ -71,33 +73,45 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty // if policy is force, don't bother with version checking // same with `latest` images, update them to versioned ones - if policy == types.PolicyTypeForce || conatinerImageRef.Tag() == "latest" { - c = updateContainer(c, conatinerImageRef, newVersion.String()) + if policy == types.PolicyTypeForce || containerImageRef.Tag() == "latest" { + // c = updateContainer(c, conatinerImageRef, newVersion.String()) - deployment.Spec.Template.Spec.Containers[idx] = c + if containerImageRef.Registry() == image.DefaultRegistryHostname { + // container.Image = fmt.Sprintf("%s:%s", ref.ShortName(), version) + + resource.UpdateContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.ShortName(), newVersion.String())) + + } else { + // container.Image = fmt.Sprintf("%s:%s", ref.Repository(), version) + + resource.UpdateContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.Repository(), newVersion.String())) + } + + // deployment.Spec.Template.Spec.Containers[idx] = c // marking this deployment for update shouldUpdateDeployment = true // updating digest if available - annotations := deployment.GetAnnotations() + annotations := resource.GetAnnotations() - if repo.Digest != "" { - // annotations[types.KeelDigestAnnotation+"/"+conatinerImageRef.Remote()] = repo.Digest - } - annotations = addImageToPull(annotations, c.Image) + annotations["keel.sh/update-time"] = time.Now().String() + // if repo.Digest != "" { + // annotations[types.KeelDigestAnnotation+"/"+conatinerImageRef.Remote()] = repo.Digest + // } + // annotations = addImageToPull(annotations, c.Image) - deployment.SetAnnotations(annotations) + resource.SetAnnotations(annotations) log.WithFields(log.Fields{ - "parsed_image": conatinerImageRef.Remote(), + "parsed_image": containerImageRef.Remote(), "raw_image_name": c.Image, "target_image": repo.Name, "target_image_tag": repo.Tag, "policy": policy, }).Info("provider.kubernetes: impacted deployment container found") - updatePlan.CurrentVersion = conatinerImageRef.Tag() + updatePlan.CurrentVersion = containerImageRef.Tag() updatePlan.NewVersion = newVersion.Original - updatePlan.Deployment = deployment + updatePlan.Resource = resource // success, moving to next container continue @@ -108,7 +122,7 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty log.WithFields(log.Fields{ "error": err, "container_image": c.Image, - "container_image_tag": conatinerImageRef.Tag(), + "container_image_tag": containerImageRef.Tag(), "keel_policy": policy, }).Error("provider.kubernetes: failed to get image version, is it tagged as semver?") continue @@ -116,8 +130,8 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty log.WithFields(log.Fields{ "labels": labels, - "name": deployment.Name, - "namespace": deployment.Namespace, + "name": resource.Name, + "namespace": resource.Namespace, "image": c.Image, "current_version": currentVersion.String(), "policy": policy, @@ -136,8 +150,8 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty log.WithFields(log.Fields{ "labels": labels, - "name": deployment.Name, - "namespace": deployment.Namespace, + "name": resource.Name, + "namespace": resource.Namespace, "image": c.Image, "current_version": currentVersion.String(), "new_version": newVersion.String(), @@ -146,25 +160,34 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty }).Info("provider.kubernetes: checked version, deciding whether to update") if shouldUpdateContainer { - c = updateContainer(c, conatinerImageRef, newVersion.String()) - deployment.Spec.Template.Spec.Containers[idx] = c + + // c = updateContainer(c, conatinerImageRef, newVersion.String()) + + if containerImageRef.Registry() == image.DefaultRegistryHostname { + resource.UpdateContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.ShortName(), newVersion.String())) + } else { + resource.UpdateContainer(idx, fmt.Sprintf("%s:%s", containerImageRef.Repository(), newVersion.String())) + } + + // deployment.Spec.Template.Spec.Containers[idx] = c // marking this deployment for update shouldUpdateDeployment = true // updating annotations - annotations := deployment.GetAnnotations() + annotations := resource.GetAnnotations() // updating digest if available - if repo.Digest != "" { - // annotations[types.KeelDigestAnnotation+"/"+conatinerImageRef.Remote()] = repo.Digest - } - deployment.SetAnnotations(annotations) + // if repo.Digest != "" { + // annotations[types.KeelDigestAnnotation+"/"+conatinerImageRef.Remote()] = repo.Digest + // } + annotations["keel.sh/update-time"] = time.Now().String() + resource.SetAnnotations(annotations) updatePlan.CurrentVersion = currentVersion.Original updatePlan.NewVersion = newVersion.Original - updatePlan.Deployment = deployment + updatePlan.Resource = resource log.WithFields(log.Fields{ - "parsed_image": conatinerImageRef.Remote(), + "parsed_image": containerImageRef.Remote(), "raw_image_name": c.Image, "target_image": repo.Name, "target_image_tag": repo.Tag, @@ -176,13 +199,13 @@ func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy ty return updatePlan, shouldUpdateDeployment, nil } -func updateContainer(container v1.Container, ref *image.Reference, version string) v1.Container { - // updating image - if ref.Registry() == image.DefaultRegistryHostname { - container.Image = fmt.Sprintf("%s:%s", ref.ShortName(), version) - } else { - container.Image = fmt.Sprintf("%s:%s", ref.Repository(), version) - } +// func updateContainer(container v1.Container, ref *image.Reference, version string) v1.Container { +// // updating image +// if ref.Registry() == image.DefaultRegistryHostname { +// container.Image = fmt.Sprintf("%s:%s", ref.ShortName(), version) +// } else { +// container.Image = fmt.Sprintf("%s:%s", ref.Repository(), version) +// } - return container -} +// return container +// } diff --git a/secrets/secrets_test.go b/secrets/secrets_test.go index 0ac13033..b6f48caa 100644 --- a/secrets/secrets_test.go +++ b/secrets/secrets_test.go @@ -25,6 +25,8 @@ func mustEncode(data string) string { return base64.StdEncoding.EncodeToString([]byte(data)) } +var secretDockerConfigJSONPayloadWithUsernamePassword = `{"auths":{"https://index.docker.io/v1/":{"username":"login","password":"somepass","email":"email@email.com","auth":"longbase64secret"}}}` + func TestGetSecret(t *testing.T) { imgRef, _ := image.Parse("karolisr/webhook-demo:0.0.11") @@ -92,6 +94,39 @@ func TestGetDockerConfigJSONSecret(t *testing.T) { t.Errorf("unexpected pass: %s", creds.Password) } } +func TestGetDockerConfigJSONSecretUsernmePassword(t *testing.T) { + imgRef, _ := image.Parse("karolisr/webhook-demo:0.0.11") + + impl := &testutil.FakeK8sImplementer{ + AvailableSecret: &v1.Secret{ + Data: map[string][]byte{ + dockerConfigJSONKey: []byte(secretDockerConfigJSONPayloadWithUsernamePassword), + }, + Type: v1.SecretTypeDockerConfigJson, + }, + } + + getter := NewGetter(impl) + + trackedImage := &types.TrackedImage{ + Image: imgRef, + Namespace: "default", + Secrets: []string{"myregistrysecret"}, + } + + creds, err := getter.Get(trackedImage) + if err != nil { + t.Errorf("failed to get creds: %s", err) + } + + if creds.Username != "login" { + t.Errorf("unexpected username: %s", creds.Username) + } + + if creds.Password != "somepass" { + t.Errorf("unexpected pass: %s", creds.Password) + } +} func TestGetSecretNotFound(t *testing.T) { imgRef, _ := image.Parse("karolisr/webhook-demo:0.0.11")