sparse-intern-71089
11/29/2021, 8:56 AMprehistoric-activity-61023
11/29/2021, 8:57 AMprehistoric-activity-61023
11/29/2021, 9:00 AMSite
) that expects another component resource (e.g. Region
) as its dependency (you can pass it in the constructor).important-magician-41327
11/29/2021, 9:01 AMprehistoric-activity-61023
11/29/2021, 9:02 AMprehistoric-activity-61023
11/29/2021, 9:02 AMRegion
class to the constructor of Site
prehistoric-activity-61023
11/29/2021, 9:03 AMclass Site(pulumi.ComponentResource):
def __init__(
self,
name: str,
region: Region,
opts: Optional[pulumi.ResourceOptions] = None,
):
super().__init__("something:something:Site", name, {}, opts)
...
prehistoric-activity-61023
11/29/2021, 9:04 AMSite
constructor:
region = Region(...)
site = Site("my-site", region=region)
prehistoric-activity-61023
11/29/2021, 9:05 AMprehistoric-activity-61023
11/29/2021, 9:06 AMimportant-magician-41327
11/29/2021, 9:07 AMimportant-magician-41327
11/29/2021, 9:07 AMsite = Site("my-site", region=region)
and this is the “trick”?prehistoric-activity-61023
11/29/2021, 9:08 AMRegion
object to the Site
class instance so it can access its properties.prehistoric-activity-61023
11/29/2021, 9:09 AMclass Site(pulumi.ComponentResource):
def __init__(
self,
name: str,
region: Region,
opts: Optional[pulumi.ResourceOptions] = None,
):
super().__init__("something:something:Site", name, {}, opts)
=> self.region_name = region.name
prehistoric-activity-61023
11/29/2021, 9:09 AM__init__
method so based on that you can create additional resourcesprehistoric-activity-61023
11/29/2021, 9:10 AMprehistoric-activity-61023
11/29/2021, 9:11 AMclass GKECluster(ComponentResource):
def __init__(
self,
name: str,
network: gcp.compute.Network,
opts: Optional[ResourceOptions] = None,
):
super().__init__("jakub-bacic:gcp:GKECluster", name, {}, opts)
self.subnetwork = gcp.compute.Subnetwork(
name,
ip_cidr_range=subnetwork_cidr_block,
network=network.name,
secondary_ip_ranges=[
gcp.compute.SubnetworkSecondaryIpRangeArgs(
range_name="pods", ip_cidr_range="10.2.0.0/16"
),
gcp.compute.SubnetworkSecondaryIpRangeArgs(
range_name="services", ip_cidr_range="10.3.0.0/16"
),
],
private_ip_google_access=True,
opts=ResourceOptions(parent=self),
)
...
prehistoric-activity-61023
11/29/2021, 9:11 AMimportant-magician-41327
11/29/2021, 9:11 AMprehistoric-activity-61023
11/29/2021, 9:12 AMGKECluster
component resource expects the user to pass the already existing gcp.compute.Network
prehistoric-activity-61023
11/29/2021, 9:12 AMprehistoric-activity-61023
11/29/2021, 9:13 AMgke = GKECluster(
common.default_resource_name,
network=common.vpc_network,
opts=pulumi.ResourceOptions(
provider=common.gcp_provider,
),
)
^ here’s how I create an instance of this resourceprehistoric-activity-61023
11/29/2021, 9:13 AMnetwork
argument is up to you (as you can see, I import it from another module called common
)billowy-army-68599
important-magician-41327
11/29/2021, 4:46 PMbillowy-army-68599
important-magician-41327
11/29/2021, 4:48 PMimportant-magician-41327
11/29/2021, 4:49 PMimportant-magician-41327
11/30/2021, 4:10 PMimport pulumi as pulumi
import pulumi_aws as aws
class Region(pulumi.ComponentResource):
def __init__(self,name,region,aws_providers,opts: pulumi.ResourceOptions = None):
self
name: str
super().__init__('Region', name, None, opts)
# #Get all available AZ's in VPC
self.available = aws.get_availability_zones(state="available",
opts=pulumi.ResourceOptions(
provider=aws_providers.get(region)
)
)
#Create VPC
self.vpc = aws.ec2.Vpc(f"vpc_sdwan_{region}",
cidr_block=f"10.0.0.0/16",
tags={
"Name": f"vpc_sdwan_{region}",
"Owner": "cloudPOC"},
opts=pulumi.ResourceOptions(
provider=aws_providers.get(region),
)
)
class Site(pulumi.ComponentResource):
def __init__(self,name,site,region,aws_providers,region_eu,opts: pulumi.ResourceOptions = None):
self
name: str
self.region = region,
self.aws_providers = aws_providers
self.region_eu = region_eu
super().__init__('Site', name, None, opts)
self.subnet_lan = aws.ec2.Subnet(f"subnet_lan_site{site}",
vpc_id=region_eu.vpc.id,
cidr_block=f"10.0.0.0/28",
availability_zone=region_eu.available.names[0],
tags={
"Name": f"subnet_lan_site{site}",
"Owner": "cloudPOC"
},
opts=pulumi.ResourceOptions(
provider=aws_providers.get(region),
)
)
#create AWS providers for every region
regions=["eu-central-1","us-east-1"]
aws_providers = {
region: aws.Provider(f"aws-provider-{region}", region=region)
for region in regions
}
#create Region Object for every region
region_eu = Region("Region_eu-central-1","eu-central-1",aws_providers)
region_us = Region("Region_us-east-1","us-east-1",aws_providers)
#create sites
site1 = Site("Site1",1,"eu-central-1",aws_providers,region_eu)
site2 = Site("Site2",2,"eu-central-1",aws_providers,region_eu)
site3 = Site("Site3",3,"us-east-1",aws_providers,region_eu)
site4 = Site("Site4",4,"us-east-1",aws_providers,region_eu)
prehistoric-activity-61023
11/30/2021, 6:36 PMRegion
instances if that fits the real life scenario.prehistoric-activity-61023
11/30/2021, 6:37 PMprehistoric-activity-61023
11/30/2021, 6:40 PMRegion
class like this:
class Region(pulumi.ComponentResource):
def __init__(self, name: str, region: str,opts: Optional[pulumi.ResourceOptions] = None):
super().__init__('Region', name, None, opts)
...
#Create VPC
self.vpc = aws.ec2.Vpc(
f"vpc_sdwan_{region}",
cidr_block="10.0.0.0/16",
tags={
"Name": f"vpc_sdwan_{region}",
"Owner": "cloudPOC",
},
opts=pulumi.ResourceOptions(
==> parent=self,
),
)
and you can assign the provider when creating an instance of this class:
region_eu = Region(
"Region_eu-central-1",
region="eu-central-1",
=> opts=pulumi.ResourceOptions(
=> provider=aws_providers_for_this_region,
=> ),
)
prehistoric-activity-61023
11/30/2021, 6:44 PMRegion
component resource with default provider (in case you have a much simpler project where you don’t create providers explicitly)
• assigning parent
gives you a nice, hierarchical view over your resources instead of flat/one-level mess (just implement the changes above and see the difference in pulumi preview
)
BTW, the way you’re gonna assign parents is totally up to you. You can even make Region
a parent of Site
resource if that fits your infrastructure design 🙂.important-magician-41327
12/01/2021, 8:47 AMimport pulumi as pulumi
import pulumi_aws as aws
class Region(pulumi.ComponentResource):
def __init__(self, name: str, region: str, opts: pulumi.ResourceOptions = None):
super().__init__('Region', name, None, opts)
# #Get all available AZ's in VPC
self.available = aws.get_availability_zones(state="available",
opts=pulumi.ResourceOptions(
parent=self
)
)
#Create VPC
self.vpc = aws.ec2.Vpc(f"vpc_sdwan_{region}",
cidr_block=f"10.0.0.0/16",
tags={
"Name": f"vpc_sdwan_{region}",
"Owner": "cloudPOC"},
opts=pulumi.ResourceOptions(
parent=self,
)
)
class Site(pulumi.ComponentResource):
def __init__(self,name,site,region,aws_providers,region_eu,opts: pulumi.ResourceOptions = None):
self
name: str
self.region = region,
self.aws_providers = aws_providers
self.region_eu = region_eu
super().__init__('Site', name, None, opts)
self.subnet_lan = aws.ec2.Subnet(f"subnet_lan_site{site}",
vpc_id=region_eu.vpc.id,
cidr_block=f"10.0.0.0/28",
availability_zone=region_eu.available.names[0],
tags={
"Name": f"subnet_lan_site{site}",
"Owner": "cloudPOC"
},
opts=pulumi.ResourceOptions(
provider=aws_providers.get(region),
)
)
#create Region Object for every region
region_eu = Region("Region_eu-central-1", "eu-central-1", opts= pulumi.ResourceOptions(provider="eu-central-1",))
important-magician-41327
12/01/2021, 8:47 AMFile "/home/coder/myproject/venv/lib/python3.8/site-packages/pulumi/runtime/stack.py", line 133, in __init__
func()
File "/home/coder/.pulumi/bin/pulumi-language-python-exec", line 106, in <lambda>
coro = pulumi.runtime.run_in_stack(lambda: runpy.run_path(args.PROGRAM, run_name='__main__'))
File "/usr/lib/python3.8/runpy.py", line 282, in run_path
return _run_code(code, mod_globals, init_globals,
File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/home/coder/myproject/./__main__.py", line 59, in <module>
region_eu = Region("Region_eu-central-1", "eu-central-1", opts= pulumi.ResourceOptions(provider="eu-central-1",))
File "/home/coder/myproject/./__main__.py", line 7, in __init__
super().__init__('Region', name, None, opts)
File "/home/coder/myproject/venv/lib/python3.8/site-packages/pulumi/resource.py", line 913, in __init__
Resource.__init__(self, t, name, False, props, opts, remote, False)
File "/home/coder/myproject/venv/lib/python3.8/site-packages/pulumi/resource.py", line 772, in __init__
providers = convert_providers(opts.provider, opts.providers)
File "/home/coder/myproject/venv/lib/python3.8/site-packages/pulumi/runtime/resource.py", line 651, in convert_providers
return convert_providers(None, [provider])
File "/home/coder/myproject/venv/lib/python3.8/site-packages/pulumi/runtime/resource.py", line 661, in convert_providers
result[p.package] = p
AttributeError: 'str' object has no attribute 'package'
error: an unhandled error occurred: Program exited with non-zero exit code: 1
important-magician-41327
12/01/2021, 8:54 AM#create Region Object for every region
for region in regions:
aws_region[region] = Region(f"Region_{region}", region, opts= pulumi.ResourceOptions(provider=region))
#create sites
site1 = Site("Site1",1,"eu-central-1",aws_region["eu-central-1"])
site2 = Site("Site2",1,"eu-central-1",aws_region["eu-central-1"])
site3 = Site("Site3",1,"eu-central-1",aws_region["us-east-1"])
site4 = Site("Site4",1,"eu-central-1",aws_region["us-east-1"])
important-magician-41327
12/01/2021, 8:56 AMprehistoric-activity-61023
12/01/2021, 10:14 AMopts: pulumi.ResourceOptions = None
is a wrong type hint, it should be opts: Optional[pulumi.ResourceOptions]
(if it’s not optional, it shouldn’t be None
at any point)
• you’re passing a str
value instead of provider instance in:
region_eu = Region("Region_eu-central-1", "eu-central-1", opts= pulumi.ResourceOptions(provider="eu-central-1",))
prehistoric-activity-61023
12/01/2021, 10:15 AMprehistoric-activity-61023
12/01/2021, 10:15 AMprehistoric-activity-61023
12/01/2021, 10:16 AM