Skip to content

Commit

Permalink
fix race conditions on pr concurrency
Browse files Browse the repository at this point in the history
when storing a pointer in the context, the pointer get nil sometime on
high load which causes some of the pipelinerun issue

we fix this by passing the value around instead of passing the pointer
in context. There is more going on in this bug that meet the eyes but
that seems to fix it.

remove all the StoreInfo and GetInfo functions and use the value directly.

Signed-off-by: Chmouel Boudjnah <[email protected]>
  • Loading branch information
chmouel committed Mar 12, 2024
1 parent 226781a commit f32eb1e
Show file tree
Hide file tree
Showing 28 changed files with 71 additions and 193 deletions.
1 change: 0 additions & 1 deletion cmd/pipelines-as-code-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ func main() {
ctx = evadapter.WithConfiguratorOptions(ctx, []evadapter.ConfiguratorOption{copt})

ctx = info.StoreNS(ctx, ns)
ctx = info.StoreInfo(ctx, rinfo.Controller.Name, rinfo)
ctx = info.StoreCurrentControllerName(ctx, rinfo.Controller.Name)

ctx = context.WithValue(ctx, client.Key{}, run.Clients.Kube)
Expand Down
3 changes: 1 addition & 2 deletions pkg/adapter/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,12 @@ func (l *listener) Start(ctx context.Context) error {
func (l listener) handleEvent(ctx context.Context) http.HandlerFunc {
return func(response http.ResponseWriter, request *http.Request) {
// we should fix this, this basically reads configmap on every request, is that supposed to be okay?
currentControllerName := info.GetCurrentControllerName(ctx)
if err := l.run.UpdatePACInfo(ctx); err != nil {
log.Fatalf("error getting config and setting from configmaps: %v", err)
}

ninfo := &info.Info{}
l.run.Info.DeepCopy(ninfo)
ctx = info.StoreInfo(ctx, currentControllerName, ninfo)

if request.Method != http.MethodPost {
l.writeResponse(response, http.StatusOK, "ok")
Expand Down Expand Up @@ -223,6 +221,7 @@ func (l listener) detectProvider(req *http.Request, reqBody string) (provider.In
}

gitHub := github.New()
gitHub.Run = l.run
isGH, processReq, logger, reason, err := gitHub.Detect(req, reqBody, &log)
if isGH {
return l.processRes(processReq, gitHub, logger, reason, err)
Expand Down
6 changes: 0 additions & 6 deletions pkg/adapter/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,6 @@ func TestHandleEvent(t *testing.T) {
logger, _ := logger.GetLogger()

ctx = info.StoreCurrentControllerName(ctx, "default")
ctx = info.StoreInfo(ctx, "default", &info.Info{
Controller: &info.ControllerInfo{
Secret: info.DefaultPipelinesAscodeSecretName,
Configmap: info.DefaultPipelinesAscodeConfigmapName,
},
})
ctx = info.StoreNS(ctx, "default")

emptys := &unstructured.Unstructured{}
Expand Down
1 change: 1 addition & 0 deletions pkg/adapter/incoming.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ func (l *listener) detectIncoming(ctx context.Context, req *http.Request, payloa

if repo.Spec.GitProvider == nil || repo.Spec.GitProvider.Type == "" {
gh := github.New()
gh.Run = l.run
ns := info.GetNS(ctx)
enterpriseURL, token, installationID, err := app.GetAndUpdateInstallationID(ctx, req, l.run, repo, gh, ns)
if err != nil {
Expand Down
12 changes: 6 additions & 6 deletions pkg/adapter/incoming_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,19 +655,18 @@ func Test_listener_detectIncoming(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
ctx, _ := rtesting.SetupFakeContext(t)
ctx = info.StoreCurrentControllerName(ctx, "default")
ctx = info.StoreInfo(ctx, "default", &info.Info{
Controller: &info.ControllerInfo{
Secret: info.DefaultPipelinesAscodeSecretName,
},
})
ctx = info.StoreNS(ctx, testNamespace.GetName())
cs, _ := testclient.SeedTestData(t, ctx, tt.args.data)
client := &params.Run{
Clients: clients.Clients{
PipelineAsCode: cs.PipelineAsCode,
Kube: cs.Kube,
},
Info: info.Info{},
Info: info.Info{
Controller: &info.ControllerInfo{
Secret: info.DefaultPipelinesAscodeSecretName,
},
},
}
observer, _ := zapobserver.New(zap.InfoLevel)
logger := zap.New(observer).Sugar()
Expand All @@ -681,6 +680,7 @@ func Test_listener_detectIncoming(t *testing.T) {
kint: kint,
event: info.NewEvent(),
}

// make a new request
req := httptest.NewRequest(tt.args.method,
fmt.Sprintf("http://localhost%s?repository=%s&secret=%s&pipelinerun=%s&branch=%s", tt.args.queryURL,
Expand Down
10 changes: 5 additions & 5 deletions pkg/cmd/tknpac/info/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,18 @@ func TestInfo(t *testing.T) {
if tt.secret != nil {
name = tt.secret.GetName()
}
ctx = info.StoreInfo(ctx, "default", &info.Info{
Controller: &info.ControllerInfo{
Secret: name,
},
})
stdata, _ := testclient.SeedTestData(t, ctx, tdata)
cs := &params.Run{
Clients: clients.Clients{
PipelineAsCode: stdata.PipelineAsCode,
Kube: stdata.Kube,
HTTP: *httpTestClient,
},
Info: info.Info{
Controller: &info.ControllerInfo{
Secret: name,
},
},
}

io, out := tcli.NewIOStream()
Expand Down
10 changes: 5 additions & 5 deletions pkg/kubeinteraction/labels.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package kubeinteraction

import (
"context"
"fmt"
"strconv"

"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode"
"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
apipac "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
"github.com/openshift-pipelines/pipelines-as-code/pkg/formatting"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/version"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
Expand All @@ -21,13 +21,13 @@ const (
StateFailed = "failed"
)

func AddLabelsAndAnnotations(ctx context.Context, event *info.Event, pipelineRun *tektonv1.PipelineRun, repo *apipac.Repository, providerinfo *info.ProviderConfig) error {
func AddLabelsAndAnnotations(event *info.Event, pipelineRun *tektonv1.PipelineRun, repo *apipac.Repository, providerConfig *info.ProviderConfig, paramsRun *params.Run) error {
if event == nil {
return fmt.Errorf("event should not be nil")
}
paramsinfo := paramsRun.Info
// Add labels on the soon-to-be created pipelinerun so UI/CLI can easily
// query them.
paramsinfo := info.GetInfo(ctx, info.GetCurrentControllerName(ctx))
labels := map[string]string{
// These keys are used in LabelSelector query, so we are keeping in Labels as it is.
// But adding same keys to Annotations so UI/CLI can fetch the actual value instead of modified value
Expand All @@ -52,7 +52,7 @@ func AddLabelsAndAnnotations(ctx context.Context, event *info.Event, pipelineRun
keys.EventType: event.EventType,
keys.Branch: event.BaseBranch,
keys.Repository: repo.GetName(),
keys.GitProvider: providerinfo.Name,
keys.GitProvider: providerConfig.Name,
keys.State: StateStarted,
keys.ControllerInfo: fmt.Sprintf(`{"name":"%s","configmap":"%s","secret":"%s"}`, paramsinfo.Controller.Name, paramsinfo.Controller.Configmap, paramsinfo.Controller.Secret),
}
Expand All @@ -63,7 +63,7 @@ func AddLabelsAndAnnotations(ctx context.Context, event *info.Event, pipelineRun
}

// TODO: move to provider specific function
if providerinfo.Name == "github" || providerinfo.Name == "github-enterprise" {
if providerConfig.Name == "github" || providerConfig.Name == "github-enterprise" {
if event.InstallationID != -1 {
annotations[keys.InstallationID] = strconv.FormatInt(event.InstallationID, 10)
}
Expand Down
14 changes: 7 additions & 7 deletions pkg/kubeinteraction/labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (

"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/keys"
apipac "github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"gotest.tools/v3/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
rtesting "knative.dev/pkg/reconciler/testing"
)

func TestAddLabelsAndAnnotations(t *testing.T) {
Expand Down Expand Up @@ -58,12 +58,12 @@ func TestAddLabelsAndAnnotations(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx, _ := rtesting.SetupFakeContext(t)
ctx = info.StoreCurrentControllerName(ctx, "default")
ctx = info.StoreInfo(ctx, "default", &info.Info{
Controller: tt.args.controllerInfo,
})
err := AddLabelsAndAnnotations(ctx, tt.args.event, tt.args.pipelineRun, tt.args.repo, &info.ProviderConfig{})
paramsRun := &params.Run{
Info: info.Info{
Controller: tt.args.controllerInfo,
},
}
err := AddLabelsAndAnnotations(tt.args.event, tt.args.pipelineRun, tt.args.repo, &info.ProviderConfig{}, paramsRun)
assert.NilError(t, err)
assert.Equal(t, tt.args.pipelineRun.Labels[keys.URLOrg], tt.args.event.Organization, "'%s' != %s",
tt.args.pipelineRun.Labels[keys.URLOrg], tt.args.event.Organization)
Expand Down
54 changes: 0 additions & 54 deletions pkg/params/info/runinfo.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package info

import (
"context"
)

type Info struct {
Pac *PacOpts
Kube *KubeOpts
Expand All @@ -17,53 +13,3 @@ func (i *Info) DeepCopy(out *Info) {
type (
contextKey string
)

type CtxInfo struct {
Pac *PacOpts
Kube *KubeOpts
Controller *ControllerInfo
}

// GetInfo Pac Settings for that label.
func GetInfo(ctx context.Context, label string) *Info {
labelContextKey := contextKey(label)
if val := ctx.Value(labelContextKey); val != nil {
if ctxInfo, ok := val.(CtxInfo); ok {
return &Info{
Pac: ctxInfo.Pac,
Kube: ctxInfo.Kube,
Controller: ctxInfo.Controller,
}
}
}
return nil
}

// StoreInfo Pac Settings for a label.
func StoreInfo(ctx context.Context, label string, info *Info) context.Context {
labelContextKey := contextKey(label)
if val := ctx.Value(labelContextKey); val != nil {
if ctxInfo, ok := val.(CtxInfo); ok {
if ctxInfo.Pac == nil {
ctxInfo.Pac = &PacOpts{}
}
if ctxInfo.Kube == nil {
ctxInfo.Kube = &KubeOpts{
Namespace: GetNS(ctx),
}
}
if ctxInfo.Controller == nil {
ctxInfo.Controller = &ControllerInfo{}
}
ctxInfo.Pac = info.Pac
ctxInfo.Kube = info.Kube
ctxInfo.Controller = info.Controller
return context.WithValue(ctx, labelContextKey, ctxInfo)
}
}
return context.WithValue(ctx, labelContextKey, CtxInfo{
Pac: info.Pac,
Kube: info.Kube,
Controller: info.Controller,
})
}
53 changes: 0 additions & 53 deletions pkg/params/info/runinfo_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/pipelineascode/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (p *PacRun) verifyRepoAndUser(ctx context.Context) (*v1alpha1.Repository, e
// so instead of having to specify their in Repo each time, they use a
// shared one from pac.
if p.event.InstallationID > 0 {
p.event.Provider.WebhookSecret, _ = GetCurrentNSWebhookSecret(ctx, p.k8int)
p.event.Provider.WebhookSecret, _ = GetCurrentNSWebhookSecret(ctx, p.k8int, p.run)
} else {
err := SecretFromRepository(ctx, p.run, p.k8int, p.vcx.GetConfig(), p.event, repo, p.logger)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/pipelineascode/pipelineascode.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func (p *PacRun) startPR(ctx context.Context, match matcher.Match) (*tektonv1.Pi
}

// Add labels and annotations to pipelinerun
err := kubeinteraction.AddLabelsAndAnnotations(ctx, p.event, match.PipelineRun, match.Repo, p.vcx.GetConfig())
err := kubeinteraction.AddLabelsAndAnnotations(p.event, match.PipelineRun, match.Repo, p.vcx.GetConfig(), p.run)
if err != nil {
p.logger.Errorf("Error adding labels/annotations to PipelineRun '%s' in namespace '%s': %v", match.PipelineRun.GetName(), match.Repo.GetNamespace(), err)
}
Expand Down
10 changes: 4 additions & 6 deletions pkg/pipelineascode/pipelineascode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,11 +502,6 @@ func TestRun(t *testing.T) {
secrets[info.DefaultPipelinesAscodeSecretName] = webhookSecret
}

ctx = info.StoreInfo(ctx, "default", &info.Info{
Controller: &info.ControllerInfo{
Secret: info.DefaultPipelinesAscodeSecretName,
},
})
if tt.repositories == nil {
tt.repositories = []*v1alpha1.Repository{
testnewrepo.NewRepo(repo),
Expand Down Expand Up @@ -552,6 +547,9 @@ func TestRun(t *testing.T) {
HubCatalogs: &hubCatalogs,
},
},
Controller: &info.ControllerInfo{
Secret: info.DefaultPipelinesAscodeSecretName,
},
},
}
mac := hmac.New(sha256.New, []byte(payloadEncodedSecret))
Expand Down Expand Up @@ -586,7 +584,7 @@ func TestRun(t *testing.T) {

vcx := &ghprovider.Provider{
Client: fakeclient,
Run: params.New(),
Run: cs,
Token: github.String("None"),
Logger: logger,
}
Expand Down
5 changes: 2 additions & 3 deletions pkg/pipelineascode/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,11 @@ func SecretFromRepository(ctx context.Context, cs *params.Run, k8int kubeinterac
}

// GetCurrentNSWebhookSecret get secret from namespace as stored on context.
func GetCurrentNSWebhookSecret(ctx context.Context, k8int kubeinteraction.Interface) (string, error) {
func GetCurrentNSWebhookSecret(ctx context.Context, k8int kubeinteraction.Interface, run *params.Run) (string, error) {
ns := info.GetNS(ctx)
paramsinfo := info.GetInfo(ctx, info.GetCurrentControllerName(ctx))
s, err := k8int.GetSecret(ctx, ktypes.GetSecretOpt{
Namespace: ns,
Name: paramsinfo.Controller.Secret,
Name: run.Info.Controller.Secret,
Key: defaultPipelinesAscodeSecretWebhookSecretKey,
})
// a lot of people have problem with this secret, when encoding it to base64 which add a \n when we do :
Expand Down
4 changes: 3 additions & 1 deletion pkg/provider/github/app/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ type JWTClaim struct {

func GenerateJWT(ctx context.Context, ns string, run *params.Run) (string, error) {
// TODO: move this out of here
applicationID, privateKey, err := github.GetAppIDAndPrivateKey(ctx, ns, run.Clients.Kube)
gh := github.New()
gh.Run = run
applicationID, privateKey, err := gh.GetAppIDAndPrivateKey(ctx, ns, run.Clients.Kube)
if err != nil {
return "", err
}
Expand Down
Loading

0 comments on commit f32eb1e

Please sign in to comment.