From d58a8624fc3325c110ac30ec2d30e7012ec76016 Mon Sep 17 00:00:00 2001 From: Arish Pyne Date: Thu, 19 Oct 2017 18:00:28 +0300 Subject: [PATCH] Add `global_envvars` module, which adds an ability to set global Jenkins environment variables --- jimmy/modules/global_envvars/__init__.py | 2 + jimmy/modules/global_envvars/impl.py | 37 ++++++++ .../global_envvars/resources/jenkins.groovy | 53 +++++++++++ .../global_envvars/resources/schema.yaml | 5 + .../modules/global_envvars/tests/__init__.py | 0 .../tests/test_global_envvars.py | 95 +++++++++++++++++++ sample/input/jenkins.yaml | 3 + 7 files changed, 195 insertions(+) create mode 100644 jimmy/modules/global_envvars/__init__.py create mode 100644 jimmy/modules/global_envvars/impl.py create mode 100644 jimmy/modules/global_envvars/resources/jenkins.groovy create mode 100644 jimmy/modules/global_envvars/resources/schema.yaml create mode 100644 jimmy/modules/global_envvars/tests/__init__.py create mode 100644 jimmy/modules/global_envvars/tests/test_global_envvars.py diff --git a/jimmy/modules/global_envvars/__init__.py b/jimmy/modules/global_envvars/__init__.py new file mode 100644 index 0000000..9d8404f --- /dev/null +++ b/jimmy/modules/global_envvars/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from impl import * diff --git a/jimmy/modules/global_envvars/impl.py b/jimmy/modules/global_envvars/impl.py new file mode 100644 index 0000000..1c7f633 --- /dev/null +++ b/jimmy/modules/global_envvars/impl.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +# Copyright 2017 Evgeny Sharypin +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import subprocess +import json +from jimmy.lib.api import BaseGroovyModule + + +class GlobalEnvVars(BaseGroovyModule): + source_tree_path = 'jenkins.global-envvars' + + def update_dest(self, source, jenkins_url, jenkins_cli_path, **kwargs): + data = self._tree_read(source, self.source_tree_path) + if data: + try: + subprocess.call(["java", + "-jar", jenkins_cli_path, + "-s", jenkins_url, + "groovy", + self.groovy_path, + "{0}".format(json.dumps(data)), + ], shell=False) + except OSError: + self.logger.exception('Could not find java') diff --git a/jimmy/modules/global_envvars/resources/jenkins.groovy b/jimmy/modules/global_envvars/resources/jenkins.groovy new file mode 100644 index 0000000..8719f17 --- /dev/null +++ b/jimmy/modules/global_envvars/resources/jenkins.groovy @@ -0,0 +1,53 @@ +/* +* Copyright 2017 Evgeny Sharypin +* +* Licensed under the Apache License, Version 2.0 (the "License"); you may +* not use this file except in compliance with the License. You may obtain +* a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations +* under the License. +*/ + +import jenkins.model.Jenkins +import groovy.json.JsonSlurper + +// parse incoming JSON +def jsonSlurper = new JsonSlurper() +def parsedArgs = jsonSlurper.parseText(args[0]) + +// get Jenkins instance and envvars container +instance = Jenkins.getInstance() + +globalNodeProperties = instance.getGlobalNodeProperties() +envVarsNodePropertyList = globalNodeProperties.getAll(hudson.slaves.EnvironmentVariablesNodeProperty.class) +newEnvVarsNodeProperty = null +globalEnvVars = null + + +// get the envvars container or create a new +if ( envVarsNodePropertyList == null || envVarsNodePropertyList.size() == 0 ) { + newEnvVarsNodeProperty = new hudson.slaves.EnvironmentVariablesNodeProperty(); + globalNodeProperties.add(newEnvVarsNodeProperty) + globalEnvVars = newEnvVarsNodeProperty.getEnvVars() + +} else { + globalEnvVars = envVarsNodePropertyList.get(0).getEnvVars() +} + +// clear the present environment variables +globalEnvVars.clear() + +// add new envvars +for (envVar in parsedArgs) { + globalEnvVars.put(envVar.key, envVar.value) +} + + +// save +instance.save() diff --git a/jimmy/modules/global_envvars/resources/schema.yaml b/jimmy/modules/global_envvars/resources/schema.yaml new file mode 100644 index 0000000..0188e72 --- /dev/null +++ b/jimmy/modules/global_envvars/resources/schema.yaml @@ -0,0 +1,5 @@ +title: Schema for Jenkins Global EnvVars setter +type: object +minProperties: 1 +additionalProperties: + type: string diff --git a/jimmy/modules/global_envvars/tests/__init__.py b/jimmy/modules/global_envvars/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/jimmy/modules/global_envvars/tests/test_global_envvars.py b/jimmy/modules/global_envvars/tests/test_global_envvars.py new file mode 100644 index 0000000..3a65403 --- /dev/null +++ b/jimmy/modules/global_envvars/tests/test_global_envvars.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +# Copyright 2017 Evgeny Sharypin +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import mock +import mockfs +import os +import sys +import jsonschema +from jimmy import cli +from click.testing import CliRunner +from jimmy.lib.common import yaml_reader +from jimmy.tests import base + +modules_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) +jimmy_dir = os.path.join(os.path.dirname(modules_dir)) +jenkins_schema_path = os.path.join(modules_dir, 'global_envvars', 'resources', 'schema.yaml') +jenkins_yaml_path = os.path.join(jimmy_dir, 'sample', 'input', 'jenkins.yaml') + + +class TestGlobalEnvVarsConfiguration(base.TestCase): + + def setup_method(self, method): + self.runner = CliRunner() + + def teardown_method(self, method): + mockfs.restore_builtins() + + @mock.patch('jimmy.lib.core.load_py_modules') + @mock.patch('subprocess.call') + def test_cli_call(self, mock_subp, mock_modules): + with open(jenkins_schema_path, 'r') as f: + mock_jenkins_schema = f.read() + self.mfs = mockfs.replace_builtins() + self.mfs.add_entries({os.path.join(jimmy_dir, 'lib', 'schema.yaml'): self.jimmy_schema, + os.path.join(jimmy_dir, 'jimmy.yaml'): self.mock_jimmy_yaml, + jenkins_schema_path: mock_jenkins_schema, + jenkins_yaml_path: '\n'.join( + [ + 'jenkins:', + ' global-envvars:', + ' KEY: value', + ]) + }) + sys.path.insert(0, modules_dir) + import global_envvars + import read_source + sys.path.pop(0) + mock_modules.return_value = [global_envvars, read_source] + os.chdir(jimmy_dir) + self.runner.invoke(cli) + mock_subp.assert_called_with( + ['java', '-jar', '<< path to jenkins-cli.jar >>', + '-s', 'http://localhost:8080', 'groovy', + modules_dir + '/' + 'global_envvars/resources/jenkins.groovy', + '{"KEY": "value"}' + ], shell=False) + assert 1 == mock_subp.call_count, "subproccess call should be equal to 1" + + +class TestGlobalEnvVarsSchema(object): + + def setup_method(self, method): + with open(jenkins_schema_path, 'r') as f: + mock_jenkins_schema = f.read() + self.mfs = mockfs.replace_builtins() + self.mfs.add_entries({jenkins_schema_path: mock_jenkins_schema}) + self.schema = yaml_reader.read(jenkins_schema_path) + + def teardown_method(self, method): + mockfs.restore_builtins() + + def test_valid_global_envvars_data(self): + self.mfs.add_entries({jenkins_yaml_path: '\n'.join( + [ + ' KEY: "value"', + ' KEY2: "value2"' + ]) + }) + global_envvars_data = yaml_reader.read(jenkins_yaml_path) + jsonschema.validate(global_envvars_data, self.schema) diff --git a/sample/input/jenkins.yaml b/sample/input/jenkins.yaml index 483448c..822b523 100644 --- a/sample/input/jenkins.yaml +++ b/sample/input/jenkins.yaml @@ -80,6 +80,9 @@ jenkins: email: jenkins@example.com name: Jenkins + global-envvars: + KEY: value + http_request: basic_auth: - key_name: auth-id