Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: migrate to python for data validation #1214

Merged
merged 6 commits into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[Makefile]
indent_style = space
indent_size = 4

[*.{bash,sh}]
[*.{bash,py,sh}]
indent_style = space
indent_size = 4
10 changes: 10 additions & 0 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@
"(^|/)kustomization\\.ya?ml(\\.j2)?(\\.j2)?$"
]
},
"pip_requirements": {
"fileMatch": [
"(^|/)[\\w-]*requirements(-\\w+)?\\.(txt|pip)(\\.j2)?(\\.j2)?$"
]
},
"ansible-galaxy": {
"fileMatch": [
"(^|/)(galaxy|requirements)(\\.ansible)?\\.ya?ml(\\.j2)?(\\.j2)?$"
]
},
// commit message topics
"commitMessageTopic": "{{depName}}",
"commitMessageExtra": "to {{newVersion}}",
Expand Down
2 changes: 1 addition & 1 deletion .github/tests/config-k0s.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
ci_test: true
skip_tests: true

bootstrap_distribution: k0s
bootstrap_github_username: onedr0p
Expand Down
2 changes: 1 addition & 1 deletion .github/tests/config-k3s-ipv4.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
ci_test: true
skip_tests: true

bootstrap_distribution: k3s
bootstrap_github_username: onedr0p
Expand Down
2 changes: 1 addition & 1 deletion .github/tests/config-k3s-ipv6.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
ci_test: true
skip_tests: true

bootstrap_distribution: k3s
bootstrap_github_username: onedr0p
Expand Down
2 changes: 1 addition & 1 deletion .github/tests/config-k3s-no-kube-vip.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
ci_test: true
skip_tests: true

bootstrap_distribution: k3s
bootstrap_github_username: onedr0p
Expand Down
2 changes: 1 addition & 1 deletion .github/tests/config-talos.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
ci_test: true
skip_tests: true

bootstrap_distribution: talos
bootstrap_github_username: onedr0p
Expand Down
28 changes: 13 additions & 15 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
shell: bash
run: brew install go-task

- name: Install Brew dependencies
- name: Run Workstation tasks
if: ${{ github.event_name == 'pull_request' && steps.cache-homebrew-packages.outputs.cache-hit != 'true' }}
shell: bash
run: task workstation:brew
Expand All @@ -86,15 +86,15 @@ jobs:
shell: bash
run: direnv allow .

- name: Initialize Sops Age key
- name: Run Sops Age key task
shell: bash
run: task sops:age-keygen

- name: Install Ansible dependencies
- name: Run setup-virtual-env task
shell: bash
run: task ansible:deps force=false
run: task setup-virtual-env

- name: Generate bootstrap config file
- name: Run init tasks
shell: bash
run: |
task init
Expand All @@ -109,28 +109,26 @@ jobs:
run: |
echo "distribution=$(yq '.bootstrap_distribution' ./bootstrap/vars/config.yaml)" >> $GITHUB_OUTPUT

- name: Run configure
- name: Run configure task
shell: bash
run: task configure --yes

- name: Run Talos configure
- name: Run Talos tasks
if: ${{ steps.config-env.outputs.distribution == 'talos' }}
shell: bash
run: |
task talos:gensecret --yes
task talos:genconfig

- name: Run Ansible lint
- name: Run Ansible tasks
if: ${{ steps.config-env.outputs.distribution == 'k3s' || steps.config-env.outputs.distribution == 'k0s' }}
shell: bash
run: task ansible:lint

- name: List Hosts with Ansible
if: ${{ steps.config-env.outputs.distribution == 'k3s' || steps.config-env.outputs.distribution == 'k0s' }}
shell: bash
run: task ansible:list
run: |
task ansible:deps force=false
task ansible:lint
task ansible:list

- name: Run repo clean and reset
- name: Run repo clean and reset tasks
shell: bash
run: |
task repository:clean
Expand Down
41 changes: 17 additions & 24 deletions .taskfiles/Ansible/Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,28 @@ env:
vars:
ANSIBLE_LINT_FILE: "{{.ANSIBLE_DIR}}/.ansible-lint"
ANSIBLE_INVENTORY_FILE: "{{.ANSIBLE_DIR}}/inventory/hosts.yaml"
ANSIBLE_REQUIREMENTS_FILE: "{{.ROOT_DIR}}/requirements.yaml"
PIP_REQUIREMENTS_FILE: "{{.ROOT_DIR}}/requirements.txt"
ANSIBLE_REQUIREMENTS_FILE: "{{.ANSIBLE_DIR}}/requirements.yaml"
ANSIBLE_PIP_REQUIREMENTS_FILE: "{{.ANSIBLE_DIR}}/requirements.txt"

tasks:

deps:
desc: Set up Ansible dependencies for the environment
desc: Set up Ansible dependencies
cmds:
- task: .setup-virtual-env
vars:
force: '{{.force | default "true"}}'
- task: :setup-virtual-env
- .venv/bin/python3 -m pip install --upgrade --requirement "{{.ANSIBLE_PIP_REQUIREMENTS_FILE}}"
- .venv/bin/ansible-galaxy install --role-file "{{.ANSIBLE_REQUIREMENTS_FILE}}" {{if eq .force "true"}}--force{{end}}
preconditions:
- { msg: "Missing Ansible requirements file", sh: "test -f {{.ANSIBLE_REQUIREMENTS_FILE}}" }
- { msg: "Missing Pip requirements file", sh: "test -f {{.ANSIBLE_PIP_REQUIREMENTS_FILE}}" }
sources:
- "{{.ANSIBLE_REQUIREMENTS_FILE}}"
- "{{.ANSIBLE_PIP_REQUIREMENTS_FILE}}"
generates:
- "{{.VIRTUAL_ENV}}/bin/ansible"
- "{{.VIRTUAL_ENV}}/bin/ansible-galaxy"
vars:
force: '{{.force | default "true"}}'

run:
desc: Run an Ansible playbook for configuring a cluster
Expand Down Expand Up @@ -74,24 +85,6 @@ tasks:
preconditions:
- { msg: "Missing Ansible lint file", sh: "test -f {{.ANSIBLE_LINT_FILE}}" }

.setup-virtual-env:
internal: true
cmds:
- "{{.PYTHON_BIN}} -m venv {{.ROOT_DIR}}/.venv"
- .venv/bin/python3 -m pip install --upgrade pip setuptools wheel
- .venv/bin/python3 -m pip install --upgrade --requirement "{{.PIP_REQUIREMENTS_FILE}}"
- .venv/bin/ansible-galaxy install --role-file "{{.ANSIBLE_REQUIREMENTS_FILE}}" {{if eq .force "true"}}--force{{end}}
sources:
- "{{.PIP_REQUIREMENTS_FILE}}"
- "{{.ANSIBLE_REQUIREMENTS_FILE}}"
generates:
- "{{.ROOT_DIR}}/.venv/pyvenv.cfg"
preconditions:
- { msg: "Missing Ansible requirements file", sh: "test -f {{.ANSIBLE_REQUIREMENTS_FILE}}" }
- { msg: "Missing Pip requirements file", sh: "test -f {{.PIP_REQUIREMENTS_FILE}}" }
vars:
force: '{{.force | default "true"}}'

.reset:
internal: true
cmd: rm -rf {{.ANSIBLE_DIR}}
29 changes: 14 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ If you are marching forward, now is a good time to choose whether you will deplo
### System requirements

> [!IMPORTANT]
> 1. The included behaviour of Talos, k0s or k3s is that all nodes are able to run workloads, **including** control nodes. Worker nodes are therefore optional.
> 1. The included behaviour of Talos, k3s or k0s is that all nodes are able to run workloads, **including** control nodes. Worker nodes are therefore optional.
> 2. Do you have 3 or more nodes? It is strongly recommended to make 3 of them control nodes for a highly available control plane.
> 3. Running the cluster on Proxmox VE? My thoughts and recommendations about that are documented [here](https://onedr0p.github.io/home-ops/notes/proxmox-considerations.html).

Expand Down Expand Up @@ -193,12 +193,12 @@ Once you have installed Talos or Debian on your nodes, there are six stages to g
go-task workstation:yay
```

4. Setup a Python virual env and install Ansible by running the following task command.
4. Setup a Python virual env by running the following task command.

📍 _This commands requires Python 3.11+ to be installed._

```sh
task ansible:deps
task setup-virtual-env
```

5. Continue on to 🔧 [**Stage 3**](#-stage-3-do-bootstrap-configuration)
Expand Down Expand Up @@ -278,14 +278,7 @@ Once you have installed Talos or Debian on your nodes, there are six stages to g

7. Once done run the following command which will verify and generate all the files needed to continue.

> [!NOTE]
> The following configure task will create a `./ansible` directory for k3s or k0s and the following directories under `./kubernetes`.
> ```sh
> 📁 kubernetes # Kubernetes cluster defined as code
> ├─📁 bootstrap # Flux installation (not tracked by Flux)
> ├─📁 flux # Main Flux configuration of repository
> └─📁 apps # Apps deployed into the cluster grouped by namespace
> ```
📍 _The following configure task will create a `./ansible` directory for k3s or k0s and the following directories under `./kubernetes` for all distributions_

```sh
task configure
Expand All @@ -305,25 +298,31 @@ Once you have installed Talos or Debian on your nodes, there are six stages to g

1. Ensure you are able to SSH into your nodes from your workstation using a private SSH key **without a passphrase** (for example using a SSH agent). This lets Ansible interact with your nodes.

2. Verify Ansible can view your config
3. Install the Ansible dependencies

```sh
task ansible:deps
```

4. Verify Ansible can view your config

```sh
task ansible:list
```

3. Verify Ansible can ping your nodes
5. Verify Ansible can ping your nodes

```sh
task ansible:ping
```

4. Run the Ansible prepare playbook (nodes wil reboot when done)
6. Run the Ansible prepare playbook (nodes wil reboot when done)

```sh
task ansible:run playbook=cluster-prepare
```

5. Continue on to ⛵ [**Stage 5**](#-stage-5-install-kubernetes)
7. Continue on to ⛵ [**Stage 5**](#-stage-5-install-kubernetes)

### ⛵ Stage 5: Install Kubernetes

Expand Down
38 changes: 19 additions & 19 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ vars:
BOOTSTRAP_CONFIG_FILE: "{{.BOOTSTRAP_DIR}}/vars/config.yaml"
KUBECONFIG_FILE: "{{.ROOT_DIR}}/kubeconfig"
MAKEJINJA_CONFIG_FILE: "{{.ROOT_DIR}}/makejinja.toml"
PYTHON_VERSION_CHECK_FILE: "{{.BOOTSTRAP_DIR}}/scripts/py_version_check.py"
PIP_REQUIREMENTS_FILE: "{{.ROOT_DIR}}/requirements.txt"
SOPS_AGE_FILE: "{{.ROOT_DIR}}/age.key"
# Binaries
PYTHON_BIN: python3
Expand All @@ -37,8 +37,9 @@ tasks:
default: task -l

init:
desc: Initialize files and directories
desc: Initialize virtual env and configuration files
cmds:
- task: setup-virtual-env
- mkdir -p {{.PRIVATE_DIR}}
- cp -n {{.BOOTSTRAP_ADDONS_FILE | replace ".yaml" ".sample.yaml"}} {{.BOOTSTRAP_ADDONS_FILE}}
- cp -n {{.BOOTSTRAP_CONFIG_FILE | replace ".yaml" ".sample.yaml"}} {{.BOOTSTRAP_CONFIG_FILE}}
Expand All @@ -50,41 +51,40 @@ tasks:
silent: true
- cmd: echo {{.BOOTSTRAP_ADDONS_FILE}}
silent: true
status:
- test -f {{.BOOTSTRAP_ADDONS_FILE}}
- test -f {{.BOOTSTRAP_CONFIG_FILE}}

configure:
desc: Configure repository from Ansible vars
prompt: Any conflicting config in the root kubernetes and ansible directories will be overwritten... continue?
cmds:
- task: .pre-validate
- task: .template
- task: .post-validate
preconditions:
- { msg: "Missing Python version check script", sh: "test -f {{.PYTHON_VERSION_CHECK_FILE}}" }
- { msg: "Python version must be 3.11 or greater", sh: "{{.PYTHON_BIN}} {{.PYTHON_VERSION_CHECK_FILE}}" }

.pre-validate:
internal: true
cmd: ./.venv/bin/ansible-playbook {{.BOOTSTRAP_DIR}}/validate.yaml
env:
ANSIBLE_DISPLAY_SKIPPED_HOSTS: "false"
preconditions:
- { msg: "Missing virtual environment", sh: "test -d {{.ROOT_DIR}}/.venv" }
- { msg: "Missing bootstrap addons file", sh: "test -f {{.BOOTSTRAP_ADDONS_FILE}}" }
- { msg: "Missing bootstrap config file", sh: "test -f {{.BOOTSTRAP_CONFIG_FILE}}" }

.template:
internal: true
cmds:
- ./.venv/bin/makejinja
- task: sops:encrypt
preconditions:
- { msg: "Missing virtual environment", sh: "test -d {{.ROOT_DIR}}/.venv" }
- { msg: "Missing Makejinja config file", sh: "test -f {{.MAKEJINJA_CONFIG_FILE}}" }
- { msg: "Missing Makejinja loader file", sh: "test -f {{.BOOTSTRAP_DIR}}/scripts/loader.py" }
- { msg: "Missing bootstrap addons file", sh: "test -f {{.BOOTSTRAP_ADDONS_FILE}}" }
- { msg: "Missing bootstrap config file", sh: "test -f {{.BOOTSTRAP_CONFIG_FILE}}" }

.post-validate:
internal: true
cmds:
- task: kubernetes:kubeconform

setup-virtual-env:
desc: Set up virtual environment
cmds:
- "{{.PYTHON_BIN}} -m venv {{.ROOT_DIR}}/.venv"
- .venv/bin/python3 -m pip install --upgrade pip setuptools wheel
- .venv/bin/python3 -m pip install --upgrade --requirement "{{.PIP_REQUIREMENTS_FILE}}"
sources:
- "{{.PIP_REQUIREMENTS_FILE}}"
generates:
- "{{.ROOT_DIR}}/.venv/pyvenv.cfg"
preconditions:
- { msg: "Missing Pip requirements file", sh: "test -f {{.PIP_REQUIREMENTS_FILE}}" }
27 changes: 23 additions & 4 deletions bootstrap/scripts/loader.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
import netaddr, bcrypt
import bcrypt
import netaddr

import validation

def nthhost(value: str, query: int) -> str:
value = netaddr.IPNetwork(value)

try:
nth = int(query)
if value.size > nth:
return str(value[nth])

except ValueError:
return False

return value

def encrypt(value: str) -> str:
return bcrypt.hashpw(value.encode(), bcrypt.gensalt(rounds=10)).decode("ascii")

class Loader:
def __init__(self, data):
if data.get("skip_tests", False):
return
validation.validate_python_version()
validation.validate_cli_tools(data)
validation.validate_distribution(data)
validation.validate_github(data)
validation.validate_age(data)
validation.validate_timezone(data)
validation.validate_acme_email(data)
validation.validate_flux_github_webhook_token(data)
validation.validate_cloudflare(data)
validation.validate_host_network(data)
validation.validate_bootstrap_dns_server(data)
validation.validate_cilium_loadbalancer_mode(data)
validation.validate_local_storage_path(data)
validation.validate_cluster_cidrs(data)
validation.validate_nodes(data)

def filters(self):
return [nthhost, encrypt]
9 changes: 0 additions & 9 deletions bootstrap/scripts/py_version_check.py

This file was deleted.

Loading