on:
workflow_dispatch:
push:
branches: [ main ]
pull_request:
branches: [ main, develop ]
permissions:
contents: read
jobs:
init:
runs-on: ubuntu-latest
outputs:
ip: ${{ steps.config.outputs.ip }}
id: ${{ steps.config.outputs.id }}
hostname: ${{ steps.config.outputs.hostname }}
cores: ${{ steps.config.outputs.cores }}
memory: ${{ steps.config.outputs.memory }}
swap: ${{ steps.config.outputs.swap }}
disk: ${{ steps.config.outputs.disk }}
boot: ${{ steps.config.outputs.boot }}
mount: ${{ steps.config.outputs.mount }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set container.env
id: config
run: |
echo "hostname=config" >> $GITHUB_OUTPUT
source container.env
echo "ip=127.0.0.1" >> $GITHUB_OUTPUT
echo "id=$ID" >> $GITHUB_OUTPUT
echo "cores=$CORES" >> $GITHUB_OUTPUT
echo "memory=$MEMORY" >> $GITHUB_OUTPUT
echo "swap=$SWAP" >> $GITHUB_OUTPUT
echo "disk=$DISK" >> $GITHUB_OUTPUT
echo "boot=$BOOT" >> $GITHUB_OUTPUT
echo "mount=$MOUNT" >> $GITHUB_OUTPUT
build:
runs-on: ubuntu-latest
needs: [init]
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Build container
run: |
docker build --build-arg TARGETARCH=amd64 -t proxmox-gitops -f local/Dockerfile .
docker run -d --name proxmox-container -v ${{ github.workspace }}:/workspace -w /workspace proxmox-gitops
deploy:
runs-on: ubuntu-latest
needs: [init]
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Mock bootstrapping
env:
IP: ${{ needs.init.outputs.ip }}
ID: ${{ needs.init.outputs.id }}
run: |
sudo apt install -y systemd ansible
ssh-keygen -t ed25519 -f "${ID}" -N ''
cat <<EOF > base.yml
- hosts: localhost
gather_facts: false
connection: local
become: true
tasks:
- name: Apply base configuration
ansible.builtin.include_role:
name: base
EOF
sudo env ANSIBLE_ROLES_PATH="$(pwd)/base/roles" ansible-playbook -i localhost, -c local --become -e "ip=${IP} id=${ID}" -e "arch=$(arch="$(uname -m)"; case "$arch" in aarch64|arm64) echo arm64 ;; x86_64) echo amd64 ;; *) echo amd64 ;; esac)" -e "configure_ssh=0" -e "update_system=0" -e "private_key='$(cat ./${ID})\n'" -e "public_key='$(cat ./${ID}.pub)\n'" base.yml
- name: Mock config.json
run: |
cat <<EOF > ./local/config.json
{"proxmox":{"host":"localhost","user":"root@pam","password":"gitops.pm","node":"pve","gateway":"192.168.178.1","mask":"24","interface":"eth0","bridge":"vmbr0","storage":"local:vztmpl","template":"debian-13-standard_13.1-2"},"login":"proxmox","password":"gitops"}
EOF
- name: System installation
env:
IP: ${{ needs.init.outputs.ip }}
ID: ${{ needs.init.outputs.id }}
PWD: ${{ github.workspace }}
run: |
sudo env IP="$IP" ID="$ID" PWD="$PWD" HOME="/app" cinc-client -l info --local-mode --chef-license accept --config-option cookbook_path="." -j ./local/config.json -o config
- name: Install libs
env:
IP: ${{ needs.init.outputs.ip }}
ID: ${{ needs.init.outputs.id }}
LOGIN: "proxmox"
PASSWORD: "gitops"
run: |
for lib in $(ls libs); do
if [ -f "libs/$lib/container.env" ]; then
source "libs/$lib/container.env"
cp -r config/libraries libs/$lib
fi
if [ "$lib" = "proxy" ]; then
openssl req -x509 -nodes -newkey rsa:2048 -keyout /tmp/mock.key -out /tmp/mock.crt -days 1 -subj '/CN=127.0.0.1' -addext 'subjectAltName = IP:127.0.0.1' >/dev/null 2>&1
nohup python3 -c 'import http.server,ssl,json,re,textwrap; s="""
import http.server, ssl, json, re
class H(http.server.BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def _r(self,d,code=200):
b=json.dumps(d).encode()
self.send_response(code)
self.send_header("Content-Type","application/json")
self.send_header("Content-Length",str(len(b)))
self.send_header("Connection","close")
self.end_headers()
self.wfile.write(b)
def do_POST(self):
if self.path.endswith("/access/ticket"): self._r({"data":{"ticket":"t","CSRFPreventionToken":"c"}}); return
self._r({"data":{}})
def do_GET(self):
p=self.path
if re.search(r"/api2/json/nodes/.*/lxc$",p): self._r({"data":[]}); return
if re.search(r"/api2/json/nodes/.*/lxc/\d+/config$",p): self._r({"data":{"net0":"name=eth0,ip=192.168.178.101/24"}}); return
if re.search(r"/api2/json/nodes/.*/lxc/\d+/status/current$",p): self._r({"data":{"status":"running"}}); return
self._r({"data":{}})
c=ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
c.load_cert_chain("/tmp/mock.crt","/tmp/mock.key")
s=http.server.HTTPServer(("127.0.0.1",8006),H)
s.socket=c.wrap_socket(s.socket,server_side=True)
s.serve_forever()
"""; exec(textwrap.dedent(s))' >/dev/null 2>&1 &
fi
sudo env IP="127.0.0.1" ID="$ID" HOST="127.0.0.1" LOGIN="$LOGIN" PASSWORD="$PASSWORD" HOME="/app" cinc-client -l info --local-mode --chef-license accept --config-option cookbook_path="['$(pwd)', '$(pwd)/config','$(pwd)/libs']" -o "$lib"
done
- name: Idempotency
env:
IP: ${{ needs.init.outputs.ip }}
ID: ${{ needs.init.outputs.id }}
PWD: ${{ github.workspace }}
run: |
sudo env IP="$IP" ID="$ID" PWD="$PWD" HOME="/app" cinc-client -l info --local-mode --chef-license accept --config-option cookbook_path="." -j ./local/config.json -o config