Esempio n. 1
0
    def test_create_new_job_fail(self, _base_poll, _poll, _job_poll):
        _job_poll.return_value = {}
        _poll.return_value = {
            'jobs': [
                {'name': 'job_one',
                 'url': 'http://localhost:8080/job_one',
                 'color': 'blue'},
                {'name': 'job_one',
                 'url': 'http://localhost:8080/job_one',
                 'color': 'blue'},
            ]
        }
        _base_poll.return_value = _poll.return_value

        mock_requester = Requester(username='******', password='******')
        mock_requester.post_xml_and_confirm_status = mock.MagicMock(
            return_value='')

        J = Jenkins('http://localhost:8080/',
                    username='******', password='******',
                    requester=mock_requester)

        with self.assertRaises(JenkinsAPIException) as ar:
            J.create_job('job_new', None)

        self.assertEquals(str(ar.exception), 'Cannot create job job_new')
Esempio n. 2
0
    def test_create_new_job_fail(self, _base_poll, _poll, _job_poll):
        _job_poll.return_value = {}
        _poll.return_value = {
            'jobs': [
                {
                    'name': 'job_one',
                    'url': 'http://localhost:8080/job_one',
                    'color': 'blue'
                },
                {
                    'name': 'job_one',
                    'url': 'http://localhost:8080/job_one',
                    'color': 'blue'
                },
            ]
        }
        _base_poll.return_value = _poll.return_value

        mock_requester = Requester(username='******', password='******')
        mock_requester.post_xml_and_confirm_status = mock.MagicMock(
            return_value='')

        J = Jenkins('http://localhost:8080/',
                    username='******',
                    password='******',
                    requester=mock_requester)

        with self.assertRaises(JenkinsAPIException) as ar:
            J.create_job('job_new', None)

        self.assertEquals(str(ar.exception), 'Cannot create job job_new')
Esempio n. 3
0
def tmp_job_name(request, tmpdir, jenkins_settings):
    config = file(os.path.join(os.path.dirname(__file__),
                               'test_config.xml')).read()

    jenkins_url, jenkins_user, jenkins_pass = jenkins_settings
    jenkins = Jenkins(jenkins_url, jenkins_user, jenkins_pass)

    # create job using base config
    hasher = hashlib.sha1(str(time.time()))
    job_name = '%s%s' % (JOB_TEST_PREFIX, hasher.hexdigest())

    job = jenkins.create_job(job_name, config)
    job.update_config(config)

    # configure local cit information using this job as base
    cit_config = {
        'jobs': [{
            'source-job': job_name,
            'feature-branch-job': job_name + '-$name',
        }],
    }
    cit_config_file = str(tmpdir.join('.cit.yaml'))
    yaml.dump(cit_config, file(cit_config_file, 'w'))

    def delete_test_jobs():
        '''
        finalizer for this fixture that removes left-over test jobs from the live jenkins server.
        '''
        jenkins = Jenkins(jenkins_url, jenkins_user, jenkins_pass)
        for job_name in jenkins.iterkeys():
            if job_name.startswith(JOB_TEST_PREFIX):
                jenkins.delete_job(job_name)

    request.addfinalizer(delete_test_jobs)
    return job_name
Esempio n. 4
0
def main():
  m = AnsibleModule(
    argument_spec = dict(
      project_key = dict(required=True),
      repo_name = dict(required=True),
      scm_host = dict(required=True),
      scm_port = dict(required=True),
      api_url = dict(required=True),
      api_username = dict(required=True),
      api_password = dict(required=True),
    ))
  p = m.params
  p['repo_name'] = p['repo_name'].lower()
  job_name = "{0}-{1}".format(p['project_key'], p["repo_name"])
  view_name = p['project_key']

  jenkins = Jenkins(p['api_url'],
                    p['api_username'],
                    p['api_password'])

  if jenkins.has_job(job_name):
    m.exit_json(changed=False, status="Job already exists: {0}".format(job_name))

  cfg = job_config % p
  job = jenkins.create_job(job_name, cfg)
  if job is None:
    m.fail_json(msg="Failed to create job: {0}".format(cfg))

  # create view
#  if view_name not in jenkins.views:
#    view = jenkins.views.create(view_name)
#    view.add(job_name)

  jenkins.build_job(job_name)
  m.exit_json(changed=True, status="DSL Job created: {0}".format(job_name))
Esempio n. 5
0
class BaseSystemTest(unittest.TestCase):

    def setUp(self):
        self.jenkins = Jenkins('http://localhost:8080')
        self._delete_all_jobs()
        self._delete_all_views()

    def tearDown(self):
        pass

    def _delete_all_jobs(self):
        self.jenkins.poll()
        for name in self.jenkins.get_jobs_list():
            self.jenkins.delete_job(name)

    def _delete_all_views(self):
        all_view_names = self.jenkins.views.keys()[1:]
        for name in all_view_names:
            del self.jenkins.views[name]

    def _create_job(self, name='whatever', config=EMPTY_JOB):
        job = self.jenkins.create_job(name, config)
        self.jenkins.poll()
        return job

    def assertJobIsPresent(self, name):
        self.jenkins.poll()
        self.assertTrue(name in self.jenkins,
                        'Job %r is absent in jenkins.' % name)

    def assertJobIsAbsent(self, name):
        self.jenkins.poll()
        self.assertTrue(name not in self.jenkins,
                        'Job %r is present in jenkins.' % name)
Esempio n. 6
0
def tmp_job_name(request, tmpdir):
    config = file(os.path.join(os.path.dirname(__file__), 'test_config.xml')).read()
    
    jenkins = Jenkins(JENKINS_URL)
    
    # create job using base config
    hasher = hashlib.sha1(str(time.time()))
    job_name = '%s%s' % (JOB_TEST_PREFIX, hasher.hexdigest())
    
    job = jenkins.create_job(job_name, config)
    job.update_config(config) 
    
    # configure local cit information using this job as base
    cit_config = {
        'jobs' : [{
            'source-job' : job_name,
            'feature-branch-job' : job_name + '-$name',
        }],
    }
    cit_config_file = str(tmpdir.join('.cit.yaml'))
    yaml.dump(cit_config, file(cit_config_file, 'w'))
    
    
    def delete_test_jobs():
        '''
        finalizer for this fixture that removes left-over test jobs from the live jenkins server.
        '''
        jenkins = Jenkins(JENKINS_URL)
        for name, job in jenkins.get_jobs():
            if name.startswith(JOB_TEST_PREFIX):
                jenkins.delete_job(name)
                
    request.addfinalizer(delete_test_jobs)
    return job_name
Esempio n. 7
0
class JenkinsApi(object):
    def __init__(self, url, username, token):
        logger.debug('create jenkins api instance')
        logger.debug('url %s username %s token %s', url, username, token)

        self.jenkins = Jenkins(url, username, token)

    def has_job(self, name):
        logger.info('check task "%s" exists', name)
        result = self.jenkins.has_job(name)

        logger.debug('return result %s', result)
        return result

    def create_job(self, name, xml):
        logger.debug('create task "%s", xml %s', name, xml)
        return self.jenkins.create_job(name, xml)

    def delete_job(self, name):
        logger.debug('upgrade task "%s", delete it', name)
        self.jenkins.delete_job(name)

    def get_config(self, name):
        logger.debug('get task task "%s"', name)
        return self.jenkins[name].get_config()

    def update_config(self, name, xml):
        logger.debug('upgrade task task "%s"', name)
        return self.jenkins[name].update_config(xml)
Esempio n. 8
0
class BaseSystemTest(unittest.TestCase):
    def setUp(self):
        port = jenkinsapi_tests.systests.state['launcher'].http_port
        self.jenkins = Jenkins('http://localhost:%d' % port)
        self._delete_all_jobs()
        self._delete_all_views()

    def tearDown(self):
        pass

    def _delete_all_jobs(self):
        self.jenkins.poll()
        for name in self.jenkins.get_jobs_list():
            self.jenkins.delete_job(name)

    def _delete_all_views(self):
        all_view_names = self.jenkins.views.keys()[1:]
        for name in all_view_names:
            del self.jenkins.views[name]

    def _create_job(self, name='whatever', config=EMPTY_JOB):
        job = self.jenkins.create_job(name, config)
        self.jenkins.poll()
        return job

    def assertJobIsPresent(self, name):
        self.jenkins.poll()
        self.assertTrue(name in self.jenkins,
                        'Job %r is absent in jenkins.' % name)

    def assertJobIsAbsent(self, name):
        self.jenkins.poll()
        self.assertTrue(name not in self.jenkins,
                        'Job %r is present in jenkins.' % name)
class TestCrumbsRequester(unittest.TestCase):
    def setUp(self):
        try:
            port = jenkinsapi_tests.systests.state['launcher'].http_port
        except KeyError:
            log.warning(
                "Jenkins was not launched from the test-framework, "
                "assuming port %i" %
                DEFAULT_JENKINS_PORT)
            port = DEFAULT_JENKINS_PORT
        self.jenkins = Jenkins('http://localhost:%d' % port)

        self.jenkins.requester.post_and_confirm_status(
            self.jenkins.baseurl + '/configureSecurity/configure',
            data={
                'Submit': 'save',
                'json': json.dumps(ENABLE_CRUMBS_CONFIG)
            },
            headers={'Content-Type': 'application/x-www-form-urlencoded'}
        )
        self.jenkins = Jenkins(
            self.jenkins.baseurl,
            requester=CrumbRequester(baseurl=self.jenkins.baseurl))

    def tearDown(self):
        self.jenkins.requester.post_and_confirm_status(
            self.jenkins.baseurl + '/configureSecurity/configure',
            data={
                'Submit': 'save',
                'json': json.dumps(DISABLE_CRUMBS_CONFIG)
            },
            headers={'Content-Type': 'application/x-www-form-urlencoded'}
        )

    def test_invoke_job_with_file(self):
        file_data = random_string()
        param_file = StringIO(file_data)

        job_name = 'create1_%s' % random_string()
        job = self.jenkins.create_job(job_name, JOB_WITH_FILE)

        self.assertTrue(job.has_params())
        self.assertTrue(len(job.get_params_list()) != 0)

        job.invoke(block=True, files={'file.txt': param_file})

        build = job.get_last_build()
        while build.is_running():
            time.sleep(0.25)

        artifacts = build.get_artifact_dict()
        self.assertIsInstance(artifacts, dict)
        art_file = artifacts['file.txt']
        self.assertTrue(art_file.get_data().strip(), file_data)
Esempio n. 10
0
def tmp_job_name():
    config = file(os.path.join(os.path.dirname(__file__), 'test_config.xml')).read()
    
    jenkins = Jenkins(JENKINS_URL)
    
    hasher = hashlib.sha1(str(time.time()))
    job_name = '%s%s' % (JOB_TEST_PREFIX, hasher.hexdigest())
    
    job = jenkins.create_job(job_name, config)
    job.update_config(config) 
    
    return job_name
Esempio n. 11
0
def tmp_job_name():
    config = file(os.path.join(os.path.dirname(__file__),
                               'test_config.xml')).read()

    jenkins = Jenkins(JENKINS_URL)

    hasher = hashlib.sha1(str(time.time()))
    job_name = '%s%s' % (JOB_TEST_PREFIX, hasher.hexdigest())

    job = jenkins.create_job(job_name, config)
    job.update_config(config)

    return job_name
def main():

    # TODO: specify requirements and check inputs.
    module=AnsibleModule(
        argument_spec=dict(
            host=dict(),
            state=dict(),
            name=dict(),
            template=dict(),
        )
    )

    host = module.params['host']
    state = module.params['state']
    name = module.params['name']
    template = module.params['template']

    # TODO: try catch here
    J = Jenkins(host)

    # TODO: try catch here
    # TODO: how to handle paths?
    if (template):
        txt = open(template)
        job_config = txt.read()
        job_config_xml = etree.fromstring(job_config)

    # There are 4 possible outcomes: created, updated, deleted, nochange.
    if (state == 'present'):
        # If the desired state is present we must check if the job exists and then check if the job has changed.
        if (J.has_job(name)):
            # The job exists so we must compare the XMLs for changes and update if they don't match.
            current_conf = J[name].get_config()
            current_conf = current_conf.encode('ascii','replace')
            current_conf_xml = etree.fromstring(current_conf)
            if (xml_compare(job_config_xml, current_conf_xml)):
                module.exit_json(msg="job exists", changed=False)
            else:
                J[name].update_config(job_config)
                module.exit_json(msg="job updated", changed=True)
        else:
            new_job = J.create_job(name, job_config)
            module.exit_json(msg="job created", changed=True)
    elif (state == 'absent'):
        if (J.has_job(name)):
            J.delete_job(name)
            module.exit_json(msg="job deleted", changed=True)
        else:
            module.exit_json(msg="job does not exist", changed=False)

    module.exit_json(msg=J.version, changed=False)
Esempio n. 13
0
    def test_create_new_job(self, _poll, _job_poll):
        _job_poll.return_value = {}

        mock_requester = Requester(username='******', password='******')
        mock_requester.post_xml_and_confirm_status = mock.MagicMock(return_value='')

        J = Jenkins('http://localhost:8080/',
                    username='******', password='******',
                    requester=mock_requester)

        job = J.create_job('job_new', None)
        self.assertTrue(isinstance(job, Job))
        self.assertTrue(job.baseurl == 'http://localhost:8080/job_new')
        self.assertTrue(job.name == 'job_new')
Esempio n. 14
0
class Myjenkins():
    def __init__(self,url,username,password):
        self.server=Jenkins(url, username=username, password=password)

    def get_job_details(self):
        for job_name,job_instance in self.server.get_jobs():
            print(job_instance.name)
            print(job_instance.get_description())
            print(job_instance.is_running())
            print(job_instance.is_enabled())
            print("######")

    def create_job(self,**config):
        curr_con=open(config['xml'],'r+',encoding='utf-8')
        cc=curr_con.read()
        self.server.create_job(config["jobname"],cc.encode('utf-8'))

    def create_job_str(self,**config):
        cc=jkconfig.base
        self.server.create_job(config["jobname"],cc.encode('utf-8'))

    def build_job(self,jobname,params=None):
        self.server.build_job(jobname,params)
def fixupFile(filename, config_xml, branch):
    #
    # fixup job template
    #
    ApplicationType = sys.argv[1]
    ApplicationFlavor = sys.argv[2]
    ApplicationName = sys.argv[3]
    GitRepoPath = sys.argv[4]
    PomPath = sys.argv[5]
    ArtifactoryUrl = sys.argv[6]
    PomPathOnly = os.path.dirname(PomPath)
    #
    s = Template(config_xml)
    job_def = s.substitute(
        ApplicationType = ApplicationType,
        ApplicationFlavor = ApplicationFlavor,
        ApplicationName = ApplicationName,
        GitRepoPath = GitRepoPath,
        PomPath = PomPath,
        ArtifactoryUrl = ArtifactoryUrl,
        PomPathOnly = PomPathOnly,
        CodeBranch = branch
    )

    jenkins_url = None
    if "JENKINS_URL" in os.environ:
        jenkins_url = os.environ["JENKINS_URL"]
    else:
        print "JENKINS_URL environment variable must be set."
        exit(1)
    jenkins_user = None
    if "NUI_USER" in os.environ:
        jenkins_user = os.environ["NUI_USER"]
    jenkins_password = None
    if "NUI_PWD" in os.environ:
        jenkins_password = os.environ["NUI_PWD"]

    if jenkins_password is None or jenkins_user is None:
        api = Jenkins(jenkins_url, requester = Requester(baseurl=jenkins_url, ssl_verify=False))
    else:
        # If authentication is not turned on, this call raises an exception
        try:
            api = Jenkins(jenkins_url, jenkins_user, jenkins_password, requester = Requester(username=jenkins_user, password=jenkins_password, baseurl=jenkins_url, ssl_verify=False))
        except:
            api = Jenkins(jenkins_url, requester = Requester(baseurl=jenkins_url, ssl_verify=False))
    filenames = filename.split(".")
    project_name = filenames[0]+" "+ApplicationName
    print "Creating project '"+project_name+"'"
    job = api.create_job(project_name, job_def)
Esempio n. 16
0
def main():

    # TODO: specify requirements and check inputs.
    module = AnsibleModule(argument_spec=dict(
        host=dict(),
        state=dict(),
        name=dict(),
        template=dict(),
    ))

    host = module.params['host']
    state = module.params['state']
    name = module.params['name']
    template = module.params['template']

    # TODO: try catch here
    J = Jenkins(host)

    # TODO: try catch here
    # TODO: how to handle paths?
    if (template):
        txt = open(template)
        job_config = txt.read()
        job_config_xml = etree.fromstring(job_config)

    # There are 4 possible outcomes: created, updated, deleted, nochange.
    if (state == 'present'):
        # If the desired state is present we must check if the job exists and then check if the job has changed.
        if (J.has_job(name)):
            # The job exists so we must compare the XMLs for changes and update if they don't match.
            current_conf = J[name].get_config()
            current_conf = current_conf.encode('ascii', 'replace')
            current_conf_xml = etree.fromstring(current_conf)
            if (xml_compare(job_config_xml, current_conf_xml)):
                module.exit_json(msg="job exists", changed=False)
            else:
                J[name].update_config(job_config)
                module.exit_json(msg="job updated", changed=True)
        else:
            new_job = J.create_job(name, job_config)
            module.exit_json(msg="job created", changed=True)
    elif (state == 'absent'):
        if (J.has_job(name)):
            J.delete_job(name)
            module.exit_json(msg="job deleted", changed=True)
        else:
            module.exit_json(msg="job does not exist", changed=False)

    module.exit_json(msg=J.version, changed=False)
Esempio n. 17
0
def test_create_new_job_fail(mocker, monkeypatch):
    def fake_jenkins_poll(cls, tree=None):  # pylint: disable=unused-argument
        return TWO_JOBS_DATA

    def fake_job_poll(cls, tree=None):  # pylint: disable=unused-argument
        return {}

    monkeypatch.setattr(JenkinsBase, '_poll', fake_jenkins_poll)
    monkeypatch.setattr(Jenkins, '_poll', fake_jenkins_poll)
    monkeypatch.setattr(Job, '_poll', fake_job_poll)

    mock_requester = Requester(username='******', password='******')
    mock_requester.post_xml_and_confirm_status = mocker.MagicMock(
        return_value=''
    )

    jenkins = Jenkins('http://localhost:8080/',
                      username='******', password='******',
                      requester=mock_requester)

    with pytest.raises(JenkinsAPIException) as ar:
        jenkins.create_job('job_new', None)

    assert 'Job XML config cannot be empty' in str(ar.value)
Esempio n. 18
0
def test_create_new_job_fail(mocker, monkeypatch):
    def fake_jenkins_poll(cls, tree=None):  # pylint: disable=unused-argument
        return TWO_JOBS_DATA

    def fake_job_poll(cls, tree=None):  # pylint: disable=unused-argument
        return {}

    monkeypatch.setattr(JenkinsBase, '_poll', fake_jenkins_poll)
    monkeypatch.setattr(Jenkins, '_poll', fake_jenkins_poll)
    monkeypatch.setattr(Job, '_poll', fake_job_poll)

    mock_requester = Requester(username='******', password='******')
    mock_requester.post_xml_and_confirm_status = mocker.MagicMock(
        return_value='')

    jenkins = Jenkins('http://localhost:8080/',
                      username='******',
                      password='******',
                      requester=mock_requester)

    with pytest.raises(JenkinsAPIException) as ar:
        jenkins.create_job('job_new', None)

    assert 'Job XML config cannot be empty' in str(ar.value)
Esempio n. 19
0
 def test_create_dup_job(self, _base_poll, _poll, _job_poll):
     _poll.return_value = {
         'jobs': [
             {'name': 'job_one', 'url': 'http://localhost:8080/job_one', 'color': 'blue'},
             {'name': 'job_two', 'url': 'http://localhost:8080/job_two', 'color': 'blue'},
         ]
     }
     _base_poll.return_value = _poll.return_value
     _job_poll.return_value = {}
     J = Jenkins('http://localhost:8080/',
                 username='******', password='******')
     job = J.create_job('job_one', None)
     self.assertTrue(isinstance(job, Job))
     self.assertTrue(job.baseurl == 'http://localhost:8080/job_one')
     self.assertTrue(job.name == 'job_one')
Esempio n. 20
0
    def test_create_new_job(self, _poll, _job_poll):
        _job_poll.return_value = {}

        mock_requester = Requester(username='******', password='******')
        mock_requester.post_xml_and_confirm_status = mock.MagicMock(
            return_value='')

        J = Jenkins('http://localhost:8080/',
                    username='******',
                    password='******',
                    requester=mock_requester)

        job = J.create_job('job_new', None)
        self.assertTrue(isinstance(job, Job))
        self.assertTrue(job.baseurl == 'http://localhost:8080/job_new')
        self.assertTrue(job.name == 'job_new')
Esempio n. 21
0
class BaseSystemTest(unittest.TestCase):
    def setUp(self):
        try:
            port = jenkinsapi_tests.systests.state['launcher'].http_port
        except KeyError:
            log.warning("Jenkins was not launched from the test-framework, "
                        "assuming port %i" % DEFAULT_JENKINS_PORT)
            port = DEFAULT_JENKINS_PORT
        self.jenkins = Jenkins('http://localhost:%d' % port)
        self._delete_all_jobs()
        self._delete_all_views()
        self._delete_all_credentials()

    def tearDown(self):
        pass

    def _delete_all_jobs(self):
        self.jenkins.poll()
        for name in self.jenkins.keys():
            del self.jenkins[name]

    def _delete_all_views(self):
        all_view_names = self.jenkins.views.keys()[1:]
        for name in all_view_names:
            del self.jenkins.views[name]

    def _delete_all_credentials(self):
        all_cred_names = self.jenkins.credentials.keys()
        for name in all_cred_names:
            del self.jenkins.credentials[name]

    def _create_job(self, name='whatever', config=EMPTY_JOB):
        job = self.jenkins.create_job(name, config)
        self.jenkins.poll()
        return job

    def assertJobIsPresent(self, name):
        self.jenkins.poll()
        self.assertTrue(name in self.jenkins,
                        'Job %r is absent in jenkins.' % name)
        self.assertIsInstance(self.jenkins.get_job(name), Job)
        self.assertIsInstance(self.jenkins[name], Job)

    def assertJobIsAbsent(self, name):
        self.jenkins.poll()
        self.assertTrue(name not in self.jenkins,
                        'Job %r is present in jenkins.' % name)
def fixupFile(filename, config_xml):
    #
    # fixup job template
    #
    ApplicationType = sys.argv[2]
    ApplicationFlavor = sys.argv[3]
    ApplicationName = sys.argv[4]
    GitRepoPath = sys.argv[5]
    GitCredentials = sys.argv[6]
    PomPath = sys.argv[7]
    PomPathOnly = os.path.dirname(PomPath)
    #
    s = Template(config_xml)
    job_def = s.substitute(
        ApplicationType = ApplicationType,
        ApplicationFlavor = ApplicationFlavor,
        ApplicationName = ApplicationName,
        GitRepoPath = GitRepoPath,
        GitCredentials = GitCredentials,
        PomPath = PomPath,
        PomPathOnly = PomPathOnly
    )
    jenkins_url = None
    if "JENKINS_URL" in os.environ:
        jenkins_url = os.environ["JENKINS_URL"]
    else:
        print "JENKINS_URL environment variable must be set."
        exit(1)
    jenkins_user = None
    if "NUI_USER" in os.environ:
        jenkins_user = os.environ["NUI_USER"]
    jenkins_password = None
    if "NUI_PWD" in os.environ:
        jenkins_password = os.environ["NUI_PWD"]
    print "Connection: "+jenkins_url+" ("+jenkins_user+")"
    try:
        api = Jenkins(jenkins_url, jenkins_user, jenkins_password)
    except:
        api = Jenkins(jenkins_url)

    filenames = filename.split(".")
    project_name = filenames[0]+" "+ApplicationName
    print "Creating project '"+project_name+"'"
    job = api.create_job(project_name, job_def)
Esempio n. 23
0
class BaseSystemTest(unittest.TestCase):

    def setUp(self):
        try:
            port = jenkinsapi_tests.systests.state['launcher'].http_port
        except KeyError:
            log.warning(
                "Jenkins was not launched from the test-framework, "
                "assuming port %i" %
                DEFAULT_JENKINS_PORT)
            port = DEFAULT_JENKINS_PORT
        self.jenkins = Jenkins('http://localhost:%d' % port)
        self._delete_all_jobs()
        self._delete_all_views()

    def tearDown(self):
        pass

    def _delete_all_jobs(self):
        self.jenkins.poll()
        for name in self.jenkins.keys():
            del self.jenkins[name]

    def _delete_all_views(self):
        all_view_names = self.jenkins.views.keys()[1:]
        for name in all_view_names:
            del self.jenkins.views[name]

    def _create_job(self, name='whatever', config=EMPTY_JOB):
        job = self.jenkins.create_job(name, config)
        self.jenkins.poll()
        return job

    def assertJobIsPresent(self, name):
        self.jenkins.poll()
        self.assertTrue(name in self.jenkins,
                        'Job %r is absent in jenkins.' % name)
        self.assertIsInstance(self.jenkins.get_job(name), Job)
        self.assertIsInstance(self.jenkins[name], Job)

    def assertJobIsAbsent(self, name):
        self.jenkins.poll()
        self.assertTrue(name not in self.jenkins,
                        'Job %r is present in jenkins.' % name)
Esempio n. 24
0
 def test_create_dup_job(self, _base_poll, _poll, _job_poll):
     _poll.return_value = {
         'jobs': [
             {
                 'name': 'job_one',
                 'url': 'http://localhost:8080/job_one'
             },
             {
                 'name': 'job_two',
                 'url': 'http://localhost:8080/job_two'
             },
         ]
     }
     _base_poll.return_value = _poll.return_value
     _job_poll.return_value = {}
     J = Jenkins('http://localhost:8080/',
                 username='******',
                 password='******')
     job = J.create_job('job_one', None)
     self.assertTrue(isinstance(job, Job))
     self.assertTrue(job.baseurl == 'http://localhost:8080/job_one')
     self.assertTrue(job.name == 'job_one')
# This is to test jenkins capability to handle a large number of
# jobs. (e.g. 100000)

# requires the jenkinsapi egg:
# https://github.com/salimfadhley/jenkinsapi

import time
from jenkinsapi.jenkins import Jenkins

limit = 100000

j = Jenkins('http://localhost:8080')
text_buffer = None
with open('test.xml') as fh:
    text_buffer = fh.read()

print "Deleting jobs..."
for i in range(limit):
    try:
        j.delete_job('job-%d' % i)
    except Exception:
        pass
    print "deleted!"
start_time = time.time()
for i in range(limit):
    print "Creating job #%d..." % i
    j.create_job('job-%d' % i, text_buffer)
print "Success!"
end_time = time.time()
print "Elapsed time: %f" % (end_time - start_time)
#!/usr/bin/env python

import logging
from jenkinsapi.jenkins import Jenkins
from pkg_resources import resource_string

log_level = getattr(logging, 'DEBUG')
logging.basicConfig(level=log_level)
logger = logging.getLogger()

jenkins_url = "http://docker:8080/"
api = Jenkins(jenkins_url)

job_name='cd-demo-seed'
if not api.has_job(job_name):
    logger.info('create job ['+ job_name + ']')
    xml = resource_string(__name__, 'cd_demo_seed.xml')
    api.create_job(job_name, xml)

    job = api[job_name]
    logger.info('job [' + job.name + '] created')
else:
    logger.info('job [' + job_name + '] exists already')
         exit(1)
     if sys.argv[4] not in api.jobs:
         print "Job '"+sys.argv[4]+"' not found"
         exit(1)
     job = api.jobs[sys.argv[4]]
     view.add_job(sys.argv[4], job)
     print "Job added to view"
 elif sys.argv[2] == "create-job":
     if (len(sys.argv) < 5):
         print "Usage: python jenkins.py <host> create-job <name> <file>"
         exit(1)
     if sys.argv[3] in api.jobs:
         print "Job '"+sys.argv[3]+"' already exists"
     else:
         xml = readFile(sys.argv[4])
         job = api.create_job(sys.argv[3], xml)
         print("Job created - "+job.name)
 elif sys.argv[2] == "create-job-add-to-view":
     if (len(sys.argv) < 6):
         print "Usage: python jenkins.py <host> create-job-add-to-view <view> <name> <file>"
         exit(1)
     if sys.argv[4] in api.jobs:
         job = api.jobs[sys.argv[4]]
         print "Job '"+sys.argv[4]+"' already exists"
     else:
         xml = readFile(sys.argv[5])
         job = api.create_job(sys.argv[4], xml)
         print("Job created - "+job.name)
     api.views[sys.argv[3]].add_job(sys.argv[4], job)
     print "Job added to view"
 elif sys.argv[2] == "run-job":
class JenkinsWorks:

    """
    Wrapper class that provides connection with Jenkins
    """

    def __init__(self, url, username, password,
                 repository_path, template_location, template_name,
                 job_prefix, job_suffix, view_prefix, view_suffix, preview):
        """
        JenkinsWorks constructor. Sets necessary variables
        """
        self.jenkins_url = url
        self.jenkins_username = username
        self.jenkins_password = password
        self.repo_path = repository_path
        self.template_name = template_name
        self.job_prefix = job_prefix
        self.job_suffix = job_suffix
        self.view_prefix = view_prefix
        self.view_suffix = view_suffix
        self.preview = preview
        self.existing_jobs = []
        self.existing_views = []
        self.branches = []
        self._get_api_instance()
        self._get_repo_origin()

    def _get_api_instance(self):
        """
        Get Jenkins API object
        """
        self.api = Jenkins(self.jenkins_url,
                           self.jenkins_username,
                           self.jenkins_password)
        return self.api

    def _get_repo_origin(self):
        """
        Get Git origin url
        """
        self.repo = git.Repo(self.repo_path)
        self.repo_url = self.repo.remotes.origin.url
        return self.repo_url

    def get_existing_jobs_list(self):
        """
        Get existing Jenkins job names that conform to the
        following convention: prefix + branch_name + suffix
        """
        for job in self.api.get_jobs():
            job_instance = self.api.get_job(job[0])
            if re.match(self.job_prefix + ".*" + self.job_suffix, job_instance.name):
                self.existing_jobs.append(job_instance.name)
        return self.existing_jobs

    def get_existing_views(self):
        """
        Get existing Jenkins views that conform to the
        following convention: prefix + branch_name + suffix
        """
        for view_name in self.api.views.keys():
            if re.match(self.view_prefix + ".*" + self.view_suffix, view_name):
                self.existing_views.append(view_name)
        return self.existing_views

    def get_branches(self):
        """
        Get all remote branches from Git
        """
        pattern = re.compile('[\w\d]+\trefs/heads/(.*)')
        output = self.repo.git.ls_remote("--heads").split("\n")
        for line in output:
            result = pattern.match(line)
            if result:
                self.branches.append(result.group(1))

        return self.branches

    def render_template(self, branch):
        """
        Render XML from the Jinja2 template
        """
        from jinja import FileSystemLoader
        from jinja.environment import Environment

        env = Environment()
        env.loader = FileSystemLoader('templates')
        template = env.get_template(self.template_name)
        rendered_xml = template.render(git_repo=self.repo_url,
                                       git_branch=branch)
        return rendered_xml

    def create_job(self, job_name, xml):
        """
        Create Jenkins job with specific job name and
        rendered from Jinja2 template XML
        """
        print("Creating job: %s" % job_name)
        if not self.preview:
            self.api.create_job(jobname=job_name,
                                xml=xml)

    def delete_job(self, job_name):
        """
        Delete Jenkins job
        """
        print("Deleting job: %s" % job_name)
        if not self.preview:
            self.api.delete_job(jobname=job_name)

    def create_view(self, view_name):
        """
        Create Jenkins view with specific view name
        """
        print("Creating view: %s" % view_name)
        if not self.preview:
            view = self.api.views.create(view_name)
            return view
        return view_name

    def populate_view(self, view, job_name):
        """
        Add job to the Jenkins view
        """
        print("Adding job %s to view %s" % (job_name, view.__str__()))
        if not self.preview:
            view.add_job(job_name)

    def delete_view(self, view_name):
        """
        Delete Jenkins view
        """
        print("Deleting view: %s" % view_name)
        if not self.preview:
            del self.api.views[view_name]

    def update_jenkins_config(self):
        """
        Function that decides what Jenkins jobs and views
        should be created and what should be deleted
        """
        if self.preview:
            print("Going to run in the PREVIEW mode")

        created_jobs = []
        created_views = []

        for branch in self.branches:
            job_name = self.job_prefix + branch + self.job_suffix
            view_name = self.view_prefix + branch

            if job_name not in self.existing_jobs:
                xml = self.render_template(branch)
                self.create_job(job_name, xml)

            if view_name not in self.existing_views:
                view = self.create_view(view_name)
                self.populate_view(view, job_name)

            created_jobs.append(job_name)
            created_views.append(view_name)

        for job in self.existing_jobs:
            if job not in created_jobs:
                self.delete_job(job)

        for view in self.existing_views:
            if view not in created_views:
                self.delete_view(view)
Esempio n. 29
0
"""
A lower-level implementation of copying a job in Jenkins
"""
from __future__ import print_function

import requests
from jenkinsapi.jenkins import Jenkins
from pkg_resources import resource_string
from jenkinsapi_tests.test_utils.random_strings import random_string

J = Jenkins('http://localhost:8080')
jobName = random_string()
jobName2 = '%s_2' % jobName

url = 'http://localhost:8080/createItem?from=%s&name=%s&mode=copy' % (jobName,
                                                                      jobName2)

xml = resource_string('examples', 'addjob.xml')
j = J.create_job(jobname=jobName, xml=xml)

h = {'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(url, data='dysjsjsjs', headers=h)
print(response.text.encode('UTF-8'))
Esempio n. 30
0
from __future__ import print_function
from pkg_resources import resource_string
from jenkinsapi.jenkins import Jenkins
from jenkinsapi.utils.crumb_requester import CrumbRequester

url = "jenkinsURL"
username = "******"
password = "******"
crumb_requester = CrumbRequester(baseurl=url, username=username, password=password)
j = Jenkins(url, username=username, password=password, requester=crumb_requester)
job_name = 'jaydeepCreatedByPythonTest-4'
xml = resource_string(__name__, 'job.xml')

print(xml)

job = j.create_job(jobname=job_name, xml=xml)

# Get job from Jenkins by job name
my_job = j[job_name]
print(my_job)
Esempio n. 31
0
JENKINS_INSTALLER_JOB_NAME = "selenium"

#start a job
jenkins_server_obj.build_job(JENKINS_INSTALLER_JOB_NAME)
jenkins_job_instance = jenkins_server_obj.get_job(JENKINS_INSTALLER_JOB_NAME)

#get job list
print(jenkins_server_obj.get_jobs_list())
#get job selenium
print(jenkins_job_instance)
#global message
jenkins_server_obj.pprint()
#job config.xml
xml = jenkins_server_obj['selenium'].get_config()
print(xml)
'''
#CURB JOB
jenkins_server_obj.create_job('RF1',xml)
jenkins_server_obj.delete_job('RF1')
jenkins_server_obj.copy_job('selenium','selenium3')
jenkins_server_obj.rename_job('selenium1','selenium4')
'''
#job list
jobs = jenkins_server_obj.get_jobs()
for job in jobs:
    print(job[0])

#get plugin details
for plugin in jenkins_server_obj.get_plugins().values():
    print('-------------------------------------------------------------')
    print(plugin)
Esempio n. 32
0
class JenkinsCI:
    def __init__(self, jenkins_url, username, password):
        self.jenkins_url = jenkins_url
        self.jenkins = Jenkins(self.jenkins_url, username=username, password=password)
        self.build_info = []
        __user_data = "Basic " + (username + ":" + password).encode("base64").rstrip()
        self.__headers = {"Content-Type": "application/x-www-form-urlencoded", "Authorization": __user_data}

    def __invoke_method(self, command, method="GET", parameters=None, silent=False):
        if parameters is None:
            parameters = {}

        method_url = urljoin(self.jenkins_url, command)
        request_data = None

        if method == "GET":
            query_string = urlencode(parameters)
            method_url = method_url + "?" + query_string
        else:
            request_data = urlencode(parameters)

        req = Request(method_url, data=request_data, headers=self.__headers)
        req.get_method = lambda: method
        try:
            response = urlopen(req).read()
        except HTTPError as e:
            if not silent:
                print "{0} : {1}".format(method_url, e)
            return None

        try:
            return loads(response.decode("utf-8"))
        except ValueError:
            return response.decode("utf-8")

    def create_job(self, job_name, xml_config):
        try:
            self.jenkins.create_job(job_name, xml_config)
        except Exception as e:
            print e
            return False
        else:
            print "[+] : job {0} created".format(job_name)
            return True

    def format_path_folder(self, path_folder):
        return "job/" + path_folder.replace("/", "/job/")

    def rename_folder(self, path_folder, new_path_folder):
        new_folder_name = new_path_folder.split("/")[-1]
        command = "{0}/doRename".format(self.format_path_folder(path_folder))
        json_parameters = dumps({"newName": new_folder_name})
        parameters = {"newName": new_folder_name, "Submit": "Yes", "json": json_parameters}
        result = self.__invoke_method(command, "POST", parameters)
        if not result:
            raise JenkinsException("Cannot rename folder {0} to {1}".format(path_folder, new_path_folder), 1)
        print "[+] : folder {0} renamed to {1}".format(path_folder, new_path_folder)

    def create_folder(self, path_folder, recursive=False):
        if recursive:
            return self.recursive_create_folders(path_folder)
        split_path = path_folder.split("/")
        folder_name = split_path[-1]
        command = "createItem"
        if len(split_path) > 1:
            new_path = "/".join(f for f in split_path[:-1])
            command = self.format_path_folder(new_path) + "/" + command

        json_parameters = dumps({"name": folder_name, "mode": "com.cloudbees.hudson.plugins.folder.Folder",
                                 "from": "", "Submit": "OK"})
        parameters = {"name": folder_name, "mode": "com.cloudbees.hudson.plugins.folder.Folder",
                      "from": "", "Submit": "OK", "json": json_parameters}
        result = self.__invoke_method(command, "GET", parameters)
        if not result:
            raise JenkinsException("Cannot create folder {0}".format(path_folder), 1)
        print "[+] : folder {0} created".format(path_folder)

    def recursive_create_folders(self, path_folder):
        split_path = path_folder.split("/")
        root = split_path[0]
        for folder in split_path[1:]:
            if not self.check_folder_exist(root):
                self.create_folder(root)
            root += "/{0}".format(folder)

    def check_folder_exist(self, path_folder):
        result = self.__invoke_method(self.format_path_folder(path_folder), "GET", silent=True)
        if result:
            return True
        return False

    def move_job_on_folder(self, job_name, path_folder):
        command = "{0}/move/move".format(self.format_path_folder(job_name))
        json_parameters = {"destination": "/{0}".format(path_folder)}
        parameters = {"destination": "/{0}".format(path_folder), "json": json_parameters, "Submit": "Move"}
        result = self.__invoke_method(command, "POST", parameters)
        if not result:
            raise JenkinsException("Cannot move job {0} to {1} folder".format(job_name, path_folder), 2)
        print "[+] : Job {0} moved to {1} folder".format(job_name, path_folder)

    def get_plugins_version_dict(self, plugins_name_list):
        plugins_version_dict = {}
        all_plugins = self.jenkins.get_plugins().get_plugins_dict()
        for plugin in plugins_name_list:
            plugins_version_dict[plugin] = all_plugins[plugin].version
        return plugins_version_dict

    def copy_job(self, template_job, new_job):
        try:
            self.jenkins.copy_job(template_job, new_job)
        except Exception as e:
            print e
            return False
        else:
            print "[+] : Job {0} created".format(new_job)
            return True

    def plugins_checker(self, plugins_list):
        all_installed = True
        for plugin in plugins_list:
            if not self.jenkins.has_plugin(plugin):
                all_installed = False
                print "[-] : Plugin {0} is not installed".format(plugin)
        if not all_installed:
            return False
        return True

    def check_job_exist(self, job_name):
        if self.jenkins.has_job(job_name):
            return True
        return False

    def check_jobs_exist(self, jobs_list):
        status_exist = False
        for job in jobs_list:
            if self.check_job_exist(job):
                print "[-] : Job {0} already exist".format(job)
                status_exist = True
        return status_exist

    def create_view(self, view_name):
        views = self.jenkins.views
        if view_name not in views.keys():
            views.create(view_name)
            print "[+] : view {0} created".format(view_name)

    def move_job_on_view(self, view_name, job_name):
        view_url = "{0}/view/{1}".format(self.jenkins_url, view_name)
        view = self.jenkins.get_view_by_url(view_url)
        view.add_job(job_name)

    def delete_job(self, job_name):
        if self.check_job_exist(job_name):
            self.jenkins.delete_job(job_name)
            print "[+] : job {0} deleted".format(job_name)

    def build_job(self, job_name, arguments):
        job = self.jenkins.get_job(job_name)
        build_number = job.get_next_build_number()
        job.invoke(build_params=arguments)
        return build_number

    def get_git_info_build(self, job_name, build_number):
        job = self.jenkins.get_job(job_name)
        build = job.get_build(build_number)
        return build.get_revision()

    def get_url_build(self, job_name, build_number):
        return "{0}/job/{1}/{2}".format(self.jenkins_url, job_name, build_number)

    def print_info_build(self, job_name, build_number):
        url = self.get_url_build(job_name, build_number)
        git_info = self.get_git_info_build(job_name, build_number)

        print "Job: {0} #{1}".format(job_name, build_number)
        print "Url: {0}".format(url)
        for info in git_info:
            print "Branch : {0} | Revision : {1}".format(info["name"], info["SHA1"])
Esempio n. 33
0
  output, errors = p.communicate()
  UPDATEMD5HASH=output.split()[0]
  if (UPDATEMD5HASH != INITIALMD5HASH ):
      print ("MD5 Hash For Hello.py has changed , Jenkins Job Triggered")
      # Trigger the jenkins job if the hash has changed
      J=Jenkins(JENKINS_SERVER_URL, username = JENKINS_SERVER_USERNAME, password = JENKINS_SERVER_PASSWORD)
      print ("Jenkins Server Version:" + str(J.version) )
      job=J.get_job('test-job')
      print ("Is Jenkins Job Enabled:" + " " + str(job.is_enabled()))
      print ("Is Jenkins JOB Running already:" + " " +  str(job.is_running()))
      #Feeding a sampple xml configuration file
      #required for the jenkins job
      xml = resource_string('examples', 'addjob.xml') 
      #This XML config file is used by the create_job api
      #To create the jenkins job title 'test-job'
      job = J.create_job(jobname='test-job', xml='addjob.xml')
      #Invoking the 'test-job' jenkins job
      job.invoke()
      print ("Jenkins Job Triggered")
      sys.exit(0)
 
  else :
       print ("hello.py has not been modified")
       print ("Jenkins Job Not Triggered ")
       print ("Exiting.....")
       sys.exit(0)		
			
#If you are curious , Additional API calls follow 			
# Jenkins objects appear to be dict-like, mapping keys (job-names) to their attributes
#print J['test-job'] -> To obtain the attributes of jenkins job titled "jenkins-job"
#print J['test_job'].get_last_good_build() -> Ex: To obtain the last successfull build 
Esempio n. 34
0
from pkg_resources import resource_string

from jenkinsapi.view import View
from jenkinsapi.views import Views
from jenkinsapi.jenkins import Jenkins

log_level = getattr(logging, 'DEBUG')
logging.basicConfig(level=log_level)
logger = logging.getLogger()

jenkins_url = "http://127.0.0.1:8080/"
api = Jenkins(jenkins_url)

jobName = 'foo_job2'
xml = resource_string('examples', 'addjob.xml')
j = api.create_job(jobname=jobName, config=xml)

# Create ListView in main view
logger.info('Attempting to create new nested view')
top_view = api.views.create('TopView', Views.NESTED_VIEW)
logger.info('top_view is %s' % top_view)
if top_view == None: 
    logger.error('View was not created')
else:
    logger.info('View has been created')

print 'top_view.views=', top_view.views.keys()
logger.info('Attempting to create view inside nested view')
sub_view = top_view.views.create('SubView')
if sub_view == None:
    logger.info('View was not created')
Esempio n. 35
0
    if new_view is None:
        logger.error("View %s was not created" % test_view_name)
    else:
        logger.info("View %s has been created: %s" % (new_view.name, new_view.baseurl))
else:
    logger.info("View %s already exists" % test_view_name)

# No error is raised if view already exists
logger.info("Attempting to create view that already exists")
my_view = api.views.create(test_view_name)

logger.info("Create job and assign it to a view")
job_name = "foo_job2"
xml = resource_string("examples", "addjob.xml")

my_job = api.create_job(jobname=job_name, xml=xml)

# add_job supports two parameters: job_name and job object
# passing job object will remove verification calls to Jenkins
my_view.add_job(job_name, my_job)
assert len(my_view) == 1

logger.info("Attempting to delete view that already exists")
del api.views[test_view_name]

if test_view_name in api.views:
    logger.error("View was not deleted")
else:
    logger.info("View has been deleted")

# No error will be raised when attempting to remove non-existing view
Esempio n. 36
0
import logging
from pkg_resources import resource_string
from jenkinsapi.views import Views
from jenkinsapi.jenkins import Jenkins

log_level = getattr(logging, 'DEBUG')
logging.basicConfig(level=log_level)
logger = logging.getLogger()

jenkins_url = "http://127.0.0.1:8080/"
api = Jenkins(jenkins_url)

jobName = 'foo_job2'
xml = resource_string('examples', 'addjob.xml')
j = api.create_job(jobname=jobName, xml=xml)

# Create ListView in main view
logger.info('Attempting to create new nested view')
top_view = api.views.create('TopView', Views.NESTED_VIEW)
logger.info('top_view is %s' % top_view)
if top_view is None:
    logger.error('View was not created')
else:
    logger.info('View has been created')

print('top_view.views=', top_view.views.keys())
logger.info('Attempting to create view inside nested view')
sub_view = top_view.views.create('SubView')
if sub_view is None:
    logger.info('View was not created')
Esempio n. 37
0
J = Jenkins('http://localhost:8080')
print J.items()
j = J['foo']
j = J.get_job("foo")
b = j.get_last_build()
print b
mjn = b.get_master_job_name()
print(mjn)

EMPTY_JOB_CONFIG = '''\
<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description></description>
  <keepDependencies>false</keepDependencies>
  <properties/>
  <scm class="hudson.scm.NullSCM"/>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers class="vector"/>
  <concurrentBuild>false</concurrentBuild>
  <builders/>
  <publishers/>
  <buildWrappers/>
</project>
'''

new_job = J.create_job(name='foo_job', config=EMPTY_JOB_CONFIG)
Esempio n. 38
0
"""
This example shows how to create job from XML file and how to delete job
"""
from __future__ import print_function
from pkg_resources import resource_string
from jenkinsapi.jenkins import Jenkins

jenkins = Jenkins('http://localhost:8080')
job_name = 'pipeline2'
xml = resource_string('examples', './jenkins_dir/jobs/config.xml')

print(xml)

job = jenkins.create_job(jobname=job_name, xml=xml)

# Get job from Jenkins by job name
my_job = jenkins[job_name]
print(my_job)
Esempio n. 39
0
#	Date			: 27.11.2013
#	
#	Licensed under GPL
#
###########################################################################

import sys
import jenkinsapi,pkg_resources
from jenkinsapi import *
from pkg_resources import *
from jenkinsapi.jenkins import Jenkins

New_Job_Name=sys.argv[1]
XML_File=sys.argv[2]

print "\n New_Job_Name	: "+New_Job_Name
print "\n XML File	: "+XML_File+"\n"

Jenkins_server=Jenkins('http://localhost:8080')

#This XML file should be located in the same directory where the script is executed
#This XML file decides so many jenkins parameters for the Job like configuration system,version control etc.
#This XML File is used as a configuration either for creation or Reconfiguration
xml=resource_string(__name__,XML_File)
#if you want the sample content just do this command for any existing job 


#Now it should have reconfigured the job for you with the configuration you have mentioned in test.xml
Jenkins_server.create_job(New_Job_Name,xml)

Esempio n. 40
0
class LazyJenkins(object):
    jobs_filter = [p for p in SETTINGS.GHP_JOBS.split(',') if p]
    build_url_re = re.compile(r'.*/job/(?P<job>.*?)/.*(?P<buildno>\d+)/?')

    def __init__(self):
        self._instance = None

    def __getattr__(self, name):
        self.load()
        return getattr(self._instance, name)

    @retry
    def get_build_from_url(self, url):
        if not url.startswith(self.baseurl):
            raise Exception("%s is not on this Jenkins" % url)
        match = self.build_url_re.match(url)
        if not match:
            raise Exception("Failed to parse build URL %s" % url)
        job_name = match.group('job')
        job = self.get_job(job_name)
        buildno = int(match.group('buildno'))
        try:
            return Build(url, buildno, job)
        except requests.exceptions.HTTPError as e:
            if 404 == e.response.status_code:
                raise Exception("Build %s not found. Lost ?" % url)
            raise

    @retry
    def load(self):
        if not self._instance:
            logger.info("Connecting to Jenkins %s", SETTINGS.JENKINS_URL)
            self._instance = Jenkins(SETTINGS.JENKINS_URL)

    @retry
    def list_projects(self):
        """List github projects tested on this jenkins.

        Mine jobs configs to find github remote URL. Attach each job to the
        corresponding project.

        """

        projects = {}

        if not SETTINGS.GHP_JOBS_AUTO and not self.jobs_filter:
            logger.warn("Use GHP_JOBS env var to list jobs to managed")
            return []

        for name, job in self.get_jobs():
            if not match(name, self.jobs_filter):
                logger.debug("Skipping %s", name)
                continue

            job = Job.factory(job)
            if SETTINGS.GHP_JOBS_AUTO and job.polled_by_jenkins:
                logger.debug("Skipping %s, polled by Jenkins", name)
                continue

            # This option works only with webhook, so we can safely use it to
            # mark a job for jenkins-ghp.
            if SETTINGS.GHP_JOBS_AUTO and not job.push_trigger:
                logger.debug("Skipping %s, trigger on push disabled", name)
                continue

            job_projects = [x for x in job.get_projects()]
            if not job_projects:
                logger.debug("Skipping %s, no GitHub project to poll", name)
                continue

            for project in job_projects:
                logger.info("Managing %s", name)
                project = projects.setdefault(str(project), project)
                project.jobs.append(job)

        repositories = filter(None, SETTINGS.GHP_REPOSITORIES.split(' '))
        for entry in repositories:
            project, branches = entry.split(':')
            owner, repository = project.split('/')
            project = projects.setdefault(
                project, Project(owner, repository)
            )
            project.branches_settings = [
                'refs/heads/' + b for b in branches.split(',') if b
            ]

        return sorted(projects.values(), key=str)

    @retry
    def is_queue_empty(self):
        return len(self.get_queue().keys()) == 0

    @retry
    def create_job(self, job_spec):
        try:
            api_instance = self._instance.get_job(job_spec.name)
        except UnknownJob:
            env = jinja2.Environment(
                loader=jinja2.FileSystemLoader(
                    os.path.join(os.path.dirname(__file__), 'jobs')
                )
            )
            template = env.get_template('freestyle.xml')
            config = template.render(
                name=job_spec.name,
                assigned_node=SETTINGS.GHP_JOBS_NODE,
                command=SETTINGS.GHP_JOBS_COMMAND,
                owner=job_spec.project.owner,
                repository=job_spec.project.repository,
                credentials=SETTINGS.GHP_JOBS_CREDENTIALS,
                publish=(
                    not SETTINGS.GHP_DRY_RUN and not SETTINGS.GHP_GITHUB_RO
                ),
            )
            if SETTINGS.GHP_DRY_RUN:
                logger.info("Would create new Jenkins job %s", job_spec)
                return None

            api_instance = self._instance.create_job(job_spec.name, config)
            logger.info("Created new Jenkins job %s", job_spec.name)
        else:
            logger.debug("Not updating job %s from Jenkins", job_spec.name)

        job = Job.factory(api_instance)
        job_spec.project.jobs.append(job)
        return job
Esempio n. 41
0
from __future__ import print_function

import logging
logging.basicConfig()

from jenkinsapi.jenkins import Jenkins
from pkg_resources import resource_string
J = Jenkins('http://localhost:8080')
jobName = 'foo_job2'
xml = resource_string('examples', 'addjob.xml')

print(xml)

j = J.create_job(jobname=jobName, config=xml)

j2 = J[jobName]
print(j)

# Delete job
J.delete_job(jobName)
import sys, os

if __name__ == '__main__':
    if (len(sys.argv) < 4):
        # python $REPO_HOME/scripts/makejob.py "$StacksetType" "$CageName"
        print "Usage: python makejob.py <host> <stackset type> <cagename>"
        exit(1)
    jenkins_url = sys.argv[1]
    stackset_type = sys.argv[2]
    # print "SST "+stackset_type
    cage_name = sys.argv[3]
    # print "Cage "+cage_name
    path = os.environ['JENKINS_HOME']
    with open (path+"/workspace/CheckoutTheGitRepo/jenkins/jobs/"+stackset_type+"/config.xml", "r") as myfile:
        xml=myfile.read()
    #
    # fixup job template
    #
    s = Template(xml)
    job_def = s.substitute(cage_name=cage_name, stackset_type=stackset_type)
    api = Jenkins(jenkins_url)
    project_name = "Create a \""+stackset_type+"\" in \""+cage_name+"\" cage"
    print "Creating project '"+project_name+"'"
    job = api.create_job(project_name, job_def)

    view = api.views["StackSets"]
    if view is None:
        api.views.create("StackSets")
    view.add_job(project_name, job)
    print("Project created - "+job.name+" and added to the 'StackSets' view.")
Esempio n. 43
0
def server_upload_jobs(args, global_config, opts):
    '''
    Uploads jobs found in a directory directly to jenkins.
    
    The jobs should be defined as with a "config.xml" file per job, while the directory containing the
    "config.xml" file will be used as the name of the job:
        
        source-dir
            /job-name1
                /config.xml
            /job-name2
                /config.xml
                
    Executing "cit server_upload_jobs source-dir" will upload "job-1" and "job-2" to jenkins,
    creating or updating them.
    '''
    if not args:
        print >> sys.stderr, "error: Must pass a directory name"
        return 2
    
    directory = args[0]
    if not os.path.exists(directory):
        print >> sys.stderr, 'error: Directory "%s" does not exist' % directory
        return 2


    jenkins_url = global_config['jenkins']['url']
    jenkins = Jenkins(jenkins_url)

    search_pattern = None
    local_jobs = []
    for dir_name in glob.glob(directory + '/*'):
        # Ignore all files
        if not os.path.isdir(dir_name):
            continue

        job_info = JobInfo(dir_name)
        if job_info.config_filename is None:
            print 'Missing config.xml file from %r' % dir_name
            continue
        
        if opts.reindex:
            if search_pattern is None:
                search_pattern = job_info.SearchPattern()
            elif search_pattern != job_info.SearchPattern():
                raise ValueError('Bad job names pattern: %r != %r' % (search_pattern, job_info.SearchPattern()))
        
        job_info.update = jenkins.has_job(job_info.name)
        local_jobs.append(job_info)
        
    rename_jobs = {}
    delete_jobs = []
    if opts.reindex:
        remote_jobs = get_remote_job_infos(search_pattern, global_config, jenkins=jenkins)
        remote_basenames = dict((ji.BaseName(), ji) for ji in remote_jobs)
        
        for job_info in local_jobs:
            base_name = job_info.BaseName()
            remote_job = remote_basenames.pop(base_name, None)
            if remote_job is not None and remote_job.name != job_info.name:
                rename_jobs[job_info.name] = remote_job.name
        
        delete_jobs = [ji.name for ji in remote_basenames.itervalues()]
        
    for job_info in local_jobs:
        if job_info.name in rename_jobs:
            print 'Renaming %r -> %r' % (rename_jobs[job_info.name], job_info.name)
            
        elif job_info.update:
            print 'Updating %r' % job_info.name
        else:
            print 'Creating %r' % job_info.name
            
    for job_name in delete_jobs:
        print
        print 'Deleting %r' % job_name
        print
            
    if len(local_jobs) > 0:
        ans = raw_input('Update jobs (y|*n): ')
        if ans.startswith('y'):
            for job_info in local_jobs:
                config_xml = file(job_info.config_filename).read()
                
                if job_info.name in rename_jobs:
                    remote_name = rename_jobs[job_info.name]
                    print '\tUpdating job'
                    job = jenkins.get_job(remote_job.name)
                    job.update_config(config_xml)
                    
                    print 'Renaming %r -> %r' % (remote_name, job_info.name)
                    jenkins.rename_job(remote_name, job_info.name)
                    
                else:
                    if job_info.update:
                        print 'Updating %r' % job_info.name
                        job = jenkins.get_job(job_info.name)
                        job.update_config(config_xml)
                    else:
                        print 'Creating %r' % job_info.name
                        job = jenkins.create_job(job_info.name, config_xml)

            for job_name in delete_jobs:
                print 'Deleting %r' % job_name
                job = jenkins.delete_job(job_name)
Esempio n. 44
0
"""
A lower-level implementation of copying a job in Jenkins
"""
from __future__ import print_function

import requests
from jenkinsapi.jenkins import Jenkins
from pkg_resources import resource_string
from jenkinsapi_tests.test_utils.random_strings import random_string

J = Jenkins('http://localhost:8080')
jobName = random_string()
jobName2 = '%s_2' % jobName

url = 'http://localhost:8080/createItem?from=%s&name=%s&mode=copy' % (jobName, jobName2)

xml = resource_string('examples', 'addjob.xml')
j = J.create_job(jobname=jobName, xml=xml)


h = {'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(url, data='dysjsjsjs', headers=h)
print(response.text.encode('UTF-8'))
dst_view_url = 'http://buildserver:8080/hudson/view/DBCI/view/Trunk-new'

api = Jenkins(URL, LOGIN, API_KEY)

view_src = api.get_view_by_url(src_view_url)
view_dst = api.get_view_by_url(dst_view_url)

for job_name, job in view_src.items():
    exclude_job = False
    if len(exclude_jobs_name_contains) > 0:
        for job_name_substr in exclude_jobs_name_contains:
            if job_name_substr in job_name:
                exclude_job = True

    if exclude_job:
        log.debug('skipping job: %s' % job_name)
        continue

    job = api.get_job(job_name)
    job_config = job.get_config()
    new_job_config = replace(job_config, replacements)
    new_job_name = make_job_name(job_name)
    log.info('new job name: %s, old: %s' % (new_job_name, job_name))
    new_job = api.create_job(new_job_name, new_job_config)
    #new_job.disable()
    view_dst.add_job(new_job_name)
    log.info('%s job added to view: %s' % (new_job_name, view_dst))



Esempio n. 46
0
        logger.error('View %s was not created' % test_view_name)
    else:
        logger.info('View %s has been created: %s' %
                    (new_view.name, new_view.baseurl))
else:
    logger.info('View %s already exists' % test_view_name)

# No error is raised if view already exists
logger.info('Attempting to create view that already exists')
my_view = api.views.create(test_view_name)

logger.info('Create job and assign it to a view')
job_name = 'foo_job2'
xml = resource_string('examples', 'addjob.xml')

my_job = api.create_job(jobname=job_name, xml=xml)

# add_job supports two parameters: job_name and job object
# passing job object will remove verification calls to Jenkins
my_view.add_job(job_name, my_job)
assert len(my_view) == 1

logger.info('Attempting to delete view that already exists')
del api.views[test_view_name]

if test_view_name in api.views:
    logger.error('View was not deleted')
else:
    logger.info('View has been deleted')

# No error will be raised when attempting to remove non-existing view
Esempio n. 47
0
        logger.error('View %s was not created', test_view_name)
    else:
        logger.info('View %s has been created: %s',
                    new_view.name, new_view.baseurl)
else:
    logger.info('View %s already exists', test_view_name)

# No error is raised if view already exists
logger.info('Attempting to create view that already exists')
my_view = jenkins.views.create(test_view_name)

logger.info('Create job and assign it to a view')
job_name = 'foo_job2'
xml = resource_string('examples', 'addjob.xml')

my_job = jenkins.create_job(jobname=job_name, xml=xml)

# add_job supports two parameters: job_name and job object
# passing job object will remove verification calls to Jenkins
my_view.add_job(job_name, my_job)
assert len(my_view) == 1

logger.info('Attempting to delete view that already exists')
del jenkins.views[test_view_name]

if test_view_name in jenkins.views:
    logger.error('View was not deleted')
else:
    logger.info('View has been deleted')

# No error will be raised when attempting to remove non-existing view
Esempio n. 48
0
J = Jenkins('http://localhost:8080')
print(J.items())
j = J.get_job("foo")
b = j.get_last_build()
print(b)
mjn = b.get_master_job_name()
print(mjn)

EMPTY_JOB_CONFIG = '''\
<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description></description>
  <keepDependencies>false</keepDependencies>
  <properties/>
  <scm class="hudson.scm.NullSCM"/>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers class="vector"/>
  <concurrentBuild>false</concurrentBuild>
  <builders/>
  <publishers/>
  <buildWrappers/>
</project>
'''

new_job = J.create_job(jobname='foo_job', xml=EMPTY_JOB_CONFIG)
Esempio n. 49
0
  <keepDependencies>false</keepDependencies>
  <properties/>
  <scm class="hudson.scm.NullSCM"/>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers class="vector"/>
  <concurrentBuild>false</concurrentBuild>
  <builders/>
  <publishers/>
  <buildWrappers/>
</project>
'''

jobname = 'foo_job'
new_job = J.create_job(jobname, EMPTY_JOB_CONFIG)
new_conf = new_job.get_config()

root = et.fromstring(new_conf.strip())

builders = root.find('builders')
shell = et.SubElement(builders, 'hudson.tasks.Shell')
command = et.SubElement(shell, 'command')
command.text = "ls"

print(et.tostring(root))
J[jobname].update_config(et.tostring(root))

# J.delete_job(jobname)
Esempio n. 50
0
def configure_master(settings, docker_url, cert_path) -> bool:
    print("Setting up docker")
    docker = utils.setup_docker_client(docker_url, cert_path)
    containers = docker.containers.list(filters={"name": MASTER_IMAGE})

    if len(containers) > 0:
        container = containers[0]

        print("Finding IP of container...")

        ip = utils.get_ip(container, docker, settings)

        while len(ip) == 0:
            ip = utils.get_ip(container, docker, settings)
            container.reload()

        jenkins_url = "http://{ip}:8080".format(ip=ip)

        while True:
            try:
                jenkins = Jenkins(jenkins_url)
            except:
                print("Waiting for jenkins to start...")
                time.sleep(5)
            else:
                break

        creds = jenkins.credentials

        print("Storing container credentials")
        env = govc.build_env(settings)
        env = utils.populate_env(env, container)
        env["GOVC_GUEST_LOGIN"] = container.id
        env["GOVC_VM"] = container.name + "-" + container.id[:12]

        files = os.listdir(cert_path)
        files = [os.path.join(cert_path, file) for file in files]

        destination = "/var/jenkins_home/docker_certs"
        govc.run(settings.gopath, env, ["guest.mkdir", destination])
        govc.upload(settings.gopath, env, destination, files)

        with open("jenkins-ssh-keys/jenkins_ssh") as f:
            private_key = f.read()

        cred_dict = {
            'description': utils.CREDS_DESCRIPTION,
            'userName': '******',
            'passphrase': '',
            'private_key': private_key
        }

        if utils.CREDS_DESCRIPTION in creds:
            print("Deleting existing credentials.")
            del creds[utils.CREDS_DESCRIPTION]

        print("Uploading new credentials")

        creds[utils.CREDS_DESCRIPTION] = SSHKeyCredential(cred_dict)

        esx_settings = settings.integration_esx_settings
        vch_settings = populate_vch_template_settings(settings)

        if not populate_integration_esx_settings(esx_settings):
            return False

        xml = config_template_integration.format(**esx_settings)

        if INTEGRATION_JOB_NAME in jenkins:
            print("Updating integration job")
            job = jenkins[INTEGRATION_JOB_NAME]
            job.update_config(xml)
        else:
            print("Creating integration job")
            job = jenkins.create_job(jobname=INTEGRATION_JOB_NAME, xml=xml)

        pprint(job)

        xml = config_template_vch.format(**vch_settings)

        if VCH_JOB_NAME in jenkins:
            print("Updating vch job")
            job = jenkins[VCH_JOB_NAME]
            job.update_config(xml)
        else:
            print("Creating vch job")
            job = jenkins.create_job(jobname=VCH_JOB_NAME, xml=xml)

        pprint(job)

        return True

    else:
        print("Failed to find the container to configure.")
        return False
Esempio n. 51
0
class JenkinsMaster(object):
    def __init__(self):
        self.args = self._parse_args()
        level = ["DEBUG", "INFO", "WARN", "ERROR"][min(3, self.args.debug)]
        logging.basicConfig(level=getattr(logging, level))
        self.log = logging.getLogger("app")
        self.config = ordered_load(open(self.args.config))
        self.basedir = os.path.dirname(self.args.config)
        requester = Requester(ssl_verify=False, baseurl=self.args.server)
        self.jenkins = Jenkins(self.args.server, requester=requester)

    def _push_job(self, name, xml):
        if name in self.jenkins.jobs:
            print "Update job: %s" % name
            job = self.jenkins.jobs[name].update_config(xml)
            assert not job, job
        else:
            print "Create job: %s" % name
            job = self.jenkins.create_job(name, xml)
            assert job is not None, job

    def _push_nested_view(self, name, subviews):
        if name in self.jenkins.views:
            print "Delete root view: %s" % name
            del (self.jenkins.views[name])
        print "Create root view: %s" % name
        root = self.jenkins.views.create(name, Views.NESTED_VIEW)
        assert root is not None, root

        for view, jobs in subviews.iteritems():
            print "  Create nested view: %s" % view
            view = root.views.create(view)
            assert view is not None, view
            for job in jobs:
                print "    Add job: %s" % job
                assert view.add_job(job)

    def _pull_jobs(self, location):
        xmls = sorted(glob.glob(os.path.join(os.path.abspath(location), "*.xml")))
        jobs = [os.path.basename(_)[:-4] for _ in xmls]
        remote_all = self.jenkins.jobs.keys()
        for name, xml in izip(jobs, xmls):
            if name in remote_all:
                job = self.jenkins.jobs[name]
                assert job is not None, job
                print "Job %s updated" % name
                open(xml, "w").write(job.get_config())
            else:
                print "Job %s removed" % name
                os.remove(xml)

    def _parse_args(self):
        parser = ArgumentParser(description="Jenkins master to manage your " "Jenkins job/views")
        parser.add_argument("-d", "--debug", action="count", default=0, help="Set the level of logging")
        parser.add_argument(
            "-s",
            "--server",
            help="Set the jenkins server " "address [http://localhost:8080]",
            default="http://localhost:8080",
        )
        parser.add_argument("config", help="Set the config file location " "[./variants.yaml]", default="variants.yaml")
        return parser.parse_args()

    def run(self):
        def basename(job):
            return os.path.basename(job)[:-4]

        if raw_input("Pull jobs first? [no]"):
            self.pull_jobs()

        self.log.info("-" * 80)
        views = self.update_all_jobs()
        self.compare_jobs()
        self.log.info("-" * 80)
        if raw_input("Push changes? [no]"):
            changes = self.push_jobs()
            removed_jobs = [
                basename(job)
                for job in glob.glob(os.path.join(self.basedir, ".jobs", "*"))
                if not os.path.exists(os.path.join(self.basedir, "jobs", basename(job) + ".xml"))
            ]
            if removed_jobs and raw_input("Remove deleted jobs? [no]"):
                changes += self.push_remove_jobs(removed_jobs)
                self.log.info("-" * 80)
            view = self.config["view"]
            if changes and raw_input("Update views? [no]"):
                self.push_view(view, views)
            else:
                self.log.debug("Remote: view %s unchanged" % view)

    def compare_jobs(self):
        orig = os.path.join(self.basedir, ".jobs")
        new = os.path.join(self.basedir, "jobs")
        os.system("meld %s %s" % (orig, new))

    def pull_jobs(self):
        self._pull_jobs(os.path.join(self.basedir, ".jobs"))

    def update_all_jobs(self):
        per_view_jobs = OrderedDict()  # Stores jobs for given variant
        # Remove the old job xmls
        for name in glob.glob(os.path.join(self.basedir, "jobs", "*.xml")):
            os.remove(name)
        for view, params in self.config["views"].iteritems():
            if "__LONG_NAME__" in params:
                view_name = params["__LONG_NAME__"]
            else:
                view_name = view
            # Jobs from views
            if "__EXTENDS__" in params:  # recursively extend values
                params = self._extends(self.config["views"], params)
            per_view_jobs[view_name] = self._update_jobs(view, params)
            # Extra jobs
        return per_view_jobs

    def _update_jobs(self, view, params):
        self.log.debug("  Processing view: %s", view)
        jobs = []
        for job, job_params in params.get("JOBS", {}).iteritems():
            self.log.debug("    Processing job: %s", job)
            if job in self.config["templates"]:
                if job_params:
                    template_params = self.config["templates"][job].copy()
                    template_params.update(job_params)
                    job_params = template_params
                else:
                    job_params = self.config["templates"][job]
                template = os.path.join(self.basedir, "templates", "jobs", "%s.tpl" % job_params["__TEMPLATE__"])
                content = open(template).read()
            else:
                template = os.path.join(self.basedir, "templates", "jobs", "%s.tpl" % job)
                content = open(template).read()
            content = self._process_job(content, params, job_params)
            open(os.path.join(self.basedir, "jobs", "%s_%s.xml" % (job, view)), "w").write(content)
            jobs.append("%s_%s" % (job, view))
        return jobs

    def _process_job(self, content, params, job_params):
        def machines(machines):
            return (
                "<allowedSlaves>\n"
                "  <string>%s</string>\n"
                "</allowedSlaves>\n"
                "<defaultSlaves>\n"
                "  <string>%s</string>\n"
                "</defaultSlaves>" % ("</string>\n  <string>".join(machines), machines[0])
            )

        if job_params is None:
            job_params = {}
        # First update MACHINES
        content = self._sub(content, "MACHINES", machines(params["MACHINES"]))
        # Job params
        for key, value in job_params.iteritems():
            content = self._sub(content, key, value)
        for key, value in params.get("__SHARED__", {}).iteritems():
            if key in job_params:
                continue
            content = self._sub(content, key, value, False)
        # Remove unused templates
        content = self._sub(content, r".*", "", False)
        return content

    def _sub(self, string, key, value, mandatory=True):
        if key[:2] == "__" and key[-2:] == "__":
            return string
        if isinstance(value, dict) and "__DATA__" in value:
            value = self.config["data"][value["__DATA__"]]
        string, count = re.subn("<!--TEMPLATE__%s__TEMPLATE-->" % key, value, string)
        if mandatory and not count:
            raise ValueError("No TEMPLATE__%s__TEMPLATE found in template." % key)
        return string

    def _extends(self, root, params):
        def recursive_default(params, _params):
            for key, value in _params.iteritems():
                if key not in params:
                    params[key] = value
                elif isinstance(value, dict):
                    recursive_default(params[key], _params[key])

        _params = root[params["__EXTENDS__"]]
        if "__EXTENDS__" in _params:
            _params = self._extends(root, _params)
        recursive_default(params, _params)
        return params

    def push_jobs(self):
        # Push all created jobs
        changes = 0
        for xml_path in glob.glob(os.path.join(self.basedir, "jobs", "*.xml")):
            name = os.path.basename(xml_path)[:-4]  # remove path + .xml
            _xml_path = os.path.join(self.basedir, ".jobs", "%s.xml" % name)
            if os.path.exists(_xml_path) and (
                md5(open(xml_path).read()).hexdigest() == md5(open(_xml_path).read()).hexdigest()
            ):
                self.log.debug("Remote: job %s unchanged", name)
                continue
            self._push_job(name, open(xml_path).read())
            shutil.copy2(xml_path, _xml_path)
            changes += 1
        return changes

    def push_view(self, view, views):
        # Recreate the view and subviews
        self._push_nested_view(view, views)

    def push_remove_jobs(self, jobs):
        changes = 0
        for name in jobs:
            self.log.debug("Remote: deleting job %s", name)
            del (self.jenkins.jobs[name])
            os.remove(os.path.join(self.basedir, ".jobs", "%s.xml" % name))
            changes += 1
        return changes
Esempio n. 52
0
                    'transfers'][
                        'jenkins.plugins.publish__over__ssh.BapSshTransfer'][
                            'sourceFiles'] = kwargs['sourcefiles']
    # execcommand
    normal_config['maven2-moduleset']['postbuilders'][
        'jenkins.plugins.publish__over__ssh.BapSshBuilderPlugin']['delegate'][
            'delegate']['publishers'][
                'jenkins.plugins.publish__over__ssh.BapSshPublisher'][
                    'transfers'][
                        'jenkins.plugins.publish__over__ssh.BapSshTransfer'][
                            'execCommand'] = kwargs['execcommand']

    xml = dicttoxml.dicttoxml(normal_config).decode(encoding='utf-8')
    # print(type(xml))
    print(xml)
    return xml


args = {
    'description': '测试下这个问题',
    'git_url': 'https://github.com/linweili0615/testsearch.git',
    'git_branches': '*/master',
    'ssh': 'test1234',
    'remotedirectory': 'source/test',
    'sourcefiles': '**/target/demo-2.0.jar',
    'execcommand': 'sh /usr/local/software/test3.sh test demo-1.0.jar 9301'
}

config_xml = get_normal_config(**args)
jk.create_job('test999', xml=config_xml)