Compare commits
3 Commits
be285606e2
...
9005685ab5
Author | SHA1 | Date | |
---|---|---|---|
9005685ab5 | |||
f452c2ef09 | |||
1f08252999 |
218
README.md
218
README.md
@ -11,3 +11,221 @@ So I decided to create a script to manage my Proxmox homelab.
|
|||||||
# How to use it
|
# How to use it
|
||||||
Have a look at the resources folder to see how to use it.
|
Have a look at the resources folder to see how to use it.
|
||||||
|
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
## Creation
|
||||||
|
In the creation section, you have the option to define conditions for checking whether your LXC/VM has been previously configured.
|
||||||
|
If all of these conditions are met, the script will proceed directly to the deploy section and execute the necessary steps to update it. *(This indicates that your LXC/VM has already been configured, and we want to avoid erasing any existing settings/config.)*
|
||||||
|
However, if **any** of the conditions fail to match, the script will process to the creation steps section and execute **all** the commands again.
|
||||||
|
|
||||||
|
## Conditions
|
||||||
|
### File
|
||||||
|
The file condition will check if a file exists or not inside the LXC/VM.
|
||||||
|
```json
|
||||||
|
"conditions": {
|
||||||
|
"file": "/var/data/traefikv2/traefik.toml"
|
||||||
|
or
|
||||||
|
"files": ["/var/data/traefikv2/traefik.toml", "/var/data/config/traefikv2/docker-compose.yml"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
It can be an array of file using ``["file1", "file2"]`` or just one file in double quote ``"file"``.
|
||||||
|
|
||||||
|
### Folder
|
||||||
|
The folder condition will check if a folder exists or not inside the LXC/VM.
|
||||||
|
```json
|
||||||
|
"conditions": {
|
||||||
|
"folder": "/var/data/traefikv2"
|
||||||
|
or
|
||||||
|
"folders": ["/var/data/traefikv2", "/var/data/config/traefikv2"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
It can be an array of folders using ``["folder1", "folder2"]`` or just one folder in double quote ``"file"``.
|
||||||
|
|
||||||
|
### Programs
|
||||||
|
The programs condition will check if a program is installed or not in the LXC/VM.
|
||||||
|
```json
|
||||||
|
"conditions": {
|
||||||
|
"program": "docker"
|
||||||
|
or
|
||||||
|
"programs": ["docker", "docker-compose"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
It can be an array of programs using ``["program1", "program2"]`` or just one program in double quote ``"program"``.
|
||||||
|
|
||||||
|
*Note:This uses `which` to check if the program matches to anything*
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
**Note: Paths**
|
||||||
|
When you have to specify a path, you can use ``/global/`` to use the global folder (`resources/<scripts|file>/`).
|
||||||
|
If nothing is specified, the script will use the VM/LXC folder (`resources/lxc/<id>/`).
|
||||||
|
|
||||||
|
*The comments in the JSON below are only for documentation purposes and are not valid JSON, remove them before running.*
|
||||||
|
### Script
|
||||||
|
The script step will execute a script.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "script",
|
||||||
|
"path": "/global/install-docker.sh" # local path (here: resources/scripts/install-docker.sh)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### File
|
||||||
|
The file step will copy a file to the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"path": "traefik.toml", # local path (here: resources/lxc/<id>/traefik.toml)
|
||||||
|
"destination": "/var/data/traefikv2/traefik.toml" # lxc/vm path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Folder
|
||||||
|
The folder step will copy a folder to the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "folder",
|
||||||
|
"path": "/data/", # local path (here: resources/lxc/<id>/data/)
|
||||||
|
"destination": "/var/data/traefikv2" # lxc/vm path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Command
|
||||||
|
The command step will execute a command on the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "whoami", # command to execute
|
||||||
|
"working_directory": "/var/data/config/traefikv2" # lxc/vm path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
The docker step will execute a docker command on the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "docker",
|
||||||
|
"command": "run -d --name=traefikv2 --restart=always -p 80:80 -p 443:443 -p 8080:8080 -v /var/data/traefikv2:/etc/traefik -v /var/data/config/traefikv2:/config -v /var/run/docker.sock:/var/run/docker.sock traefik:latest", # docker command to execute
|
||||||
|
"working_directory": "/var/data/config/traefikv2" # lxc/vm path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker-compose
|
||||||
|
The docker-compose step will execute a docker-compose command on the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "docker-compose",
|
||||||
|
"command": "up -d", # docker-compose command to execute
|
||||||
|
"working_directory": "/var/data/config/traefikv2" # lxc/vm path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
*Note : Here, why not use the `command` step? Docker Compose can sometimes be executed with `docker-compose` or `docker compose`, the script will take care of choosing the correct one.*
|
||||||
|
|
||||||
|
### Git
|
||||||
|
The git step will clone a git repo on the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.abc.xyz/abc/abc.git", # git url
|
||||||
|
"destination": "/root/" # lxc/vm path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
*Note: At the the moment, no authentication is supported, so only works on public repo.*
|
||||||
|
|
||||||
|
### Download
|
||||||
|
The download step will download a file on the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "download",
|
||||||
|
"url": "https://git.abc.xyz/file.tar.gz", # download url
|
||||||
|
or
|
||||||
|
"urls": ["https://git.abc.xyz/file1.tar.gz", "https://git.abc.xyz/file2.tar.gz"] # download urls
|
||||||
|
"destination": "/tmp/" # lxc/vm path
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extract archive (tar/zip)
|
||||||
|
The unzip step will unzip a file in the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "unzip",
|
||||||
|
"path": "/tmp/file.tar.gz", # lxc/vm path to the archive
|
||||||
|
"destination": "/var/data/config/traefikv2" # (optional) lxc/vm path to extract the archive, will use archive parent directory if blank
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
*Note : At the the moment, only tar and zip are supported.*
|
||||||
|
|
||||||
|
### Install package
|
||||||
|
The install-package step will install a package on the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "install-package",
|
||||||
|
"package": "git" # package to install
|
||||||
|
or
|
||||||
|
"packages": ["git", "docker"] # packages to install
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
*Note : At the the moment, only apt, apk, dnf, yum are supported.*
|
||||||
|
*Warning : Packages can have different names depending on the Linux distribution.*
|
||||||
|
|
||||||
|
### Remove package
|
||||||
|
The remove-package step will remove a package on the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "remove-package",
|
||||||
|
"package": "git" # package to remove
|
||||||
|
or
|
||||||
|
"packages": ["git", "docker"] # packages to remove
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
*Note : At the the moment, only apt, apk, dnf, yum are supported.*
|
||||||
|
*Warning : Packages can have different names depending on the Linux distribution.*
|
||||||
|
|
||||||
|
### Reboot
|
||||||
|
The reboot step will reboot the VM/LXC.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "reboot"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Replace in file
|
||||||
|
The replace-in-file step will replace a string in a file.
|
||||||
|
```json
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "replace-in-file",
|
||||||
|
"path": "/var/data/config/traefikv2/traefik.toml", # lxc/vm path to the file
|
||||||
|
or
|
||||||
|
"paths": ["/var/data/config/traefikv2/traefik.toml", "/var/data/config/traefikv2/traefik2.toml"] # lxc/vm paths to the files
|
||||||
|
"search": "abc", # string to search
|
||||||
|
"replace": "xyz" # string to replace
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
@ -29,20 +29,18 @@
|
|||||||
"tags": "2-proxy+auth"
|
"tags": "2-proxy+auth"
|
||||||
},
|
},
|
||||||
"creation": {
|
"creation": {
|
||||||
"conditions": [
|
"conditions": {
|
||||||
{
|
"programs": ["docker"],
|
||||||
"type": "program",
|
"folders": ["/var/data/traefik", "/var/data/config/traefik"],
|
||||||
"program": "docker"
|
"files": ["/var/data/traefik/traefik.toml", "/var/data/config/traefikv2/docker-compose.yml"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "folder",
|
|
||||||
"path": "/var/data/traefik"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"type": "script",
|
"type": "script",
|
||||||
"path": "/global/install-docker.sh"
|
"path": "/global/install-docker.sh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
40
resources/lxc/100/data/config/traefikv2/docker-compose.yml
Normal file
40
resources/lxc/100/data/config/traefikv2/docker-compose.yml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: traefik:v2.9
|
||||||
|
env_file: /var/data/config/traefikv2/traefik.env
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "80:80" # http
|
||||||
|
- "443:443" # https
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
- /var/data/config/traefikv2/dyn:/dyn
|
||||||
|
- /var/data/config/traefikv2/traefik.toml:/etc/traefik/traefik.toml
|
||||||
|
- /var/data/traefik/traefik.log:/traefik.log
|
||||||
|
- /var/data/traefik/access.log:/access.log
|
||||||
|
- /var/data/traefik/acme.json:/acme.json
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.api.rule=Host(`traefik.xyz.abc`)"
|
||||||
|
- "traefik.http.routers.api.entrypoints=https"
|
||||||
|
|
||||||
|
- "traefik.http.routers.api.service=api@internal"
|
||||||
|
- "traefik.http.services.dummy.loadbalancer.server.port=9999"
|
||||||
|
|
||||||
|
- "traefik.http.routers.api.tls=true"
|
||||||
|
- "traefik.http.routers.api.tls.domains[0].main=xyz.abc"
|
||||||
|
- "traefik.http.routers.api.tls.domains[0].sans=*.xyz.abc"
|
||||||
|
- "traefik.http.routers.api.tls.certresolver=cloudflare"
|
||||||
|
networks:
|
||||||
|
- traefik_public
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "2m"
|
||||||
|
max-file: "2"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik_public:
|
||||||
|
external: true
|
3
resources/lxc/100/data/config/traefikv2/traefik.env
Normal file
3
resources/lxc/100/data/config/traefikv2/traefik.env
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# CloudFlare example
|
||||||
|
CLOUDFLARE_EMAIL=me@xyz.abc
|
||||||
|
CLOUDFLARE_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
52
resources/lxc/100/data/config/traefikv2/traefik.toml
Normal file
52
resources/lxc/100/data/config/traefikv2/traefik.toml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
[global]
|
||||||
|
checkNewVersion = true
|
||||||
|
|
||||||
|
# Enable the Dashboard
|
||||||
|
[api]
|
||||||
|
dashboard = true
|
||||||
|
|
||||||
|
# Write out Traefik logs
|
||||||
|
[log]
|
||||||
|
level = "INFO"
|
||||||
|
filePath = "/traefik.log"
|
||||||
|
|
||||||
|
# [accessLog]
|
||||||
|
# filePath = "/access.log"
|
||||||
|
|
||||||
|
[entryPoints.http]
|
||||||
|
address = ":80"
|
||||||
|
# Redirect to HTTPS (why wouldn't you?)
|
||||||
|
[entryPoints.http.http.redirections.entryPoint]
|
||||||
|
to = "https"
|
||||||
|
scheme = "https"
|
||||||
|
|
||||||
|
[entryPoints.http.forwardedHeaders]
|
||||||
|
trustedIPs = ["10.0.0.0/8", "172.16.0.0/16", "192.168.0.0/16", "fc00::/7"]
|
||||||
|
|
||||||
|
[entryPoints.https]
|
||||||
|
address = ":443"
|
||||||
|
[entryPoints.https.http.tls]
|
||||||
|
certResolver = "cloudflare"
|
||||||
|
|
||||||
|
[entryPoints.https.forwardedHeaders]
|
||||||
|
trustedIPs = ["10.0.0.0/8", "172.16.0.0/16", "192.168.0.0/16", "fc00::/7"]
|
||||||
|
|
||||||
|
|
||||||
|
# Cloudflare
|
||||||
|
[certificatesResolvers.infomaniak.acme]
|
||||||
|
email = "me@xyz.abc"
|
||||||
|
storage = "acme.json"
|
||||||
|
[certificatesResolvers.infomaniak.acme.dnsChallenge]
|
||||||
|
provider = "cloudflare"
|
||||||
|
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
|
||||||
|
|
||||||
|
# Docker Traefik provider
|
||||||
|
[providers.docker]
|
||||||
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
|
swarmMode = false
|
||||||
|
watch = true
|
||||||
|
exposedByDefault = false
|
||||||
|
|
||||||
|
[providers.file]
|
||||||
|
directory = "/dyn"
|
||||||
|
watch = true
|
1
resources/lxc/100/data/traefikv2/acme.json
Normal file
1
resources/lxc/100/data/traefikv2/acme.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
0
resources/lxc/100/data/traefikv2/treafik.log
Normal file
0
resources/lxc/100/data/traefikv2/treafik.log
Normal file
@ -19,15 +19,12 @@ def are_all_conditions_met(lxc):
|
|||||||
|
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for condition in conditions:
|
for file in conditions['files']:
|
||||||
if condition["type"] == "file":
|
result.append(Path(file).is_file())
|
||||||
result.append(Path(condition["path"]).is_file())
|
for folder in conditions['folders']:
|
||||||
elif condition["type"] == "folder":
|
result.append(Path(folder).is_dir())
|
||||||
result.append(Path(condition["path"]).is_dir())
|
for program in conditions['programs']:
|
||||||
elif condition["type"] == "program":
|
result.append(lxc.run_command("which " + program, only_code=True) == 0)
|
||||||
result.append(lxc.run_command("which " + condition["program"], only_code=True) == 0)
|
|
||||||
else:
|
|
||||||
raise Exception(f"Unknown condition type {condition['type']}")
|
|
||||||
|
|
||||||
if all(result):
|
if all(result):
|
||||||
logging.info(f"All creations conditions met for LXC {lxc.lxc_id}, running deploy steps...")
|
logging.info(f"All creations conditions met for LXC {lxc.lxc_id}, running deploy steps...")
|
||||||
@ -44,14 +41,11 @@ def run_creations_steps(lxc):
|
|||||||
:param lxc: lxc
|
:param lxc: lxc
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
creation = lxc.get_creation()
|
creation = lxc.get_creation()
|
||||||
creation_steps = creation["creation_steps"]
|
creation_steps = creation["creation_steps"]
|
||||||
|
|
||||||
for step in creation_steps:
|
for step in creation_steps:
|
||||||
if step["type"] == "command":
|
match step["type"]:
|
||||||
lxc.run_command(step["command"])
|
case "file":
|
||||||
elif step["type"] == "script":
|
if type(step["path"]) is list:
|
||||||
lxc.run_script(step["script"])
|
pass
|
||||||
else:
|
|
||||||
raise Exception(f"Unknown creation step type {step['type']}")
|
|
||||||
|
Loading…
Reference in New Issue
Block a user