worker and master splited #8
120
lib/worker_multibuild.py
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
from os import listdir, walk
|
||||||
|
from os.path import exists, isfile, join
|
||||||
|
import requests
|
||||||
|
import re
|
||||||
|
|
||||||
PeterSurda marked this conversation as resolved
Outdated
|
|||||||
|
|
||||||
|
request_data = {
|
||||||
|
"project": "testproject",
|
||||||
|
"comments": "testcomment",
|
||||||
|
}
|
||||||
|
request_headers = {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"Accept": "text/plain",
|
||||||
|
}
|
||||||
|
|
||||||
|
ty = "/change_hook/base"
|
||||||
|
path =".buildbot"
|
||||||
|
dockerfile_extra_contents = {}
|
||||||
|
dockerfile_extra_contents['focal'] = """
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
make this into a dict make this into a dict
|
|||||||
|
|
||||||
|
# Buildbot
|
||||||
|
RUN apt-get install -yq --no-install-suggests --no-install-recommends \
|
||||||
|
buildbot-worker git subversion python3-dev libffi-dev python3-setuptools \
|
||||||
|
python3-pip dumb-init curl openssh-client wget
|
||||||
|
|
||||||
|
# buildbot entrypoint
|
||||||
|
RUN wget -O /usr/local/bin/buildbot_entrypoint.sh https://git.bitmessage.org/Bitmessage/buildbot-scripts/raw/branch/master/docker/bionic/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/buildbot_entrypoint.sh
|
||||||
|
|
||||||
|
RUN echo 'buildbot ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||||
|
|
||||||
|
USER buildbot
|
||||||
|
|
||||||
|
ENTRYPOINT /usr/local/bin/buildbot_entrypoint.sh "$BUILDMASTER" "$WORKERNAME" "$WORKERPASS"
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
dockerfile_extra_contents['bionic'] = """
|
||||||
|
|
||||||
|
# Buildbot
|
||||||
|
RUN apt-get install -yq --no-install-suggests --no-install-recommends \
|
||||||
|
buildbot-slave git subversion python3-dev libffi-dev python3-setuptools \
|
||||||
|
python3-pip dumb-init curl openssh-client wget
|
||||||
|
|
||||||
|
# buildbot entrypoint
|
||||||
|
RUN wget -O /usr/local/bin/buildbot_entrypoint.sh https://git.bitmessage.org/Bitmessage/buildbot-scripts/raw/branch/master/docker/bionic/entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/buildbot_entrypoint.sh
|
||||||
|
|
||||||
|
RUN echo 'buildbot ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||||
|
|
||||||
|
USER buildbot
|
||||||
|
|
||||||
|
ENTRYPOINT /usr/local/bin/buildbot_entrypoint.sh "$BUILDMASTER" "$WORKERNAME" "$WORKERPASS"
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def list_jobs(directory=".buildbot"):
|
||||||
|
"""
|
||||||
|
list jobs found in a directory
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
for _ in next(walk(directory))[1]:
|
||||||
|
if exists(join(directory, _, "Dockerfile")) and (
|
||||||
|
exists(join(directory, _, "build.sh"))
|
||||||
|
or exists(join(directory, _, "test.sh"))
|
||||||
|
):
|
||||||
|
results.append(_)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def _get_dockerfile_contents(jobname, os_codename='bionic'):
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
no no `props`
|
|||||||
|
"""
|
||||||
|
Read contents of a Dockerfile and add extra contents for the given os_codename
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
can't access can't access `props`, instead the `jobname` variable needs to be passed from master
cis-muzahid
commented
Also passed os_codename instead of Also passed os_codename instead of `util.Interpolate("%(prop:os_codename)s")`
|
|||||||
|
"""
|
||||||
|
res = ""
|
||||||
|
with open(join(path + jobname), "r") as file:
|
||||||
|
contents = file.read()
|
||||||
|
# accept any line containing FROM and RUN keywords
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
the check should be reversed. Instead of removing lines containing FROM or RUN, it should remove the other lines. the check should be reversed. Instead of removing lines containing FROM or RUN, it should remove the other lines.
|
|||||||
|
res = ""
|
||||||
|
inside_allowed_command = False
|
||||||
|
for line in contents:
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
```
inside_allowed_command = False
for line in contents:
# maybe add newlines when appending line
if re.match(r"(?m)^(FROM|RUN).*$", line):
inside_allowed_command = True
if inside_allowed_command:
ret += line
if not re.match(r"\\\w*$", line):
inside_allowed_command = False
```
|
|||||||
|
if re.match(r"(?m)^(FROM|RUN).*$", line):
|
||||||
|
inside_allowed_command = True
|
||||||
|
if inside_allowed_command:
|
||||||
|
res += line
|
||||||
|
l = line.strip()
|
||||||
|
if not l.endswith("\\"):
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
- `\n` probably not needed due to `strip`
- remove `continue` and revert conditional
|
|||||||
|
inside_allowed_command = False
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
this can't be on a worker, because of the decorator this can't be on a worker, because of the decorator
however, it needs to worker differently. It needs to return `getProperty('dockerfile')` or soemthing like that.
|
|||||||
|
|
||||||
|
return res + dockerfile_extra_contents[os_codename]
|
||||||
|
|
||||||
|
|
||||||
|
def trigger_child_hooks(buildbotUrl: str, os_codename: str, repository, branch, jobname, directory=".buildbot", is_build_script_available, is_test_script_available):
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
- buildbotUrl: not sure, perhaps needs to be passed from master
- os_codename: probably there is a python library that does this
- repository, branch, jobname: master needs to pass this data to worker
- direcotry: can remain as it is as it's only for testing, we don't really need this
|
|||||||
|
request_url = buildbotUrl + ty
|
||||||
|
|
||||||
|
# List all jobs in the directory
|
||||||
|
jobs = list_jobs(directory)
|
||||||
|
|
||||||
|
# Check if build.sh or test.sh exists in each of the jobs
|
||||||
|
for job in jobs:
|
||||||
|
build_script_exists = False
|
||||||
|
test_script_exists = False
|
||||||
|
if exists(join(directory, job, "build.sh")):
|
||||||
|
build_script_exists = True
|
||||||
|
if exists(join(directory, job, "test.sh")):
|
||||||
|
test_script_exists = True
|
||||||
|
|
||||||
|
# make a post request
|
||||||
|
request_data["properties"] = {
|
||||||
|
"dockerfile": _get_dockerfile_contents(
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
`"dockerfile": _get_dockerfile_contents(`
|
|||||||
|
join(directory, job, "Dockerfile"), os_codename
|
||||||
|
),
|
||||||
|
"build_script_available": is_build_script_available(build_script_exists),
|
||||||
|
"test_script_available": is_test_script_available(test_script_exists),
|
||||||
|
"repository": repository,
|
||||||
|
"branch": branch,
|
||||||
|
"jobname": jobname,
|
||||||
|
}
|
||||||
|
requests.post(request_url, headers=request_headers, data=request_data)
|
145
multibuild.py
|
@ -10,7 +10,7 @@ Requires docker
|
||||||
# TODO: write hook job, maybe also a dockerfile?
|
# TODO: write hook job, maybe also a dockerfile?
|
||||||
# TODO: what to do about non-docker jobs
|
# TODO: what to do about non-docker jobs
|
||||||
|
|
||||||
from os import listdir, walk
|
from os import listdir, walk, getenv
|
||||||
from os.path import exists, isfile, join
|
from os.path import exists, isfile, join
|
||||||
import requests
|
import requests
|
||||||
import re
|
import re
|
||||||
|
@ -18,70 +18,6 @@ from buildbot.plugins import steps, util
|
||||||
|
|
||||||
from .lib.renderers import *
|
from .lib.renderers import *
|
||||||
|
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
also only worker also only worker
|
|||||||
ty = "/change_hook/base"
|
|
||||||
request_headers = {
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
"Accept": "text/plain",
|
|
||||||
}
|
|
||||||
request_data = {
|
|
||||||
"project": "testproject",
|
|
||||||
"comments": "testcomment",
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerfile_extra_contents_focal = """
|
|
||||||
|
|
||||||
# Buildbot
|
|
||||||
RUN apt-get install -yq --no-install-suggests --no-install-recommends \
|
|
||||||
buildbot-worker git subversion python3-dev libffi-dev python3-setuptools \
|
|
||||||
python3-pip dumb-init curl openssh-client wget
|
|
||||||
|
|
||||||
# buildbot entrypoint
|
|
||||||
RUN wget -O /usr/local/bin/buildbot_entrypoint.sh https://git.bitmessage.org/Bitmessage/buildbot-scripts/raw/branch/master/docker/bionic/entrypoint.sh
|
|
||||||
RUN chmod +x /usr/local/bin/buildbot_entrypoint.sh
|
|
||||||
|
|
||||||
RUN echo 'buildbot ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
|
||||||
|
|
||||||
USER buildbot
|
|
||||||
|
|
||||||
ENTRYPOINT /usr/local/bin/buildbot_entrypoint.sh "$BUILDMASTER" "$WORKERNAME" "$WORKERPASS"
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
dockerfile_extra_contents_bionic = """
|
|
||||||
|
|
||||||
# Buildbot
|
|
||||||
RUN apt-get install -yq --no-install-suggests --no-install-recommends \
|
|
||||||
buildbot-slave git subversion python3-dev libffi-dev python3-setuptools \
|
|
||||||
python3-pip dumb-init curl openssh-client wget
|
|
||||||
|
|
||||||
# buildbot entrypoint
|
|
||||||
RUN wget -O /usr/local/bin/buildbot_entrypoint.sh https://git.bitmessage.org/Bitmessage/buildbot-scripts/raw/branch/master/docker/bionic/entrypoint.sh
|
|
||||||
RUN chmod +x /usr/local/bin/buildbot_entrypoint.sh
|
|
||||||
|
|
||||||
RUN echo 'buildbot ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
|
||||||
|
|
||||||
USER buildbot
|
|
||||||
|
|
||||||
ENTRYPOINT /usr/local/bin/buildbot_entrypoint.sh "$BUILDMASTER" "$WORKERNAME" "$WORKERPASS"
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
path =".buildbot"
|
|
||||||
|
|
||||||
def list_jobs(directory=".buildbot"):
|
|
||||||
"""
|
|
||||||
list jobs found in a directory
|
|
||||||
"""
|
|
||||||
results = []
|
|
||||||
for _ in next(walk(directory))[1]:
|
|
||||||
if exists(join(directory, _, "Dockerfile")) and (
|
|
||||||
exists(join(directory, _, "build.sh"))
|
|
||||||
or exists(join(directory, _, "test.sh"))
|
|
||||||
):
|
|
||||||
results.append(_)
|
|
||||||
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
ok but different location (inside ok but different location (inside `add_child_step`)
|
|||||||
def find_artifacts(directory="out"):
|
def find_artifacts(directory="out"):
|
||||||
"""
|
"""
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
needs to be on the worker needs to be on the worker
|
|||||||
|
@ -93,62 +29,29 @@ def find_artifacts(directory="out"):
|
||||||
return join(directory, _)
|
return join(directory, _)
|
||||||
|
|
||||||
|
|
||||||
def get_dockerfile_contents(props):
|
# @util.renderer
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
we don't need this function we don't need this function
|
|||||||
"""
|
# def get_dockerfile_contents(props):
|
||||||
Read contents of a Dockerfile and add extra contents for the given os_codename
|
# return _get_dockerfile_contents(props.getProperty('jobname', default=None), util.Interpolate("%(prop:os_codename)s"))
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
no calling no calling `_get_dockerfile_contents`, just access `props`
PeterSurda
commented
We already have this information. `return props.getProperty('dockerfile')`
We already have this information.
|
|||||||
"""
|
|
||||||
with open(join(path + props.getProperty('jobname', default=None)), "r") as file:
|
|
||||||
contents = file.read()
|
|
||||||
# remove any line containing CMD or ENTRYFILE keywords
|
|
||||||
re.sub(r"(?m)^(CMD|ENTRYFILE).*$", "", contents)
|
|
||||||
|
|
||||||
return contents + {
|
|
||||||
"focal": dockerfile_extra_contents_focal,
|
|
||||||
"bionic": dockerfile_extra_contents_bionic,
|
|
||||||
}[util.Interpolate("%(prop:os_codename)s")]
|
|
||||||
|
|
||||||
|
|
||||||
def trigger_child_hooks(buildbotUrl: str, os_codename: str, repository, branch, jobname, directory=".buildbot"):
|
|
||||||
request_url = buildbotUrl + ty
|
|
||||||
|
|
||||||
# List all jobs in the directory
|
|
||||||
jobs = list_jobs(directory)
|
|
||||||
|
|
||||||
# Check if build.sh or test.sh exists in each of the jobs
|
|
||||||
for job in jobs:
|
|
||||||
build_script_exists = False
|
|
||||||
test_script_exists = False
|
|
||||||
if exists(join(directory, job, "build.sh")):
|
|
||||||
build_script_exists = True
|
|
||||||
if exists(join(directory, job, "test.sh")):
|
|
||||||
test_script_exists = True
|
|
||||||
|
|
||||||
# make a post request
|
|
||||||
request_data["properties"] = {
|
|
||||||
"dockerfile": get_dockerfile_contents(
|
|
||||||
join(directory, job, "Dockerfile"), os_codename
|
|
||||||
),
|
|
||||||
"build_script_available": is_build_script_available(build_script_exists),
|
|
||||||
"test_script_available": is_test_script_available(test_script_exists),
|
|
||||||
"repository": repository,
|
|
||||||
"branch": branch,
|
|
||||||
"jobname": jobname,
|
|
||||||
}
|
|
||||||
requests.post(request_url, headers=request_headers, data=request_data)
|
|
||||||
|
|
||||||
|
|
||||||
def add_parent_step(build_factory):
|
def add_parent_step(build_factory):
|
||||||
"""
|
"""
|
||||||
Add a step to the parent build factory that will trigger the child hooks
|
Add a step to the parent build factory that will trigger the child hooks
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
`return props.getProperty('dockerfile')`
|
|||||||
"""
|
"""
|
||||||
build_factory.addStep(
|
|
||||||
steps.SetPropertyFromCommand(
|
|
||||||
name="Get OS codename",
|
|
||||||
command="grep ^VERSION_CODENAME= /etc/os-release | cut -d= -f2",
|
|
||||||
property="os_codename",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
build_factory.addStep(steps.ShellCommand(
|
||||||
|
name="download worker",
|
||||||
|
command=["wget", "-O", "https://git.bitmessage.org/Bitmessage/buildbot_multibuild/raw/branch/master/lib/worker_multibuild.py", join(getenv['HOME'], '.local/bin/worker_multibuild.py')]
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
no need for sudo, however we need a different directory no need for sudo, however we need a different directory
PeterSurda
commented
maybe into maybe into `~/.local/bin/` (also needs to create the directory if not existant)
PeterSurda
commented
no no `sudo`
PeterSurda
commented
also maybe also maybe
`os.path.join(os.getenv['HOME'], '.local/bin/worker_multibuild.py')`
cis-muzahid
commented
I am using I am using ```--force-directories``` for crete folder if not exists
|
|||||||
|
))
|
||||||
|
|
||||||
|
# build_factory.addStep(
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
The `os_codename` should be per-Dockerfile. We don't really need `os_codename` in the parent, only in the child.
The `Dockerfile`s will begin with, e.g. `FROM ubuntu:bionic ...`. So the parent will then extract the codename from that, and based on that append the corresponding buildbot's setup and entrypoint.
|
|||||||
|
# steps.SetPropertyFromCommand(
|
||||||
|
# name="Get OS codename",
|
||||||
|
# command="grep ^VERSION_CODENAME= /etc/os-release | cut -d= -f2",
|
||||||
|
# property="os_codename",
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
|
||||||
build_factory.addStep(
|
build_factory.addStep(
|
||||||
steps.ShellCommand(
|
steps.ShellCommand(
|
||||||
name="Execute multibuild script",
|
name="Execute multibuild script",
|
||||||
|
@ -165,24 +68,20 @@ def add_parent_step(build_factory):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
upon reflection, this upon reflection, this `BuildStep` needs to go to the parent, not child
|
|||||||
def add_child_build_sh_step(build_factory, directory=".buildbot"):
|
def add_child_sh_steps(build_factory, directory=".buildbot"):
|
||||||
"""
|
"""
|
||||||
Add a step to the build factory
|
Add a step to the download, build and test factory
|
||||||
PeterSurda marked this conversation as resolved
Outdated
PeterSurda
commented
please same indent as elsewhere please same indent as elsewhere
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
build_factory.addStep(
|
build_factory.addStep(
|
||||||
steps.ShellCommand(
|
steps.ShellCommand(
|
||||||
name=util.Interpolate("build_%(prop:jobname)s"),
|
name=util.Interpolate("build_%(prop:jobname)s"),
|
||||||
command=util.Interpolate("%(kw:directory)s/%(prop:jobname)s/test.sh", directory=directory),
|
command=util.Interpolate("%(kw:directory)s/%(prop:jobname)s/build.sh", directory=directory),
|
||||||
doStepIf=is_build_script_available,
|
doStepIf=is_build_script_available,
|
||||||
hideStepIf=isnt_build_script_available,
|
hideStepIf=isnt_build_script_available,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_child_test_sh_step(build_factory, directory=".buildbot"):
|
|
||||||
"""
|
|
||||||
Add a step to the build factory
|
|
||||||
"""
|
|
||||||
build_factory.addStep(
|
build_factory.addStep(
|
||||||
steps.ShellCommand(
|
steps.ShellCommand(
|
||||||
name= util.Interpolate("test_%(prop:jobname)s"),
|
name= util.Interpolate("test_%(prop:jobname)s"),
|
||||||
|
@ -204,7 +103,7 @@ if __name__ == "__main__":
|
||||||
buildbotUrl = sys.argv[4]
|
buildbotUrl = sys.argv[4]
|
||||||
os_codename = sys.argv[5]
|
os_codename = sys.argv[5]
|
||||||
|
|
||||||
trigger_child_hooks(buildbotUrl, os_codename, repository, branch, jobname)
|
trigger_child_hooks(buildbotUrl, os_codename, repository, branch, jobname, ".buildbot", is_build_script_available, is_test_script_available)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
"Usage: python3 multibuild.py <jobname> <repository> <branch> <buildbotUrl> <os_codename>"
|
"Usage: python3 multibuild.py <jobname> <repository> <branch> <buildbotUrl> <os_codename>"
|
||||||
|
|
this is probably here only because of
@util.renderer
, which shouldn't be on the workerRemoved from worker
also remove
from .renderers import *