Merge "API, CLI: Allow use of tenant-scoped API URLs"

This commit is contained in:
Zuul 2020-12-17 17:28:19 +00:00 committed by Gerrit Code Review
commit da8e50862e
4 changed files with 297 additions and 22 deletions

View File

@ -73,6 +73,7 @@ class TestApi(BaseTestCase):
client = ZuulRESTClient(url='https://fake.zuul/',
auth_token='aiaiaiai')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'post', client.autohold,
@ -92,10 +93,24 @@ class TestApi(BaseTestCase):
'node_hold_expiration': 3600}
)
self.assertEqual(True, ah)
client.info_ = {'tenant': 'scoped'}
ah = client.autohold(
'tenant', 'project', 'job', 1, None, 'reason', 1, 3600)
client.session.post.assert_called_with(
'https://fake.zuul/api/project/project/autohold',
json={'reason': 'reason',
'count': 1,
'job': 'job',
'change': 1,
'ref': None,
'node_hold_expiration': 3600}
)
self.assertEqual(True, ah)
def test_autohold_list(self):
"""Test autohold-list"""
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'get', client.autohold_list, 'tenant1')
@ -117,16 +132,23 @@ class TestApi(BaseTestCase):
client.session.get.assert_called_with(
'https://fake.zuul/api/tenant/tenant1/autohold')
self.assertEqual(fakejson, ahl)
client.info_ = {'tenant': 'scoped'}
ahl = client.autohold_list('tenant1')
client.session.get.assert_called_with(
'https://fake.zuul/api/autohold')
self.assertEqual(fakejson, ahl)
def test_autohold_delete(self):
"""Test autohold-delete"""
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
# token required
with self.assertRaisesRegex(Exception, 'Auth Token required'):
client.autohold_delete(123, 'tenant1')
client = ZuulRESTClient(url='https://fake.zuul/',
auth_token='aiaiaiai')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'delete', client.autohold_delete,
@ -140,10 +162,17 @@ class TestApi(BaseTestCase):
'https://fake.zuul/api/tenant/tenant1/autohold/123'
)
self.assertEqual(True, ahd)
client.info_ = {'tenant': 'scoped'}
ahd = client.autohold_delete(123, 'tenant1')
client.session.delete.assert_called_with(
'https://fake.zuul/api/autohold/123'
)
self.assertEqual(True, ahd)
def test_autohold_info(self):
"""Test autohold-info"""
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'get', client.autohold_info, 123, 'tenant1')
@ -165,16 +194,23 @@ class TestApi(BaseTestCase):
client.session.get.assert_called_with(
'https://fake.zuul/api/tenant/tenant1/autohold/123')
self.assertEqual(fakejson, ahl)
client.info_ = {'tenant': 'scoped'}
ahl = client.autohold_info(tenant='tenant1', id=123)
client.session.get.assert_called_with(
'https://fake.zuul/api/autohold/123')
self.assertEqual(fakejson, ahl)
def test_enqueue(self):
"""Test enqueue"""
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
# token required
with self.assertRaisesRegex(Exception, 'Auth Token required'):
client.enqueue('tenant1', 'check', 'project1', '1,1')
client = ZuulRESTClient(url='https://fake.zuul/',
auth_token='aiaiaiai')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'post', client.enqueue,
@ -190,10 +226,19 @@ class TestApi(BaseTestCase):
'pipeline': 'check'}
)
self.assertEqual(True, enq)
client.info_ = {'tenant': 'scoped'}
enq = client.enqueue('tenant1', 'check', 'project1', '1,1')
client.session.post.assert_called_with(
'https://fake.zuul/api/project/project1/enqueue',
json={'change': '1,1',
'pipeline': 'check'}
)
self.assertEqual(True, enq)
def test_enqueue_ref(self):
"""Test enqueue ref"""
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
# token required
with self.assertRaisesRegex(Exception, 'Auth Token required'):
client.enqueue_ref(
@ -201,6 +246,7 @@ class TestApi(BaseTestCase):
client = ZuulRESTClient(url='https://fake.zuul/',
auth_token='aiaiaiai')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'post', client.enqueue_ref,
@ -219,16 +265,29 @@ class TestApi(BaseTestCase):
'pipeline': 'check'}
)
self.assertEqual(True, enq_ref)
client.info_ = {'tenant': 'scoped'}
enq_ref = client.enqueue_ref(
'tenant1', 'check', 'project1', 'refs/heads/stable', '0', '0')
client.session.post.assert_called_with(
'https://fake.zuul/api/project/project1/enqueue',
json={'ref': 'refs/heads/stable',
'oldrev': '0',
'newrev': '0',
'pipeline': 'check'}
)
self.assertEqual(True, enq_ref)
def test_dequeue(self):
"""Test dequeue"""
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
# token required
with self.assertRaisesRegex(Exception, 'Auth Token required'):
client.dequeue('tenant1', 'check', 'project1', '1,1')
client = ZuulRESTClient(url='https://fake.zuul/',
auth_token='aiaiaiai')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'post', client.dequeue,
@ -257,16 +316,34 @@ class TestApi(BaseTestCase):
'pipeline': 'check'}
)
self.assertEqual(True, deq)
client.info_ = {'tenant': 'scoped'}
deq = client.dequeue('tenant1', 'check', 'project1', change='1,1')
client.session.post.assert_called_with(
'https://fake.zuul/api/project/project1/dequeue',
json={'change': '1,1',
'pipeline': 'check'}
)
self.assertEqual(True, deq)
deq = client.dequeue(
'tenant1', 'check', 'project1', ref='refs/heads/stable')
client.session.post.assert_called_with(
'https://fake.zuul/api/project/project1/dequeue',
json={'ref': 'refs/heads/stable',
'pipeline': 'check'}
)
self.assertEqual(True, deq)
def test_promote(self):
"""Test promote"""
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
# token required
with self.assertRaisesRegex(Exception, 'Auth Token required'):
client.promote('tenant1', 'check', ['1,1', '2,1'])
client = ZuulRESTClient(url='https://fake.zuul/',
auth_token='aiaiaiai')
client.info_ = {}
# test status checks
self._test_status_check(
client, 'post', client.promote,
@ -282,6 +359,14 @@ class TestApi(BaseTestCase):
'pipeline': 'check'}
)
self.assertEqual(True, prom)
client.info_ = {'tenant': 'scoped'}
prom = client.promote('tenant1', 'check', ['1,1', '2,1'])
client.session.post.assert_called_with(
'https://fake.zuul/api/promote',
json={'changes': ['1,1', '2,1'],
'pipeline': 'check'}
)
self.assertEqual(True, prom)
def test_get_key(self):
"""Test getting a project's public key"""
@ -302,6 +387,16 @@ GuS6/ewjS+arA1Iyeg/IxmECAwEAAQ==
-----END PUBLIC KEY-----"""
req = FakeRequestResponse(200, text=pubkey)
client = ZuulRESTClient(url='https://fake.zuul/')
client.info_ = {}
client.session.get = MagicMock(return_value=req)
key = client.get_key('tenant1', 'project1')
client.session.get.assert_called_with(
'https://fake.zuul/api/tenant/tenant1/key/project1.pub'
)
self.assertEqual(pubkey, key)
client.info_ = {'tenant': 'scoped'}
key = client.get_key('tenant1', 'project1')
client.session.get.assert_called_with(
'https://fake.zuul/api/key/project1.pub'
)
self.assertEqual(pubkey, key)

View File

@ -36,6 +36,17 @@ chunks = [
'1tlAuq+vIhlY3iYlzVtPTiIOtF/6V+qPHnq1k6Tiv8YzJms1WyOuw106Bzl9XM=']
def mock_get(func=MagicMock(return_value=None), info={}):
def funk(*args, **kwargs):
if args[0].endswith('/info'):
return FakeRequestResponse(200, info)
else:
return func(*args, **kwargs)
return funk
class TestCmd(BaseTestCase):
def test_client_args_errors(self):
@ -52,6 +63,54 @@ class TestCmd(BaseTestCase):
'--reason', 'some reason',
'--node-hold-expiration', '3600'])
def test_tenant_scoping_errors(self):
"""Test the right uses of --tenant"""
ZC = ZuulClient()
with patch('requests.Session') as mock_sesh:
session = mock_sesh.return_value
test_args = [
['autohold',
'--project', 'project1',
'--job', 'job1', '--change', '3',
'--reason', 'some reason',
'--node-hold-expiration', '3600'],
['autohold-delete', '1234'],
['autohold-info', '1234'],
['enqueue',
'--pipeline', 'check',
'--change', '3,1',
'--project', 'project1'],
['enqueue-ref',
'--pipeline', 'check',
'--ref', 'refs/heads/stable',
'--project', 'project1',
'--oldrev', 'ababababab'],
['dequeue',
'--pipeline', 'check',
'--change', '3,3',
'--project', 'project1'],
['promote',
'--pipeline', 'gate',
'--changes', '3,3', '4,1', '5,3'],
['encrypt', '--project', 'project1']
]
for args in test_args:
session.get = MagicMock(
side_effect=mock_get()
)
with self.assertRaisesRegex(Exception,
'--tenant argument is required'):
ZC._main(['--zuul-url', 'https://fake.zuul',
'--auth-token', 'aiaiaiai', ] + args)
session.get = MagicMock(
side_effect=mock_get(info={'tenant': 'scoped'})
)
with self.assertRaisesRegex(Exception,
'scoped to tenant "scoped"'):
ZC._main(['--zuul-url', 'https://fake.zuul',
'--auth-token', 'aiaiaiai', ] + args +
['--tenant', 'tenant-' + args[0]])
def test_autohold(self):
"""Test autohold via CLI"""
ZC = ZuulClient()
@ -59,6 +118,9 @@ class TestCmd(BaseTestCase):
session = mock_sesh.return_value
session.post = MagicMock(
return_value=FakeRequestResponse(200, True))
session.get = MagicMock(
side_effect=mock_get()
)
exit_code = ZC._main(
['--zuul-url', 'https://fake.zuul',
'--auth-token', 'aiaiaiai', 'autohold',
@ -76,6 +138,27 @@ class TestCmd(BaseTestCase):
'node_hold_expiration': 3600}
)
self.assertEqual(0, exit_code)
# test scoped
session.get = MagicMock(
side_effect=mock_get(info={'tenant': 'scoped'})
)
exit_code = ZC._main(
['--zuul-url', 'https://scoped.zuul',
'--auth-token', 'aiaiaiai', 'autohold',
'--project', 'project1',
'--job', 'job1', '--change', '3', '--reason', 'some reason',
'--node-hold-expiration', '3600'])
session.post.assert_called_with(
'https://scoped.zuul/api/'
'project/project1/autohold',
json={'reason': 'some reason',
'count': 1,
'job': 'job1',
'change': '3',
'ref': '',
'node_hold_expiration': 3600}
)
self.assertEqual(0, exit_code)
def test_autohold_args_errors(self):
"""Test wrong arguments for autohold"""
@ -130,6 +213,9 @@ class TestCmd(BaseTestCase):
session = mock_sesh.return_value
session.delete = MagicMock(
return_value=FakeRequestResponse(204))
session.get = MagicMock(
side_effect=mock_get()
)
exit_code = ZC._main(
['--zuul-url', 'https://fake.zuul',
'--auth-token', 'aiaiaiai', 'autohold-delete',
@ -143,8 +229,9 @@ class TestCmd(BaseTestCase):
ZC = ZuulClient()
with patch('requests.Session') as mock_sesh:
session = mock_sesh.return_value
session.get = MagicMock(
return_value=FakeRequestResponse(
def rv(*args, **kargs):
return FakeRequestResponse(
200,
json={'id': 1234,
'tenant': 'tenant1',
@ -156,7 +243,11 @@ class TestCmd(BaseTestCase):
'node_expiration': 0,
'expired': 0,
'reason': 'some_reason',
'nodes': ['node1', 'node2']}))
'nodes': ['node1', 'node2']})
session.get = MagicMock(
side_effect=mock_get(rv)
)
exit_code = ZC._main(
['--zuul-url', 'https://fake.zuul', 'autohold-info',
'--tenant', 'tenant1', '1234'])
@ -178,6 +269,9 @@ class TestCmd(BaseTestCase):
session = mock_sesh.return_value
session.post = MagicMock(
return_value=FakeRequestResponse(200, True))
session.get = MagicMock(
side_effect=mock_get()
)
exit_code = ZC._main(
['--zuul-url', 'https://fake.zuul',
'--auth-token', 'aiaiaiai', 'enqueue',
@ -199,6 +293,9 @@ class TestCmd(BaseTestCase):
session = mock_sesh.return_value
session.post = MagicMock(
return_value=FakeRequestResponse(200, True))
session.get = MagicMock(
side_effect=mock_get()
)
# ensure default revs are set
exit_code = ZC._main(
['--zuul-url', 'https://fake.zuul',
@ -272,6 +369,9 @@ class TestCmd(BaseTestCase):
session = mock_sesh.return_value
session.post = MagicMock(
return_value=FakeRequestResponse(200, True))
session.get = MagicMock(
side_effect=mock_get()
)
exit_code = ZC._main(
['--zuul-url', 'https://fake.zuul',
'--auth-token', 'aiaiaiai', 'dequeue',
@ -306,6 +406,9 @@ class TestCmd(BaseTestCase):
session = mock_sesh.return_value
session.post = MagicMock(
return_value=FakeRequestResponse(200, True))
session.get = MagicMock(
side_effect=mock_get()
)
exit_code = ZC._main(
['--zuul-url', 'https://fake.zuul',
'--auth-token', 'aiaiaiai', 'promote',
@ -329,8 +432,13 @@ class TestCmd(BaseTestCase):
ZC = ZuulClient()
with patch('requests.Session') as mock_sesh:
session = mock_sesh.return_value
def rv(*args, **kwargs):
return FakeRequestResponse(200, text='aaa')
session.get = MagicMock(
return_value=FakeRequestResponse(200, text='aaa'))
side_effect=mock_get(rv)
)
with patch('zuulclient.cmd.encrypt_with_openssl') as m_encrypt:
m_encrypt.return_value = chunks
exit_code = ZC._main(

View File

@ -51,6 +51,20 @@ class ZuulRESTClient(object):
self.session.verify = self.verify
if self.auth_token:
self.session.auth = BearerAuth(self.auth_token)
self.info_ = None
@property
def info(self):
"""Return the Zuul info data.
Useful to get capabilities and tenant info."""
if self.info_ is None:
url = urllib.parse.urljoin(
self.base_url,
'info')
req = self.session.get(url)
self._check_request_status(req)
self.info_ = req.json()
return self.info_
def _check_request_status(self, req):
try:
@ -76,17 +90,25 @@ class ZuulRESTClient(object):
"change": change,
"ref": ref,
"node_hold_expiration": node_hold_expiration}
if self.info.get('tenant'):
suffix = 'project/%s/autohold' % project
else:
suffix = 'tenant/%s/project/%s/autohold' % (tenant, project)
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/project/%s/autohold' % (tenant, project))
suffix)
req = self.session.post(url, json=args)
self._check_request_status(req)
return req.json()
def autohold_list(self, tenant):
if self.info.get('tenant'):
suffix = 'autohold'
else:
suffix = 'tenant/%s/autohold' % tenant
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/autohold' % tenant)
suffix)
# auth not needed here
req = self.session.get(url)
self._check_request_status(req)
@ -96,18 +118,26 @@ class ZuulRESTClient(object):
def autohold_delete(self, id, tenant):
if not self.auth_token:
raise Exception('Auth Token required')
if self.info.get('tenant'):
suffix = 'autohold/%s' % id
else:
suffix = 'tenant/%s/autohold/%s' % (tenant, id)
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/autohold/%s' % (tenant, id))
suffix)
req = self.session.delete(url)
self._check_request_status(req)
# DELETE doesn't return a body, just the HTTP code
return (req.status_code == 204)
def autohold_info(self, id, tenant):
if self.info.get('tenant'):
suffix = 'autohold/%s' % id
else:
suffix = 'tenant/%s/autohold/%s' % (tenant, id)
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/autohold/%s' % (tenant, id))
suffix)
# auth not needed here
req = self.session.get(url)
self._check_request_status(req)
@ -119,9 +149,13 @@ class ZuulRESTClient(object):
raise Exception('Auth Token required')
args = {"change": change,
"pipeline": pipeline}
if self.info.get('tenant'):
suffix = 'project/%s/enqueue' % project
else:
suffix = 'tenant/%s/project/%s/enqueue' % (tenant, project)
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/project/%s/enqueue' % (tenant, project))
suffix)
req = self.session.post(url, json=args)
self._check_request_status(req)
return req.json()
@ -133,9 +167,13 @@ class ZuulRESTClient(object):
"oldrev": oldrev,
"newrev": newrev,
"pipeline": pipeline}
if self.info.get('tenant'):
suffix = 'project/%s/enqueue' % project
else:
suffix = 'tenant/%s/project/%s/enqueue' % (tenant, project)
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/project/%s/enqueue' % (tenant, project))
suffix)
req = self.session.post(url, json=args)
self._check_request_status(req)
return req.json()
@ -150,9 +188,13 @@ class ZuulRESTClient(object):
args['ref'] = ref
else:
raise Exception('need change OR ref')
if self.info.get('tenant'):
suffix = 'project/%s/dequeue' % project
else:
suffix = 'tenant/%s/project/%s/dequeue' % (tenant, project)
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/project/%s/dequeue' % (tenant, project))
suffix)
req = self.session.post(url, json=args)
self._check_request_status(req)
return req.json()
@ -162,17 +204,25 @@ class ZuulRESTClient(object):
raise Exception('Auth Token required')
args = {'pipeline': pipeline,
'changes': change_ids}
if self.info.get('tenant'):
suffix = 'promote'
else:
suffix = 'tenant/%s/promote' % tenant
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/promote' % tenant)
suffix)
req = self.session.post(url, json=args)
self._check_request_status(req)
return req.json()
def get_key(self, tenant, project):
if self.info.get('tenant'):
suffix = 'key/%s.pub' % project
else:
suffix = 'tenant/%s/key/%s.pub' % (tenant, project)
url = urllib.parse.urljoin(
self.base_url,
'tenant/%s/key/%s.pub' % (tenant, project))
suffix)
req = self.session.get(url)
self._check_request_status(req)
return req.text

View File

@ -153,11 +153,24 @@ class ZuulClient():
self.log.error(e)
sys.exit(1)
def _check_tenant_scope(self, client):
tenant_scope = client.info.get('tenant', None)
if self.args.tenant != '':
if tenant_scope is not None and tenant_scope != self.args.tenant:
raise Exception(
'Error: Zuul API URL %s is '
'scoped to tenant "%s"' % (client.base_url, tenant_scope))
else:
if tenant_scope is None:
raise Exception(
"Error: the --tenant argument is required"
)
def add_autohold_subparser(self, subparsers):
cmd_autohold = subparsers.add_parser(
'autohold', help='hold nodes for failed job')
cmd_autohold.add_argument('--tenant', help='tenant name',
required=True)
required=False, default='')
cmd_autohold.add_argument('--project', help='project name',
required=True)
cmd_autohold.add_argument('--job', help='job name',
@ -188,6 +201,7 @@ class ZuulClient():
node_hold_expiration = self.args.node_hold_expiration
client = self.get_client()
self._check_tenant_scope(client)
r = client.autohold(
tenant=self.args.tenant,
project=self.args.project,
@ -204,12 +218,13 @@ class ZuulClient():
'autohold-delete', help='delete autohold request')
cmd_autohold_delete.set_defaults(func=self.autohold_delete)
cmd_autohold_delete.add_argument('--tenant', help='tenant name',
required=True, default=None)
required=False, default='')
cmd_autohold_delete.add_argument('id', metavar='REQUEST_ID',
help='the hold request ID')
def autohold_delete(self):
client = self.get_client()
self._check_tenant_scope(client)
return client.autohold_delete(self.args.id, self.args.tenant)
def add_autohold_info_subparser(self, subparsers):
@ -217,12 +232,13 @@ class ZuulClient():
'autohold-info', help='retrieve autohold request detailed info')
cmd_autohold_info.set_defaults(func=self.autohold_info)
cmd_autohold_info.add_argument('--tenant', help='tenant name',
required=True, default=None)
required=False, default='')
cmd_autohold_info.add_argument('id', metavar='REQUEST_ID',
help='the hold request ID')
def autohold_info(self):
client = self.get_client()
self._check_tenant_scope(client)
request = client.autohold_info(self.args.id, self.args.tenant)
if not request:
@ -247,11 +263,12 @@ class ZuulClient():
cmd_autohold_list = subparsers.add_parser(
'autohold-list', help='list autohold requests')
cmd_autohold_list.add_argument('--tenant', help='tenant name',
required=True)
required=False, default='')
cmd_autohold_list.set_defaults(func=self.autohold_list)
def autohold_list(self):
client = self.get_client()
self._check_tenant_scope(client)
autohold_requests = client.autohold_list(tenant=self.args.tenant)
if not autohold_requests:
@ -281,7 +298,7 @@ class ZuulClient():
def add_enqueue_subparser(self, subparsers):
cmd_enqueue = subparsers.add_parser('enqueue', help='enqueue a change')
cmd_enqueue.add_argument('--tenant', help='tenant name',
required=True)
required=False, default='')
cmd_enqueue.add_argument('--pipeline', help='pipeline name',
required=True)
cmd_enqueue.add_argument('--project', help='project name',
@ -292,6 +309,7 @@ class ZuulClient():
def enqueue(self):
client = self.get_client()
self._check_tenant_scope(client)
r = client.enqueue(
tenant=self.args.tenant,
pipeline=self.args.pipeline,
@ -310,7 +328,7 @@ class ZuulClient():
to manually "replay" a trigger received from an external
source such as gerrit.'''))
cmd_enqueue.add_argument('--tenant', help='tenant name',
required=True)
required=False, default='')
cmd_enqueue.add_argument('--pipeline', help='pipeline name',
required=True)
cmd_enqueue.add_argument('--project', help='project name',
@ -325,6 +343,7 @@ class ZuulClient():
def enqueue_ref(self):
client = self.get_client()
self._check_tenant_scope(client)
r = client.enqueue_ref(
tenant=self.args.tenant,
pipeline=self.args.pipeline,
@ -339,7 +358,7 @@ class ZuulClient():
help='dequeue a buildset by its '
'change or ref')
cmd_dequeue.add_argument('--tenant', help='tenant name',
required=True)
required=False, default='')
cmd_dequeue.add_argument('--pipeline', help='pipeline name',
required=True)
cmd_dequeue.add_argument('--project', help='project name',
@ -352,6 +371,7 @@ class ZuulClient():
def dequeue(self):
client = self.get_client()
self._check_tenant_scope(client)
r = client.dequeue(
tenant=self.args.tenant,
pipeline=self.args.pipeline,
@ -364,7 +384,7 @@ class ZuulClient():
cmd_promote = subparsers.add_parser('promote',
help='promote one or more changes')
cmd_promote.add_argument('--tenant', help='tenant name',
required=True)
required=False, default='')
cmd_promote.add_argument('--pipeline', help='pipeline name',
required=True)
cmd_promote.add_argument('--changes', help='change ids',
@ -373,6 +393,7 @@ class ZuulClient():
def promote(self):
client = self.get_client()
self._check_tenant_scope(client)
r = client.promote(
tenant=self.args.tenant,
pipeline=self.args.pipeline,
@ -420,7 +441,7 @@ class ZuulClient():
cmd_encrypt = subparsers.add_parser(
'encrypt', help='Encrypt a secret to be used in a project\'s jobs')
cmd_encrypt.add_argument('--tenant', help='tenant name',
required=True)
required=False, default='')
cmd_encrypt.add_argument('--project', help='project name',
required=True)
cmd_encrypt.add_argument('--no-strip', action='store_true',
@ -469,6 +490,7 @@ class ZuulClient():
pubkey_file = tempfile.NamedTemporaryFile(delete=False)
self.log.debug('Creating temporary key file %s' % pubkey_file.name)
client = self.get_client()
self._check_tenant_scope(client)
try:
key = client.get_key(self.args.tenant, self.args.project)
pubkey_file.write(str.encode(key))