osi-dump 0.1.5__py3-none-any.whl → 0.1.6__py3-none-any.whl
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.
- osi_dump/batch_handler/external_port_batch_handler.py +8 -26
- osi_dump/batch_handler/flavor_batch_handler.py +4 -18
- osi_dump/batch_handler/hypervisor_batch_handler.py +5 -17
- osi_dump/batch_handler/image_batch_handler.py +4 -18
- osi_dump/batch_handler/network_batch_handler.py +5 -19
- osi_dump/batch_handler/project_batch_handler.py +5 -17
- osi_dump/batch_handler/router_batch_handler.py +4 -16
- osi_dump/batch_handler/volume_batch_handler.py +4 -10
- osi_dump/exporter/external_port/excel_external_port_exporter.py +16 -11
- osi_dump/exporter/external_port/external_port_exporter.py +4 -3
- osi_dump/exporter/flavor/excel_flavor_exporter.py +10 -9
- osi_dump/exporter/flavor/flavor_exporter.py +4 -2
- osi_dump/exporter/floating_ip/excel_floating_ip_exporter.py +17 -11
- osi_dump/exporter/floating_ip/floating_ip_exporter.py +4 -2
- osi_dump/exporter/hypervisor/excel_hypervisor_exporter.py +14 -13
- osi_dump/exporter/hypervisor/hypervisor_exporter.py +4 -3
- osi_dump/exporter/image/excel_image_exporter.py +10 -7
- osi_dump/exporter/image/image_exporter.py +4 -2
- osi_dump/exporter/network/excel_network_exporter.py +13 -11
- osi_dump/exporter/network/network_exporter.py +4 -3
- osi_dump/exporter/project/excel_project_exporter.py +11 -11
- osi_dump/exporter/project/project_exporter.py +4 -3
- osi_dump/exporter/router/excel_router_exporter.py +9 -8
- osi_dump/exporter/router/router_exporter.py +3 -2
- osi_dump/exporter/volume/excel_volume_exporter.py +10 -8
- osi_dump/exporter/volume/volume_exporter.py +4 -2
- osi_dump/importer/external_port/external_port_importer.py +3 -4
- osi_dump/importer/external_port/openstack_external_port_importer.py +44 -131
- osi_dump/importer/flavor/flavor_importer.py +3 -3
- osi_dump/importer/flavor/openstack_flavor_importer.py +13 -35
- osi_dump/importer/floating_ip/floating_ip_importer.py +3 -3
- osi_dump/importer/floating_ip/openstack_floating_ip_importer.py +11 -38
- osi_dump/importer/hypervisor/hypervisor_importer.py +3 -4
- osi_dump/importer/hypervisor/openstack_hypervisor_importer.py +44 -88
- osi_dump/importer/image/image_importer.py +3 -3
- osi_dump/importer/image/openstack_image_importer.py +16 -44
- osi_dump/importer/network/network_importer.py +3 -4
- osi_dump/importer/network/openstack_network_importer.py +23 -52
- osi_dump/importer/project/openstack_project_importer.py +45 -83
- osi_dump/importer/project/project_importer.py +3 -4
- osi_dump/importer/router/openstack_router_importer.py +18 -53
- osi_dump/importer/router/router_importer.py +2 -3
- osi_dump/importer/volume/openstack_volume_importer.py +15 -45
- osi_dump/importer/volume/volume_importer.py +3 -4
- {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/METADATA +1 -1
- {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/RECORD +49 -49
- {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/WHEEL +0 -0
- {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/entry_points.txt +0 -0
- {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
|
3
|
-
import concurrent
|
4
|
-
|
2
|
+
from typing import Generator
|
5
3
|
from openstack.connection import Connection
|
6
4
|
from openstack.network.v2.floating_ip import FloatingIP as OSFloatingIP
|
7
5
|
|
@@ -10,49 +8,26 @@ from osi_dump.model.floating_ip import FloatingIP
|
|
10
8
|
|
11
9
|
logger = logging.getLogger(__name__)
|
12
10
|
|
13
|
-
|
14
11
|
class OpenStackFloatingIPImporter(FloatingIPImporter):
|
15
12
|
def __init__(self, connection: Connection):
|
16
13
|
self.connection = connection
|
17
14
|
|
18
|
-
def import_floating_ips(self) ->
|
19
|
-
"""Import instances information from Openstack
|
20
|
-
|
21
|
-
Raises:
|
22
|
-
Exception: Raises exception if fetching server failed
|
23
|
-
|
24
|
-
Returns:
|
25
|
-
list[Instance]: _description_
|
26
|
-
"""
|
27
|
-
|
15
|
+
def import_floating_ips(self) -> Generator[FloatingIP, None, None]:
|
28
16
|
logger.info(f"Importing floating ips for {self.connection.auth['auth_url']}")
|
29
|
-
|
30
17
|
try:
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
raise Exception(
|
36
|
-
f"Can not fetch floating IPs for {self.connection.auth['auth_url']}"
|
37
|
-
) from e
|
38
|
-
|
39
|
-
floating_ips: list[FloatingIP] = []
|
40
|
-
|
41
|
-
with concurrent.futures.ThreadPoolExecutor() as executor:
|
42
|
-
futures = [
|
43
|
-
executor.submit(self._get_floating_ip_info, osfloating_ip)
|
44
|
-
for osfloating_ip in osfloating_ips
|
45
|
-
]
|
46
|
-
for future in concurrent.futures.as_completed(futures):
|
47
|
-
floating_ips.append(future.result())
|
18
|
+
osfloating_ip_iterator = self.connection.list_floating_ips()
|
19
|
+
|
20
|
+
for floating_ip in osfloating_ip_iterator:
|
21
|
+
yield self._get_floating_ip_info(floating_ip)
|
48
22
|
|
49
|
-
|
23
|
+
except Exception as e:
|
24
|
+
logger.error(f"Cannot fetch floating IPs for {self.connection.auth['auth_url']}: {e}")
|
25
|
+
return
|
50
26
|
|
51
|
-
|
27
|
+
logger.info(f"Finished importing floating ips for {self.connection.auth['auth_url']}")
|
52
28
|
|
53
29
|
def _get_floating_ip_info(self, floating_ip: OSFloatingIP) -> FloatingIP:
|
54
|
-
|
55
|
-
ret_floating_ip = FloatingIP(
|
30
|
+
return FloatingIP(
|
56
31
|
floating_ip_id=floating_ip.id,
|
57
32
|
project_id=floating_ip.project_id,
|
58
33
|
floating_ip_address=floating_ip.floating_ip_address,
|
@@ -64,5 +39,3 @@ class OpenStackFloatingIPImporter(FloatingIPImporter):
|
|
64
39
|
created_at=floating_ip.created_at,
|
65
40
|
updated_at=floating_ip.updated_at,
|
66
41
|
)
|
67
|
-
|
68
|
-
return ret_floating_ip
|
@@ -1,9 +1,8 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
|
-
|
2
|
+
from typing import Generator
|
3
3
|
from osi_dump.model.hypervisor import Hypervisor
|
4
4
|
|
5
|
-
|
6
5
|
class HypervisorImporter(ABC):
|
7
6
|
@abstractmethod
|
8
|
-
def import_hypervisors(self) ->
|
9
|
-
pass
|
7
|
+
def import_hypervisors(self) -> Generator[Hypervisor, None, None]:
|
8
|
+
pass
|
@@ -1,124 +1,84 @@
|
|
1
1
|
import logging
|
2
|
-
|
3
|
-
import concurrent
|
4
|
-
|
2
|
+
from typing import Generator
|
5
3
|
from openstack.connection import Connection
|
6
4
|
from openstack.compute.v2.hypervisor import Hypervisor as OSHypervisor
|
7
5
|
from openstack.compute.v2.aggregate import Aggregate as OSAggregate
|
8
|
-
|
9
6
|
from openstack.placement.v1._proxy import Proxy as PlacementProxy
|
10
7
|
from openstack.placement.v1.resource_provider_inventory import ResourceProviderInventory
|
11
8
|
|
12
9
|
from osi_dump.importer.hypervisor.hypervisor_importer import HypervisorImporter
|
13
10
|
from osi_dump.model.hypervisor import Hypervisor
|
14
|
-
|
15
11
|
from osi_dump.api.placement import get_usage
|
16
12
|
|
17
13
|
logger = logging.getLogger(__name__)
|
18
14
|
|
19
|
-
|
20
15
|
class OpenStackHypervisorImporter(HypervisorImporter):
|
21
16
|
def __init__(self, connection: Connection):
|
22
17
|
self.connection = connection
|
23
18
|
|
24
|
-
def import_hypervisors(self) ->
|
25
|
-
""
|
26
|
-
|
27
|
-
Raises:
|
28
|
-
Exception: Raises exception if fetching hypervisor failed
|
29
|
-
|
30
|
-
Returns:
|
31
|
-
list[Hypervisor]: _description_
|
32
|
-
"""
|
33
|
-
aggregates = list(self.connection.list_aggregates())
|
34
|
-
|
19
|
+
def import_hypervisors(self) -> Generator[Hypervisor, None, None]:
|
20
|
+
logger.info("Pre-caching aggregates...")
|
35
21
|
try:
|
36
|
-
|
37
|
-
self.connection.compute.hypervisors(details=True, with_servers=True)
|
38
|
-
)
|
39
|
-
|
22
|
+
aggregates = list(self.connection.list_aggregates())
|
40
23
|
except Exception as e:
|
41
|
-
|
42
|
-
|
43
|
-
) from e
|
44
|
-
|
45
|
-
hypervisors: list[Hypervisor] = []
|
46
|
-
|
47
|
-
with concurrent.futures.ThreadPoolExecutor() as executor:
|
48
|
-
futures = [
|
49
|
-
executor.submit(self._get_hypervisor_info, hypervisor, aggregates)
|
50
|
-
for hypervisor in oshypervisors
|
51
|
-
]
|
52
|
-
for future in concurrent.futures.as_completed(futures):
|
53
|
-
hypervisors.append(future.result())
|
54
|
-
|
55
|
-
logger.info(f"Imported hypervisors for {self.connection.auth['auth_url']}")
|
56
|
-
|
57
|
-
return hypervisors
|
58
|
-
|
59
|
-
|
60
|
-
def _normalize_hypervisor_aggregate(self, hypervisors: list[Hypervisor]):
|
61
|
-
|
62
|
-
aggregate_id_map = {
|
63
|
-
|
64
|
-
}
|
65
|
-
|
66
|
-
aggregates: list[list[dict]] = [
|
24
|
+
logger.warning(f"Could not pre-cache aggregates: {e}")
|
25
|
+
aggregates = []
|
67
26
|
|
68
|
-
]
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
27
|
+
logger.info(f"Importing hypervisors for {self.connection.auth['auth_url']}")
|
28
|
+
try:
|
29
|
+
hypervisor_iterator = self.connection.compute.hypervisors(details=True, with_servers=True)
|
30
|
+
for hypervisor in hypervisor_iterator:
|
31
|
+
yield self._get_hypervisor_info(hypervisor, aggregates)
|
32
|
+
except Exception as e:
|
33
|
+
logger.error(f"Cannot fetch hypervisors for {self.connection.auth['auth_url']}: {e}")
|
34
|
+
return
|
35
|
+
|
36
|
+
logger.info(f"Finished importing hypervisors for {self.connection.auth['auth_url']}")
|
75
37
|
|
76
38
|
def _get_hypervisor_info(
|
77
39
|
self, hypervisor: OSHypervisor, aggregates: list[OSAggregate]
|
78
40
|
) -> Hypervisor:
|
79
|
-
aggregate_list, az = self._get_aggregates(hypervisor=hypervisor)
|
41
|
+
aggregate_list, az = self._get_aggregates(hypervisor=hypervisor, all_aggregates=aggregates)
|
80
42
|
|
81
43
|
placement_proxy: PlacementProxy = self.connection.placement
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
44
|
+
rpi: list[ResourceProviderInventory] = []
|
45
|
+
usage_data = {}
|
46
|
+
|
47
|
+
try:
|
48
|
+
rpi = list(
|
49
|
+
placement_proxy.resource_provider_inventories(
|
50
|
+
resource_provider=hypervisor.id
|
51
|
+
)
|
86
52
|
)
|
87
|
-
|
88
|
-
|
89
|
-
|
53
|
+
usage_data = get_usage(self.connection, resource_provider_id=hypervisor.id)
|
54
|
+
except Exception as e:
|
55
|
+
logger.warning(f"Could not get placement data for hypervisor {hypervisor.name}: {e}")
|
90
56
|
|
91
|
-
vcpu = rpi[0]
|
92
|
-
memory = rpi[1]
|
93
|
-
disk = rpi[2]
|
57
|
+
vcpu = rpi[0] if len(rpi) > 0 else {}
|
58
|
+
memory = rpi[1] if len(rpi) > 1 else {}
|
59
|
+
disk = rpi[2] if len(rpi) > 2 else {}
|
94
60
|
|
95
|
-
|
61
|
+
return Hypervisor(
|
96
62
|
hypervisor_id=hypervisor.id,
|
97
63
|
hypervisor_type=hypervisor.hypervisor_type,
|
98
64
|
name=hypervisor.name,
|
99
65
|
state=hypervisor.state,
|
100
66
|
status=hypervisor.status,
|
101
|
-
local_disk_size=disk
|
102
|
-
memory_size=memory
|
103
|
-
vcpus=vcpu
|
104
|
-
vcpus_usage=usage_data
|
105
|
-
memory_usage=usage_data
|
106
|
-
local_disk_usage=usage_data
|
67
|
+
local_disk_size=disk.get("max_unit", 0),
|
68
|
+
memory_size=memory.get("max_unit", 0) + memory.get("reserved", 0),
|
69
|
+
vcpus=vcpu.get("max_unit", 0),
|
70
|
+
vcpus_usage=usage_data.get("VCPU", 0),
|
71
|
+
memory_usage=usage_data.get("MEMORY_MB", 0),
|
72
|
+
local_disk_usage=usage_data.get("DISK_GB", 0),
|
107
73
|
vm_count=len(hypervisor.servers),
|
108
74
|
aggregates=aggregate_list,
|
109
75
|
availability_zone=az,
|
110
76
|
)
|
111
77
|
|
112
|
-
|
113
|
-
|
114
|
-
def _get_aggregates(self, hypervisor: OSHypervisor):
|
78
|
+
def _get_aggregates(self, hypervisor: OSHypervisor, all_aggregates: list[OSAggregate]):
|
115
79
|
aggregates_ret = []
|
116
|
-
|
117
|
-
aggregates: OSAggregate = list(self.connection.list_aggregates())
|
118
|
-
|
119
80
|
az = None
|
120
|
-
|
121
|
-
for aggregate in aggregates:
|
81
|
+
for aggregate in all_aggregates:
|
122
82
|
if hypervisor.name in aggregate.hosts:
|
123
83
|
aggregates_ret.append(
|
124
84
|
{
|
@@ -126,12 +86,8 @@ class OpenStackHypervisorImporter(HypervisorImporter):
|
|
126
86
|
"name": aggregate.name,
|
127
87
|
}
|
128
88
|
)
|
129
|
-
|
130
|
-
if aggregate.availability_zone != None:
|
89
|
+
if aggregate.availability_zone is not None:
|
131
90
|
az = aggregate.availability_zone
|
132
|
-
|
133
|
-
aggregates_ret = [
|
134
|
-
|
135
|
-
]
|
136
|
-
|
137
|
-
return aggregates_ret, az
|
91
|
+
|
92
|
+
aggregates_ret = sorted(aggregates_ret, key=lambda x: x['name'])
|
93
|
+
return aggregates_ret, az
|
@@ -1,9 +1,9 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
|
-
|
2
|
+
from typing import Generator
|
3
3
|
from osi_dump.model.image import Image
|
4
4
|
|
5
|
-
|
6
5
|
class ImageImporter(ABC):
|
7
6
|
@abstractmethod
|
8
|
-
def import_images(self) ->
|
7
|
+
def import_images(self) -> Generator[Image, None, None]:
|
9
8
|
pass
|
9
|
+
|
@@ -1,7 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
|
3
|
-
import concurrent
|
4
|
-
|
2
|
+
from typing import Generator
|
5
3
|
from openstack.connection import Connection
|
6
4
|
from openstack.image.v2.image import Image as OSImage
|
7
5
|
|
@@ -10,64 +8,40 @@ from osi_dump.model.image import Image
|
|
10
8
|
|
11
9
|
logger = logging.getLogger(__name__)
|
12
10
|
|
13
|
-
|
14
11
|
class OpenStackImageImporter(ImageImporter):
|
15
12
|
def __init__(self, connection: Connection):
|
16
13
|
self.connection = connection
|
17
14
|
|
18
|
-
def import_images(self) ->
|
19
|
-
"""Import instances information from Openstack
|
20
|
-
|
21
|
-
Raises:
|
22
|
-
Exception: Raises exception if fetching server failed
|
23
|
-
|
24
|
-
Returns:
|
25
|
-
list[Instance]: _description_
|
26
|
-
"""
|
27
|
-
|
15
|
+
def import_images(self) -> Generator[Image, None, None]:
|
28
16
|
logger.info(f"Importing images for {self.connection.auth['auth_url']}")
|
29
|
-
|
30
17
|
try:
|
18
|
+
os_image_iterator = self.connection.list_images(show_all=True)
|
19
|
+
|
20
|
+
for os_image in os_image_iterator:
|
21
|
+
yield self._get_image_info(os_image)
|
31
22
|
|
32
|
-
os_images: list[OSImage] = list(self.connection.list_images(show_all=True))
|
33
23
|
except Exception as e:
|
34
|
-
|
35
|
-
|
36
|
-
) from e
|
24
|
+
logger.error(f"Cannot fetch images for {self.connection.auth['auth_url']}: {e}")
|
25
|
+
return
|
37
26
|
|
38
|
-
images
|
27
|
+
logger.info(f"Finished importing images for {self.connection.auth['auth_url']}")
|
39
28
|
|
40
|
-
with concurrent.futures.ThreadPoolExecutor() as executor:
|
41
|
-
futures = [
|
42
|
-
executor.submit(self._get_image_info, image) for image in os_images
|
43
|
-
]
|
44
|
-
for future in concurrent.futures.as_completed(futures):
|
45
|
-
images.append(future.result())
|
46
|
-
|
47
|
-
logger.info(f"Imported images for {self.connection.auth['auth_url']}")
|
48
|
-
|
49
|
-
return images
|
50
29
|
|
51
30
|
def _get_image_info(self, os_image: OSImage) -> Image:
|
31
|
+
properties = os_image.properties or {}
|
32
|
+
properties.pop("owner_specified.openstack.md5", None)
|
33
|
+
properties.pop("owner_specified.openstack.sha256", None)
|
34
|
+
properties.pop("owner_specified.openstack.object", None)
|
35
|
+
properties.pop("stores", None)
|
52
36
|
|
53
|
-
|
54
|
-
properties: dict = os_image.properties
|
55
|
-
|
56
|
-
properties.pop("owner_specified.openstack.md5", None)
|
57
|
-
properties.pop("owner_specified.openstack.sha256", None)
|
58
|
-
properties.pop("owner_specified.openstack.object", None)
|
59
|
-
properties.pop("stores", None)
|
60
|
-
except Exception as e:
|
61
|
-
logger.warn(f"properties for {os_image.id} is None")
|
62
|
-
|
63
|
-
image = Image(
|
37
|
+
return Image(
|
64
38
|
image_id=os_image.id,
|
65
39
|
disk_format=os_image.disk_format,
|
66
40
|
min_disk=os_image.min_disk,
|
67
41
|
min_ram=os_image.min_ram,
|
68
42
|
image_name=os_image.name,
|
69
43
|
owner=os_image.owner,
|
70
|
-
properties=
|
44
|
+
properties=properties,
|
71
45
|
protected=os_image.is_protected,
|
72
46
|
status=os_image.status,
|
73
47
|
os_distro=os_image.os_distro,
|
@@ -77,5 +51,3 @@ class OpenStackImageImporter(ImageImporter):
|
|
77
51
|
created_at=os_image.created_at,
|
78
52
|
updated_at=os_image.updated_at,
|
79
53
|
)
|
80
|
-
|
81
|
-
return image
|
@@ -1,9 +1,8 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
|
-
|
2
|
+
from typing import Generator
|
3
3
|
from osi_dump.model.network import Network
|
4
4
|
|
5
|
-
|
6
5
|
class NetworkImporter(ABC):
|
7
6
|
@abstractmethod
|
8
|
-
def import_networks(self) ->
|
9
|
-
pass
|
7
|
+
def import_networks(self) -> Generator[Network, None, None]:
|
8
|
+
pass
|
@@ -1,59 +1,33 @@
|
|
1
1
|
import logging
|
2
|
-
|
3
|
-
import concurrent
|
4
|
-
|
2
|
+
from typing import Generator
|
5
3
|
from openstack.network.v2.network import Network as OSNetwork
|
6
4
|
from openstack.network.v2.subnet import Subnet as OSSubnet
|
7
|
-
|
8
5
|
from openstack.connection import Connection
|
9
6
|
|
10
7
|
from osi_dump.importer.network.network_importer import NetworkImporter
|
11
8
|
from osi_dump.model.network import Network
|
12
9
|
|
13
|
-
|
14
10
|
logger = logging.getLogger(__name__)
|
15
11
|
|
16
|
-
|
17
12
|
class OpenStackNetworkImporter(NetworkImporter):
|
18
13
|
def __init__(self, connection: Connection):
|
19
14
|
self.connection = connection
|
20
15
|
|
21
|
-
def import_networks(self) ->
|
22
|
-
"
|
23
|
-
|
24
|
-
Raises:
|
25
|
-
Exception: Raises exception if fetching networks failed
|
26
|
-
|
27
|
-
Returns:
|
28
|
-
list[Network]: _description_
|
29
|
-
"""
|
30
|
-
|
16
|
+
def import_networks(self) -> Generator[Network, None, None]:
|
17
|
+
logger.info(f"Importing networks for {self.connection.auth['auth_url']}")
|
31
18
|
try:
|
32
|
-
|
33
|
-
except Exception as e:
|
34
|
-
raise Exception(
|
35
|
-
f"Can not fetch hypervisor for {self.connection.auth['auth_url']}"
|
36
|
-
) from e
|
37
|
-
|
38
|
-
networks: list[Network] = []
|
19
|
+
network_iterator = self.connection.list_networks()
|
39
20
|
|
40
|
-
|
41
|
-
|
42
|
-
executor.submit(self._get_network_info, network)
|
43
|
-
for network in os_networks
|
44
|
-
]
|
45
|
-
for future in concurrent.futures.as_completed(futures):
|
46
|
-
networks.append(future.result())
|
47
|
-
|
48
|
-
logger.info(f"Imported networks for {self.connection.auth['auth_url']}")
|
49
|
-
|
50
|
-
return networks
|
21
|
+
for network in network_iterator:
|
22
|
+
yield self._get_network_info(network)
|
51
23
|
|
24
|
+
except Exception as e:
|
25
|
+
logger.error(f"Cannot fetch networks for {self.connection.auth['auth_url']}: {e}")
|
26
|
+
return
|
52
27
|
|
53
|
-
|
54
|
-
self, network: OSNetwork,
|
55
|
-
) -> Network:
|
28
|
+
logger.info(f"Finished importing networks for {self.connection.auth['auth_url']}")
|
56
29
|
|
30
|
+
def _get_network_info(self, network: OSNetwork) -> Network:
|
57
31
|
subnets = self._get_subnets_info(subnet_ids=network.subnet_ids)
|
58
32
|
|
59
33
|
return Network(
|
@@ -72,23 +46,20 @@ class OpenStackNetworkImporter(NetworkImporter):
|
|
72
46
|
subnets=subnets
|
73
47
|
)
|
74
48
|
|
75
|
-
|
76
49
|
def _get_subnets_info(self, subnet_ids: list[str]) -> list[dict]:
|
77
50
|
subnets = []
|
51
|
+
if not subnet_ids:
|
52
|
+
return subnets
|
78
53
|
|
79
54
|
for subnet_id in subnet_ids:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
55
|
+
try:
|
56
|
+
os_subnet: OSSubnet = self.connection.get_subnet(subnet_id)
|
57
|
+
if os_subnet:
|
58
|
+
subnets.append({
|
59
|
+
"id": os_subnet.id,
|
60
|
+
"cidr": os_subnet.cidr
|
61
|
+
})
|
62
|
+
except Exception as e:
|
63
|
+
logger.warning(f"Could not get info for subnet {subnet_id}: {e}")
|
84
64
|
|
85
|
-
|
86
|
-
"id": os_subnet.id,
|
87
|
-
"cidr": os_subnet.cidr
|
88
|
-
})
|
89
|
-
|
90
|
-
return subnets
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
65
|
+
return subnets
|
@@ -1,7 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
|
3
|
-
import concurrent
|
4
|
-
|
2
|
+
from typing import Generator
|
5
3
|
from openstack.connection import Connection
|
6
4
|
from openstack.identity.v3.project import Project as OSProject
|
7
5
|
from openstack.load_balancer.v2.load_balancer import LoadBalancer as OSLoadBalancer
|
@@ -9,101 +7,67 @@ from openstack.load_balancer.v2.load_balancer import LoadBalancer as OSLoadBalan
|
|
9
7
|
from osi_dump.importer.project.project_importer import ProjectImporter
|
10
8
|
from osi_dump.model.project import Project
|
11
9
|
import osi_dump.api.octavia as octavia_api
|
12
|
-
logger = logging.getLogger(__name__)
|
13
10
|
|
11
|
+
logger = logging.getLogger(__name__)
|
14
12
|
|
15
13
|
class OpenStackProjectImporter(ProjectImporter):
|
16
14
|
def __init__(self, connection: Connection):
|
17
15
|
self.connection = connection
|
18
16
|
|
19
|
-
def import_projects(self) ->
|
20
|
-
|
21
|
-
|
22
|
-
Raises:
|
23
|
-
Exception: Raises exception if fetching project failed
|
24
|
-
|
25
|
-
Returns:
|
26
|
-
list[Instance]: _description_
|
27
|
-
"""
|
28
|
-
|
29
|
-
logger.info(f"Importing projects for {self.connection.auth['auth_url']}")
|
17
|
+
def import_projects(self) -> Generator[Project, None, None]:
|
18
|
+
project_lb_dict = {}
|
19
|
+
logger.info(f"Pre-caching load balancers for project count on {self.connection.auth['auth_url']}")
|
30
20
|
try:
|
31
|
-
osload_balancers
|
32
|
-
|
33
|
-
|
21
|
+
osload_balancers = octavia_api.get_load_balancers(connection=self.connection)
|
22
|
+
if osload_balancers:
|
23
|
+
for lb in osload_balancers:
|
24
|
+
project_id = lb.get("project_id")
|
25
|
+
if project_id:
|
26
|
+
project_lb_dict[project_id] = project_lb_dict.get(project_id, 0) + 1
|
34
27
|
except Exception as e:
|
35
|
-
|
36
|
-
f"Can not fetch load_balancers for {self.connection.auth['auth_url']} {e}"
|
37
|
-
) from e
|
38
|
-
|
39
|
-
project_lb_dict = {}
|
40
|
-
|
41
|
-
for osload_balancer in osload_balancers:
|
42
|
-
if project_lb_dict.get(osload_balancer["project_id"]):
|
43
|
-
project_lb_dict[osload_balancer["project_id"]] += 1
|
44
|
-
else:
|
45
|
-
project_lb_dict[osload_balancer["project_id"]] = 1
|
28
|
+
logger.warning(f"Could not pre-cache load balancers for project count: {e}")
|
46
29
|
|
30
|
+
logger.info(f"Importing projects for {self.connection.auth['auth_url']}")
|
47
31
|
try:
|
48
|
-
|
32
|
+
project_iterator = self.connection.identity.projects()
|
33
|
+
for project in project_iterator:
|
34
|
+
yield self._get_project_info(project, project_lb_dict)
|
49
35
|
except Exception as e:
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
projects: list[Project] = []
|
55
|
-
|
56
|
-
with concurrent.futures.ThreadPoolExecutor() as executor:
|
57
|
-
futures = [
|
58
|
-
executor.submit(self._get_project_info, project, project_lb_dict)
|
59
|
-
for project in osprojects
|
60
|
-
]
|
61
|
-
for future in concurrent.futures.as_completed(futures):
|
62
|
-
projects.append(future.result())
|
63
|
-
|
64
|
-
logger.info(f"Imported projects for {self.connection.auth['auth_url']}")
|
65
|
-
|
66
|
-
return projects
|
36
|
+
logger.error(f"Cannot fetch projects for {self.connection.auth['auth_url']}: {e}")
|
37
|
+
return
|
38
|
+
|
39
|
+
logger.info(f"Finished importing projects for {self.connection.auth['auth_url']}")
|
67
40
|
|
68
41
|
def _get_project_info(self, project: OSProject, project_lb_dict: dict) -> Project:
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
quota_vcpu=None
|
42
|
+
usage_instance, quota_instance = None, None
|
43
|
+
usage_ram, quota_ram = None, None
|
44
|
+
usage_vcpu, quota_vcpu = None, None
|
45
|
+
usage_volume, quota_volume = None, None
|
46
|
+
usage_snapshot, quota_snapshot = None, None
|
47
|
+
usage_storage, quota_storage = None, None
|
76
48
|
|
77
49
|
try:
|
78
|
-
compute_quotas = self.connection.compute.get_quota_set(
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
usage_vcpu=compute_quotas.usage["cores"]
|
87
|
-
quota_vcpu=compute_quotas.cores
|
50
|
+
compute_quotas = self.connection.compute.get_quota_set(project.id, usage=True)
|
51
|
+
if compute_quotas and compute_quotas.usage:
|
52
|
+
usage_instance = compute_quotas.usage.get("instances")
|
53
|
+
quota_instance = compute_quotas.instances
|
54
|
+
usage_ram = compute_quotas.usage.get("ram")
|
55
|
+
quota_ram = compute_quotas.ram
|
56
|
+
usage_vcpu = compute_quotas.usage.get("cores")
|
57
|
+
quota_vcpu = compute_quotas.cores
|
88
58
|
except Exception as e:
|
89
59
|
logger.warning(f"Get compute quotas failed for {project.id} error: {e}")
|
90
60
|
|
91
|
-
|
92
|
-
quota_volume=None
|
93
|
-
usage_snapshot=None
|
94
|
-
quota_snapshot=None
|
95
|
-
usage_storage=None
|
96
|
-
quota_storage=None
|
61
|
+
# Lấy thông tin storage quotas
|
97
62
|
try:
|
98
|
-
storage_quotas = self.connection.block_storage.get_quota_set(
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
quota_storage=storage_quotas.gigabytes
|
63
|
+
storage_quotas = self.connection.block_storage.get_quota_set(project.id, usage=True)
|
64
|
+
if storage_quotas and storage_quotas.usage:
|
65
|
+
usage_volume = storage_quotas.usage.get("volumes")
|
66
|
+
quota_volume = storage_quotas.volumes
|
67
|
+
usage_snapshot = storage_quotas.usage.get("snapshots")
|
68
|
+
quota_snapshot = storage_quotas.snapshots
|
69
|
+
usage_storage = storage_quotas.usage.get("gigabytes")
|
70
|
+
quota_storage = storage_quotas.gigabytes
|
107
71
|
except Exception as e:
|
108
72
|
logger.warning(f"Get storage quotas failed for {project.id} error: {e}")
|
109
73
|
|
@@ -116,7 +80,7 @@ class OpenStackProjectImporter(ProjectImporter):
|
|
116
80
|
|
117
81
|
lb_count = project_lb_dict.get(project.id)
|
118
82
|
|
119
|
-
|
83
|
+
return Project(
|
120
84
|
project_id=project.id,
|
121
85
|
project_name=project.name,
|
122
86
|
domain_id=project.domain_id,
|
@@ -136,6 +100,4 @@ class OpenStackProjectImporter(ProjectImporter):
|
|
136
100
|
usage_storage=usage_storage,
|
137
101
|
quota_storage=quota_storage,
|
138
102
|
load_balancer_count=lb_count
|
139
|
-
)
|
140
|
-
|
141
|
-
return project_ret
|
103
|
+
)
|