Skip to content

Commit

Permalink
Merge pull request #2 from SlothCroissant/staging
Browse files Browse the repository at this point in the history
Added GitHub SSH Key support
  • Loading branch information
SlothCroissant authored Sep 26, 2024
2 parents 24866a4 + 0a6a160 commit 07d3a98
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 75 deletions.
10 changes: 1 addition & 9 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@
// "features": {},
// "forwardPorts": [8000],
"appPort": ["8000:8000"], // exposes on 0.0.0.0, which forwardPorts doesn't support
"postCreateCommand": "pip install -r app/requirements.txt",
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {},
"extensions": ["ms-azuretools.vscode-docker"]
}
}
"postCreateCommand": "pip install -r app/requirements.txt"
// "remoteUser": "root"
}
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,4 @@ jobs:
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.meta.outputs.tag }}
generate_release_notes: true
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Ignore Answers folder, but keep example toml:
app/answers/*
!app/answers/01:23:45:67:89:ab.toml

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
107 changes: 44 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,21 @@ Builds are available at the following Docker repositories:

# Run the Container

Populate a folder on the host with your .toml files (in this example, `/host/path/answers`). Each file should be `<mac_address>.toml` - for example `bc:24:11:d5:36:d1.toml`
Populate a folder on the host with your .toml files (in this example, `/host/path/answers`). Each file must contain the mac address of *any* NIC presented by the host in `01:23:45:67:89:ab` case-insensitive format - for example:

* `01:23:45:67:89:ab.toml`
* `myhost_01:23:45:67:89:ab.toml`

Run the container:

``` bash
```bash
docker run -p 8000:8000 --mount type=bind,source=/host/path/answers,target=/app/answers slothcroissant/proxmox-auto-installer-server:latest
```

| Key | Value |
|-|-|
| `-p 8000:8000` | Port (host:container) on which to expose the application. The container port is `8000`, but you can map a different port via Docker. Ref: [Docker: Expose Ports](https://docs.docker.com/engine/containers/run/#exposed-ports)|
| `--mount type=bind,source=/host/path/answers,target=/app/answers` | Volume (via Bind Mount) exposed into the container. This can be anywhere on your host, and should always map to `/app/answers` in the container. Ref: [Docker: Bind Mounts](https://docs.docker.com/engine/containers/run/#bind-mounts)|
| `-p 8000:8000` | Port (host:container) on which to expose the application. The container port is `8000`, but you can map a different port via Docker. Ref: [Docker: Expose Ports](https://docs.docker.com/engine/containers/run/#exposed-ports) |
| `--mount type=bind,source=/host/path/answers,target=/app/answers` | Volume (via Bind Mount) exposed into the container. This can be anywhere on your host, and should always map to `/app/answers` in the container. Ref: [Docker: Bind Mounts](https://docs.docker.com/engine/containers/run/#bind-mounts) |
| `-e PUID=<int>` (Optional) | Sets the container's User ID (PUID) in case your volume mount has dependencies on PUID/PGID and is different than the default `1000`. |
| `-e PGID=<int>` (Optional) | Sets the container's Group ID (PGID) in case your volume mount has dependencies on PUID/PGID and is different than the default `1000`. |

Expand All @@ -41,91 +44,69 @@ Take note of your docker host's IP address and exposed port (if you deviated fro

You will need to point Proxmox at your now-deployed container URL: `http://<ip_address>:8000/answer`.

If using DNS (via TXT record at `proxmox-auto-installer.{search domain}`, where `{search domain}` is the search domain provided by the DHCP server) or DHCP (as DHCP option 250) discovery options, you must have these configured prior to proceeding. As there are an infinite number of DNS/DHCP servers out there, please reference your specific solution if you choose this path.
If using DNS (via TXT record at `proxmox-auto-installer.{search domain}`, where `{search domain}` is the search domain provided by the DHCP server) or DHCP (as DHCP option 250) discovery options, you must have these configured prior to proceeding. As there are an infinite number of DNS/DHCP servers out there, please reference your specific solution if you choose this path.

Alternatively, there are no prerequisites if using the `--url` option in the ISO itself.

Once this container is running, you will see logs confirming:

``` bash
```bash
======== Running on http://0.0.0.0:8000 ========
```

## Boot Proxmox

To run the PVE installer against this container:

1. Install `proxmox-auto-install-assistant`:

``` bash
apt install proxmox-auto-install-assistant
```

1. Download the PVE ISO from https://www.proxmox.com/downloads:

``` bash
wget https://enterprise.proxmox.com/iso/proxmox-ve_8.2-2.iso
```
``` bash
wget https://enterprise.proxmox.com/iso/proxmox-ve_8.2-2.iso
```

1. Prepare the PVE ISO for Automated Install

* If using DNS/DHCP (previously configured - see prerequisites):
```
proxmox-auto-install-assistant prepare-iso \
--fetch-from http \
--output /root/proxmox-ve_8.2-2.-httpanswer.iso \
/root/proxmox-ve_8.2-2.iso
```
* If using `--url` to declare the URL manually, you must add the parameter:
```
proxmox-auto-install-assistant prepare-iso \
--fetch-from http \
--url http://<ip_address>:8000/answer
--output /root/proxmox-ve_8.2-2.-httpanswer.iso \
/root/proxmox-ve_8.2-2.iso
```
```
proxmox-auto-install-assistant prepare-iso \
--fetch-from http \
--output /root/proxmox-ve_8.2-2.-httpanswer.iso \
/root/proxmox-ve_8.2-2.iso
```
* If using `-url` to declare the URL manually, you must add the parameter:
```
proxmox-auto-install-assistant prepare-iso \
--fetch-from http \
--url http://<ip_address>:8000/answer
--output /root/proxmox-ve_8.2-2.-httpanswer.iso \
/root/proxmox-ve_8.2-2.iso
```
1. Boot to this ISO, and the automated process shoud take over from there!
# Appendix
## Example JSON POST data
## GitHub SSH Keys
GitHub allows anyone to retrieve their (or anyone's) SSH public key by heading to https://github.com/<username>.keys. For example, mine is: https://github.com/SlothCroissant.keys. This is used by client-side tooling to automate addition of these keys into solutions. For example, when installing Canonical Ubuntu, you can specify your GitHub username, and the installer will retrieve your public keys to be injected into your user account's allowed keys list.
Below you can find a few exmples of the JSON POST data sent by Proxmox VE installer:

### Cisco UCS C220m4:

### Proxmox VM

This is just for additional context/learning, it's generally rare to use this (in a nested virtualization scenario). In this example, the VM was created with *all* the defaults, with the PVE 8.2.2 ISO booted:
``` json
{
"product": {
"fullname": "Proxmox VE",
"product": "pve",
"enable_btrfs": true
},
"iso": {
"release": "8.2",
"isorelease": "2"
},
"dmi": {
"system": {
"name": "Standard PC (i440FX + PIIX, 1996)",
"serial": "",
"uuid": "bcf43ddf-6d92-4ace-b93f-76f71ffe4495",
"sku": ""
},
"baseboard": {},
"chassis": {
"asset_tag": "",
"serial": ""
}
},
"network_interfaces": [
{
"link": "ens18",
"mac": "bc:24:11:d5:36:d1"
}
]
}
You can now use this feature in proxmox-auto-installer-server. Add the following (optional) TOML, and the user's keys will be appended to your `global.root_ssh_keys[]`
``` toml
[custom]
github_username = "Octocat" # Will add this user's GitHub public key(s) to global.root_ssh_keys[].
```

## Example JSON POST data

In the [example_post_data](./example_post_data/) folder, you can find a few exmples of the JSON POST data sent by Proxmox VE installer, for reference.

[version-image]: https://img.shields.io/github/v/release/SlothCroissant/proxmox-auto-installer-server?style=for-the-badge
[version-url]: https://github.com/SlothCroissant/proxmox-auto-installer-server/releases

Expand Down
3 changes: 3 additions & 0 deletions app/answers/01:23:45:67:89:ab.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ source = "from-dhcp"

[disk-setup]
filesystem = "ext4"

[custom]
github_username = "Octocat" # Will add this user's GitHub public key(s) to global.root_ssh_keys[].
3 changes: 2 additions & 1 deletion app/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
aiohttp
tomlkit
tomlkit
requests
37 changes: 35 additions & 2 deletions app/server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import json
import pathlib
import requests

try:
import tomlkit
Expand Down Expand Up @@ -71,9 +72,41 @@ def lookup_answer_for_mac(mac: str) -> tomlkit.TOMLDocument | None:
mac = mac.lower()

for filename in ANSWER_FILE_DIR.glob("*.toml"):
if filename.name.lower().startswith(mac):
if mac in filename.name.lower():
with open(filename) as mac_file:
return tomlkit.parse(mac_file.read())
toml_data = tomlkit.parse(mac_file.read())
toml_data_processed = process_custom_gh_username(toml_data)
return toml_data_processed


def process_custom_gh_username(toml_data: tomlkit.TOMLDocument):
if 'custom' in toml_data:
toml_data['custom'] = tomlkit.table()

if 'gh_username' in toml_data['custom']:

# Extract the custom.gh_username string value
gh_username = toml_data['custom']['gh_username']

# HTTP GET request to fetch the keys
keys_uri = f'https://github.com/{gh_username}.keys'
response = requests.get(keys_uri)
if response.status_code != 200:
raise RuntimeError(
f"Failed to fetch keys for {gh_username}. Response from GitHub: HTTP/{response.status_code}: {response.reason}"
)
keys = response.text.splitlines()
# Append keys to global.root_ssh_keys
if 'global' not in toml_data:
toml_data['global'] = tomlkit.table()
if 'root_ssh_keys' not in toml_data['global']:
toml_data['global']['root_ssh_keys'] = tomlkit.array()
toml_data['global']['root_ssh_keys'].extend(keys)
# Remove custom/custom.gh_username
del toml_data['custom']['gh_username']
if not toml_data['custom']:
del toml_data['custom']
return toml_data


def assert_default_answer_file_exists():
Expand Down
46 changes: 46 additions & 0 deletions example_post_data/cisco_ucs_c240m4sx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"product": {
"fullname": "Proxmox VE (mocked)",
"product": "pve",
"enable_btrfs": true
},
"iso": {
"release": "8.2",
"isorelease": "2"
},
"dmi": {
"system": {
"uuid": "00000000-0000-0000-0000-000000000000",
"serial": "<serial_number_chassis>",
"name": "UCSC-C220-M4S",
"sku": ""
},
"baseboard": {
"name": "UCSC-C220-M4S",
"asset_tag": "",
"serial": "<serial_number_baseboard>"
},
"chassis": {
"asset_tag": "",
"serial": "<serial_number_chassis>"
}
},
"network_interfaces": [
{
"link": "enp9s0",
"mac": "aa:bb:cc:dd:ee:01"
},
{
"link": "enp10s0",
"mac": "aa:bb:cc:dd:ee:02"
},
{
"link": "enp1s0f0",
"mac": "aa:bb:cc:dd:ee:03"
},
{
"link": "enp1s0f1",
"mac": "aa:bb:cc:dd:ee:04"
}
]
}
30 changes: 30 additions & 0 deletions example_post_data/pve_vm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"product": {
"fullname": "Proxmox VE",
"product": "pve",
"enable_btrfs": true
},
"iso": {
"release": "8.2",
"isorelease": "2"
},
"dmi": {
"system": {
"name": "Standard PC (i440FX + PIIX, 1996)",
"serial": "",
"uuid": "00000000-0000-0000-0000-000000000000",
"sku": ""
},
"baseboard": {},
"chassis": {
"asset_tag": "",
"serial": ""
}
},
"network_interfaces": [
{
"link": "ens18",
"mac": "aa:bb:cc:dd:ee:01"
}
]
}

0 comments on commit 07d3a98

Please sign in to comment.