Esempi di Buildbot

Ho dovuto configurare il processo di build e consegna di pacchetti software dal repository Git al sito. E vedendo, non molto tempo fa, un articolo su Habr riguardante buildbot (link alla fine), ho deciso di provarlo e applicarlo.

Poiché buildbot è un sistema distribuito, sarà logico creare un host di build separato per ogni architettura e sistema operativo. Nel nostro caso, si tratterà di contenitori LXC (per Linux) e qemu (per 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 di pacchetti DEB
  • vm-srv-build3 — windows 10, per la costruzione, sapete già per cosa

Costruiremo Rac GUI — interfaccia grafica per 1C rac per gestire un cluster di server. Per Linux verranno utilizzati gli strumenti predefiniti per ogni OS, mentre per costruire un file exe per Windows da uno script tcl si utilizza freewrap.

Installazione

GNU/Linux

Per l'installazione, ci sono molte documentazioni online. 1,2E non causa problemi particolari:
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-dateutil

Per i "worker", è sufficiente questo:

pip3 install buildbot-worker

Certamente, sarebbe più corretto compilare i pacchetti per ciascun sistema operativo, ma questo esula dallo scopo dell'articolo. Inoltre, salteremo la descrizione della configurazione dei container per il funzionamento, segnalo solo che utilizzo ProxMox VE. È inoltre necessario installare i pacchetti richiesti per la compilazione per ciascuna distribuzione (centos: rpmdevtools, ecc.; debian: build-essential, dh-make, pbuilder, ecc.)

La compilazione dei progetti e i servizi buildbot verranno eseguiti con un utente non privilegiato, quindi è necessario crearlo su tutti gli host coinvolti nel processo:


adduser buildbot

Successivamente, configureremo l'avvio automatico dei servizi, rispettivamente su ciascuno degli host (container):

Unità Systemd per avviare il master:

touch /etc/systemd/buildbot-master.service 

[Unit]
Description=Servizio master 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.target

e «worker»

touch /etc/systemd/buildbot-worker.service 

[Unit]
Description=Servizio worker BuildBot
After=network.target

[Service]
User=buildbot
Group=buildbot
WorkingDirectory=/home/buildbot/worker
ExecStart=/usr/local/bin/buildbot-worker start --nodaemon

[Install]
WantedBy=buildbot-master.service

Poiché tutti gli script (nel nostro caso) si trovano in /usr/local/, è necessario specificare il percorso per loro nelle variabili d'ambiente:

nano /root/.bash_profile

PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/bin

Dopo ciò, puoi creare la struttura delle directory per i "lavoratori" (su tutti gli host), registrandoti come utente buildbot ed eseguendo i seguenti comandi:

Sull'host principale vm-srv-build1:

su - buildbot
mkdir /home/buildbot/worker
cd ~
buildbot-worker create-worker --umask=0o22 --keepalive=60 worker vm-srv-build1:4000 CentOS 123456

Sull'host secondario 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 123456

Sugli host lavoratori, il servizio buildbot-worker può essere avviato

systemctl start buildbot-worker

MS Windows

Come "lavoratore" per la compilazione su Windows, verrà utilizzata una macchina virtuale con l'ultima versione di Win10.
Per operare, avrai bisogno di:

Dopo che tutto il sopra elencato è stato installato, puoi installare anche il buildbot:

pip install buildbot-worker

Creiamo la directory di lavoro

md c:worker

E avviamo

buildbot-worker start c:worker

Se tutto funziona (vedi log c:workertwistd.log), puoi registrare il tuo "lavoratore" come servizio, aggiungendo una voce nel registro con la directory di lavoro (i comandi devono essere eseguiti in powershell aperto 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 buildbot

Con i "lavoratori" è tutto, da qui in poi possono rimanere inalterati, tutto il controllo avviene dal master.

Configurazione del master

Per prima cosa, creiamo l'infrastruttura per il master (sull'host principale), per farlo ci registriamo come utente buildbot e eseguiamo i seguenti comandi:

su - buildbot
mkdir /home/buildbot/master
cd ~
buildbot create-master master

Per i pacchetti pronti, creiamo una cartella builds

mkdir /home/buildbot/builds

Nella cartella /home/buildbot/master/ è stato creato il file master.cfg. Questo file è un codice Python e contiene la descrizione di tutti i meccanismi di funzionamento del sistema, e lavoreremo con esso in seguito.

nano /home/buildbot/master/master.cfg

import 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}} 

# Indica al master 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
# Build 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, nel principale script del programma rac_gui.tcl sono state aggiunte righe con la versione corrente e il rilascio:

######################################################
#        Rac GUI
...
# version: 1.0.3
# release: 1

E sulla base di queste righe, buildbot numererà i pacchetti. Per estrarre i dati, si utilizza la chiamata console grep. In buildbot non è possibile definire variabili per i "lavoratori" così facilmente (almeno, non ho trovato come). A questo scopo servono le proprietà. Cioè, nel processo di build, aggiungiamo passaggi per definire la versione e il rilascio e quindi impostiamo le proprietà version e release. Le proprietà possono essere impostate in vari modi, in questo caso si tratta di una chiamata a un comando della 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 tramite la chiamata 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"]
       )
)

È importante notare che, poiché l'host viene utilizzato anche per la build manuale dei pacchetti, la compilazione seguirà 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 la chiamata 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 assemblato completo e l'archivio con i sorgenti vengono copiati sul master. Ma è possibile anche copiare direttamente i 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")
       )
)

Avviamo sul master il processo di copia dei pacchetti assemblati sul hosting via FTP. A questo scopo si utilizza script su 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 concluso con RPM. Ora passiamo alla descrizione dell'algoritmo per la creazione del pacchetto DEB. Poiché i processi di creazione dei pacchetti per sistemi diversi sono indipendenti tra loro, 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 seguenti procedure è gestita da rpm durante la compilazione e sono descritte all'interno dello spec, per Debian è necessario 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 il DEB è tutto, ora tocca 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?), utilizzeremo 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 compilazione utilizzeremo la posta elettronica.


c['services'] = []

template=u'''
    <h4>Stato della costruzione: {{ summary }}</h4>
    <p> Lavoratore 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 lanciare il servizio master:

systemctl restart buildbot-master

Nel log verificheremo che la configurazione sia a posto e tutto funzioni regolarmente. Tutti i nostri lavoratori devono ora connettersi, e nel log »»’/home/buildbot/master/twistd.log»»’ sarà comunicato con gioia:

 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 reactor: twisted.internet.epollreactor.EPollReactor.
 2019-07-24 16:50:35+0300 [-] Avvio 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.
 Non vengono raccolte informazioni personali.
 Vengono inviati solo informazioni sulla versione del software di installazione e sull'uso dei plugin.
 Puoi `disattivarti` impostando questa variabile su None.
 Oppure `attivarti` per ulteriori informazioni impostandola 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 0
 2019-07-24 16:50:36+0300 [-] aggiunta di 1 nuova sorgente di cambiamenti, rimozione 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 0
 2019-07-24 16:50:36+0300 [-] aggiunta di 1 nuovo scheduler, rimozione 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 factory <buildbot.www.service.BuildbotSite object at 0x7fe31c2657b8>
 2019-07-24 16:50:36+0300 [-] aggiunta di 3 nuovi lavoratori, rimozione 0
 2019-07-24 16:50:36+0300 [-] PBServerFactory avviata sulla porta 4000
 2019-07-24 16:50:36+0300 [-] Avvio della factory <twisted.spread.pb.PBServerFactory object at 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' attaching da IPv4Address(type='TCP', host='127.0.0.1', port=37332)
 2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Ricevuto workerinfo da 'CentOS'
 2019-07-24 16:50:37+0300 [-] bot attached
 2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Lavoratore CentOS attaccato 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' attaching da IPv4Address(type='TCP', host='192.168.5.145', port=49831)
 2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] Ricevuto workerinfo da 'Windows-10'
 2019-07-24 16:50:40+0300 [-] bot attached
 2019-07-24 16:50:40+0300 [Broker,1,192.168.55.15] Lavoratore Windows-10 attaccato a Rac-GUI-WIN-builder
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] lavoratore 'Debian-10' attaching da IPv4Address(type='TCP', host='192.168.5.9', port=44430)
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Ricevuto workerinfo da 'Debian-10'
 2019-07-24 16:50:41+0300 [-] bot attached
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Lavoratore Debian-10 attaccato a Rac-GUI-DEB-builder

La configurazione è stata completata. È possibile visualizzare lo stato attuale tramite la web interface, dove è possibile anche controllare gli errori di compilazione, interrompere processi bloccati, e così via.

Subito dopo l'avvio dei nostri lavoratori, puoi controllare attraverso il menu 'Builds' -> 'Workers'.

Esempi di Buildbot

Dopo il primo processo di compilazione (cioè, modifiche nel repository Git), apparirà lo stato dei processi nella prima pagina.

Esempi di Buildbot

Cliccando sulla riga desiderata si aprirà una pagina con lo stato attuale di questo processo, dove si può vedere cosa sta succedendo, gli errori, ecc.

Esempi di Buildbot

Puoi trovare l'intera configurazione del master 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 costruzione
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)
    )

# Aggiungeremo 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"
    )
)

# Aggiungeremo 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)
    )

# Aggiungeremo 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"
    )
)

# Aggiungeremo 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"
    )
)

# Rinomineremo il file eseguibile
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["mv", "rac_gui.tcl", "racgui"]))

# Cambieremo 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"]))

# Cambieremo i percorsi dei file
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["sed", "-i", "s+[pwd]+/usr/share/rac-gui+g", "racgui"]))

# Archivieremo i sorgenti
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["tar", "czf", util.Interpolate("../rac-gui_%(prop:version)s.orig.tar.gz"), "."]))

# Prepariamo 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)
    )

# Aggiungeremo 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"
    )
)

# Aggiungeremo 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"
    )
)

# Creeremo il file eseguibile
rac_gui_build_WIN.addStep(steps.ShellCommand(
    command=["c:binfreewrap.exe", "rac_gui.tcl"]))

# Compattiamo il risultato
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 sul 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 costruzione: {{ summary }}</h4>
<p> Lavoratore 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

Per la preparazione dell'articolo sono stati utilizzati i seguenti materiali:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster