Skip to content

Commit de516be

Browse files
committed
Manully merge PR104 to expose permanent_freeze conf option in conf generator and add unit tests for it. Reworks generateconfs script to wrap actual call in a main function for easier external testing. Adjusted with comments from review at github.
git-svn-id: svn+ssh://svn.code.sf.net/p/migrid/code/trunk@6115 b75ad72c-e7d7-11dd-a971-7dbc132099af
1 parent 5e8ae4c commit de516be

File tree

8 files changed

+137
-14
lines changed

8 files changed

+137
-14
lines changed

mig/install/MiGserver-template.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ transfers_from = __PUBLIC_FQDN__ __MIG_CERT_FQDN__ __EXT_CERT_FQDN__ __MIG_OID_F
660660
enable_freeze = __ENABLE_FREEZE__
661661
# Which frozen archive flavors can be deleted (True for all, False or empty for
662662
# none and a space-separated list of flavors for individual control.
663-
#permanent_freeze =
663+
permanent_freeze = __PERMANENT_FREEZE__
664664
# Delay before frozen archives are expected to hit tape (e.g. 5m, 4d or 2w).
665665
# Leave unset or empty if no tape archiving is available.
666666
freeze_to_tape = __FREEZE_TO_TAPE__

mig/install/generateconfs.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def usage(options):
6464
''' % (sys.argv[0], '\n'.join(lines)))
6565

6666

67-
if '__main__' == __name__:
67+
def main(argv, _generate_confs=generate_confs):
6868
str_names = [
6969
'source',
7070
'destination',
@@ -289,6 +289,7 @@ def usage(options):
289289
'enable_sitestatus',
290290
'daemon_pubkey_from_dns',
291291
'seafile_ro_access',
292+
'permanent_freeze',
292293
'public_use_https',
293294
'prefer_python3',
294295
'io_account_expire',
@@ -318,23 +319,23 @@ def usage(options):
318319
else:
319320
print('Error: environment options %r not supported!' % opt_name)
320321
usage(names)
321-
sys.exit(1)
322+
return 1
322323

323324
# apply values from CLI parameters
324325
flag_str = 'h'
325326
opts_str = ["%s=" % key for key in names] + ["help"]
326327
try:
327-
(opts, args) = getopt.getopt(sys.argv[1:], flag_str, opts_str)
328+
(opts, args) = getopt.getopt(argv, flag_str, opts_str)
328329
except getopt.GetoptError as exc:
329330
print('Error: ', exc.msg)
330331
usage(names)
331-
sys.exit(1)
332+
return 1
332333

333334
for (opt, val) in opts:
334335
opt_name = opt.lstrip('-')
335336
if opt in ('-h', '--help'):
336337
usage(names)
337-
sys.exit(0)
338+
return 0
338339
elif opt_name in str_names:
339340
settings[opt_name] = val
340341
elif opt_name in int_names:
@@ -350,7 +351,7 @@ def usage(options):
350351
print('Error: non-option arguments are no longer supported!')
351352
print(" ... found: %s" % args)
352353
usage(names)
353-
sys.exit(1)
354+
return 1
354355
if settings['destination_suffix'] == 'DEFAULT':
355356
suffix = "-%s" % datetime.datetime.now().isoformat()
356357
settings['destination_suffix'] = suffix
@@ -371,7 +372,7 @@ def usage(options):
371372
if val == 'DEFAULT':
372373
del settings[key]
373374

374-
options = generate_confs(output_path, **settings)
375+
options = _generate_confs(output_path, **settings)
375376

376377
# TODO: avoid reconstructing this path (also done inside generate_confs)
377378
instructions_path = os.path.join(options['destination_dir'],
@@ -383,5 +384,10 @@ def usage(options):
383384
print(instructions)
384385
except Exception as exc:
385386
print("ERROR: could not read generated instructions: %s" % exc)
386-
sys.exit(1)
387-
sys.exit(0)
387+
return 1
388+
return 0
389+
390+
391+
if '__main__' == __name__:
392+
exit_code = main(sys.argv[1:])
393+
sys.exit(exit_code)

mig/server/MiGserver-localhost.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ enable_transfers = True
343343
enable_freeze = True
344344
# Which frozen archive flavors can be deleted (True for all, False or empty for
345345
# none and a space-separated list of flavors for individual control.
346-
#permanent_freeze =
346+
permanent_freeze =
347347
# Delay before frozen archives are expected to hit tape (e.g. 5m, 4d or 2w).
348348
# Leave unset or empty if no tape archiving is available.
349349
#freeze_to_tape =

mig/shared/install.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
from __future__ import print_function
3737
from __future__ import absolute_import
38+
from past.builtins import basestring
3839

3940
import ast
4041
import base64
@@ -482,6 +483,7 @@ def generate_confs(
482483
smtp_server='localhost',
483484
smtp_sender='',
484485
log_level='info',
486+
permanent_freeze='no',
485487
freeze_to_tape='',
486488
status_system_match=keyword_any,
487489
duplicati_protocols='',
@@ -796,6 +798,7 @@ def _generate_confs_prepare(
796798
smtp_server,
797799
smtp_sender,
798800
log_level,
801+
permanent_freeze,
799802
freeze_to_tape,
800803
status_system_match,
801804
duplicati_protocols,
@@ -1043,6 +1046,13 @@ def _generate_confs_prepare(
10431046
user_dict['__SMTP_SERVER__'] = smtp_server
10441047
user_dict['__SMTP_SENDER__'] = smtp_sender
10451048
user_dict['__LOG_LEVEL__'] = log_level
1049+
1050+
if isinstance(permanent_freeze, basestring):
1051+
permanent_freeze = permanent_freeze.split(' ')
1052+
elif isinstance(permanent_freeze, bool):
1053+
permanent_freeze = ['yes' if permanent_freeze else 'no']
1054+
user_dict['__PERMANENT_FREEZE__'] = ' '.join(permanent_freeze)
1055+
10461056
user_dict['__FREEZE_TO_TAPE__'] = freeze_to_tape
10471057
user_dict['__STATUS_SYSTEM_MATCH__'] = status_system_match
10481058
user_dict['__IMNOTIFY_ADDRESS__'] = imnotify_address

tests/fixture/confs-stdlocal/MiGserver.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ transfers_from =
660660
enable_freeze = True
661661
# Which frozen archive flavors can be deleted (True for all, False or empty for
662662
# none and a space-separated list of flavors for individual control.
663-
#permanent_freeze =
663+
permanent_freeze = no
664664
# Delay before frozen archives are expected to hit tape (e.g. 5m, 4d or 2w).
665665
# Leave unset or empty if no tape archiving is available.
666666
freeze_to_tape =

tests/support.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,14 @@ def is_path_within(path, start=None, _msg=None):
278278
return not relative.startswith('..')
279279

280280

281-
def cleanpath(relative_path, test_case):
281+
def cleanpath(relative_path, test_case, ensure_dir=False):
282282
assert isinstance(test_case, MigTestCase)
283283
tmp_path = os.path.join(TEST_OUTPUT_DIR, relative_path)
284+
if ensure_dir:
285+
try:
286+
os.mkdir(tmp_path)
287+
except FileExistsError:
288+
raise AssertionError("ABORT: use of unclean output path: %s" % relative_path)
284289
test_case._cleanup_paths.add(tmp_path)
285290
return tmp_path
286291

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# --- BEGIN_HEADER ---
4+
#
5+
# test_mig_install_generateconfs - unit test of the corresponding mig module
6+
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
7+
#
8+
# This file is part of MiG.
9+
#
10+
# MiG is free software: you can redistribute it and/or modify
11+
# it under the terms of the GNU General Public License as published by
12+
# the Free Software Foundation; either version 2 of the License, or
13+
# (at your option) any later version.
14+
#
15+
# MiG is distributed in the hope that it will be useful,
16+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
# GNU General Public License for more details.
19+
#
20+
# You should have received a copy of the GNU General Public License
21+
# along with this program; if not, write to the Free Software
22+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
23+
# USA.
24+
#
25+
# --- END_HEADER ---
26+
#
27+
28+
"""Unit tests for the migrid module pointed to in the filename"""
29+
30+
from __future__ import print_function
31+
32+
import importlib
33+
import os
34+
import sys
35+
36+
from tests.support import MIG_BASE, MigTestCase, testmain, cleanpath
37+
38+
39+
def _import_generateconfs():
40+
"""Internal helper to work around non-package import location"""
41+
sys.path.append(os.path.join(MIG_BASE, 'mig/install'))
42+
mod = importlib.import_module('generateconfs')
43+
sys.path.pop(-1)
44+
return mod
45+
46+
47+
# workaround for generatconfs being placed witin a non-module directory
48+
generateconfs = _import_generateconfs()
49+
main = generateconfs.main
50+
51+
52+
def create_fake_generate_confs(return_dict=None):
53+
"""Fake generate confs helper"""
54+
def _generate_confs(*args, **kwargs):
55+
if return_dict:
56+
return return_dict
57+
else:
58+
return {}
59+
return _generate_confs
60+
61+
62+
class MigInstallGenerateconfs__main(MigTestCase):
63+
"""Unit test helper for the migrid code pointed to in class name"""
64+
65+
def test_option_permanent_freeze(self):
66+
expected_generated_dir = cleanpath('confs-stdlocal', self,
67+
ensure_dir=True)
68+
with open(os.path.join(expected_generated_dir, "instructions.txt"),
69+
"w"):
70+
pass
71+
fake_generate_confs = create_fake_generate_confs(dict(
72+
destination_dir=expected_generated_dir
73+
))
74+
test_arguments = ['--permanent_freeze', 'yes']
75+
76+
exit_code = main(test_arguments, _generate_confs=fake_generate_confs)
77+
self.assertEqual(exit_code, 0)
78+
79+
80+
if __name__ == '__main__':
81+
testmain()

tests/test_mig_shared_install.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
import pwd
3737
import sys
3838

39-
sys.path.append(os.path.realpath(os.path.join(os.path.dirname(__file__), "..")))
39+
sys.path.append(os.path.realpath(
40+
os.path.join(os.path.dirname(__file__), "..")))
4041

4142
from support import MIG_BASE, TEST_OUTPUT_DIR, MigTestCase, \
4243
testmain, temppath, cleanpath, fixturepath, is_path_within, outputpath
@@ -231,6 +232,26 @@ def test_creates_output_files_with_datasafety(self):
231232
self.assertConfigKey(
232233
actual_file, 'SITE', 'datasafety_text', expected='TEST_DATASAFETY_TEXT')
233234

235+
def test_creates_output_files_with_permanent_freeze(self):
236+
fixture_dir = fixturepath("confs-stdlocal")
237+
expected_generated_dir = cleanpath('confs-stdlocal', self)
238+
symlink_path = temppath('confs', self)
239+
240+
generate_confs(
241+
self.output_path,
242+
destination=symlink_path,
243+
destination_suffix='-stdlocal',
244+
permanent_freeze=('foo', 'bar', 'baz'),
245+
_getpwnam=create_dummy_gpwnam(4321, 1234),
246+
)
247+
248+
relative_file = 'confs-stdlocal/MiGserver.conf'
249+
self.assertPathExists('confs-stdlocal/MiGserver.conf')
250+
251+
actual_file = outputpath(relative_file)
252+
self.assertConfigKey(
253+
actual_file, 'SITE', 'permanent_freeze', expected='foo bar baz')
254+
234255
def test_options_for_source_auto(self):
235256
options = generate_confs(
236257
'/some/arbitrary/path',

0 commit comments

Comments
 (0)