osi-dump 0.1.3.3.4.3__py3-none-any.whl → 0.1.4__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 (102) hide show
  1. osi_dump/__main__.py +4 -4
  2. osi_dump/api/keystone.py +70 -70
  3. osi_dump/api/neutron.py +65 -65
  4. osi_dump/api/octavia.py +94 -94
  5. osi_dump/api/placement.py +41 -41
  6. osi_dump/batch_handler/__init__.py +6 -5
  7. osi_dump/batch_handler/external_port_batch_handler.py +55 -55
  8. osi_dump/batch_handler/flavor_batch_handler.py +51 -51
  9. osi_dump/batch_handler/floating_ip_batch_handler.py +57 -57
  10. osi_dump/batch_handler/hypervisor_batch_handler.py +55 -55
  11. osi_dump/batch_handler/image_batch_handler.py +51 -51
  12. osi_dump/batch_handler/instance_batch_handler.py +46 -54
  13. osi_dump/batch_handler/load_balancer_batch_handler.py +59 -59
  14. osi_dump/batch_handler/network_batch_handler.py +51 -51
  15. osi_dump/batch_handler/project_batch_handler.py +51 -51
  16. osi_dump/batch_handler/role_assignment_batch_handler.py +38 -61
  17. osi_dump/batch_handler/router_batch_handler.py +49 -49
  18. osi_dump/batch_handler/security_group_batch_handler.py +37 -0
  19. osi_dump/batch_handler/volume_batch_handler.py +45 -45
  20. osi_dump/cli.py +267 -257
  21. osi_dump/exporter/external_port/excel_external_port_exporter.py +34 -34
  22. osi_dump/exporter/external_port/external_port_exporter.py +7 -7
  23. osi_dump/exporter/flavor/excel_flavor_exporter.py +30 -30
  24. osi_dump/exporter/flavor/flavor_exporter.py +7 -7
  25. osi_dump/exporter/floating_ip/excel_floating_ip_exporter.py +30 -30
  26. osi_dump/exporter/floating_ip/floating_ip_exporter.py +7 -7
  27. osi_dump/exporter/hypervisor/excel_hypervisor_exporter.py +32 -32
  28. osi_dump/exporter/hypervisor/hypervisor_exporter.py +7 -7
  29. osi_dump/exporter/image/excel_image_exporter.py +28 -28
  30. osi_dump/exporter/image/image_exporter.py +7 -7
  31. osi_dump/exporter/instance/excel_instance_exporter.py +29 -29
  32. osi_dump/exporter/instance/instance_exporter.py +8 -7
  33. osi_dump/exporter/load_balancer/excel_load_balancer_exporter.py +36 -36
  34. osi_dump/exporter/load_balancer/load_balancer_exporter.py +7 -7
  35. osi_dump/exporter/network/excel_network_exporter.py +32 -32
  36. osi_dump/exporter/network/network_exporter.py +7 -7
  37. osi_dump/exporter/project/excel_project_exporter.py +30 -30
  38. osi_dump/exporter/project/project_exporter.py +7 -7
  39. osi_dump/exporter/role_assignment/excel_role_assignment_exporter.py +43 -35
  40. osi_dump/exporter/role_assignment/role_assignment_exporter.py +7 -7
  41. osi_dump/exporter/router/excel_router_exporter.py +30 -30
  42. osi_dump/exporter/router/router_exporter.py +7 -7
  43. osi_dump/exporter/security_group/excel_security_group_exporter.py +35 -0
  44. osi_dump/exporter/security_group/security_group_exporter.py +8 -0
  45. osi_dump/exporter/volume/excel_volume_exporter.py +29 -29
  46. osi_dump/exporter/volume/volume_exporter.py +7 -7
  47. osi_dump/importer/external_port/external_port_importer.py +9 -9
  48. osi_dump/importer/external_port/openstack_external_port_importer.py +177 -177
  49. osi_dump/importer/flavor/flavor_importer.py +9 -9
  50. osi_dump/importer/flavor/openstack_flavor_importer.py +64 -64
  51. osi_dump/importer/floating_ip/floating_ip_importer.py +9 -9
  52. osi_dump/importer/floating_ip/openstack_floating_ip_importer.py +68 -68
  53. osi_dump/importer/hypervisor/hypervisor_importer.py +9 -9
  54. osi_dump/importer/hypervisor/openstack_hypervisor_importer.py +137 -137
  55. osi_dump/importer/image/image_importer.py +9 -9
  56. osi_dump/importer/image/openstack_image_importer.py +81 -81
  57. osi_dump/importer/instance/instance_importer.py +8 -9
  58. osi_dump/importer/instance/openstack_instance_importer.py +136 -136
  59. osi_dump/importer/load_balancer/load_balancer_importer.py +9 -9
  60. osi_dump/importer/load_balancer/openstack_load_balancer_importer.py +113 -113
  61. osi_dump/importer/network/network_importer.py +9 -9
  62. osi_dump/importer/network/openstack_network_importer.py +93 -93
  63. osi_dump/importer/project/openstack_project_importer.py +141 -141
  64. osi_dump/importer/project/project_importer.py +9 -9
  65. osi_dump/importer/role_assignment/openstack_role_assignment_importer.py +117 -147
  66. osi_dump/importer/role_assignment/role_assignment_importer.py +16 -9
  67. osi_dump/importer/router/openstack_router_importer.py +87 -87
  68. osi_dump/importer/router/router_importer.py +9 -9
  69. osi_dump/importer/security_group/openstack_security_group_importer.py +54 -0
  70. osi_dump/importer/security_group/security_group_importer.py +8 -0
  71. osi_dump/importer/volume/openstack_volume_importer.py +81 -81
  72. osi_dump/importer/volume/volume_importer.py +9 -9
  73. osi_dump/model/authentication_info.py +15 -15
  74. osi_dump/model/external_port.py +30 -30
  75. osi_dump/model/flavor.py +20 -20
  76. osi_dump/model/floating_ip.py +24 -24
  77. osi_dump/model/hypervisor.py +24 -24
  78. osi_dump/model/image.py +27 -27
  79. osi_dump/model/instance.py +29 -29
  80. osi_dump/model/load_balancer.py +26 -26
  81. osi_dump/model/network.py +25 -25
  82. osi_dump/model/project.py +33 -33
  83. osi_dump/model/role_assignment.py +30 -23
  84. osi_dump/model/router.py +23 -23
  85. osi_dump/model/security_group.py +22 -0
  86. osi_dump/model/volume.py +25 -25
  87. osi_dump/os_connection/get_connections.py +67 -67
  88. osi_dump/util/__init__.py +7 -7
  89. osi_dump/util/create_file.py +11 -11
  90. osi_dump/util/excel_autosize_column.py +39 -39
  91. osi_dump/util/excel_sort_sheet.py +35 -35
  92. osi_dump/util/export_data_excel.py +36 -36
  93. osi_dump/util/extract_hostname.py +5 -5
  94. osi_dump/util/openstack_util.py +48 -48
  95. osi_dump/util/panda_excel.py +26 -26
  96. osi_dump/util/validate_dir_path.py +20 -20
  97. {osi_dump-0.1.3.3.4.3.dist-info → osi_dump-0.1.4.dist-info}/METADATA +40 -40
  98. osi_dump-0.1.4.dist-info/RECORD +130 -0
  99. osi_dump-0.1.3.3.4.3.dist-info/RECORD +0 -124
  100. {osi_dump-0.1.3.3.4.3.dist-info → osi_dump-0.1.4.dist-info}/WHEEL +0 -0
  101. {osi_dump-0.1.3.3.4.3.dist-info → osi_dump-0.1.4.dist-info}/entry_points.txt +0 -0
  102. {osi_dump-0.1.3.3.4.3.dist-info → osi_dump-0.1.4.dist-info}/top_level.txt +0 -0
@@ -1,141 +1,141 @@
1
- import logging
2
-
3
- import concurrent
4
-
5
- from openstack.connection import Connection
6
- from openstack.identity.v3.project import Project as OSProject
7
- from openstack.load_balancer.v2.load_balancer import LoadBalancer as OSLoadBalancer
8
-
9
- from osi_dump.importer.project.project_importer import ProjectImporter
10
- from osi_dump.model.project import Project
11
- import osi_dump.api.octavia as octavia_api
12
- logger = logging.getLogger(__name__)
13
-
14
-
15
- class OpenStackProjectImporter(ProjectImporter):
16
- def __init__(self, connection: Connection):
17
- self.connection = connection
18
-
19
- def import_projects(self) -> list[Project]:
20
- """Import projects information from Openstack
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']}")
30
- try:
31
- osload_balancers: list[OSLoadBalancer] = octavia_api.get_load_balancers(
32
- connection=self.connection
33
- )
34
- except Exception as e:
35
- raise Exception(
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
46
-
47
- try:
48
- osprojects: list[OSProject] = list(self.connection.identity.projects())
49
- except Exception as e:
50
- raise Exception(
51
- f"Can not fetch projects for {self.connection.auth['auth_url']}"
52
- ) from e
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
67
-
68
- def _get_project_info(self, project: OSProject, project_lb_dict: dict) -> Project:
69
-
70
- usage_instance=None
71
- quota_instance=None
72
- usage_ram=None
73
- quota_ram=None
74
- usage_vcpu=None
75
- quota_vcpu=None
76
-
77
- try:
78
- compute_quotas = self.connection.compute.get_quota_set(
79
- project.id, usage=True
80
- )
81
-
82
- usage_instance=compute_quotas.usage["instances"]
83
- quota_instance=compute_quotas.instances
84
- usage_ram=compute_quotas.usage["ram"]
85
- quota_ram=compute_quotas.ram
86
- usage_vcpu=compute_quotas.usage["cores"]
87
- quota_vcpu=compute_quotas.cores
88
- except Exception as e:
89
- logger.warning(f"Get compute quotas failed for {project.id} error: {e}")
90
-
91
- usage_volume=None
92
- quota_volume=None
93
- usage_snapshot=None
94
- quota_snapshot=None
95
- usage_storage=None
96
- quota_storage=None
97
- try:
98
- storage_quotas = self.connection.block_storage.get_quota_set(
99
- project.id, usage=True
100
- )
101
- usage_volume=storage_quotas.usage["volumes"]
102
- quota_volume=storage_quotas.volumes
103
- usage_snapshot=storage_quotas.usage["snapshots"]
104
- quota_snapshot=storage_quotas.snapshots
105
- usage_storage=storage_quotas.usage["gigabytes"]
106
- quota_storage=storage_quotas.gigabytes
107
- except Exception as e:
108
- logger.warning(f"Get storage quotas failed for {project.id} error: {e}")
109
-
110
- domain_name = None
111
- try:
112
- domain = self.connection.identity.get_domain(project.domain_id)
113
- domain_name = domain.name
114
- except Exception as e:
115
- logger.warning(f"Get domain failed for {project.domain_id} error: {e}")
116
-
117
- lb_count = project_lb_dict.get(project.id)
118
-
119
- project_ret = Project(
120
- project_id=project.id,
121
- project_name=project.name,
122
- domain_id=project.domain_id,
123
- domain_name=domain_name,
124
- enabled=project.is_enabled,
125
- parent_id=project.parent_id,
126
- usage_instance=usage_instance,
127
- quota_instance=quota_instance,
128
- usage_ram=usage_ram,
129
- quota_ram=quota_ram,
130
- usage_vcpu=usage_vcpu,
131
- quota_vcpu=quota_vcpu,
132
- usage_volume=usage_volume,
133
- quota_volume=quota_volume,
134
- usage_snapshot=usage_snapshot,
135
- quota_snapshot=quota_snapshot,
136
- usage_storage=usage_storage,
137
- quota_storage=quota_storage,
138
- load_balancer_count=lb_count
139
- )
140
-
141
- return project_ret
1
+ import logging
2
+
3
+ import concurrent
4
+
5
+ from openstack.connection import Connection
6
+ from openstack.identity.v3.project import Project as OSProject
7
+ from openstack.load_balancer.v2.load_balancer import LoadBalancer as OSLoadBalancer
8
+
9
+ from osi_dump.importer.project.project_importer import ProjectImporter
10
+ from osi_dump.model.project import Project
11
+ import osi_dump.api.octavia as octavia_api
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class OpenStackProjectImporter(ProjectImporter):
16
+ def __init__(self, connection: Connection):
17
+ self.connection = connection
18
+
19
+ def import_projects(self) -> list[Project]:
20
+ """Import projects information from Openstack
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']}")
30
+ try:
31
+ osload_balancers: list[OSLoadBalancer] = octavia_api.get_load_balancers(
32
+ connection=self.connection
33
+ )
34
+ except Exception as e:
35
+ raise Exception(
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
46
+
47
+ try:
48
+ osprojects: list[OSProject] = list(self.connection.identity.projects())
49
+ except Exception as e:
50
+ raise Exception(
51
+ f"Can not fetch projects for {self.connection.auth['auth_url']}"
52
+ ) from e
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
67
+
68
+ def _get_project_info(self, project: OSProject, project_lb_dict: dict) -> Project:
69
+
70
+ usage_instance=None
71
+ quota_instance=None
72
+ usage_ram=None
73
+ quota_ram=None
74
+ usage_vcpu=None
75
+ quota_vcpu=None
76
+
77
+ try:
78
+ compute_quotas = self.connection.compute.get_quota_set(
79
+ project.id, usage=True
80
+ )
81
+
82
+ usage_instance=compute_quotas.usage["instances"]
83
+ quota_instance=compute_quotas.instances
84
+ usage_ram=compute_quotas.usage["ram"]
85
+ quota_ram=compute_quotas.ram
86
+ usage_vcpu=compute_quotas.usage["cores"]
87
+ quota_vcpu=compute_quotas.cores
88
+ except Exception as e:
89
+ logger.warning(f"Get compute quotas failed for {project.id} error: {e}")
90
+
91
+ usage_volume=None
92
+ quota_volume=None
93
+ usage_snapshot=None
94
+ quota_snapshot=None
95
+ usage_storage=None
96
+ quota_storage=None
97
+ try:
98
+ storage_quotas = self.connection.block_storage.get_quota_set(
99
+ project.id, usage=True
100
+ )
101
+ usage_volume=storage_quotas.usage["volumes"]
102
+ quota_volume=storage_quotas.volumes
103
+ usage_snapshot=storage_quotas.usage["snapshots"]
104
+ quota_snapshot=storage_quotas.snapshots
105
+ usage_storage=storage_quotas.usage["gigabytes"]
106
+ quota_storage=storage_quotas.gigabytes
107
+ except Exception as e:
108
+ logger.warning(f"Get storage quotas failed for {project.id} error: {e}")
109
+
110
+ domain_name = None
111
+ try:
112
+ domain = self.connection.identity.get_domain(project.domain_id)
113
+ domain_name = domain.name
114
+ except Exception as e:
115
+ logger.warning(f"Get domain failed for {project.domain_id} error: {e}")
116
+
117
+ lb_count = project_lb_dict.get(project.id)
118
+
119
+ project_ret = Project(
120
+ project_id=project.id,
121
+ project_name=project.name,
122
+ domain_id=project.domain_id,
123
+ domain_name=domain_name,
124
+ enabled=project.is_enabled,
125
+ parent_id=project.parent_id,
126
+ usage_instance=usage_instance,
127
+ quota_instance=quota_instance,
128
+ usage_ram=usage_ram,
129
+ quota_ram=quota_ram,
130
+ usage_vcpu=usage_vcpu,
131
+ quota_vcpu=quota_vcpu,
132
+ usage_volume=usage_volume,
133
+ quota_volume=quota_volume,
134
+ usage_snapshot=usage_snapshot,
135
+ quota_snapshot=quota_snapshot,
136
+ usage_storage=usage_storage,
137
+ quota_storage=quota_storage,
138
+ load_balancer_count=lb_count
139
+ )
140
+
141
+ return project_ret
@@ -1,9 +1,9 @@
1
- from abc import ABC, abstractmethod
2
-
3
- from osi_dump.model.project import Project
4
-
5
-
6
- class ProjectImporter(ABC):
7
- @abstractmethod
8
- def import_projects(self) -> list[Project]:
9
- pass
1
+ from abc import ABC, abstractmethod
2
+
3
+ from osi_dump.model.project import Project
4
+
5
+
6
+ class ProjectImporter(ABC):
7
+ @abstractmethod
8
+ def import_projects(self) -> list[Project]:
9
+ pass
@@ -1,147 +1,117 @@
1
- import logging
2
-
3
- import concurrent
4
-
5
- from openstack.connection import Connection
6
- from openstack.identity.v3.role_assignment import RoleAssignment as OSRoleAssignment
7
- from openstack.identity.v3.user import User as OSUser
8
-
9
-
10
- from osi_dump.importer.role_assignment.role_assignment_importer import (
11
- RoleAssignmentImporter,
12
- )
13
- from osi_dump.model.role_assignment import RoleAssignment
14
-
15
- from osi_dump.api.keystone import get_role_assignments, get_users
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- class OpenStackRoleAssignmentImporter(RoleAssignmentImporter):
21
- def __init__(self, connection: Connection):
22
- self.connection = connection
23
-
24
- self.users: dict[str, dict] = {}
25
- self.roles = {}
26
-
27
- def _get_users(self):
28
- os_users = get_users(self.connection)
29
-
30
- for os_user in os_users:
31
- self.users[os_user["id"]] = os_user
32
-
33
- def _get_roles(self):
34
- os_roles = self.connection.identity.roles()
35
-
36
- for os_role in os_roles:
37
- self.roles[os_role.id] = os_role.name
38
-
39
- def import_role_assignments(self) -> list[RoleAssignment]:
40
- """Import role_assignments information from Openstack
41
-
42
- Raises:
43
- Exception: Raises exception if fetching role_assignment failed
44
-
45
- Returns:
46
- list[RoleAssignment]: _description_
47
- """
48
-
49
- logger.info(
50
- f"Importing role_assignments for {self.connection.auth['auth_url']}"
51
- )
52
-
53
- try:
54
- self._get_users()
55
- except Exception as e:
56
- logger.info(f"Getting user list failed {e}")
57
-
58
- try:
59
- self._get_roles()
60
- except Exception as e:
61
- logger.info(f"Getting role list failed {e}")
62
-
63
- try:
64
- osrole_assignments: list[OSRoleAssignment] = list(
65
- self.connection.identity.role_assignments()
66
- )
67
-
68
- except Exception as e:
69
- raise Exception(
70
- f"Can not fetch role_assignments for {self.connection.auth['auth_url']} {e}"
71
- ) from e
72
-
73
- role_assignments: list[RoleAssignment] = []
74
-
75
- with concurrent.futures.ThreadPoolExecutor() as executor:
76
- futures = [
77
- executor.submit(self._get_role_assignment_info, role_assignment)
78
- for role_assignment in osrole_assignments
79
- ]
80
- for future in concurrent.futures.as_completed(futures):
81
- role_assignments.append(future.result())
82
-
83
- logger.info(f"Imported role_assignments for {self.connection.auth['auth_url']}")
84
-
85
- return role_assignments
86
-
87
- def _get_role_assignment_info(
88
- self, role_assignment: OSRoleAssignment
89
- ) -> RoleAssignment:
90
-
91
- user_id = None
92
- role_id = None
93
-
94
- try:
95
- user_id: str = role_assignment["user"]["id"]
96
- except Exception as e:
97
- logger.warning(f"Can not get user id: {e}")
98
-
99
- try:
100
- role_id = role_assignment["role"]["id"]
101
- except Exception as e:
102
- logger.warning(f"Can not get role id: {e}")
103
-
104
- user_name = None
105
- role_name = None
106
-
107
- password_expires_at = None
108
- options = None
109
-
110
- try:
111
- user_name = self.users[user_id]["name"]
112
- except Exception as e:
113
- logger.warning(f"Can not get user name: {e}")
114
-
115
- try:
116
- role_name = self.roles[role_id]
117
- except Exception as e:
118
- logger.warning(f"Can not get role name: {e}")
119
-
120
- try:
121
- password_expires_at = self.users[user_id]["password_expires_at"]
122
- except Exception as e:
123
- logger.warning(f"Can not get password expires at: {e}")
124
-
125
-
126
- try:
127
- options = self.users[user_id]["options"]
128
- except Exception as e:
129
- logger.warning(f"Can not get option")
130
-
131
- try:
132
- enabled = self.users[user_id]["enabled"]
133
- except Exception as e:
134
- logger.warning(f"Can not get enabled")
135
-
136
- role_assignment_ret = RoleAssignment(
137
- user_id=user_id,
138
- user_name=user_name,
139
- role_id=role_id,
140
- role_name=role_name,
141
- enabled=enabled,
142
- scope=role_assignment["scope"],
143
- password_expires_at=password_expires_at,
144
- options=options
145
- )
146
-
147
- return role_assignment_ret
1
+ import logging
2
+ from openstack.connection import Connection
3
+ from openstack.identity.v3.role_assignment import RoleAssignment as OSRoleAssignment
4
+ from typing import Generator
5
+
6
+ from .role_assignment_importer import RoleAssignmentImporter
7
+ from osi_dump.model.role_assignment import UserRoleAssignment, GroupRoleAssignment, EffectiveUserRole
8
+ from osi_dump.api.keystone import get_users
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ class OpenStackRoleAssignmentImporter(RoleAssignmentImporter):
13
+ def __init__(self, connection: Connection):
14
+ self.connection = connection
15
+ self.users = {}
16
+ self.roles = {}
17
+ self.groups = {}
18
+ self.group_members = {} # group_id -> [user_id_1, user_id_2]
19
+ self._raw_assignments = None # Cache
20
+
21
+ def _fetch_all_data(self):
22
+ """pre-cache for metadata."""
23
+ if self._raw_assignments is not None:
24
+ return
25
+
26
+ logger.info(f"Pre-caching all role assignment metadata for {self.connection.auth['auth_url']}")
27
+
28
+ try:
29
+ os_users = get_users(self.connection)
30
+ for os_user in os_users: self.users[os_user["id"]] = os_user
31
+ except Exception as e:
32
+ logger.error(f"Could not fetch users: {e}")
33
+
34
+ try:
35
+ os_roles = self.connection.identity.roles()
36
+ for os_role in os_roles: self.roles[os_role.id] = os_role.name
37
+ except Exception as e:
38
+ logger.error(f"Could not fetch roles: {e}")
39
+
40
+ try:
41
+ os_groups = list(self.connection.identity.groups())
42
+ for group in os_groups:
43
+ self.groups[group.id] = group.name
44
+ try:
45
+ members = list(self.connection.identity.group_users(group))
46
+ self.group_members[group.id] = [user.id for user in members]
47
+ except Exception as e:
48
+ logger.warning(f"Could not fetch members for group {group.name}: {e}")
49
+ self.group_members[group.id] = []
50
+ except Exception as e:
51
+ logger.error(f"Could not fetch groups: {e}")
52
+
53
+ try:
54
+ self._raw_assignments = list(self.connection.identity.role_assignments())
55
+ except Exception as e:
56
+ logger.error(f"Could not fetch role assignments: {e}")
57
+ self._raw_assignments = []
58
+
59
+ def get_user_roles(self) -> Generator[UserRoleAssignment, None, None]:
60
+ self._fetch_all_data()
61
+ for assignment in self._raw_assignments:
62
+ if assignment.user:
63
+ user_id = assignment.user.get('id')
64
+ user_info = self.users.get(user_id, {})
65
+ role_id = assignment.role.get('id') if assignment.role else None
66
+ yield UserRoleAssignment(
67
+ user_id=user_id,
68
+ user_name=user_info.get('name'),
69
+ role_id=role_id,
70
+ role_name=self.roles.get(role_id),
71
+ scope=assignment.scope,
72
+ enabled=user_info.get('enabled'),
73
+ password_expires_at=user_info.get('password_expires_at'),
74
+ options=user_info.get('options')
75
+ )
76
+
77
+ def get_group_roles(self) -> Generator[GroupRoleAssignment, None, None]:
78
+ self._fetch_all_data()
79
+ for assignment in self._raw_assignments:
80
+ if assignment.group:
81
+ group_id = assignment.group.get('id')
82
+ role_id = assignment.role.get('id') if assignment.role else None
83
+ yield GroupRoleAssignment(
84
+ group_id=group_id,
85
+ group_name=self.groups.get(group_id),
86
+ role_id=role_id,
87
+ role_name=self.roles.get(role_id),
88
+ scope=assignment.scope
89
+ )
90
+
91
+ def calculate_effective_roles(self) -> Generator[EffectiveUserRole, None, None]:
92
+ # generator
93
+ # direct role
94
+ for user_role in self.get_user_roles():
95
+ yield EffectiveUserRole(
96
+ user_id=user_role.user_id,
97
+ user_name=user_role.user_name,
98
+ role_id=user_role.role_id,
99
+ role_name=user_role.role_name,
100
+ scope=user_role.scope,
101
+ inherited_from_group='[Direct]'
102
+ )
103
+
104
+ # inherited_from_group
105
+ for group_role in self.get_group_roles():
106
+ group_id = group_role.group_id
107
+ if group_id in self.group_members:
108
+ for user_id in self.group_members[group_id]:
109
+ user_info = self.users.get(user_id, {})
110
+ yield EffectiveUserRole(
111
+ user_id=user_id,
112
+ user_name=user_info.get('name'),
113
+ role_id=group_role.role_id,
114
+ role_name=group_role.role_name,
115
+ scope=group_role.scope,
116
+ inherited_from_group=group_role.group_name
117
+ )
@@ -1,9 +1,16 @@
1
- from abc import ABC, abstractmethod
2
-
3
- from osi_dump.model.role_assignment import RoleAssignment
4
-
5
-
6
- class RoleAssignmentImporter(ABC):
7
- @abstractmethod
8
- def import_role_assignments(self) -> list[RoleAssignment]:
9
- pass
1
+ from abc import ABC, abstractmethod
2
+ from typing import Generator
3
+ from osi_dump.model.role_assignment import UserRoleAssignment, GroupRoleAssignment, EffectiveUserRole
4
+
5
+ class RoleAssignmentImporter(ABC):
6
+ @abstractmethod
7
+ def get_user_roles(self) -> Generator[UserRoleAssignment, None, None]:
8
+ pass
9
+
10
+ @abstractmethod
11
+ def get_group_roles(self) -> Generator[GroupRoleAssignment, None, None]:
12
+ pass
13
+
14
+ @abstractmethod
15
+ def calculate_effective_roles(self) -> Generator[EffectiveUserRole, None, None]:
16
+ pass