Buildbot u primjerima

Trebalo mi je postaviti proces izgradnje i isporuke paketa s web stranice iz Git repozitorija. I nedavno sam na Habr-u vidio članak o buildbot-u (link na kraju) i odlučio ga isprobati za to.

Budući da je buildbot distribuirani sustav, logično je napraviti zasebni build host za svaku arhitekturu i operativni sustav. U našem slučaju to će biti LXC kontejneri (u slučaju Linuxa) i qemu (u slučaju Windowsa):

  • vm-srv-build1 — centos 7, ovdje će biti buildbot majstor (master) i jedan od radnika (worker)
  • vm-srv-build2 — debian 10, za izgradnju DEB paketa
  • vm-srv-build3 — windows 10, za izgradnju, sami razumijete, za što

Gradit ćemo Rac GUI — grafički sučelje za 1C rac za upravljanje klasterom poslužitelja. Za Linux će se koristiti standardni alati za svaku OS, a za izgradnju exe datoteka za Windows iz tcl skripte koristi se freewrap.

Instalacija

GNU/Linux

Informacija o instalaciji, dokumentacija na mreži je dovoljna 1,2. I ne izaziva posebne probleme:
Za majstora:

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

Za «radnike», dovoljno je ovo:

pip3 install buildbot-worker

Naravno, ispravnije bi bilo izgraditi pakete za svaki OS, ali to nije u okviru ovog članka. Također ćemo izostaviti opis postavljanja kontejnera za rad, napominjem samo da koristim ProxMox VE. I još će biti potrebno instalirati pakete potrebne za izgradnju za svaku OS (centos: rpmdevtools i sl; debian: build-essential, dh-make, pbuilder i sl.)

Izgradnja projekata i servisni buildbot bit će pokrenuti u ime neprivilegiranog korisnika, pa ga je potrebno kreirati na svim hostovima koji sudjeluju u procesu:


adduser buildbot

Dalje ćemo postaviti automatsko pokretanje servisa, prema tome na svakom od hostova (kontejnera):

Systemd jedinica za pokretanje majstora:

touch /etc/systemd/buildbot-master.service 

[Unit]
Description=BuildBot master service
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

i «radnog»

touch /etc/systemd/buildbot-worker.service 

[Unit]
Description=BuildBot worker service
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

Budući da svi skripti (u našem slučaju) leže u /usr/local/, potrebno je navesti put do njih u varijablama okruženja:

nano /root/.bash_profile

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

Nakon toga, moguće je stvoriti infrastrukturu direktorija za 'radnike' (na svim hostovima), za to se registrira pod korisnikom buildbot i izvršavaju sljedeće naredbe:

Na prvom hostu 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

Na drugom hostu 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

Na radnim hostovima službu buildbot-worker možete pokrenuti

systemctl start buildbot-worker

MS Windows

Kao 'radnik' za gradnju za Windows, koristit će se virtualna mašina s najnovijom verzijom Win10.
Za rad će biti potrebno:

Nakon što se sve navedeno instalira, možete instalirati i sam buildbot:

pip install buildbot-worker

Stvorimo radni direktorij

md c:worker

I pokrenimo

buildbot-worker start c:worker

Ako sve radi (vidi log c:workertwistd.log), tada našeg 'radnika' možemo registrirati kao uslugu, dodajući u registar stavku s radnim direktorijem (naredbe se izvršavaju u powershellu pokrenutom s administratorskim pravima):

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

I možemo pokrenuti uslugu

Start-Service buildbot

To je sve o 'radnicima', dalje ih ne treba dirati, sve upravljanje ide s majstora.

Postavljanje majstora

Za početak, stvorimo infrastrukturu za majstora (na glavnom hostu), za to se registrira pod korisnikom buildbot i izvršavaju sljedeće naredbe:

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

Za gotove pakete stvorit ćemo direktorij builds

mkdir /home/buildbot/builds

U direktoriju /home/buildbot/master/ je stvoren datoteku master.cfg. Ova datoteka predstavlja kod na Pythonu i sadrži opis svih mehanizama rada sustava, s njom ćemo raditi u nastavku.

nano /home/buildbot/master/master.cfg

import os, re
from buildbot.plugins import steps, util, schedulers, worker, changes, reporters

c= BuildmasterConfig ={}

# Opis naših radnika.
c['workers'] = [ worker.Worker('CentOS', '123456'), worker.Worker('Debian-10', '123456'), worker.Worker('Windows-10', '123456')]
c['protocols'] = {'pb': {'port': 4000}} 

# Naredba masteru koji repozitorij pratiti
c['change_source'] = []
c['change_source'].append(changes.GitPoller(
       repourl = 'https://bitbucket.org/svk28/rac-gui.git',
       project = 'Rac-GUI',
       branches = True,
       pollInterval = 60
      )
)

# Usluga pokretanja izgradnje
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
# Izgradnja RPM paketa
 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)
)

Za automatizaciju izgradnje paketa različitih verzija, kako ne bismo morali zadirati u kod datoteke master.cfg, u glavnom skriptu programa rac_gui.tcl dodane su linije s trenutnom verzijom i izdanjem:

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

I na temelju ovih linija buildbot će brojati pakete. Za povlačenje podataka koristi se poziv konzolnog grep-a. U buildbot-u nije moguće jednostavno definirati varijable za "radnike" (barem ja nisam našao kako). Za to služe svojstva (property). Tj. u proces izgradnje dodajemo korake za određivanje verzije i izdanja i sukladno tome, postavljamo svojstva version i release. Svojstva se mogu postavljati na razne načine, u ovom slučaju to je poziv konzolne naredbe:

# Добавим определение версии из основного файла
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"
       )
)

Dobivene vrijednosti možemo umetnuti putem poziva 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"]
       )
)

Ovdje treba napomenuti da, s obzirom na to da se host koristi i za ručnu izgradnju paketa, izgradnja će prolaziti putem standardnih putanja.

# Копируем spec
rac_gui_build_RPM.addStep(steps.ShellCommand(
       command=["cp", "../rac-gui/rac_gui.spec", "/home/buildbot/rpmbuild/SPECS/rac_gui.spec"]))

Za postavljanje ispravnih brojeva izdanja i verzije koristi se poziv standardnog sed, tj. naredba zamjenjuje vrijednosti unutar spec datoteke na potrebne

# меняем версию
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'
      )
)

Gotov sastavljeni paket i arhiva s izvorima kopiraju se na master. No moguće je i odmah s radnog računala kopirati u vlastiti repozitorij ili na web stranicu.

# Скопируем файл на мастер
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")
       )
)

Pokrenut ćemo na masteru proces kopiranja sastavljenih paketa na hosting putem FTP-a. Za to se koristi skriptu na 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")]
        )
)

Završili smo s RPM-om. Sada ćemo opisati algoritam za izradu DEB paketa. Budući da su procesi izrade paketa za različite sustave neovisni jedni o drugima, mnogi koraci će se ponavljati.


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

# Dodajmo definiciju verzije iz glavne datoteke
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"
       )
)

# Dodajmo definiciju izdanja iz glavne datoteke
rac_gui_build_DEB.addStep(
       steps.SetPropertyFromCommand(
       command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
       )
)

# Preimenujmo pokretnu datoteku
    rac_gui_build_DEB.addStep(steps.ShellCommand(
       command=["mv", "rac_gui.tcl", "racgui"]))

Za RPM paket dio sljedećih procedura obavlja rpm tijekom izrade i opisane su unutar speca, za debian to se mora raditi ovdje:

# Поменяем пути к библиотекам
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")]
        )
)

I s DEB-om je gotovo, sada 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)
)

Budući da Windows obično nema grep i sed (ili ipak ima?), koristit ćemo 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),
]

Za obavještavanje o stanju procesa izrade koristit ćemo elektronsku poštu.


c['services'] = []

template=u'''
    <h4>Status izgradnje: {{ summary }}</h4>
    <p> Korišten radnik: {{ workername }}</p>
    {% for step in build['steps'] %}
    <p> {{ step['name'] }}: {{ step['result'] }}</p>
    {% endfor %}
    <p><b> -- Buildbot</b></p>
    '''

mailNotifier = reporters.MailNotifier(fromaddr="builder@domain.hr",
             sendToInterestedUsers=False,
             mode=('all'),
             extraRecipients=["admin@domain.hr"],
             relayhost="mail.domain.hr",
             smtpPort=587,
             smtpUser="builder@domain.hr",
             smtpPassword="******",
             messageFormatter=reporters.MessageFormatter(
                                 template=template, template_type='html',
                                 wantProperties=True, wantSteps=True))

c['services'].append(mailNotifier)

# Glavne postavke majstora
c['title'] = "Proces izgradnje"
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"
}

Spremite datoteku i možete pokušati pokrenuti uslugu majstora:

systemctl restart buildbot-master

U logu ćemo provjeriti je li s konfiguracijom sve u redu i da sve radi normalno. Svi naši radnici sada bi se trebali povezati, što će biti radosno objavljeno u logu »»’/home/buildbot/master/twistd.log»»’:

 2019-07-24 16:50:35+0300 [-] Učitavanje buildbot.tac...
 2019-07-24 16:50:35+0300 [-] Učitano.
 2019-07-24 16:50:35+0300 [-] twistd 19.2.1 (/usr/bin/python3.6 3.6.8) se pokreće.
 2019-07-24 16:50:35+0300 [-] Klasa reaktora: twisted.internet.epollreactor.EPollReactor.
 2019-07-24 16:50:35+0300 [-] Pokreće se BuildMaster -- buildbot.version: 2.3.1
 2019-07-24 16:50:35+0300 [-] Učitavanje konfiguracije iz '/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 i noviji] `buildbotNetUsageData` nije podešen i zadano je na osnovno.
 Oparametar pomaže razvojnom timu buildbota da shvati bazu instalacija.
 Nema ličnih informacija se prikuplja.
 Samo informacije o verziji softvera instalacije i korištenju dodataka se šalju.
 Možete se `odjaviti` postavljanjem ove varijable na None.
 Ili se `prijaviti` za više informacija postavljanjem na "full".

 2019-07-24 16:50:36+0300 [-] Postavljanje baze podataka s URL-om 'sqlite:/state.sqlite'
 2019-07-24 16:50:36+0300 [-] postavljanje načina vođenja dnevnika baze podataka na 'wal'
 2019-07-24 16:50:36+0300 [-] dodano 1 nova usluga, uklanjanje 0
 2019-07-24 16:50:36+0300 [-] dodano 1 nova change_sources, uklanjanje 0
 2019-07-24 16:50:36+0300 [-] gitpoller: koristi radni direktorij '/home/buildbot/master/gitpoller-work'
 2019-07-24 16:50:36+0300 [-] dodano 3 nova graditelja, uklanjanje 0
 2019-07-24 16:50:36+0300 [-] dodano 1 novi raspored, uklanjanje 0
 2019-07-24 16:50:36+0300 [-] inicijalizacija www dodatka 'waterfall_view'
 2019-07-24 16:50:36+0300 [-] inicijalizacija www dodatka 'console_view'
 2019-07-24 16:50:36+0300 [-] inicijalizacija www dodatka 'grid_view'
 2019-07-24 16:50:36+0300 [-] NAPOMENA: www dodatak 'sitenav' je instaliran, ali nije konfigurisan
 2019-07-24 16:50:36+0300 [-] inicijalizacija www dodatka 'waterfall_view'
 2019-07-24 16:50:36+0300 [-] inicijalizacija www dodatka 'console_view'
 2019-07-24 16:50:36+0300 [-] inicijalizacija www dodatka 'grid_view'
 2019-07-24 16:50:36+0300 [-] NAPOMENA: www dodatak 'sitenav' je instaliran, ali nije konfigurisan
 2019-07-24 16:50:36+0300 [-] BuildbotSite se pokreće na 80
 2019-07-24 16:50:36+0300 [-] Pokreće se tvornica 
 2019-07-24 16:50:36+0300 [-] dodato 3 nova radnika, uklanjanje 0
 2019-07-24 16:50:36+0300 [-] PBServerFactory se pokreće na 4000
 2019-07-24 16:50:36+0300 [-] Pokreće se tvornica 
 2019-07-24 16:50:37+0300 [-] BuildMaster radi
 2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: slanje {'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] radnik 'CentOS' se pridružuje sa IPv4Address(type='TCP', host='127.0.0.1', port=37332)
 2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Dobio informacije o radniku od 'CentOS'
 2019-07-24 16:50:37+0300 [-] bot se pridružio
 2019-07-24 16:50:37+0300 [Broker,0,127.0.0.1] Radnik CentOS se pridružio Rac-GUI-RPM-builder
 2019-07-24 16:50:37+0300 [-] buildbotNetUsageData: buildbot.net je rekao: ok
 2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] radnik 'Windows-10' se pridružuje sa IPv4Address(type='TCP', host='192.168.5.145', port=49831)
 2019-07-24 16:50:39+0300 [Broker,1,192.168.55.15] Dobio informacije o radniku od 'Windows-10'
 2019-07-24 16:50:40+0300 [-] bot se pridružio
 2019-07-24 16:50:40+0300 [Broker,1,192.168.55.15] Radnik Windows-10 se pridružio Rac-GUI-WIN-builder
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] radnik 'Debian-10' se pridružuje sa IPv4Address(type='TCP', host='192.168.5.9', port=44430)
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Dobio informacije o radniku od 'Debian-10'
 2019-07-24 16:50:41+0300 [-] bot se pridružio
 2019-07-24 16:50:41+0300 [Broker,2,192.168.55.99] Radnik Debian-10 se pridružio Rac-GUI-DEB-builder

Ovim je proces postavljanja završen. Trenutno stanje možete pregledati putem web sučelja. Tamo možete vidjeti i greške u gradnji, pokrenuti zamrznuti proces ako nešto nije u redu, itd.

Odmah nakon pokretanja naših radnih konja, stanje možete provjeriti putem izbornika „Builds” -> „Workers”

Buildbot u primjerima

Nakon što se izvrši prvi proces gradnje (tj. promjene u Git repozitoriju), na prvoj stranici će se pojaviti stanje procesa.

Buildbot u primjerima

Ako kliknete na odgovarajući redak, otvorit će se stranica s trenutnim stanjem tog procesa, gdje možete vidjeti što se događa, koje greške itd.

Buildbot u primjerima

Cjelokupnu konfiguraciju majstora možete preuzeti ovdje

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

# servir za pokretanje izgradnje
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)
    )

# Dodajmo definiciju verzije iz glavne datoteke
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"
    )
)

# Dodajmo definiciju izdanja iz glavne datoteke
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'
    ))

# Kopirajmo datoteku na glavni
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)
    )

# Dodajmo definiciju verzije iz glavne datoteke
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"
    )
)

# Dodajmo definiciju izdanja iz glavne datoteke
rac_gui_build_DEB.addStep(
    steps.SetPropertyFromCommand(
    command="grep release rac_gui.tcl | grep -oE 'b[0-9]{1,3}b'", property="release"
    )
)

# Preimenujmo izvršnu datoteku
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["mv", "rac_gui.tcl", "racgui"]))

# Zamenimo putanje do biblioteka
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["sed", "-i", "s+^set dir(lib)+set dir(lib) \/usr\/share\/rac-gui\/lib ;#+g", "racgui"]))

# Zamenimo putanje do datoteka
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["sed", "-i", "s+[pwd]+\/usr\/share\/rac-gui+g", "racgui"]))

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

# Izgradimo paket
rac_gui_build_DEB.addStep(steps.ShellCommand(
    command=["dpkg-buildpackage"]))

# Kopiramo datoteku na glavni
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)
    )

# Dodajmo definiciju verzije iz glavne datoteke
rac_gui_build_WIN.addStep(
    steps.SetPropertyFromCommand(
    command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'version:') -split 's')[2]",
    property="version"
    )
)

# Dodajmo definiciju izdanja iz glavne datoteke
rac_gui_build_WIN.addStep(
    steps.SetPropertyFromCommand(
    command="powershell -command "((Get-Content .rac_gui.tcl | Select-String -Pattern 'release:') -split 's')[2]",
    property="release"
    )
)

# Kreiramo izvršnu datoteku
rac_gui_build_WIN.addStep(steps.ShellCommand(
    command=["c:binfreewrap.exe", "rac_gui.tcl"]))

# zapakujte ono što ste dobili
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"]))

# kopiramo na glavni
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")
    )
)

# Kopiramo datoteku na 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>Status izgradnje: {{ summary }}</h4>
<p> Korišten radnik: {{ workername }}</p>
{% for step in build['steps'] %}
<p> {{ step['name'] }}: {{ step['result'] }}</p>
{% endfor %}
<p><b> -- 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'] = "Proces izgradnje"
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"
}

Materijali

U pripremi ovog članka korišteni su sljedeći materijali:

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster