Skip to content

Commit 66b7bd7

Browse files
committed
Load VO mapping in correct place
1 parent 5da8065 commit 66b7bd7

File tree

10 files changed

+114
-90
lines changed

10 files changed

+114
-90
lines changed

caso/_cmd/projects.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ def main():
3030
caso.config.parse_args(sys.argv)
3131
log.setup(cfg.CONF, "caso")
3232
manager = caso.manager.Manager()
33-
for prj in manager.projects():
34-
print(prj)
33+
for prj, vo in manager.projects_and_vos():
34+
print(f"'{prj} mapped to VO '{vo}'")
3535

3636

3737
if __name__ == "__main__":

caso/extract/base.py

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
"""Module containing the base class and configuration for all cASO extractors."""
1818

1919
import abc
20-
import json
21-
import warnings
2220

2321
from oslo_config import cfg
2422
from oslo_log import log
@@ -29,16 +27,6 @@
2927
cfg.StrOpt(
3028
"service_name", default="$site_name", help="Service name within the site"
3129
),
32-
cfg.StrOpt(
33-
"mapping_file",
34-
default="/etc/caso/voms.json",
35-
deprecated_group="extractor",
36-
deprecated_for_removal=True,
37-
deprecated_reason="This option is marked for removal in the next release. "
38-
"Please see the release notes, and migrate your current configuration "
39-
"to use the project_mapping file as soon as possible.",
40-
help="File containing the VO <-> project mapping as used in Keystone-VOMS.",
41-
),
4230
]
4331

4432
CONF = cfg.CONF
@@ -55,40 +43,6 @@ def __init__(self, project):
5543
"""Initialize extractor, loading the VO map."""
5644
self.project = project
5745

58-
@property
59-
def voms_map(self):
60-
"""Get the VO map."""
61-
# FIXME(remove this)
62-
try:
63-
mapping = json.loads(open(CONF.mapping_file).read())
64-
except ValueError:
65-
# FIXME(aloga): raise a proper exception here
66-
raise
67-
else:
68-
voms_map = {}
69-
for vo, vomap in six.iteritems(mapping):
70-
tenant = vomap.get("tenant", None)
71-
tenants = vomap.get("tenants", [])
72-
if tenant is not None:
73-
warnings.warn(
74-
"Using deprecated 'tenant' mapping, please "
75-
"use 'projects' instead",
76-
DeprecationWarning,
77-
)
78-
if tenants:
79-
warnings.warn(
80-
"Using deprecated 'tenants' mapping, please "
81-
"use 'projects' instead",
82-
DeprecationWarning,
83-
)
84-
tenants.append(tenant)
85-
projects = vomap.get("projects", tenants)
86-
if not projects:
87-
LOG.warning(f"No project mapping found for VO {vo}")
88-
for project in projects:
89-
voms_map[project] = vo
90-
return voms_map
91-
9246
@abc.abstractmethod
9347
def extract(self, extract_from):
9448
"""Extract records for a project from given date.

caso/extract/manager.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
"""Module containing the manager for all extractors configured in cASO."""
1818

1919
import datetime
20+
import json
2021
import os.path
2122
import sys
23+
import warnings
2224

2325
import dateutil.parser
2426
from dateutil import tz
@@ -43,6 +45,21 @@
4345
default="caso",
4446
help="Tag used to mark a project in Keystone to be extracted by cASO",
4547
),
48+
cfg.StrOpt(
49+
"vo_property",
50+
default="accounting:VO",
51+
help="Property key used to get the VO name from the project properties. ",
52+
),
53+
cfg.StrOpt(
54+
"mapping_file",
55+
default="/etc/caso/voms.json",
56+
deprecated_group="extractor",
57+
deprecated_for_removal=True,
58+
deprecated_reason="This option is marked for removal in the next release. "
59+
"Please see the release notes, and migrate your current configuration "
60+
"to use the project_mapping file as soon as possible.",
61+
help="File containing the VO <-> project mapping as used in Keystone-VOMS.",
62+
),
4663
cfg.StrOpt(
4764
"extract-to",
4865
deprecated_name="extract_to",
@@ -97,6 +114,7 @@ def __init__(self):
97114
self.extractors = extractors
98115
self.last_run_base = os.path.join(CONF.spooldir, "lastrun")
99116

117+
self._voms_map = {}
100118
self.keystone = self._get_keystone_client()
101119

102120
@property
@@ -145,6 +163,70 @@ def write_lastrun(self, project):
145163
with open(lfile, "w") as fd:
146164
fd.write(str(datetime.datetime.now(tz.tzutc())))
147165

166+
@property
167+
def voms_map(self):
168+
"""Get the VO map."""
169+
if self._voms_map:
170+
return self._voms_map
171+
172+
try:
173+
mapping = json.loads(open(CONF.mapping_file).read())
174+
except ValueError:
175+
# FIXME(aloga): raise a proper exception here
176+
raise
177+
else:
178+
self._voms_map = {}
179+
for vo, vomap in six.iteritems(mapping):
180+
tenant = vomap.get("tenant", None)
181+
tenants = vomap.get("tenants", [])
182+
if tenant is not None:
183+
warnings.warn(
184+
"Using deprecated 'tenant' mapping, please "
185+
"use 'projects' instead",
186+
DeprecationWarning,
187+
)
188+
if tenants:
189+
warnings.warn(
190+
"Using deprecated 'tenants' mapping, please "
191+
"use 'projects' instead",
192+
DeprecationWarning,
193+
)
194+
tenants.append(tenant)
195+
projects = vomap.get("projects", tenants)
196+
if not projects:
197+
LOG.warning(f"No project mapping found for VO {vo}")
198+
for project in projects:
199+
self._voms_map[project] = vo
200+
return self._voms_map
201+
202+
def get_project_vo(self, project_id):
203+
"""Get the VO where the project should be mapped."""
204+
project = self.keystone.projects.get(project_id)
205+
project.get()
206+
vo = project.to_dict().get(CONF.vo_property, None)
207+
if vo is None:
208+
LOG.warning(
209+
f"No mapping could be found for project '{project_id}' in the "
210+
"Keystone project metadata, please check cASO documentation."
211+
)
212+
vo = self.voms_map.get(project_id, None)
213+
if vo is None:
214+
LOG.warning(
215+
"No mapping could be found for project "
216+
f"'{project_id}', please check mapping file!"
217+
)
218+
else:
219+
LOG.warning(
220+
"Using deprecated mapping file, please check cASO documentation "
221+
"and migrate to Keystone properties as soon as possible."
222+
)
223+
else:
224+
LOG.debug(
225+
f"Found VO mapping ({vo}) in Keystone project '{project_id}' "
226+
"metadata."
227+
)
228+
return vo
229+
148230
def get_records(self):
149231
"""Get records from given date.
150232
@@ -173,6 +255,8 @@ def get_records(self):
173255
for project in self.projects:
174256
LOG.info(f"Extracting records for project '{project}'")
175257

258+
vo = self.get_project_vo(project)
259+
176260
extract_from = CONF.extract_from or self.get_lastrun(project)
177261
if isinstance(extract_from, six.string_types):
178262
extract_from = dateutil.parser.parse(extract_from)
@@ -196,7 +280,7 @@ def get_records(self):
196280
f"({extract_from} to {extract_to})"
197281
)
198282
try:
199-
extractor = extractor_cls(project)
283+
extractor = extractor_cls(project, vo)
200284
records = extractor.extract(extract_from, extract_to)
201285
current_count = len(records)
202286
record_count += current_count

caso/extract/openstack/base.py

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@
3636
"there are several defined in the OpenStack site. "
3737
"Defaults to None.",
3838
),
39-
cfg.StrOpt(
40-
"vo_property",
41-
default="accounting:VO",
42-
help="Property key used to get the VO name from the project properties. ",
43-
),
4439
]
4540

4641
CONF.register_opts(opts)
@@ -51,14 +46,14 @@
5146
class BaseOpenStackExtractor(base.BaseProjectExtractor):
5247
"""Base OpenStack Extractor that all other extractors should inherit from."""
5348

54-
def __init__(self, project):
49+
def __init__(self, project, vo):
5550
"""Initialize the OpenStack extractor for a given project."""
5651
super(BaseOpenStackExtractor, self).__init__(project)
5752

5853
self.keystone = self._get_keystone_client()
5954
self.project_id = self._get_project_id()
6055

61-
self.vo = self._get_vo()
56+
self.vo = vo
6257

6358
class Users:
6459
def __init__(self, parent):
@@ -114,34 +109,6 @@ def _get_keystone_user(self, uuid):
114109
LOG.exception(e)
115110
return None
116111

117-
def _get_vo(self):
118-
"""Get the VO where the project should be mapped."""
119-
project = self.keystone.projects.get(self.project)
120-
project.get()
121-
vo = project.to_dict().get(CONF.vo_property, None)
122-
if vo is None:
123-
LOG.warning(
124-
f"No mapping could be found for project '{self.project}' in the "
125-
"Keystone project metadata, please check cASO documentation."
126-
)
127-
vo = self.voms_map.get(self.project, None)
128-
if vo is None:
129-
LOG.warning(
130-
"No mapping could be found for project "
131-
f"'{self.project}', please check mapping file!"
132-
)
133-
else:
134-
LOG.warning(
135-
"Using deprecated mapping file, please check cASO documentation "
136-
"and migrate to Keystone properties as soon as possible."
137-
)
138-
else:
139-
LOG.debug(
140-
f"Found VO mapping ({vo}) in Keystone project '{self.project}' "
141-
"metadata."
142-
)
143-
return vo
144-
145112
# FIXME(aloga): this has to go inside a record
146113
@staticmethod
147114
def _get_measure_time():

caso/extract/openstack/cinder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@
3737
class CinderExtractor(base.BaseOpenStackExtractor):
3838
"""An OpenStack Volume (Cinder) record extractor for cASO."""
3939

40-
def __init__(self, project):
40+
def __init__(self, project, vo):
4141
"""Get a Cinder record extractor for a given project."""
42-
super(CinderExtractor, self).__init__(project)
42+
super(CinderExtractor, self).__init__(project, vo)
4343

4444
self.cinder = self._get_cinder_client()
4545

caso/extract/openstack/neutron.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@
3838
class NeutronExtractor(base.BaseOpenStackExtractor):
3939
"""An OpenStack Network (Neutron) record extractor for cASO."""
4040

41-
def __init__(self, project):
41+
def __init__(self, project, vo):
4242
"""Get a Neutron record extractor for a given project."""
43-
super(NeutronExtractor, self).__init__(project)
43+
super(NeutronExtractor, self).__init__(project, vo)
4444

4545
self.neutron = self._get_neutron_client()
4646

caso/extract/openstack/nova.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@
100100
class NovaExtractor(base.BaseOpenStackExtractor):
101101
"""An OpenStack Compute (Nova) record extractor for cASO."""
102102

103-
def __init__(self, project):
103+
def __init__(self, project, vo):
104104
"""Get a Nova record extractor for a given project."""
105-
super(NovaExtractor, self).__init__(project)
105+
super(NovaExtractor, self).__init__(project, vo)
106106

107107
self.nova = self._get_nova_client()
108108
self.glance = self._get_glance_client()

caso/manager.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from oslo_concurrency import lockutils
2323
from oslo_config import cfg
24+
from oslo_log import log
2425

2526
import caso.extract.manager
2627
from caso import loading
@@ -65,6 +66,8 @@
6566
CONF.register_opts(opts)
6667
CONF.register_cli_opts(cli_opts)
6768

69+
LOG = log.getLogger(__name__)
70+
6871

6972
class Manager(object):
7073
"""cASO manager class to deal with the main functionality."""
@@ -90,6 +93,16 @@ def projects(self):
9093

9194
return self.extractor_manager.projects
9295

96+
def projects_and_vos(self):
97+
"""Get the configured projects and VOs as tuples."""
98+
self._load_managers()
99+
100+
for prj in self.extractor_manager.projects:
101+
try:
102+
yield (prj, self.extractor_manager.get_project_vo(prj))
103+
except Exception as e:
104+
LOG.error(e)
105+
93106
def run(self):
94107
"""Run the manager.
95108

caso/tests/extract/test_manager.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def test_extract(self):
7575
ret = self.manager.get_records()
7676
self.m_extractor.assert_called_once_with(
7777
"bazonk",
78+
mock.ANY,
7879
)
7980
self.m_extractor.return_value.extract.assert_called_once_with(
8081
dateutil.parser.parse(extract_from).replace(tzinfo=tz.tzutc()),
@@ -109,6 +110,7 @@ def test_get_records_with_lastrun(self):
109110
m.assert_called_once_with("bazonk")
110111
self.m_extractor.assert_called_once_with(
111112
"bazonk",
113+
mock.ANY,
112114
)
113115
self.m_extractor.return_value.extract.assert_called_once_with(
114116
dateutil.parser.parse(lastrun).replace(tzinfo=tz.tzutc()),

etc/caso/caso.conf.sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
# Tag used to mark a project in Keystone to be extracted by cASO (string value)
3838
#caso_tag = caso
3939

40+
# Property key used to get the VO name from the project properties. (string
41+
# value)
42+
#vo_property = accounting:VO
43+
4044
# DEPRECATED: File containing the VO <-> project mapping as used in Keystone-
4145
# VOMS. (string value)
4246
# This option is deprecated for removal.

0 commit comments

Comments
 (0)