Skip to content
Closed
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
16 changes: 10 additions & 6 deletions cloud/aws/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,17 @@ func (a *NitricAwsPulumiProvider) Pre(ctx *pulumi.Context, resources []*pulumix.
return err
}

stackIdChan := make(chan string)
pulumi.Sprintf("%s-%s", ctx.Stack(), stackRandId.Result).ApplyT(func(id string) string {
stackIdChan <- id
return id
})
a.StackId = "stack-id"

if !ctx.DryRun() {
stackIdChan := make(chan string)
pulumi.Sprintf("%s-%s", ctx.Stack(), stackRandId.Result).ApplyT(func(id string) string {
stackIdChan <- id
return id
})

a.StackId = <-stackIdChan
a.StackId = <-stackIdChan
}

sess := session.Must(session.NewSessionWithOptions(session.Options{
Config: aws.Config{Region: aws.String(a.Region)},
Expand Down
16 changes: 10 additions & 6 deletions cloud/azure/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,17 @@ func (a *NitricAzurePulumiProvider) Pre(ctx *pulumi.Context, nitricResources []*
return err
}

stackIdChan := make(chan string)
pulumi.Sprintf("%s-%s", ctx.Stack(), stackRandId.Result).ApplyT(func(id string) string {
stackIdChan <- id
return id
})
a.StackId = "stack-id"

if !ctx.DryRun() {
stackIdChan := make(chan string)
pulumi.Sprintf("%s-%s", ctx.Stack(), stackRandId.Result).ApplyT(func(id string) string {
stackIdChan <- id
return id
})

a.StackId = <-stackIdChan
a.StackId = <-stackIdChan
}

a.ClientConfig, err = authorization.GetClientConfig(ctx)
if err != nil {
Expand Down
132 changes: 87 additions & 45 deletions cloud/common/deploy/provider/pulumi.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ import (
"github.com/pulumi/pulumi/sdk/v3/go/auto"
"github.com/pulumi/pulumi/sdk/v3/go/auto/events"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optdestroy"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optpreview"
"github.com/pulumi/pulumi/sdk/v3/go/auto/optup"
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -73,7 +75,7 @@ func nitricResourceToPulumiResource(res *deploymentspb.Resource) *pulumix.Nitric
}
}

func createPulumiProgramForNitricProvider(req *deploymentspb.DeploymentUpRequest, nitricProvider NitricPulumiProvider, runtime RuntimeProvider) func(*pulumi.Context) error {
func createPulumiProgramForNitricProvider(spec *deploymentspb.Spec, nitricProvider NitricPulumiProvider, runtime RuntimeProvider) func(*pulumi.Context) error {
return func(ctx *pulumi.Context) (err error) {
defer func() {
if r := recover(); r != nil {
Expand All @@ -83,8 +85,8 @@ func createPulumiProgramForNitricProvider(req *deploymentspb.DeploymentUpRequest
}()

// Need to convert the Nitric resources to Pulumi resources, this will allow us to extend their configurations with pulumi inputs/outputs
pulumiResources := make([]*pulumix.NitricPulumiResource[any], 0, len(req.Spec.Resources))
for _, res := range nitricProvider.Order(req.Spec.Resources) {
pulumiResources := make([]*pulumix.NitricPulumiResource[any], 0, len(spec.Resources))
for _, res := range nitricProvider.Order(spec.Resources) {
pulumiResources = append(pulumiResources, nitricResourceToPulumiResource(res))
}

Expand Down Expand Up @@ -205,49 +207,61 @@ func parsePulumiError(err error) error {
return pe
}

// Up - automatically called by the Nitric CLI via the `up` command
func (s *PulumiProviderServer) Up(req *deploymentspb.DeploymentUpRequest, stream deploymentspb.Deployment_UpServer) error {
func (s *PulumiProviderServer) initializePulumiStack(spec *deploymentspb.Spec, attributesMap map[string]any) (*auto.Stack, error) {
// Verify if dependencies are available
if err := checkDependencies(checkPulumiAvailable, checkDockerAvailable); err != nil {
return status.Error(codes.FailedPrecondition, err.Error())
return nil, status.Error(codes.FailedPrecondition, err.Error())
}

projectName, stackName, err := stackAndProjectFromAttributes(req.Attributes.AsMap())
projectName, stackName, err := stackAndProjectFromAttributes(attributesMap)
if err != nil {
return err
return nil, err
}

attributesMap := req.Attributes.AsMap()

err = s.provider.Init(attributesMap)
if err != nil {
return err
return nil, err
}

pulumiProgram := createPulumiProgramForNitricProvider(req, s.provider, s.runtime)
var pulumiProgram func(*pulumi.Context) error
if spec != nil {
pulumiProgram = createPulumiProgramForNitricProvider(spec, s.provider, s.runtime)
}

autoStack, err := auto.UpsertStackInlineSource(context.TODO(), fmt.Sprintf("%s-%s", projectName, stackName), projectName, pulumiProgram)
if err != nil {
return err
return nil, err
}

pulumiEventsChan := make(chan events.EngineEvent)

go func() {
// output the stream
_ = pulumix.StreamPulumiUpEngineEvents(stream, pulumiEventsChan)
}()

config, err := s.provider.Config()
if err != nil {
return err
return nil, err
}

err = autoStack.SetAllConfig(context.TODO(), config)
if err != nil {
return nil, err
}

return &autoStack, err
}

// Up - automatically called by the Nitric CLI via the `up` command
func (s *PulumiProviderServer) Up(req *deploymentspb.DeploymentUpRequest, stream deploymentspb.Deployment_UpServer) error {
attributesMap := req.Attributes.AsMap()

autoStack, err := s.initializePulumiStack(req.Spec, attributesMap)
if err != nil {
return err
}

pulumiEventsChan := make(chan events.EngineEvent)

go func() {
// output the stream
_ = pulumix.StreamPulumiUpEngineEvents(stream, pulumiEventsChan)
}()

refresh, ok := attributesMap["refresh"].(bool)

options := []optup.Option{optup.EventStreams(pulumiEventsChan)}
Expand Down Expand Up @@ -287,25 +301,9 @@ func (s *PulumiProviderServer) Up(req *deploymentspb.DeploymentUpRequest, stream

// Down - automatically called by the Nitric CLI via the `down` command
func (s *PulumiProviderServer) Down(req *deploymentspb.DeploymentDownRequest, stream deploymentspb.Deployment_DownServer) error {
// Verify if dependencies are available
if err := checkDependencies(checkPulumiAvailable, checkDockerAvailable); err != nil {
return status.Error(codes.FailedPrecondition, err.Error())
}

projectName, stackName, err := stackAndProjectFromAttributes(req.Attributes.AsMap())

attributesMap := req.Attributes.AsMap()
if err != nil {
return err
}

// run down on the stack
err = s.provider.Init(attributesMap)
if err != nil {
return err
}

stack, err := auto.UpsertStackInlineSource(context.TODO(), fmt.Sprintf("%s-%s", projectName, stackName), projectName, nil)
autoStack, err := s.initializePulumiStack(nil, attributesMap)
if err != nil {
return err
}
Expand All @@ -316,31 +314,75 @@ func (s *PulumiProviderServer) Down(req *deploymentspb.DeploymentDownRequest, st
_ = pulumix.StreamPulumiDownEngineEvents(stream, pulumiEventsChan)
}()

config, err := s.provider.Config()
refresh, ok := attributesMap["refresh"].(bool)

options := []optdestroy.Option{optdestroy.EventStreams(pulumiEventsChan)}

if ok && refresh {
options = append(options, optdestroy.Refresh())
}

_, err = autoStack.Destroy(context.TODO(), options...)
if err != nil {
logger.Error(err.Error())
return err
}

err = stack.SetAllConfig(context.TODO(), config)
return nil
}

// Preview - automatically called by the Nitric CLI via the `preview` command
func (s *PulumiProviderServer) Preview(req *deploymentspb.DeploymentPreviewRequest, stream deploymentspb.Deployment_PreviewServer) error {
attributesMap := req.Attributes.AsMap()

autoStack, err := s.initializePulumiStack(req.Spec, attributesMap)
if err != nil {
return err
}

pulumiEventsChan := make(chan events.EngineEvent)

go func() {
// output the stream
_ = pulumix.StreamPulumiPreviewEngineEvents(stream, pulumiEventsChan)
}()

refresh, ok := attributesMap["refresh"].(bool)

options := []optdestroy.Option{optdestroy.EventStreams(pulumiEventsChan)}
options := []optpreview.Option{optpreview.EventStreams(pulumiEventsChan)}

if ok && refresh {
options = append(options, optdestroy.Refresh())
options = append(options, optpreview.Refresh())
}

_, err = stack.Destroy(context.TODO(), options...)
result, err := autoStack.Preview(context.TODO(), options...)
if err != nil {
logger.Error(err.Error())
err = handleCommonErrors(err)

for _, handler := range s.errorHandlers {
err = handler(err)
}

return err
}

return nil
resultStr := fmt.Sprintf("%d to add, %d to change, %d to destroy.",
result.ChangeSummary[apitype.OpCreate],
result.ChangeSummary[apitype.OpUpdate],
result.ChangeSummary[apitype.OpDelete],
)

err = stream.Send(&deploymentspb.DeploymentPreviewEvent{
Content: &deploymentspb.DeploymentPreviewEvent_Result{
Result: &deploymentspb.UpResult{
Content: &deploymentspb.UpResult_Text{
Text: resultStr,
},
},
},
})

return err
}

// Start - starts the Nitric Provider gRPC server, making it callable by the Nitric CLI during deployments.
Expand Down
8 changes: 8 additions & 0 deletions cloud/common/deploy/provider/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ func (s *TerraformProviderServer) Down(req *deploymentspb.DeploymentDownRequest,
return status.Error(codes.Unimplemented, "Down not implemented for Terraform providers, please run terraform destroy against your stack state")
}

func (s *TerraformProviderServer) Preview(req *deploymentspb.DeploymentPreviewRequest, stream deploymentspb.Deployment_PreviewServer) error {
if beta, err := env.BETA_PROVIDERS.Bool(); err != nil || !beta {
return status.Error(codes.FailedPrecondition, "Nitric terraform providers are currently in beta, please add beta-providers to the preview field of your nitric.yaml to enable")
}

return status.Error(codes.Unimplemented, "Preview not implemented for Terraform providers, please run terraform plan against your stack state")
}

func NewTerraformProviderServer(provider NitricTerraformProvider, runtime RuntimeProvider) *TerraformProviderServer {
return &TerraformProviderServer{
provider: provider,
Expand Down
32 changes: 32 additions & 0 deletions cloud/common/deploy/pulumix/clistream.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,38 @@ func StreamPulumiUpEngineEvents(stream deploymentspb.Deployment_UpServer, pulumi
return nil
}

func StreamPulumiPreviewEngineEvents(stream deploymentspb.Deployment_PreviewServer, pulumiEventsChan <-chan events.EngineEvent) error {
evtHandler := pulumiEventHandler{
tree: DataTree{
Root: &DataNode{
Id: "stack",
Data: nil,
Children: make([]*DataNode, 0),
},
},
}

for evt := range pulumiEventsChan {
// translate the engine event to a server message and send back to the CLIent
updateDetails, err := evtHandler.engineEventToResourceUpdate(evt)
if err != nil {
// unknown event, possibly still useful for debugging.
logger.Debugf("%+v", evt)
continue
}

err = stream.Send(&deploymentspb.DeploymentPreviewEvent{
Content: &deploymentspb.DeploymentPreviewEvent_Update{
Update: updateDetails,
},
})
if err != nil {
return err
}
}
return nil
}

func StreamPulumiDownEngineEvents(stream deploymentspb.Deployment_DownServer, pulumiEventsChan <-chan events.EngineEvent) (err error) {
evtHandler := pulumiEventHandler{
tree: DataTree{
Expand Down
16 changes: 10 additions & 6 deletions cloud/gcp/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,17 @@ func (a *NitricGcpPulumiProvider) Pre(ctx *pulumi.Context, resources []*pulumix.
return err
}

stackIdChan := make(chan string)
pulumi.Sprintf("%s-%s", ctx.Stack(), stackRandId.Result).ApplyT(func(id string) string {
stackIdChan <- id
return id
})
a.StackId = "stack-id"

if !ctx.DryRun() {
stackIdChan := make(chan string)
pulumi.Sprintf("%s-%s", ctx.Stack(), stackRandId.Result).ApplyT(func(id string) string {
stackIdChan <- id
return id
})

a.StackId = <-stackIdChan
a.StackId = <-stackIdChan
}

project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{
ProjectId: &a.GcpConfig.ProjectId,
Expand Down
Loading
Loading