Skip to content
Draft
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
7 changes: 7 additions & 0 deletions ansible/playbooks/coachlight-infra-stack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,14 @@
vars:
k8s_validator_kubeconfig: "{{ kubeconfig_manager_artifacts.target_kubeconfig_path }}"
k8s_validator_context: "{{ kubeconfig_manager_artifacts.context_name }}"
- role: proxmox_homepage_token
vars:
proxmox_homepage_token_op_service_account_token: "{{ lookup('env', 'OP_SERVICE_ACCOUNT_TOKEN') }}"
- role: homepage_deploy
vars:
homepage_deploy_proxmox_url: "{{ proxmox_homepage_token_artifacts.url | default('') }}"
homepage_deploy_proxmox_username: "{{ proxmox_homepage_token_artifacts.username | default('') }}"
homepage_deploy_proxmox_secret: "{{ proxmox_homepage_token_artifacts.secret | default('') }}"
# - role: argocd_api_auth
# vars:
# argocd_api_auth_username: "{{ argocd_admin_username }}"
Expand Down
5 changes: 5 additions & 0 deletions ansible/roles/homepage_deploy/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ homepage_deploy_application_name: homepage
homepage_deploy_ingress_templates_root: "{{ role_path }}/templates/ingresses"

homepage_deploy_artifacts_path: "{{ artifacts_path }}"

homepage_deploy_proxmox_node_name: "{{ groups['proxmox'][0] | default('pve') }}"
homepage_deploy_proxmox_url: ""
homepage_deploy_proxmox_username: ""
homepage_deploy_proxmox_secret: ""
16 changes: 16 additions & 0 deletions ansible/roles/homepage_deploy/meta/argument_specs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,19 @@ argument_specs:
homepage_deploy_artifacts_path:
type: str
required: false
homepage_deploy_proxmox_node_name:
type: str
required: false
description: Proxmox node name for the widget configuration.
homepage_deploy_proxmox_url:
type: str
required: false
description: Proxmox API URL.
homepage_deploy_proxmox_username:
type: str
required: false
description: Proxmox API username (user@realm!tokenid).
homepage_deploy_proxmox_secret:
type: str
required: false
description: Proxmox API token secret.
9 changes: 9 additions & 0 deletions ansible/roles/homepage_deploy/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
state: present
definition: "{{ lookup('ansible.builtin.template', 'homepage-application.yml.j2') }}"

- name: Apply Homepage Proxmox ConfigMap when credentials are provided
kubernetes.core.k8s:
state: present
definition: "{{ lookup('ansible.builtin.template', 'homepage-proxmox-configmap.yml.j2') }}"
when:
- homepage_deploy_proxmox_url | length > 0
- homepage_deploy_proxmox_username | length > 0
- homepage_deploy_proxmox_secret | length > 0

- name: Discover Homepage ingress templates
ansible.builtin.find:
paths: "{{ homepage_deploy_ingress_templates_root }}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ spec:
main:
enabled: false

{% if homepage_deploy_proxmox_url | length > 0 and homepage_deploy_proxmox_username | length > 0 and homepage_deploy_proxmox_secret | length > 0 %}
persistence:
proxmox:
enabled: true
type: configMap
name: homepage-proxmox-config
mountPath: /app/config/proxmox.yaml
subPath: proxmox.yaml
readOnly: true
{% endif %}

env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: "homepage.rohu-shark.ts.net"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: homepage-proxmox-config
namespace: {{ homepage_deploy_namespace }}
data:
proxmox.yaml: |
{{ homepage_deploy_proxmox_node_name }}:
url: {{ homepage_deploy_proxmox_url }}
username: {{ homepage_deploy_proxmox_username }}
password: {{ homepage_deploy_proxmox_secret }}
9 changes: 9 additions & 0 deletions ansible/roles/proxmox_homepage_token/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
proxmox_homepage_token_user: api@pam
proxmox_homepage_token_group: api-ro-users
proxmox_homepage_token_role: PVEAuditor
proxmox_homepage_token_id: homepage
proxmox_homepage_token_1p_vault: coachlight-homelab
proxmox_homepage_token_1p_item_title: proxmox-homepage-token
proxmox_homepage_token_url: "https://{{ hostvars[groups['proxmox'][0]].ansible_host }}:8006"
proxmox_homepage_token_primary_node: "{{ groups['proxmox'][0] }}"
proxmox_homepage_token_artifacts_path: "{{ artifacts_path }}"
43 changes: 43 additions & 0 deletions ansible/roles/proxmox_homepage_token/meta/argument_specs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
argument_specs:
main:
options:
proxmox_homepage_token_user:
type: str
required: false
description: Proxmox user for Homepage API token (e.g., api@pam).
proxmox_homepage_token_group:
type: str
required: false
description: Proxmox group for read-only API access.
proxmox_homepage_token_role:
type: str
required: false
description: Proxmox role to assign to the group (e.g., PVEAuditor).
proxmox_homepage_token_id:
type: str
required: false
description: Token ID for the Homepage token.
proxmox_homepage_token_1p_vault:
type: str
required: false
description: 1Password vault name for storing the token.
proxmox_homepage_token_1p_item_title:
type: str
required: false
description: 1Password item title for the token.
proxmox_homepage_token_url:
type: str
required: false
description: Proxmox API URL including scheme and port.
proxmox_homepage_token_primary_node:
type: str
required: false
description: Primary Proxmox node to run pveum commands on.
proxmox_homepage_token_artifacts_path:
type: str
required: false
description: Base path for artifacts output.
proxmox_homepage_token_op_service_account_token:
type: str
required: false
description: 1Password service account token for API access.
174 changes: 174 additions & 0 deletions ansible/roles/proxmox_homepage_token/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
- name: Ensure 1Password vault exists for {{ proxmox_homepage_token_1p_vault }}
ansible.builtin.include_role:
name: op_vault_validator
vars:
op_vault_validator_vault_name: "{{ proxmox_homepage_token_1p_vault }}"
op_vault_validator_op_service_account_token: "{{ proxmox_homepage_token_op_service_account_token }}"
op_vault_validator_artifacts_path: "{{ proxmox_homepage_token_artifacts_path }}/op_vault_validator"

- name: Initialize proxmox_homepage_token facts
ansible.builtin.set_fact:
proxmox_homepage_token_url_value: ""
proxmox_homepage_token_username_value: ""
proxmox_homepage_token_secret_value: ""
proxmox_homepage_token_exists: false

- name: Check if 1Password item {{ proxmox_homepage_token_1p_item_title }} exists
ansible.builtin.command:
cmd: >-
op item get {{ proxmox_homepage_token_1p_item_title }}
--vault {{ proxmox_homepage_token_1p_vault }}
--format json
environment:
OP_SERVICE_ACCOUNT_TOKEN: "{{ proxmox_homepage_token_op_service_account_token }}"
register: proxmox_homepage_token_1p_item_check
changed_when: false
failed_when: false

- name: Read existing token from 1Password when item exists
ansible.builtin.include_role:
name: op_read
vars:
op_read_items:
- vault_name: "{{ proxmox_homepage_token_1p_vault }}"
item_name: "{{ proxmox_homepage_token_1p_item_title }}"
field_name: url
- vault_name: "{{ proxmox_homepage_token_1p_vault }}"
item_name: "{{ proxmox_homepage_token_1p_item_title }}"
field_name: username
- vault_name: "{{ proxmox_homepage_token_1p_vault }}"
item_name: "{{ proxmox_homepage_token_1p_item_title }}"
field_name: credential
op_read_op_service_account_token: "{{ proxmox_homepage_token_op_service_account_token }}"
op_read_artifacts_path: "{{ proxmox_homepage_token_artifacts_path }}/op_read"
when: proxmox_homepage_token_1p_item_check.rc == 0

- name: Set facts from existing 1Password item when present
ansible.builtin.set_fact:
proxmox_homepage_token_url_value: "{{ op_read_artifacts.items | selectattr('field_name', 'equalto', 'url') | map(attribute='value') | first }}"
proxmox_homepage_token_username_value: "{{ op_read_artifacts.items | selectattr('field_name', 'equalto', 'username') | map(attribute='value') | first }}"
proxmox_homepage_token_secret_value: "{{ op_read_artifacts.items | selectattr('field_name', 'equalto', 'credential') | map(attribute='value') | first }}"
proxmox_homepage_token_exists: true
when: proxmox_homepage_token_1p_item_check.rc == 0

- name: Ensure Proxmox group {{ proxmox_homepage_token_group }} exists
ansible.builtin.command:
cmd: pveum group add {{ proxmox_homepage_token_group }}
delegate_to: "{{ proxmox_homepage_token_primary_node }}"
register: proxmox_homepage_token_group_add
changed_when: "'already exists' not in proxmox_homepage_token_group_add.stderr"
failed_when:
- proxmox_homepage_token_group_add.rc != 0
- "'already exists' not in proxmox_homepage_token_group_add.stderr"
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Ensure Proxmox user {{ proxmox_homepage_token_user }} exists
ansible.builtin.command:
cmd: pveum user add {{ proxmox_homepage_token_user }}
delegate_to: "{{ proxmox_homepage_token_primary_node }}"
register: proxmox_homepage_token_user_add
changed_when: "'already exists' not in proxmox_homepage_token_user_add.stderr"
failed_when:
- proxmox_homepage_token_user_add.rc != 0
- "'already exists' not in proxmox_homepage_token_user_add.stderr"
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Add user {{ proxmox_homepage_token_user }} to group {{ proxmox_homepage_token_group }}
ansible.builtin.command:
cmd: pveum user modify {{ proxmox_homepage_token_user }} -group {{ proxmox_homepage_token_group }}
delegate_to: "{{ proxmox_homepage_token_primary_node }}"
register: proxmox_homepage_token_user_modify
changed_when: true
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Set ACL for group {{ proxmox_homepage_token_group }} with role {{ proxmox_homepage_token_role }}
ansible.builtin.command:
cmd: >-
pveum acl modify /
-group {{ proxmox_homepage_token_group }}
-role {{ proxmox_homepage_token_role }}
-propagate 1
delegate_to: "{{ proxmox_homepage_token_primary_node }}"
register: proxmox_homepage_token_acl_modify
changed_when: true
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Check if API token {{ proxmox_homepage_token_user }}!{{ proxmox_homepage_token_id }} exists
ansible.builtin.command:
cmd: pveum user token list {{ proxmox_homepage_token_user }}
delegate_to: "{{ proxmox_homepage_token_primary_node }}"
register: proxmox_homepage_token_list
changed_when: false
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Remove existing API token {{ proxmox_homepage_token_user }}!{{ proxmox_homepage_token_id }} if present
ansible.builtin.command:
cmd: pveum user token remove {{ proxmox_homepage_token_user }} {{ proxmox_homepage_token_id }}
delegate_to: "{{ proxmox_homepage_token_primary_node }}"
register: proxmox_homepage_token_remove
changed_when: true
when:
- proxmox_homepage_token_1p_item_check.rc != 0
- proxmox_homepage_token_list.stdout is defined
- proxmox_homepage_token_id in proxmox_homepage_token_list.stdout

- name: Create API token {{ proxmox_homepage_token_user }}!{{ proxmox_homepage_token_id }} with privsep
ansible.builtin.command:
cmd: pveum user token add {{ proxmox_homepage_token_user }} {{ proxmox_homepage_token_id }} --privsep 1 --output-format json
delegate_to: "{{ proxmox_homepage_token_primary_node }}"
register: proxmox_homepage_token_create
changed_when: true
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Parse token creation output when token was created
ansible.builtin.set_fact:
proxmox_homepage_token_secret_new: "{{ (proxmox_homepage_token_create.stdout | from_json).value }}"
when:
- proxmox_homepage_token_1p_item_check.rc != 0
- proxmox_homepage_token_create is defined
- proxmox_homepage_token_create.stdout is defined

- name: Create 1Password item for new token
ansible.builtin.include_role:
name: op_item_create
vars:
op_item_create_vault_name: "{{ proxmox_homepage_token_1p_vault }}"
op_item_create_op_service_account_token: "{{ proxmox_homepage_token_op_service_account_token }}"
op_item_create_artifacts_path: "{{ proxmox_homepage_token_artifacts_path }}/op_item_create"
op_item_create_items:
- name: "{{ proxmox_homepage_token_1p_item_title }}"
category: api_credential
url: "{{ proxmox_homepage_token_url }}"
tags:
- ansible_managed
- proxmox
- homepage
fields:
username[text]: "{{ proxmox_homepage_token_user }}!{{ proxmox_homepage_token_id }}"
credential[concealed]: "{{ proxmox_homepage_token_secret_new }}"
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Set facts from newly created token
ansible.builtin.set_fact:
proxmox_homepage_token_url_value: "{{ proxmox_homepage_token_url }}"
proxmox_homepage_token_username_value: "{{ proxmox_homepage_token_user }}!{{ proxmox_homepage_token_id }}"
proxmox_homepage_token_secret_value: "{{ proxmox_homepage_token_secret_new }}"
proxmox_homepage_token_exists: true
when: proxmox_homepage_token_1p_item_check.rc != 0

- name: Build proxmox_homepage_token_artifacts
ansible.builtin.set_fact:
proxmox_homepage_token_artifacts:
url: "{{ proxmox_homepage_token_url_value }}"
username: "{{ proxmox_homepage_token_username_value }}"
secret: "{{ proxmox_homepage_token_secret_value }}"
exists: "{{ proxmox_homepage_token_exists }}"

- name: Record proxmox_homepage_token artifacts
ansible.builtin.include_role:
name: role_artifacts
vars:
# noqa: var-naming
role_artifacts_path: "{{ proxmox_homepage_token_artifacts_path }}"
calling_role_name: proxmox_homepage_token
calling_role_artifacts_inputs: "{{ proxmox_homepage_token_artifacts }}"