Compare commits
1 Commits
master
...
78d0390d05
Author | SHA1 | Date | |
---|---|---|---|
78d0390d05
|
13
.github/workflows/e2e.yml
vendored
13
.github/workflows/e2e.yml
vendored
@ -2,19 +2,13 @@ name: E2E
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * 0'
|
|
||||||
push:
|
push:
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
- dev
|
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- ".github/workflows/images-*"
|
- ".github/workflows/images-*"
|
||||||
- ".github/workflows/ubuntu.yml"
|
- ".github/workflows/ubuntu.yml"
|
||||||
- ".github/workflows/macos.yml"
|
- ".github/workflows/macos.yml"
|
||||||
- ".github/workflows/debian-cache.yml"
|
- ".github/workflows/debian-cache.yml"
|
||||||
- "docs/**"
|
- "docs/**"
|
||||||
- 'tools/**'
|
|
||||||
- ".readthedocs.yaml"
|
- ".readthedocs.yaml"
|
||||||
- "README.md"
|
- "README.md"
|
||||||
|
|
||||||
@ -37,7 +31,6 @@ jobs:
|
|||||||
{ distro: Ubuntu, release: 18.04 },
|
{ distro: Ubuntu, release: 18.04 },
|
||||||
{ distro: Ubuntu, release: 20.04 },
|
{ distro: Ubuntu, release: 20.04 },
|
||||||
{ distro: Ubuntu, release: 22.04 },
|
{ distro: Ubuntu, release: 22.04 },
|
||||||
{ distro: Ubuntu, release: 24.04 },
|
|
||||||
{ distro: CentOS, release: 6 },
|
{ distro: CentOS, release: 6 },
|
||||||
{ distro: CentOS, release: 7 },
|
{ distro: CentOS, release: 7 },
|
||||||
{ distro: CentOS, release: 8 },
|
{ distro: CentOS, release: 8 },
|
||||||
@ -126,7 +119,7 @@ jobs:
|
|||||||
echo 'distro = { id = "${{ matrix.os.distro }}", release = "${{ matrix.os.release }}" }' >> examples/kernel-module/.out-of-tree.toml
|
echo 'distro = { id = "${{ matrix.os.distro }}", release = "${{ matrix.os.release }}" }' >> examples/kernel-module/.out-of-tree.toml
|
||||||
echo 'kernel = { regex = ".*" }' >> examples/kernel-module/.out-of-tree.toml
|
echo 'kernel = { regex = ".*" }' >> examples/kernel-module/.out-of-tree.toml
|
||||||
echo '[qemu]' >> examples/kernel-module/.out-of-tree.toml
|
echo '[qemu]' >> examples/kernel-module/.out-of-tree.toml
|
||||||
echo 'timeout = "5m"' >> examples/kernel-module/.out-of-tree.toml
|
echo 'timeout = "10m"' >> examples/kernel-module/.out-of-tree.toml
|
||||||
echo 'after_start_timeout = "10s"' >> examples/kernel-module/.out-of-tree.toml
|
echo 'after_start_timeout = "10s"' >> examples/kernel-module/.out-of-tree.toml
|
||||||
|
|
||||||
echo 'modprobe uio || modprobe 9p || modprobe xfs' >> examples/kernel-module/test.sh
|
echo 'modprobe uio || modprobe 9p || modprobe xfs' >> examples/kernel-module/test.sh
|
||||||
@ -142,8 +135,8 @@ jobs:
|
|||||||
echo 'Type=oneshot' >> test.service
|
echo 'Type=oneshot' >> test.service
|
||||||
echo 'WorkingDirectory=/root/test' >> test.service
|
echo 'WorkingDirectory=/root/test' >> test.service
|
||||||
echo 'TimeoutStopSec=1' >> test.service
|
echo 'TimeoutStopSec=1' >> test.service
|
||||||
echo 'ExecStart=/usr/local/bin/out-of-tree kernel --no-prebuilt-containers autogen --threads=8 --max=64 --shuffle' >> test.service
|
echo 'ExecStart=/usr/local/bin/out-of-tree kernel --no-container-cache autogen --threads=8 --max=128 --shuffle' >> test.service
|
||||||
echo 'ExecStart=/usr/local/bin/out-of-tree pew --threads=4 --include-internal-errors' >> test.service
|
echo 'ExecStart=/usr/local/bin/out-of-tree pew --qemu-timeout=10m --threads=4 --include-internal-errors' >> test.service
|
||||||
|
|
||||||
scp test.service root@$IP:/etc/systemd/system/test.service
|
scp test.service root@$IP:/etc/systemd/system/test.service
|
||||||
|
|
||||||
|
87
.github/workflows/images-centos.yml
vendored
87
.github/workflows/images-centos.yml
vendored
@ -1,87 +0,0 @@
|
|||||||
name: CentOS images
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'tools/qemu-centos-img/**'
|
|
||||||
- '.github/workflows/images-centos.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow_ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
images-centos:
|
|
||||||
name: Qemu Images
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: digitalocean/action-doctl@v2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- uses: webfactory/ssh-agent@v0.8.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: create droplet
|
|
||||||
run: doctl compute droplet create --ssh-keys='b4:4c:66:7d:be:19:25:43:1c:e0:02:61:9f:49:12:94,37:46:77:a8:4a:96:3b:20:16:46:35:04:95:ca:0c:5c' --tag-name=github-actions ga-out-of-tree-images-centos-$GITHUB_SHA --size s-1vcpu-1gb --image ubuntu-22-04-x64 --wait
|
|
||||||
|
|
||||||
# TODO Move to common script
|
|
||||||
- name: generate images
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sleep 1m
|
|
||||||
|
|
||||||
IP=$(doctl compute droplet list --tag-name=github-actions --format "Name,Public IPv4" | grep -v ID | grep ga-out-of-tree-images-centos-$GITHUB_SHA | awk '{print $2}')
|
|
||||||
|
|
||||||
while ! ssh -o StrictHostKeyChecking=accept-new root@$IP echo
|
|
||||||
do
|
|
||||||
sleep 1s
|
|
||||||
done
|
|
||||||
|
|
||||||
ssh root@$IP "cloud-init status --wait | grep done"
|
|
||||||
|
|
||||||
ssh root@$IP apt-get update
|
|
||||||
ssh root@$IP apt-get install -y git podman s3cmd
|
|
||||||
ssh root@$IP git clone https://github.com/out-of-tree/out-of-tree
|
|
||||||
ssh root@$IP "cd out-of-tree && git checkout $GITHUB_SHA"
|
|
||||||
|
|
||||||
ssh root@$IP "echo -e '[Unit]\nDescription=CentOS image generator and uploader\n[Service]\nRemainAfterExit=yes\nStandardError=append:/var/log/images-centos.log\nStandardOutput=append:/var/log/images-centos.log\nType=oneshot' >> /etc/systemd/system/images-centos.service"
|
|
||||||
|
|
||||||
ssh root@$IP "echo Environment=HOST=fra1.digitaloceanspaces.com >> /etc/systemd/system/images-centos.service"
|
|
||||||
ssh root@$IP "echo Environment=HOST_BUCKET=out-of-tree.fra1.digitaloceanspaces.com >> /etc/systemd/system/images-centos.service"
|
|
||||||
ssh root@$IP "echo Environment=ACCESS_KEY=${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }} >> /etc/systemd/system/images-centos.service"
|
|
||||||
ssh root@$IP "echo Environment=SECRET_KEY=${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }} >> /etc/systemd/system/images-centos.service"
|
|
||||||
|
|
||||||
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-centos-img/6/generate.sh' >> /etc/systemd/system/images-centos.service"
|
|
||||||
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-centos-img/7/generate.sh' >> /etc/systemd/system/images-centos.service"
|
|
||||||
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-centos-img/8/generate.sh' >> /etc/systemd/system/images-centos.service"
|
|
||||||
|
|
||||||
ssh root@$IP 'echo ExecStart=/bin/sh -c \"s3cmd put --acl-public /root/out-of-tree/tools/qemu-centos-img/*/*.tar.gz s3://out-of-tree/3.0.0/ --host=\$HOST --host-bucket=\$HOST_BUCKET --access_key=\$ACCESS_KEY --secret_key=\$SECRET_KEY\" >> /etc/systemd/system/images-centos.service'
|
|
||||||
|
|
||||||
ssh root@$IP "echo TimeoutStopSec=1 >> /etc/systemd/system/images-centos.service"
|
|
||||||
|
|
||||||
ssh root@$IP systemctl daemon-reload
|
|
||||||
|
|
||||||
ssh root@$IP systemctl start images-centos --no-block
|
|
||||||
|
|
||||||
while ! ssh root@$IP systemctl show images-centos -p SubState --value | grep -E '(failed|exited)'
|
|
||||||
do
|
|
||||||
sleep 3m
|
|
||||||
done
|
|
||||||
|
|
||||||
scp root@$IP:/var/log/images-centos.log .
|
|
||||||
|
|
||||||
ssh root@$IP systemctl is-active images-centos
|
|
||||||
|
|
||||||
- name: Archive logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: images-centos-log
|
|
||||||
path: images-centos.log
|
|
||||||
|
|
||||||
- name: delete droplet
|
|
||||||
if: always()
|
|
||||||
run: doctl compute droplet delete -f ga-out-of-tree-images-centos-$GITHUB_SHA
|
|
9
.github/workflows/images-debian.yml
vendored
9
.github/workflows/images-debian.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Debian images
|
name: Debian
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@ -25,7 +25,7 @@ jobs:
|
|||||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: create droplet
|
- name: create droplet
|
||||||
run: doctl compute droplet create --ssh-keys='b4:4c:66:7d:be:19:25:43:1c:e0:02:61:9f:49:12:94,37:46:77:a8:4a:96:3b:20:16:46:35:04:95:ca:0c:5c' --tag-name=github-actions ga-out-of-tree-images-debian-$GITHUB_SHA --size s-1vcpu-1gb --image ubuntu-22-04-x64 --wait
|
run: doctl compute droplet create --ssh-keys='b4:4c:66:7d:be:19:25:43:1c:e0:02:61:9f:49:12:94' --tag-name=github-actions ga-out-of-tree-images-debian-$GITHUB_SHA --size s-1vcpu-1gb --image ubuntu-22-04-x64 --wait
|
||||||
|
|
||||||
# TODO Move to common script
|
# TODO Move to common script
|
||||||
- name: generate images
|
- name: generate images
|
||||||
@ -40,7 +40,8 @@ jobs:
|
|||||||
sleep 1s
|
sleep 1s
|
||||||
done
|
done
|
||||||
|
|
||||||
ssh root@$IP "cloud-init status --wait | grep done"
|
sleep 5m
|
||||||
|
ssh root@$IP pkill apt-get || true
|
||||||
|
|
||||||
ssh root@$IP apt-get update
|
ssh root@$IP apt-get update
|
||||||
ssh root@$IP apt-get install -y git podman s3cmd
|
ssh root@$IP apt-get install -y git podman s3cmd
|
||||||
@ -56,7 +57,7 @@ jobs:
|
|||||||
|
|
||||||
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-debian-img/generate-images.sh' >> /etc/systemd/system/images-debian.service"
|
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-debian-img/generate-images.sh' >> /etc/systemd/system/images-debian.service"
|
||||||
|
|
||||||
ssh root@$IP 'echo ExecStart=/bin/sh -c \"s3cmd put --acl-public /root/out-of-tree/tools/qemu-debian-img/*.tar.gz s3://out-of-tree/3.0.0/ --host=\$HOST --host-bucket=\$HOST_BUCKET --access_key=\$ACCESS_KEY --secret_key=\$SECRET_KEY\" >> /etc/systemd/system/images-debian.service'
|
ssh root@$IP 'echo ExecStart=/bin/sh -c \"s3cmd put --acl-public /root/out-of-tree/tools/qemu-debian-img/*.tar.gz s3://out-of-tree/1.0.0/ --host=\$HOST --host-bucket=\$HOST_BUCKET --access_key=\$ACCESS_KEY --secret_key=\$SECRET_KEY\" >> /etc/systemd/system/images-debian.service'
|
||||||
|
|
||||||
ssh root@$IP "echo TimeoutStopSec=1 >> /etc/systemd/system/images-debian.service"
|
ssh root@$IP "echo TimeoutStopSec=1 >> /etc/systemd/system/images-debian.service"
|
||||||
|
|
||||||
|
16
.github/workflows/images-oraclelinux.yml
vendored
16
.github/workflows/images-oraclelinux.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Oracle Linux images
|
name: Oracle Linux
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@ -25,7 +25,7 @@ jobs:
|
|||||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: create droplet
|
- name: create droplet
|
||||||
run: doctl compute droplet create --ssh-keys='b4:4c:66:7d:be:19:25:43:1c:e0:02:61:9f:49:12:94,37:46:77:a8:4a:96:3b:20:16:46:35:04:95:ca:0c:5c' --tag-name=github-actions ga-out-of-tree-images-oraclelinux-$GITHUB_SHA --size s-1vcpu-2gb --image ubuntu-22-04-x64 --wait
|
run: doctl compute droplet create --ssh-keys='b4:4c:66:7d:be:19:25:43:1c:e0:02:61:9f:49:12:94' --tag-name=github-actions ga-out-of-tree-images-oraclelinux-$GITHUB_SHA --size s-1vcpu-1gb --image ubuntu-22-04-x64 --wait
|
||||||
|
|
||||||
# TODO Move to common script
|
# TODO Move to common script
|
||||||
- name: generate images
|
- name: generate images
|
||||||
@ -40,7 +40,8 @@ jobs:
|
|||||||
sleep 1s
|
sleep 1s
|
||||||
done
|
done
|
||||||
|
|
||||||
ssh root@$IP "cloud-init status --wait | grep done"
|
sleep 5m
|
||||||
|
ssh root@$IP pkill apt-get || true
|
||||||
|
|
||||||
ssh root@$IP apt-get update
|
ssh root@$IP apt-get update
|
||||||
ssh root@$IP apt-get install -y git podman s3cmd
|
ssh root@$IP apt-get install -y git podman s3cmd
|
||||||
@ -56,7 +57,7 @@ jobs:
|
|||||||
|
|
||||||
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-oraclelinux-img/generate-images.sh' >> /etc/systemd/system/images-oraclelinux.service"
|
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-oraclelinux-img/generate-images.sh' >> /etc/systemd/system/images-oraclelinux.service"
|
||||||
|
|
||||||
ssh root@$IP 'echo ExecStart=/bin/sh -c \"s3cmd put --acl-public /root/out-of-tree/tools/qemu-oraclelinux-img/*.tar.gz s3://out-of-tree/3.0.0/ --host=\$HOST --host-bucket=\$HOST_BUCKET --access_key=\$ACCESS_KEY --secret_key=\$SECRET_KEY\" >> /etc/systemd/system/images-oraclelinux.service'
|
ssh root@$IP 'echo ExecStart=/bin/sh -c \"s3cmd put --acl-public /root/out-of-tree/tools/qemu-oraclelinux-img/*.tar.gz s3://out-of-tree/1.0.0/ --host=\$HOST --host-bucket=\$HOST_BUCKET --access_key=\$ACCESS_KEY --secret_key=\$SECRET_KEY\" >> /etc/systemd/system/images-oraclelinux.service'
|
||||||
|
|
||||||
ssh root@$IP "echo TimeoutStopSec=1 >> /etc/systemd/system/images-oraclelinux.service"
|
ssh root@$IP "echo TimeoutStopSec=1 >> /etc/systemd/system/images-oraclelinux.service"
|
||||||
|
|
||||||
@ -73,13 +74,6 @@ jobs:
|
|||||||
|
|
||||||
ssh root@$IP systemctl is-active images-oraclelinux
|
ssh root@$IP systemctl is-active images-oraclelinux
|
||||||
|
|
||||||
- name: Archive logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: images-oraclelinux-log
|
|
||||||
path: images-oraclelinux.log
|
|
||||||
|
|
||||||
- name: delete droplet
|
- name: delete droplet
|
||||||
if: always()
|
if: always()
|
||||||
run: doctl compute droplet delete -f ga-out-of-tree-images-oraclelinux-$GITHUB_SHA
|
run: doctl compute droplet delete -f ga-out-of-tree-images-oraclelinux-$GITHUB_SHA
|
||||||
|
89
.github/workflows/images-ubuntu.yml
vendored
89
.github/workflows/images-ubuntu.yml
vendored
@ -1,89 +0,0 @@
|
|||||||
name: Ubuntu images
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'tools/qemu-ubuntu-img/**'
|
|
||||||
- '.github/workflows/images-ubuntu.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow_ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
images:
|
|
||||||
name: Qemu Images
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: digitalocean/action-doctl@v2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- uses: webfactory/ssh-agent@v0.8.0
|
|
||||||
with:
|
|
||||||
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: create droplet
|
|
||||||
run: doctl compute droplet create --ssh-keys='b4:4c:66:7d:be:19:25:43:1c:e0:02:61:9f:49:12:94,37:46:77:a8:4a:96:3b:20:16:46:35:04:95:ca:0c:5c' --tag-name=github-actions ga-out-of-tree-images-ubuntu-$GITHUB_SHA --size s-1vcpu-1gb --image ubuntu-22-04-x64 --wait
|
|
||||||
|
|
||||||
# TODO Move to common script
|
|
||||||
- name: generate images
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set -x
|
|
||||||
|
|
||||||
sleep 1m
|
|
||||||
|
|
||||||
IP=$(doctl compute droplet list --tag-name=github-actions --format "Name,Public IPv4" | grep -v ID | grep ga-out-of-tree-images-ubuntu-$GITHUB_SHA | awk '{print $2}')
|
|
||||||
|
|
||||||
while ! ssh -o StrictHostKeyChecking=accept-new root@$IP echo
|
|
||||||
do
|
|
||||||
sleep 1s
|
|
||||||
done
|
|
||||||
|
|
||||||
ssh root@$IP "cloud-init status --wait | grep done"
|
|
||||||
|
|
||||||
ssh root@$IP apt-get update
|
|
||||||
ssh root@$IP apt-get install -y git podman s3cmd
|
|
||||||
ssh root@$IP git clone https://github.com/out-of-tree/out-of-tree
|
|
||||||
ssh root@$IP "cd out-of-tree && git checkout $GITHUB_SHA"
|
|
||||||
|
|
||||||
ssh root@$IP "echo -e '[Unit]\nDescription=Ubuntu image generator and uploader\n[Service]\nRemainAfterExit=yes\nStandardError=append:/var/log/images-ubuntu.log\nStandardOutput=append:/var/log/images-ubuntu.log\nType=oneshot' >> /etc/systemd/system/images-ubuntu.service"
|
|
||||||
|
|
||||||
ssh root@$IP "echo Environment=HOST=fra1.digitaloceanspaces.com >> /etc/systemd/system/images-ubuntu.service"
|
|
||||||
ssh root@$IP "echo Environment=HOST_BUCKET=out-of-tree.fra1.digitaloceanspaces.com >> /etc/systemd/system/images-ubuntu.service"
|
|
||||||
ssh root@$IP "echo Environment=ACCESS_KEY=${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }} >> /etc/systemd/system/images-ubuntu.service"
|
|
||||||
ssh root@$IP "echo Environment=SECRET_KEY=${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }} >> /etc/systemd/system/images-ubuntu.service"
|
|
||||||
|
|
||||||
ssh root@$IP "echo 'ExecStart=/root/out-of-tree/tools/qemu-ubuntu-img/generate-images.py' >> /etc/systemd/system/images-ubuntu.service"
|
|
||||||
|
|
||||||
ssh root@$IP 'echo ExecStart=/bin/sh -c \"s3cmd put --acl-public /root/out-of-tree/tools/qemu-ubuntu-img/*.tar.gz s3://out-of-tree/3.0.0/ --host=\$HOST --host-bucket=\$HOST_BUCKET --access_key=\$ACCESS_KEY --secret_key=\$SECRET_KEY\" >> /etc/systemd/system/images-ubuntu.service'
|
|
||||||
|
|
||||||
ssh root@$IP "echo TimeoutStopSec=1 >> /etc/systemd/system/images-ubuntu.service"
|
|
||||||
|
|
||||||
ssh root@$IP systemctl daemon-reload
|
|
||||||
|
|
||||||
ssh root@$IP systemctl start images-ubuntu --no-block
|
|
||||||
|
|
||||||
while ! ssh root@$IP systemctl show images-ubuntu -p SubState --value | grep -E '(failed|exited)'
|
|
||||||
do
|
|
||||||
sleep 1m
|
|
||||||
done
|
|
||||||
|
|
||||||
scp root@$IP:/var/log/images-ubuntu.log .
|
|
||||||
|
|
||||||
cat images-ubuntu.log
|
|
||||||
|
|
||||||
ssh root@$IP systemctl is-active images-ubuntu
|
|
||||||
|
|
||||||
- name: Archive logs
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: images-ubuntu-log
|
|
||||||
path: images-ubuntu.log
|
|
||||||
|
|
||||||
- name: delete droplet
|
|
||||||
if: always()
|
|
||||||
run: doctl compute droplet delete -f ga-out-of-tree-images-ubuntu-$GITHUB_SHA
|
|
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@ -18,7 +18,7 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: macOS-12
|
runs-on: macOS-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
|
|
||||||
|
5
.github/workflows/ubuntu.yml
vendored
5
.github/workflows/ubuntu.yml
vendored
@ -2,8 +2,6 @@ name: Ubuntu
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * 0'
|
|
||||||
push:
|
push:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- ".github/workflows/images-*"
|
- ".github/workflows/images-*"
|
||||||
@ -115,7 +113,6 @@ jobs:
|
|||||||
{ distro: Ubuntu, release: 18.04 },
|
{ distro: Ubuntu, release: 18.04 },
|
||||||
{ distro: Ubuntu, release: 20.04 },
|
{ distro: Ubuntu, release: 20.04 },
|
||||||
{ distro: Ubuntu, release: 22.04 },
|
{ distro: Ubuntu, release: 22.04 },
|
||||||
{ distro: Ubuntu, release: 24.04 },
|
|
||||||
{ distro: CentOS, release: 6 },
|
{ distro: CentOS, release: 6 },
|
||||||
{ distro: CentOS, release: 7 },
|
{ distro: CentOS, release: 7 },
|
||||||
{ distro: CentOS, release: 8 },
|
{ distro: CentOS, release: 8 },
|
||||||
@ -203,7 +200,7 @@ jobs:
|
|||||||
|
|
||||||
cp ../examples/kernel-module/{module.c,Makefile,test.sh} .
|
cp ../examples/kernel-module/{module.c,Makefile,test.sh} .
|
||||||
|
|
||||||
../out-of-tree --log-level=debug kernel list-remote --distro-id=${{ matrix.os.distro }} --distro-release=${{ matrix.os.release }}
|
../out-of-tree --log-level=debug kernel list-remote --distro=${{ matrix.os.distro }} --ver=${{ matrix.os.release }}
|
||||||
../out-of-tree --log-level=debug kernel autogen --max=1 --shuffle
|
../out-of-tree --log-level=debug kernel autogen --max=1 --shuffle
|
||||||
../out-of-tree --log-level=debug pew --qemu-timeout=20m --include-internal-errors
|
../out-of-tree --log-level=debug pew --qemu-timeout=20m --include-internal-errors
|
||||||
|
|
||||||
|
10
README.md
10
README.md
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
*out-of-tree* was created to reduce the complexity of the environment for developing, testing and debugging Linux kernel exploits and out-of-tree kernel modules (hence the name "out-of-tree").
|
*out-of-tree* was created to reduce the complexity of the environment for developing, testing and debugging Linux kernel exploits and out-of-tree kernel modules (hence the name "out-of-tree").
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### GNU/Linux (with [Nix](https://nixos.org/nix/))
|
### GNU/Linux (with [Nix](https://nixos.org/nix/))
|
||||||
@ -40,9 +42,9 @@ Read [documentation](https://out-of-tree.readthedocs.io) for further info.
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
Download all Ubuntu 24.04 kernels:
|
Generate all Ubuntu 22.04 kernels:
|
||||||
|
|
||||||
$ out-of-tree kernel genall --distro-id=Ubuntu --distro-release=24.04
|
$ out-of-tree kernel genall --distro=Ubuntu --ver=22.04
|
||||||
|
|
||||||
Run tests based on .out-of-tree.toml definitions:
|
Run tests based on .out-of-tree.toml definitions:
|
||||||
|
|
||||||
@ -50,8 +52,8 @@ Run tests based on .out-of-tree.toml definitions:
|
|||||||
|
|
||||||
Test with a specific kernel:
|
Test with a specific kernel:
|
||||||
|
|
||||||
$ out-of-tree pew --realtime-output --distro-id=ubuntu --kernel-regex=6.8.0-41-generic
|
$ out-of-tree pew --kernel='Ubuntu:5.4.0-29-generic'
|
||||||
|
|
||||||
Run debug environment:
|
Run debug environment:
|
||||||
|
|
||||||
$ out-of-tree debug --distro-id=ubuntu --distro-release=24.04 --kernel-regex=6.8.0-41-generic
|
$ out-of-tree debug --kernel='Ubuntu:5.4.0-29-generic'
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/naoina/toml"
|
"github.com/naoina/toml"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
||||||
"code.dumpstack.io/tools/out-of-tree/distro"
|
"code.dumpstack.io/tools/out-of-tree/distro"
|
||||||
@ -133,12 +134,8 @@ type Patch struct {
|
|||||||
type Artifact struct {
|
type Artifact struct {
|
||||||
Name string
|
Name string
|
||||||
Type ArtifactType
|
Type ArtifactType
|
||||||
|
|
||||||
SourcePath string
|
|
||||||
SourceFiles []string
|
|
||||||
|
|
||||||
TestFiles []FileTransfer
|
TestFiles []FileTransfer
|
||||||
|
SourcePath string
|
||||||
Targets []Target
|
Targets []Target
|
||||||
|
|
||||||
Script string
|
Script string
|
||||||
@ -240,9 +237,8 @@ func (ka Artifact) Supported(ki distro.KernelInfo) (supported bool, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO too many parameters
|
|
||||||
func (ka Artifact) Process(slog zerolog.Logger, ki distro.KernelInfo,
|
func (ka Artifact) Process(slog zerolog.Logger, ki distro.KernelInfo,
|
||||||
outputOnSuccess, realtimeOutput, endless bool, cBinary,
|
endless bool, cBinary,
|
||||||
cEndlessStress string, cEndlessTimeout time.Duration,
|
cEndlessStress string, cEndlessTimeout time.Duration,
|
||||||
dump func(q *qemu.System, ka Artifact, ki distro.KernelInfo,
|
dump func(q *qemu.System, ka Artifact, ki distro.KernelInfo,
|
||||||
result *Result)) {
|
result *Result)) {
|
||||||
@ -334,22 +330,12 @@ func (ka Artifact) Process(slog zerolog.Logger, ki distro.KernelInfo,
|
|||||||
// TODO: build should return structure
|
// TODO: build should return structure
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
result.BuildDir, result.BuildArtifact, result.Build.Output, err =
|
result.BuildDir, result.BuildArtifact, result.Build.Output, err =
|
||||||
Build(slog, tmp, ka, ki, ka.Docker.Timeout.Duration, realtimeOutput)
|
Build(slog, tmp, ka, ki, ka.Docker.Timeout.Duration)
|
||||||
slog.Debug().Str("duration", time.Since(start).String()).
|
slog.Debug().Str("duration", time.Since(start).String()).
|
||||||
Msg("build done")
|
Msg("build done")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !realtimeOutput {
|
log.Error().Err(err).Msg("build")
|
||||||
slog.Error().Err(err).Msgf("build failure\n%v\n", result.Build.Output)
|
|
||||||
} else {
|
|
||||||
slog.Error().Err(err).Msg("build failure")
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
if outputOnSuccess && !realtimeOutput {
|
|
||||||
slog.Info().Msgf("build success\n%v\n", result.Build.Output)
|
|
||||||
} else {
|
|
||||||
slog.Info().Msg("build success")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result.Build.Ok = true
|
result.Build.Ok = true
|
||||||
} else {
|
} else {
|
||||||
@ -371,8 +357,6 @@ func (ka Artifact) Process(slog zerolog.Logger, ki distro.KernelInfo,
|
|||||||
ka.Qemu.Timeout.Duration = time.Minute
|
ka.Qemu.Timeout.Duration = time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info().Msg("wait for vm initialisation")
|
|
||||||
|
|
||||||
err = q.WaitForSSH(ka.Qemu.Timeout.Duration)
|
err = q.WaitForSSH(ka.Qemu.Timeout.Duration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.InternalError = err
|
result.InternalError = err
|
||||||
@ -409,40 +393,11 @@ func (ka Artifact) Process(slog zerolog.Logger, ki distro.KernelInfo,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var qemuTestOutput string
|
|
||||||
q.SetQemuOutputHandler(func(s string) {
|
|
||||||
if realtimeOutput {
|
|
||||||
fmt.Printf("kmsg: %s\n", s)
|
|
||||||
} else {
|
|
||||||
qemuTestOutput += s + "\n"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if realtimeOutput {
|
|
||||||
q.SetCommandsOutputHandler(func(s string) {
|
|
||||||
fmt.Printf("test: %s\n", s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
slog.Info().Msg("copy artifact and run test")
|
copyArtifactAndTest(slog, q, ka, &result, remoteTest)
|
||||||
copyArtifactAndTest(slog, q, ka, &result, remoteTest, outputOnSuccess, realtimeOutput)
|
|
||||||
slog.Debug().Str("duration", time.Since(start).String()).
|
slog.Debug().Str("duration", time.Since(start).String()).
|
||||||
Msgf("test completed (success: %v)", result.Test.Ok)
|
Msgf("test completed (success: %v)", result.Test.Ok)
|
||||||
|
|
||||||
if result.Build.Ok && !realtimeOutput {
|
|
||||||
if !result.Run.Ok || !result.Test.Ok {
|
|
||||||
slog.Error().Msgf("qemu output\n%v\n", qemuTestOutput)
|
|
||||||
} else if outputOnSuccess {
|
|
||||||
slog.Info().Msgf("qemu output\n%v\n", qemuTestOutput)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if realtimeOutput {
|
|
||||||
q.CloseCommandsOutputHandler()
|
|
||||||
}
|
|
||||||
q.CloseQemuOutputHandler()
|
|
||||||
|
|
||||||
if !endless {
|
if !endless {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func preload(q *qemu.System, ki distro.KernelInfo, pm PreloadModule,
|
|||||||
|
|
||||||
var workPath, cache string
|
var workPath, cache string
|
||||||
if pm.Path != "" {
|
if pm.Path != "" {
|
||||||
log.Debug().Msg("Use non-git path for preload module (no cache)")
|
log.Print("Use non-git path for preload module (no cache)")
|
||||||
workPath = pm.Path
|
workPath = pm.Path
|
||||||
} else if pm.Repo != "" {
|
} else if pm.Repo != "" {
|
||||||
workPath, cache, err = cloneOrPull(pm.Repo, ki)
|
workPath, cache, err = cloneOrPull(pm.Repo, ki)
|
||||||
@ -85,7 +85,7 @@ func buildAndInsmod(workPath string, q *qemu.System, ki distro.KernelInfo,
|
|||||||
|
|
||||||
output, err := q.CopyAndInsmod(af)
|
output, err := q.CopyAndInsmod(af)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg(output)
|
log.Print(output)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -111,7 +111,7 @@ func buildPreload(workPath, tmp string, ki distro.KernelInfo,
|
|||||||
dockerTimeout = ka.Docker.Timeout.Duration
|
dockerTimeout = ka.Docker.Timeout.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
_, af, _, err = Build(log.Logger, tmp, ka, ki, dockerTimeout, false)
|
_, af, _, err = Build(log.Logger, tmp, ka, ki, dockerTimeout)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ func cloneOrPull(repo string, ki distro.KernelInfo) (workPath, cache string,
|
|||||||
|
|
||||||
err = w.Pull(&git.PullOptions{})
|
err = w.Pull(&git.PullOptions{})
|
||||||
if err != nil && err != git.NoErrAlreadyUpToDate {
|
if err != nil && err != git.NoErrAlreadyUpToDate {
|
||||||
log.Error().Err(err).Msgf("pull %s error", repo)
|
log.Print(repo, "pull error:", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
r, err = git.PlainClone(workPath, false, &git.CloneOptions{URL: repo})
|
r, err = git.PlainClone(workPath, false, &git.CloneOptions{URL: repo})
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -103,7 +102,7 @@ func applyPatches(src string, ka Artifact) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Build(flog zerolog.Logger, tmp string, ka Artifact,
|
func Build(flog zerolog.Logger, tmp string, ka Artifact,
|
||||||
ki distro.KernelInfo, dockerTimeout time.Duration, realtimeOutput bool) (
|
ki distro.KernelInfo, dockerTimeout time.Duration) (
|
||||||
outdir, outpath, output string, err error) {
|
outdir, outpath, output string, err error) {
|
||||||
|
|
||||||
target := strings.Replace(ka.Name, " ", "_", -1)
|
target := strings.Replace(ka.Name, " ", "_", -1)
|
||||||
@ -113,11 +112,7 @@ func Build(flog zerolog.Logger, tmp string, ka Artifact,
|
|||||||
|
|
||||||
outdir = tmp + "/source"
|
outdir = tmp + "/source"
|
||||||
|
|
||||||
if len(ka.SourceFiles) == 0 {
|
|
||||||
err = copy.Copy(ka.SourcePath, outdir)
|
err = copy.Copy(ka.SourcePath, outdir)
|
||||||
} else {
|
|
||||||
err = CopyFiles(ka.SourcePath, ka.SourceFiles, outdir)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -155,21 +150,9 @@ func Build(flog zerolog.Logger, tmp string, ka Artifact,
|
|||||||
log.Fatal().Err(err).Msg("container creation failure")
|
log.Fatal().Err(err).Msg("container creation failure")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Args = append(c.Args, "--network", "none")
|
|
||||||
|
|
||||||
if realtimeOutput {
|
|
||||||
c.SetCommandsOutputHandler(func(s string) {
|
|
||||||
fmt.Printf("%s\n", s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
output, err = c.Run(outdir, []string{
|
output, err = c.Run(outdir, []string{
|
||||||
buildCommand + " && chmod -R 777 /work",
|
buildCommand + " && chmod -R 777 /work",
|
||||||
})
|
})
|
||||||
|
|
||||||
if realtimeOutput {
|
|
||||||
c.CloseCommandsOutputHandler()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cmd := exec.Command("bash", "-c", "cd "+outdir+" && "+
|
cmd := exec.Command("bash", "-c", "cd "+outdir+" && "+
|
||||||
buildCommand)
|
buildCommand)
|
||||||
@ -243,35 +226,6 @@ type Result struct {
|
|||||||
InternalErrorString string
|
InternalErrorString string
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyFiles(path string, files []string, dest string) (err error) {
|
|
||||||
err = os.MkdirAll(dest, os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sf := range files {
|
|
||||||
if sf[0] == '/' {
|
|
||||||
err = CopyFile(sf, filepath.Join(dest, filepath.Base(sf)))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.MkdirAll(filepath.Join(dest, filepath.Dir(sf)), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = CopyFile(filepath.Join(path, sf), filepath.Join(dest, sf))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func CopyFile(sourcePath, destinationPath string) (err error) {
|
func CopyFile(sourcePath, destinationPath string) (err error) {
|
||||||
sourceFile, err := os.Open(sourcePath)
|
sourceFile, err := os.Open(sourcePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -291,7 +245,7 @@ func CopyFile(sourcePath, destinationPath string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func copyArtifactAndTest(slog zerolog.Logger, q *qemu.System, ka Artifact,
|
func copyArtifactAndTest(slog zerolog.Logger, q *qemu.System, ka Artifact,
|
||||||
res *Result, remoteTest string, outputOnSuccess, realtimeOutput bool) (err error) {
|
res *Result, remoteTest string) (err error) {
|
||||||
|
|
||||||
// Copy all test files to the remote machine
|
// Copy all test files to the remote machine
|
||||||
for _, f := range ka.TestFiles {
|
for _, f := range ka.TestFiles {
|
||||||
@ -323,7 +277,8 @@ func copyArtifactAndTest(slog zerolog.Logger, q *qemu.System, ka Artifact,
|
|||||||
|
|
||||||
res.Test.Output, err = testKernelModule(q, ka, remoteTest)
|
res.Test.Output, err = testKernelModule(q, ka, remoteTest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
slog.Error().Err(err).Msg(res.Test.Output)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
res.Test.Ok = true
|
res.Test.Ok = true
|
||||||
case KernelExploit:
|
case KernelExploit:
|
||||||
@ -336,36 +291,24 @@ func copyArtifactAndTest(slog zerolog.Logger, q *qemu.System, ka Artifact,
|
|||||||
res.Test.Output, err = testKernelExploit(q, ka, remoteTest,
|
res.Test.Output, err = testKernelExploit(q, ka, remoteTest,
|
||||||
remoteExploit)
|
remoteExploit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
slog.Error().Err(err).Msg(res.Test.Output)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
res.Run.Ok = true // does not really used
|
res.Run.Ok = true // does not really used
|
||||||
res.Test.Ok = true
|
res.Test.Ok = true
|
||||||
case Script:
|
case Script:
|
||||||
res.Test.Output, err = runScript(q, remoteTest)
|
res.Test.Output, err = runScript(q, remoteTest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
slog.Error().Err(err).Msg(res.Test.Output)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
slog.Info().Msgf("\n%v\n", res.Test.Output)
|
||||||
res.Run.Ok = true
|
res.Run.Ok = true
|
||||||
res.Test.Ok = true
|
res.Test.Ok = true
|
||||||
default:
|
default:
|
||||||
slog.Fatal().Msg("Unsupported artifact type")
|
slog.Fatal().Msg("Unsupported artifact type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil || !res.Test.Ok {
|
|
||||||
if !realtimeOutput {
|
|
||||||
slog.Error().Err(err).Msgf("test failure\n%v\n", res.Test.Output)
|
|
||||||
} else {
|
|
||||||
slog.Error().Err(err).Msg("test failure")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if outputOnSuccess && !realtimeOutput {
|
|
||||||
slog.Info().Msgf("test success\n%v\n", res.Test.Output)
|
|
||||||
} else {
|
|
||||||
slog.Info().Msg("test success")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = q.Command("root", "echo")
|
_, err = q.Command("root", "echo")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error().Err(err).Msg("after-test ssh reconnect")
|
slog.Error().Err(err).Msg("after-test ssh reconnect")
|
||||||
|
@ -198,11 +198,9 @@ func (c Client) PushRepo(repo api.Repo) (err error) {
|
|||||||
remote := fmt.Sprintf("git://%s/%s", addr, repo.Name)
|
remote := fmt.Sprintf("git://%s/%s", addr, repo.Name)
|
||||||
log.Debug().Msgf("git proxy remote: %v", remote)
|
log.Debug().Msgf("git proxy remote: %v", remote)
|
||||||
|
|
||||||
raw, err := exec.Command("git", "-c", "push.default=current",
|
raw, err := exec.Command("git", "--work-tree", repo.Path, "push", "--force", remote).
|
||||||
"--work-tree", repo.Path, "push", "--force", remote).
|
|
||||||
CombinedOutput()
|
CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("push repo %v\n%v", repo, string(raw))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
106
cmd/container.go
106
cmd/container.go
@ -1,74 +1,39 @@
|
|||||||
// Copyright 2024 Mikhail Klementev. All rights reserved.
|
// Copyright 2023 Mikhail Klementev. All rights reserved.
|
||||||
// Use of this source code is governed by a AGPLv3 license
|
// Use of this source code is governed by a AGPLv3 license
|
||||||
// (or later) that can be found in the LICENSE file.
|
// (or later) that can be found in the LICENSE file.
|
||||||
|
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"code.dumpstack.io/tools/out-of-tree/container"
|
"code.dumpstack.io/tools/out-of-tree/container"
|
||||||
"code.dumpstack.io/tools/out-of-tree/distro"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContainerCmd struct {
|
type ContainerCmd struct {
|
||||||
DistroID string `help:"filter by distribution"`
|
Filter string `help:"filter by name"`
|
||||||
DistroRelease string `help:"filter by distribution release"`
|
|
||||||
|
|
||||||
List ContainerListCmd `cmd:"" help:"list containers"`
|
List ContainerListCmd `cmd:"" help:"list containers"`
|
||||||
Update ContainerUpdateCmd `cmd:"" help:"update containers"`
|
|
||||||
Save ContainerSaveCmd `cmd:"" help:"save containers"`
|
Save ContainerSaveCmd `cmd:"" help:"save containers"`
|
||||||
Cleanup ContainerCleanupCmd `cmd:"" help:"cleanup containers"`
|
Cleanup ContainerCleanupCmd `cmd:"" help:"cleanup containers"`
|
||||||
|
|
||||||
RealtimeOutput RealtimeContainerOutputFlag `help:"show realtime output"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RealtimeContainerOutputFlag bool
|
func (cmd ContainerCmd) Containers() (names []string) {
|
||||||
|
|
||||||
func (f RealtimeContainerOutputFlag) AfterApply() (err error) {
|
|
||||||
container.Stdout = bool(f)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cmd ContainerCmd) Containers() (diis []container.Image, err error) {
|
|
||||||
images, err := container.Images()
|
images, err := container.Images()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
log.Fatal().Err(err).Msg("")
|
||||||
}
|
|
||||||
|
|
||||||
var dt distro.Distro
|
|
||||||
if cmd.DistroID != "" {
|
|
||||||
dt.ID, err = distro.NewID(cmd.DistroID)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.DistroRelease != "" {
|
|
||||||
dt.Release = cmd.DistroRelease
|
|
||||||
}
|
|
||||||
} else if cmd.DistroRelease != "" {
|
|
||||||
err = errors.New("--distro-release has no use on its own")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, img := range images {
|
for _, img := range images {
|
||||||
if dt.ID != distro.None && dt.ID != img.Distro.ID {
|
if cmd.Filter != "" && !strings.Contains(img.Name, cmd.Filter) {
|
||||||
log.Debug().Msgf("skip %s", img.Name)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
names = append(names, img.Name)
|
||||||
if dt.Release != "" && dt.Release != img.Distro.Release {
|
|
||||||
log.Debug().Msgf("skip %s", img.Name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug().Msgf("append %s", img.Name)
|
|
||||||
diis = append(diis, img)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -76,40 +41,9 @@ func (cmd ContainerCmd) Containers() (diis []container.Image, err error) {
|
|||||||
type ContainerListCmd struct{}
|
type ContainerListCmd struct{}
|
||||||
|
|
||||||
func (cmd ContainerListCmd) Run(containerCmd *ContainerCmd) (err error) {
|
func (cmd ContainerListCmd) Run(containerCmd *ContainerCmd) (err error) {
|
||||||
images, err := containerCmd.Containers()
|
for _, name := range containerCmd.Containers() {
|
||||||
if err != nil {
|
fmt.Println(name)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, img := range images {
|
|
||||||
fmt.Printf("%s\n", img.Distro.String())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContainerUpdateCmd struct{}
|
|
||||||
|
|
||||||
func (cmd ContainerUpdateCmd) Run(g *Globals, containerCmd *ContainerCmd) (err error) {
|
|
||||||
images, err := containerCmd.Containers()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
container.UseCache = false
|
|
||||||
container.UsePrebuilt = false
|
|
||||||
|
|
||||||
// TODO move from all commands to main command line handler
|
|
||||||
container.Commands = g.Config.Docker.Commands
|
|
||||||
container.Registry = g.Config.Docker.Registry
|
|
||||||
container.Timeout = g.Config.Docker.Timeout.Duration
|
|
||||||
|
|
||||||
for _, img := range images {
|
|
||||||
_, err = img.Distro.Packages()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,18 +52,13 @@ type ContainerSaveCmd struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cmd ContainerSaveCmd) Run(containerCmd *ContainerCmd) (err error) {
|
func (cmd ContainerSaveCmd) Run(containerCmd *ContainerCmd) (err error) {
|
||||||
images, err := containerCmd.Containers()
|
for _, name := range containerCmd.Containers() {
|
||||||
if err != nil {
|
nlog := log.With().Str("name", name).Logger()
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, img := range images {
|
output := filepath.Join(cmd.OutDir, name+".tar")
|
||||||
nlog := log.With().Str("name", img.Name).Logger()
|
|
||||||
|
|
||||||
output := filepath.Join(cmd.OutDir, img.Name+".tar")
|
|
||||||
nlog.Info().Msgf("saving to %v", output)
|
nlog.Info().Msgf("saving to %v", output)
|
||||||
|
|
||||||
err = container.Save(img.Name, output)
|
err = container.Save(name, output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -152,14 +81,9 @@ func (cmd ContainerSaveCmd) Run(containerCmd *ContainerCmd) (err error) {
|
|||||||
type ContainerCleanupCmd struct{}
|
type ContainerCleanupCmd struct{}
|
||||||
|
|
||||||
func (cmd ContainerCleanupCmd) Run(containerCmd *ContainerCmd) (err error) {
|
func (cmd ContainerCleanupCmd) Run(containerCmd *ContainerCmd) (err error) {
|
||||||
images, err := containerCmd.Containers()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var output []byte
|
var output []byte
|
||||||
for _, img := range images {
|
for _, name := range containerCmd.Containers() {
|
||||||
output, err = exec.Command(container.Runtime, "image", "rm", img.Name).
|
output, err = exec.Command(container.Runtime, "image", "rm", name).
|
||||||
CombinedOutput()
|
CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("output", string(output)).Msg("")
|
log.Error().Err(err).Str("output", string(output)).Msg("")
|
||||||
|
42
cmd/debug.go
42
cmd/debug.go
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Mikhail Klementev. All rights reserved.
|
// Copyright 2018 Mikhail Klementev. All rights reserved.
|
||||||
// Use of this source code is governed by a AGPLv3 license
|
// Use of this source code is governed by a AGPLv3 license
|
||||||
// (or later) that can be found in the LICENSE file.
|
// (or later) that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -22,10 +22,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DebugCmd struct {
|
type DebugCmd struct {
|
||||||
KernelRegex string `required:"" help:"set kernel regex"`
|
Kernel string `help:"regexp (first match)" required:""`
|
||||||
DistroID string `required:"" help:"set distribution"`
|
|
||||||
DistroRelease string `required:"" help:"set distribution release"`
|
|
||||||
|
|
||||||
Gdb string `help:"gdb listen address" default:"tcp::1234"`
|
Gdb string `help:"gdb listen address" default:"tcp::1234"`
|
||||||
|
|
||||||
SshAddr string `help:"ssh address to listen" default:"127.0.0.1"`
|
SshAddr string `help:"ssh address to listen" default:"127.0.0.1"`
|
||||||
@ -48,7 +45,7 @@ type DebugCmd struct {
|
|||||||
func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
||||||
kcfg, err := config.ReadKernelConfig(g.Config.Kernels)
|
kcfg, err := config.ReadKernelConfig(g.Config.Kernels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("read kernel config")
|
log.Print(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var configPath string
|
var configPath string
|
||||||
@ -66,17 +63,7 @@ func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
|||||||
ka.SourcePath = g.WorkDir
|
ka.SourcePath = g.WorkDir
|
||||||
}
|
}
|
||||||
|
|
||||||
var km artifact.Target
|
ki, err := firstSupported(kcfg, ka, cmd.Kernel)
|
||||||
km.Distro.ID, err = distro.NewID(cmd.DistroID)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
km.Distro.Release = cmd.DistroRelease
|
|
||||||
km.Kernel.Regex = cmd.KernelRegex
|
|
||||||
|
|
||||||
ka.Targets = []artifact.Target{km}
|
|
||||||
|
|
||||||
ki, err := firstSupported(kcfg, ka)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -174,14 +161,14 @@ func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
|||||||
// Module depends on one of the standard modules
|
// Module depends on one of the standard modules
|
||||||
err = artifact.CopyStandardModules(q, ki)
|
err = artifact.CopyStandardModules(q, ki)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("copy standard modules")
|
log.Print(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = artifact.PreloadModules(q, ka, ki, g.Config.Docker.Timeout.Duration)
|
err = artifact.PreloadModules(q, ka, ki, g.Config.Docker.Timeout.Duration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("preload modules")
|
log.Print(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,10 +180,9 @@ func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buildDir, outFile, output, err = artifact.Build(
|
buildDir, outFile, output, err = artifact.Build(log.Logger, tmp, ka, ki, g.Config.Docker.Timeout.Duration)
|
||||||
log.Logger, tmp, ka, ki, g.Config.Docker.Timeout.Duration, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg(output)
|
log.Print(err, output)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +206,7 @@ func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
|||||||
}
|
}
|
||||||
err = q.CopyFile(f.User, f.Local, f.Remote)
|
err = q.CopyFile(f.User, f.Local, f.Remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("copy %s -> %s", f.Local, f.Remote)
|
log.Print("error copy err:", err, f.Local, f.Remote)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +223,15 @@ func (cmd *DebugCmd) Run(g *Globals) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstSupported(kcfg config.KernelConfig, ka artifact.Artifact) (ki distro.KernelInfo, err error) {
|
func firstSupported(kcfg config.KernelConfig, ka artifact.Artifact,
|
||||||
|
kernel string) (ki distro.KernelInfo, err error) {
|
||||||
|
|
||||||
|
km, err := kernelMask(kernel)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ka.Targets = []artifact.Target{km}
|
||||||
|
|
||||||
for _, ki = range kcfg.Kernels {
|
for _, ki = range kcfg.Kernels {
|
||||||
var supported bool
|
var supported bool
|
||||||
|
@ -11,15 +11,18 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cavaliergopher/grab/v3"
|
||||||
"github.com/naoina/toml"
|
"github.com/naoina/toml"
|
||||||
"github.com/remeh/sizedwaitgroup"
|
"github.com/remeh/sizedwaitgroup"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"code.dumpstack.io/tools/out-of-tree/artifact"
|
"code.dumpstack.io/tools/out-of-tree/artifact"
|
||||||
|
"code.dumpstack.io/tools/out-of-tree/cache"
|
||||||
"code.dumpstack.io/tools/out-of-tree/config"
|
"code.dumpstack.io/tools/out-of-tree/config"
|
||||||
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
||||||
"code.dumpstack.io/tools/out-of-tree/container"
|
"code.dumpstack.io/tools/out-of-tree/container"
|
||||||
"code.dumpstack.io/tools/out-of-tree/distro"
|
"code.dumpstack.io/tools/out-of-tree/distro"
|
||||||
|
"code.dumpstack.io/tools/out-of-tree/fs"
|
||||||
"code.dumpstack.io/tools/out-of-tree/kernel"
|
"code.dumpstack.io/tools/out-of-tree/kernel"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,15 +35,13 @@ type KernelCmd struct {
|
|||||||
Retries int `help:"amount of tries for each kernel" default:"2"`
|
Retries int `help:"amount of tries for each kernel" default:"2"`
|
||||||
Threads int `help:"threads for parallel installation" default:"1"`
|
Threads int `help:"threads for parallel installation" default:"1"`
|
||||||
Update bool `help:"update container"`
|
Update bool `help:"update container"`
|
||||||
PrebuiltContainers bool `help:"try prebuilt container images first" default:"true" negatable:""`
|
ContainerCache bool `help:"try prebuilt container images first" default:"true" negatable:""`
|
||||||
Max int `help:"maximum kernels to download" default:"100500"`
|
Max int `help:"maximum kernels to download" default:"100500"`
|
||||||
NoPrune bool `help:"do not remove dangling or unused images from local storage after build"`
|
NoPrune bool `help:"do not remove dangling or unused images from local storage after build"`
|
||||||
NoCfgRegen bool `help:"do not update kernels.toml"`
|
NoCfgRegen bool `help:"do not update kernels.toml"`
|
||||||
|
|
||||||
ContainerTimeout time.Duration `help:"container timeout"`
|
ContainerTimeout time.Duration `help:"container timeout"`
|
||||||
|
|
||||||
RealtimeOutput RealtimeContainerOutputFlag `help:"show realtime output"`
|
|
||||||
|
|
||||||
List KernelListCmd `cmd:"" help:"list kernels"`
|
List KernelListCmd `cmd:"" help:"list kernels"`
|
||||||
ListRemote KernelListRemoteCmd `cmd:"" help:"list remote kernels"`
|
ListRemote KernelListRemoteCmd `cmd:"" help:"list remote kernels"`
|
||||||
Autogen KernelAutogenCmd `cmd:"" help:"generate kernels based on the current config"`
|
Autogen KernelAutogenCmd `cmd:"" help:"generate kernels based on the current config"`
|
||||||
@ -167,6 +168,33 @@ func (cmd *KernelCmd) GenKernel(km artifact.Target, pkg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cmd *KernelCmd) fetchContainerCache(c container.Container) {
|
||||||
|
if !cmd.ContainerCache {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if c.Exist() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp, err := fs.TempDir()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
resp, err := grab.Get(tmp, cache.ContainerURL(c.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.Remove(resp.Filename)
|
||||||
|
|
||||||
|
err = container.Load(resp.Filename, c.Name())
|
||||||
|
if err == nil {
|
||||||
|
log.Info().Msgf("use prebuilt container %s", c.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cmd *KernelCmd) Generate(g *Globals, km artifact.Target) (err error) {
|
func (cmd *KernelCmd) Generate(g *Globals, km artifact.Target) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -183,8 +211,6 @@ func (cmd *KernelCmd) Generate(g *Globals, km artifact.Target) (err error) {
|
|||||||
container.Prune = false
|
container.Prune = false
|
||||||
}
|
}
|
||||||
|
|
||||||
container.UsePrebuilt = cmd.PrebuiltContainers
|
|
||||||
|
|
||||||
cmd.kcfg, err = config.ReadKernelConfig(g.Config.Kernels)
|
cmd.kcfg, err = config.ReadKernelConfig(g.Config.Kernels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug().Err(err).Msg("read kernels config")
|
log.Debug().Err(err).Msg("read kernels config")
|
||||||
@ -204,6 +230,13 @@ func (cmd *KernelCmd) Generate(g *Globals, km artifact.Target) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c, err := container.New(km.Distro)
|
||||||
|
if err != nil || cmd.shutdown {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.fetchContainerCache(c)
|
||||||
|
|
||||||
pkgs, err := kernel.MatchPackages(km)
|
pkgs, err := kernel.MatchPackages(km)
|
||||||
if err != nil || cmd.shutdown {
|
if err != nil || cmd.shutdown {
|
||||||
return
|
return
|
||||||
@ -230,7 +263,7 @@ func (cmd *KernelCmd) Generate(g *Globals, km artifact.Target) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cmd.stats.success >= cmd.Max {
|
if cmd.stats.success >= cmd.Max {
|
||||||
log.Info().Msg("Max is reached")
|
log.Print("Max is reached")
|
||||||
swg.Done()
|
swg.Done()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -267,8 +300,8 @@ func (cmd *KernelListCmd) Run(g *Globals) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KernelListRemoteCmd struct {
|
type KernelListRemoteCmd struct {
|
||||||
DistroID string `required:"" help:"distribution"`
|
Distro string `required:"" help:"distribution"`
|
||||||
DistroRelease string `help:"distro version"`
|
Ver string `help:"distro version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *KernelListRemoteCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
func (cmd *KernelListRemoteCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
||||||
@ -279,15 +312,13 @@ func (cmd *KernelListRemoteCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error
|
|||||||
container.Prune = false
|
container.Prune = false
|
||||||
}
|
}
|
||||||
|
|
||||||
container.UsePrebuilt = kernelCmd.PrebuiltContainers
|
distroType, err := distro.NewID(cmd.Distro)
|
||||||
|
|
||||||
distroType, err := distro.NewID(cmd.DistroID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
km := artifact.Target{
|
km := artifact.Target{
|
||||||
Distro: distro.Distro{ID: distroType, Release: cmd.DistroRelease},
|
Distro: distro.Distro{ID: distroType, Release: cmd.Ver},
|
||||||
Kernel: artifact.Kernel{Regex: ".*"},
|
Kernel: artifact.Kernel{Regex: ".*"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,6 +330,13 @@ func (cmd *KernelListRemoteCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error
|
|||||||
container.Registry = g.Config.Docker.Registry
|
container.Registry = g.Config.Docker.Registry
|
||||||
container.Commands = g.Config.Docker.Commands
|
container.Commands = g.Config.Docker.Commands
|
||||||
|
|
||||||
|
c, err := container.New(km.Distro)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kernelCmd.fetchContainerCache(c)
|
||||||
|
|
||||||
pkgs, err := kernel.MatchPackages(km)
|
pkgs, err := kernel.MatchPackages(km)
|
||||||
// error check skipped on purpose
|
// error check skipped on purpose
|
||||||
|
|
||||||
@ -338,12 +376,12 @@ func (cmd *KernelAutogenCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KernelGenallCmd struct {
|
type KernelGenallCmd struct {
|
||||||
DistroID string `help:"distribution"`
|
Distro string `help:"distribution"`
|
||||||
DistroRelease string `help:"distro version"`
|
Ver string `help:"distro version"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *KernelGenallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
func (cmd *KernelGenallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
||||||
distroType, err := distro.NewID(cmd.DistroID)
|
distroType, err := distro.NewID(cmd.Distro)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -359,7 +397,7 @@ func (cmd *KernelGenallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.DistroRelease != "" && dist.Release != cmd.DistroRelease {
|
if cmd.Ver != "" && dist.Release != cmd.Ver {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,13 +416,13 @@ func (cmd *KernelGenallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KernelInstallCmd struct {
|
type KernelInstallCmd struct {
|
||||||
DistroID string `required:"" help:"distribution"`
|
Distro string `required:"" help:"distribution"`
|
||||||
DistroRelease string `required:"" help:"distro version"`
|
Ver string `required:"" help:"distro version"`
|
||||||
KernelRegex string `required:"" help:"kernel release mask"`
|
Kernel string `required:"" help:"kernel release mask"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *KernelInstallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
func (cmd *KernelInstallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
||||||
distroType, err := distro.NewID(cmd.DistroID)
|
distroType, err := distro.NewID(cmd.Distro)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -392,8 +430,8 @@ func (cmd *KernelInstallCmd) Run(kernelCmd *KernelCmd, g *Globals) (err error) {
|
|||||||
kernel.SetSigintHandler(&kernelCmd.shutdown)
|
kernel.SetSigintHandler(&kernelCmd.shutdown)
|
||||||
|
|
||||||
km := artifact.Target{
|
km := artifact.Target{
|
||||||
Distro: distro.Distro{ID: distroType, Release: cmd.DistroRelease},
|
Distro: distro.Distro{ID: distroType, Release: cmd.Ver},
|
||||||
Kernel: artifact.Kernel{Regex: cmd.KernelRegex},
|
Kernel: artifact.Kernel{Regex: cmd.Kernel},
|
||||||
}
|
}
|
||||||
err = kernelCmd.Generate(g, km)
|
err = kernelCmd.Generate(g, km)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
18
cmd/log.go
18
cmd/log.go
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Mikhail Klementev. All rights reserved.
|
// Copyright 2023 Mikhail Klementev. All rights reserved.
|
||||||
// Use of this source code is governed by a AGPLv3 license
|
// Use of this source code is governed by a AGPLv3 license
|
||||||
// (or later) that can be found in the LICENSE file.
|
// (or later) that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ func (cmd *LogQueryCmd) Run(g *Globals) (err error) {
|
|||||||
|
|
||||||
ka, kaErr := artifact.Artifact{}.Read(g.WorkDir + "/.out-of-tree.toml")
|
ka, kaErr := artifact.Artifact{}.Read(g.WorkDir + "/.out-of-tree.toml")
|
||||||
if kaErr == nil {
|
if kaErr == nil {
|
||||||
log.Debug().Msg(".out-of-tree.toml found, filter by artifact name")
|
log.Print(".out-of-tree.toml found, filter by artifact name")
|
||||||
les, err = getAllArtifactLogs(db, cmd.Tag, cmd.Num, ka)
|
les, err = getAllArtifactLogs(db, cmd.Tag, cmd.Num, ka)
|
||||||
} else {
|
} else {
|
||||||
les, err = getAllLogs(db, cmd.Tag, cmd.Num)
|
les, err = getAllLogs(db, cmd.Tag, cmd.Num)
|
||||||
@ -212,12 +212,7 @@ func center(s string, w int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func genOkFailCentered(name string, ok bool) (aurv aurora.Value) {
|
func genOkFailCentered(name string, ok bool) (aurv aurora.Value) {
|
||||||
if ok {
|
name = center(name, 10)
|
||||||
name += " OK"
|
|
||||||
} else {
|
|
||||||
name += " FAIL"
|
|
||||||
}
|
|
||||||
name = center(name, 14)
|
|
||||||
if ok {
|
if ok {
|
||||||
aurv = aurora.BgGreen(aurora.Black(name))
|
aurv = aurora.BgGreen(aurora.Black(name))
|
||||||
} else {
|
} else {
|
||||||
@ -230,7 +225,7 @@ func logLogEntry(l logEntry) {
|
|||||||
distroInfo := fmt.Sprintf("%s-%s {%s}", l.Distro.ID,
|
distroInfo := fmt.Sprintf("%s-%s {%s}", l.Distro.ID,
|
||||||
l.Distro.Release, l.KernelRelease)
|
l.Distro.Release, l.KernelRelease)
|
||||||
|
|
||||||
artifactInfo := fmt.Sprintf("%s", l.Name)
|
artifactInfo := fmt.Sprintf("{[%s] %s}", l.Type, l.Name)
|
||||||
|
|
||||||
timestamp := l.Timestamp.Format("2006-01-02 15:04")
|
timestamp := l.Timestamp.Format("2006-01-02 15:04")
|
||||||
|
|
||||||
@ -262,10 +257,7 @@ func logLogEntry(l logEntry) {
|
|||||||
additional = "(timeout)"
|
additional = "(timeout)"
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(distroInfo) > 40 {
|
colored := aurora.Sprintf("[%4d %4s] [%s] %s %-70s: %s %s",
|
||||||
distroInfo = distroInfo[:40]
|
|
||||||
}
|
|
||||||
colored := aurora.Sprintf("[%4d %4s] [%s] %s %-40s: %s %s",
|
|
||||||
l.ID, l.Tag, timestamp, artifactInfo, distroInfo, status,
|
l.ID, l.Tag, timestamp, artifactInfo, distroInfo, status,
|
||||||
additional)
|
additional)
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ type PackCmd struct {
|
|||||||
|
|
||||||
func (cmd *PackCmd) Run(g *Globals) (err error) {
|
func (cmd *PackCmd) Run(g *Globals) (err error) {
|
||||||
tag := fmt.Sprintf("pack_run_%d", time.Now().Unix())
|
tag := fmt.Sprintf("pack_run_%d", time.Now().Unix())
|
||||||
log.Info().Msgf("Tag: %s", tag)
|
log.Print("Tag:", tag)
|
||||||
|
|
||||||
files, err := os.ReadDir(g.WorkDir)
|
files, err := os.ReadDir(g.WorkDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -65,7 +65,7 @@ func (cmd *PackCmd) Run(g *Globals) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msg(f.Name())
|
log.Print(f.Name())
|
||||||
|
|
||||||
pew := PewCmd{
|
pew := PewCmd{
|
||||||
Max: cmd.KernelRuns,
|
Max: cmd.KernelRuns,
|
||||||
|
184
cmd/pew.go
184
cmd/pew.go
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Mikhail Klementev. All rights reserved.
|
// Copyright 2023 Mikhail Klementev. All rights reserved.
|
||||||
// Use of this source code is governed by a AGPLv3 license
|
// Use of this source code is governed by a AGPLv3 license
|
||||||
// (or later) that can be found in the LICENSE file.
|
// (or later) that can be found in the LICENSE file.
|
||||||
|
|
||||||
@ -12,7 +12,6 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -65,6 +64,7 @@ func successRate(state runstate) float64 {
|
|||||||
type PewCmd struct {
|
type PewCmd struct {
|
||||||
Max int64 `help:"test no more than X kernels" default:"100500"`
|
Max int64 `help:"test no more than X kernels" default:"100500"`
|
||||||
Runs int64 `help:"runs per each kernel" default:"1"`
|
Runs int64 `help:"runs per each kernel" default:"1"`
|
||||||
|
Kernel string `help:"override kernel regex"`
|
||||||
RootFS string `help:"override rootfs image" type:"existingfile"`
|
RootFS string `help:"override rootfs image" type:"existingfile"`
|
||||||
Guess bool `help:"try all defined kernels"`
|
Guess bool `help:"try all defined kernels"`
|
||||||
Shuffle bool `help:"randomize kernels test order"`
|
Shuffle bool `help:"randomize kernels test order"`
|
||||||
@ -75,10 +75,6 @@ type PewCmd struct {
|
|||||||
Tag string `help:"log tagging"`
|
Tag string `help:"log tagging"`
|
||||||
Timeout time.Duration `help:"timeout after tool will not spawn new tests"`
|
Timeout time.Duration `help:"timeout after tool will not spawn new tests"`
|
||||||
|
|
||||||
KernelRegex string `help:"set kernel regex"`
|
|
||||||
DistroID string `help:"set distribution"`
|
|
||||||
DistroRelease string `help:"set distribution release"`
|
|
||||||
|
|
||||||
ArtifactConfig string `help:"path to artifact config" type:"path"`
|
ArtifactConfig string `help:"path to artifact config" type:"path"`
|
||||||
|
|
||||||
QemuTimeout time.Duration `help:"timeout for qemu"`
|
QemuTimeout time.Duration `help:"timeout for qemu"`
|
||||||
@ -87,12 +83,6 @@ type PewCmd struct {
|
|||||||
|
|
||||||
Threshold float64 `help:"reliablity threshold for exit code" default:"1.00"`
|
Threshold float64 `help:"reliablity threshold for exit code" default:"1.00"`
|
||||||
IncludeInternalErrors bool `help:"count internal errors as part of the success rate"`
|
IncludeInternalErrors bool `help:"count internal errors as part of the success rate"`
|
||||||
InternalErrorsRetries int `help:"amount of retries on internal errors" default:"3"`
|
|
||||||
|
|
||||||
OutputOnSuccess bool `help:"show output on success"`
|
|
||||||
RealtimeOutput bool `help:"show realtime output"`
|
|
||||||
|
|
||||||
LogDir string `help:"write logs to directory"`
|
|
||||||
|
|
||||||
Endless bool `help:"endless tests"`
|
Endless bool `help:"endless tests"`
|
||||||
EndlessTimeout time.Duration `help:"timeout between tests" default:"1m"`
|
EndlessTimeout time.Duration `help:"timeout between tests" default:"1m"`
|
||||||
@ -168,11 +158,6 @@ func (cmd *PewCmd) Run(g *Globals) (err error) {
|
|||||||
cmd.useRemote = g.Remote
|
cmd.useRemote = g.Remote
|
||||||
cmd.remoteAddr = g.RemoteAddr
|
cmd.remoteAddr = g.RemoteAddr
|
||||||
|
|
||||||
if cmd.RealtimeOutput && cmd.Threads != 1 {
|
|
||||||
log.Warn().Msg("realtime output disables multithreading")
|
|
||||||
cmd.Threads = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.useRemote {
|
if cmd.useRemote {
|
||||||
c := client.Client{RemoteAddr: cmd.remoteAddr}
|
c := client.Client{RemoteAddr: cmd.remoteAddr}
|
||||||
cmd.Kcfg.Kernels, err = c.Kernels()
|
cmd.Kcfg.Kernels, err = c.Kernels()
|
||||||
@ -235,68 +220,32 @@ func (cmd *PewCmd) Run(g *Globals) (err error) {
|
|||||||
ka.SourcePath = g.WorkDir
|
ka.SourcePath = g.WorkDir
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.KernelRegex != "" {
|
if cmd.Kernel != "" {
|
||||||
var km artifact.Target
|
var km artifact.Target
|
||||||
km.Kernel.Regex = cmd.KernelRegex
|
km, err = kernelMask(cmd.Kernel)
|
||||||
|
|
||||||
if cmd.DistroID == "" {
|
|
||||||
err = errors.New("--distro-id is required")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var dt distro.ID
|
|
||||||
dt, err = distro.NewID(cmd.DistroID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
km.Distro.ID = dt
|
|
||||||
|
|
||||||
if cmd.DistroRelease != "" {
|
|
||||||
km.Distro.Release = cmd.DistroRelease
|
|
||||||
}
|
|
||||||
|
|
||||||
ka.Targets = []artifact.Target{km}
|
ka.Targets = []artifact.Target{km}
|
||||||
} else if cmd.DistroID != "" {
|
|
||||||
var km artifact.Target
|
|
||||||
|
|
||||||
var dt distro.ID
|
|
||||||
dt, err = distro.NewID(cmd.DistroID)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
km.Distro.ID = dt
|
// TODO there was a lib for merge structures
|
||||||
|
|
||||||
if cmd.DistroRelease != "" {
|
|
||||||
km.Distro.Release = cmd.DistroRelease
|
|
||||||
}
|
|
||||||
|
|
||||||
ka.Targets = []artifact.Target{km}
|
|
||||||
} else if cmd.DistroRelease != "" {
|
|
||||||
err = errors.New("--distro-release has no use on its own")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ka.Qemu.Timeout.Duration == 0 {
|
|
||||||
ka.Qemu.Timeout.Duration = g.Config.Qemu.Timeout.Duration
|
ka.Qemu.Timeout.Duration = g.Config.Qemu.Timeout.Duration
|
||||||
}
|
|
||||||
|
|
||||||
if ka.Docker.Timeout.Duration == 0 {
|
|
||||||
ka.Docker.Timeout.Duration = g.Config.Docker.Timeout.Duration
|
ka.Docker.Timeout.Duration = g.Config.Docker.Timeout.Duration
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.QemuTimeout != 0 {
|
if cmd.QemuTimeout != 0 {
|
||||||
|
log.Info().Msgf("Set qemu timeout to %s", cmd.QemuTimeout)
|
||||||
|
g.Config.Qemu.Timeout.Duration = cmd.QemuTimeout
|
||||||
ka.Qemu.Timeout.Duration = cmd.QemuTimeout
|
ka.Qemu.Timeout.Duration = cmd.QemuTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.DockerTimeout != 0 {
|
if cmd.DockerTimeout != 0 {
|
||||||
|
log.Info().Msgf("Set docker timeout to %s", cmd.DockerTimeout)
|
||||||
|
g.Config.Docker.Timeout.Duration = cmd.DockerTimeout
|
||||||
ka.Docker.Timeout.Duration = cmd.DockerTimeout
|
ka.Docker.Timeout.Duration = cmd.DockerTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Msgf("Qemu timeout: %s", ka.Qemu.Timeout.Duration)
|
|
||||||
log.Info().Msgf("Docker timeout: %s", ka.Docker.Timeout.Duration)
|
|
||||||
|
|
||||||
if cmd.Tag == "" {
|
if cmd.Tag == "" {
|
||||||
cmd.Tag = fmt.Sprintf("%d", time.Now().Unix())
|
cmd.Tag = fmt.Sprintf("%d", time.Now().Unix())
|
||||||
}
|
}
|
||||||
@ -412,9 +361,7 @@ func (cmd PewCmd) testArtifact(swg *sizedwaitgroup.SizedWaitGroup,
|
|||||||
|
|
||||||
defer swg.Done()
|
defer swg.Done()
|
||||||
|
|
||||||
var logDirWriter *zerolog.ConsoleWriter
|
logdir := "logs/" + cmd.Tag
|
||||||
if cmd.LogDir != "" {
|
|
||||||
logdir := filepath.Join(cmd.LogDir, cmd.Tag)
|
|
||||||
err := os.MkdirAll(logdir, os.ModePerm)
|
err := os.MkdirAll(logdir, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("mkdir %s", logdir)
|
log.Error().Err(err).Msgf("mkdir %s", logdir)
|
||||||
@ -434,32 +381,19 @@ func (cmd PewCmd) testArtifact(swg *sizedwaitgroup.SizedWaitGroup,
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
logDirWriter = &zerolog.ConsoleWriter{
|
slog := zerolog.New(zerolog.MultiLevelWriter(
|
||||||
|
&ConsoleWriter,
|
||||||
|
&FileWriter,
|
||||||
|
&zerolog.ConsoleWriter{
|
||||||
Out: f,
|
Out: f,
|
||||||
FieldsExclude: []string{
|
FieldsExclude: []string{
|
||||||
"distro_release",
|
"distro_release",
|
||||||
"distro_type",
|
"distro_type",
|
||||||
"kernel",
|
"kernel",
|
||||||
"command",
|
|
||||||
"workdir",
|
|
||||||
},
|
},
|
||||||
NoColor: true,
|
NoColor: true,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
|
|
||||||
var slog zerolog.Logger
|
|
||||||
if logDirWriter != nil {
|
|
||||||
slog = zerolog.New(zerolog.MultiLevelWriter(
|
|
||||||
&ConsoleWriter,
|
|
||||||
&FileWriter,
|
|
||||||
logDirWriter,
|
|
||||||
))
|
))
|
||||||
} else {
|
|
||||||
slog = zerolog.New(zerolog.MultiLevelWriter(
|
|
||||||
&ConsoleWriter,
|
|
||||||
&FileWriter,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch LogLevel {
|
switch LogLevel {
|
||||||
case zerolog.TraceLevel, zerolog.DebugLevel:
|
case zerolog.TraceLevel, zerolog.DebugLevel:
|
||||||
@ -472,33 +406,12 @@ func (cmd PewCmd) testArtifact(swg *sizedwaitgroup.SizedWaitGroup,
|
|||||||
Str("kernel", ki.KernelRelease).
|
Str("kernel", ki.KernelRelease).
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
retriesLeft := cmd.InternalErrorsRetries
|
ka.Process(slog, ki,
|
||||||
var stop bool
|
|
||||||
for !stop {
|
|
||||||
ka.Process(slog, ki, cmd.OutputOnSuccess, cmd.RealtimeOutput,
|
|
||||||
cmd.Endless, cmd.Binary, cmd.EndlessStress, cmd.EndlessTimeout,
|
cmd.Endless, cmd.Binary, cmd.EndlessStress, cmd.EndlessTimeout,
|
||||||
func(q *qemu.System, ka artifact.Artifact, ki distro.KernelInfo, res *artifact.Result) {
|
func(q *qemu.System, ka artifact.Artifact, ki distro.KernelInfo, result *artifact.Result) {
|
||||||
if res.InternalError == nil {
|
dumpResult(q, ka, ki, result, cmd.Dist, cmd.Tag, cmd.Binary, cmd.DB)
|
||||||
cmd.dumpResult(q, ka, ki, res)
|
|
||||||
stop = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
q.Log.Warn().Err(res.InternalError).
|
|
||||||
Str("panic", fmt.Sprintf("%v", q.KernelPanic)).
|
|
||||||
Str("timeout", fmt.Sprintf("%v", q.KilledByTimeout)).
|
|
||||||
Int("retries_left", retriesLeft).
|
|
||||||
Msg("internal")
|
|
||||||
|
|
||||||
if retriesLeft == 0 {
|
|
||||||
state.InternalErrors += 1
|
|
||||||
stop = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
retriesLeft -= 1
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func shuffleKernels(a []distro.KernelInfo) []distro.KernelInfo {
|
func shuffleKernels(a []distro.KernelInfo) []distro.KernelInfo {
|
||||||
@ -579,6 +492,25 @@ func (cmd PewCmd) performCI(ka artifact.Artifact) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func kernelMask(kernel string) (km artifact.Target, err error) {
|
||||||
|
parts := strings.Split(kernel, ":")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
err = errors.New("kernel is not 'distroType:regex'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dt, err := distro.NewID(parts[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
km = artifact.Target{
|
||||||
|
Distro: distro.Distro{ID: dt},
|
||||||
|
Kernel: artifact.Kernel{Regex: parts[1]},
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func genOkFail(name string, ok bool) (aurv aurora.Value) {
|
func genOkFail(name string, ok bool) (aurv aurora.Value) {
|
||||||
s := " " + name
|
s := " " + name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
@ -594,14 +526,27 @@ func genOkFail(name string, ok bool) (aurv aurora.Value) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd PewCmd) dumpResult(q *qemu.System, ka artifact.Artifact, ki distro.KernelInfo, res *artifact.Result) {
|
func dumpResult(q *qemu.System, ka artifact.Artifact, ki distro.KernelInfo,
|
||||||
|
res *artifact.Result, dist, tag, binary string, db *sql.DB) {
|
||||||
|
|
||||||
|
// TODO refactor
|
||||||
|
|
||||||
|
if res.InternalError != nil {
|
||||||
|
q.Log.Warn().Err(res.InternalError).
|
||||||
|
Str("panic", fmt.Sprintf("%v", q.KernelPanic)).
|
||||||
|
Str("timeout", fmt.Sprintf("%v", q.KilledByTimeout)).
|
||||||
|
Msg("internal")
|
||||||
|
res.InternalErrorString = res.InternalError.Error()
|
||||||
|
state.InternalErrors += 1
|
||||||
|
} else {
|
||||||
|
colored := ""
|
||||||
|
|
||||||
state.Overall += 1
|
state.Overall += 1
|
||||||
|
|
||||||
if res.Test.Ok {
|
if res.Test.Ok {
|
||||||
state.Success += 1
|
state.Success += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
colored := ""
|
|
||||||
switch ka.Type {
|
switch ka.Type {
|
||||||
case artifact.KernelExploit:
|
case artifact.KernelExploit:
|
||||||
colored = aurora.Sprintf("%s %s",
|
colored = aurora.Sprintf("%s %s",
|
||||||
@ -629,27 +574,20 @@ func (cmd PewCmd) dumpResult(q *qemu.System, ka artifact.Artifact, ki distro.Ker
|
|||||||
} else {
|
} else {
|
||||||
q.Log.Info().Msgf("%v", colored)
|
q.Log.Info().Msgf("%v", colored)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := addToLog(cmd.DB, q, ka, ki, res, cmd.Tag)
|
err := addToLog(db, q, ka, ki, res, tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.Log.Error().Err(err).Msgf("[db] addToLog (%v)", ka)
|
q.Log.Warn().Err(err).Msgf("[db] addToLog (%v)", ka)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Binary != "" {
|
if binary == "" && dist != pathDevNull {
|
||||||
return
|
err = os.MkdirAll(dist, os.ModePerm)
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.Dist == pathDevNull { // why?
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.MkdirAll(cmd.Dist, os.ModePerm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("os.MkdirAll (%v)", ka)
|
log.Warn().Err(err).Msgf("os.MkdirAll (%v)", ka)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("%s/%s-%s-%s", cmd.Dist, ki.Distro.ID,
|
path := fmt.Sprintf("%s/%s-%s-%s", dist, ki.Distro.ID,
|
||||||
ki.Distro.Release, ki.KernelRelease)
|
ki.Distro.Release, ki.KernelRelease)
|
||||||
if ka.Type != artifact.KernelExploit {
|
if ka.Type != artifact.KernelExploit {
|
||||||
path += ".ko"
|
path += ".ko"
|
||||||
@ -657,7 +595,7 @@ func (cmd PewCmd) dumpResult(q *qemu.System, ka artifact.Artifact, ki distro.Ker
|
|||||||
|
|
||||||
err = artifact.CopyFile(res.BuildArtifact, path)
|
err = artifact.CopyFile(res.BuildArtifact, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("copy file (%v)", ka)
|
log.Warn().Err(err).Msgf("copy file (%v)", ka)
|
||||||
return
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,12 +35,9 @@ type OutOfTree struct {
|
|||||||
Timeout artifact.Duration
|
Timeout artifact.Duration
|
||||||
Registry string
|
Registry string
|
||||||
|
|
||||||
// Commands that are executed before (prepend) and after (append) the
|
// Commands that will be executed before
|
||||||
// base layer of the Dockerfile.
|
// the base layer of Dockerfile
|
||||||
Commands struct {
|
Commands []distro.Command
|
||||||
Prepend []distro.Command
|
|
||||||
Append []distro.Command
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,17 +14,13 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cavaliergopher/grab/v3"
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"code.dumpstack.io/tools/out-of-tree/cache"
|
|
||||||
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
"code.dumpstack.io/tools/out-of-tree/config/dotfiles"
|
||||||
"code.dumpstack.io/tools/out-of-tree/distro"
|
"code.dumpstack.io/tools/out-of-tree/distro"
|
||||||
"code.dumpstack.io/tools/out-of-tree/fs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var Runtime = "docker"
|
var Runtime = "docker"
|
||||||
@ -33,21 +29,12 @@ var Registry = ""
|
|||||||
|
|
||||||
var Timeout time.Duration
|
var Timeout time.Duration
|
||||||
|
|
||||||
// Commands that are executed before (prepend) and after (append) the
|
var Commands []distro.Command
|
||||||
// base layer of the Dockerfile.
|
|
||||||
var Commands struct {
|
|
||||||
Prepend []distro.Command
|
|
||||||
Append []distro.Command
|
|
||||||
}
|
|
||||||
|
|
||||||
var UseCache = true
|
var UseCache = true
|
||||||
|
|
||||||
var UsePrebuilt = true
|
|
||||||
|
|
||||||
var Prune = true
|
var Prune = true
|
||||||
|
|
||||||
var Stdout = false
|
|
||||||
|
|
||||||
type Image struct {
|
type Image struct {
|
||||||
Name string
|
Name string
|
||||||
Distro distro.Distro
|
Distro distro.Distro
|
||||||
@ -105,25 +92,6 @@ func Load(localpath string, name string) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(Runtime, "docker") {
|
|
||||||
var err2 error
|
|
||||||
cmd = exec.Command(Runtime, "tag", "localhost/"+name, name)
|
|
||||||
log.Debug().Msgf("%v", cmd)
|
|
||||||
|
|
||||||
raw, err2 = cmd.CombinedOutput()
|
|
||||||
if err2 != nil {
|
|
||||||
log.Debug().Err(err2).Msg(string(raw))
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd = exec.Command(Runtime, "rmi", "localhost/"+name)
|
|
||||||
log.Debug().Msgf("%v", cmd)
|
|
||||||
|
|
||||||
raw, err2 = cmd.CombinedOutput()
|
|
||||||
if err2 != nil {
|
|
||||||
log.Debug().Err(err2).Msg(string(raw))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,15 +146,7 @@ type Container struct {
|
|||||||
// Additional arguments
|
// Additional arguments
|
||||||
Args []string
|
Args []string
|
||||||
|
|
||||||
// Base of container is local-only
|
|
||||||
LocalBase bool
|
|
||||||
|
|
||||||
Log zerolog.Logger
|
Log zerolog.Logger
|
||||||
|
|
||||||
commandsOutput struct {
|
|
||||||
listener chan string
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(dist distro.Distro) (c Container, err error) {
|
func New(dist distro.Distro) (c Container, err error) {
|
||||||
@ -245,43 +205,6 @@ func NewFromKernelInfo(ki distro.KernelInfo) (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// c.SetCommandsOutputHandler(func(s string) { fmt.Println(s) })
|
|
||||||
// defer c.CloseCommandsOutputHandler()
|
|
||||||
func (c *Container) SetCommandsOutputHandler(handler func(s string)) {
|
|
||||||
c.commandsOutput.mu.Lock()
|
|
||||||
defer c.commandsOutput.mu.Unlock()
|
|
||||||
|
|
||||||
c.commandsOutput.listener = make(chan string)
|
|
||||||
|
|
||||||
go func(l chan string) {
|
|
||||||
for m := range l {
|
|
||||||
if m != "" {
|
|
||||||
handler(m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(c.commandsOutput.listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) CloseCommandsOutputHandler() {
|
|
||||||
c.commandsOutput.mu.Lock()
|
|
||||||
defer c.commandsOutput.mu.Unlock()
|
|
||||||
|
|
||||||
close(c.commandsOutput.listener)
|
|
||||||
c.commandsOutput.listener = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Container) handleCommandsOutput(m string) {
|
|
||||||
if c.commandsOutput.listener == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.commandsOutput.mu.Lock()
|
|
||||||
defer c.commandsOutput.mu.Unlock()
|
|
||||||
|
|
||||||
if c.commandsOutput.listener != nil {
|
|
||||||
c.commandsOutput.listener <- m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Container) Name() string {
|
func (c Container) Name() string {
|
||||||
return c.name
|
return c.name
|
||||||
}
|
}
|
||||||
@ -308,38 +231,7 @@ func (c Container) Exist() (yes bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Container) loadPrebuilt() (err error) {
|
|
||||||
if c.Exist() && UseCache {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp, err := fs.TempDir()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tmp)
|
|
||||||
|
|
||||||
log.Info().Msgf("download prebuilt container %s", c.Name())
|
|
||||||
resp, err := grab.Get(tmp, cache.ContainerURL(c.Name()))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer os.Remove(resp.Filename)
|
|
||||||
|
|
||||||
err = Load(resp.Filename, c.Name())
|
|
||||||
if err == nil {
|
|
||||||
log.Info().Msgf("use prebuilt container %s", c.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Container) Build(image string, envs, runs []string) (err error) {
|
func (c Container) Build(image string, envs, runs []string) (err error) {
|
||||||
if c.Exist() && UseCache {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cdir := dotfiles.Dir("containers", c.name)
|
cdir := dotfiles.Dir("containers", c.name)
|
||||||
cfile := filepath.Join(cdir, "Dockerfile")
|
cfile := filepath.Join(cdir, "Dockerfile")
|
||||||
|
|
||||||
@ -349,15 +241,9 @@ func (c Container) Build(image string, envs, runs []string) (err error) {
|
|||||||
}
|
}
|
||||||
cf += image + "\n"
|
cf += image + "\n"
|
||||||
|
|
||||||
for _, cmd := range Commands.Prepend {
|
for _, c := range Commands {
|
||||||
if cmd.Distro.ID != distro.None && cmd.Distro.ID != c.dist.ID {
|
// TODO check for distro type
|
||||||
continue
|
cf += "RUN " + c.Command + "\n"
|
||||||
}
|
|
||||||
if cmd.Distro.Release != "" && cmd.Distro.Release != c.dist.Release {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
cf += "RUN " + cmd.Command + "\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range envs {
|
for _, e := range envs {
|
||||||
@ -368,17 +254,6 @@ func (c Container) Build(image string, envs, runs []string) (err error) {
|
|||||||
cf += "RUN " + c + "\n"
|
cf += "RUN " + c + "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cmd := range Commands.Append {
|
|
||||||
if cmd.Distro.ID != distro.None && cmd.Distro.ID != c.dist.ID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if cmd.Distro.Release != "" && cmd.Distro.Release != c.dist.Release {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
cf += "RUN " + cmd.Command + "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := os.ReadFile(cfile)
|
buf, err := os.ReadFile(cfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = os.WriteFile(cfile, []byte(cf), os.ModePerm)
|
err = os.WriteFile(cfile, []byte(cf), os.ModePerm)
|
||||||
@ -402,18 +277,11 @@ func (c Container) Build(image string, envs, runs []string) (err error) {
|
|||||||
c.Log.Info().Msg("build")
|
c.Log.Info().Msg("build")
|
||||||
}
|
}
|
||||||
|
|
||||||
if UsePrebuilt {
|
output, err := c.build(cdir)
|
||||||
err = c.loadPrebuilt()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil || !UsePrebuilt {
|
|
||||||
var output string
|
|
||||||
output, err = c.build(cdir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Log.Error().Err(err).Msg(output)
|
c.Log.Error().Err(err).Msg(output)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
c.Log.Info().Msg("success")
|
c.Log.Info().Msg("success")
|
||||||
return
|
return
|
||||||
@ -431,10 +299,7 @@ func (c Container) build(imagePath string) (output string, err error) {
|
|||||||
|
|
||||||
args := []string{"build"}
|
args := []string{"build"}
|
||||||
if !UseCache {
|
if !UseCache {
|
||||||
if !c.LocalBase {
|
args = append(args, "--pull", "--no-cache")
|
||||||
args = append(args, "--pull")
|
|
||||||
}
|
|
||||||
args = append(args, "--no-cache")
|
|
||||||
}
|
}
|
||||||
args = append(args, "-t", c.name, imagePath)
|
args = append(args, "-t", c.name, imagePath)
|
||||||
|
|
||||||
@ -459,10 +324,6 @@ func (c Container) build(imagePath string) (output string, err error) {
|
|||||||
scanner := bufio.NewScanner(stdout)
|
scanner := bufio.NewScanner(stdout)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
m := scanner.Text()
|
m := scanner.Text()
|
||||||
if Stdout {
|
|
||||||
fmt.Println(m)
|
|
||||||
}
|
|
||||||
c.handleCommandsOutput(m)
|
|
||||||
output += m + "\n"
|
output += m + "\n"
|
||||||
flog.Trace().Str("stdout", m).Msg("")
|
flog.Trace().Str("stdout", m).Msg("")
|
||||||
}
|
}
|
||||||
@ -472,7 +333,7 @@ func (c Container) build(imagePath string) (output string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) Run(workdir string, cmds []string) (out string, err error) {
|
func (c Container) Run(workdir string, cmds []string) (out string, err error) {
|
||||||
flog := c.Log.With().
|
flog := c.Log.With().
|
||||||
Str("workdir", workdir).
|
Str("workdir", workdir).
|
||||||
Str("command", fmt.Sprintf("%v", cmds)).
|
Str("command", fmt.Sprintf("%v", cmds)).
|
||||||
@ -536,17 +397,16 @@ func (c *Container) Run(workdir string, cmds []string) (out string, err error) {
|
|||||||
scanner := bufio.NewScanner(stdout)
|
scanner := bufio.NewScanner(stdout)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
m := scanner.Text()
|
m := scanner.Text()
|
||||||
if Stdout {
|
|
||||||
fmt.Println(m)
|
|
||||||
}
|
|
||||||
c.handleCommandsOutput(m)
|
|
||||||
out += m + "\n"
|
out += m + "\n"
|
||||||
flog.Trace().Str("container stdout", m).Msg("")
|
flog.Trace().Str("stdout", m).Msg("")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = cmd.Wait()
|
err = cmd.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
e := fmt.Sprintf("error `%v` for cmd `%v` with output `%v`",
|
||||||
|
err, cmds, out)
|
||||||
|
err = errors.New(e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ func (pj *jobProcessor) Process(res *Resources) (err error) {
|
|||||||
var result *artifact.Result
|
var result *artifact.Result
|
||||||
var dq *qemu.System
|
var dq *qemu.System
|
||||||
|
|
||||||
pj.job.Artifact.Process(pj.log, pj.job.Target, false, false, false, "", "", 0,
|
pj.job.Artifact.Process(pj.log, pj.job.Target, false, "", "", 0,
|
||||||
func(q *qemu.System, ka artifact.Artifact, ki distro.KernelInfo,
|
func(q *qemu.System, ka artifact.Artifact, ki distro.KernelInfo,
|
||||||
res *artifact.Result) {
|
res *artifact.Result) {
|
||||||
|
|
||||||
|
@ -37,10 +37,13 @@ func (centos CentOS) Packages() (pkgs []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Build("centos:"+centos.release, centos.envs(), centos.runs())
|
if !c.Exist() {
|
||||||
|
err = c.Build("centos:"+centos.release,
|
||||||
|
centos.envs(), centos.runs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd := "yum search kernel --showduplicates 2>/dev/null " +
|
cmd := "yum search kernel --showduplicates 2>/dev/null " +
|
||||||
"| grep '^kernel-[0-9]' " +
|
"| grep '^kernel-[0-9]' " +
|
||||||
@ -79,41 +82,36 @@ func (centos CentOS) runs() (commands []string) {
|
|||||||
// TODO refactor
|
// TODO refactor
|
||||||
switch centos.release {
|
switch centos.release {
|
||||||
case "6":
|
case "6":
|
||||||
repofmt := "[6.%d-%s]\\n" +
|
repofmt := "[6.%d-%s]\\nbaseurl=https://vault.centos.org/6.%d/%s/$basearch/\\ngpgcheck=0"
|
||||||
"name=CentOS-6.%d - %s\\n" +
|
|
||||||
"baseurl=https://vault.centos.org/6.%d/%s/$basearch/\\n" +
|
|
||||||
"gpgcheck=0"
|
|
||||||
for i := 0; i <= 10; i++ {
|
for i := 0; i <= 10; i++ {
|
||||||
repos = append(repos, fmt.Sprintf(repofmt, i, "os", i, "os", i, "os"))
|
repos = append(repos, fmt.Sprintf(repofmt, i, "os", i, "os"))
|
||||||
repos = append(repos, fmt.Sprintf(repofmt, i, "updates", i, "updates", i, "updates"))
|
repos = append(repos, fmt.Sprintf(repofmt, i, "updates", i, "updates"))
|
||||||
}
|
}
|
||||||
cmdf("rm /etc/yum.repos.d/*")
|
cmdf("rm /etc/yum.repos.d/*")
|
||||||
case "7":
|
case "7":
|
||||||
repofmt := "[%s-%s]\\n" +
|
repofmt := "[%s-%s]\\nbaseurl=https://vault.centos.org/%s/%s/$basearch/\\ngpgcheck=0"
|
||||||
"name=CentOS-%s - %s\\n" +
|
|
||||||
"baseurl=https://vault.centos.org/%s/%s/$basearch/\\n" +
|
|
||||||
"gpgcheck=0"
|
|
||||||
for _, ver := range []string{
|
for _, ver := range []string{
|
||||||
"7.0.1406", "7.1.1503", "7.2.1511",
|
"7.0.1406", "7.1.1503", "7.2.1511",
|
||||||
"7.3.1611", "7.4.1708", "7.5.1804",
|
"7.3.1611", "7.4.1708", "7.5.1804",
|
||||||
"7.6.1810", "7.7.1908", "7.8.2003",
|
"7.6.1810", "7.7.1908", "7.8.2003",
|
||||||
"7.9.2009",
|
|
||||||
} {
|
} {
|
||||||
repos = append(repos, fmt.Sprintf(repofmt, ver, "os", ver, "os", ver, "os"))
|
repos = append(repos, fmt.Sprintf(repofmt, ver, "os", ver, "os"))
|
||||||
repos = append(repos, fmt.Sprintf(repofmt, ver, "updates", ver, "updates", ver, "updates"))
|
repos = append(repos, fmt.Sprintf(repofmt, ver, "updates", ver, "updates"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME http/gpgcheck=0
|
||||||
|
repofmt = "[%s-%s]\\nbaseurl=http://mirror.centos.org/centos-7/%s/%s/$basearch/\\ngpgcheck=0"
|
||||||
|
repos = append(repos, fmt.Sprintf(repofmt, "7.9.2009", "os", "7.9.2009", "os"))
|
||||||
|
repos = append(repos, fmt.Sprintf(repofmt, "7.9.2009", "updates", "7.9.2009", "updates"))
|
||||||
case "8":
|
case "8":
|
||||||
repofmt := "[%s-%s]\\n" +
|
repofmt := "[%s-%s]\\nbaseurl=https://vault.centos.org/%s/%s/$basearch/os/\\ngpgcheck=0"
|
||||||
"name=CentOS-%s - %s\\n" +
|
|
||||||
"baseurl=https://vault.centos.org/%s/%s/$basearch/os/\\n" +
|
|
||||||
"gpgcheck=0"
|
|
||||||
|
|
||||||
for _, ver := range []string{
|
for _, ver := range []string{
|
||||||
"8.0.1905", "8.1.1911", "8.2.2004",
|
"8.0.1905", "8.1.1911", "8.2.2004",
|
||||||
"8.3.2011", "8.4.2105", "8.5.2111",
|
"8.3.2011", "8.4.2105", "8.5.2111",
|
||||||
} {
|
} {
|
||||||
repos = append(repos, fmt.Sprintf(repofmt, ver, "baseos", ver, "baseos", ver, "BaseOS"))
|
repos = append(repos, fmt.Sprintf(repofmt, ver, "baseos", ver, "BaseOS"))
|
||||||
repos = append(repos, fmt.Sprintf(repofmt, ver, "appstream", ver, "appstream", ver, "AppStream"))
|
repos = append(repos, fmt.Sprintf(repofmt, ver, "appstream", ver, "AppStream"))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Fatal().Msgf("no support for centos %s", centos.release)
|
log.Fatal().Msgf("no support for centos %s", centos.release)
|
||||||
@ -121,7 +119,6 @@ func (centos CentOS) runs() (commands []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmdf("sed -i 's/enabled=1/enabled=0/' /etc/yum.repos.d/* || true")
|
cmdf("sed -i 's/enabled=1/enabled=0/' /etc/yum.repos.d/* || true")
|
||||||
cmdf("sed -i 's/name/enabled=0\\nname/' /etc/yum.repos.d/* || true")
|
|
||||||
|
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
cmdf("echo -e '%s' >> /etc/yum.repos.d/oot.repo\n", repo)
|
cmdf("echo -e '%s' >> /etc/yum.repos.d/oot.repo\n", repo)
|
||||||
|
@ -54,10 +54,12 @@ func (d Debian) Packages() (packages []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !c.Exist() {
|
||||||
err = c.Build(d.image(), d.envs(), d.runs())
|
err = c.Build(d.image(), d.envs(), d.runs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kernels, err := GetKernels()
|
kernels, err := GetKernels()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -57,8 +57,6 @@ func (suse OpenSUSE) Packages() (pkgs []string, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.LocalBase = true
|
|
||||||
|
|
||||||
} else if strings.HasPrefix(suse.release, "13") {
|
} else if strings.HasPrefix(suse.release, "13") {
|
||||||
name = "opensuse:13"
|
name = "opensuse:13"
|
||||||
cnturl := cache.ContainerURL("openSUSE-13.2")
|
cnturl := cache.ContainerURL("openSUSE-13.2")
|
||||||
@ -66,18 +64,18 @@ func (suse OpenSUSE) Packages() (pkgs []string, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.LocalBase = true
|
|
||||||
|
|
||||||
} else if strings.HasPrefix(suse.release, "42") {
|
} else if strings.HasPrefix(suse.release, "42") {
|
||||||
name = "opensuse/leap:42"
|
name = "opensuse/leap:42"
|
||||||
} else if strings.HasPrefix(suse.release, "15") {
|
} else if strings.HasPrefix(suse.release, "15") {
|
||||||
name = "opensuse/leap:" + suse.release
|
name = "opensuse/leap:" + suse.release
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !c.Exist() {
|
||||||
err = c.Build(name, suse.envs(), suse.runs())
|
err = c.Build(name, suse.envs(), suse.runs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd := "zypper search -s --match-exact kernel-default | grep x86_64 " +
|
cmd := "zypper search -s --match-exact kernel-default | grep x86_64 " +
|
||||||
"| cut -d '|' -f 4 | sed 's/ //g'"
|
"| cut -d '|' -f 4 | sed 's/ //g'"
|
||||||
@ -87,32 +85,7 @@ func (suse OpenSUSE) Packages() (pkgs []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Find a way for non-interactive installation of
|
pkgs = append(pkgs, strings.Fields(output)...)
|
||||||
// retracted kernels
|
|
||||||
retracted := []string{
|
|
||||||
"5.14.21-150400.24.49.3",
|
|
||||||
"5.14.21-150400.24.84.1",
|
|
||||||
"5.14.21-150500.55.22.1",
|
|
||||||
"5.3.18-150300.59.81.1",
|
|
||||||
"5.3.18-59.30.1",
|
|
||||||
"5.3.18-lp152.98.1",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k := range strings.Fields(output) {
|
|
||||||
skip := false
|
|
||||||
for _, rk := range retracted {
|
|
||||||
if rk == k {
|
|
||||||
skip = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if skip {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgs = append(pkgs, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +38,13 @@ func (ol OracleLinux) Packages() (pkgs []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.Build("oraclelinux:"+ol.release, ol.envs(), ol.runs())
|
if !c.Exist() {
|
||||||
|
err = c.Build("oraclelinux:"+ol.release,
|
||||||
|
ol.envs(), ol.runs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ol.release == "8" {
|
if ol.release == "8" {
|
||||||
// Image for ol9 is required for some kernels
|
// Image for ol9 is required for some kernels
|
||||||
|
@ -17,7 +17,6 @@ func init() {
|
|||||||
"18.04",
|
"18.04",
|
||||||
"20.04",
|
"20.04",
|
||||||
"22.04",
|
"22.04",
|
||||||
"24.04",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, release := range releases {
|
for _, release := range releases {
|
||||||
@ -43,10 +42,12 @@ func (u Ubuntu) Packages() (pkgs []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !c.Exist() {
|
||||||
err = c.Build("ubuntu:"+u.release, u.envs(), u.runs())
|
err = c.Build("ubuntu:"+u.release, u.envs(), u.runs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd := "apt-cache search " +
|
cmd := "apt-cache search " +
|
||||||
"--names-only '^linux-image-[0-9\\.\\-]*-generic$' " +
|
"--names-only '^linux-image-[0-9\\.\\-]*-generic$' " +
|
||||||
|
@ -34,7 +34,7 @@ func GenHostKernels(download bool) (kernels []distro.KernelInfo, err error) {
|
|||||||
|
|
||||||
rawOutput, err := cmd.CombinedOutput()
|
rawOutput, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg(string(rawOutput))
|
log.Print(string(rawOutput), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ func GenHostKernels(download bool) (kernels []distro.KernelInfo, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vmlinux := "/usr/lib/debug/boot/vmlinux-" + krel
|
vmlinux := "/usr/lib/debug/boot/vmlinux-" + krel
|
||||||
log.Info().Msgf("vmlinux %s", vmlinux)
|
log.Print("vmlinux", vmlinux)
|
||||||
if fs.PathExists(vmlinux) {
|
if fs.PathExists(vmlinux) {
|
||||||
ki.VmlinuxPath = vmlinux
|
ki.VmlinuxPath = vmlinux
|
||||||
}
|
}
|
||||||
|
6
main.go
6
main.go
@ -35,13 +35,13 @@ type CLI struct {
|
|||||||
cmd.Globals
|
cmd.Globals
|
||||||
|
|
||||||
Pew cmd.PewCmd `cmd:"" help:"build, run, and test module/exploit"`
|
Pew cmd.PewCmd `cmd:"" help:"build, run, and test module/exploit"`
|
||||||
Kernel cmd.KernelCmd `cmd:"" aliases:"kernels" help:"manipulate kernels"`
|
Kernel cmd.KernelCmd `cmd:"" help:"manipulate kernels"`
|
||||||
Debug cmd.DebugCmd `cmd:"" help:"debug environment"`
|
Debug cmd.DebugCmd `cmd:"" help:"debug environment"`
|
||||||
Log cmd.LogCmd `cmd:"" help:"query logs"`
|
Log cmd.LogCmd `cmd:"" help:"query logs"`
|
||||||
Pack cmd.PackCmd `cmd:"" help:"exploit pack test"`
|
Pack cmd.PackCmd `cmd:"" help:"exploit pack test"`
|
||||||
Gen cmd.GenCmd `cmd:"" help:"generate .out-of-tree.toml skeleton"`
|
Gen cmd.GenCmd `cmd:"" help:"generate .out-of-tree.toml skeleton"`
|
||||||
Image cmd.ImageCmd `cmd:"" aliases:"images" help:"manage images"`
|
Image cmd.ImageCmd `cmd:"" help:"manage images"`
|
||||||
Container cmd.ContainerCmd `cmd:"" aliases:"containers" help:"manage containers"`
|
Container cmd.ContainerCmd `cmd:"" help:"manage containers"`
|
||||||
Distro cmd.DistroCmd `cmd:"" help:"distro-related helpers"`
|
Distro cmd.DistroCmd `cmd:"" help:"distro-related helpers"`
|
||||||
|
|
||||||
Daemon cmd.DaemonCmd `cmd:"" help:"run daemon"`
|
Daemon cmd.DaemonCmd `cmd:"" help:"run daemon"`
|
||||||
|
@ -101,16 +101,6 @@ type System struct {
|
|||||||
|
|
||||||
Stdout, Stderr string
|
Stdout, Stderr string
|
||||||
|
|
||||||
qemuOutput struct {
|
|
||||||
listener chan string
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
commandsOutput struct {
|
|
||||||
listener chan string
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// accessible after qemu is closed
|
// accessible after qemu is closed
|
||||||
exitErr error
|
exitErr error
|
||||||
|
|
||||||
@ -148,80 +138,6 @@ func NewSystem(arch arch, kernel Kernel, drivePath string) (q *System, err error
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// q.SetQemuOutputHandler(func(s string) { fmt.Println(s) })
|
|
||||||
// defer q.CloseQemuOutputHandler()
|
|
||||||
func (q *System) SetQemuOutputHandler(handler func(s string)) {
|
|
||||||
q.qemuOutput.mu.Lock()
|
|
||||||
defer q.qemuOutput.mu.Unlock()
|
|
||||||
|
|
||||||
q.qemuOutput.listener = make(chan string)
|
|
||||||
|
|
||||||
go func(l chan string) {
|
|
||||||
for m := range l {
|
|
||||||
if m != "" {
|
|
||||||
handler(m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(q.qemuOutput.listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *System) CloseQemuOutputHandler() {
|
|
||||||
q.qemuOutput.mu.Lock()
|
|
||||||
defer q.qemuOutput.mu.Unlock()
|
|
||||||
|
|
||||||
close(q.qemuOutput.listener)
|
|
||||||
q.qemuOutput.listener = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *System) handleQemuOutput(m string) {
|
|
||||||
if q.qemuOutput.listener == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
q.qemuOutput.mu.Lock()
|
|
||||||
defer q.qemuOutput.mu.Unlock()
|
|
||||||
|
|
||||||
if q.qemuOutput.listener != nil {
|
|
||||||
q.qemuOutput.listener <- m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// q.SetCommandsOutputHandler(func(s string) { fmt.Println(s) })
|
|
||||||
// defer q.CloseCommandsOutputHandler()
|
|
||||||
func (q *System) SetCommandsOutputHandler(handler func(s string)) {
|
|
||||||
q.commandsOutput.mu.Lock()
|
|
||||||
defer q.commandsOutput.mu.Unlock()
|
|
||||||
|
|
||||||
q.commandsOutput.listener = make(chan string)
|
|
||||||
|
|
||||||
go func(l chan string) {
|
|
||||||
for m := range l {
|
|
||||||
if m != "" {
|
|
||||||
handler(m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(q.commandsOutput.listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *System) CloseCommandsOutputHandler() {
|
|
||||||
q.commandsOutput.mu.Lock()
|
|
||||||
defer q.commandsOutput.mu.Unlock()
|
|
||||||
|
|
||||||
close(q.commandsOutput.listener)
|
|
||||||
q.commandsOutput.listener = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *System) handleCommandsOutput(m string) {
|
|
||||||
if q.commandsOutput.listener == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
q.commandsOutput.mu.Lock()
|
|
||||||
defer q.commandsOutput.mu.Unlock()
|
|
||||||
|
|
||||||
if q.commandsOutput.listener != nil {
|
|
||||||
q.commandsOutput.listener <- m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *System) SetSSHAddrPort(addr string, port int) (err error) {
|
func (q *System) SetSSHAddrPort(addr string, port int) (err error) {
|
||||||
// TODO validate
|
// TODO validate
|
||||||
q.SSH.AddrPort = fmt.Sprintf("%s:%d", addr, port)
|
q.SSH.AddrPort = fmt.Sprintf("%s:%d", addr, port)
|
||||||
@ -396,8 +312,7 @@ func (q *System) Start() (err error) {
|
|||||||
go func() {
|
go func() {
|
||||||
scanner := bufio.NewScanner(q.pipe.stdout)
|
scanner := bufio.NewScanner(q.pipe.stdout)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
m := strings.TrimSpace(scanner.Text())
|
m := scanner.Text()
|
||||||
q.handleQemuOutput(m)
|
|
||||||
q.Stdout += m + "\n"
|
q.Stdout += m + "\n"
|
||||||
q.Log.Trace().Str("stdout", m).Msg("qemu")
|
q.Log.Trace().Str("stdout", m).Msg("qemu")
|
||||||
go q.checkOopsPanic(m)
|
go q.checkOopsPanic(m)
|
||||||
@ -407,8 +322,7 @@ func (q *System) Start() (err error) {
|
|||||||
go func() {
|
go func() {
|
||||||
scanner := bufio.NewScanner(q.pipe.stderr)
|
scanner := bufio.NewScanner(q.pipe.stderr)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
m := strings.TrimSpace(scanner.Text())
|
m := scanner.Text()
|
||||||
q.handleQemuOutput(m)
|
|
||||||
q.Stderr += m + "\n"
|
q.Stderr += m + "\n"
|
||||||
q.Log.Trace().Str("stderr", m).Msg("qemu")
|
q.Log.Trace().Str("stderr", m).Msg("qemu")
|
||||||
}
|
}
|
||||||
@ -428,7 +342,6 @@ func (q *System) Start() (err error) {
|
|||||||
|
|
||||||
if q.Timeout != 0 {
|
if q.Timeout != 0 {
|
||||||
go func() {
|
go func() {
|
||||||
q.Log.Debug().Msgf("qemu wait for %s before kill", q.Timeout)
|
|
||||||
time.Sleep(q.Timeout)
|
time.Sleep(q.Timeout)
|
||||||
q.KilledByTimeout = true
|
q.KilledByTimeout = true
|
||||||
q.Stop()
|
q.Stop()
|
||||||
@ -560,8 +473,7 @@ func (q System) Command(user, cmd string) (output string, err error) {
|
|||||||
|
|
||||||
scanner := bufio.NewScanner(stdout)
|
scanner := bufio.NewScanner(stdout)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
m := strings.TrimSpace(scanner.Text())
|
m := scanner.Text()
|
||||||
q.handleCommandsOutput(m)
|
|
||||||
output += m + "\n"
|
output += m + "\n"
|
||||||
flog.Trace().Str("stdout", m).Msg("qemu command")
|
flog.Trace().Str("stdout", m).Msg("qemu command")
|
||||||
}
|
}
|
||||||
@ -574,8 +486,7 @@ func (q System) Command(user, cmd string) (output string, err error) {
|
|||||||
|
|
||||||
scanner := bufio.NewScanner(stderr)
|
scanner := bufio.NewScanner(stderr)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
m := strings.TrimSpace(scanner.Text())
|
m := scanner.Text()
|
||||||
q.handleCommandsOutput(m)
|
|
||||||
output += m + "\n"
|
output += m + "\n"
|
||||||
// Note: it prints stderr as stdout
|
// Note: it prints stderr as stdout
|
||||||
flog.Trace().Str("stdout", m).Msg("qemu command")
|
flog.Trace().Str("stdout", m).Msg("qemu command")
|
||||||
|
@ -28,8 +28,6 @@ RUN sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config
|
|||||||
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/UseDNS/d' $TMPDIR/etc/ssh/sshd_config
|
|
||||||
RUN echo UseDNS no >> $TMPDIR/etc/ssh/sshd_config
|
|
||||||
|
|
||||||
# network workaround
|
# network workaround
|
||||||
RUN chmod +x $TMPDIR/etc/rc.local
|
RUN chmod +x $TMPDIR/etc/rc.local
|
||||||
|
@ -4,6 +4,6 @@ set -eux
|
|||||||
|
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
sudo podman build -t gen-centos6-image .
|
sudo docker build -t gen-centos6-image .
|
||||||
sudo podman run --privileged -v $(pwd):/shared -t gen-centos6-image
|
sudo docker run --privileged -v $(pwd):/shared -t gen-centos6-image
|
||||||
tar -Szcf out_of_tree_centos_6.img.tar.gz out_of_tree_centos_6.img
|
tar -Szcf out_of_tree_centos_6.img.tar.gz out_of_tree_centos_6.img
|
||||||
|
@ -13,11 +13,6 @@
|
|||||||
#
|
#
|
||||||
FROM centos:7
|
FROM centos:7
|
||||||
|
|
||||||
RUN sed -i 's/enabled=1/enabled=0/' /etc/yum.repos.d/* || true
|
|
||||||
RUN sed -i 's/name/enabled=0\nname/' /etc/yum.repos.d/* || true
|
|
||||||
RUN echo -e '[7.9.2009-os]\nbaseurl=https://vault.centos.org/7.9.2009/os/$basearch/\ngpgcheck=0' >> /etc/yum.repos.d/oot.repo
|
|
||||||
RUN echo -e '[7.9.2009-updates]\nbaseurl=https://vault.centos.org/7.9.2009/updates/$basearch/\ngpgcheck=0' >> /etc/yum.repos.d/oot.repo
|
|
||||||
|
|
||||||
RUN yum -y update
|
RUN yum -y update
|
||||||
RUN yum -y groupinstall "Development Tools"
|
RUN yum -y groupinstall "Development Tools"
|
||||||
RUN yum -y install qemu-img e2fsprogs
|
RUN yum -y install qemu-img e2fsprogs
|
||||||
@ -26,13 +21,13 @@ ENV TMPDIR=/tmp/centos
|
|||||||
|
|
||||||
RUN yum --installroot=$TMPDIR \
|
RUN yum --installroot=$TMPDIR \
|
||||||
--releasever=7 \
|
--releasever=7 \
|
||||||
|
--disablerepo='*' \
|
||||||
|
--enablerepo=base \
|
||||||
-y groupinstall Base
|
-y groupinstall Base
|
||||||
|
|
||||||
RUN rm $TMPDIR/etc/yum.repos.d/*
|
|
||||||
RUN cp /etc/yum.repos.d/* $TMPDIR/etc/yum.repos.d/
|
|
||||||
|
|
||||||
RUN yum --installroot=$TMPDIR \
|
RUN yum --installroot=$TMPDIR \
|
||||||
--releasever=7 \
|
--releasever=7 \
|
||||||
|
--disablerepo='*' \
|
||||||
|
--enablerepo=base \
|
||||||
-y install openssh-server openssh-clients
|
-y install openssh-server openssh-clients
|
||||||
|
|
||||||
RUN chroot $TMPDIR /bin/sh -c 'useradd -m user'
|
RUN chroot $TMPDIR /bin/sh -c 'useradd -m user'
|
||||||
@ -42,8 +37,6 @@ RUN sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config
|
|||||||
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/UseDNS/d' $TMPDIR/etc/ssh/sshd_config
|
|
||||||
RUN echo UseDNS no >> $TMPDIR/etc/ssh/sshd_config
|
|
||||||
|
|
||||||
# network workaround
|
# network workaround
|
||||||
RUN chmod +x $TMPDIR/etc/rc.local
|
RUN chmod +x $TMPDIR/etc/rc.local
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -eux
|
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
sudo podman build -t gen-centos7-image .
|
|
||||||
sudo podman run --privileged -v $(pwd):/shared -t gen-centos7-image
|
|
||||||
tar -Szcf out_of_tree_centos_7.img.tar.gz out_of_tree_centos_7.img
|
|
@ -28,8 +28,6 @@ RUN sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config
|
|||||||
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/UseDNS/d' $TMPDIR/etc/ssh/sshd_config
|
|
||||||
RUN echo UseDNS no >> $TMPDIR/etc/ssh/sshd_config
|
|
||||||
|
|
||||||
# network workaround
|
# network workaround
|
||||||
RUN chmod +x $TMPDIR/etc/rc.local
|
RUN chmod +x $TMPDIR/etc/rc.local
|
||||||
|
@ -4,6 +4,6 @@ set -eux
|
|||||||
|
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
sudo podman build -t gen-centos8-image .
|
sudo docker build -t gen-centos8-image .
|
||||||
sudo podman run --privileged -v $(pwd):/shared -t gen-centos8-image
|
sudo docker run --privileged -v $(pwd):/shared -t gen-centos8-image
|
||||||
tar -Szcf out_of_tree_centos_8.img.tar.gz out_of_tree_centos_8.img
|
tar -Szcf out_of_tree_centos_8.img.tar.gz out_of_tree_centos_8.img
|
||||||
|
@ -11,8 +11,6 @@ sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config
|
|||||||
echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
sed -i '/UseDNS/d' $TMPDIR/etc/ssh/sshd_config
|
|
||||||
echo UseDNS no >> $TMPDIR/etc/ssh/sshd_config
|
|
||||||
|
|
||||||
echo '#!/bin/sh' > $TMPDIR/etc/rc.local
|
echo '#!/bin/sh' > $TMPDIR/etc/rc.local
|
||||||
echo 'dhclient' >> $TMPDIR/etc/rc.local
|
echo 'dhclient' >> $TMPDIR/etc/rc.local
|
||||||
|
@ -13,7 +13,6 @@ RUN yum --installroot=$TMPDIR \
|
|||||||
--releasever=_VERSION_ \
|
--releasever=_VERSION_ \
|
||||||
--disablerepo='*' \
|
--disablerepo='*' \
|
||||||
--enablerepo=ol_VERSION__baseos_latest \
|
--enablerepo=ol_VERSION__baseos_latest \
|
||||||
--enablerepo=ol_VERSION__appstream \
|
|
||||||
-y groupinstall Base
|
-y groupinstall Base
|
||||||
|
|
||||||
RUN cp /etc/yum.repos.d/* $TMPDIR/etc/yum.repos.d/
|
RUN cp /etc/yum.repos.d/* $TMPDIR/etc/yum.repos.d/
|
||||||
@ -22,7 +21,6 @@ RUN yum --installroot=$TMPDIR \
|
|||||||
--releasever=_VERSION_ \
|
--releasever=_VERSION_ \
|
||||||
--disablerepo='*' \
|
--disablerepo='*' \
|
||||||
--enablerepo=ol_VERSION__baseos_latest \
|
--enablerepo=ol_VERSION__baseos_latest \
|
||||||
--enablerepo=ol_VERSION__appstream \
|
|
||||||
-y install openssh-server openssh-clients dhclient yum
|
-y install openssh-server openssh-clients dhclient yum
|
||||||
|
|
||||||
RUN chroot $TMPDIR /bin/sh -c 'useradd -m user'
|
RUN chroot $TMPDIR /bin/sh -c 'useradd -m user'
|
||||||
@ -32,8 +30,6 @@ RUN sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config
|
|||||||
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
RUN sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
RUN echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
RUN sed -i '/UseDNS/d' $TMPDIR/etc/ssh/sshd_config
|
|
||||||
RUN echo UseDNS no >> $TMPDIR/etc/ssh/sshd_config
|
|
||||||
|
|
||||||
# network workaround
|
# network workaround
|
||||||
RUN chmod +x $TMPDIR/etc/rc.local
|
RUN chmod +x $TMPDIR/etc/rc.local
|
||||||
|
@ -11,11 +11,9 @@ for version in 6 7 8 9; do
|
|||||||
|
|
||||||
if [[ $version -eq 6 ]]; then
|
if [[ $version -eq 6 ]]; then
|
||||||
sed -i 's/baseos_latest/u10_base/' $version/Dockerfile
|
sed -i 's/baseos_latest/u10_base/' $version/Dockerfile
|
||||||
sed -i '/appstream/d' $version/Dockerfile
|
|
||||||
fi
|
fi
|
||||||
if [[ $version -eq 7 ]]; then
|
if [[ $version -eq 7 ]]; then
|
||||||
sed -i 's/baseos_latest/u9_base/' $version/Dockerfile
|
sed -i 's/baseos_latest/u9_base/' $version/Dockerfile
|
||||||
sed -i '/appstream/d' $version/Dockerfile
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
podman build -t gen-oraclelinux${version}-image $version
|
podman build -t gen-oraclelinux${version}-image $version
|
||||||
|
35
tools/qemu-ubuntu-img/14.04/Dockerfile
Normal file
35
tools/qemu-ubuntu-img/14.04/Dockerfile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Copyright 2018 Mikhail Klementev. All rights reserved.
|
||||||
|
# Use of this source code is governed by a AGPLv3 license
|
||||||
|
# (or later) that can be found in the LICENSE file.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
#
|
||||||
|
# $ docker build -t gen-ubuntu1404-image .
|
||||||
|
# $ docker run --privileged -v $(pwd):/shared -t gen-ubuntu1404-image
|
||||||
|
#
|
||||||
|
# ubuntu1404.img will be created in current directory. You can change $(pwd) to
|
||||||
|
# different directory to use different destination for image.
|
||||||
|
#
|
||||||
|
FROM ubuntu:14.04
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get install -y debootstrap qemu
|
||||||
|
|
||||||
|
ENV TMPDIR=/tmp/ubuntu
|
||||||
|
ENV IMAGEDIR=/tmp/image
|
||||||
|
ENV IMAGE=/shared/out_of_tree_ubuntu_14__04.img
|
||||||
|
ENV REPOSITORY=http://archive.ubuntu.com/ubuntu
|
||||||
|
ENV RELEASE=trusty
|
||||||
|
|
||||||
|
RUN mkdir $IMAGEDIR
|
||||||
|
|
||||||
|
# Must be executed with --privileged because of /dev/loop
|
||||||
|
CMD debootstrap --include=openssh-server,policykit-1 \
|
||||||
|
$RELEASE $TMPDIR $REPOSITORY && \
|
||||||
|
/shared/setup.sh $TMPDIR && \
|
||||||
|
qemu-img create $IMAGE 2G && \
|
||||||
|
mkfs.ext4 -F $IMAGE && \
|
||||||
|
mount -o loop $IMAGE $IMAGEDIR && \
|
||||||
|
cp -a $TMPDIR/* $IMAGEDIR/ && \
|
||||||
|
umount $IMAGEDIR
|
17
tools/qemu-ubuntu-img/14.04/setup.sh
Executable file
17
tools/qemu-ubuntu-img/14.04/setup.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh -eux
|
||||||
|
# Copyright 2018 Mikhail Klementev. All rights reserved.
|
||||||
|
# Use of this source code is governed by a AGPLv3 license
|
||||||
|
# (or later) that can be found in the LICENSE file.
|
||||||
|
TMPDIR=$1
|
||||||
|
chroot $TMPDIR /bin/sh -c 'useradd -m user'
|
||||||
|
sed -i 's/root:\*:/root::/' $TMPDIR/etc/shadow
|
||||||
|
sed -i 's/user:!!:/user::/' $TMPDIR/etc/shadow
|
||||||
|
echo auth sufficient pam_permit.so > $TMPDIR/etc/pam.d/sshd
|
||||||
|
sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
|
echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
|
sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
|
echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
|
|
||||||
|
echo '#!/bin/sh' > $TMPDIR/etc/rc.local
|
||||||
|
echo 'dhclient eth0' >> $TMPDIR/etc/rc.local
|
||||||
|
chmod +x $TMPDIR/etc/rc.local
|
@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
os.chdir(script_dir)
|
|
||||||
|
|
||||||
releases = [
|
|
||||||
('12.04', 'precise', 'http://old-releases.ubuntu.com/ubuntu'),
|
|
||||||
('14.04', 'trusty', 'http://archive.ubuntu.com/ubuntu'),
|
|
||||||
('16.04', 'xenial', 'http://archive.ubuntu.com/ubuntu'),
|
|
||||||
('18.04', 'bionic', 'http://archive.ubuntu.com/ubuntu'),
|
|
||||||
('20.04', 'focal', 'http://archive.ubuntu.com/ubuntu'),
|
|
||||||
('22.04', 'jammy', 'http://archive.ubuntu.com/ubuntu'),
|
|
||||||
('24.04', 'noble', 'http://archive.ubuntu.com/ubuntu')
|
|
||||||
]
|
|
||||||
|
|
||||||
template = '''
|
|
||||||
FROM ubuntu:{version}
|
|
||||||
|
|
||||||
RUN sed -i 's;http://archive.ubuntu.com/ubuntu;{repository};' /etc/apt/sources.list
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get install -y debootstrap qemu-utils
|
|
||||||
RUN apt-get install -y linux-image-generic
|
|
||||||
|
|
||||||
ENV TMPDIR=/tmp/ubuntu
|
|
||||||
ENV IMAGEDIR=/tmp/image
|
|
||||||
ENV IMAGE=/shared/out_of_tree_ubuntu_{img_version}.img
|
|
||||||
ENV REPOSITORY={repository}
|
|
||||||
ENV RELEASE={codename}
|
|
||||||
|
|
||||||
RUN mkdir $IMAGEDIR
|
|
||||||
|
|
||||||
# Must be executed with --privileged because of /dev/loop
|
|
||||||
CMD debootstrap --include=openssh-server,policykit-1 \
|
|
||||||
$RELEASE $TMPDIR $REPOSITORY && \
|
|
||||||
/shared/setup.sh $TMPDIR && \
|
|
||||||
qemu-img create $IMAGE 2G && \
|
|
||||||
mkfs.ext4 -F $IMAGE && \
|
|
||||||
mount -o loop $IMAGE $IMAGEDIR && \
|
|
||||||
cp -a $TMPDIR/* $IMAGEDIR/ && \
|
|
||||||
umount $IMAGEDIR
|
|
||||||
'''
|
|
||||||
|
|
||||||
def run_cmd(cmd):
|
|
||||||
print(f"+ {cmd}")
|
|
||||||
subprocess.run(cmd, shell=True, check=True, executable='/bin/bash')
|
|
||||||
|
|
||||||
for version, codename, repository in releases:
|
|
||||||
numeric_version = version.replace('.', '')
|
|
||||||
img_version=version.replace(".","__")
|
|
||||||
|
|
||||||
dockerfile_content = template.format(
|
|
||||||
version=version,
|
|
||||||
img_version=img_version,
|
|
||||||
codename=codename,
|
|
||||||
repository=repository,
|
|
||||||
numeric_version=numeric_version)
|
|
||||||
|
|
||||||
os.makedirs(str(version), exist_ok=True)
|
|
||||||
with open(f"{version}/Dockerfile", "w") as dockerfile:
|
|
||||||
dockerfile.write(dockerfile_content)
|
|
||||||
|
|
||||||
run_cmd(f"podman build -t gen-ubuntu{numeric_version}-image {version}")
|
|
||||||
run_cmd(f"rm -rf {version}")
|
|
||||||
|
|
||||||
run_cmd(f"podman run --privileged -v {os.getcwd()}:/shared -t gen-ubuntu{numeric_version}-image")
|
|
||||||
|
|
||||||
run_cmd(f"tar -Szcf out_of_tree_ubuntu_{img_version}.img.tar.gz out_of_tree_ubuntu_{img_version}.img")
|
|
||||||
|
|
@ -11,9 +11,7 @@ sed -i '/PermitEmptyPasswords/d' $TMPDIR/etc/ssh/sshd_config
|
|||||||
echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
echo PermitEmptyPasswords yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
sed -i '/PermitRootLogin/d' $TMPDIR/etc/ssh/sshd_config
|
||||||
echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
echo PermitRootLogin yes >> $TMPDIR/etc/ssh/sshd_config
|
||||||
sed -i '/UseDNS/d' $TMPDIR/etc/ssh/sshd_config
|
|
||||||
echo UseDNS no >> $TMPDIR/etc/ssh/sshd_config
|
|
||||||
|
|
||||||
echo '#!/bin/sh' > $TMPDIR/etc/rc.local
|
echo '#!/bin/sh' > $TMPDIR/etc/rc.local
|
||||||
echo 'dhclient || dhcpcd' >> $TMPDIR/etc/rc.local
|
echo 'dhclient' >> $TMPDIR/etc/rc.local
|
||||||
chmod +x $TMPDIR/etc/rc.local
|
chmod +x $TMPDIR/etc/rc.local
|
||||||
|
Reference in New Issue
Block a user