summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-11-28 17:52:54 +0000
committerGerrit Code Review <review@openstack.org>2018-11-28 17:52:54 +0000
commit21f29820c498f8bea28c25fe6f62a51590919af1 (patch)
treebb9adea6f87acd1fd9cc67b0d67aaa12e3fe4b41
parentfea3ebeae0a08e19a52227a52e40b09d61d7c801 (diff)
parentc00a01a5e89c4febec29480c949bb9403b25aedf (diff)
Merge "Add allowed-labels tenant setting"
-rw-r--r--doc/source/admin/tenants.rst7
-rw-r--r--releasenotes/notes/allowed-labels-d3ca17f3c7e167c8.yaml5
-rw-r--r--tests/fixtures/config/multi-tenant/git/tenant-one-config/zuul.d/config.yaml2
-rw-r--r--tests/fixtures/config/multi-tenant/main.yaml4
-rw-r--r--tests/unit/test_v3.py25
-rw-r--r--zuul/configloader.py21
6 files changed, 63 insertions, 1 deletions
diff --git a/doc/source/admin/tenants.rst b/doc/source/admin/tenants.rst
index 07d33a8..e2b3eed 100644
--- a/doc/source/admin/tenants.rst
+++ b/doc/source/admin/tenants.rst
@@ -247,3 +247,10 @@ configuration. Some examples of tenant definitions are:
247 The list of connections a tenant can report to. When set, this setting 247 The list of connections a tenant can report to. When set, this setting
248 can be used to restrict what connections a tenant can use as reporter. 248 can be used to restrict what connections a tenant can use as reporter.
249 Without this setting, the tenant can report to any connection. 249 Without this setting, the tenant can report to any connection.
250
251 .. attr:: allowed-labels
252 :default: []
253
254 The list of labels regexp a tenant can use in job's nodeset. When set,
255 this setting can be used to restrict what labels a tenant can use.
256 Without this setting, the tenant can use any labels.
diff --git a/releasenotes/notes/allowed-labels-d3ca17f3c7e167c8.yaml b/releasenotes/notes/allowed-labels-d3ca17f3c7e167c8.yaml
new file mode 100644
index 0000000..3077aac
--- /dev/null
+++ b/releasenotes/notes/allowed-labels-d3ca17f3c7e167c8.yaml
@@ -0,0 +1,5 @@
1---
2features:
3 - |
4 A new tenant option :attr:`tenant.allowed-labels`
5 can be used to restrict what labels a tenant has access to.
diff --git a/tests/fixtures/config/multi-tenant/git/tenant-one-config/zuul.d/config.yaml b/tests/fixtures/config/multi-tenant/git/tenant-one-config/zuul.d/config.yaml
index a51a77c..cc7328e 100644
--- a/tests/fixtures/config/multi-tenant/git/tenant-one-config/zuul.d/config.yaml
+++ b/tests/fixtures/config/multi-tenant/git/tenant-one-config/zuul.d/config.yaml
@@ -23,7 +23,7 @@
23 name: nodeset1 23 name: nodeset1
24 nodes: 24 nodes:
25 - name: controller 25 - name: controller
26 label: controller-label 26 label: tenant-one-controller-label
27 27
28- job: 28- job:
29 name: project1-test1 29 name: project1-test1
diff --git a/tests/fixtures/config/multi-tenant/main.yaml b/tests/fixtures/config/multi-tenant/main.yaml
index 7ad270b..cffae0b 100644
--- a/tests/fixtures/config/multi-tenant/main.yaml
+++ b/tests/fixtures/config/multi-tenant/main.yaml
@@ -3,6 +3,10 @@
3 max-job-timeout: 1800 3 max-job-timeout: 1800
4 allowed-reporters: 4 allowed-reporters:
5 - gerrit 5 - gerrit
6 allowed-labels:
7 - tenant-one-.*
8 - ubuntu-trusty
9 - fake
6 source: 10 source:
7 gerrit: 11 gerrit:
8 config-projects: 12 config-projects:
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index 2d1aee0..e0553d3 100644
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -3235,6 +3235,31 @@ class TestAllowedConnection(AnsibleZuulTestCase):
3235 "B should not fail because of allowed-reporters") 3235 "B should not fail because of allowed-reporters")
3236 3236
3237 3237
3238class TestAllowedLabels(AnsibleZuulTestCase):
3239 config_file = 'zuul-connections-gerrit-and-github.conf'
3240 tenant_config_file = 'config/multi-tenant/main.yaml'
3241
3242 def test_allowed_labels(self):
3243 in_repo_conf = textwrap.dedent(
3244 """
3245 - job:
3246 name: test
3247 nodeset:
3248 nodes:
3249 - name: controller
3250 label: tenant-two-label
3251 """)
3252 file_dict = {'zuul.d/test.yaml': in_repo_conf}
3253 A = self.fake_gerrit.addFakeChange(
3254 'tenant-one-config', 'master', 'A', files=file_dict)
3255 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3256 self.waitUntilSettled()
3257 self.assertIn(
3258 'Label named "tenant-two-label" is not part of the allowed',
3259 A.messages[0],
3260 "A should fail because of allowed-labels")
3261
3262
3238class TestPragma(ZuulTestCase): 3263class TestPragma(ZuulTestCase):
3239 tenant_config_file = 'config/pragma/main.yaml' 3264 tenant_config_file = 'config/pragma/main.yaml'
3240 3265
diff --git a/zuul/configloader.py b/zuul/configloader.py
index a476a35..87bb6db 100644
--- a/zuul/configloader.py
+++ b/zuul/configloader.py
@@ -22,6 +22,7 @@ import io
22import re 22import re
23import subprocess 23import subprocess
24 24
25import re2
25import voluptuous as vs 26import voluptuous as vs
26 27
27from zuul import model 28from zuul import model
@@ -79,6 +80,17 @@ class UnknownConnection(Exception):
79 super(UnknownConnection, self).__init__(message) 80 super(UnknownConnection, self).__init__(message)
80 81
81 82
83class LabelForbiddenError(Exception):
84 def __init__(self, label, allowed_labels):
85 message = textwrap.dedent("""\
86 Label named "{label}" is not part of the allowed
87 labels ({allowed_labels}) for this tenant.""")
88 message = textwrap.fill(message.format(
89 label=label,
90 allowed_labels=", ".join(allowed_labels)))
91 super(LabelForbiddenError, self).__init__(message)
92
93
82class MaxTimeoutError(Exception): 94class MaxTimeoutError(Exception):
83 def __init__(self, job, tenant): 95 def __init__(self, job, tenant):
84 message = textwrap.dedent("""\ 96 message = textwrap.dedent("""\
@@ -452,7 +464,14 @@ class NodeSetParser(object):
452 ns.start_mark = conf.get('_start_mark') 464 ns.start_mark = conf.get('_start_mark')
453 node_names = set() 465 node_names = set()
454 group_names = set() 466 group_names = set()
467 allowed_labels = self.pcontext.tenant.allowed_labels
455 for conf_node in as_list(conf['nodes']): 468 for conf_node in as_list(conf['nodes']):
469 if allowed_labels:
470 if not [True for allowed_label in allowed_labels if
471 re2.match(allowed_label, conf_node['label'])]:
472 raise LabelForbiddenError(
473 label=conf_node['label'],
474 allowed_labels=allowed_labels)
456 for name in as_list(conf_node['name']): 475 for name in as_list(conf_node['name']):
457 if name in node_names: 476 if name in node_names:
458 raise DuplicateNodeError(name, conf_node['name']) 477 raise DuplicateNodeError(name, conf_node['name'])
@@ -1293,6 +1312,7 @@ class TenantParser(object):
1293 'exclude-unprotected-branches': bool, 1312 'exclude-unprotected-branches': bool,
1294 'allowed-triggers': to_list(str), 1313 'allowed-triggers': to_list(str),
1295 'allowed-reporters': to_list(str), 1314 'allowed-reporters': to_list(str),
1315 'allowed-labels': to_list(str),
1296 'default-parent': str, 1316 'default-parent': str,
1297 } 1317 }
1298 return vs.Schema(tenant) 1318 return vs.Schema(tenant)
@@ -1309,6 +1329,7 @@ class TenantParser(object):
1309 conf['exclude-unprotected-branches'] 1329 conf['exclude-unprotected-branches']
1310 tenant.allowed_triggers = conf.get('allowed-triggers') 1330 tenant.allowed_triggers = conf.get('allowed-triggers')
1311 tenant.allowed_reporters = conf.get('allowed-reporters') 1331 tenant.allowed_reporters = conf.get('allowed-reporters')
1332 tenant.allowed_labels = conf.get('allowed-labels')
1312 tenant.default_base_job = conf.get('default-parent', 'base') 1333 tenant.default_base_job = conf.get('default-parent', 'base')
1313 1334
1314 tenant.unparsed_config = conf 1335 tenant.unparsed_config = conf