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.
Files changed (49) hide show
  1. osi_dump/batch_handler/external_port_batch_handler.py +8 -26
  2. osi_dump/batch_handler/flavor_batch_handler.py +4 -18
  3. osi_dump/batch_handler/hypervisor_batch_handler.py +5 -17
  4. osi_dump/batch_handler/image_batch_handler.py +4 -18
  5. osi_dump/batch_handler/network_batch_handler.py +5 -19
  6. osi_dump/batch_handler/project_batch_handler.py +5 -17
  7. osi_dump/batch_handler/router_batch_handler.py +4 -16
  8. osi_dump/batch_handler/volume_batch_handler.py +4 -10
  9. osi_dump/exporter/external_port/excel_external_port_exporter.py +16 -11
  10. osi_dump/exporter/external_port/external_port_exporter.py +4 -3
  11. osi_dump/exporter/flavor/excel_flavor_exporter.py +10 -9
  12. osi_dump/exporter/flavor/flavor_exporter.py +4 -2
  13. osi_dump/exporter/floating_ip/excel_floating_ip_exporter.py +17 -11
  14. osi_dump/exporter/floating_ip/floating_ip_exporter.py +4 -2
  15. osi_dump/exporter/hypervisor/excel_hypervisor_exporter.py +14 -13
  16. osi_dump/exporter/hypervisor/hypervisor_exporter.py +4 -3
  17. osi_dump/exporter/image/excel_image_exporter.py +10 -7
  18. osi_dump/exporter/image/image_exporter.py +4 -2
  19. osi_dump/exporter/network/excel_network_exporter.py +13 -11
  20. osi_dump/exporter/network/network_exporter.py +4 -3
  21. osi_dump/exporter/project/excel_project_exporter.py +11 -11
  22. osi_dump/exporter/project/project_exporter.py +4 -3
  23. osi_dump/exporter/router/excel_router_exporter.py +9 -8
  24. osi_dump/exporter/router/router_exporter.py +3 -2
  25. osi_dump/exporter/volume/excel_volume_exporter.py +10 -8
  26. osi_dump/exporter/volume/volume_exporter.py +4 -2
  27. osi_dump/importer/external_port/external_port_importer.py +3 -4
  28. osi_dump/importer/external_port/openstack_external_port_importer.py +44 -131
  29. osi_dump/importer/flavor/flavor_importer.py +3 -3
  30. osi_dump/importer/flavor/openstack_flavor_importer.py +13 -35
  31. osi_dump/importer/floating_ip/floating_ip_importer.py +3 -3
  32. osi_dump/importer/floating_ip/openstack_floating_ip_importer.py +11 -38
  33. osi_dump/importer/hypervisor/hypervisor_importer.py +3 -4
  34. osi_dump/importer/hypervisor/openstack_hypervisor_importer.py +44 -88
  35. osi_dump/importer/image/image_importer.py +3 -3
  36. osi_dump/importer/image/openstack_image_importer.py +16 -44
  37. osi_dump/importer/network/network_importer.py +3 -4
  38. osi_dump/importer/network/openstack_network_importer.py +23 -52
  39. osi_dump/importer/project/openstack_project_importer.py +45 -83
  40. osi_dump/importer/project/project_importer.py +3 -4
  41. osi_dump/importer/router/openstack_router_importer.py +18 -53
  42. osi_dump/importer/router/router_importer.py +2 -3
  43. osi_dump/importer/volume/openstack_volume_importer.py +15 -45
  44. osi_dump/importer/volume/volume_importer.py +3 -4
  45. {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/METADATA +1 -1
  46. {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/RECORD +49 -49
  47. {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/WHEEL +0 -0
  48. {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/entry_points.txt +0 -0
  49. {osi_dump-0.1.5.dist-info → osi_dump-0.1.6.dist-info}/top_level.txt +0 -0
@@ -1,28 +1,31 @@
1
1
  import pandas as pd
2
-
3
2
  import logging
4
-
3
+ from typing import Generator
5
4
 
6
5
  from osi_dump import util
7
6
  from osi_dump.exporter.image.image_exporter import ImageExporter
8
-
9
7
  from osi_dump.model.image import Image
10
8
 
11
9
  logger = logging.getLogger(__name__)
12
10
 
13
-
14
11
  class ExcelImageExporter(ImageExporter):
15
12
  def __init__(self, sheet_name: str, output_file: str):
16
13
  self.sheet_name = sheet_name
17
14
  self.output_file = output_file
18
15
 
19
- def export_images(self, images: list[Image]):
20
- df = pd.json_normalize([image.model_dump() for image in images])
16
+ def export_images(self, images: Generator[Image, None, None]):
17
+ df = pd.json_normalize(image.model_dump() for image in images)
18
+
19
+ if df.empty:
20
+ logger.info(f"No images to export for {self.sheet_name}")
21
+ return
22
+
23
+ if 'image_name' in df.columns:
24
+ df.sort_values(by='image_name', inplace=True, na_position='last')
21
25
 
22
26
  logger.info(f"Exporting images for {self.sheet_name}")
23
27
  try:
24
28
  util.export_data_excel(self.output_file, sheet_name=self.sheet_name, df=df)
25
-
26
29
  logger.info(f"Exported images for {self.sheet_name}")
27
30
  except Exception as e:
28
31
  logger.warning(f"Exporting images for {self.sheet_name} error: {e}")
@@ -1,7 +1,9 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
+ from osi_dump.model.image import Image
3
4
 
4
5
  class ImageExporter(ABC):
5
6
  @abstractmethod
6
- def export_images(self, images, output_file: str):
7
+ def export_images(self, images: Generator[Image, None, None]):
7
8
  pass
9
+
@@ -1,32 +1,34 @@
1
1
  import logging
2
-
3
-
4
2
  import pandas as pd
5
-
3
+ from typing import Generator
6
4
 
7
5
  from osi_dump.exporter.network.network_exporter import NetworkExporter
8
-
9
6
  from osi_dump.model.network import Network
10
-
11
7
  from osi_dump import util
12
8
 
13
9
  logger = logging.getLogger(__name__)
14
10
 
15
-
16
11
  class ExcelNetworkExporter(NetworkExporter):
17
12
  def __init__(self, sheet_name: str, output_file: str):
18
13
  self.sheet_name = sheet_name
19
14
  self.output_file = output_file
20
15
 
21
- def export_networks(self, networks: list[Network]):
22
- df = pd.json_normalize([network.model_dump() for network in networks])
16
+ def export_networks(self, networks: Generator[Network, None, None]):
17
+ df = pd.DataFrame(network.model_dump() for network in networks)
23
18
 
24
- df = util.expand_list_column(df, "subnets")
19
+ if df.empty:
20
+ logger.info(f"No networks to export for {self.sheet_name}")
21
+ return
22
+
23
+ if 'subnets' in df.columns:
24
+ df = util.expand_list_column(df, "subnets")
25
+
26
+ if 'name' in df.columns:
27
+ df.sort_values(by='name', inplace=True, na_position='last')
25
28
 
26
29
  logger.info(f"Exporting networks for {self.sheet_name}")
27
30
  try:
28
31
  util.export_data_excel(self.output_file, sheet_name=self.sheet_name, df=df)
29
-
30
32
  logger.info(f"Exported networks for {self.sheet_name}")
31
33
  except Exception as e:
32
- logger.warning(f"Exporting networks for {self.sheet_name} error: {e}")
34
+ logger.warning(f"Exporting networks for {self.sheet_name} error: {e}")
@@ -1,7 +1,8 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
+ from osi_dump.model.network import Network
3
4
 
4
5
  class NetworkExporter(ABC):
5
6
  @abstractmethod
6
- def export_networks(self, networks, output_file: str):
7
- pass
7
+ def export_networks(self, networks: Generator[Network, None, None]):
8
+ pass
@@ -1,30 +1,30 @@
1
1
  import pandas as pd
2
-
3
2
  import logging
4
-
5
- from openpyxl import load_workbook
6
-
3
+ from typing import Generator
7
4
  from osi_dump import util
8
5
  from osi_dump.exporter.project.project_exporter import ProjectExporter
9
-
10
6
  from osi_dump.model.project import Project
11
7
 
12
8
  logger = logging.getLogger(__name__)
13
9
 
14
-
15
10
  class ExcelProjectExporter(ProjectExporter):
16
11
  def __init__(self, sheet_name: str, output_file: str):
17
12
  self.sheet_name = sheet_name
18
13
  self.output_file = output_file
19
14
 
20
- def export_projects(self, projects: list[Project]):
21
-
22
- df = pd.DataFrame([project.model_dump() for project in projects])
15
+ def export_projects(self, projects: Generator[Project, None, None]):
16
+ df = pd.DataFrame(p.model_dump() for p in projects)
17
+
18
+ if df.empty:
19
+ logger.info(f"No projects to export for {self.sheet_name}")
20
+ return
21
+
22
+ if 'project_name' in df.columns:
23
+ df.sort_values(by='project_name', inplace=True, na_position='last')
23
24
 
24
25
  logger.info(f"Exporting projects for {self.sheet_name}")
25
26
  try:
26
27
  util.export_data_excel(self.output_file, sheet_name=self.sheet_name, df=df)
27
-
28
28
  logger.info(f"Exported projects for {self.sheet_name}")
29
29
  except Exception as e:
30
- logger.warning(f"Exporting projects for {self.sheet_name} error: {e}")
30
+ logger.warning(f"Exporting projects for {self.sheet_name} error: {e}")
@@ -1,7 +1,8 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
+ from osi_dump.model.project import Project
3
4
 
4
5
  class ProjectExporter(ABC):
5
6
  @abstractmethod
6
- def export_projects(self, projects, output_file: str):
7
- pass
7
+ def export_projects(self, projects: Generator[Project, None, None]):
8
+ pass
@@ -1,30 +1,31 @@
1
1
  import pandas as pd
2
-
3
2
  import logging
4
-
5
- from openpyxl import load_workbook
3
+ from typing import Generator
6
4
 
7
5
  from osi_dump import util
8
6
  from osi_dump.exporter.router.router_exporter import RouterExporter
9
-
10
7
  from osi_dump.model.router import Router
11
8
 
12
9
  logger = logging.getLogger(__name__)
13
10
 
14
-
15
11
  class ExcelRouterExporter(RouterExporter):
16
12
  def __init__(self, sheet_name: str, output_file: str):
17
13
  self.sheet_name = sheet_name
18
14
  self.output_file = output_file
19
15
 
20
- def export_routers(self, routers: list[Router]):
16
+ def export_routers(self, routers: Generator[Router, None, None]):
17
+ df = pd.DataFrame(router.model_dump() for router in routers)
21
18
 
22
- df = pd.DataFrame([router.model_dump() for router in routers])
19
+ if df.empty:
20
+ logger.info(f"No routers to export for {self.sheet_name}")
21
+ return
22
+
23
+ if 'name' in df.columns:
24
+ df.sort_values(by='name', inplace=True, na_position='last')
23
25
 
24
26
  logger.info(f"Exporting routers for {self.sheet_name}")
25
27
  try:
26
28
  util.export_data_excel(self.output_file, sheet_name=self.sheet_name, df=df)
27
-
28
29
  logger.info(f"Exported routers for {self.sheet_name}")
29
30
  except Exception as e:
30
31
  logger.warning(f"Exporting routers for {self.sheet_name} error: {e}")
@@ -1,7 +1,8 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
+ from osi_dump.model.router import Router
3
4
 
4
5
  class RouterExporter(ABC):
5
6
  @abstractmethod
6
- def export_routers(self, routers, output_file: str):
7
+ def export_routers(self, routers: Generator[Router, None, None]):
7
8
  pass
@@ -1,29 +1,31 @@
1
1
  import pandas as pd
2
-
3
2
  import logging
4
-
3
+ from typing import Generator
5
4
 
6
5
  from osi_dump import util
7
-
8
6
  from osi_dump.exporter.volume.volume_exporter import VolumeExporter
9
-
10
7
  from osi_dump.model.volume import Volume
11
8
 
12
9
  logger = logging.getLogger(__name__)
13
10
 
14
-
15
11
  class ExcelVolumeExporter(VolumeExporter):
16
12
  def __init__(self, sheet_name: str, output_file: str):
17
13
  self.sheet_name = sheet_name
18
14
  self.output_file = output_file
19
15
 
20
- def export_volumes(self, volumes: list[Volume]):
21
- df = pd.DataFrame([volume.model_dump() for volume in volumes])
16
+ def export_volumes(self, volumes: Generator[Volume, None, None]):
17
+ df = pd.DataFrame(volume.model_dump() for volume in volumes)
18
+
19
+ if df.empty:
20
+ logger.info(f"No volumes to export for {self.sheet_name}")
21
+ return
22
+
23
+ if 'volume_name' in df.columns:
24
+ df.sort_values(by='volume_name', inplace=True, na_position='last')
22
25
 
23
26
  logger.info(f"Exporting volumes for {self.sheet_name}")
24
27
  try:
25
28
  util.export_data_excel(self.output_file, sheet_name=self.sheet_name, df=df)
26
-
27
29
  logger.info(f"Exported volumes for {self.sheet_name}")
28
30
  except Exception as e:
29
31
  logger.warning(f"Exporting volumes for {self.sheet_name} error: {e}")
@@ -1,7 +1,9 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
+ from osi_dump.model.volume import Volume
3
4
 
4
5
  class VolumeExporter(ABC):
5
6
  @abstractmethod
6
- def export_volumes(self, volumes, output_file: str):
7
+ def export_volumes(self, volumes: Generator[Volume, None, None]):
7
8
  pass
9
+
@@ -1,9 +1,8 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
3
  from osi_dump.model.external_port import ExternalPort
4
4
 
5
-
6
5
  class ExternalPortImporter(ABC):
7
6
  @abstractmethod
8
- def import_external_ports(self) -> list[ExternalPort]:
9
- pass
7
+ def import_external_ports(self) -> Generator[ExternalPort, None, None]:
8
+ pass
@@ -1,146 +1,74 @@
1
1
  import logging
2
-
3
2
  import ipaddress
4
-
5
- import concurrent
6
-
7
- import numpy as np
8
-
3
+ from typing import Generator
9
4
  from openstack.connection import Connection
10
5
  from openstack.network.v2.port import Port as OSPort
11
6
  from openstack.network.v2.subnet import Subnet as OSSubnet
12
- from openstack.network.v2.floating_ip import FloatingIP as OSFloatingIP
13
- from openstack.network.v2.router import Router as OSRouter
14
7
  from openstack.network.v2.network import Network as OSNetwork
15
8
 
16
9
  from osi_dump.importer.external_port.external_port_importer import ExternalPortImporter
17
10
  from osi_dump.model.external_port import ExternalPort
18
-
19
11
  import osi_dump.api.neutron as osi_neutron
20
12
 
21
13
  logger = logging.getLogger(__name__)
22
14
 
23
-
24
15
  class OpenStackExternalPortImporter(ExternalPortImporter):
25
16
  def __init__(self, connection: Connection):
26
17
  self.connection = connection
27
18
 
28
- def _get_external_ports(self) -> list[OSPort]:
29
-
30
- # Get all external networks
31
- networks = self.connection.network.networks(
32
- is_router_external=True,
33
- )
34
-
35
- external_ports = []
36
-
37
- for network in networks:
38
- ex_ports = list(self.connection.network.ports(network_id=network.id))
39
-
40
- for ex_port in ex_ports:
41
- external_ports.append(ex_port)
42
-
43
- # Get all port on those networks
44
-
45
- return external_ports
46
-
47
- def import_external_ports(self) -> list[ExternalPort]:
48
- """Import external_ports information from Openstack
49
-
50
-
51
- Raises:
52
- Exception: Raises exception if fetching external_port failed
53
-
54
- Returns:
55
- list[Instance]: _description_
56
- """
57
-
58
- logger.info(f"Importing external_ports for {self.connection.auth['auth_url']}")
59
-
19
+ def _get_external_ports_stream(self) -> Generator[OSPort, None, None]:
20
+ """Generator để lấy về từng port trên các network ngoại vi."""
60
21
  try:
61
- os_ports: list[OSPort] = self._get_external_ports()
22
+ external_networks = self.connection.network.networks(is_router_external=True)
23
+
24
+ for network in external_networks:
25
+ ports_on_network = self.connection.network.ports(network_id=network.id)
26
+ yield from ports_on_network
62
27
  except Exception as e:
63
- raise Exception(
64
- f"Can not fetch external_ports for {self.connection.auth['auth_url']} {e}"
65
- ) from e
28
+ logger.error(f"Failed to stream external networks/ports: {e}")
66
29
 
67
- external_ports: list[ExternalPort] = []
68
30
 
69
- with concurrent.futures.ThreadPoolExecutor() as executor:
70
- futures = [
71
- executor.submit(self._get_external_port_info, external_port)
72
- for external_port in os_ports
73
- ]
74
- for future in concurrent.futures.as_completed(futures):
75
- external_ports.append(future.result())
76
-
77
- logger.info(f"Imported external_ports for {self.connection.auth['auth_url']}")
78
-
79
- external_ports = sorted(
80
- external_ports,
81
- key=lambda external_port: (
82
- external_port.network_id,
83
- (
84
- ipaddress.ip_address(external_port.ip_address)
85
- if external_port.ip_address
86
- else ipaddress.ip_address("0.0.0.0")
87
- ),
88
- ),
89
- )
90
-
91
- return external_ports
31
+ def import_external_ports(self) -> Generator[ExternalPort, None, None]:
32
+ logger.info(f"Importing external ports for {self.connection.auth['auth_url']}")
33
+
34
+ for os_port in self._get_external_ports_stream():
35
+ yield self._get_external_port_info(os_port)
36
+
37
+ logger.info(f"Finished importing external ports for {self.connection.auth['auth_url']}")
92
38
 
93
39
  def _get_external_port_info(self, external_port: OSPort) -> ExternalPort:
94
-
95
40
  subnet_id = None
96
41
  ip_address = None
97
42
  subnet_cidr = None
98
43
 
99
- try:
100
- ip_address = external_port.fixed_ips[0]["ip_address"]
101
- except Exception as e:
102
- logger.warning(f"No IP address found for port {external_port.id}")
103
-
104
- try:
105
- subnet_id = external_port.fixed_ips[0]["subnet_id"]
106
- except Exception as e:
107
- logger.warning(f"No subnet ID found for {external_port.id}")
108
-
109
- try:
110
- subnet: OSSubnet = self.connection.get_subnet_by_id(subnet_id)
111
-
112
- subnet_cidr = subnet.cidr
113
- except Exception as e:
114
- logger.warning(f"No subnet cidr found for port {external_port.id}")
115
-
116
- mapped_device_project = ["network:floatingip", "network:router_gateway"]
117
-
118
- project_id = (
119
- external_port.project_id
120
- if external_port.device_owner not in mapped_device_project
121
- else self._map_project_id(
44
+ if external_port.fixed_ips:
45
+ ip_address = external_port.fixed_ips[0].get("ip_address")
46
+ subnet_id = external_port.fixed_ips[0].get("subnet_id")
47
+
48
+ if subnet_id:
49
+ try:
50
+ subnet: OSSubnet = self.connection.get_subnet(subnet_id)
51
+ if subnet:
52
+ subnet_cidr = subnet.cidr
53
+ except Exception as e:
54
+ logger.warning(f"Could not get subnet cidr for {subnet_id}: {e}")
55
+
56
+ project_id = external_port.project_id
57
+ mapped_device_projects = ["network:floatingip", "network:router_gateway"]
58
+ if external_port.device_owner in mapped_device_projects and external_port.device_id:
59
+ project_id = self._map_project_id(
122
60
  device_owner=external_port.device_owner,
123
61
  device_id=external_port.device_id,
124
62
  )
125
- )
126
63
 
127
- network: OSNetwork = self.connection.get_network(name_or_id=external_port.network_id)
128
-
129
- vlan_id = None
64
+ network: OSNetwork = self.connection.get_network(external_port.network_id)
65
+ vlan_id = network.provider_segmentation_id if network else None
130
66
 
131
- try:
132
- if not network.segments:
133
- vlan_id = network.provider_segmentation_id
134
- else:
135
- logger.warning(f"Multiple segments mapped for net id {network.id}")
136
- except Exception as e:
137
- logger.warning(f"Can not get vlan ID for external port {external_port.id}, net id {network.id}")
138
-
139
- external_port_ret = ExternalPort(
67
+ return ExternalPort(
140
68
  port_id=external_port.id,
141
69
  project_id=project_id,
142
70
  network_id=external_port.network_id,
143
- network_name=network.name,
71
+ network_name=network.name if network else None,
144
72
  subnet_id=subnet_id,
145
73
  subnet_cidr=subnet_cidr,
146
74
  ip_address=ip_address,
@@ -151,27 +79,12 @@ class OpenStackExternalPortImporter(ExternalPortImporter):
151
79
  vlan_id=vlan_id
152
80
  )
153
81
 
154
- return external_port_ret
155
-
156
82
  def _map_project_id(self, device_owner: str, device_id: str) -> str:
157
-
158
- if device_owner == "network:router_gateway":
159
- return self._map_project_id_router(device_id=device_id)
160
- elif device_owner == "network:floatingip":
161
- return self._map_project_id_floating(device_id=device_id)
162
-
163
- return ""
164
-
165
- def _map_project_id_router(self, device_id: str) -> str:
166
- project_id = osi_neutron.get_router_project(
167
- self.connection, router_id=device_id
168
- )
169
-
170
- return project_id
171
-
172
- def _map_project_id_floating(self, device_id: str) -> str:
173
- project_id = osi_neutron.get_floating_ip_project(
174
- self.connection, floating_ip_id=device_id
175
- )
176
-
177
- return project_id
83
+ try:
84
+ if device_owner == "network:router_gateway":
85
+ return osi_neutron.get_router_project(self.connection, router_id=device_id)
86
+ elif device_owner == "network:floatingip":
87
+ return osi_neutron.get_floating_ip_project(self.connection, floating_ip_id=device_id)
88
+ except Exception as e:
89
+ logger.warning(f"Could not map project ID for {device_owner}:{device_id}: {e}")
90
+ return None
@@ -1,9 +1,9 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
3
  from osi_dump.model.flavor import Flavor
4
4
 
5
-
6
5
  class FlavorImporter(ABC):
7
6
  @abstractmethod
8
- def import_flavors(self) -> list[Flavor]:
7
+ def import_flavors(self) -> Generator[Flavor, 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.compute.v2.flavor import Flavor as OSFlavor
7
5
 
@@ -10,55 +8,35 @@ from osi_dump.model.flavor import Flavor
10
8
 
11
9
  logger = logging.getLogger(__name__)
12
10
 
13
-
14
11
  class OpenStackFlavorImporter(FlavorImporter):
15
12
  def __init__(self, connection: Connection):
16
13
  self.connection = connection
17
14
 
18
- def import_flavors(self) -> list[Flavor]:
19
- """Import flavors information from Openstack
20
-
21
- Raises:
22
- Exception: Raises exception if fetching flavor failed
23
-
24
- Returns:
25
- list[Instance]: _description_
26
- """
27
-
15
+ def import_flavors(self) -> Generator[Flavor, None, None]:
28
16
  logger.info(f"Importing flavors for {self.connection.auth['auth_url']}")
29
-
30
17
  try:
31
- osflavors: list[OSFlavor] = list(self.connection.list_flavors())
32
- except Exception as e:
33
- raise Exception(
34
- f"Can not fetch flavors for {self.connection.auth['auth_url']}"
35
- ) from e
36
-
37
- flavors: list[Flavor] = []
18
+ flavor_iterator = self.connection.list_flavors()
38
19
 
39
- with concurrent.futures.ThreadPoolExecutor() as executor:
40
- futures = [
41
- executor.submit(self._get_flavor_info, osflavor)
42
- for osflavor in osflavors
43
- ]
44
- for future in concurrent.futures.as_completed(futures):
45
- flavors.append(future.result())
20
+ for osflavor in flavor_iterator:
21
+ yield self._get_flavor_info(osflavor)
46
22
 
47
- logger.info(f"Imported flavors for {self.connection.auth['auth_url']}")
23
+ except Exception as e:
24
+ logger.error(f"Cannot fetch flavors for {self.connection.auth['auth_url']}: {e}")
25
+ return
48
26
 
49
- return flavors
27
+ logger.info(f"Finished importing flavors for {self.connection.auth['auth_url']}")
50
28
 
51
29
  def _get_flavor_info(self, flavor: OSFlavor) -> Flavor:
52
30
 
53
- ret_flavor = Flavor(
31
+ swap_val = flavor.swap if flavor.swap else None
32
+
33
+ return Flavor(
54
34
  flavor_id=flavor.id,
55
35
  flavor_name=flavor.name,
56
36
  ram=flavor.ram,
57
37
  vcpus=flavor.vcpus,
58
38
  disk=flavor.disk,
59
- swap=flavor.swap,
39
+ swap=swap_val,
60
40
  public=flavor.is_public,
61
41
  properties=flavor.extra_specs,
62
42
  )
63
-
64
- return ret_flavor
@@ -1,9 +1,9 @@
1
1
  from abc import ABC, abstractmethod
2
-
2
+ from typing import Generator
3
3
  from osi_dump.model.floating_ip import FloatingIP
4
4
 
5
-
6
5
  class FloatingIPImporter(ABC):
7
6
  @abstractmethod
8
- def import_floating_ips(self) -> list[FloatingIP]:
7
+ def import_floating_ips(self) -> Generator[FloatingIP, None, None]:
9
8
  pass
9
+