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 Siteprehistoric-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.nameprehistoric-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.Networkprehistoric-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: 1important-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