feat(gitops): general improvements BE-12919 (#2780)

This commit is contained in:
andres-portainer
2026-06-02 09:44:57 -03:00
committed by GitHub
parent 484af3c2c8
commit 1fa756372e
10 changed files with 190 additions and 124 deletions
+87 -97
View File
@@ -16,115 +16,105 @@ import (
// FetchWorkflows returns all GitOps workflows visible to the given user.
func FetchWorkflows(
ctx context.Context,
dataStore dataservices.DataStore,
tx dataservices.DataStoreTx,
gitService portainer.GitService,
k8sFactory *cli.ClientFactory,
sc *security.RestrictedRequestContext,
endpointIDSet set.Set[portainer.EndpointID],
) ([]Workflow, error) {
var stacks []portainer.Stack
var endpointMap map[portainer.EndpointID]portainer.Endpoint
gitConfigs := map[portainer.StackID]*gittypes.RepoConfig{}
err := dataStore.ViewTx(func(tx dataservices.DataStoreTx) error {
var err error
stacks, err = tx.Stack().ReadAll(func(s portainer.Stack) bool {
return s.WorkflowID != 0 && (len(endpointIDSet) == 0 || endpointIDSet.Contains(s.EndpointID))
})
if err != nil {
return err
}
endpointMap, err = buildEndpointMap(tx, stacks)
if err != nil {
return err
}
stacks, err = filterDockerStacksByAccess(tx, stacks, sc)
if err != nil {
return err
}
// First pass: filter by endpoint/stack-type match and collect workflow IDs.
preFiltered := make([]portainer.Stack, 0, len(stacks))
workflowIDSet := make(map[portainer.WorkflowID]struct{}, len(stacks))
for _, stack := range stacks {
if ep, ok := endpointMap[stack.EndpointID]; ok && !EndpointMatchesStackType(ep, stack.Type) {
continue
}
preFiltered = append(preFiltered, stack)
workflowIDSet[stack.WorkflowID] = struct{}{}
}
// Batch-load all needed workflows in one scan.
workflows, err := tx.Workflow().ReadAll(func(wf portainer.Workflow) bool {
_, ok := workflowIDSet[wf.ID]
return ok
})
if err != nil {
return err
}
workflowMap := make(map[portainer.WorkflowID]portainer.Workflow, len(workflows))
var allArtifacts []portainer.ArtifactSources
for _, wf := range workflows {
workflowMap[wf.ID] = wf
allArtifacts = append(allArtifacts, wf.Artifacts...)
}
sourceSet := ArtifactsToSourceSet(allArtifacts...)
// Batch-load all needed sources in one scan.
srcs, err := tx.Source().ReadAll(func(src portainer.Source) bool {
return sourceSet.Contains(src.ID)
})
if err != nil {
return err
}
sourceMap := make(map[portainer.SourceID]portainer.Source, len(srcs))
for _, src := range srcs {
sourceMap[src.ID] = src
}
// Second pass: build filtered list using in-memory lookups.
var filtered []portainer.Stack
for _, stack := range preFiltered {
wf, ok := workflowMap[stack.WorkflowID]
if !ok {
log.Warn().Int("stackID", int(stack.ID)).Msg("workflow record missing for stack, skipping")
continue
}
outer:
for _, as := range wf.Artifacts {
if as.Artifact.StackID != stack.ID {
continue
}
for _, srcID := range as.SourceIDs {
src, ok := sourceMap[srcID]
if !ok {
log.Warn().Int("stackID", int(stack.ID)).Msg("source record missing for stack, skipping")
break outer
}
if src.Type == portainer.SourceTypeGit {
gitConfigs[stack.ID] = MergeSourceAndArtifact(&src, &as.Artifact)
break outer
}
}
}
filtered = append(filtered, stack)
}
stacks = filtered
return nil
stacks, err := tx.Stack().ReadAll(func(s portainer.Stack) bool {
return s.WorkflowID != 0 && (len(endpointIDSet) == 0 || endpointIDSet.Contains(s.EndpointID))
})
if err != nil {
return nil, err
}
endpointMap, err := buildEndpointMap(tx, stacks)
if err != nil {
return nil, err
}
stacks, err = filterDockerStacksByAccess(tx, stacks, sc)
if err != nil {
return nil, err
}
// First pass: filter by endpoint/stack-type match and collect workflow IDs.
preFiltered := make([]portainer.Stack, 0, len(stacks))
workflowIDSet := make(map[portainer.WorkflowID]struct{}, len(stacks))
for _, stack := range stacks {
if ep, ok := endpointMap[stack.EndpointID]; ok && !EndpointMatchesStackType(ep, stack.Type) {
continue
}
preFiltered = append(preFiltered, stack)
workflowIDSet[stack.WorkflowID] = struct{}{}
}
// Batch-load all needed workflows in one scan.
wfs, err := tx.Workflow().ReadAll(func(wf portainer.Workflow) bool {
_, ok := workflowIDSet[wf.ID]
return ok
})
if err != nil {
return nil, err
}
workflowMap := make(map[portainer.WorkflowID]portainer.Workflow, len(wfs))
var allArtifacts []portainer.ArtifactSources
for _, wf := range wfs {
workflowMap[wf.ID] = wf
allArtifacts = append(allArtifacts, wf.Artifacts...)
}
sourceSet := ArtifactsToSourceSet(allArtifacts...)
// Batch-load all needed sources in one scan.
srcs, err := tx.Source().ReadAll(func(src portainer.Source) bool {
return sourceSet.Contains(src.ID)
})
if err != nil {
return nil, err
}
sourceMap := make(map[portainer.SourceID]portainer.Source, len(srcs))
for _, src := range srcs {
sourceMap[src.ID] = src
}
// Second pass: build filtered list using in-memory lookups.
var filtered []portainer.Stack
for _, stack := range preFiltered {
wf, ok := workflowMap[stack.WorkflowID]
if !ok {
log.Warn().Int("stackID", int(stack.ID)).Msg("workflow record missing for stack, skipping")
continue
}
outer:
for _, as := range wf.Artifacts {
if as.Artifact.StackID != stack.ID {
continue
}
for _, srcID := range as.SourceIDs {
src, ok := sourceMap[srcID]
if !ok {
log.Warn().Int("stackID", int(stack.ID)).Msg("source record missing for stack, skipping")
break outer
}
if src.Type == portainer.SourceTypeGit {
gitConfigs[stack.ID] = MergeSourceAndArtifact(&src, &as.Artifact)
break outer
}
}
}
filtered = append(filtered, stack)
}
stacks = filtered
accessMap, err := buildEndpointAccessMap(k8sFactory, sc, endpointMap)
if err != nil {
return nil, err