package backend import ( "context" opentracing "github.com/opentracing/opentracing-go" "github.com/pulumi/pulumi/pkg/v3/backend/display" "github.com/pulumi/pulumi/pkg/v3/engine" "github.com/pulumi/pulumi/sdk/v3/go/common/util/result" ) type MakeQuery func(context.Context, QueryOperation) (engine.QueryInfo, error) // RunQuery executes a query program against the resource outputs of a locally hosted stack. func RunQuery(ctx context.Context, b Backend, op QueryOperation, callerEventsOpt chan<- engine.Event, newQuery MakeQuery) result.Result { q, err := newQuery(ctx, op) if err != nil { return result.FromError(err) } // Render query output to CLI. displayEvents := make(chan engine.Event) displayDone := make(chan bool) go display.ShowQueryEvents("running query", displayEvents, displayDone, op.Opts.Display) // The engineEvents channel receives all events from the engine, which we then forward onto other // channels for actual processing. (displayEvents and callerEventsOpt.) engineEvents := make(chan engine.Event) eventsDone := make(chan bool) go func() { for e := range engineEvents { displayEvents <- e if callerEventsOpt != nil { callerEventsOpt <- e } } close(eventsDone) }() // Depending on the action, kick off the relevant engine activity. Note that we don't immediately check and // return error conditions, because we will do so below after waiting for the display channels to close. cancellationScope := op.Scopes.NewScope(engineEvents, true /*dryRun*/) engineCtx := &engine.Context{ Cancel: cancellationScope.Context(), Events: engineEvents, BackendClient: NewBackendClient(b), } if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil { engineCtx.ParentSpan = parentSpan.Context() } res := engine.Query(engineCtx, q, op.Opts.Engine) // Wait for dependent channels to finish processing engineEvents before closing. <-displayDone cancellationScope.Close() // Don't take any cancellations anymore, we're shutting down. close(engineEvents) // Make sure that the goroutine writing to displayEvents and callerEventsOpt // has exited before proceeding <-eventsDone close(displayEvents) return res }