Add README file and python 2 version
Signed-off-by: Benjamin Copeland <ben.copeland@linaro.org>
Change-Id: I5c3a44932c6d6521a23579d000955b03e566f135
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3cc1bd3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,78 @@
+Yet Another Docker Plugin config builder
+=======
+
+Yet Another Docker Plugin (YADP) is extremely hard to manage, when running multiple slaves with multiple images. Due to the way Jenkins displays the configuration page. YADP provides a [groovy script](https://github.com/KostyaSha/yet-another-docker-plugin/blob/master/docs/script-console-scripts/configure-yadocker-cloud.groovy) which builds a JSON array to populate the configuration in Jenkins.
+
+This script uses YAML and Jinja2 to generate a java JSONARRAY to build the configuration, using a !include constructor in the YAML file, allowing the ability to template up docker_images, since many of our slaves run the same image, it lessens repetition.
+
+Features
+=======
+
+1. Ability to !include inside YAML to lessen duplication
+2. Ability to include multiple YAML files with !include [file1.yml, file2.yml]
+3. Ability to include SSH settings via using launch_method:" along with ssh: or jnlp:
+
+
+Usage
+=======
+
+####hosts
+
+```
+- host1:
+ cloud_name: host1.example.org
+ docker-url: tcp://0.0.0.0:2375
+ docker_templates: !include external_template_file.yml
+
+- host2:
+ cloud_name: host2.example.org
+ docker-url: tcp://0.0.0.1:2375
+ docker_templates:
+ - xenial-amd64:
+ docker_image_name: 'ubuntu:latest'
+ max_instances: '1'
+ labels: 'docker-ubuntu'
+ launch_method: ssh
+ ssh:
+ launch_ssh_credentials_id: 'random-id'
+ launch_ssh_port: '22'
+
+- host3
+ cloud_name: host3.example.org
+ docker-url: tcp://0.0.0.0:2375
+ docker_templates:
+ !include [external_template_file.yml, external_template_file_2.yml]
+```
+
+Limitations
+=======
+
+Due to the nature of YAML and populating the Java JSONARRAY, its important that YAML is phased correctly.
+
+Most of the limitations surround docker_templates.
+
+A list of limitations and pending improvements.
+
+1. Do not mix !include and templates under docker_templates.
+
+Example of broken approach:
+
+- host1:
+ cloud_name: host1.example.org
+ docker-url: tcp://0.0.0.0:2375
+ docker_templates:
+ !include external_template_file.yml
+ - xenial-amd64:
+ docker_image_name: 'ubuntu:latest'
+ max_instances: '1'
+ labels: 'docker-ubuntu'
+
+2. Do not add spaces under the image cloud_name, the must fall inline with the image name
+
+Example of broken approach:
+- xenial-amd64:
+ docker_image_name: 'ubuntu:latest'
+ max_instances: '1'
+ labels: 'docker-ubuntu'
+
+3. Docker labels could be "host" specific. If you are including a template file, the template has no link to the host, so its not possible to do "host based labels". Instead just create another template file with custom settings and include that file.
diff --git a/yadp_builder_v2.py b/yadp_builder_v2.py
new file mode 100755
index 0000000..f1bffb4
--- /dev/null
+++ b/yadp_builder_v2.py
@@ -0,0 +1,107 @@
+import argparse
+import yaml
+import os
+from jinja2 import FileSystemLoader, Environment
+import jenkins
+import logging
+
+
+class Loader(yaml.Loader):
+
+ def __init__(self, *args, **kwargs):
+ super(Loader, self).__init__(*args, **kwargs)
+ self.add_constructor('!include', type(self).construct_include)
+ try:
+ self._root = os.path.split(self)[0]
+ except AttributeError:
+ self._root = os.path.curdir
+
+ def construct_include(self, node):
+ if isinstance(node, yaml.ScalarNode):
+ return self.extractFile(self.construct_scalar(node))
+
+ elif isinstance(node, yaml.SequenceNode):
+ result = []
+ for filename in self.construct_sequence(node):
+ result += self.extractFile(filename)
+ return result
+
+ elif isinstance(node, yaml.MappingNode):
+ result = {}
+ for k,v in self.construct_mapping(node).iteritems():
+ result[k] = self.extractFile(v)
+ return result
+
+ else:
+ print "Error:: unrecognised node type in !include statement"
+ raise yaml.constructor.ConstructorError
+
+
+ def extractFile(self, filename):
+ filepath = os.path.join(self._root, filename)
+ with open(filepath, 'r') as f:
+ return yaml.load(f, Loader=Loader)
+
+
+def jinja2_from_template(directory, template_name, data, dryrun=False):
+ loader = FileSystemLoader(directory)
+ env = Environment(loader=loader)
+ template = env.get_template(template_name)
+ return template.render(hosts=data, dryrun=dryrun)
+
+
+def get_parser():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-u', '--username', type=str,
+ default=os.environ.get('JJB_USER'),
+ help='Username for Jenkins server')
+ parser.add_argument('-p', '--password', type=str,
+ default=os.environ.get('JJB_PASSWORD'),
+ help='Password for Jenkins server')
+ parser.add_argument('-s', '--server', type=str,
+ default='http://localhost:8080',
+ help='Jenkins server URL. e.g. http://localhost:8080')
+ parser.add_argument('-i', '--inventory', type=str, default='hosts',
+ help='specify inventory host path')
+ parser.add_argument('-l', '--loglevel', default='INFO',
+ help="Setting logging level, default: %(default)s")
+ parser.add_argument('--dryrun', action='store_true',
+ help='Do not publish to Jenkins')
+ parser.add_argument('--local', action='store_true',
+ help='Create tmp file only')
+ return parser
+
+
+if __name__ == '__main__':
+ parser = get_parser()
+ args = parser.parse_args()
+ logging.basicConfig(level=args.loglevel)
+ with open(args.inventory, 'r') as f:
+ data = yaml.load(f, Loader=Loader)
+ logging.debug(data)
+ template_output = jinja2_from_template(
+ './templates',
+ 'configure-yadocker-cloud.groovy.j2', data)
+
+ if not args.local:
+ server = jenkins.Jenkins(args.server, username=args.username,
+ password=args.password)
+ if args.dryrun:
+ with open('/tmp/configure-yadocker-cloud.groovy', 'w') as fw:
+ fw.write(template_output)
+ template_output = jinja2_from_template(
+ './templates',
+ 'configure-yadocker-cloud.groovy.j2', data, args.dryrun)
+ if not args.local:
+ publishdry = server.run_script(template_output)
+ if 'error' in publishdry:
+ logging.info(publishdry)
+ exit(1)
+ logging.info(publishdry)
+ else:
+ logging.info('Template file created at \
+ /tmp/configure-yadocker-cloud.groovy')
+ logging.debug(template_output)
+ else:
+ publish = server.run_script(template_output)
+ logging.info(publish)