keel/provider/kubernetes/versioned_updates.go

174 lines
5.5 KiB
Go

package kubernetes
import (
"fmt"
"k8s.io/client-go/pkg/api/v1"
"k8s.io/client-go/pkg/apis/extensions/v1beta1"
"github.com/rusenask/keel/types"
"github.com/rusenask/keel/util/image"
"github.com/rusenask/keel/util/version"
log "github.com/Sirupsen/logrus"
)
func (p *Provider) checkVersionedDeployment(newVersion *types.Version, policy types.PolicyType, repo *types.Repository, deployment v1beta1.Deployment) (updated v1beta1.Deployment, shouldUpdateDeployment bool, err error) {
eventRepoRef, err := image.Parse(repo.Name)
if err != nil {
return
}
labels := deployment.GetLabels()
log.WithFields(log.Fields{
"labels": labels,
"name": deployment.Name,
"namespace": deployment.Namespace,
"policy": policy,
}).Info("provider.kubernetes.checkVersionedDeployment: keel policy found, checking deployment...")
shouldUpdateDeployment = false
for idx, c := range deployment.Spec.Template.Spec.Containers {
// Remove version if any
// containerImageName := versionreg.ReplaceAllString(c.Image, "")
conatinerImageRef, 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": deployment.Name,
"namespace": deployment.Namespace,
"parsed_image_name": conatinerImageRef.Remote(),
"target_image_name": repo.Name,
"target_tag": repo.Tag,
"policy": policy,
"image": c.Image,
}).Info("provider.kubernetes: checking image")
if conatinerImageRef.Repository() != eventRepoRef.Repository() {
log.WithFields(log.Fields{
"parsed_image_name": conatinerImageRef.Remote(),
"target_image_name": repo.Name,
}).Info("provider.kubernetes: images do not match, ignoring")
continue
}
// 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())
deployment.Spec.Template.Spec.Containers[idx] = c
// marking this deployment for update
shouldUpdateDeployment = true
// updating digest if available
annotations := deployment.GetAnnotations()
if repo.Digest != "" {
// annotations[types.KeelDigestAnnotation+"/"+conatinerImageRef.Remote()] = repo.Digest
}
annotations = addImageToPull(annotations, c.Image)
deployment.SetAnnotations(annotations)
log.WithFields(log.Fields{
"parsed_image": conatinerImageRef.Remote(),
"raw_image_name": c.Image,
"target_image": repo.Name,
"target_image_tag": repo.Tag,
"policy": policy,
}).Info("provider.kubernetes: impacted deployment container found")
// success, moving to next container
continue
}
currentVersion, err := version.GetVersionFromImageName(c.Image)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"container_image": c.Image,
"container_image_tag": conatinerImageRef.Tag(),
"keel_policy": policy,
}).Error("provider.kubernetes: failed to get image version, is it tagged as semver?")
continue
}
log.WithFields(log.Fields{
"labels": labels,
"name": deployment.Name,
"namespace": deployment.Namespace,
"image": c.Image,
"current_version": currentVersion.String(),
"policy": policy,
}).Info("provider.kubernetes: current image version")
shouldUpdateContainer, err := version.ShouldUpdate(currentVersion, newVersion, policy)
if err != nil {
log.WithFields(log.Fields{
"error": err,
"new_version": newVersion.String(),
"current_version": currentVersion.String(),
"keel_policy": policy,
}).Error("provider.kubernetes: got error while checking whether deployment should be updated")
continue
}
log.WithFields(log.Fields{
"labels": labels,
"name": deployment.Name,
"namespace": deployment.Namespace,
"image": c.Image,
"current_version": currentVersion.String(),
"new_version": newVersion.String(),
"policy": policy,
"should_update": shouldUpdateContainer,
}).Info("provider.kubernetes: checked version, deciding whether to update")
if shouldUpdateContainer {
c = updateContainer(c, conatinerImageRef, newVersion.String())
deployment.Spec.Template.Spec.Containers[idx] = c
// marking this deployment for update
shouldUpdateDeployment = true
// updating annotations
annotations := deployment.GetAnnotations()
// updating digest if available
if repo.Digest != "" {
// annotations[types.KeelDigestAnnotation+"/"+conatinerImageRef.Remote()] = repo.Digest
}
deployment.SetAnnotations(annotations)
log.WithFields(log.Fields{
"parsed_image": conatinerImageRef.Remote(),
"raw_image_name": c.Image,
"target_image": repo.Name,
"target_image_tag": repo.Tag,
"policy": policy,
}).Info("provider.kubernetes: impacted deployment container found")
}
}
return deployment, 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)
}
return container
}