Ho avuto la necessità di configurare il processo di costruzione e consegna dei pacchetti software sul sito da un repository Git. E vedendo, non molto tempo fa, un articolo su Habr riguardante buildbot (link alla fine) ho deciso di provarlo e utilizzarlo.
Poiché buildbot è un sistema distribuito, sarà logico creare un'istanza di costruzione separata per ogni architettura e sistema operativo. Nel nostro caso saranno contenitori LXC (in caso di linux) e qemu (in caso di windows):
- vm-srv-build1 — centos 7, qui ci sarà il master di buildbot e uno dei worker
- vm-srv-build2 — debian 10, per la costruzione dei pacchetti DEB
- vm-srv-build3 — windows 10, per la costruzione, sapete bene a cosa serve
Costruiremo — interfaccia grafica per 1C rac per la gestione di un cluster di server. Su linux verranno utilizzati gli strumenti nativi per ogni SO, per costruire il file exe sotto windows da uno script tcl si utilizza .
Installazione
GNU/Linux
Ci sono molte informazioni su installazione e documentazione in rete. ,E non presenta particolari problemi:
Per il master:
pip3 install buildbot
pip3 install twisted
pip3 install autobahn
pip3 install pysqlite3
pip3 install sqlalchemy sqlalchemy-migrate
pip3 install buildbot-www buildbot-grid-view buildbot-console-view buildbot-waterfall-view
pip3 install python-dateutilPer i "worker", questo è sufficiente:
pip3 install buildbot-workerNaturalmente, sarebbe più corretto costruire i pacchetti per ogni OS, ma questo non rientra nell'ambito di questo articolo. Trascurerò anche la descrizione della configurazione dei contenitori per il funzionamento, segnalo solo che utilizzo ProxMox VE. Inoltre, sarà necessario installare i pacchetti necessari per la costruzione per ciascun sistema operativo (centos: rpmdevtools e così via; debian: build-essential, dh-make, pbuilder e così via).
I progetti di costruzione e i servizi buildbot verranno eseguiti con un utente non privilegiato, quindi è necessario crearlo su tutti gli host partecipanti al processo:
adduser buildbotPoi configureremo l'avvio automatico dei servizi, rispettivamente su ciascuno degli host (contenitori):
Unità systemd per avviare il master:
touch /etc/systemd/buildbot-master.service
[Unit]
Description=Servizio master di BuildBot
After=network.target
[Service]
User=buildbot
Group=buildbot
WorkingDirectory=/home/buildbot/master
ExecStart=/usr/local/bin/buildbot start --nodaemon
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.targete il "worker"
touch /etc/systemd/buildbot-worker.service
[Unit]
Description=Servizio worker di BuildBot
After=network.target
[Service]master
User=buildbot
Group=buildbot
WorkingDirectory=/home/buildbot/worker
ExecStart=/usr/local/bin/buildbot-worker start --nodaemon
[Install]
WantedBy=buildbot-master.servicePoiché tutti gli script (nel nostro caso) si trovano in /usr/local/, è necessario specificare il percorso nella variabile di ambiente:
nano /root/.bash_profile
PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/binDopo di ciò, è possibile creare un'infrastruttura di directory per i «lavoratori» (su tutti gli host), registrandosi come utente buildbot ed eseguendo i seguenti comandi:
Sul primo host vm-srv-build1:
su - buildbot
mkdir /home/buildbot/worker
cd ~
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker vm-srv-build1:4000 CentOS 123456Sul secondo host vm-srv-build2:
su - buildbot
mkdir /home/buildbot/worker
cd ~
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker vm-srv-build1:4000 Debian-10 123456Sugli host-lavoratori, il servizio buildbot-worker può essere avviato
systemctl start buildbot-workerMS Windows
Come «lavoratore» per la compilazione su Windows, verrà utilizzata una macchina virtuale con l'ultima versione di Win10.
Per il lavoro sono necessari:
- Per installare vari pacchetti in Python, è stato necessario scaricare
- 7Zip
Dopo che quanto sopra è stato installato, è possibile installare anche buildbot:
pip install buildbot-workerCreeremo una directory di lavoro
md c:workerE avviamolo
buildbot-worker start c:workerSe tutto funziona (vedi log c:workertwistd.log), è possibile registrare il nostro «lavoratore» come servizio, aggiungendo nel registro una voce con la directory di lavoro (i comandi vengono eseguiti in PowerShell lanciato come amministratore):
buildbot_worker_windows_service.exe --user VM-SRV-BUILD3buildbot --password 123456 --startup auto install
New-ItemProperty -path Registry::HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesBuildBotParameters -Name directories -PropertyType String -Value c:worker
E si può avviare il servizio
Start-Service buildbotCon i «lavoratori» è tutto, ora possono rimanere inalterati, tutta la gestione avviene dal master.
Configurazione del master
Per iniziare, creiamo un'infrastruttura per il master (sull'host principale), registrandosi come utente buildbot ed eseguendo i seguenti comandi:
su - buildbot
mkdir /home/buildbot/master
cd ~
buildbot create-master masterPer i pacchetti pronti, creiamo una directory builds
mkdir /home/buildbot/buildsNella directory /home/buildbot/master/ è stato creato un file master.cfg. Questo file rappresenta un codice Python e contiene la descrizione di tutti i meccanismi di funzionamento del sistema, con cui lavoreremo in seguito.
nano /home/buildbot/master/master.cfgimport os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters
c= BuildmasterConfig ={}
# Descrizione dei nostri lavoratori.
c['workers'] = [ worker.Worker('CentOS', '123456'), worker.Worker('Debian-10', '123456'), worker.Worker('Windows-10', '123456')]
c['protocols'] = {'pb': {'port': 4000}}
# Indicare al maestro quale repository monitorare
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
project = 'Rac-GUI',
branches = True,
pollInterval = 60
)
)
# Servizio di avvio della build
c['schedulers'] = []
c['schedulers'].append(schedulers.SingleBranchScheduler(
name="Rac-GUI-schedulers",
change_filter=util.ChangeFilter(branch='master'),
builderNames=["Rac-GUI-RPM-builder", "Rac-GUI-DEB-builder", "Rac-GUI-WIN-builder"],
properties = {'owner': 'admin'}
)
)
@util.renderer
######################################3
# Costruzione del pacchetto RPM
rac_gui_build_RPM = util.BuildFactory()
rac_gui_build_RPM.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
workdir = 'rac-gui',
haltOnFailure = True,
submodules = True,
mode='full',
progress = True)
)Per automatizzare la costruzione di pacchetti di diverse versioni, evitando di dover modificare il codice del file master.cfg, sono state aggiunte nel file principale rac_gui.tcl righe con la versione e il rilascio attuali:
######################################################
# Rac GUI
...
# version: 1.0.3
# release: 1E sulla base di queste righe, buildbot numererà i pacchetti. Per estrarre i dati, si utilizza il comando console grep. In buildbot non è possibile definire variabili per i "lavoratori" (almeno, non sono riuscito a trovare un modo). A questo scopo servono le proprietà (property). Quindi, nel processo di build, aggiungiamo passaggi per definire la versione e il rilascio e, di conseguenza, impostiamo le proprietà version e release. Le proprietà possono essere impostate in vari modi, in questo caso si utilizza una chiamata a un comando console:
# Добавим определение версии из основного файла
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep version ../rac-gui/rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Добавим определение релиза из основного файла
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep release ../rac-gui/rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)I valori ottenuti possono essere inseriti utilizzando util.Interpolate().
# Запакуем исходники
rac_gui_build_RPM.addStep(
steps.ShellCommand(
command=["tar", "czf", util.Interpolate("/home/buildbot/rpmbuild/SOURCES/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"), "../rac-gui"]
)
)Va notato che, poiché l'host è utilizzato anche per la costruzione manuale dei pacchetti, la costruzione avverrà secondo i percorsi standard.
# Копируем spec
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["cp", "../rac-gui/rac_gui.spec", "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))Per impostare correttamente i numeri di rilascio e versione si utilizza il comando standard sed, cioè il comando sostituisce i valori all'interno del file spec con quelli necessari.
# меняем версию
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s/.*Version:.*/Version:t%(prop:version)s/"), "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))
# меняем релиз
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s/.*Release:.*/Release:t%(prop:release)s/"), "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))
# запускаем процесс сборки
rac_gui_build_RPM.addStep(steps.RpmBuild(
specfile="/home/buildbot/rpmbuild/SPECS/rac_gui.spec",
dist='.el5',
topdir='/home/buildbot/rpmbuild',
builddir='/home/buildbot/rpmbuild/build',
rpmdir='/home/buildbot/rpmbuild/RPMS',
sourcedir='/home/buildbot/rpmbuild/SOURCES'
)
)Il pacchetto costruito e l'archivio con i sorgenti vengono copiati sul maestro. Ma è possibile anche copiare direttamente dai file di lavoro nel proprio repository o sul sito.
# Скопируем файл на мастер
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("/home/buildbot/rpmbuild/RPMS/noarch/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")
)
)
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("/home/buildbot/rpmbuild/SOURCES/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")
)
)Avvieremo sul maestro il processo di copia dei pacchetti costruiti sull'hosting tramite ftp. Per questo viene utilizzato in tcl.
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")]
)
)
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")]
)
)Abbiamo finito con RPM. Ora passiamo alla descrizione dell'algoritmo di costruzione del pacchetto DEB. Poiché i processi di costruzione dei pacchetti per diversi sistemi sono indipendenti l'uno dall'altro, molti passaggi si ripeteranno.
rac_gui_build_DEB = util.BuildFactory()
rac_gui_build_DEB.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)
# Aggiungiamo la definizione della versione dal file principale
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep version rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Aggiungiamo la definizione del rilascio dal file principale
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
# Rinominiamo il file eseguibile
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["mv", "rac_gui.tcl", "racgui"]))Per il pacchetto RPM, parte delle procedure seguenti vengono eseguite dal rpm durante la costruzione e sono descritte all'interno dello spec, per Debian dobbiamo farlo qui:
# Поменяем пути к библиотекам
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+^set dir(lib)+set dir(lib) /usr/share/rac-gui/lib ;#+g", "racgui"]))
# Поменяем пути к файлам
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+[pwd]+/usr/share/rac-gui+g", "racgui"]))
# заархивируем исходники
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["tar", "czf", util.Interpolate("../rac-gui_%(prop:version)s.orig.tar.gz"), "."]))
# Соберём пакет
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["dpkg-buildpackage"]))
# Скопируем файл на мастер
rac_gui_build_DEB.addStep(
steps.FileUpload(
workersrc=util.Interpolate("../rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")
)
)
rac_gui_build_DEB.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")]
)
)E con DEB abbiamo finito, ora passiamo a Windows!
rac_gui_build_WIN = util.BuildFactory()
rac_gui_build_WIN.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)Poiché in Windows non ci sono grep e sed (o ci sono?), useremo PowerShell.
# Добавим определение версии из основного файла
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'version:') -split 's')[2]",
property="version"
)
)
# Добавим определение релиза из основного файла
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'release:') -split 's')[2]",
property="release"
)
)
# Создадим запускаемый файл
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:binfreewrap.exe", "rac_gui.tcl"]))
# запакуем то, что получилось
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:Program Files7-zip7z.exe", "a", "-r", util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"), "..build"]))
# скопируем на мастер
rac_gui_build_WIN.addStep(
steps.FileUpload(
workersrc=util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
masterdest=util.Interpolate("/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")
)
)
# Скопируем файл на хостинг
rac_gui_build_WIN.addStep(
steps.MasterShellCommand(
command=["/usr/local/bin/deploy-ftp.tcl",
util.Interpolate("--local-file=/home/buildbot/builds/rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
util.Interpolate("--remote-file=uploads/rac-gui/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")]
)
)
# Тут определяем какие сборщики у нас есть
c['builders'] = [
util.BuilderConfig(name="Rac-GUI-RPM-builder", workername='CentOS', factory=rac_gui_build_RPM),
util.BuilderConfig(name="Rac-GUI-DEB-builder", workername='Debian-10', factory=rac_gui_build_DEB),
util.BuilderConfig(name="Rac-GUI-WIN-builder", workername='Windows-10', factory=rac_gui_build_WIN),
]Per notificare lo stato del processo di costruzione utilizzeremo la posta elettronica.
c['services'] = []
template=u'''
<h4>Stato della build: {{ summary }}</h4>
<p> Operatore utilizzato: {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }}: {{ step['result'] }}</p>
{% endfor %}
<p><b> -- Il Buildbot</b></p>
'''
mailNotifier = reporters.MailNotifier(fromaddr="builder@domain.it",
sendToInterestedUsers=False,
mode=('all'),
extraRecipients=["admin@domain.it"],
relayhost="mail.domain.it",
smtpPort=587,
smtpUser="builder@domain.it",
smtpPassword="******",
messageFormatter=reporters.MessageFormatter(
template=template, template_type='html',
wantProperties=True, wantSteps=True))
c['services'].append(mailNotifier)
# Impostazioni principali del master
c['title'] = "Il processo di costruzione"
c['titleURL'] = "http://vm-srv-build1:80/"
c['buildbotURL'] = "http://vm-srv-build1/"
c['www'] = dict(port=80,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}))
c['db'] = {
'db_url' : "sqlite:///state.sqlite"
}Salviamo il file e possiamo provare a avviare il servizio master:
systemctl restart buildbot-masterNel log controlleremo che la configurazione è a posto e tutto funziona normalmente. Tutti i nostri worker dovrebbero ora connettersi, come sarà felicemente comunicato nel log »»’/home/buildbot/master/twistd.log»»’:
2019-07-24 16:50:35+0300 [-] Caricamento buildbot.tac...
2019-07-24 16:50:35+0300 [-] Caricato.
2019-07-24 16:50:35+0300 [-] twistd 19.2.1 (\/usr\/bin\/python3.6 3.6.8) avviato.
2019-07-24 16:50:35+0300 [-] classe del reattore: twisted.internet.epollreactor.EPollReactor.
2019-07-24 16:50:35+0300 [-] Avvio di BuildMaster -- buildbot.version: 2.3.1
2019-07-24 16:50:35+0300 [-] Caricamento della configurazione da '\/home\/buildbot\/master\/master.cfg'
2019-07-24 16:50:36+0300 [-] \/usr\/local\/lib\/python3.6\/site-packages\/buildbot\/config.py:90: buildbot.config.ConfigWarning: [0.9.0 e successivi] `buildbotNetUsageData` non è configurato e predefinito a base.
Questo parametro aiuta il team di sviluppo di buildbot a comprendere la base di installazione.
Nessuna informazione personale viene raccolta.
Solo l'informazione sulla versione del software di installazione e l'uso dei plugin viene inviata.
Puoi `opt-out` impostando questa variabile su None.
Oppure `opt-in` per ulteriori informazioni impostando su "full".
2019-07-24 16:50:36+0300 [-] Configurazione del database con URL 'sqlite:\/state.sqlite'
2019-07-24 16:50:36+0300 [-] impostazione della modalità diario del database su 'wal'
2019-07-24 16:50:36+0300 [-] aggiunta di 1 nuovo servizio, rimozione di 0
2019-07-24 16:50:36+0300 [-] aggiunta di 1 nuova sorgente di cambiamento, rimozione di 0
2019-07-24 16:50:36+0300 [-] gitpoller: utilizzo della directory di lavoro '\/home\/buildbot\/master\/gitpoller-work'
2019-07-24 16:50:36+0300 [-] aggiunta di 3 nuovi builder, rimozione di 0
2019-07-24 16:50:36+0300 [-] aggiunta di 1 nuovo scheduler, rimozione di 0
2019-07-24 16:50:36+0300 [-] inizializzazione del plugin www 'waterfall_view'
2019-07-24 16:50:36+0300 [-] inizializzazione del plugin www 'console_view'
2019-07-24 16:50:36+0300 [-] inizializzazione del plugin www 'grid_view'
2019-07-24 16:50:36+0300 [-] NOTA: il plugin www 'sitenav' è installato ma non configurato
2019-07-24 16:50:36+0300 [-] inizializzazione del plugin www 'waterfall_view'
2019-07-24 16:50:36+0300 [-] inizializzazione del plugin www 'console_view'
2019-07-24 16:50:36+0300 [-] inizializzazione del plugin www 'grid_view'
2019-07-24 16:50:36+0300 [-] NOTA: il plugin www 'sitenav' è installato ma non configurato
2019-07-24 16:50:36+0300 [-] BuildbotSite avviato sulla porta 80
2019-07-24 16:50:36+0300 [-] Avvio della fabbrica <buildbot.www.service.BuildbotSite oggetto a 0x7fe31c2657b8>
2019-07-24 16:50:36+0300 [-] aggiunta di 3 nuovi lavoratori, rimozione di 0
2019-07-24 16:50:36+0300 [-] PBServerFactory avviato sulla porta 4000
2019-07-24 16:50:36+0300 [-] Avvio della fabbrica <twisted.spread.pb.PBServerFactory oggetto a 0x7fe31c147470>
2019-07-24 16:50:37+0300 [-] BuildMaster in esecuzione
2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: invio {'installid': 'b6193b126b96689351d2fe95787c5a03fc0879f9', 'versions': {'Python': '3.6.8', 'Buildbot': '2.3.1', 'Twisted': '19.2.1'}, 'platform': {'platform': 'Linux-4.15.18-10- pve-x86_64-with-centos-7.6.1810-Core', 'system': 'Linux', 'machine': 'x86_64', 'processor': 'x86_64', 'python_implementation': 'CPython', 'version': '#1 SMP PVE 4.15.18-32', 'distro': 'centos:7'}, 'plugins': {'buildbot\/worker\/base\/Worker': 3, 'buildbot\/config\/BuilderConfig': 3, 'buildbot\/schedulers\/basic\/SingleBranchScheduler': 1, 'buildbot\/reporters\/mail\/MailNotifier': 1, 'buildbot\/changes\/gitpoller\/GitPoller': 1, 'buildbot\/steps\/worker\/MakeDirectory': 1, 'buildbot\/steps\/source\/git\/Git': 3, 'buildbot\/steps\/shell\/ShellCommand': 9, 'buildbot\/steps\/package\/rpm\/rpmbuild\/RpmBuild': 1}, 'db': 'sqlite', 'mq': 'simple', 'www_plugins': ['waterfall_view', 'console_view', 'grid_view']}
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] lavoratore 'CentOS' collegato da IPv4Address(type='TCP', host='127.0.0.1', port=37332)
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Ricevuta workerinfo da 'CentOS'
2019-07-24 16:50:37+0300 [-] bot collegato
2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Lavoratore CentOS collegato a Rac-GUI-RPM-builder
2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: buildbot.net ha detto: ok
2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] lavoratore 'Windows-10' collegato da IPv4Address(type='TCP', host='192.168.5.145', port=49831)
2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] Ricevuta workerinfo da 'Windows-10'
2019-07-24 16:50:40+0300 [-] bot collegato
2019-07-24 16:50:40+0300 [Broker,1,192.168.55.15] Lavoratore Windows-10 collegato a Rac-GUI-WIN-builder
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] lavoratore 'Debian-10' collegato da IPv4Address(type='TCP', host='192.168.5.9', port=44430)
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Ricevuta workerinfo da 'Debian-10'
2019-07-24 16:50:41+0300 [-] bot collegato
2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Lavoratore Debian-10 collegato a Rac-GUI-DEB-builderLa configurazione è stata completata. È possibile controllare lo stato attuale tramite l'interfaccia web, dove è anche possibile visualizzare gli errori di build, riavviare un processo bloccato se qualcosa va storto, ecc.
Subito dopo l'avvio dei nostri lavoratori, è possibile controllare tramite il menu «Builds» -> «Workers»

Dopo che il primo processo di build sarà stato eseguito (cioè dopo le modifiche nel repository Git), sulla prima pagina apparirà lo stato dei processi.

Se si fa clic sulla riga desiderata, si aprirà una pagina con lo stato attuale di quel processo, mostrando cosa sta succedendo, quali errori, ecc.

Puoi trovare la configurazione completa del maestro qui
import os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters
c= BuildmasterConfig ={}
c['workers'] = [ worker.Worker('CentOS', '123456'), worker.Worker('Debian-10', '123456'), worker.Worker('Windows-10', '123456')]
c['protocols'] = {'pb': {'port': 4000}}
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
project = 'Rac-GUI',
branches = True,
pollInterval = 600
))
# Servizio di avvio della compilazione
c['schedulers'] = []
c['schedulers'].append(schedulers.SingleBranchScheduler(
name="Rac-GUI-schedulers",
change_filter=util.ChangeFilter(branch='master'),
builderNames=["Rac-GUI-RPM-builder", "Rac-GUI-DEB-builder", "Rac-GUI-WIN-builder"],
properties = {'owner': 'admin'}
))
@util.renderer
def get_name_version_release(props):
prog_name = "rac-gui"
prog_version = "1.0.3"
prog_release = "3"
return {
"prog_name": prog_name
#"prog_version": prog_version,
#"prog_release": prog_release
}
rac_gui_build_RPM = util.BuildFactory()
rac_gui_build_RPM.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
workdir = 'rac-gui',
haltOnFailure = True,
submodules = True,
mode='full',
progress = True)
)
# Aggiungiamo la definizione della versione dal file principale
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep version ..\/rac-gui\/rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Aggiungiamo la definizione del rilascio dal file principale
rac_gui_build_RPM.addStep(
steps.SetPropertyFromCommand(
command="grep release ..\/rac-gui\/rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["tar", "czf", util.Interpolate("\/home\/buildbot\/rpmbuild\/SOURCES\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"), "..\/rac-gui"]))
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["cp", "..\/rac-gui\/rac_gui.spec", "\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec"]))
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s\/.*Version:.*\/Version:t%(prop:version)s\/"), "\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec"]))
rac_gui_build_RPM.addStep(steps.ShellCommand(
command=["sed", "-i", util.Interpolate("s\/.*Release:.*\/Release:t%(prop:release)s\/"), "\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec"]))
rac_gui_build_RPM.addStep(steps.RpmBuild(
specfile="\/home\/buildbot\/rpmbuild\/SPECS\/rac_gui.spec",
dist='.el5',
topdir='\/home\/buildbot\/rpmbuild',
builddir='\/home\/buildbot\/rpmbuild\/build',
rpmdir='\/home\/buildbot\/rpmbuild\/RPMS',
sourcedir='\/home\/buildbot\/rpmbuild\/SOURCES'
))
# Copiamo il file sul master
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("\/home\/buildbot\/rpmbuild\/RPMS\/noarch\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")
)
)
rac_gui_build_RPM.addStep(
steps.FileUpload(
workersrc=util.Interpolate("\/home\/buildbot\/rpmbuild\/SOURCES\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")
)
)
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui-%(prop:version)s-%(prop:release)s.noarch.rpm")]
)
)
rac_gui_build_RPM.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui-%(prop:version)s-%(prop:release)s.tar.gz")]
)
)
####################################
## DEB
####################################
rac_gui_build_DEB = util.BuildFactory()
rac_gui_build_DEB.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)
# Aggiungiamo la definizione della versione dal file principale
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep version rac_gui.tcl | grep -oE 'b[0-9]{1,2}.[0-9]{1,2}.[0-9]{1,2}b'", property="version"
)
)
# Aggiungiamo la definizione del rilascio dal file principale
rac_gui_build_DEB.addStep(
steps.SetPropertyFromCommand(
command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
)
)
# Rinominiamo il file eseguibile
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["mv", "rac_gui.tcl", "racgui"]))
# Modifichiamo i percorsi delle librerie
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+^set dir(lib)+set dir(lib) \/usr\/share\/rac-gui\/lib ;#+g", "racgui"]))
# Modifichiamo i percorsi dei file
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["sed", "-i", "s+[pwd]+\/usr\/share\/rac-gui+g", "racgui"]))
# Zip di origine
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["tar", "czf", util.Interpolate("..\/rac-gui_%(prop:version)s.orig.tar.gz"), "."]))
# Costruiamo il pacchetto
rac_gui_build_DEB.addStep(steps.ShellCommand(
command=["dpkg-buildpackage"]))
# Copiamo il file sul master
rac_gui_build_DEB.addStep(
steps.FileUpload(
workersrc=util.Interpolate("..\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")
)
)
rac_gui_build_DEB.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui_%(prop:version)s-%(prop:release)s_amd64.deb")]
)
)
############################################
# WIN
############################################
rac_gui_build_WIN = util.BuildFactory()
rac_gui_build_WIN.addStep(steps.Git(
repourl = 'https://bitbucket.org/svk28/rac-gui.git',
haltOnFailure = True,
submodules = True,
mode='full',
workdir='build',
progress = True)
)
# Aggiungiamo la definizione della versione dal file principale
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'version:') -split 's')[2]",
property="version"
)
)
# Aggiungiamo la definizione del rilascio dal file principale
rac_gui_build_WIN.addStep(
steps.SetPropertyFromCommand(
command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'release:') -split 's')[2]",
property="release"
)
)
# Creiamo il file eseguibile
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:binfreewrap.exe", "rac_gui.tcl"]))
# Zip di ciò che è stato prodotto
rac_gui_build_WIN.addStep(steps.ShellCommand(
command=["c:Program Files7-zip7z.exe", "a", "-r", util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"), "..build"]))
# Copiamo sul master
rac_gui_build_WIN.addStep(
steps.FileUpload(
workersrc=util.Interpolate("..rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
masterdest=util.Interpolate("\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")
)
)
# Copiamo il file sull'hosting
rac_gui_build_WIN.addStep(
steps.MasterShellCommand(
command=["\/usr\/local\/bin\/deploy-ftp.tcl",
util.Interpolate("--local-file=\/home\/buildbot\/builds\/rac-gui_%(prop:version)s-%(prop:release)s.win.zip"),
util.Interpolate("--remote-file=uploads\/rac-gui\/rac-gui_%(prop:version)s-%(prop:release)s.win.zip")]
)
)
c['builders'] = [
util.BuilderConfig(name="Rac-GUI-RPM-builder", workername='CentOS', factory=rac_gui_build_RPM),
util.BuilderConfig(name="Rac-GUI-DEB-builder", workername='Debian-10', factory=rac_gui_build_DEB),
util.BuilderConfig(name="Rac-GUI-WIN-builder", workername='Windows-10', factory=rac_gui_build_WIN),
]
c['services'] = []
template=u'''
<h4>Stato della build: {{ summary }}</h4>
<p> Operatore utilizzato: {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }}: {{ step['result'] }}</p>
{% endfor %}
<p><b> -- Il Buildbot</b></p>
'''
mailNotifier = reporters.MailNotifier(fromaddr="112@icvibor.ru",
sendToInterestedUsers=False,
mode=('all'),
extraRecipients=["my@domain.local"],
relayhost="mail.domain.local",
smtpPort=587,
smtpUser="buildbot@domain.local",
smtpPassword="**********",
messageFormatter=reporters.MessageFormatter(
template=template, template_type='html',
wantProperties=True, wantSteps=True))
c['services'].append(mailNotifier)
c['title'] = "Il processo di costruzione"
c['titleURL'] = "http://vm-srv-build1:80/"
c['buildbotURL'] = "http://vm-srv-build1/"
c['www'] = dict(port=80,
plugins=dict(waterfall_view={}, console_view={}, grid_view={}))
c['db'] = {
'db_url' : "sqlite://state.sqlite"
}Materiali
Nella preparazione dell'articolo sono stati utilizzati i seguenti materiali:
- E la documentazione sul prodotto
Fonte: habr.com
