Hi All- hoping you can help me out. I’m a bit stum...
# typescript
p
Hi All- hoping you can help me out. I’m a bit stumped. I’ve updated some dependencies to:
Copy code
"@pulumi/aws": "^5",
"@pulumi/awsx": "^0.40",
And something that used to work (a while back) now doesn’t, and I can’t figure out how to update my code to make it work again. I have an
awsx.ec2.Vpc
(notice it’s the CrossWalk VPC), and I’m trying to map the private subnet CIDR blocks so I can use them in a security group ingress rule. This code used to work.
privateCidrBlocks
resolves to
Promise<pulumi.Output<string | undefined>[]>
and
cidrBlocks
now expects
pulumi.Input<pulumi.Input<string>[]>
. I’d love a suggestion for how to get the CIDR blocks from the
vpc.privateSubnets
into a format that I can feed into the
cidrBlocks
input for the security group ingress. Any ideas?
c
And something that used to work (a while back) now doesn’t, and I can’t figure out how to update my code to make it work again.
What is not working? Are you getting type errors?
r
Can't you just use something like this?
Copy code
const privateCidrBlocks = vpc.getSubnetsIds('private');


const storageSG = new aws.ec2.SecurityGroup('storage', {
  description: 'Allow private subnet access to EFS',
  vpcId: vpc.id,
  ingress: [
    {
      cidrBlocks: privateCidrBlocks,
      fromPort: 2049,
      toPort: 2049,
      protocol: 'tcp'
    }
  ]
});
c
@rhythmic-whale-48997 that would just get the subnet IDs and not the CIDR blocks of those subnets, no?
r
F**ck, my bad. I just tried to run your code and it created a security group with 2 inbound rules for 2 private subnets that I have in my VPC. Are you sure that this doesn't work? 😅
p
Sadly, not for me, getting type errors.
Copy code
Diagnostics:
  pulumi:pulumi:Stack (demo_cluster-demo_cluster_sandbox):
    error: Running program '/Users/matthew.riedel/Source/devex/demo_cluster' failed with an unhandled exception:
    TSError: ⨯ Unable to compile TypeScript:
    index.ts(182,56): error TS2345: Argument of type '{ description: string; vpcId: pulumi.Output<string>; ingress: { cidrBlocks: Promise<pulumi.Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }[]; }' is not assignable to parameter of type 'SecurityGroupArgs'.
      Types of property 'ingress' are incompatible.
        Type '{ cidrBlocks: Promise<Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }[]' is not assignable to type 'Input<SecurityGroupIngress>[] | Promise<Input<SecurityGroupIngress>[]> | OutputInstance<Input<SecurityGroupIngress>[]> | undefined'.
          Type '{ cidrBlocks: Promise<Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }[]' is not assignable to type 'Input<SecurityGroupIngress>[]'.
            Type '{ cidrBlocks: Promise<pulumi.Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }' is not assignable to type 'Input<SecurityGroupIngress>'.
              Type '{ cidrBlocks: Promise<pulumi.Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }' is not assignable to type 'SecurityGroupIngress'.
                Types of property 'cidrBlocks' are incompatible.
                  Type 'Promise<Output<string | undefined>[]>' is not assignable to type 'Input<string>[] | Promise<Input<string>[]> | OutputInstance<Input<string>[]> | undefined'.
                    Type 'Promise<Output<string | undefined>[]>' is not assignable to type 'Promise<Input<string>[]>'.
                      Type 'Output<string | undefined>[]' is not assignable to type 'Input<string>[]'.
                        Type 'Output<string | undefined>' is not assignable to type 'Input<string>'.
                          Type 'OutputInstance<string | undefined>' is not assignable to type 'Input<string>'.
                            Type 'OutputInstance<string | undefined>' is not assignable to type 'OutputInstance<string>'.
                              Type 'string | undefined' is not assignable to type 'string'.
                                Type 'undefined' is not assignable to type 'string'.
    index.ts(216,46): error TS2345: Argument of type '{ description: string; vpcId: pulumi.Output<string>; ingress: { cidrBlocks: Promise<pulumi.Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }[]; }' is not assignable to parameter of type 'SecurityGroupArgs'.
      Types of property 'ingress' are incompatible.
        Type '{ cidrBlocks: Promise<Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }[]' is not assignable to type 'Input<SecurityGroupIngress>[] | Promise<Input<SecurityGroupIngress>[]> | OutputInstance<Input<SecurityGroupIngress>[]> | undefined'.
          Type '{ cidrBlocks: Promise<Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }[]' is not assignable to type 'Input<SecurityGroupIngress>[]'.
            Type '{ cidrBlocks: Promise<pulumi.Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }' is not assignable to type 'Input<SecurityGroupIngress>'.
              Type '{ cidrBlocks: Promise<pulumi.Output<string | undefined>[]>; fromPort: number; toPort: number; protocol: string; }' is not assignable to type 'SecurityGroupIngress'.
                Types of property 'cidrBlocks' are incompatible.
                  Type 'Promise<Output<string | undefined>[]>' is not assignable to type 'Input<string>[] | Promise<Input<string>[]> | OutputInstance<Input<string>[]> | undefined'.
                    Type 'Promise<Output<string | undefined>[]>' is not assignable to type 'Promise<Input<string>[]>'.

        at createTSError (/Users/matthew.riedel/Source/devex/demo_cluster/node_modules/ts-node/src/index.ts:261:12)
        at getOutput (/Users/matthew.riedel/Source/devex/demo_cluster/node_modules/ts-node/src/index.ts:367:40)
        at Object.compile (/Users/matthew.riedel/Source/devex/demo_cluster/node_modules/ts-node/src/index.ts:558:11)
        at Module.m._compile (/Users/matthew.riedel/Source/devex/demo_cluster/node_modules/ts-node/src/index.ts:439:43)
        at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
        at Object.require.extensions.<computed> [as .ts] (/Users/matthew.riedel/Source/devex/demo_cluster/node_modules/ts-node/src/index.ts:442:12)
        at Module.load (node:internal/modules/cjs/loader:981:32)
        at Function.Module._load (node:internal/modules/cjs/loader:822:12)
        at Module.require (node:internal/modules/cjs/loader:1005:19)
        at require (node:internal/modules/cjs/helpers:102:18)
l
Your code is working for me. However, for me, privateCidrBlocks is resolving to type
Promise<pulumi.Output<string>[]>
which is why I'm not getting that error. I can force the error by switching to this artificial code:
Copy code
const privateCidrBlocks = vpc.privateSubnets
    .then(subnets => subnets.map(subnet =>
          subnet.subnet.cidrBlock.length ? subnet.subnet.cidrBlock
                                         : undefined));
Is there any way that you could be translating cidrBlock to an
Output<string | undefined>
instead of the
Output<string>
that it originally was? There's nothing in your example code that I can see..
p
thanks @little-cartoon-10569 - the code I have is what I pasted in.. What versions of @pulumi/pulumi, @pulumi/awsx are you using?
l
Copy code
"devDependencies": {
    "@pulumi/aws": "5.3.0",
    "@pulumi/awsx": "^0.40.0",
    "@pulumi/cloudinit": "*",
    "@pulumi/pulumi": "3.30.0",
    "@pulumi/random": "4.5.0",
    "@pulumi/docker": "^3.2.0",
    "@pulumi/tls": "^4.3.0",
...
Anything I should change and try again?
p
Hmm. looks close to mine:
Copy code
"@pulumi/aws": "^5",
        "@pulumi/awsx": "^0.40",
        "@pulumi/eks": "^0.40",
        "@pulumi/kubernetes": "^3.1.2",
        "@pulumi/kubernetesx": "^0.1.6",
        "@pulumi/pulumi": "^3.0.0",
        "@pulumi/random": "^4.1.1",
        "ts-retry": "^2.3.3"
That resolved, for me, to:
Copy code
"@pulumi/aws@^5", "@pulumi/aws@^5.1.2":
  version "5.4.0"
"@pulumi/awsx@^0.40":
  version "0.40.0"
"@pulumi/eks@^0.40":
  version "0.40.0"
"@pulumi/kubernetes@^3.0.0", "@pulumi/kubernetes@^3.1.2":
  version "3.19.0"
"@pulumi/kubernetesx@^0.1.6":
  version "0.1.6"
"@pulumi/pulumi@^3.0.0":
  version "3.32.1"
So, pretty close to yours. 🤔 Maybe the old “blow away the node modules folder and re-run yarn” trick will fix it.
l
Oh yes, downloading the internet fixes everything... except DNS.
p
lol
otherwise I’m still stumped.. It’s just testing, so for now I got around it with
cidrBlocks: [vpc.vpc.cidrBlock]
- but obviously not ideal
l
Is your IDE (VSCode?) showing the error, or just Pulumi runtime? If you're seeing it in the IDE, then following the code into the libraries (ctrl-click, F12, whatever..) might take you into an unexpected version of the code, where transitive dependencies are your problem. There's no peerDependencies at play in Pulumi since it's all devDepenedencies, so different versions of the same code can happen, and cause this sort of problem...
I know that the next version of awsx will break this code, so maybe you're depending on something that's sneakily depending on that next version?
p
Is your IDE (VSCode?) showing the error,
I’m seeing it in WebStorm &
pulumi up
fails with the same error. The output above was from
pulumi up
.
There’s no peerDependencies at play in Pulumi since it’s all devDepenedencies
Interesting - I didn’t install
@pulumi/*
as dev dependencies. Should I have?
"dependencies": {
"@pulumi/aws": "^5",
"@pulumi/awsx": "^0.40",
"@pulumi/eks": "^0.40",
"@pulumi/kubernetes": "^3.1.2",
"@pulumi/kubernetesx": "^0.1.6",
"@pulumi/pulumi": "^3.0.0",
"@pulumi/random": "^4.1.1",
"ts-retry": "^2.3.3"
l
No, only devDependencies are needed, unless you have an automation-api app, but all dependencies are devDependencies too. You can though, and it will reduce the size of any packages you build (if any).
Everything runs at "build" time, as far as node is concerned.
For example, one of my clients' exposes all their stack references via interfaces defined in the project. Which means they have
@pulumi/pulumi
as in
dependencies
(for the StackReference stuff), but everything else is in
devDependencies
(since none of the "deployment" code is packaged and made available to other projects).
p
Good to know- we’re starting to build automation API apps 😄
This particular stack isn’t using that yet, though..
l
Then you can safely change it if you want to, but it's not necessary.
p
Hi @little-cartoon-10569 - finally have time to circle back to this. I’m trying to figure out how you’re getting:
Copy code
Promise<pulumi.Output<string>[]>
and I’m getting
Copy code
Promise<pulumi.Output<string | undefined>[]>
vpc.privateSubnets
ultimately boils down to a list of
aws.ec2.Subnet
types, and based on the definition, it seems
cidrBlock
might be undefined. So that kind of explains what I’m seeing - it’s an array of `pulumi.Output`s that might be a string or undefined. Did you do anything to assert that
cidrBlock
would be defined?
Also:
I know that the next version of awsx will break this code, so maybe you’re depending on something that’s sneakily depending on that next version?
Are you able to elaborate on that a little more? Is there something I could be doing here to prepare for this change?
l
No, I think it's just that awsx 1 is in the pipeline. I don't know what will change, maybe a look at the repo will help?
My aws/ec2/subnet.d.ts has this:
Copy code
/**
     * The CIDR block for the subnet.
     */
    readonly cidrBlock: pulumi.Output<string>;
Looks like 4.33.1 is the latest to have this shape code.
I think that if you're requiring that all your subnets have IPv4 CIDR blocks, then you can just add an assert:
Copy code
const privateCidrBlocks = vpc.privateSubnets.then(subnets => subnets.map(subnet => subnet.subnet.cidrBlock!));
p
I tried the assert, but my IDE still complained about that (didn’t actually try with a
pulumi up
, though). Went for maximum effort 😉
Copy code
function getCidrBlocks(): Promise<pulumi.Output<string>[]> {
  return vpc.privateSubnetIds.then(ids => {
    return ids.map(id => id.apply(i => pulumi.output(aws.ec2.getSubnet({id: i})).cidrBlock));
  });
}

const storageSG = new aws.ec2.SecurityGroup('storage', {
  description: 'Allow private subnet access to EFS',
  vpcId: vpc.id,
  ingress: [
    {
      cidrBlocks: getCidrBlocks(),
      fromPort: 2049,
      toPort: 2049,
      protocol: 'tcp'
    }
  ]
});
seems to be working. Would be nice if
awsx.ec2.Vpc
had a
getCidrBlocks
method for this. I reckon this will be a fairly common use case?
I should make that generic and allow passing in a subnet type.
In case this helps anyone else.