Add secret top-level config object
This adds secrets as a top-level config object, including a new
custom YAML tag to indicate encrypted data.
It also adds a script which encrypts data for use in tests.
Change-Id: I92a6bc048874f8aa4ebe0dd27180b253bede7370
diff --git a/zuul/model.py b/zuul/model.py
index 9c395c4..e929f8b 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -515,6 +515,35 @@
self.state_time = data['state_time']
+class Secret(object):
+ """A collection of private data.
+
+ In configuration, Secrets are collections of private data in
+ key-value pair format. They are defined as top-level
+ configuration objects and then referenced by Jobs.
+
+ """
+
+ def __init__(self, name):
+ self.name = name
+ # The secret data may or may not be encrypted. This attribute
+ # is named 'secret_data' to make it easy to search for and
+ # spot where it is directly used.
+ self.secret_data = {}
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __eq__(self, other):
+ if not isinstance(other, Secret):
+ return False
+ return (self.name == other.name and
+ self.secret_data == other.secret_data)
+
+ def __repr__(self):
+ return '<Secret %s>' % (self.name,)
+
+
class SourceContext(object):
"""A reference to the branch of a project in configuration.
@@ -2132,6 +2161,7 @@
self.project_templates = []
self.projects = {}
self.nodesets = []
+ self.secrets = []
def copy(self):
r = UnparsedTenantConfig()
@@ -2140,6 +2170,7 @@
r.project_templates = copy.deepcopy(self.project_templates)
r.projects = copy.deepcopy(self.projects)
r.nodesets = copy.deepcopy(self.nodesets)
+ r.secrets = copy.deepcopy(self.secrets)
return r
def extend(self, conf):
@@ -2150,6 +2181,7 @@
for k, v in conf.projects.items():
self.projects.setdefault(k, []).extend(v)
self.nodesets.extend(conf.nodesets)
+ self.secrets.extend(conf.secrets)
return
if not isinstance(conf, list):
@@ -2178,6 +2210,8 @@
self.pipelines.append(value)
elif key == 'nodeset':
self.nodesets.append(value)
+ elif key == 'secret':
+ self.secrets.append(value)
else:
raise Exception("Configuration item `%s` not recognized "
"(when parsing %s)" %
@@ -2200,6 +2234,7 @@
# inherit from the reference definition.
self.jobs = {'noop': [Job('noop')]}
self.nodesets = {}
+ self.secrets = {}
def getJob(self, name):
if name in self.jobs:
@@ -2233,6 +2268,11 @@
raise Exception("NodeSet %s already defined" % (nodeset.name,))
self.nodesets[nodeset.name] = nodeset
+ def addSecret(self, secret):
+ if secret.name in self.secrets:
+ raise Exception("Secret %s already defined" % (secret.name,))
+ self.secrets[secret.name] = secret
+
def addPipeline(self, pipeline):
self.pipelines[pipeline.name] = pipeline