inmanta-module-openstack 6.0.0__tar.gz → 6.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/PKG-INFO +1 -1
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_module_openstack.egg-info/PKG-INFO +1 -1
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_module_openstack.egg-info/SOURCES.txt +8 -1
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/common/base.py +86 -15
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/common/deps.py +60 -11
- inmanta_module_openstack-6.1.1/inmanta_plugins/openstack/compute/flavor.py +364 -0
- inmanta_module_openstack-6.1.1/inmanta_plugins/openstack/compute/server_group.py +87 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/compute/virtual_machine.py +97 -26
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/model/_init.cf +121 -6
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/network_port.py +138 -39
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/security_group.py +38 -7
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/setup.cfg +1 -1
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/setup.cfg +1 -1
- inmanta_module_openstack-6.1.1/tests/test_common_base.py +60 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_dependency_handling.py +64 -0
- inmanta_module_openstack-6.1.1/tests/test_flavor.py +659 -0
- inmanta_module_openstack-6.1.1/tests/test_network_port_missing_network.py +177 -0
- inmanta_module_openstack-6.1.1/tests/test_network_port_shared_network.py +264 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_neutron.py +17 -7
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_nova.py +25 -0
- inmanta_module_openstack-6.1.1/tests/test_security_group_ethertype.py +157 -0
- inmanta_module_openstack-6.1.1/tests/test_server_group.py +398 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_trunk.py +2 -1
- inmanta_module_openstack-6.1.1/tests/test_vm_boot_nic.py +322 -0
- inmanta_module_openstack-6.0.0/inmanta_plugins/openstack/compute/flavor.py +0 -181
- inmanta_module_openstack-6.0.0/tests/test_flavor.py +0 -227
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/MANIFEST.in +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/README.md +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_module_openstack.egg-info/dependency_links.txt +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_module_openstack.egg-info/not-zip-safe +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_module_openstack.egg-info/requires.txt +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_module_openstack.egg-info/top_level.txt +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/__init__.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/common/__init__.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/compute/__init__.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/compute/host_aggregate.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/identity/__init__.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/identity/group.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/identity/group_role.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/identity/keystone_base.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/identity/project.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/identity/role.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/identity/user.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/image/__init__.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/image/image.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/__init__.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/floating_ip.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/network.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/qos_policy.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/router.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/router_port.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/subnet.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/subnet_v6.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/trunk_network.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/network/trunk_port.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/quota/__init__.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/inmanta_plugins/openstack/quota/quota.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/pyproject.toml +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_block_devices.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_examples.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_host_aggregate.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_image.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_keystone.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_network_port_fixed_ips.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_network_port_security_groups.py +0 -0
- {inmanta_module_openstack-6.0.0 → inmanta_module_openstack-6.1.1}/tests/test_quota.py +0 -0
|
@@ -16,6 +16,7 @@ inmanta_plugins/openstack/common/deps.py
|
|
|
16
16
|
inmanta_plugins/openstack/compute/__init__.py
|
|
17
17
|
inmanta_plugins/openstack/compute/flavor.py
|
|
18
18
|
inmanta_plugins/openstack/compute/host_aggregate.py
|
|
19
|
+
inmanta_plugins/openstack/compute/server_group.py
|
|
19
20
|
inmanta_plugins/openstack/compute/virtual_machine.py
|
|
20
21
|
inmanta_plugins/openstack/identity/__init__.py
|
|
21
22
|
inmanta_plugins/openstack/identity/group.py
|
|
@@ -42,6 +43,7 @@ inmanta_plugins/openstack/network/trunk_port.py
|
|
|
42
43
|
inmanta_plugins/openstack/quota/__init__.py
|
|
43
44
|
inmanta_plugins/openstack/quota/quota.py
|
|
44
45
|
tests/test_block_devices.py
|
|
46
|
+
tests/test_common_base.py
|
|
45
47
|
tests/test_dependency_handling.py
|
|
46
48
|
tests/test_examples.py
|
|
47
49
|
tests/test_flavor.py
|
|
@@ -49,8 +51,13 @@ tests/test_host_aggregate.py
|
|
|
49
51
|
tests/test_image.py
|
|
50
52
|
tests/test_keystone.py
|
|
51
53
|
tests/test_network_port_fixed_ips.py
|
|
54
|
+
tests/test_network_port_missing_network.py
|
|
52
55
|
tests/test_network_port_security_groups.py
|
|
56
|
+
tests/test_network_port_shared_network.py
|
|
53
57
|
tests/test_neutron.py
|
|
54
58
|
tests/test_nova.py
|
|
55
59
|
tests/test_quota.py
|
|
56
|
-
tests/
|
|
60
|
+
tests/test_security_group_ethertype.py
|
|
61
|
+
tests/test_server_group.py
|
|
62
|
+
tests/test_trunk.py
|
|
63
|
+
tests/test_vm_boot_nic.py
|
|
@@ -18,9 +18,11 @@ Contact: code@inmanta.com
|
|
|
18
18
|
|
|
19
19
|
import openstack.connection
|
|
20
20
|
import openstack.exceptions
|
|
21
|
-
from inmanta.agent.handler import CRUDHandler, cache
|
|
21
|
+
from inmanta.agent.handler import CRUDHandler, SkipResource, cache
|
|
22
22
|
from inmanta.execute import proxy
|
|
23
23
|
from inmanta.resources import ManagedResource, PurgeableResource
|
|
24
|
+
from openstack.network.v2.network import Network as OSNetwork
|
|
25
|
+
from openstack.network.v2.subnet import Subnet as OSSubnet
|
|
24
26
|
|
|
25
27
|
CRED_TIMEOUT = 600 # OpenStackHandler
|
|
26
28
|
|
|
@@ -94,8 +96,12 @@ class Port(OpenstackResource):
|
|
|
94
96
|
|
|
95
97
|
fields = ("name", "address", "subnet", "network")
|
|
96
98
|
name: str
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
# A NetworkPort does not need a fixed ip, nor to be pinned to a subnet: its getters
|
|
100
|
+
# report None for both when the relation is unset. RouterPort re-declares them as
|
|
101
|
+
# mandatory, which its model cardinality guarantees. The network is always there,
|
|
102
|
+
# taken from the relation itself or from the subnet the port is pinned to.
|
|
103
|
+
address: str | None
|
|
104
|
+
subnet: str | None
|
|
99
105
|
network: str
|
|
100
106
|
|
|
101
107
|
@staticmethod
|
|
@@ -169,15 +175,19 @@ class OpenStackHandler(CRUDHandler):
|
|
|
169
175
|
"""
|
|
170
176
|
Retrieve the id of a project based on the given name
|
|
171
177
|
"""
|
|
178
|
+
# A project-scoped token already knows its own project id. Use it before
|
|
179
|
+
# querying Keystone: non-admin users may be forbidden to get/list projects.
|
|
180
|
+
current_project_id = self._connection.current_project_id
|
|
181
|
+
if name == resource.admin_project_name and current_project_id:
|
|
182
|
+
return current_project_id
|
|
183
|
+
|
|
172
184
|
project = self._connection.identity.find_project(name)
|
|
173
185
|
if project:
|
|
174
186
|
return project.id
|
|
175
187
|
|
|
176
188
|
# fallback for non-admins: if we’re scoped to a project and its name matches
|
|
177
|
-
if
|
|
178
|
-
current = self._connection.identity.get_project(
|
|
179
|
-
self._connection.current_project_id
|
|
180
|
-
)
|
|
189
|
+
if current_project_id:
|
|
190
|
+
current = self._connection.identity.get_project(current_project_id)
|
|
181
191
|
if current and current.name == name:
|
|
182
192
|
return current.id
|
|
183
193
|
|
|
@@ -185,14 +195,30 @@ class OpenStackHandler(CRUDHandler):
|
|
|
185
195
|
f"Project not found or not visible: {name}"
|
|
186
196
|
)
|
|
187
197
|
|
|
188
|
-
def get_network(
|
|
198
|
+
def get_network(
|
|
199
|
+
self,
|
|
200
|
+
project_id: str | None = None,
|
|
201
|
+
name: str | None = None,
|
|
202
|
+
network_id: str | None = None,
|
|
203
|
+
include_shared: bool = False,
|
|
204
|
+
include_external: bool = False,
|
|
205
|
+
) -> OSNetwork | None:
|
|
189
206
|
"""
|
|
190
207
|
Retrieve the network id based on the name of the network
|
|
208
|
+
|
|
209
|
+
:param include_shared: also consider networks owned by another project when the
|
|
210
|
+
project scoped lookup comes up empty, restricted to shared networks. A shared
|
|
211
|
+
network is owned by the project that created it, so a lookup scoped to a
|
|
212
|
+
project merely using it never finds it.
|
|
213
|
+
:param include_external: likewise for external networks, which another project
|
|
214
|
+
owns as well: the management network of an appliance typically is one. Note
|
|
215
|
+
that every project can read an external network, but only an admin can create
|
|
216
|
+
a port in its own project on one, unless it is shared as well.
|
|
191
217
|
"""
|
|
192
218
|
if not name and not network_id:
|
|
193
219
|
raise Exception("Either a name or an id needs to be provided.")
|
|
194
220
|
|
|
195
|
-
query_params = {}
|
|
221
|
+
query_params: dict[str, object] = {}
|
|
196
222
|
if project_id:
|
|
197
223
|
query_params["project_id"] = project_id
|
|
198
224
|
if name:
|
|
@@ -201,26 +227,70 @@ class OpenStackHandler(CRUDHandler):
|
|
|
201
227
|
query_params["id"] = network_id
|
|
202
228
|
|
|
203
229
|
networks = self._connection.network.networks(**query_params)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
230
|
+
network = self.require_single_item(networks)
|
|
231
|
+
|
|
232
|
+
if network is None and project_id and (include_shared or include_external):
|
|
233
|
+
del query_params["project_id"]
|
|
234
|
+
if include_shared:
|
|
235
|
+
networks = self._connection.network.networks(
|
|
236
|
+
**query_params, is_shared=True
|
|
237
|
+
)
|
|
238
|
+
network = self.require_single_item(networks)
|
|
239
|
+
if network is None and include_external:
|
|
240
|
+
networks = self._connection.network.networks(
|
|
241
|
+
**query_params, is_router_external=True
|
|
242
|
+
)
|
|
243
|
+
network = self.require_single_item(networks)
|
|
244
|
+
|
|
245
|
+
return network
|
|
246
|
+
|
|
247
|
+
def get_subnet(
|
|
248
|
+
self,
|
|
249
|
+
project_id: str | None = None,
|
|
250
|
+
name: str | None = None,
|
|
251
|
+
subnet_id: str | None = None,
|
|
252
|
+
network_id: str | None = None,
|
|
253
|
+
) -> OSSubnet | None:
|
|
207
254
|
"""
|
|
208
255
|
Retrieve the subnet based on name or id
|
|
209
256
|
"""
|
|
210
257
|
if not name and not subnet_id:
|
|
211
258
|
raise Exception("Either a name or an id needs to be provided.")
|
|
212
259
|
|
|
213
|
-
query_params = {}
|
|
260
|
+
query_params: dict[str, object] = {}
|
|
214
261
|
if project_id:
|
|
215
262
|
query_params["project_id"] = project_id
|
|
216
263
|
if name:
|
|
217
264
|
query_params["name"] = name
|
|
218
265
|
if subnet_id:
|
|
219
266
|
query_params["id"] = subnet_id
|
|
267
|
+
if network_id:
|
|
268
|
+
query_params["network_id"] = network_id
|
|
220
269
|
|
|
221
270
|
subnets = self._connection.network.subnets(**query_params)
|
|
222
271
|
return self.require_single_item(subnets)
|
|
223
272
|
|
|
273
|
+
def get_server_group(self, name: str):
|
|
274
|
+
"""
|
|
275
|
+
Retrieve a Nova server group by name.
|
|
276
|
+
|
|
277
|
+
Nova does not filter server groups by name server-side, so list the groups in the
|
|
278
|
+
connection's project scope and match on the name ourselves. Nova does allow
|
|
279
|
+
several groups to share a name, which cannot be managed unambiguously: skip
|
|
280
|
+
rather than pick one.
|
|
281
|
+
"""
|
|
282
|
+
groups = [
|
|
283
|
+
group
|
|
284
|
+
for group in self._connection.compute.server_groups()
|
|
285
|
+
if group.name == name
|
|
286
|
+
]
|
|
287
|
+
if len(groups) > 1:
|
|
288
|
+
raise SkipResource(
|
|
289
|
+
f"Found more than one server group named '{name}'; refusing "
|
|
290
|
+
"to manage a non-unique server group."
|
|
291
|
+
)
|
|
292
|
+
return groups[0] if groups else None
|
|
293
|
+
|
|
224
294
|
def get_router(self, project_id=None, name=None, router_id=None):
|
|
225
295
|
"""
|
|
226
296
|
Retrieve the router based on name or id
|
|
@@ -276,14 +346,15 @@ class OpenStackHandler(CRUDHandler):
|
|
|
276
346
|
return None
|
|
277
347
|
return self._connection.identity.find_domain(domain_name)
|
|
278
348
|
|
|
279
|
-
def get_server_by_name(self, name, project_id=None):
|
|
349
|
+
def get_server_by_name(self, name, project_id=None, all_projects=False):
|
|
280
350
|
"""
|
|
281
351
|
Retrieve a server by name
|
|
282
352
|
"""
|
|
283
353
|
additional_args = {}
|
|
284
354
|
if project_id is not None:
|
|
285
|
-
additional_args["all_projects"] = True
|
|
286
355
|
additional_args["project_id"] = project_id
|
|
356
|
+
if all_projects:
|
|
357
|
+
additional_args["all_projects"] = True
|
|
287
358
|
# regex for exact match
|
|
288
359
|
servers = self._connection.compute.servers(name=f"^{name}$", **additional_args)
|
|
289
360
|
|
|
@@ -18,11 +18,17 @@ Contact: code@inmanta.com
|
|
|
18
18
|
|
|
19
19
|
from collections import defaultdict
|
|
20
20
|
from collections.abc import Mapping
|
|
21
|
+
from typing import TYPE_CHECKING, cast
|
|
21
22
|
|
|
22
23
|
from inmanta.export import dependency_manager
|
|
23
24
|
|
|
24
25
|
from inmanta_plugins.openstack.common.base import OpenstackResource
|
|
25
26
|
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
# Only a name for the cast below: this export-time module does not depend on a
|
|
29
|
+
# handler module at runtime.
|
|
30
|
+
from inmanta_plugins.openstack.network.network_port import NetworkPort
|
|
31
|
+
|
|
26
32
|
# Per-provider view of the collected resources: resource type -> resource name -> resource.
|
|
27
33
|
ResourceCollector = Mapping[str, Mapping[str, OpenstackResource]]
|
|
28
34
|
|
|
@@ -35,6 +41,7 @@ MANAGED_DEPENDENCIES = {
|
|
|
35
41
|
"openstack::NetworkPort",
|
|
36
42
|
"openstack::FloatingIP",
|
|
37
43
|
"openstack::SecurityGroup",
|
|
44
|
+
"openstack::ServerGroup",
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
|
|
@@ -68,9 +75,14 @@ def set_dependencies_on_purged_resources(collector: ResourceCollector) -> None:
|
|
|
68
75
|
vms = collector.get("openstack::VirtualMachine", {})
|
|
69
76
|
ports = collector.get("openstack::NetworkPort", {})
|
|
70
77
|
sgs = collector.get("openstack::SecurityGroup", {})
|
|
78
|
+
server_groups = collector.get("openstack::ServerGroup", {})
|
|
71
79
|
|
|
72
80
|
# When the VM is purged, all its purged ports should be deployed first
|
|
73
81
|
for vm in vms.values():
|
|
82
|
+
# A purged server group is removed only after the VMs scheduled into it are gone.
|
|
83
|
+
if vm.server_group in server_groups:
|
|
84
|
+
server_groups[vm.server_group].requires.add(vm.id)
|
|
85
|
+
|
|
74
86
|
for vm_port in vm.ports:
|
|
75
87
|
if vm_port["name"] in ports:
|
|
76
88
|
port = ports[vm_port["name"]]
|
|
@@ -99,6 +111,7 @@ def set_dependencies_on_non_purged_resources(collector: ResourceCollector) -> No
|
|
|
99
111
|
ports = collector.get("openstack::NetworkPort", {})
|
|
100
112
|
fips = collector.get("openstack::FloatingIP", {})
|
|
101
113
|
sgs = collector.get("openstack::SecurityGroup", {})
|
|
114
|
+
server_groups = collector.get("openstack::ServerGroup", {})
|
|
102
115
|
router_map = {}
|
|
103
116
|
|
|
104
117
|
# they require the project to exist
|
|
@@ -133,22 +146,40 @@ def set_dependencies_on_non_purged_resources(collector: ResourceCollector) -> No
|
|
|
133
146
|
if vm.model.project.name in projects:
|
|
134
147
|
vm.requires.add(projects[vm.model.project.name].id)
|
|
135
148
|
|
|
149
|
+
# The vm resolves each boot NIC through the port's subnet, or through its network
|
|
150
|
+
# when the port is not pinned to a subnet. Either way that object has to exist
|
|
151
|
+
# before the vm boots.
|
|
136
152
|
for port in vm.ports:
|
|
137
|
-
if port["
|
|
138
|
-
vm.requires.add(subnets[port["
|
|
153
|
+
if port["subnet"] in subnets:
|
|
154
|
+
vm.requires.add(subnets[port["subnet"]].id)
|
|
155
|
+
elif port["network"] in networks:
|
|
156
|
+
vm.requires.add(networks[port["network"]].id)
|
|
139
157
|
|
|
140
158
|
for sg in vm.security_groups:
|
|
141
159
|
if sg in sgs:
|
|
142
160
|
vm.requires.add(sgs[sg].id)
|
|
143
161
|
|
|
144
|
-
|
|
162
|
+
# The scheduler hint is resolved at boot, so the group must exist by then.
|
|
163
|
+
if vm.server_group in server_groups:
|
|
164
|
+
vm.requires.add(server_groups[vm.server_group].id)
|
|
165
|
+
|
|
166
|
+
for collected_port in ports.values():
|
|
167
|
+
# The collector hands out the base type; every entry here is a NetworkPort.
|
|
168
|
+
port = cast("NetworkPort", collected_port)
|
|
169
|
+
|
|
145
170
|
if port.model.project.name in projects:
|
|
146
171
|
port.requires.add(projects[port.model.project.name].id)
|
|
147
172
|
|
|
148
|
-
|
|
149
|
-
|
|
173
|
+
# The port lives on a network, and is pinned to one of its subnets when it
|
|
174
|
+
# requests a fixed ip. The network has to exist before the port is created at
|
|
175
|
+
# all; the subnet has to exist before the port can pin a fixed ip in it.
|
|
176
|
+
if port.network in networks:
|
|
177
|
+
port.requires.add(networks[port.network].id)
|
|
178
|
+
|
|
179
|
+
if port.subnet is not None and port.subnet in subnets:
|
|
180
|
+
port.requires.add(subnets[port.subnet].id)
|
|
150
181
|
|
|
151
|
-
if port.host in vms:
|
|
182
|
+
if port.host is not None and port.host in vms:
|
|
152
183
|
if port.is_trunk_parent:
|
|
153
184
|
# A trunk parent must exist (unbound) before its vm: the trunk is built
|
|
154
185
|
# on it and the vm then boots on the pre-created port. Ordering the port
|
|
@@ -167,13 +198,31 @@ def set_dependencies_on_non_purged_resources(collector: ResourceCollector) -> No
|
|
|
167
198
|
fip.requires.add(networks[fip.external_network].id)
|
|
168
199
|
|
|
169
200
|
if fip.port in ports:
|
|
170
|
-
port = ports[fip.port]
|
|
201
|
+
port = cast("NetworkPort", ports[fip.port])
|
|
171
202
|
fip.requires.add(port.id)
|
|
172
203
|
|
|
173
|
-
#
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
204
|
+
# Find the router this floating ip is routed over: the one with a gateway on
|
|
205
|
+
# the external network and an interface on the port's network. A port pinned
|
|
206
|
+
# to a subnet names that subnet; a port that only knows its network is
|
|
207
|
+
# matched through every managed subnet of that network instead, as the
|
|
208
|
+
# router is attached to the network by one of them.
|
|
209
|
+
if port.subnet is not None:
|
|
210
|
+
port_subnets = [port.subnet]
|
|
211
|
+
else:
|
|
212
|
+
# Matching networks by name is enough even though the collector spans
|
|
213
|
+
# every project of the provider: a network resource is identified by
|
|
214
|
+
# (provider, name), so two projects of one provider cannot both hold a
|
|
215
|
+
# network under this name.
|
|
216
|
+
port_subnets = [
|
|
217
|
+
subnet_name
|
|
218
|
+
for subnet_name, subnet in subnets.items()
|
|
219
|
+
if subnet.model.network.name == port.network
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
for subnet_name in port_subnets:
|
|
223
|
+
key = (fip.external_network, subnet_name)
|
|
224
|
+
if key in router_map:
|
|
225
|
+
fip.requires.add(router_map[key].id)
|
|
177
226
|
|
|
178
227
|
|
|
179
228
|
@dependency_manager
|