2016-05-25 9 views
8

Mamy setki projektów Jenkins (głównie utworzone z kilku szablonów), często trzeba wprowadzić te same zmiany do wszystkich z nich. na przykład dzisiaj muszę dodać krok po kompilacji, aby usunąć obszar roboczy na końcu. Następnie muszę zmienić krok, aby skopiować wynik kompilacji na udostępniony dysk do repozytorium Nexusa.Jaki jest najlepszy sposób zbiorczego aktualizowania projektów Jenkins?

Jaki jest najlepszy sposób zastosowania tego rodzaju zmiany w masowych projektach Jenkins?

+0

Nie jestem pewien, czy to ma wystarczająco dużo opcji, ale użyłem wtyczki Jobcopy Builder w przeszłości, aby zrobić coś podobnego, możesz użyć tego do skopiowania zadań i określenia ciągów do znalezienia i zamiany w konfiguracji – iestync

+0

Jeśli są to konfiguracje automatycznie generowanych zadań, możesz przejść do $ Jenkins_Home/jobs na swoim master i string-replace-add, co potrzebujesz. Użyłem go do zmiany wszystkich konfiguracji jdk dla wszystkich zadań zaczynających się od Master- *, całkiem łatwo zrobić to w skrypcie powłoki. – Dvir669

Odpowiedz

4

Groovy jest zdecydowanie najlepszą metodą zbiorczego aktualizowania zadań. Być może będziesz musiał trochę zagłębić się w interfejsie jenkins/plugin, aby dowiedzieć się, do czego służy wywołanie api, ale konsola skryptowa (http://yourJenkinsUrl/script) zapewnia łatwy sposób na obejście kodu, dopóki nie zostanie poprawiony.

Aby rozpocząć, można dodawać/usuwać etapy post-build, wywołując metodę getPublishersList() dla zadania, a następnie wywołując metody dodawania/usuwania.

def publishersList = Jenkins.instance.getJob("JobName").getPublishersList() 
publishersList.removeAll { it.class == whatever.plugin.class } 
publishersList.add(new PluginConstructor()) 

Jeśli nie jesteś pewien, co klasa wydawca trzeba usunąć obszar roboczy, chciałbym zaproponować ręcznie dodając żądane konfiguracje do jednego zadania, a następnie uruchomić getPublishersList() z konsoli skryptu na tej pracy. Na liście zobaczysz klasę, z którą pracujesz, a następnie możesz przejrzeć api, aby zobaczyć, co jest potrzebne do jego zbudowania.

Następnie można wykonać iterację wszystkich swoich zadań i dodać wydawcy robią coś takiego:

Jenkins.instance.getView("All Jobs").items.each { job -> 
    //Maybe some logic here to filter out specific jobs 

    job.getPublishersList().add(new PluginConstructor()) 
} 

Alternatywnie, można użyć API Jenkins CLI lub interfejsu API REST, ale w celu aktualizacji pokompilacyjnych działania, będziesz musiał zmodyfikować plik xml konfiguracji projektu (który nie jest trywialnie programowo konfigurowany), a następnie zastąpić konfigurację zadania nowym plikiem konfiguracyjnym.

+0

Używam 'Jenkins.instance.items', aby uzyskać listę wszystkich zadań. 'Jenkins.instance.getView (" All Jobs ")' nie działa dla mnie, być może dlatego, że zależy to od określonego widoku. Ponadto, [wiki strony Jenkins Script Console] (https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Script+Console) jest dobrym miejscem do znalezienia przykładowych skryptów. –

+0

Przepraszamy. Nadzór z mojej strony. Poprawiłem moją odpowiedź poprawnym kodem. – TheEllis

4

The REST API jest dość potężny. Poniższa sekwencja pracował dla mnie:

W pętli dla wszystkich istotnych projektów (lista projektów jest dostępna poprzez np /api/xml?tree=jobs[name]):

  • pobieranie config.xml poprzez /job/{name}/config.xml
  • edytować za pośrednictwem swojego ulubionego skryptów XML Editor (kopalnia był xmlstarlet)
  • wgrać nowy config xml poprzez /job/{name}/config.xml

Niektóre losowe Uwagi:

  • zrobić BACKUP * * zanim cokolwiek
  • pewnie mógłby zakładać jakiś przykład skryptu bash, jeśli ktoś jest zainteresowany

Powodzenia!

EDIT> Przykład skryptu bash:

#!/bin/bash 

jenkinsUrlBase='http://user:[email protected]' 

callJenkins() { # funcPath 
    curl --silent --show-error -g "${jenkinsUrlBase}${1}" 
} 

postJenkinsFile() { # funcPath fileName 
    curl --silent --show-error -g -d "@${2}" "${jenkinsUrlBase}${1}" 
} 

callJenkins '/api/xml?tree=jobs[name]' | xmlstarlet sel -t -v '//hudson/job/name' | while read projectName ; do 

    echo "Processing ${projectName}..." 
    origFile="${projectName}_old.xml" 
    newFile="${projectName}_new.xml" 
    callJenkins "/job/${projectName}/config.xml" > "$origFile" 

    echo " - Updating artifactory url..." 
    cat "$origFile" \ 
     | xmlstarlet ed -P -u '//maven2-moduleset/publishers/org.jfrog.hudson.ArtifactoryRedeployPublisher/details/artifactoryUrl' -v "http://newServer/artifactory" \ 
    > "${newFile}" 

    if false ; then 
     echo " - Commiting new config file..." 
     postJenkinsFile "/job/${projectName}/config.xml" "$newFile" 
    else 
     echo " - Dry run: not commiting new config file" 
    fi 

done 
+0

Czy nie musisz ponownie ładować Jenkinsa, aby zmiany systemu plików zostały wprowadzone? – Slav

+0

@Slav O ile wiem zmiany za pomocą REST API zachowują się tak samo, jak zmiany za pośrednictwem interfejsu internetowego - w związku z tym nie powinno być potrzeby ponownego ładowania. (IMHO) Będziesz musiał przeładować Jenkinsa, jeśli zmienisz pliki konfiguracyjne bezpośrednio w systemie plików, ale metoda w odpowiedzi działa inaczej. – vlp

3

można edytować plik config.xml ze swoim ulubionym narzędziem tekstowym (VI, Python, ...), a następnie przeładować konfigurację Jenkins.

W mojej konfiguracji zadania są przechowywane w ~/.jenkins/jobs/*/config.xml.

Patrz: https://wiki.jenkins-ci.org/display/JENKINS/Administering+Jenkins

Oto mały przykład zaktualizować foo do bar:

</com.cwctravel.hudson.plugins.extended__choice__parameter.ExtendedChoiceParameterDefinition> 
     <hudson.model.StringParameterDefinition> 
      <name>additional_requirements</name> 
      <description>foo</description> 
... 

skryptu:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
from __future__ import absolute_import, division, unicode_literals, print_function 

import sys 
from lxml import etree 
from collections import defaultdict 


def change_parameter_descrption(config_xml_path, parameter_name, new_description): 
    tree=etree.parse(config_xml_path) 

    for tag in tree.findall('.//hudson.model.StringParameterDefinition'): 
     name_tag=tag.find('./name') 
     if not name_tag.text==parameter_name: 
      continue 
     description=tag.find('./description') 
     description.text=new_description 
    tree.write(config_xml_path) 


for config_xml_path in sys.argv[1:]: 
    change_parameter_descrption(config_xml_path, 'additional_requirements', 'bar') 

W tej niewielkiej przykład regex będzie działać, ale jeśli rzeczy rozpiętość kilku linii, lepiej jest pracować z narzędziami xml :-)

Powiązane problemy