using cred helper from watcher
parent
286508d60d
commit
52c5101646
|
@ -40,6 +40,7 @@ import (
|
|||
|
||||
// credentials helpers
|
||||
_ "github.com/keel-hq/keel/extension/credentialshelper/aws"
|
||||
secretsCredentialsHelper "github.com/keel-hq/keel/extension/credentialshelper/secrets"
|
||||
|
||||
// bots
|
||||
_ "github.com/keel-hq/keel/bot/hipchat"
|
||||
|
@ -171,8 +172,14 @@ func main() {
|
|||
|
||||
// setting up providers
|
||||
providers := setupProviders(implementer, sender, approvalsManager, &t.GenericResourceCache)
|
||||
|
||||
// registering secrets based credentials helper
|
||||
secretsGetter := secrets.NewGetter(implementer)
|
||||
teardownTriggers := setupTriggers(ctx, providers, secretsGetter, approvalsManager)
|
||||
ch := secretsCredentialsHelper.New(secretsGetter)
|
||||
credentialshelper.RegisterCredentialsHelper("secrets", ch)
|
||||
|
||||
// trigger setup
|
||||
teardownTriggers := setupTriggers(ctx, providers, approvalsManager)
|
||||
|
||||
bot.Run(implementer, approvalsManager)
|
||||
|
||||
|
@ -235,7 +242,7 @@ func setupProviders(k8sImplementer kubernetes.Implementer, sender notification.S
|
|||
|
||||
// setupTriggers - setting up triggers. New triggers should be added to this function. Each trigger
|
||||
// should go through all providers (or not if there is a reason) and submit events)
|
||||
func setupTriggers(ctx context.Context, providers provider.Providers, secretsGetter secrets.Getter, approvalsManager approvals.Manager) (teardown func()) {
|
||||
func setupTriggers(ctx context.Context, providers provider.Providers, approvalsManager approvals.Manager) (teardown func()) {
|
||||
|
||||
// setting up generic http webhook server
|
||||
whs := http.NewTriggerServer(&http.Opts{
|
||||
|
@ -273,7 +280,7 @@ func setupTriggers(ctx context.Context, providers provider.Providers, secretsGet
|
|||
|
||||
registryClient := registry.New()
|
||||
watcher := poll.NewRepositoryWatcher(providers, registryClient)
|
||||
pollManager := poll.NewPollManager(providers, watcher, secretsGetter, credentialshelper.New())
|
||||
pollManager := poll.NewPollManager(providers, watcher)
|
||||
|
||||
// start poll manager, will finish with ctx
|
||||
go watcher.Start(ctx)
|
||||
|
|
|
@ -5,9 +5,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/keel-hq/keel/extension/credentialshelper"
|
||||
"github.com/keel-hq/keel/provider"
|
||||
"github.com/keel-hq/keel/secrets"
|
||||
"github.com/keel-hq/keel/types"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
@ -31,10 +29,6 @@ func init() {
|
|||
type DefaultManager struct {
|
||||
providers provider.Providers
|
||||
|
||||
secretsGetter secrets.Getter
|
||||
|
||||
credentialsHelper credentialshelper.CredentialsHelper
|
||||
|
||||
// repository watcher
|
||||
watcher Watcher
|
||||
|
||||
|
@ -48,14 +42,12 @@ type DefaultManager struct {
|
|||
}
|
||||
|
||||
// NewPollManager - new default poller
|
||||
func NewPollManager(providers provider.Providers, watcher Watcher, secretsGetter secrets.Getter, credentialsHelper credentialshelper.CredentialsHelper) *DefaultManager {
|
||||
func NewPollManager(providers provider.Providers, watcher Watcher) *DefaultManager {
|
||||
return &DefaultManager{
|
||||
providers: providers,
|
||||
secretsGetter: secretsGetter,
|
||||
credentialsHelper: credentialsHelper,
|
||||
watcher: watcher,
|
||||
mu: &sync.Mutex{},
|
||||
scanTick: 1,
|
||||
providers: providers,
|
||||
watcher: watcher,
|
||||
mu: &sync.Mutex{},
|
||||
scanTick: 1,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,59 +85,25 @@ func (s *DefaultManager) Start(ctx context.Context) error {
|
|||
}
|
||||
|
||||
func (s *DefaultManager) scan(ctx context.Context) error {
|
||||
log.Info("performing scan")
|
||||
log.Debug("trigger.poll.manager: performing scan")
|
||||
trackedImages, err := s.providers.TrackedImages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var tracked float64
|
||||
|
||||
for _, trackedImage := range trackedImages {
|
||||
if trackedImage.Trigger != types.TriggerTypePoll {
|
||||
continue
|
||||
}
|
||||
|
||||
tracked++
|
||||
|
||||
var imageCreds *types.Credentials
|
||||
|
||||
// anonymous credentials
|
||||
creds := &types.Credentials{}
|
||||
imageCreds, err = s.secretsGetter.Get(trackedImage)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"secrets": trackedImage.Secrets,
|
||||
"image": trackedImage.Image.Remote(),
|
||||
}).Error("trigger.poll.manager: failed to get authentication credentials")
|
||||
} else {
|
||||
creds = imageCreds
|
||||
}
|
||||
|
||||
// TODO: refactor to either recreate it every 10 hours (12 hours expiration) or better to retrieve creds
|
||||
// just before quering the registry
|
||||
if imageCreds.Username == "" && imageCreds.Password == "" {
|
||||
registryCreds, err := s.credentialsHelper.GetCredentials(trackedImage.Image.Registry())
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"registry": trackedImage.Image.Registry(),
|
||||
"image": trackedImage.Image.Remote(),
|
||||
}).Error("trigger.poll.manager: failed to get registry credentials")
|
||||
} else {
|
||||
creds = registryCreds
|
||||
}
|
||||
}
|
||||
|
||||
err = s.watcher.Watch(trackedImage.Image.Remote(), trackedImage.PollSchedule, creds.Username, creds.Password)
|
||||
err = s.watcher.Watch(trackedImage, trackedImage.PollSchedule)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"schedule": trackedImage.PollSchedule,
|
||||
"image": trackedImage.Image.Remote(),
|
||||
}).Error("trigger.poll.manager: failed to start watching repository")
|
||||
// continue processing other images
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/keel-hq/keel/util/codecs"
|
||||
"github.com/keel-hq/keel/util/image"
|
||||
|
||||
"github.com/keel-hq/keel/extension/credentialshelper"
|
||||
// "github.com/keel-hq/keel/extension/credentialshelper"
|
||||
_ "github.com/keel-hq/keel/extension/credentialshelper/aws"
|
||||
|
||||
"testing"
|
||||
|
@ -59,7 +59,7 @@ func TestCheckDeployment(t *testing.T) {
|
|||
|
||||
watcher := NewRepositoryWatcher(providers, frc)
|
||||
|
||||
pm := NewPollManager(providers, watcher, &FakeSecretsGetter{}, credentialshelper.New())
|
||||
pm := NewPollManager(providers, watcher)
|
||||
|
||||
imageA := "gcr.io/v2-namespace/hello-world:1.1.1"
|
||||
imageB := "gcr.io/v2-namespace/greetings-world:1.1.1"
|
||||
|
@ -80,11 +80,11 @@ func TestCheckDeployment(t *testing.T) {
|
|||
if watcher.watched[keyA].schedule != types.KeelPollDefaultSchedule {
|
||||
t.Errorf("unexpected schedule: %s", watcher.watched[keyA].schedule)
|
||||
}
|
||||
if watcher.watched[keyA].imageRef.Remote() != ref.Remote() {
|
||||
t.Errorf("unexpected remote remote: %s", watcher.watched[keyA].imageRef.Remote())
|
||||
if watcher.watched[keyA].trackedImage.Image.Remote() != ref.Remote() {
|
||||
t.Errorf("unexpected remote remote: %s", watcher.watched[keyA].trackedImage.Image.Remote())
|
||||
}
|
||||
if watcher.watched[keyA].imageRef.Tag() != ref.Tag() {
|
||||
t.Errorf("unexpected tag: %s", watcher.watched[keyA].imageRef.Tag())
|
||||
if watcher.watched[keyA].trackedImage.Image.Tag() != ref.Tag() {
|
||||
t.Errorf("unexpected tag: %s", watcher.watched[keyA].trackedImage.Image.Tag())
|
||||
}
|
||||
|
||||
refB, _ := image.Parse(imageB)
|
||||
|
@ -95,11 +95,11 @@ func TestCheckDeployment(t *testing.T) {
|
|||
if watcher.watched[keyB].schedule != types.KeelPollDefaultSchedule {
|
||||
t.Errorf("unexpected schedule: %s", watcher.watched[keyB].schedule)
|
||||
}
|
||||
if watcher.watched[keyB].imageRef.Remote() != refB.Remote() {
|
||||
t.Errorf("unexpected remote remote: %s", watcher.watched[keyB].imageRef.Remote())
|
||||
if watcher.watched[keyB].trackedImage.Image.Remote() != refB.Remote() {
|
||||
t.Errorf("unexpected remote remote: %s", watcher.watched[keyB].trackedImage.Image.Remote())
|
||||
}
|
||||
if watcher.watched[keyB].imageRef.Tag() != refB.Tag() {
|
||||
t.Errorf("unexpected tag: %s", watcher.watched[keyB].imageRef.Tag())
|
||||
if watcher.watched[keyB].trackedImage.Image.Tag() != refB.Tag() {
|
||||
t.Errorf("unexpected tag: %s", watcher.watched[keyB].trackedImage.Image.Tag())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ func TestCheckECRDeployment(t *testing.T) {
|
|||
|
||||
watcher := NewRepositoryWatcher(providers, rc)
|
||||
|
||||
pm := NewPollManager(providers, watcher, &FakeSecretsGetter{}, credentialshelper.New())
|
||||
pm := NewPollManager(providers, watcher)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
@ -157,10 +157,10 @@ func TestCheckECRDeployment(t *testing.T) {
|
|||
if watcher.watched[keyA].schedule != types.KeelPollDefaultSchedule {
|
||||
t.Errorf("unexpected schedule: %s", watcher.watched[keyA].schedule)
|
||||
}
|
||||
if watcher.watched[keyA].imageRef.Remote() != imgA.Remote() {
|
||||
t.Errorf("unexpected remote remote: %s", watcher.watched[keyA].imageRef.Remote())
|
||||
if watcher.watched[keyA].trackedImage.Image.Remote() != imgA.Remote() {
|
||||
t.Errorf("unexpected remote remote: %s", watcher.watched[keyA].trackedImage.Image.Remote())
|
||||
}
|
||||
if watcher.watched[keyA].imageRef.Tag() != imgA.Tag() {
|
||||
t.Errorf("unexpected tag: %s", watcher.watched[keyA].imageRef.Tag())
|
||||
if watcher.watched[keyA].trackedImage.Image.Tag() != imgA.Tag() {
|
||||
t.Errorf("unexpected tag: %s", watcher.watched[keyA].trackedImage.Image.Tag())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/keel-hq/keel/extension/credentialshelper"
|
||||
"github.com/keel-hq/keel/provider"
|
||||
"github.com/keel-hq/keel/registry"
|
||||
"github.com/keel-hq/keel/types"
|
||||
|
@ -30,17 +31,15 @@ func init() {
|
|||
|
||||
// Watcher - generic watcher interface
|
||||
type Watcher interface {
|
||||
Watch(imageName, registryUsername, registryPassword, schedule string) error
|
||||
Watch(image *types.TrackedImage, schedule string) error
|
||||
Unwatch(image string) error
|
||||
}
|
||||
|
||||
type watchDetails struct {
|
||||
imageRef *image.Reference
|
||||
registryUsername string // "" for anonymous
|
||||
registryPassword string // "" for anonymous
|
||||
digest string // image digest
|
||||
latest string // latest tag
|
||||
schedule string
|
||||
trackedImage *types.TrackedImage
|
||||
digest string // image digest
|
||||
latest string // latest tag
|
||||
schedule string
|
||||
}
|
||||
|
||||
// RepositoryWatcher - repository watcher cron
|
||||
|
@ -115,7 +114,7 @@ func (w *RepositoryWatcher) Unwatch(imageName string) error {
|
|||
|
||||
// Watch - starts watching repository for changes, if it's already watching - ignores,
|
||||
// if details changed - updates details
|
||||
func (w *RepositoryWatcher) Watch(imageName, schedule, registryUsername, registryPassword string) error {
|
||||
func (w *RepositoryWatcher) Watch(image *types.TrackedImage, schedule string) error {
|
||||
|
||||
if schedule == "" {
|
||||
return fmt.Errorf("cron schedule cannot be empty")
|
||||
|
@ -125,32 +124,23 @@ func (w *RepositoryWatcher) Watch(imageName, schedule, registryUsername, registr
|
|||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image": imageName,
|
||||
"image": image.String(),
|
||||
"schedule": schedule,
|
||||
}).Error("trigger.poll.RepositoryWatcher.addJob: invalid cron schedule")
|
||||
return fmt.Errorf("invalid cron schedule: %s", err)
|
||||
}
|
||||
|
||||
imageRef, err := image.Parse(imageName)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image_name": imageName,
|
||||
}).Error("trigger.poll.RepositoryWatcher.Watch: failed to parse image")
|
||||
return err
|
||||
}
|
||||
|
||||
key := getImageIdentifier(imageRef)
|
||||
key := getImageIdentifier(image.Image)
|
||||
|
||||
// checking whether it's already being watched
|
||||
details, ok := w.watched[key]
|
||||
if !ok {
|
||||
err = w.addJob(imageRef, registryUsername, registryPassword, schedule)
|
||||
// err = w.addJob(imageRef, registryUsername, registryPassword, schedule)
|
||||
err = w.addJob(image, schedule)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image_name": imageName,
|
||||
"registry_username": registryUsername,
|
||||
"error": err,
|
||||
"image": image.String(),
|
||||
}).Error("trigger.poll.RepositoryWatcher.Watch: failed to add image watch job")
|
||||
|
||||
}
|
||||
|
@ -162,53 +152,38 @@ func (w *RepositoryWatcher) Watch(imageName, schedule, registryUsername, registr
|
|||
w.cron.UpdateJob(key, schedule)
|
||||
}
|
||||
|
||||
// checking auth details, if changed - need to update
|
||||
if details.registryPassword != registryPassword || details.registryUsername != registryUsername {
|
||||
// recreating job
|
||||
w.cron.DeleteJob(key)
|
||||
err = w.addJob(imageRef, registryUsername, registryPassword, schedule)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image_name": imageName,
|
||||
"registry_username": registryUsername,
|
||||
}).Error("trigger.poll.RepositoryWatcher.Watch: failed to add image watch job")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// nothing to do
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *RepositoryWatcher) addJob(ref *image.Reference, registryUsername, registryPassword, schedule string) error {
|
||||
func (w *RepositoryWatcher) addJob(ti *types.TrackedImage, schedule string) error {
|
||||
// getting initial digest
|
||||
reg := ref.Scheme() + "://" + ref.Registry()
|
||||
reg := ti.Image.Scheme() + "://" + ti.Image.Registry()
|
||||
|
||||
creds := credentialshelper.GetCredentials(ti)
|
||||
|
||||
digest, err := w.registryClient.Digest(registry.Opts{
|
||||
Registry: reg,
|
||||
Name: ref.ShortName(),
|
||||
Tag: ref.Tag(),
|
||||
Username: registryUsername,
|
||||
Password: registryPassword,
|
||||
Name: ti.Image.ShortName(),
|
||||
Tag: ti.Image.Tag(),
|
||||
Username: creds.Username,
|
||||
Password: creds.Password,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image": ref.Remote(),
|
||||
"image": ti.Image.String(),
|
||||
}).Error("trigger.poll.RepositoryWatcher.addJob: failed to get image digest")
|
||||
return err
|
||||
}
|
||||
|
||||
key := getImageIdentifier(ref)
|
||||
key := getImageIdentifier(ti.Image)
|
||||
details := &watchDetails{
|
||||
imageRef: ref,
|
||||
digest: digest, // current image digest
|
||||
latest: ref.Tag(),
|
||||
registryUsername: registryUsername,
|
||||
registryPassword: registryPassword,
|
||||
schedule: schedule,
|
||||
trackedImage: ti,
|
||||
digest: digest, // current image digest
|
||||
latest: ti.Image.Tag(),
|
||||
schedule: schedule,
|
||||
}
|
||||
|
||||
// adding job to internal map
|
||||
|
@ -217,13 +192,13 @@ func (w *RepositoryWatcher) addJob(ref *image.Reference, registryUsername, regis
|
|||
// checking tag type, for versioned (semver) tags we setup a watch all tags job
|
||||
// and for non-semver types we create a single tag watcher which
|
||||
// checks digest
|
||||
_, err = version.GetVersion(ref.Tag())
|
||||
_, err = version.GetVersion(ti.Image.Tag())
|
||||
if err != nil {
|
||||
// adding new job
|
||||
job := NewWatchTagJob(w.providers, w.registryClient, details)
|
||||
log.WithFields(log.Fields{
|
||||
"job_name": key,
|
||||
"image": ref.Remote(),
|
||||
"image": ti.Image.String(),
|
||||
"digest": digest,
|
||||
"schedule": schedule,
|
||||
}).Info("trigger.poll.RepositoryWatcher: new watch tag digest job added")
|
||||
|
@ -234,7 +209,7 @@ func (w *RepositoryWatcher) addJob(ref *image.Reference, registryUsername, regis
|
|||
job := NewWatchRepositoryTagsJob(w.providers, w.registryClient, details)
|
||||
log.WithFields(log.Fields{
|
||||
"job_name": key,
|
||||
"image": ref.Remote(),
|
||||
"image": ti.Image.String(),
|
||||
"digest": digest,
|
||||
"schedule": schedule,
|
||||
}).Info("trigger.poll.RepositoryWatcher: new watch repository tags job added")
|
||||
|
@ -261,21 +236,22 @@ func NewWatchTagJob(providers provider.Providers, registryClient registry.Client
|
|||
|
||||
// Run - main function to check schedule
|
||||
func (j *WatchTagJob) Run() {
|
||||
reg := j.details.imageRef.Scheme() + "://" + j.details.imageRef.Registry()
|
||||
creds := credentialshelper.GetCredentials(j.details.trackedImage)
|
||||
reg := j.details.trackedImage.Image.Scheme() + "://" + j.details.trackedImage.Image.Registry()
|
||||
currentDigest, err := j.registryClient.Digest(registry.Opts{
|
||||
Registry: reg,
|
||||
Name: j.details.imageRef.ShortName(),
|
||||
Tag: j.details.imageRef.Tag(),
|
||||
Username: j.details.registryUsername,
|
||||
Password: j.details.registryPassword,
|
||||
Name: j.details.trackedImage.Image.ShortName(),
|
||||
Tag: j.details.trackedImage.Image.Tag(),
|
||||
Username: creds.Username,
|
||||
Password: creds.Password,
|
||||
})
|
||||
|
||||
registriesScannedCounter.With(prometheus.Labels{"registry": j.details.imageRef.Registry(), "image": j.details.imageRef.Name()}).Inc()
|
||||
registriesScannedCounter.With(prometheus.Labels{"registry": j.details.trackedImage.Image.Registry(), "image": j.details.trackedImage.Image.Name()}).Inc()
|
||||
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image": j.details.imageRef.Remote(),
|
||||
"image": j.details.trackedImage.Image.String(),
|
||||
}).Error("trigger.poll.WatchTagJob: failed to check digest")
|
||||
return
|
||||
}
|
||||
|
@ -283,7 +259,7 @@ func (j *WatchTagJob) Run() {
|
|||
log.WithFields(log.Fields{
|
||||
"current_digest": j.details.digest,
|
||||
"new_digest": currentDigest,
|
||||
"image_name": j.details.imageRef.Remote(),
|
||||
"image": j.details.trackedImage.Image.String(),
|
||||
}).Debug("trigger.poll.WatchTagJob: checking digest")
|
||||
|
||||
// checking whether image digest has changed
|
||||
|
@ -293,14 +269,14 @@ func (j *WatchTagJob) Run() {
|
|||
|
||||
event := types.Event{
|
||||
Repository: types.Repository{
|
||||
Name: j.details.imageRef.Repository(),
|
||||
Tag: j.details.imageRef.Tag(),
|
||||
Name: j.details.trackedImage.Image.Repository(),
|
||||
Tag: j.details.trackedImage.Image.Tag(),
|
||||
Digest: currentDigest,
|
||||
},
|
||||
TriggerName: types.TriggerTypePoll.String(),
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"repository": j.details.imageRef.Repository(),
|
||||
"image": j.details.trackedImage.Image.String(),
|
||||
"new_digest": currentDigest,
|
||||
}).Info("trigger.poll.WatchTagJob: digest change detected, submiting event to providers")
|
||||
|
||||
|
@ -327,32 +303,35 @@ func NewWatchRepositoryTagsJob(providers provider.Providers, registryClient regi
|
|||
|
||||
// Run - main function to check schedule
|
||||
func (j *WatchRepositoryTagsJob) Run() {
|
||||
reg := j.details.imageRef.Scheme() + "://" + j.details.imageRef.Registry()
|
||||
|
||||
creds := credentialshelper.GetCredentials(j.details.trackedImage)
|
||||
|
||||
// reg := j.details.imageRef.Scheme() + "://" + j.details.imageRef.Registry()
|
||||
reg := j.details.trackedImage.Image.Scheme() + "://" + j.details.trackedImage.Image.Registry()
|
||||
if j.details.latest == "" {
|
||||
j.details.latest = j.details.imageRef.Tag()
|
||||
j.details.latest = j.details.trackedImage.Image.Tag()
|
||||
}
|
||||
|
||||
repository, err := j.registryClient.Get(registry.Opts{
|
||||
Registry: reg,
|
||||
Name: j.details.imageRef.ShortName(),
|
||||
Name: j.details.trackedImage.Image.ShortName(),
|
||||
Tag: j.details.latest,
|
||||
Username: j.details.registryUsername,
|
||||
Password: j.details.registryPassword,
|
||||
Username: creds.Username,
|
||||
Password: creds.Password,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"image": j.details.imageRef.Remote(),
|
||||
"image": j.details.trackedImage.Image.String(),
|
||||
}).Error("trigger.poll.WatchRepositoryTagsJob: failed to get repository")
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
"current_tag": j.details.imageRef.Tag(),
|
||||
"current_tag": j.details.trackedImage.Image.Tag(),
|
||||
"repository_tags": repository.Tags,
|
||||
"image_name": j.details.imageRef.Remote(),
|
||||
"image_name": j.details.trackedImage.Image.Remote(),
|
||||
}).Debug("trigger.poll.WatchRepositoryTagsJob: checking tags")
|
||||
|
||||
latestVersion, newAvailable, err := version.NewAvailable(j.details.latest, repository.Tags)
|
||||
|
@ -360,7 +339,8 @@ func (j *WatchRepositoryTagsJob) Run() {
|
|||
log.WithFields(log.Fields{
|
||||
"error": err,
|
||||
"repository_tags": repository.Tags,
|
||||
"image": j.details.imageRef.Remote(),
|
||||
// "image": j.details.imageRef.Remote(),
|
||||
"image": j.details.trackedImage.Image.String(),
|
||||
}).Error("trigger.poll.WatchRepositoryTagsJob: failed to get latest version from tags")
|
||||
return
|
||||
}
|
||||
|
@ -372,13 +352,13 @@ func (j *WatchRepositoryTagsJob) Run() {
|
|||
j.details.latest = latestVersion
|
||||
event := types.Event{
|
||||
Repository: types.Repository{
|
||||
Name: j.details.imageRef.Repository(),
|
||||
Name: j.details.trackedImage.Image.Repository(),
|
||||
Tag: latestVersion,
|
||||
},
|
||||
TriggerName: types.TriggerTypePoll.String(),
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
"repository": j.details.imageRef.Repository(),
|
||||
"repository": j.details.trackedImage.Image.Repository(),
|
||||
"new_tag": latestVersion,
|
||||
}).Info("trigger.poll.WatchRepositoryTagsJob: submiting event to providers")
|
||||
j.providers.Submit(event)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"github.com/keel-hq/keel/approvals"
|
||||
"github.com/keel-hq/keel/cache/memory"
|
||||
"github.com/keel-hq/keel/extension/credentialshelper"
|
||||
"github.com/keel-hq/keel/provider"
|
||||
"github.com/keel-hq/keel/registry"
|
||||
"github.com/keel-hq/keel/types"
|
||||
|
@ -13,6 +14,16 @@ import (
|
|||
"github.com/keel-hq/keel/util/image"
|
||||
)
|
||||
|
||||
func mustParse(img string) *types.TrackedImage {
|
||||
ref, err := image.Parse(img)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &types.TrackedImage{
|
||||
Image: ref,
|
||||
}
|
||||
}
|
||||
|
||||
// ======== fake registry client for testing =======
|
||||
type fakeRegistryClient struct {
|
||||
opts registry.Opts // opts set if anything called Digest(opts Opts)
|
||||
|
@ -23,6 +34,7 @@ type fakeRegistryClient struct {
|
|||
}
|
||||
|
||||
func (c *fakeRegistryClient) Get(opts registry.Opts) (*registry.Repository, error) {
|
||||
c.opts = opts
|
||||
return ®istry.Repository{
|
||||
Name: opts.Name,
|
||||
Tags: c.tagsToReturn,
|
||||
|
@ -30,6 +42,7 @@ func (c *fakeRegistryClient) Get(opts registry.Opts) (*registry.Repository, erro
|
|||
}
|
||||
|
||||
func (c *fakeRegistryClient) Digest(opts registry.Opts) (digest string, err error) {
|
||||
c.opts = opts
|
||||
return c.digestToReturn, nil
|
||||
}
|
||||
|
||||
|
@ -68,8 +81,10 @@ func TestWatchTagJob(t *testing.T) {
|
|||
reference, _ := image.Parse("foo/bar:1.1")
|
||||
|
||||
details := &watchDetails{
|
||||
imageRef: reference,
|
||||
digest: "sha256:123123123",
|
||||
trackedImage: &types.TrackedImage{
|
||||
Image: reference,
|
||||
},
|
||||
digest: "sha256:123123123",
|
||||
}
|
||||
|
||||
job := NewWatchTagJob(providers, frc, details)
|
||||
|
@ -113,8 +128,10 @@ func TestWatchTagJobLatest(t *testing.T) {
|
|||
reference, _ := image.Parse("foo/bar:latest")
|
||||
|
||||
details := &watchDetails{
|
||||
imageRef: reference,
|
||||
digest: "sha256:123123123",
|
||||
trackedImage: &types.TrackedImage{
|
||||
Image: reference,
|
||||
},
|
||||
digest: "sha256:123123123",
|
||||
}
|
||||
|
||||
job := NewWatchTagJob(providers, frc, details)
|
||||
|
@ -158,7 +175,9 @@ func TestWatchAllTagsJob(t *testing.T) {
|
|||
reference, _ := image.Parse("foo/bar:1.1.0")
|
||||
|
||||
details := &watchDetails{
|
||||
imageRef: reference,
|
||||
trackedImage: &types.TrackedImage{
|
||||
Image: reference,
|
||||
},
|
||||
}
|
||||
|
||||
job := NewWatchRepositoryTagsJob(providers, frc, details)
|
||||
|
@ -192,7 +211,9 @@ func TestWatchAllTagsJobCurrentLatest(t *testing.T) {
|
|||
reference, _ := image.Parse("foo/bar:latest")
|
||||
|
||||
details := &watchDetails{
|
||||
imageRef: reference,
|
||||
trackedImage: &types.TrackedImage{
|
||||
Image: reference,
|
||||
},
|
||||
}
|
||||
|
||||
job := NewWatchRepositoryTagsJob(providers, frc, details)
|
||||
|
@ -257,10 +278,10 @@ func TestWatchMultipleTags(t *testing.T) {
|
|||
|
||||
watcher := NewRepositoryWatcher(providers, frc)
|
||||
|
||||
watcher.Watch("gcr.io/v2-namespace/hello-world:1.1.1", "@every 10m", "", "")
|
||||
watcher.Watch("gcr.io/v2-namespace/greetings-world:1.1.1", "@every 10m", "", "")
|
||||
watcher.Watch("gcr.io/v2-namespace/greetings-world:alpha", "@every 10m", "", "")
|
||||
watcher.Watch("gcr.io/v2-namespace/greetings-world:master", "@every 10m", "", "")
|
||||
watcher.Watch(mustParse("gcr.io/v2-namespace/hello-world:1.1.1"), "@every 10m")
|
||||
watcher.Watch(mustParse("gcr.io/v2-namespace/greetings-world:1.1.1"), "@every 10m")
|
||||
watcher.Watch(mustParse("gcr.io/v2-namespace/greetings-world:alpha"), "@every 10m")
|
||||
watcher.Watch(mustParse("gcr.io/v2-namespace/greetings-world:master"), "@every 10m")
|
||||
|
||||
if len(watcher.watched) != 4 {
|
||||
t.Errorf("expected to find watching 4 entries, found: %d", len(watcher.watched))
|
||||
|
@ -287,3 +308,64 @@ func TestWatchMultipleTags(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeCredentialsHelper struct {
|
||||
|
||||
// set by the caller
|
||||
getImageRequest *types.TrackedImage
|
||||
|
||||
// credentials to return
|
||||
creds *types.Credentials
|
||||
}
|
||||
|
||||
func (fch *fakeCredentialsHelper) GetCredentials(image *types.TrackedImage) (*types.Credentials, error) {
|
||||
fch.getImageRequest = image
|
||||
return fch.creds, nil
|
||||
}
|
||||
|
||||
func (fch *fakeCredentialsHelper) IsEnabled() bool { return true }
|
||||
|
||||
func TestWatchTagJobCheckCredentials(t *testing.T) {
|
||||
|
||||
fakeHelper := &fakeCredentialsHelper{
|
||||
creds: &types.Credentials{
|
||||
Username: "user-xx",
|
||||
Password: "pass-xx",
|
||||
},
|
||||
}
|
||||
|
||||
credentialshelper.RegisterCredentialsHelper("fake", fakeHelper)
|
||||
defer credentialshelper.UnregisterCredentialsHelper("fake")
|
||||
|
||||
fp := &fakeProvider{}
|
||||
mem := memory.NewMemoryCache(100*time.Millisecond, 100*time.Millisecond, 10*time.Millisecond)
|
||||
am := approvals.New(mem, codecs.DefaultSerializer())
|
||||
providers := provider.New([]provider.Provider{fp}, am)
|
||||
|
||||
frc := &fakeRegistryClient{
|
||||
digestToReturn: "sha256:0604af35299dd37ff23937d115d103532948b568a9dd8197d14c256a8ab8b0bb",
|
||||
}
|
||||
|
||||
reference, _ := image.Parse("foo/bar:1.1")
|
||||
|
||||
details := &watchDetails{
|
||||
trackedImage: &types.TrackedImage{
|
||||
Image: reference,
|
||||
},
|
||||
digest: "sha256:123123123",
|
||||
}
|
||||
|
||||
job := NewWatchTagJob(providers, frc, details)
|
||||
|
||||
job.Run()
|
||||
|
||||
// checking whether new job was submitted
|
||||
|
||||
if frc.opts.Password != "pass-xx" {
|
||||
t.Errorf("unexpected password for registry: %s", frc.opts.Password)
|
||||
}
|
||||
|
||||
if frc.opts.Username != "user-xx" {
|
||||
t.Errorf("unexpected username for registry: %s", frc.opts.Username)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue