Skip to content

Change verbosity code, use self._display.verbosity instead #138

Change verbosity code, use self._display.verbosity instead

Change verbosity code, use self._display.verbosity instead #138

Workflow file for this run

name: LXC ssh test
# Run this workflow every time a new commit pushed to your repository
on:
push:
#branches: '**'
#branches-ignore: 'main'
pull_request:
#branches: '**'
#branches-ignore: 'main'
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
pr-test-ubuntu-user:
name: Check the PR (ubuntu user)
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# also test 'latest', eventually this will be upgraded to a newer version and might fail early
# build the matrix manually - not all versions of Ubuntu can do with all Ansible versions,
# mostly because the Python version is outdated (20.04 only has Python 3.8)
# maybe in the future this can be build with include/exclude
#os: [ubuntu-20.04, ubuntu-22.04, ubuntu-latest]
#ansible: ["stable-2.9", "stable-2.10", "stable-2.11", "stable-2.12", "stable-2.13", "stable-2.14"]
include:
- os: ubuntu-20.04
guest: 20.04
#guest-image: 20.04/amd64
ansible: "stable-2.9"
- os: ubuntu-20.04
guest: 20.04
ansible: "stable-2.10"
- os: ubuntu-20.04
guest: 20.04
ansible: "stable-2.11"
- os: ubuntu-20.04
guest: 20.04
ansible: "stable-2.12"
- os: ubuntu-20.04
guest: 20.04
ansible: "stable-2.13"
- os: ubuntu-22.04
guest: 22.04
ansible: "stable-2.9"
- os: ubuntu-22.04
guest: 22.04
ansible: "stable-2.10"
- os: ubuntu-22.04
guest: 22.04
ansible: "stable-2.11"
- os: ubuntu-22.04
guest: 22.04
ansible: "stable-2.12"
- os: ubuntu-22.04
guest: 22.04
ansible: "stable-2.13"
- os: ubuntu-22.04
guest: 22.04
ansible: "stable-2.14"
# build the latest known stable Ansible on the latest known stable Ubuntu
- os: ubuntu-latest
guest: 22.04
ansible: "stable-2.14"
# build the development version of Ansible on latest Ubuntu
- os: ubuntu-latest
guest: 22.04
ansible: "devel"
steps:
- name: Checkout code
uses: actions/checkout@v3
# check Python syntax
- name: Python syntax check
run: python3 -m py_compile lxc_ssh.py
# prepare container with LXD installation
- name: Install basic packages
run: sudo apt-get install -y iptables
- name: Install LXD (Ubuntu 20.x)
run: sudo apt-get install -y lxd lxd-client lxd-tools
if: ${{ matrix.guest == '20.04' }}
- name: Install LXD (Ubuntu >= 22.x)
run: sudo snap install lxd
if: ${{ matrix.guest != '20.04' }}
# different LXD versions need different init steps
- name: Store LXD version
run: echo "LXD_Version=$(lxd --version)" >> $GITHUB_OUTPUT
id: lxd_version
- name: Store LXD major version
run: echo "LXD_Major_Version=$(lxd --version | cut -f1 -d'.')" >> $GITHUB_OUTPUT
id: lxd__major_version
- name: Output version
run: echo "${{ steps.lxd_version.outputs.LXD_Version }} - ${{ steps.lxd__major_version.outputs.LXD_Major_Version }}"
- name: Fail for unknown older versions
run: exit 1
if: steps.lxd__major_version.outputs.LXD_Major_Version < 3
- name: Fail for unknown newer versions
run: exit 1
if: steps.lxd__major_version.outputs.LXD_Major_Version > 5
- name: Init LXD version 3
run: sudo lxd init --preseed < $GITHUB_WORKSPACE/.github/resources/lxd3-init.yml
if: steps.lxd__major_version.outputs.LXD_Major_Version == 3
- name: Init LXD version 4
run: sudo lxd init --preseed < $GITHUB_WORKSPACE/.github/resources/lxd4-init.yml
if: steps.lxd__major_version.outputs.LXD_Major_Version >= 4
- name: Show LXD status
run: sudo lxc profile show default
- name: Store IPv4 address for lxdbr0
run: echo "IP=$(ip -4 addr show lxdbr0 | grep inet | awk '{print $2}' | cut -d/ -f1)" >> $GITHUB_OUTPUT
id: lxdbr0_ipv4
- name: Show lxdbr0 IP address
run: echo "${{ steps.lxdbr0_ipv4.outputs.IP }}"
- name: Create container-pool for LXD
run: sudo lxc storage create container-pool dir
- name: Remove default storage pool from LXD
run: sudo lxc profile device remove default root
- name: Attach container storage pool to default profile
run: sudo lxc profile device add default root disk path=/ pool=container-pool
# - name: Firewall IPv6
# run: sudo lxc network set lxdbr0 ipv6.firewall false
# - name: Firewall IPv4
# run: sudo lxc network set lxdbr0 ipv4.firewall false
# - name: Firewall 1
# run: sudo ufw allow in on lxdbr0
# - name: Firewall 2
# run: sudo ufw route allow in on lxdbr0
# - name: Firewall 3
# run: sudo ufw route allow out on lxdbr0
# - name: Docker
# run: sudo docker ps
# https://linuxcontainers.org/lxd/docs/master/howto/network_bridge_firewalld/#prevent-issues-with-lxd-and-docker
- name: Show network configuration
run: sudo ip addr
- name: Docker Firewall 1
run: sudo iptables -I DOCKER-USER -i lxdbr0 -o eth0 -j ACCEPT
- name: Docker Firewall 2
run: sudo iptables -I DOCKER-USER -o lxdbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# create an actual container, and configure it
# Enable container nesting
- name: Create container
run: sudo lxc launch images:ubuntu/${{ matrix.guest }} test-container -c security.nesting=true
- name: Wait for container to start
run: sleep 10
- name: Show container
run: sudo lxc list
- name: Debug
run: sudo lxc exec test-container -- ip -4 -o link show
- name: Store Container interface name
run: echo "IF=$(sudo lxc exec test-container -- ip -4 -o link show | awk '{print $2}' | cut -f1 -d':' | cut -f1 -d'@' | grep '^e[tn]')" >> $GITHUB_OUTPUT
id: test_container_interface
- name: Request and wait for IPv4 address
run: sudo lxc exec test-container -- dhclient -v ${{ steps.test_container_interface.outputs.IF }}
- name: Store Container IPv4 address
run: echo "IPv4=$(sudo lxc exec test-container -- ip -o -4 addr show ${{ steps.test_container_interface.outputs.IF }} | awk '{print $4}' | cut -d/ -f1)" >> $GITHUB_OUTPUT
id: test_container_ipv4
- name: Output container network data
run: echo "${{ steps.test_container_interface.outputs.IF }} - ${{ steps.test_container_ipv4.outputs.IPv4 }}"
- name: Fail if no network available
run: exit 1
if: steps.test_container_ipv4.outputs.IPv4 == ''
- name: Ping test if the container is connected
run: ping -4 -c 3 -n -v ${{ steps.test_container_ipv4.outputs.IPv4 }}
- name: Add container to /etc/hosts
run: ls -ld /etc/hosts
- name: Add container to /etc/hosts
run: echo -e "${{ steps.test_container_ipv4.outputs.IPv4 }}\ttest-container" | sudo tee -a /etc/hosts
- name: Show /etc/hosts
run: cat /etc/hosts
# create ssh key for root
- name: Create ssh directory for root
run: sudo mkdir -p /root/.ssh/
- name: Update permissions for ssh directory for root
run: sudo chmod 0700 /root/.ssh/
- name: Generate OpenSSH key for root
#run: sudo ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa -v -N "" -P "" -C "root@host"
run: sudo ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -v -N "" -P "" -C "root@host"
# create ssh key for runner user
- name: Create ssh directory for runner user
run: mkdir -p $HOME/.ssh/
- name: Update permissions for ssh directory for runner user
run: chmod 0700 $HOME/.ssh/
- name: Generate OpenSSH key for runner user
#run: ssh-keygen -t rsa -b 4096 -f $HOME/.ssh/id_rsa -v -N "" -P "" -C "home/runner@host"
run: ssh-keygen -t ed25519 -f $HOME/.ssh/id_ed25519 -v -N "" -P "" -C "home/runner@host"
# 22.04 can't reach the Ubuntu servers over IPv6
# - name: Disable IPv6 (all)
# run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- sysctl -w net.ipv6.conf.all.disable_ipv6=1
# - name: Disable IPv6 (default)
# run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- sysctl -w net.ipv6.conf.default.disable_ipv6=1
# - name: Disable IPv6 (lo)
# run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- sysctl -w net.ipv6.conf.lo.disable_ipv6=1
- name: Network
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- ip addr
- name: Network
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- ip route
# install OpenSSH in container
- name: Install OpenSSH in container
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- apt-get -y install -y openssh-client openssh-server openssh-sftp-server
- name: OpenSSH create root .ssh directory in container
run: sudo lxc exec test-container -- mkdir -p /root/.ssh
- name: OpenSSH permissions of root .ssh directory in container
run: sudo lxc exec test-container -- chmod 0700 /root/.ssh
- name: OpenSSH create ubuntu .ssh directory in container
run: sudo lxc exec test-container -- mkdir -p /home/ubuntu/.ssh
- name: OpenSSH permissions of ubuntu .ssh directory in container
run: sudo lxc exec test-container -- chmod 0700 /home/ubuntu/.ssh
# install root and user ssh key in container for root and user
- name: OpenSSH push authorized_keys for root into container
#run: sudo lxc file push /root/.ssh/id_rsa.pub test-container/root/.ssh/authorized_keys
run: sudo lxc file push /root/.ssh/id_ed25519.pub test-container/root/.ssh/authorized_keys
- name: OpenSSH push authorized_keys for user into container
#run: sudo lxc file push $HOME/.ssh/id_rsa.pub test-container/tmp/authorized_keys.user
run: sudo lxc file push $HOME/.ssh/id_ed25519.pub test-container/tmp/authorized_keys.user
- name: OpenSSH add user key to root authorized_keys in container
#run: sudo lxc exec test-container -- bash -c "cat /tmp/authorized_keys.user | sudo tee -a /root/.ssh/authorized_keys"
run: sudo lxc exec test-container -- sudo bash -c "cat /tmp/authorized_keys.user >> /root/.ssh/authorized_keys"
- name: Install authorized_keys for ubuntu user in container
run: sudo lxc exec test-container -- cp -ai /root/.ssh/authorized_keys /home/ubuntu/.ssh
- name: OpenSSH ownership of ubuntu .ssh directory in container
run: sudo lxc exec test-container -- chown -R ubuntu. /home/ubuntu/.ssh
# configure password & other requirements for password authentication
- name: Set root user password in container
run: sudo lxc exec test-container -- sh -c 'printf "password\npassword\n" | passwd'
- name: Set ubuntu user password in container
run: sudo lxc exec test-container -- sh -c 'printf "password\npassword\n" | passwd ubuntu'
- name: Install sshpass on runner
run: sudo apt-get -y install sshpass
# update known_hosts for root
- name: Create /root/.ssh/known_hosts
run: sudo touch /root/.ssh/known_hosts
- name: Add container to known_hosts for root
run: sudo bash -c "ssh-keyscan -4 test-container >> /root/.ssh/known_hosts"
- name: Add container IP to known_hosts for root
run: sudo bash -c "ssh-keyscan -4 ${{ steps.test_container_ipv4.outputs.IPv4 }} >> /root/.ssh/known_hosts"
# update known_hosts for user
- name: Create /user/.ssh/known_hosts
run: touch $HOME/.ssh/known_hosts
- name: Add container to known_hosts for user
run: bash -c "ssh-keyscan -4 test-container >> $HOME/.ssh/known_hosts"
- name: Add container IP to known_hosts for user
run: bash -c "ssh-keyscan -4 ${{ steps.test_container_ipv4.outputs.IPv4 }} >> $HOME/.ssh/known_hosts"
# test ssh connection in all combinations
- name: Test ssh connection from root into root
run: sudo ssh -i /root/.ssh/id_ed25519 -o PreferredAuthentications=publickey -o PasswordAuthentication=no -l root ${{ steps.test_container_ipv4.outputs.IPv4 }} uptime
- name: Test ssh connection from root into ubuntu user
run: sudo ssh -i /root/.ssh/id_ed25519 -o PreferredAuthentications=publickey -o PasswordAuthentication=no -l ubuntu ${{ steps.test_container_ipv4.outputs.IPv4 }} uptime
- name: Test ssh connection from runner into root user
run: ssh -i $HOME/.ssh/id_ed25519 -o PreferredAuthentications=publickey -o PasswordAuthentication=no -l root ${{ steps.test_container_ipv4.outputs.IPv4 }} uptime
- name: Test ssh connection from runner into ubuntu user
run: ssh -i $HOME/.ssh/id_ed25519 -o PreferredAuthentications=publickey -o PasswordAuthentication=no -l ubuntu ${{ steps.test_container_ipv4.outputs.IPv4 }} uptime
- name: Test ssh connection into root user with password authentication
run: sshpass -p 'password' ssh -i /dev/null -l ubuntu ${{ steps.test_container_ipv4.outputs.IPv4 }} uptime
# copy logfiles from container into log
- name: Show logfile in container
if: always()
run: sudo lxc exec test-container -- tail -n 500 /var/log/syslog
- name: Show logfile in container
if: always()
run: sudo lxc exec test-container -- tail -n 500 /var/log/auth.log
# - name: Stop
# run: exit 1
# install Python3 in container
- name: apt-get update
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- apt-get update
# don't upgrade the container to the latest software version
# should work out of the box for testing, and saves time
#- name: apt-get dist-upgrade
# run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- apt-get dist-upgrade -y
- name: Ubuntu version
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- lsb_release -a
- name: Python3
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- apt-get -y install -y python3
# Install LXD inside container, it's missing inside container
- name: Install LXD inside container (20.04)
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- sudo apt-get install -y lxd lxd-client lxd-tools iptables
if: ${{ matrix.guest == '20.04' }}
- name: Install Snap inside container (>= 22.04)
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- sudo apt-get -y install snapd iptables
if: ${{ matrix.guest != '20.04' }}
- name: Install LXD inside container (>= 22.04)
run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- sudo snap install lxd
if: ${{ matrix.guest != '20.04' }}
# - name: Ping test if the container has connectivity
# run: sudo lxc exec test-container --env DEBIAN_FRONTEND=noninteractive -- ping -4 -c 3 -n -v 8.8.8.8
# container is ready
# install Ansible
- name: Install requested Ansible version using pip
run: python -m pip install --user https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz
- name: Show Ansible version
run: ansible --version
- name: Install plugin for tests
run: cp -af $GITHUB_WORKSPACE/lxc_ssh.py $GITHUB_WORKSPACE/tests/connection_plugins/lxc_ssh.py
- name: Create empty file for tests
run: touch $GITHUB_WORKSPACE/tests/test_empty.txt
- name: Create a 1000 Bytes file for tests
run: dd if=/dev/urandom of=$GITHUB_WORKSPACE/tests/test_1000b.txt bs=1KB count=1
- name: Create a 5MB file for tests
run: dd if=/dev/urandom of=$GITHUB_WORKSPACE/tests/test_5mb.txt bs=5MB count=1
- name: Create a 50MB file for tests
run: dd if=/dev/urandom of=$GITHUB_WORKSPACE/tests/test_50mb.txt bs=50MB count=1
- name: Show test directory
run: bash -c "ls -ld $GITHUB_WORKSPACE/tests/*"
# nested LXD configuration
- name: Init LXD inside container
run: sudo lxc exec test-container -- sudo lxd init --preseed < $GITHUB_WORKSPACE/.github/resources/lxd4-init.yml
# Create a nested container for lxc_ssh tests
- name: Create a nested container
run: sudo lxc exec test-container -- sudo lxc launch images:ubuntu/${{ matrix.guest }} nested-container
- name: add container user to lxd group
run: sudo lxc exec test-container -- sudo adduser ubuntu lxd
- name: Wait for container to start
run: sleep 10
- name: Generate ansible inventory
run: |
cat <<EOF > $GITHUB_WORKSPACE/tests/inventory.yml
---
all:
hosts:
testhost:
ansible_host: ${{ steps.test_container_ipv4.outputs.IPv4 }}
ansible_ssh_user: 'ubuntu'
lxc_host: "nested-container"
ansible_connection: lxc_ssh
EOF
- name: Show inventory file
run: cat $GITHUB_WORKSPACE/tests/inventory.yml
- name: Run test
run: ANSIBLE_CONFIG=$GITHUB_WORKSPACE/tests/ cd tests && ansible-playbook -i $GITHUB_WORKSPACE/tests/inventory.yml $GITHUB_WORKSPACE/tests/test-lxc_ssh.yml
# Test password authentication
- name: Add a password for the SSH connection
run: >
printf ' ansible_ssh_pass: "password"\n ansible_ssh_private_key_file: "/dev/null"' >> $GITHUB_WORKSPACE/tests/inventory.yml
- name: Run test with password
run: >
ANSIBLE_CONFIG=$GITHUB_WORKSPACE/tests/ cd tests && ansible-playbook -i $GITHUB_WORKSPACE/tests/inventory.yml $GITHUB_WORKSPACE/tests/test-lxc_ssh.yml -t short
- name: Remove sshpass
run: sudo apt-get remove -y sshpass
- name: Run test with password and without sshpass (expect command failure)
run: >
set +e;
stdout=$(ANSIBLE_CONFIG=$GITHUB_WORKSPACE/tests/ cd tests && ansible-playbook -i $GITHUB_WORKSPACE/tests/inventory.yml $GITHUB_WORKSPACE/tests/test-lxc_ssh.yml -t short);
status=$?;
set -e;
[ $status -eq 2 ] && echo "$stdout" | grep -F "to use the 'ssh' connection type with passwords, you must install the sshpass program"