Buildbot negli esempi

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 Rac GUI — 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 freewrap.

Installazione

GNU/Linux

Ci sono molte informazioni su installazione e documentazione in rete. 1,2E 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-dateutil

Per i "worker", questo è sufficiente:

pip3 install buildbot-worker

Naturalmente, 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 buildbot

Poi 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.target

e 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.service

Poiché 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/bin

Dopo 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 123456

Sul 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 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 il lavoro sono necessari:

Dopo che quanto sopra è stato installato, è possibile installare anche buildbot:

pip install buildbot-worker

Creeremo una directory di lavoro

md c:worker

E avviamolo

buildbot-worker start c:worker

Se 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 buildbot

Con 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 master

Per i pacchetti pronti, creiamo una directory builds

mkdir /home/buildbot/builds

Nella 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.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}} 

# 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: 1

E 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 script 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-master

Nel 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-builder

La 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»

Buildbot negli esempi

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.

Buildbot negli esempi

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.

Buildbot negli esempi

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:

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