Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python 3 Lab Controller support #235

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d5dafec
feat: enable lab-controller build for Python 3
StykMartin Jan 19, 2024
5e99a7b
ci: remove centos stream targets
StykMartin Oct 28, 2024
8c08a17
docs: generate man page for beaker-import
StykMartin Jan 21, 2024
bdf3def
fix(async): rename module to avoid use of reserved keyword
StykMartin Jan 19, 2024
0fd6603
fix(test): use range instead of xrange
StykMartin Jan 19, 2024
6d10e2a
fix: update exception handling for Python 2/3 compatibility
StykMartin Oct 28, 2024
9cc72f5
fix(distro_import): update print statements for Python 3 compatibility
StykMartin Oct 28, 2024
5baa28b
fix: use proper octal notation for file permissions
StykMartin Oct 28, 2024
6f0cade
ci: run unit tests during pull requests
StykMartin Oct 28, 2024
617d312
fix: use six for StringIO to ensure Python 2 and 3 compatibility
StykMartin Oct 28, 2024
9deebb7
fix: use six.text_type for unicode compatibility
StykMartin Oct 28, 2024
2db11d1
fix: use six_moves to ensure compatibility with Python 2 and 3
StykMartin Oct 28, 2024
adb5f5d
fix: broken utils import
StykMartin Oct 28, 2024
4c51d56
fix(tests): use appropriate file open mode based on python version
StykMartin Oct 28, 2024
4eb489a
fix(concurrency): handle reading from pipe with Python 2 and 3 compat…
StykMartin Oct 28, 2024
15a194d
fix: ensure proper handling of bytes for Python 3 compatibility
StykMartin Oct 28, 2024
dad40fc
build: manage logrotate and log dir for py3 targets
StykMartin Jan 21, 2024
8963491
fix: update iter methods for Python 3 compatibility
StykMartin Oct 28, 2024
8a13c3c
fix: handle unicode and byte encoding for power environment variables
StykMartin Oct 28, 2024
b4d5d56
fix: handle XMLRPCDocGenerator import for Python 3 compatibility
StykMartin Oct 28, 2024
cc5f552
fix(proxy-main): use pywsgi instead of deprecated wsgi
StykMartin Oct 28, 2024
91df68a
fix: replace string.map with lambda for Python 3 compatibility
StykMartin Oct 28, 2024
e9c6000
fix: convert filter to list for compatibility with Python 3
StykMartin Oct 28, 2024
a70cb82
fix: handle SSL error import for compatibility with Python 2 and 3
StykMartin Oct 28, 2024
374ff60
fix: update base64 decoding method for compatibility with Python 3
StykMartin Oct 28, 2024
d16e435
ci: include additional repository to enable EL7 build
StykMartin Oct 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/review-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,69 @@ jobs:
# Disable Selenium tests until we have plan for selenium driver + firefox
rm -rf src/bkr/inttest/server/selenium
./run-tests.sh -v ${{ matrix.test-target }}

unit-tests:
runs-on: ubuntu-latest
env:
# https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/
ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION: node16
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
container:
image: ${{ matrix.os-target.name }}
options: --init
strategy:
fail-fast: false
matrix:
test-target:
- Common
- Client
- LabController
os-target:
- name: centos:7
- name: quay.io/centos/centos:stream9
additional_repos: "crb"
additional_packages: "epel-release"
steps:
StykMartin marked this conversation as resolved.
Show resolved Hide resolved
- name: Fixup CentOS repo files
if: matrix.os-target.name == 'centos:7'
run: |
sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo
sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo
sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo

- name: Set BKR_PY3 environment variable
run: echo "BKR_PY3=1" >> $GITHUB_ENV
if: matrix.os-target.name != 'centos:7'

- name: Install DNF and plugins
run: yum install -y dnf 'dnf-command(builddep)' 'dnf-command(config-manager)'

- name: Enable additional repositories
run: |
IFS=', ' read -r -a repos <<< "${{ matrix.os-target.additional_repos }}"
for repo in "${repos[@]}"; do
dnf config-manager --set-enabled $repo
done
- name: Install additional packages
run: |
IFS=', ' read -r -a packages <<< "${{ matrix.os-target.additional_packages }}"
for package in "${packages[@]}"; do
dnf install -y $package
done

# Do not upgrade to @v4 as node 20 is incompatible with CentOS 7
- name: Checkout
uses: actions/checkout@v3

- name: Add Beaker Server YUM repository
if: matrix.os-target.name == 'centos:7'
run: |
curl -o /etc/yum.repos.d/beaker-server.repo https://beaker-project.org/yum/beaker-server-RedHatEnterpriseLinux.repo
# Build dependencies must be sufficient, the same is done during RPM build
- name: Install Beaker dependency from specfile
run: |
dnf builddep -y *.spec
- name: Run unit tests
run: |
pushd ${{ matrix.test-target }}
./run-tests.sh
7 changes: 4 additions & 3 deletions .packit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ jobs:
targets:
- epel-8-x86_64
- epel-9-x86_64
- centos-stream-8-x86_64
- centos-stream-9-x86_64
identifier: rhel_8_9

- job: copr_build
Expand All @@ -35,7 +33,10 @@ jobs:
- job: copr_build
trigger: pull_request
targets:
- epel-7-x86_64
epel-7-x86_64:
additional_repos:
- https://beaker-project.org/yum/server/RedHatEnterpriseLinux7/
- https://vault.centos.org/centos/7/extras/x86_64/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upstream mock configuration disables the extras repository, and there is no other way to include the CentOS repository for now. More reasons to migrate quickly.

identifier: rhel_7
actions:
post-upstream-clone:
Expand Down
18 changes: 16 additions & 2 deletions Common/bkr/common/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import os
import fcntl
import errno

import six
from six.moves import queue

log = getLogger(__name__)
Expand Down Expand Up @@ -100,12 +102,20 @@ def run(self):
self.finished.clear()


class SensitiveUnicode(unicode):
class SensitiveUnicode(six.text_type):
"""The intent of this class is to standardize the behavior of Unicode strings across Python 2 and 3,
while treating the contents of the string as sensitive.

In Python 2, it encodes the unicode string to bytes (str), wrapped in SensitiveStr.
In Python 3, it preserves the unicode representation (str) by overriding the default 'encode' behavior.
"""
def __repr__(self):
return '<repr blocked>'

def encode(self, *args, **kwargs):
return SensitiveStr(super(SensitiveUnicode, self).encode(*args, **kwargs))
if six.PY2:
return SensitiveStr(super(SensitiveUnicode, self).encode(*args, **kwargs))
return self


class SensitiveStr(str):
Expand Down Expand Up @@ -235,6 +245,10 @@ def siphon(src, dest):
chunk = src.read(4096)
if not chunk:
break

if six.PY3 and isinstance(chunk, bytes):
chunk = chunk.decode('utf-8')

dest.write(chunk)


Expand Down
14 changes: 11 additions & 3 deletions LabController/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

BKR_PY3 ?= 0
COMMAND := python2

ifeq ($(BKR_PY3),1)
COMMAND := python3
endif


.PHONY: build
build:
python2 setup.py build
$(COMMAND) setup.py build

.PHONY: install
install: build
python2 setup.py install -O1 --skip-build --root $(DESTDIR)
$(COMMAND) setup.py install -O1 --skip-build --root $(DESTDIR)

.PHONY: clean
clean:
python2 setup.py clean
$(COMMAND) setup.py clean
rm -rf build

.PHONY: check
Expand Down
17 changes: 14 additions & 3 deletions LabController/run-tests.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
#/bin/bash
#!/bin/bash
set -x

env PYTHONPATH=src:../Common${PYTHONPATH:+:$PYTHONPATH} \
nosetests ${*:--v --traverse-namespace bkr.labcontroller}
# Use nosetests with python2 interpreter
if [[ -z ${BKR_PY3} ]] || [[ ${BKR_PY3} != 1 ]]; then
command="nosetests ${*:--v --traverse-namespace bkr.labcontroller}";
else
# Check if pytest-3 is available
if command -v pytest-3 >/dev/null 2>&1; then
command="pytest-3";
else
command="pytest";
fi
fi

env PYTHONPATH=src:../Common${PYTHONPATH:+:$PYTHONPATH} $command
11 changes: 8 additions & 3 deletions LabController/setup.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
from setuptools import setup, find_packages
import commands
from glob import glob

try:
from subprocess import getstatusoutput
except ImportError:
from commands import getstatusoutput


def systemd_unit_dir():
status, output = commands.getstatusoutput('pkg-config --variable systemdsystemunitdir systemd')
status, output = getstatusoutput('pkg-config --variable systemdsystemunitdir systemd')
if status or not output:
return None # systemd not found
return output.strip()

def systemd_tmpfiles_dir():
# There doesn't seem to be a specific pkg-config variable for this
status, output = commands.getstatusoutput('pkg-config --variable prefix systemd')
status, output = getstatusoutput('pkg-config --variable prefix systemd')
if status or not output:
return None # systemd not found
return output.strip() + '/lib/tmpfiles.d'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import errno
import logging
import gevent.event, gevent.socket, gevent.hub
import six

logger = logging.getLogger(__name__)

Expand All @@ -29,22 +30,27 @@ def _read_from_pipe(f):
discarding = False
while True:
try:
gevent.socket.wait_read(f.fileno())
chunk = f.read(4096)
if not chunk:
break
if not discarding:
chunks.append(chunk)
if len(chunks) >= 1000:
logger.error('Too many chunks read from fd %s, '
'child process is running amok?!', f.fileno())
chunks.append('+++ DISCARDED')
logger.error(
"Too many chunks read from fd %s, "
"child process is running amok?!",
f.fileno(),
)
chunks.append(b"+++ DISCARDED")
StykMartin marked this conversation as resolved.
Show resolved Hide resolved
discarding = True
except IOError, e:
except IOError as e:
if e.errno != errno.EAGAIN:
raise
sys.exc_clear()
gevent.socket.wait_read(f.fileno())
return ''.join(chunks)
if six.PY3:
# Keep data in bytes until the end to reduce memory footprint
return b"".join(chunks).decode("utf-8")
return "".join(chunks)

def _timeout_kill(p, timeout):
gevent.sleep(timeout)
Expand All @@ -54,14 +60,14 @@ def _kill_process_group(pgid):
# Try SIGTERM first, then SIGKILL just to be safe
try:
os.killpg(pgid, signal.SIGTERM)
except OSError, e:
except OSError as e:
if e.errno != errno.ESRCH:
raise
else:
gevent.sleep(1)
try:
os.killpg(pgid, signal.SIGKILL)
except OSError, e:
except OSError as e:
if e.errno != errno.ESRCH:
raise

Expand Down
Loading
Loading