Hi everyone, I am hitting a race condition b/w 2 r...
# general
r
Hi everyone, I am hitting a race condition b/w 2 resources. first resources is creating a vpc and the second one is creating subnets. for the second one i have a get_vpc block
vpc_info = aws.ec2.get_vpc(id=resource_vpc.id, opts=ResourceOptions(depends_on=[resource_vpc]))
to get the ipv6 subnet… however, if i run the whole stack in one go it fails… if i run it in stages i.e. create just the vpc and then create the subnet in second try it works fine. i have tried the depends_on mechanism but doesnt seem to be working… any idea what I might be doing wrong?
w
If you created the VPC in Pulumi then you can reference the resource when creating the subnet. No need to use get_vpc() Ie reference my_vpc.id in your subnet resource declaration.
r
so yes i am doing that, however in my case i need the string representation of the IPv6 CIDR allocated for this VPC…for that I am running the get_vpc…it is giving me the IPv6 CIDR in string… I was having trouble converting the
resource_vpc.ipv6_cidr_block
object to string…
w
Maybe a
.apply()
scenario. But in what context do you need to convert
resource_vpc.ipv6_cidr_block
to a string?
r
sorry @witty-candle-66007 have been away so I am dynamically calculating IPv6 subnets out of the IPv6 CIDR allocated to the VPC. I am using the netaddr library. The library needs the CIDR in str format
ipv6_network = IPNetwork(cidr)
Out of this i can then use the subnet method for a specific prefix length to generated the number of subnets per vpc. `ipv6_network.subnet(prefix``
how would i get the string version of it using apply… I had tried the concat and apply version too but couldnt get far with that too
w
@rhythmic-lamp-79430 I believe you want the
_output
form of this call, which will take inputs and return outputs, ensuring that your call happens once the inputs are available (the VPC has been created).
Copy code
vpc_info = aws.ec2.get_vpc_output(id=resource_vpc.id)
l
If you have the Pulumi resource and can access the returned ipv6_cidr_block, then you should be able to use
apply()
to turn that block into one of the blocks for a subnets. Something like this (excuse the poor pseudocode, it's heavily typescript-influenced...):
Copy code
ipv6_network.subnet(resource_vpc.ipv6_cidr_block.apply(cidr => IPNetwork(cidr)));
The value passed to
IPNework()
is a string, and its return value is wrapped in a new Output before being passed to
subnet()
. But since
subnet()
is a Pulumi function, it handles Output parameters just fine.
r
Thanks @white-balloon-205 and @little-cartoon-10569 for the suggestion and example..let me try it now
@white-balloon-205 i have tried this
vpc_info = aws.ec2.get_vpc_output(id=resource_vpc.id, opts=pulumi.ResourceOptions(depends_on=[resource_vpc]))
and is failing similar to .get_vpc
@little-cartoon-10569 while using your mechanism i am still getting
TypeError: 'Output' object is not callable
l
That's probably a problem with my pseudocode. The objective is to call
apply()
on an object, do your work inside the apply() callback, then pass the result of
apply()
to a Pulumi function or property.
I'm not sure what the python syntax is, but there'll be plenty of examples about. Let me find one for you.
In this example, the
bucket_name
on line 40 is an output,
public_read_policy_for_bucket()
is a function that operates on a string (which is the value "inside"
bucket_name
), the
bucket_name
on line 32 is a string, and the thing returned from
public_read_policy_for_bucket()
is another Output which is used as the value of
policy
.
I think you want something very close to this.
r
thanks @little-cartoon-10569 Let me read this and test
looks like what i need but somehow i am unable to make it work
so i have done this fyi.
Copy code
ipv6_cidr_block = resource_vpc.ipv6_cidr_block
ipv6_subnets_generator = ipv6_cidr_block.apply(get_ipv6_subnets_of)
Copy code
def get_ipv6_subnets_of(cidr):
    ipv6_network = IPNetwork(cidr)
    return ipv6_network.subnet(64)
ipv6_network.subnet(64)
give a generator which I am using in the subnet creation to get the next available one
ipv6_cidr = str(next(ipv6_subnets_generator))
The error this time is different though
Copy code
File "./__main__.py", line 46, in <module>
        ipv6_cidr = str(next(ipv6_subnets_generator))
    TypeError: 'Output' object is not an iterator
l
Yes, the thing returned from any
apply()
is always an Output; you return a string or iterator or whatever, and Pulumi wraps it in an Output before your code gets it. So you need to call
apply()
on it too. Usually, the best thing is to make the function that you pass to
apply()
return the ultimate thing you need, not an interim thing:
Copy code
ipv6_cidr = ipv6_cidr_block.apply(myfunc);
def myfunc(cidr):
  ipv6 _network = IPNetwork(cidr)
  return str(next(ipv6_network.subnet(64)))
But you can do it any way you like, so long as you're always inside a call to
apply()
when you're operating on a value that's contained in an Output.
r
yeah I tried its with
return str(next(ipv6_network.subnet(64)))
too…but then the generator doesnt work 🙂
l
Is that because
subnet(64)
returns an Output? If it does, then you have to use
apply()
again.
r
yes @little-cartoon-10569 subnet(64) returns a list of subnet objects
l
If it's not working yet, we'll need to see a larger chunk of code, maybe in a gist or in collapsible code snippet in Slack. The current problem is probably something like you're calling the generator outside the
apply()
, or you're not taking an Output parameter and you need to, or something like that.
r
sure @little-cartoon-10569