Skip to content

Commit 47a1174

Browse files
authored
Merge pull request #213 from brianhlin/SOFTWARE-4221.add-scitokens-tests
Add scitokens tests (SOFTWARE-4221)
2 parents 52f32db + a159763 commit 47a1174

File tree

6 files changed

+148
-57
lines changed

6 files changed

+148
-57
lines changed

files/test_sequence

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ test_280_gsiopenssh
1919
test_290_slurm
2020
test_380_cvmfs
2121
test_400_proxy
22+
test_401_scitokens
2223
test_403_myproxy
2324
test_407_voms
2425
test_410_jobs

osgtest/tests/test_190_condorce.py

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import cagen
2-
import re
32

43
import osgtest.library.core as core
54
import osgtest.library.files as files
65
import osgtest.library.osgunittest as osgunittest
76
import osgtest.library.condor as condor
87
import osgtest.library.service as service
98

9+
1010
class TestStartCondorCE(osgunittest.OSGTestCase):
11-
# Tests 01-02 are needed to reconfigure condor to work with HTCondor-CE
1211
def test_01_configure_condor(self):
1312
core.skip_ok_unless_installed('condor', 'htcondor-ce', 'htcondor-ce-client')
1413

@@ -34,31 +33,41 @@ def test_02_reconfigure_condor(self):
3433

3534
command = ('condor_reconfig', '-debug')
3635
core.check_system(command, 'Reconfigure Condor')
37-
self.assert_(service.is_running('condor', timeout=10), 'Condor not running after reconfig')
36+
self.assertTrue(service.is_running('condor', timeout=10), 'Condor not running after reconfig')
37+
38+
def test_02_scitoken_mapping(self):
39+
core.state['condor-ce.wrote-mapfile'] = False
40+
core.skip_ok_unless_installed('condor', 'htcondor-ce')
41+
self.skip_ok_if(core.PackageVersion('condor') <= '8.9.4',
42+
'HTCondor version does not support SciToken submission')
43+
44+
condorce_version = core.PackageVersion('htcondor-ce')
45+
scitoken_mapping = f'SCITOKENS "https://demo.scitokens.org" {core.options.username}\n'
46+
47+
# Write the mapfile to the admin mapfile directory
48+
# https://github.com/htcondor/htcondor-ce/pull/425
49+
if condorce_version >= '5.1.0':
50+
core.config['condor-ce.mapfile'] = '/etc/condor-ce/mapfiles.d/01-osg-test.conf'
51+
else:
52+
core.config['condor-ce.mapfile'] = '/etc/condor-ce/condor_mapfile'
53+
mapfile_contents = files.read(core.config['condor-ce.mapfile'], as_single_string=True)
54+
scitoken_mapping += mapfile_contents
55+
56+
files.write(core.config['condor-ce.mapfile'],
57+
scitoken_mapping,
58+
owner='condor-ce',
59+
chmod=0o644)
60+
core.state['condor-ce.wrote-mapfile'] = True
3861

3962
def test_03_configure_ce(self):
4063
core.skip_ok_unless_installed('condor', 'htcondor-ce', 'htcondor-ce-client')
4164

4265
# Set up Condor, PBS, and Slurm routes
4366
# Leave the GRIDMAP knob in tact to verify that it works with the LCMAPS VOMS plugin
4467
core.config['condor-ce.condor-ce-cfg'] = '/etc/condor-ce/config.d/99-osgtest.condor-ce.conf'
45-
# Add host DN to condor_mapfile
46-
if core.options.hostcert:
47-
core.config['condor-ce.condorce_mapfile'] = '/etc/condor-ce/condor_mapfile.osg-test'
48-
hostcert_dn, _ = cagen.certificate_info(core.config['certs.hostcert'])
49-
mapfile_contents = files.read('/etc/condor-ce/condor_mapfile')
50-
mapfile_contents.insert(0, re.sub(r'([/=\.])', r'\\\1', "GSI \"^%s$\" " % hostcert_dn) + \
51-
"%[email protected]\n" % core.get_hostname())
52-
files.write(core.config['condor-ce.condorce_mapfile'],
53-
mapfile_contents,
54-
owner='condor-ce',
55-
chmod=0o644)
56-
else:
57-
core.config['condor-ce.condorce_mapfile'] = '/etc/condor-ce/condor_mapfile'
5868

5969
condor_contents = """GRIDMAP = /etc/grid-security/grid-mapfile
60-
CERTIFICATE_MAPFILE = %s
61-
ALL_DEBUG=D_FULLDEBUG
70+
ALL_DEBUG=D_CAT D_ALWAYS:2
6271
JOB_ROUTER_DEFAULTS = $(JOB_ROUTER_DEFAULTS) [set_default_maxMemory = 128;]
6372
JOB_ROUTER_ENTRIES = \\
6473
[ \\
@@ -82,7 +91,16 @@ def test_03_configure_ce(self):
8291
JOB_ROUTER_SCHEDD2_SPOOL=/var/lib/condor/spool
8392
JOB_ROUTER_SCHEDD2_NAME=$(FULL_HOSTNAME)
8493
JOB_ROUTER_SCHEDD2_POOL=$(FULL_HOSTNAME):9618
85-
""" % core.config['condor-ce.condorce_mapfile']
94+
95+
AUTH_SSL_SERVER_CERTFILE = /etc/grid-security/hostcert.pem
96+
AUTH_SSL_SERVER_KEYFILE = /etc/grid-security/hostkey.pem
97+
AUTH_SSL_SERVER_CADIR = /etc/grid-security/certificates
98+
AUTH_SSL_SERVER_CAFILE =
99+
AUTH_SSL_CLIENT_CERTFILE = /etc/grid-security/hostcert.pem
100+
AUTH_SSL_CLIENT_KEYFILE = /etc/grid-security/hostkey.pem
101+
AUTH_SSL_CLIENT_CADIR = /etc/grid-security/certificates
102+
AUTH_SSL_CLIENT_CAFILE =
103+
"""
86104

87105
if core.rpm_is_installed('htcondor-ce-view'):
88106
condor_contents += "\nDAEMON_LIST = $(DAEMON_LIST), CEVIEW, GANGLIAD, SCHEDD"
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import json
2+
import os
3+
import pwd
4+
import time
5+
6+
from urllib import error, request
7+
8+
import osgtest.library.core as core
9+
import osgtest.library.files as files
10+
import osgtest.library.osgunittest as osgunittest
11+
12+
# Headers so that heroku doesn't block us
13+
HEADERS = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko)' +
14+
'Chrome/35.0.1916.47 Safari/537.36',
15+
'Content-Type': 'application/json'}
16+
17+
18+
def request_demo_scitoken(scope, audience='ANY'):
19+
"""Request a token with 'scope' from the demo SciTokens issuer
20+
"""
21+
22+
payload_dict = {'aud': audience,
23+
'ver': 'scitokens:2.0',
24+
'scope': scope,
25+
'exp': int(time.time() + 3600),
26+
'sub': 'osg-test'}
27+
payload = json.dumps({'payload': json.dumps(payload_dict),
28+
'algorithm': 'ES256'}).encode()
29+
30+
req = request.Request('https://demo.scitokens.org/issue',
31+
data=payload,
32+
headers=HEADERS)
33+
34+
return request.urlopen(req).read()
35+
36+
37+
class TestTokens(osgunittest.OSGTestCase):
38+
39+
def test_01_request_condor_write_scitoken(self):
40+
core.state['token.condor_write_created'] = False
41+
core.config['token.condor_write'] = '/tmp/condor_write.scitoken'
42+
43+
core.skip_ok_unless_installed('htcondor-ce', 'condor')
44+
self.skip_ok_if(core.PackageVersion('condor') <= '8.9.4',
45+
'HTCondor version does not support SciToken submission')
46+
self.skip_ok_if(os.path.exists(core.config['token.condor_write']),
47+
'SciToken with HTCondor WRITE already exists')
48+
49+
hostname = core.get_hostname()
50+
try:
51+
token = request_demo_scitoken('condor:/READ condor:/WRITE', audience=f'{hostname}:9619')
52+
except error.URLError as exc:
53+
self.fail(f"Failed to request token from demo.scitokens.org:\n{exc}")
54+
55+
ids = (0, 0)
56+
if core.state['general.user_added']:
57+
user = pwd.getpwnam(core.options.username)
58+
ids = (user.pw_uid, user.pw_gid)
59+
60+
files.write(core.config['token.condor_write'], core.to_str(token), backup=False, chown=ids)
61+
core.state['token.condor_write_created'] = True

osgtest/tests/test_410_jobs.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ def test_02_condor_ce_run_condor(self):
5858
self.skip_bad_unless(service.is_running('condor-ce'), 'ce not running')
5959
self.skip_bad_unless(service.is_running('condor'), 'condor not running')
6060
self.skip_bad_unless(core.state['jobs.env-set'], 'job environment not set')
61-
self.skip_bad_unless(core.state['proxy.valid'], 'requires a proxy cert')
61+
self.skip_bad_unless(core.state['proxy.valid'] or core.state['token.condor_write_created'],
62+
'requires a scitoken or a proxy')
6263

63-
command = ('condor_ce_run', '-r', '%s:9619' % core.get_hostname(), '/bin/env')
64+
command = ['condor_ce_run', '-r', '%s:9619' % core.get_hostname(), '/bin/env']
65+
if core.state['token.condor_write_created']:
66+
command.insert(0, f"_condor_SCITOKENS_FILE={core.config['token.condor_write']}")
6467
self.run_job_in_tmp_dir(command, 'condor_ce_run a Condor job')

osgtest/tests/test_550_condorce.py

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
except ImportError:
99
from urllib.request import urlopen
1010

11-
import osgtest.library.condor as condor
1211
import osgtest.library.core as core
1312
import osgtest.library.files as files
1413
import osgtest.library.service as service
@@ -18,20 +17,40 @@
1817
class TestCondorCE(osgunittest.OSGTestCase):
1918

2019
def setUp(self):
21-
# Enforce GSI auth for testing
22-
os.environ['_condor_SEC_CLIENT_AUTHENTICATION_METHODS'] = 'GSI'
20+
# Enforce SciToken or GSI auth for testing
21+
os.environ['_condor_SEC_CLIENT_AUTHENTICATION_METHODS'] = 'SCITOKENS, GSI'
22+
core.skip_ok_unless_installed('condor', 'htcondor-ce')
23+
self.skip_bad_unless(service.is_running('condor-ce'), 'ce not running')
24+
25+
self.command = []
26+
if core.state['token.condor_write_created']:
27+
self.command = [f"_condor_SCITOKENS_FILE={core.config['token.condor_write']}"]
2328

2429
def tearDown(self):
2530
os.environ.pop('_condor_SEC_CLIENT_AUTHENTICATION_METHODS')
2631

32+
def check_write_creds(self):
33+
"""Check for credentials necessary for HTCondor-CE WRITE
34+
"""
35+
self.skip_bad_unless(core.state['proxy.valid'] or core.state['token.condor_write_created'],
36+
'requires a scitoken or a proxy')
37+
38+
def check_schedd_ready(self):
39+
"""Check if the HTCondor-CE schedd is up as expected
40+
"""
41+
self.skip_bad_unless(core.state['condor-ce.schedd-ready'], 'CE schedd not ready to accept jobs')
42+
2743
def run_blahp_trace(self, lrms):
2844
"""Run condor_ce_trace() against a non-HTCondor backend and verify the cache"""
2945
lrms_cache_prefix = {'pbs': 'qstat', 'slurm': 'slurm'}
3046

3147
cwd = os.getcwd()
3248
os.chdir('/tmp')
33-
command = ('condor_ce_trace', '-a osgTestBatchSystem = %s' % lrms.lower(), '--debug', core.get_hostname())
34-
trace_out, _, _ = core.check_system(command, 'ce trace against %s' % lrms.lower(), user=True)
49+
self.command += ['condor_ce_trace',
50+
'-a osgTestBatchSystem = %s' % lrms.lower(),
51+
'--debug',
52+
core.get_hostname()]
53+
trace_out, _, _ = core.check_system(self.command, 'ce trace against %s' % lrms.lower(), user=True)
3554

3655
try:
3756
backend_jobid = re.search(r'%s_JOBID=(\d+)' % lrms.upper(), trace_out).group(1)
@@ -64,69 +83,55 @@ def run_blahp_trace(self, lrms):
6483
# S'2'
6584
# p6
6685
# s."
67-
self.assert_(re.search(r'BatchJobId[=\s"\'p1S]+%s' % backend_jobid, cache),
68-
'Job %s not found in %s blahp cache:\n%s' % (backend_jobid, lrms.upper(), cache))
86+
self.assertTrue(re.search(r'BatchJobId[=\s"\'p1S]+%s' % backend_jobid, cache),
87+
'Job %s not found in %s blahp cache:\n%s' % (backend_jobid, lrms.upper(), cache))
6988

7089
os.chdir(cwd)
7190

72-
def general_requirements(self):
73-
core.skip_ok_unless_installed('condor', 'htcondor-ce', 'htcondor-ce-client')
74-
self.skip_bad_unless(service.is_running('condor-ce'), 'ce not running')
75-
7691
def test_01_status(self):
77-
self.general_requirements()
78-
7992
command = ('condor_ce_status', '-any')
8093
core.check_system(command, 'ce status', user=True)
8194

8295
def test_02_queue(self):
83-
self.general_requirements()
84-
8596
command = ('condor_ce_q', '-verbose')
8697
core.check_system(command, 'ce queue', user=True)
8798

8899
def test_03_ping(self):
89-
self.general_requirements()
90-
self.skip_bad_unless(core.state['proxy.valid'], 'requires a proxy cert')
91-
92-
command = ('condor_ce_ping', 'WRITE', '-verbose')
93-
stdout, _, _ = core.check_system(command, 'ping using GSI and gridmap', user=True)
94-
self.assert_(re.search(r'Authorized:\s*TRUE', stdout), 'could not authorize with GSI')
100+
self.check_write_creds()
101+
self.command += ['condor_ce_ping', 'WRITE', '-verbose']
102+
stdout, _, _ = core.check_system(self.command, 'ping using SCITOKENS or GSI', user=True)
103+
self.assertTrue(re.search(r'Authorized:\s*TRUE', stdout), 'could not authorize with SCITOKENS or GSI')
95104

96105
def test_04_trace(self):
97-
self.general_requirements()
98-
self.skip_bad_unless(core.state['condor-ce.schedd-ready'], 'CE schedd not ready to accept jobs')
99-
self.skip_bad_unless(core.state['proxy.valid'], 'requires a proxy cert')
106+
self.check_schedd_ready()
107+
self.check_write_creds()
100108

101109
cwd = os.getcwd()
102110
os.chdir('/tmp')
103111

104-
command = ('condor_ce_trace', '--debug', core.get_hostname())
105-
core.check_system(command, 'ce trace', user=True)
112+
self.command += ['condor_ce_trace', '--debug', core.get_hostname()]
113+
core.check_system(self.command, 'ce trace', user=True)
106114

107115
os.chdir(cwd)
108116

109117
def test_05_pbs_trace(self):
110-
self.general_requirements()
111-
self.skip_bad_unless(core.state['condor-ce.schedd-ready'], 'CE schedd not ready to accept jobs')
112118
core.skip_ok_unless_installed('torque-mom', 'torque-server', 'torque-scheduler', 'torque-client', 'munge',
113119
by_dependency=True)
114120
self.skip_ok_unless(service.is_running('pbs_server'), 'pbs service not running')
115-
self.skip_bad_unless(core.state['proxy.valid'], 'requires a proxy cert')
121+
self.check_schedd_ready()
122+
self.check_write_creds()
116123
self.run_blahp_trace('pbs')
117124

118125
def test_06_slurm_trace(self):
119-
self.general_requirements()
120126
core.skip_ok_unless_installed(core.SLURM_PACKAGES)
121-
self.skip_bad_unless(service.is_running('munge'), 'slurm requires munge')
122127
self.skip_bad_unless(core.state['condor-ce.schedd-ready'], 'CE schedd not ready to accept jobs')
123128
self.skip_ok_unless(service.is_running(core.config['slurm.service-name']), 'slurm service not running')
124-
self.skip_bad_unless(core.state['proxy.valid'], 'requires a proxy cert')
129+
self.check_schedd_ready()
130+
self.check_write_creds()
125131
self.run_blahp_trace('slurm')
126132

127133
def test_07_ceview(self):
128134
core.config['condor-ce.view-listening'] = False
129-
self.general_requirements()
130135
core.skip_ok_unless_installed('htcondor-ce-view')
131136
view_url = 'http://%s:%s' % (core.get_hostname(), int(core.config['condor-ce.view-port']))
132137
try:
@@ -141,6 +146,9 @@ def test_07_ceview(self):
141146
debug_contents += 'Failed to read %s\n' % debug_file
142147
core.log_message(debug_contents)
143148
self.fail('Could not reach HTCondor-CE View at %s: %s' % (view_url, err))
144-
self.assert_(re.search(r'HTCondor-CE Overview', src), 'Failed to find expected CE View contents')
149+
self.assertTrue(re.search(r'HTCondor-CE Overview', src), 'Failed to find expected CE View contents')
145150
core.config['condor-ce.view-listening'] = True
146151

152+
def test_08_config_val(self):
153+
command = ('condor_ce_config_val', '-dump')
154+
core.check_system(command, 'condor_ce_config_val as non-root', user=True)

osgtest/tests/test_790_condorce.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ def test_02_restore_config(self):
1414

1515
files.restore(core.config['condor-ce.condor-cfg'], 'condor-ce')
1616
files.restore(core.config['condor-ce.condor-ce-cfg'], 'condor-ce')
17-
if core.options.hostcert:
18-
files.restore(core.config['condor-ce.condorce_mapfile'], 'condor-ce')
17+
if core.state['condor-ce.wrote-mapfile']:
18+
files.restore(core.config['condor-ce.mapfile'], 'condor-ce')

0 commit comments

Comments
 (0)