osi-dump 0.1.4__py3-none-any.whl → 0.1.5__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/role_assignment_batch_handler.py +0 -1
- osi_dump/exporter/role_assignment/excel_role_assignment_exporter.py +2 -10
- osi_dump/importer/instance/openstack_instance_importer.py +33 -59
- osi_dump/importer/role_assignment/openstack_role_assignment_importer.py +10 -46
- osi_dump/importer/role_assignment/role_assignment_importer.py +5 -5
- osi_dump/model/role_assignment.py +8 -8
- {osi_dump-0.1.4.dist-info → osi_dump-0.1.5.dist-info}/METADATA +1 -1
- {osi_dump-0.1.4.dist-info → osi_dump-0.1.5.dist-info}/RECORD +11 -11
- {osi_dump-0.1.4.dist-info → osi_dump-0.1.5.dist-info}/WHEEL +0 -0
- {osi_dump-0.1.4.dist-info → osi_dump-0.1.5.dist-info}/entry_points.txt +0 -0
- {osi_dump-0.1.4.dist-info → osi_dump-0.1.5.dist-info}/top_level.txt +0 -0
@@ -12,22 +12,14 @@ class ExcelRoleAssignmentExporter(RoleAssignmentExporter):
|
|
12
12
|
self.output_file = output_file
|
13
13
|
|
14
14
|
def export_role_assignments(self, importer: RoleAssignmentImporter):
|
15
|
-
# Sheet 1: User
|
16
|
-
df_effective = pd.json_normalize(
|
17
|
-
(role.model_dump() for role in importer.calculate_effective_roles())
|
18
|
-
)
|
19
|
-
if not df_effective.empty:
|
20
|
-
df_effective.sort_values(by=['user_name', 'role_name'], inplace=True)
|
21
|
-
self._export_to_sheet(df_effective, f"{self.sheet_name_prefix}-effective")
|
22
|
-
|
23
|
-
# Sheet 2: Raw User Roles
|
15
|
+
# Sheet 1: Raw User Role Assignments
|
24
16
|
df_user = pd.json_normalize(
|
25
17
|
(role.model_dump() for role in importer.get_user_roles())
|
26
18
|
)
|
27
19
|
if not df_user.empty:
|
28
20
|
self._export_to_sheet(df_user, f"{self.sheet_name_prefix}-user")
|
29
21
|
|
30
|
-
# Sheet
|
22
|
+
# Sheet 2: Raw Group Role Assignments
|
31
23
|
df_group = pd.json_normalize(
|
32
24
|
(role.model_dump() for role in importer.get_group_roles())
|
33
25
|
)
|
@@ -1,10 +1,7 @@
|
|
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.server import Server
|
7
|
-
|
8
5
|
from openstack.compute.v2.flavor import Flavor as OSFlavor
|
9
6
|
|
10
7
|
from osi_dump.importer.instance.instance_importer import InstanceImporter
|
@@ -17,63 +14,45 @@ class OpenStackInstanceImporter(InstanceImporter):
|
|
17
14
|
def __init__(self, connection: Connection):
|
18
15
|
self.connection = connection
|
19
16
|
|
20
|
-
def import_instances(self) ->
|
21
|
-
"""Import instances information from Openstack
|
22
|
-
|
23
|
-
Raises:
|
24
|
-
Exception: Raises exception if fetching server failed
|
25
|
-
|
26
|
-
Returns:
|
27
|
-
list[Instance]: _description_
|
28
|
-
"""
|
17
|
+
def import_instances(self) -> Generator[Instance, None, None]:
|
18
|
+
"""Import instances information from Openstack as a generator."""
|
29
19
|
|
30
20
|
logger.info(f"Importing instances for {self.connection.auth['auth_url']}")
|
31
|
-
|
32
21
|
try:
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
raise Exception(
|
38
|
-
f"Can not fetch instances for {self.connection.auth['auth_url']}: {e}"
|
39
|
-
) from e
|
40
|
-
|
41
|
-
instances: list[Instance] = []
|
42
|
-
|
43
|
-
with concurrent.futures.ThreadPoolExecutor() as executor:
|
44
|
-
futures = [
|
45
|
-
executor.submit(self._get_instance_info, server) for server in servers
|
46
|
-
]
|
47
|
-
for future in concurrent.futures.as_completed(futures):
|
48
|
-
instances.append(future.result())
|
22
|
+
server_iterator = self.connection.compute.servers(details=True, all_projects=True)
|
23
|
+
|
24
|
+
for server in server_iterator:
|
25
|
+
yield self._get_instance_info(server)
|
49
26
|
|
50
|
-
|
51
|
-
|
52
|
-
|
27
|
+
except Exception as e:
|
28
|
+
logger.error(f"Cannot fetch instances for {self.connection.auth['auth_url']}: {e}")
|
29
|
+
return
|
30
|
+
|
31
|
+
logger.info(f"Finished importing instances for {self.connection.auth['auth_url']}")
|
53
32
|
|
54
33
|
def _get_instance_info(self, server: Server) -> Instance:
|
55
|
-
|
56
34
|
project_name = None
|
57
35
|
project_id = None
|
36
|
+
project = None
|
58
37
|
try:
|
59
38
|
project = self.connection.identity.get_project(server.project_id)
|
60
39
|
project_name = project.name
|
61
40
|
project_id = project.id
|
62
41
|
except Exception as e:
|
63
|
-
logger.
|
42
|
+
logger.warning(
|
64
43
|
f"Unable to obtain project name for instance: {server.name}: {e}"
|
65
44
|
)
|
66
45
|
|
67
46
|
domain_name = None
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
47
|
+
if project:
|
48
|
+
try:
|
49
|
+
domain = self.connection.identity.get_domain(project.domain_id)
|
50
|
+
domain_name = domain.name
|
51
|
+
except Exception as e:
|
52
|
+
logger.warning(
|
53
|
+
f"Unable to obtain domain name for instance {server.name}: {e}"
|
54
|
+
)
|
75
55
|
|
76
|
-
# Lấy thông tin IPv4 private
|
77
56
|
private_v4_ips = []
|
78
57
|
floating_ip = None
|
79
58
|
|
@@ -91,28 +70,25 @@ class OpenStackInstanceImporter(InstanceImporter):
|
|
91
70
|
|
92
71
|
vgpus = None
|
93
72
|
vgpu_type = None
|
94
|
-
|
95
73
|
vgpu_metadata_property = "pci_passthrough:alias"
|
96
74
|
|
97
75
|
try:
|
98
76
|
flavor: OSFlavor = self.connection.get_flavor(
|
99
77
|
name_or_id=server.flavor["id"]
|
100
78
|
)
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
except Exception as e:
|
79
|
+
if flavor and flavor.extra_specs:
|
80
|
+
vgpu_prop: str = flavor.extra_specs.get(vgpu_metadata_property)
|
81
|
+
if vgpu_prop:
|
82
|
+
vgpu_props = vgpu_prop.split(":")
|
83
|
+
vgpu_type = vgpu_props[0]
|
84
|
+
vgpus = int(vgpu_props[1])
|
85
|
+
except Exception:
|
110
86
|
pass
|
111
87
|
|
112
|
-
image_id = server.image
|
113
|
-
flavor_id = server.flavor
|
88
|
+
image_id = server.image.get("id") if server.image else None
|
89
|
+
flavor_id = server.flavor.get("id") if server.flavor else None
|
114
90
|
|
115
|
-
|
91
|
+
return Instance(
|
116
92
|
instance_id=server.id,
|
117
93
|
instance_name=server.name,
|
118
94
|
project_id=project_id,
|
@@ -131,6 +107,4 @@ class OpenStackInstanceImporter(InstanceImporter):
|
|
131
107
|
vgpu_type=vgpu_type,
|
132
108
|
image_id=image_id,
|
133
109
|
flavor_id=flavor_id
|
134
|
-
)
|
135
|
-
|
136
|
-
return instance
|
110
|
+
)
|
@@ -4,7 +4,7 @@ from openstack.identity.v3.role_assignment import RoleAssignment as OSRoleAssign
|
|
4
4
|
from typing import Generator
|
5
5
|
|
6
6
|
from .role_assignment_importer import RoleAssignmentImporter
|
7
|
-
from osi_dump.model.role_assignment import UserRoleAssignment, GroupRoleAssignment
|
7
|
+
from osi_dump.model.role_assignment import UserRoleAssignment, GroupRoleAssignment
|
8
8
|
from osi_dump.api.keystone import get_users
|
9
9
|
|
10
10
|
logger = logging.getLogger(__name__)
|
@@ -15,15 +15,14 @@ class OpenStackRoleAssignmentImporter(RoleAssignmentImporter):
|
|
15
15
|
self.users = {}
|
16
16
|
self.roles = {}
|
17
17
|
self.groups = {}
|
18
|
-
self.
|
19
|
-
self._raw_assignments = None # Cache
|
18
|
+
self._raw_assignments = None
|
20
19
|
|
21
|
-
def
|
22
|
-
"""
|
20
|
+
def _fetch_metadata(self):
|
21
|
+
"""cache metadata"""
|
23
22
|
if self._raw_assignments is not None:
|
24
|
-
return
|
23
|
+
return
|
25
24
|
|
26
|
-
logger.info(f"Pre-caching
|
25
|
+
logger.info(f"Pre-caching metadata for role assignments on {self.connection.auth['auth_url']}")
|
27
26
|
|
28
27
|
try:
|
29
28
|
os_users = get_users(self.connection)
|
@@ -39,14 +38,7 @@ class OpenStackRoleAssignmentImporter(RoleAssignmentImporter):
|
|
39
38
|
|
40
39
|
try:
|
41
40
|
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] = []
|
41
|
+
for group in os_groups: self.groups[group.id] = group.name
|
50
42
|
except Exception as e:
|
51
43
|
logger.error(f"Could not fetch groups: {e}")
|
52
44
|
|
@@ -57,7 +49,7 @@ class OpenStackRoleAssignmentImporter(RoleAssignmentImporter):
|
|
57
49
|
self._raw_assignments = []
|
58
50
|
|
59
51
|
def get_user_roles(self) -> Generator[UserRoleAssignment, None, None]:
|
60
|
-
self.
|
52
|
+
self._fetch_metadata()
|
61
53
|
for assignment in self._raw_assignments:
|
62
54
|
if assignment.user:
|
63
55
|
user_id = assignment.user.get('id')
|
@@ -75,7 +67,7 @@ class OpenStackRoleAssignmentImporter(RoleAssignmentImporter):
|
|
75
67
|
)
|
76
68
|
|
77
69
|
def get_group_roles(self) -> Generator[GroupRoleAssignment, None, None]:
|
78
|
-
self.
|
70
|
+
self._fetch_metadata()
|
79
71
|
for assignment in self._raw_assignments:
|
80
72
|
if assignment.group:
|
81
73
|
group_id = assignment.group.get('id')
|
@@ -86,32 +78,4 @@ class OpenStackRoleAssignmentImporter(RoleAssignmentImporter):
|
|
86
78
|
role_id=role_id,
|
87
79
|
role_name=self.roles.get(role_id),
|
88
80
|
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
|
-
)
|
81
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from abc import ABC, abstractmethod
|
2
2
|
from typing import Generator
|
3
|
-
from osi_dump.model.role_assignment import UserRoleAssignment, GroupRoleAssignment
|
3
|
+
from osi_dump.model.role_assignment import UserRoleAssignment, GroupRoleAssignment
|
4
4
|
|
5
5
|
class RoleAssignmentImporter(ABC):
|
6
6
|
@abstractmethod
|
@@ -10,7 +10,7 @@ class RoleAssignmentImporter(ABC):
|
|
10
10
|
@abstractmethod
|
11
11
|
def get_group_roles(self) -> Generator[GroupRoleAssignment, None, None]:
|
12
12
|
pass
|
13
|
-
|
14
|
-
@abstractmethod
|
15
|
-
def calculate_effective_roles(self) -> Generator[EffectiveUserRole, None, None]:
|
16
|
-
pass
|
13
|
+
|
14
|
+
# @abstractmethod
|
15
|
+
# def calculate_effective_roles(self) -> Generator[EffectiveUserRole, None, None]:
|
16
|
+
# pass
|
@@ -20,11 +20,11 @@ class GroupRoleAssignment(BaseModel):
|
|
20
20
|
role_name: Optional[str]
|
21
21
|
scope: dict
|
22
22
|
|
23
|
-
class EffectiveUserRole(BaseModel):
|
24
|
-
model_config = ConfigDict(strict=True)
|
25
|
-
user_id: str
|
26
|
-
user_name: Optional[str]
|
27
|
-
role_id: str
|
28
|
-
role_name: Optional[str]
|
29
|
-
scope: dict
|
30
|
-
inherited_from_group: Optional[str]
|
23
|
+
#class EffectiveUserRole(BaseModel):
|
24
|
+
# model_config = ConfigDict(strict=True)
|
25
|
+
# user_id: str
|
26
|
+
# user_name: Optional[str]
|
27
|
+
# role_id: str
|
28
|
+
# role_name: Optional[str]
|
29
|
+
# scope: dict
|
30
|
+
# inherited_from_group: Optional[str]
|
@@ -16,7 +16,7 @@ osi_dump/batch_handler/instance_batch_handler.py,sha256=9Q6T7qLGgxVWGMWX9Re7rW0U
|
|
16
16
|
osi_dump/batch_handler/load_balancer_batch_handler.py,sha256=57M8umBGPGkzJfES8Ge7NyW2PPkURTIH-jo5TfNKvhE,1855
|
17
17
|
osi_dump/batch_handler/network_batch_handler.py,sha256=k-WLnz5UCiX70fGjLywRV_ufEMySSP8UZbdlI0W1DSM,1665
|
18
18
|
osi_dump/batch_handler/project_batch_handler.py,sha256=8tpF3_yJMXXvOogX2iN1C4xx5_IKt_xIP71ZFwOzNPI,1677
|
19
|
-
osi_dump/batch_handler/role_assignment_batch_handler.py,sha256=
|
19
|
+
osi_dump/batch_handler/role_assignment_batch_handler.py,sha256=Ms1BkmoBqAeVlLOlb6lR-gj9rymI-xSdXIRiGSxK5T0,1747
|
20
20
|
osi_dump/batch_handler/router_batch_handler.py,sha256=cjccPBF7nBzLMxaMgPYa7yNU6YLWz6Wcsbur7o9Jwa4,1636
|
21
21
|
osi_dump/batch_handler/security_group_batch_handler.py,sha256=iI5s-Lup9masy1s0TNtdKTCYpbQ1Hznwqc3edfRsPyo,1747
|
22
22
|
osi_dump/batch_handler/volume_batch_handler.py,sha256=Lqd5CHsdRZzr7dxCy0jiXKatTHFdqU4H7AdO0OFHiYU,1614
|
@@ -49,7 +49,7 @@ osi_dump/exporter/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
49
49
|
osi_dump/exporter/project/excel_project_exporter.py,sha256=mr0QKYxkTt8ilFLyIjBZ9SFIFBOKV5hEaq5D0enam6A,946
|
50
50
|
osi_dump/exporter/project/project_exporter.py,sha256=iD0TfkhNCGzu6GXDoK5amabPWNwbio8n16I68ezNWfc,165
|
51
51
|
osi_dump/exporter/role_assignment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
|
-
osi_dump/exporter/role_assignment/excel_role_assignment_exporter.py,sha256=
|
52
|
+
osi_dump/exporter/role_assignment/excel_role_assignment_exporter.py,sha256=nj4wCKHsQ39FtVLik93vs47f4YN78xPSTKGICJimp2Y,1524
|
53
53
|
osi_dump/exporter/role_assignment/role_assignment_exporter.py,sha256=7PJuwTTkSolSWalbKY5iydniPGPUS5eoB3kf1mMFlNQ,277
|
54
54
|
osi_dump/exporter/router/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
55
|
osi_dump/exporter/router/excel_router_exporter.py,sha256=rckGg5SMCK6Y1gbXjasWpkOnkBEWSj6c1jrtt0Pd-wU,930
|
@@ -76,7 +76,7 @@ osi_dump/importer/image/image_importer.py,sha256=-S4zjWvnEONK_G_D8cJaK7txDgICgmd
|
|
76
76
|
osi_dump/importer/image/openstack_image_importer.py,sha256=jf0bE6SNV8vMInGsrMNWrtAt1U7cJqbRLMEPNpGQLGg,2666
|
77
77
|
osi_dump/importer/instance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
78
78
|
osi_dump/importer/instance/instance_importer.py,sha256=PaTGNBzMtIht624LGTumlXEZVdcLS2WkXvzeAtDNAHA,246
|
79
|
-
osi_dump/importer/instance/openstack_instance_importer.py,sha256=
|
79
|
+
osi_dump/importer/instance/openstack_instance_importer.py,sha256=aQIbIL_ftgW-sMYXBK65ZQ1cFsoFMN3ICX9m67pAo24,4100
|
80
80
|
osi_dump/importer/load_balancer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
81
81
|
osi_dump/importer/load_balancer/load_balancer_importer.py,sha256=8QPbe0DmaLEOcRcr82IcCuB1gRc0ZG-vIuSXiO_QfhQ,227
|
82
82
|
osi_dump/importer/load_balancer/openstack_load_balancer_importer.py,sha256=U1DyAc_ca0fXR1n27sMk14R_X_vI2rQESOGBEpdlR4I,4146
|
@@ -87,8 +87,8 @@ osi_dump/importer/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
87
87
|
osi_dump/importer/project/openstack_project_importer.py,sha256=wlPPGEi1uOBDCU0eoxsof6KjIs2lVy3laXiRvt53QyQ,5105
|
88
88
|
osi_dump/importer/project/project_importer.py,sha256=DYQFTIPsROt0BYgPWI8NNRwyvnjmaTNThXoCB415xe8,200
|
89
89
|
osi_dump/importer/role_assignment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
90
|
-
osi_dump/importer/role_assignment/openstack_role_assignment_importer.py,sha256=
|
91
|
-
osi_dump/importer/role_assignment/role_assignment_importer.py,sha256=
|
90
|
+
osi_dump/importer/role_assignment/openstack_role_assignment_importer.py,sha256=ezUFhMIMNvRH-4Wbz8PtBkmmA5AqEvDO-9hm01mlQBo,3388
|
91
|
+
osi_dump/importer/role_assignment/role_assignment_importer.py,sha256=fNHhTufpopzUo-0j3HlHVa2pQSCxAxcS68Z16P7TW9w,543
|
92
92
|
osi_dump/importer/router/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
93
93
|
osi_dump/importer/router/openstack_router_importer.py,sha256=cV-R4qUFUYlAIVLFxxozlD6howOfjZ-O4vgU4mL5UhE,2868
|
94
94
|
osi_dump/importer/router/router_importer.py,sha256=4tEbkMPErSrFiW648fSRwnd80DtSKbz70et-gzzRJMA,195
|
@@ -108,7 +108,7 @@ osi_dump/model/instance.py,sha256=UjJagGoD86sSEkAC4vS0j4VFoHTGZvns-TV45KynOtU,66
|
|
108
108
|
osi_dump/model/load_balancer.py,sha256=uPYqzoh2vbPeAhKPHdM2TGhh5-ZpGC0u2fhX6IZxdKk,597
|
109
109
|
osi_dump/model/network.py,sha256=HJmRIrVPCu4FLEPVY3Q0W05CE42qFhiEpMId2gclSRs,565
|
110
110
|
osi_dump/model/project.py,sha256=nTVswIdfhLH-vvtvrcHvxc31Wol_jPCKopGVMhEN2XE,782
|
111
|
-
osi_dump/model/role_assignment.py,sha256=
|
111
|
+
osi_dump/model/role_assignment.py,sha256=tv9h4HqNrXI-WV8deBm8d-onpy6-wJtHy6V6Hu7FmTY,811
|
112
112
|
osi_dump/model/router.py,sha256=CORkRw5AuU_A8eGY1t2FJSFX0l0nExzjZTGl3I0hGLs,440
|
113
113
|
osi_dump/model/security_group.py,sha256=MJjmgSM8WOuGW2h4PxMv6PwlwLrZzRiToR-5JFUDbBc,642
|
114
114
|
osi_dump/model/volume.py,sha256=cHbIVmG1Cs08AkQGE167Ih3hYCIWRjdKHSwD3SDb4js,448
|
@@ -123,8 +123,8 @@ osi_dump/util/extract_hostname.py,sha256=NdpF2tYt-Gl1Wx4nVZA0FkBzh-IbPfid_dLGQrA
|
|
123
123
|
osi_dump/util/openstack_util.py,sha256=m8Xcp2KNNf3jzo-J7BYj_SdnoNymRN-1DJeQcOwygDg,1347
|
124
124
|
osi_dump/util/panda_excel.py,sha256=db53jqLsBhSE1oM14GbeKJZpF7RAUA7bHBjDh9Be8H4,760
|
125
125
|
osi_dump/util/validate_dir_path.py,sha256=JHjZBsQIT5ubw8rnsHbw2hkKDBFzYMjmjQ_oJT8EtJc,527
|
126
|
-
osi_dump-0.1.
|
127
|
-
osi_dump-0.1.
|
128
|
-
osi_dump-0.1.
|
129
|
-
osi_dump-0.1.
|
130
|
-
osi_dump-0.1.
|
126
|
+
osi_dump-0.1.5.dist-info/METADATA,sha256=K1Em-pKBquQWRPhuIMAqMfuqJJZwzkJrqKYFFjA9PVc,719
|
127
|
+
osi_dump-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
128
|
+
osi_dump-0.1.5.dist-info/entry_points.txt,sha256=ozm5sIBtXzLv6_FiUe26v1BgA3_xUReGLPhKQKZ56wQ,46
|
129
|
+
osi_dump-0.1.5.dist-info/top_level.txt,sha256=OtAAwmJfcoPvlw_Cemo_H1aXIGV_7w0O2941KQt6faQ,9
|
130
|
+
osi_dump-0.1.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|