Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package environmentprogression

import (
"context"
"fmt"

"workspace-engine/pkg/oapi"
"workspace-engine/pkg/selector"
"workspace-engine/pkg/workspace/releasemanager/action"
"workspace-engine/pkg/workspace/store"
)

type ReconcileFn func(ctx context.Context, target *oapi.ReleaseTarget) error

type EnvironmentProgressionAction struct {
store *store.Store
reconcileFn ReconcileFn
}

func NewEnvironmentProgressionAction(store *store.Store, reconcileFn ReconcileFn) *EnvironmentProgressionAction {
return &EnvironmentProgressionAction{
store: store,
reconcileFn: reconcileFn,
}
}

func (a *EnvironmentProgressionAction) Name() string {
return "environmentprogression"
}

func (a *EnvironmentProgressionAction) Execute(ctx context.Context, trigger action.ActionTrigger, actx action.ActionContext) error {
if trigger != action.TriggerJobSuccess {
return nil
}

environment := a.getEnvironment(actx.Release.ReleaseTarget.EnvironmentId)
if environment == nil {
return nil
}

progressionDependentPolicies, err := a.getProgressionDependentPolicies(ctx, environment)
if err != nil {
return fmt.Errorf("failed to get progression dependent policies: %w", err)
}

if len(progressionDependentPolicies) == 0 {
return nil
}

progressionDependentTargets, err := a.getProgressionDependentTargets(ctx, progressionDependentPolicies)
if err != nil {
return fmt.Errorf("failed to get progression dependent targets: %w", err)
}

if len(progressionDependentTargets) == 0 {
return nil
}

return a.reconcileTargets(ctx, progressionDependentTargets)
}

func (a *EnvironmentProgressionAction) getEnvironment(envId string) *oapi.Environment {
env, ok := a.store.Environments.Get(envId)
if !ok {
return nil
}
return env
}

func (a *EnvironmentProgressionAction) getProgressionDependentPolicies(ctx context.Context, environment *oapi.Environment) ([]*oapi.Policy, error) {
policies := make([]*oapi.Policy, 0)
for _, policy := range a.store.Policies.Items() {
for _, rule := range policy.Rules {
if rule.EnvironmentProgression == nil {
continue
}

dependsOnSelector := rule.EnvironmentProgression.DependsOnEnvironmentSelector

matched, err := selector.Match(ctx, &dependsOnSelector, *environment)
if err != nil {
return nil, fmt.Errorf("failed to match selector: %w", err)
}

if matched {
policies = append(policies, policy)
}

break
}
}

return policies, nil
}

func (a *EnvironmentProgressionAction) getProgressionDependentTargets(ctx context.Context, policies []*oapi.Policy) ([]*oapi.ReleaseTarget, error) {
targetMap := make(map[string]*oapi.ReleaseTarget)
for _, policy := range policies {
policyTargets, err := a.store.ReleaseTargets.GetForPolicy(ctx, policy)
if err != nil {
return nil, fmt.Errorf("failed to get release targets for policy %s: %w", policy.Id, err)
}
for _, target := range policyTargets {
targetMap[target.Key()] = target
}
}

targetList := make([]*oapi.ReleaseTarget, 0, len(targetMap))
for _, target := range targetMap {
targetList = append(targetList, target)
}
return targetList, nil
}

func (a *EnvironmentProgressionAction) reconcileTargets(ctx context.Context, targets []*oapi.ReleaseTarget) error {
for _, target := range targets {
if err := a.reconcileFn(ctx, target); err != nil {
return fmt.Errorf("failed to reconcile target %s: %w", target.Key(), err)
}
}
return nil
}
27 changes: 27 additions & 0 deletions apps/workspace-engine/pkg/workspace/store/release_targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,33 @@ func (r *ReleaseTargets) GetForSystem(ctx context.Context, systemId string) ([]*
return releaseTargets, nil
}

func (r *ReleaseTargets) GetForPolicy(ctx context.Context, policy *oapi.Policy) (map[string]*oapi.ReleaseTarget, error) {
targetMap := make(map[string]*oapi.ReleaseTarget)

allReleaseTargets := r.releaseTargets.Items()
for _, releaseTarget := range allReleaseTargets {
environment, ok := r.store.Environments.Get(releaseTarget.EnvironmentId)
if !ok {
continue
}
deployment, ok := r.store.Deployments.Get(releaseTarget.DeploymentId)
if !ok {
continue
}
resource, ok := r.store.Resources.Get(releaseTarget.ResourceId)
if !ok {
continue
}

isMatch := selector.MatchPolicy(ctx, policy, selector.NewResolvedReleaseTarget(environment, deployment, resource))
if isMatch {
targetMap[releaseTarget.Key()] = releaseTarget
}
}

return targetMap, nil
}

func (r *ReleaseTargets) RemoveForResource(ctx context.Context, resourceId string) {
for _, releaseTarget := range r.GetForResource(ctx, resourceId) {
if releaseTarget.ResourceId == resourceId {
Expand Down
26 changes: 9 additions & 17 deletions apps/workspace-engine/pkg/workspace/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
verificationaction "workspace-engine/pkg/workspace/releasemanager/action/verification"
"workspace-engine/pkg/workspace/releasemanager/deployment/jobs"
"workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency"
"workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression"
"workspace-engine/pkg/workspace/releasemanager/trace"
"workspace-engine/pkg/workspace/releasemanager/trace/spanstore"
"workspace-engine/pkg/workspace/store"
Expand All @@ -33,25 +34,16 @@ func New(ctx context.Context, id string, options ...WorkspaceOption) *Workspace

// Create release manager with trace store (will panic if nil)
ws.releasemanager = releasemanager.New(s, ws.traceStore)
reconcileFn := func(ctx context.Context, target *oapi.ReleaseTarget) error {
return ws.releasemanager.ReconcileTarget(ctx, target, releasemanager.WithTrigger(trace.TriggerJobSuccess))
}

ws.actionOrchestrator = action.
NewOrchestrator(s).
RegisterAction(
verificationaction.NewVerificationAction(
ws.releasemanager.VerificationManager(),
),
).RegisterAction(
deploymentdependency.NewDeploymentDependencyAction(
s,
func(ctx context.Context, target *oapi.ReleaseTarget) error {
return ws.releasemanager.ReconcileTarget(ctx, target, releasemanager.WithTrigger(trace.TriggerJobSuccess))
},
),
).RegisterAction(
rollback.NewRollbackAction(
s,
jobs.NewDispatcher(s, ws.releasemanager.VerificationManager()),
),
)
RegisterAction(verificationaction.NewVerificationAction(ws.releasemanager.VerificationManager())).
RegisterAction(deploymentdependency.NewDeploymentDependencyAction(s, reconcileFn)).
RegisterAction(environmentprogression.NewEnvironmentProgressionAction(s, reconcileFn)).
RegisterAction(rollback.NewRollbackAction(s, jobs.NewDispatcher(s, ws.releasemanager.VerificationManager())))

return ws
}
Expand Down
Loading
Loading