@@ -32,21 +32,50 @@ def GetManagedVmGroupClass(cloud):
3232
3333
3434class BaseManagedVmGroup (resource .BaseResource ):
35- """Base class representing a Managed VM group."""
35+ """Base class representing a Managed VM group.
36+
37+ Attributes:
38+ name: The name of the managed VM group.
39+ region: The region where the managed VM group is located.
40+ vms: A sequence of all VMs in the managed VM group.
41+
42+ Internal Attributes:
43+ spec: The spec of the managed VM group.
44+ vm_config: A virtual machine instance representing the prototype/template VM
45+ configuration used to clone new VMs in the group. Individual VM operations
46+ like `_Create()` and `_Delete()` are NOT called on this object (creation
47+ and deletion are managed by the VM group at the cloud level), but it
48+ defines the template settings.
49+ zoned_vm_configs: A list of all template VM instances, one for each
50+ configured zone in the group. Used to pre-create and cleanup zone-specific
51+ VM dependencies (like firewalls, networks, subnets) in every candidate
52+ zone.
53+ _vms: A mapping of VM names to active VM objects representing actual
54+ instances running in the cloud.
55+ """
3656
3757 name : str
58+ region : str
3859
3960 RESOURCE_TYPE = 'BaseManagedVmGroup'
4061 CLOUD = None
4162
4263 def __init__ (
4364 self ,
4465 spec : vm_group_decoders .VmGroupSpec ,
45- vm_config : virtual_machine .BaseVirtualMachine ,
66+ vm_configs : list [ virtual_machine .BaseVirtualMachine ] ,
4667 ):
4768 super ().__init__ ()
4869 self .spec : vm_group_decoders .VmGroupSpec = spec
49- self .vm_config = vm_config
70+ assert vm_configs , 'No VM configs provided.'
71+ # `vm_config` is the primary prototype/template VM configuration.
72+ # We do NOT run `_Create` or `_Delete` on it. Instead, we use it to
73+ # copy-clone the target VMs.
74+ self .vm_config = vm_configs [0 ]
75+ # `zoned_vm_configs` contains a template VM configuration for each zone.
76+ # Used to create/delete dependencies (e.g. networks, firewalls) in all
77+ # zones.
78+ self .zoned_vm_configs = vm_configs
5079 self .vm_config .metadata ['in_managed_vm_group' ] = True
5180 # When we clone the VM config and rename it, our assumptions about the
5281 # disk names are wrong.
@@ -56,22 +85,37 @@ def __init__(
5685
5786 self .name = self .vm_config .name
5887 self .vm_count = self .spec .vm_count
88+ # `_vms` mapping VM names to active VM objects representing actual instances
89+ # running in the cloud. They are populated by copy-cloning `vm_config` and
90+ # initializing names/zones. Then passed back to the benchmark spec for
91+ # benchmarking.
5992 self ._vms : dict [str , virtual_machine .BaseVirtualMachine ] = {}
6093 self ._deleted_vms : list [virtual_machine .BaseVirtualMachine ] = []
6194
62- self .region : str | None = None
63- self .zone : str | None = None
95+ self .zones : list [str ] = [vm .zone for vm in vm_configs ]
6496
6597 self .last_operation_start_time : float | None = None
6698 self .last_ready_time : float | None = None
6799
100+ @property
101+ def is_regional (self ) -> bool :
102+ assert self .zones
103+ return len (self .zones ) > 1 or self .zones [0 ] == self .region
104+
105+ @property
106+ def zone (self ) -> str | None :
107+ assert self .zones
108+ if self .is_regional :
109+ return None
110+ return self .zones [0 ]
111+
68112 def GetResourceMetadata (self ) -> dict [Any , Any ]:
69113 metadata = super ().GetResourceMetadata ().copy ()
70114 vm = (list (self .vms ) + self ._deleted_vms + [self .vm_config ])[0 ]
71115 metadata .update (vm .GetResourceMetadata ())
72116 metadata ['region' ] = self .region
73- metadata ['zone ' ] = self .zone
74- metadata ['is_regional' ] = self .zone is None
117+ metadata ['zones ' ] = self .zones
118+ metadata ['is_regional' ] = self .is_regional
75119 return metadata
76120
77121 @property
@@ -80,10 +124,16 @@ def vms(self) -> Sequence[virtual_machine.BaseVirtualMachine]:
80124 return list (self ._vms .values ())
81125
82126 def _CreateDependencies (self ):
83- self .vm_config ._CreateDependencies () # pylint: disable=protected-access
127+ background_tasks .RunThreaded (
128+ lambda vm : vm ._CreateDependencies (), # pylint: disable=protected-access
129+ self .zoned_vm_configs ,
130+ )
84131
85132 def _DeleteDependencies (self ):
86- self .vm_config ._DeleteDependencies () # pylint: disable=protected-access
133+ background_tasks .RunThreaded (
134+ lambda vm : vm ._DeleteDependencies (), # pylint: disable=protected-access
135+ self .zoned_vm_configs ,
136+ )
87137
88138 @dataclasses .dataclass
89139 class VmReference :
0 commit comments