Skip to content

Commit

Permalink
HCL2/NodeJS: fix proxy apply lowering for promises (#4317)
Browse files Browse the repository at this point in the history
Applies cannot be proxied when the applied value is a promise.

Fixes #4315.
  • Loading branch information
pgavlin committed Apr 7, 2020
1 parent 2f22c1c commit 00f1433
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 16 deletions.
8 changes: 4 additions & 4 deletions pkg/codegen/internal/test/testdata/aws-fargate.pp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const subnets = vpc.then(vpc => aws.ec2.getSubnetIds({
}));
// Create a security group that permits HTTP ingress and unrestricted egress.
const webSecurityGroup = new aws.ec2.SecurityGroup("webSecurityGroup", {
vpcId: vpc.id,
vpcId: vpc.then(vpc => vpc.id),
egress: [{
protocol: "-1",
fromPort: 0,
Expand Down Expand Up @@ -43,14 +43,14 @@ const taskExecRolePolicyAttachment = new aws.iam.RolePolicyAttachment("taskExecR
});
// Create a load balancer to listen for HTTP traffic on port 80.
const webLoadBalancer = new aws.elasticloadbalancingv2.LoadBalancer("webLoadBalancer", {
subnets: subnets.ids,
subnets: subnets.then(subnets => subnets.ids),
securityGroups: [webSecurityGroup.id],
});
const webTargetGroup = new aws.elasticloadbalancingv2.TargetGroup("webTargetGroup", {
port: 80,
protocol: "HTTP",
targetType: "ip",
vpcId: vpc.id,
vpcId: vpc.then(vpc => vpc.id),
});
const webListener = new aws.elasticloadbalancingv2.Listener("webListener", {
loadBalancerArn: webLoadBalancer.arn,
Expand Down Expand Up @@ -85,7 +85,7 @@ const appService = new aws.ecs.Service("appService", {
taskDefinition: appTask.arn,
networkConfiguraiton: {
assignPublicIp: true,
subnets: subnets.ids,
subnets: subnets.then(subnets => subnets.ids),
securityGroups: [webSecurityGroup.id],
},
loadBalancers: [{
Expand Down
2 changes: 1 addition & 1 deletion pkg/codegen/internal/test/testdata/aws-webserver.pp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const server = new aws.ec2.Instance("server", {
},
instanceType: "t2.micro",
securityGroups: [securityGroup.name],
ami: ami.id,
ami: ami.then(ami => ami.id),
userData: `#!/bin/bash
echo "Hello, World!" > index.html
nohup python -m SimpleHTTPServer 80 &
Expand Down
18 changes: 8 additions & 10 deletions pkg/codegen/nodejs/gen_program_expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,16 @@ func (g *generator) genApply(w io.Writer, expr *model.FunctionCallExpression) {

// If all of the arguments are promises, use promise methods. If any argument is an output, convert all other args
// to outputs and use output methods.
//
// TODO(pdg): unions
isPromise := make([]bool, len(applyArgs))
allPromises := true
isOutput := make([]bool, len(applyArgs))
anyOutputs := false
for i, arg := range applyArgs {
_, isPromise[i] = arg.Type().(*model.PromiseType)
allPromises = allPromises && isPromise[i]
isOutput[i] = isOutputType(arg.Type())
anyOutputs = anyOutputs || isOutput[i]
}

apply, all := "apply", "pulumi.all"
if allPromises {
apply, all = "then", "Promise.all"
apply, all := "then", "Promise.all"
if anyOutputs {
apply, all = "apply", "pulumi.all"
}

if len(applyArgs) == 1 {
Expand All @@ -156,7 +154,7 @@ func (g *generator) genApply(w io.Writer, expr *model.FunctionCallExpression) {
if i > 0 {
g.Fgen(w, ", ")
}
if isPromise[i] {
if anyOutputs && !isOutput[i] {
g.Fgenf(w, "pulumi.output(%v)", o)
} else {
g.Fgenf(w, "%v", o)
Expand Down
17 changes: 16 additions & 1 deletion pkg/codegen/nodejs/gen_program_lower.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,27 @@ import (
"github.com/pulumi/pulumi/sdk/go/common/util/contract"
)

func isOutputType(t model.Type) bool {
switch t := t.(type) {
case *model.OutputType:
return true
case *model.UnionType:
for _, t := range t.ElementTypes {
if _, isOutput := t.(*model.OutputType); isOutput {
return true
}
}
}
return false
}

// canLiftScopeTraversalExpression returns true if this variable access expression can be lifted. Any variable access
// expression that does not contain references to potentially-undefined values (e.g. optional fields of a resource) can
// be lifted.
func (g *generator) canLiftScopeTraversalExpression(v *model.ScopeTraversalExpression) bool {
for _, p := range v.Parts {
if model.IsOptionalType(model.GetTraversableType(p)) {
t := model.GetTraversableType(p)
if model.IsOptionalType(t) || !isOutputType(t) {
return false
}
}
Expand Down

0 comments on commit 00f1433

Please sign in to comment.