Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added multiple repos support for bitbucket eventsource #2031

Merged
merged 3 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions eventsources/sources/bitbucket/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byt
hookIDs: make(map[string]string),
}

if !bitbucketEventSource.ShouldCreateWebhook() {
logger.Info("no need to create webhook")
if !bitbucketEventSource.ShouldCreateWebhooks() {
logger.Info("access token or webhook configuration were not provided, skipping webhooks creation")
return webhook.ManageRoute(ctx, router, controller, dispatch)
}

Expand Down
4 changes: 2 additions & 2 deletions eventsources/sources/bitbucket/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ func validate(eventSource *v1alpha1.BitbucketEventSource) error {
if eventSource.GetBitbucketRepositories() == nil {
return fmt.Errorf("at least one repository is required")
}
if eventSource.ShouldCreateWebhook() && len(eventSource.Events) == 0 {
return fmt.Errorf("events must be defined to create a bitbucket webhook")
if eventSource.ShouldCreateWebhooks() && len(eventSource.Events) == 0 {
return fmt.Errorf("events must be defined to create a bitbucket webhooks")
}
return webhook.ValidateWebhookContext(eventSource.Webhook)
}
107 changes: 54 additions & 53 deletions eventsources/sources/bitbucketserver/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,71 +184,72 @@ func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byt
hookIDs: make(map[string]int),
}

if bitbucketserverEventSource.ShouldCreateWebhooks() {
logger.Info("retrieving the access token credentials...")
bitbucketToken, err := common.GetSecretFromVolume(bitbucketserverEventSource.AccessToken)
if err != nil {
return errors.Errorf("failed to get bitbucketserver token. err: %+v", err)
}
if !bitbucketserverEventSource.ShouldCreateWebhooks() {
VaibhavPage marked this conversation as resolved.
Show resolved Hide resolved
logger.Info("access token or webhook configuration were not provided, skipping webhooks creation")
return webhook.ManageRoute(ctx, router, controller, dispatch)
}

if bitbucketserverEventSource.WebhookSecret != nil {
logger.Info("retrieving the webhook secret...")
webhookSecret, err := common.GetSecretFromVolume(bitbucketserverEventSource.WebhookSecret)
if err != nil {
return errors.Errorf("failed to get bitbucketserver webhook secret. err: %+v", err)
}
logger.Info("retrieving the access token credentials...")
bitbucketToken, err := common.GetSecretFromVolume(bitbucketserverEventSource.AccessToken)
if err != nil {
return errors.Errorf("failed to get bitbucketserver token. err: %+v", err)
}

router.hookSecret = webhookSecret
if bitbucketserverEventSource.WebhookSecret != nil {
logger.Info("retrieving the webhook secret...")
webhookSecret, err := common.GetSecretFromVolume(bitbucketserverEventSource.WebhookSecret)
if err != nil {
return errors.Errorf("failed to get bitbucketserver webhook secret. err: %+v", err)
}

logger.Info("setting up the client to connect to Bitbucket Server...")
bitbucketConfig := bitbucketv1.NewConfiguration(bitbucketserverEventSource.BitbucketServerBaseURL)
bitbucketConfig.AddDefaultHeader("x-atlassian-token", "no-check")
bitbucketConfig.AddDefaultHeader("x-requested-with", "XMLHttpRequest")
router.hookSecret = webhookSecret
}

ctx, cancel := context.WithCancel(ctx)
defer cancel()
logger.Info("setting up the client to connect to Bitbucket Server...")
bitbucketConfig := bitbucketv1.NewConfiguration(bitbucketserverEventSource.BitbucketServerBaseURL)
bitbucketConfig.AddDefaultHeader("x-atlassian-token", "no-check")
bitbucketConfig.AddDefaultHeader("x-requested-with", "XMLHttpRequest")

ctx = context.WithValue(ctx, bitbucketv1.ContextAccessToken, bitbucketToken)
ctx, cancel := context.WithCancel(ctx)
defer cancel()

applyWebhooks := func() {
for _, repo := range bitbucketserverEventSource.GetBitbucketServerRepositories() {
if err = router.applyBitbucketServerWebhook(ctx, bitbucketConfig, repo); err != nil {
logger.Errorw("failed to apply Bitbucket webhook",
zap.String("project-key", repo.ProjectKey), zap.String("repository-slug", repo.RepositorySlug), zap.Error(err))
continue
}
ctx = context.WithValue(ctx, bitbucketv1.ContextAccessToken, bitbucketToken)

time.Sleep(500 * time.Millisecond)
applyWebhooks := func() {
for _, repo := range bitbucketserverEventSource.GetBitbucketServerRepositories() {
if err = router.applyBitbucketServerWebhook(ctx, bitbucketConfig, repo); err != nil {
logger.Errorw("failed to apply Bitbucket webhook",
zap.String("project-key", repo.ProjectKey), zap.String("repository-slug", repo.RepositorySlug), zap.Error(err))
continue
}

time.Sleep(500 * time.Millisecond)
}
}

// When running multiple replicas of the eventsource, they will all try to create the webhook.
// Randomly sleep some time to mitigate the issue.
randomNum, _ := rand.Int(rand.Reader, big.NewInt(int64(2000)))
time.Sleep(time.Duration(randomNum.Int64()) * time.Millisecond)
applyWebhooks()

go func() {
// Another kind of race conditions might happen when pods do rolling upgrade - new pod starts
// and old pod terminates, if DeleteHookOnFinish is true, the hook will be deleted from Bitbucket.
// This is a workaround to mitigate the race conditions.
logger.Info("starting bitbucket hooks manager daemon")
ticker := time.NewTicker(60 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
logger.Info("exiting bitbucket hooks manager daemon")
return
case <-ticker.C:
applyWebhooks()
}
// When running multiple replicas of the eventsource, they will all try to create the webhook.
// Randomly sleep some time to mitigate the issue.
randomNum, _ := rand.Int(rand.Reader, big.NewInt(int64(2000)))
time.Sleep(time.Duration(randomNum.Int64()) * time.Millisecond)
applyWebhooks()

go func() {
// Another kind of race conditions might happen when pods do rolling upgrade - new pod starts
// and old pod terminates, if DeleteHookOnFinish is true, the hook will be deleted from Bitbucket.
// This is a workaround to mitigate the race conditions.
logger.Info("starting bitbucket hooks manager daemon")
ticker := time.NewTicker(60 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
logger.Info("exiting bitbucket hooks manager daemon")
return
case <-ticker.C:
applyWebhooks()
}
}()
} else {
logger.Info("access token or webhook configuration were not provided, skipping webhook creation")
}
}
}()

return webhook.ManageRoute(ctx, router, controller, dispatch)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/eventsource/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ func (b BitbucketEventSource) HasConfiguredWebhook() bool {
return b.Webhook != nil && b.Webhook.URL != ""
}

func (b BitbucketEventSource) ShouldCreateWebhook() bool {
func (b BitbucketEventSource) ShouldCreateWebhooks() bool {
return (b.HasBitbucketBasicAuth() || b.HasBitbucketOAuthToken()) && b.HasConfiguredWebhook()
}

Expand Down