Compare commits
2 Commits
test
...
0ee4990960
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ee4990960 | |||
| 93d14fedbe |
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"MD041": false
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
---
|
|
||||||
name: Ansible Best Practices
|
|
||||||
description: Ansible best practices and conventions
|
|
||||||
alwaysApply: false
|
|
||||||
globs:
|
|
||||||
- "**/*.yml"
|
|
||||||
- "**/*.yaml"
|
|
||||||
---
|
|
||||||
|
|
||||||
You are an expert Ansible automation engineer.
|
|
||||||
|
|
||||||
When working with Ansible content, always follow these rules:
|
|
||||||
|
|
||||||
## General
|
|
||||||
|
|
||||||
- Prefer **idempotent** solutions; tasks must be safe to run multiple times.
|
|
||||||
- Use **Ansible built-in modules** instead of shell or command whenever possible.
|
|
||||||
- Do not assume root access; use `become: true` only when required.
|
|
||||||
- Avoid hard-coded values; prefer variables, defaults, and group/host vars.
|
|
||||||
- Use clear, descriptive task names.
|
|
||||||
- Ensure all YAML is valid, properly indented, and ansible-lint compliant.
|
|
||||||
- Favor clarity and maintainability over cleverness.
|
|
||||||
- Add README files to complex directories.
|
|
||||||
- Document complex algorithms and business rules.
|
|
||||||
- Maintain up-to-date dependencies list.
|
|
||||||
|
|
||||||
## Security Hardening
|
|
||||||
|
|
||||||
- **Never embed secrets** directly in playbooks, roles, or templates.
|
|
||||||
- Use **Ansible Vault**, external secret managers, or injected variables for secrets.
|
|
||||||
- Mark sensitive tasks with:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
no_log: true
|
|
||||||
```
|
|
||||||
|
|
||||||
- Avoid leaking secrets via debug, register, or error messages.
|
|
||||||
- Use least privilege:
|
|
||||||
- Avoid running entire plays as root.
|
|
||||||
- Scope become to individual tasks where possible.
|
|
||||||
- Set secure file permissions explicitly:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
mode: "0640"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
```
|
|
||||||
|
|
||||||
- Validate downloaded files using checksums.
|
|
||||||
- Avoid ignore_errors for security-sensitive operations.
|
|
||||||
- Do not disable SSL/TLS validation unless explicitly required and documented.
|
|
||||||
- Prefer validate_certs: true for network modules.
|
|
||||||
- Assume hosts may be compromised—do not trust remote state blindly.
|
|
||||||
|
|
||||||
## Playbooks
|
|
||||||
|
|
||||||
- Use `hosts`, `gather_facts`, and `become` explicitly.
|
|
||||||
- Keep playbooks minimal; delegate logic to roles.
|
|
||||||
- Apply tags consistently for safe partial execution.
|
|
||||||
- Use serial for rolling updates to reduce blast radius.
|
|
||||||
- Avoid large monolithic plays.
|
|
||||||
|
|
||||||
## Roles
|
|
||||||
|
|
||||||
- Follow the standard role structure:
|
|
||||||
(`tasks/`, `handlers/`, `defaults/`, `vars/`, `templates/`, `files/`).
|
|
||||||
- Put overridable values in `defaults/main.yml`.
|
|
||||||
- Put non-overridable or internal values in `vars/main.yml`.
|
|
||||||
- Namespace all role variables (role_name_variable).
|
|
||||||
- Use meta/main.yml to define role dependencies.
|
|
||||||
- Use handlers only when a change requires a follow-up action.
|
|
||||||
|
|
||||||
## Tasks
|
|
||||||
|
|
||||||
- Always name tasks clearly and descriptively.
|
|
||||||
- Use `state: present/absent/latest` explicitly.
|
|
||||||
- Register variables only when they are actually used.
|
|
||||||
- Use `changed_when` and `failed_when` to ensure correct task status.
|
|
||||||
- Avoid `ignore_errors` unless absolutely necessary.
|
|
||||||
- Avoid shell unless absolutely unavoidable; document why if used.
|
|
||||||
- Prefer creates and removes when using command-like tasks.
|
|
||||||
- Avoid unnecessary loops; simplify logic where possible.
|
|
||||||
|
|
||||||
## Variables & Templates
|
|
||||||
|
|
||||||
- Use snake_case for variable names.
|
|
||||||
- Quote variables in YAML to prevent parsing issues.
|
|
||||||
- Namespace role variables (e.g., `nginx_port`, not `port`).
|
|
||||||
- Avoid complex logic in templates—use when instead.
|
|
||||||
- Use Jinja2 filters safely and defensively (default, bool, int).
|
|
||||||
- Do not reference undefined variables without defaults.
|
|
||||||
|
|
||||||
## Conditionals & Loops
|
|
||||||
|
|
||||||
- Use when for conditionals.
|
|
||||||
- Prefer `loop` over deprecated `with_*`.
|
|
||||||
- Use `ansible_facts` instead of shell commands for system data.
|
|
||||||
- Avoid deeply nested conditionals.
|
|
||||||
|
|
||||||
## Error Handling & Validation
|
|
||||||
|
|
||||||
- Fail fast on critical errors.
|
|
||||||
- Use assert to validate assumptions.
|
|
||||||
- Use check_mode compatibility whenever possible.
|
|
||||||
- Ensure tasks behave correctly in --diff and --check.
|
|
||||||
|
|
||||||
## Linting & Compatibility
|
|
||||||
|
|
||||||
- Code must comply with ansible-lint.
|
|
||||||
- Write code compatible with recent Ansible versions.
|
|
||||||
- Avoid deprecated modules and syntax.
|
|
||||||
- Do not rely on undefined behavior or undocumented features.
|
|
||||||
|
|
||||||
## Performance & Reliability (Tips & Tricks)
|
|
||||||
|
|
||||||
- Use gather_facts: false if facts are not needed.
|
|
||||||
- Use run_once and delegate_to when appropriate.
|
|
||||||
- Cache facts when operating at scale.
|
|
||||||
- Avoid repeated expensive operations.
|
|
||||||
- Prefer block for grouping related tasks and error handling.
|
|
||||||
|
|
||||||
## Output Expectations
|
|
||||||
|
|
||||||
- Generated YAML must be valid and properly indented.
|
|
||||||
- Provide minimal but sufficient comments when clarity is needed.
|
|
||||||
- Do not include explanations unless explicitly requested.
|
|
||||||
- Assume production usage and security-sensitive environments.
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
---
|
|
||||||
name: Project README Standards
|
|
||||||
globs: "**/README.md"
|
|
||||||
alwaysApply: false
|
|
||||||
description: Guidelines for creating comprehensive project README files
|
|
||||||
tags:
|
|
||||||
- readme
|
|
||||||
- documentation
|
|
||||||
- markdown
|
|
||||||
- project-setup
|
|
||||||
- best-practices
|
|
||||||
---
|
|
||||||
|
|
||||||
You are an expert in:
|
|
||||||
|
|
||||||
- technical documentation
|
|
||||||
- open source best practices
|
|
||||||
- developer experience.
|
|
||||||
|
|
||||||
## README Structure
|
|
||||||
|
|
||||||
A well-structured README should include these sections in order:
|
|
||||||
|
|
||||||
1. Project Title and Description
|
|
||||||
2. Badges (build status, version, license)
|
|
||||||
3. Key Features
|
|
||||||
4. Screenshots/Demo (if applicable)
|
|
||||||
5. Quick Start
|
|
||||||
6. Installation
|
|
||||||
7. Usage Examples
|
|
||||||
8. API Reference (or link to docs)
|
|
||||||
9. Configuration
|
|
||||||
10. Contributing
|
|
||||||
11. License
|
|
||||||
|
|
||||||
## Essential Sections
|
|
||||||
|
|
||||||
### Project Header
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# Project Name
|
|
||||||
|
|
||||||
> One-line description of what this project does
|
|
||||||
|
|
||||||
[](https://github.com/user/repo/actions)
|
|
||||||
[](https://www.npmjs.com/package/package-name)
|
|
||||||
[](LICENSE)
|
|
||||||
|
|
||||||
Brief paragraph explaining the project's purpose, main features,
|
|
||||||
and why someone would want to use it.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Quick Start
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
Get up and running in less than 5 minutes:
|
|
||||||
|
|
||||||
\`\`\`bash
|
|
||||||
npm install package-name
|
|
||||||
npm run dev
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
Visit http://localhost:3000 to see the application.
|
|
||||||
```
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- Node.js 18+
|
|
||||||
- PostgreSQL 14+
|
|
||||||
- Redis 6.2+
|
|
||||||
|
|
||||||
### Install from npm
|
|
||||||
|
|
||||||
\`\`\`bash
|
|
||||||
npm install package-name
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### Install from source
|
|
||||||
|
|
||||||
\`\`\`bash
|
|
||||||
git clone https://github.com/user/repo.git
|
|
||||||
cd repo
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
\`\`\`
|
|
||||||
```
|
|
||||||
|
|
||||||
### Usage Examples
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Basic Example
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
import { Widget } from 'package-name';
|
|
||||||
|
|
||||||
const widget = new Widget({
|
|
||||||
apiKey: 'your-api-key',
|
|
||||||
theme: 'dark'
|
|
||||||
});
|
|
||||||
|
|
||||||
widget.render('#app');
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
### Advanced Example
|
|
||||||
|
|
||||||
\`\`\`javascript
|
|
||||||
// Custom configuration with error handling
|
|
||||||
const widget = new Widget({
|
|
||||||
apiKey: process.env.API_KEY,
|
|
||||||
theme: 'dark',
|
|
||||||
onError: (error) => {
|
|
||||||
console.error('Widget error:', error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add custom event handlers
|
|
||||||
widget.on('ready', () => {
|
|
||||||
console.log('Widget is ready');
|
|
||||||
});
|
|
||||||
|
|
||||||
widget.render('#app');
|
|
||||||
\`\`\`
|
|
||||||
```
|
|
||||||
|
|
||||||
## Best Practices
|
|
||||||
|
|
||||||
- Keep the README focused and concise
|
|
||||||
- Use clear, simple language
|
|
||||||
- Include code examples that actually work
|
|
||||||
- Add visuals when they help understanding
|
|
||||||
- Link to more detailed documentation
|
|
||||||
- Keep examples up-to-date with the code
|
|
||||||
- Test your installation instructions regularly
|
|
||||||
|
|
||||||
## Common Mistakes to Avoid
|
|
||||||
|
|
||||||
- Don't assume reader knowledge
|
|
||||||
- Don't skip the Quick Start section
|
|
||||||
- Don't use jargon without explanation
|
|
||||||
- Don't forget to update version numbers
|
|
||||||
- Don't include sensitive information
|
|
||||||
|
|
||||||
## Formatting Tips
|
|
||||||
|
|
||||||
- Use consistent heading levels
|
|
||||||
- Include a table of contents for long READMEs
|
|
||||||
- Use code blocks with language highlighting
|
|
||||||
- Add alt text to images
|
|
||||||
- Use tables for comparing options
|
|
||||||
- Include emoji sparingly and purposefully
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
---
|
|
||||||
# https://github.com/kekxv/AiReviewPR
|
|
||||||
name: ai-reviews
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened, synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
review:
|
|
||||||
name: Review PR
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
# Number of commits to fetch. 0 indicates all history for all
|
|
||||||
# branches and tags.
|
|
||||||
# Default: 1
|
|
||||||
fetch-depth: 0
|
|
||||||
# The base URL for the GitHub instance that you are trying to clone
|
|
||||||
# from, will use environment defaults to fetch from the same instance
|
|
||||||
# that the workflow is running from unless specified.
|
|
||||||
# Example URLs are https://github.com or
|
|
||||||
# https://my-ghes-server.example.com
|
|
||||||
github-server-url: ${{ vars.GIT_SERVER_URL }}
|
|
||||||
|
|
||||||
- name: Review code
|
|
||||||
uses: kekxv/AiReviewPR@v0.1.0
|
|
||||||
with:
|
|
||||||
model: ${{ vars.OLLAMA_MODEL }}
|
|
||||||
host: http://192.168.2.233:11435
|
|
||||||
# host: ${{ vars.OLLAMA_HOST }}
|
|
||||||
# ai_token: ${{ secrets.AI_TOKEN }}
|
|
||||||
REVIEW_PULL_REQUEST: false
|
|
||||||
LANGUAGE: English
|
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
---
|
# .github/workflows/ansible-lint.yml
|
||||||
# .gitea/workflows/ansible-lint.yml
|
|
||||||
name: ansible-lint
|
name: ansible-lint
|
||||||
|
|
||||||
on: [pull_request, issues, push]
|
on: [pull_request, issues, push]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Ansible Lint
|
name: Ansible Lint # Naming the build is important to use it as a status check
|
||||||
# Naming the build is important to use it as a status check
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
github-server-url: ${{ vars.GIT_SERVER_URL }}
|
github-server-url: ${{ vars.GIT_SERVER_URL }}
|
||||||
|
|
||||||
@@ -23,11 +21,7 @@ jobs:
|
|||||||
- name: Install ansible-lint
|
- name: Install ansible-lint
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install ansible ansible-lint yamllint
|
pip install ansible ansible-lint
|
||||||
|
|
||||||
- name: Run yamllint
|
|
||||||
run: |
|
|
||||||
yamllint .
|
|
||||||
|
|
||||||
- name: Run ansible-lint
|
- name: Run ansible-lint
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
---
|
|
||||||
name: Gitleaks Scan
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
gitleaks:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Install Gitleaks
|
|
||||||
run: |
|
|
||||||
curl -sSL https://github.com/gitleaks/gitleaks/releases/download/v8.30.0/gitleaks_8.30.0_linux_x64.tar.gz \
|
|
||||||
| tar -xz
|
|
||||||
sudo mv gitleaks /usr/local/bin/
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
github-server-url: ${{ vars.GIT_SERVER_URL }}
|
|
||||||
|
|
||||||
- name: Run Gitleaks
|
|
||||||
run: |
|
|
||||||
gitleaks dir . \
|
|
||||||
--redact=10 \
|
|
||||||
--verbose \
|
|
||||||
--exit-code 1
|
|
||||||
# gitleaks detect \
|
|
||||||
# --source . \
|
|
||||||
# --no-git \
|
|
||||||
# --redact=20 \
|
|
||||||
# --verbose \
|
|
||||||
# --exit-code 1
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
---
|
|
||||||
# .gitea/workflows/markdown-lint.yml
|
|
||||||
name: Markdown Lint
|
|
||||||
|
|
||||||
on: [pull_request, issues, push]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: markdown-lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
github-server-url: ${{ vars.GIT_SERVER_URL }}
|
|
||||||
|
|
||||||
- name: Install Node.js & markdownlint
|
|
||||||
run: |
|
|
||||||
apt-get update && apt-get install -y npm
|
|
||||||
npm install -g markdownlint-cli2
|
|
||||||
|
|
||||||
- name: Run lint
|
|
||||||
run: markdownlint-cli2 "**/*.md" "#node_modules"
|
|
||||||
|
|
||||||
# on:
|
|
||||||
# push:
|
|
||||||
# branches:
|
|
||||||
# - main
|
|
||||||
# pull_request:
|
|
||||||
# branches:
|
|
||||||
# - main
|
|
||||||
|
|
||||||
# jobs:
|
|
||||||
# markdown-lint:
|
|
||||||
# runs-on: docker
|
|
||||||
# container:
|
|
||||||
# image: node:20-alpine
|
|
||||||
# steps:
|
|
||||||
# - name: Install dependencies
|
|
||||||
# run: |
|
|
||||||
# apk add --no-cache git
|
|
||||||
# npm install -g markdownlint-cli2
|
|
||||||
|
|
||||||
# - name: Run Markdown lint
|
|
||||||
# run: |
|
|
||||||
# markdownlint-cli2 "**/*.md" "#node_modules"
|
|
||||||
|
|
||||||
#########################################à
|
|
||||||
|
|
||||||
# ---
|
|
||||||
# https://github.com/marketplace/actions/markdownlint-cli2-action
|
|
||||||
# name: Markdown Lint
|
|
||||||
|
|
||||||
# on: [pull_request, push]
|
|
||||||
|
|
||||||
# jobs:
|
|
||||||
# build:
|
|
||||||
# name: markdown-lint
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
# steps:
|
|
||||||
# - name: Checkout code
|
|
||||||
# uses: actions/checkout@v4
|
|
||||||
# with:
|
|
||||||
# github-server-url: ${{ vars.GIT_SERVER_URL }}
|
|
||||||
|
|
||||||
# - name: Markdown lint
|
|
||||||
# uses: DavidAnson/markdownlint-cli2-action@v22
|
|
||||||
# with:
|
|
||||||
# globs: '**/*.md'
|
|
||||||
# fix: true
|
|
||||||
# continue-on-error: true
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
---
|
|
||||||
# This workflow warns and then closes issues and PRs that have
|
|
||||||
# had no activity for a specified amount of time.
|
|
||||||
#
|
|
||||||
# You can adjust the behavior by modifying this file.
|
|
||||||
# For more information, see:
|
|
||||||
# https://github.com/actions/stale
|
|
||||||
name: Mark stale issues and pull requests
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '21 3 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write # for actions/stale to close stale issues
|
|
||||||
pull-requests: write # for actions/stale to close stale PRs
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# - name: Checkout code
|
|
||||||
# uses: actions/checkout@v4
|
|
||||||
# with:
|
|
||||||
# # Number of commits to fetch. 0 indicates all history for all branches
|
|
||||||
# # and tags.
|
|
||||||
# # Default: 1
|
|
||||||
# fetch-depth: 0
|
|
||||||
# # The base URL for the GitHub instance that you are trying to clone from,
|
|
||||||
# # will use environment defaults to fetch from the same instance that the
|
|
||||||
# # workflow is running from unless specified.
|
|
||||||
# # Example URLs are https://github.com or
|
|
||||||
# # https://my-ghes-server.example.com
|
|
||||||
# github-server-url: ${{ vars.GIT_SERVER_URL }}
|
|
||||||
|
|
||||||
# The 90 day stale policy
|
|
||||||
# Used for:
|
|
||||||
# - Issues & PRs
|
|
||||||
# - No PRs marked as no-stale or pinned
|
|
||||||
# - No issues marked as no-stale, help-wanted or pinned
|
|
||||||
- name: 90 days stale issues & PRs policy
|
|
||||||
uses: actions/stale@v9.1.0
|
|
||||||
with:
|
|
||||||
# repo-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
|
||||||
days-before-stale: 90
|
|
||||||
days-before-close: 7
|
|
||||||
operations-per-run: 150
|
|
||||||
remove-stale-when-updated: true
|
|
||||||
stale-issue-label: "stale"
|
|
||||||
exempt-issue-labels: "no-stale,help-wanted,pinned,enhancement"
|
|
||||||
stale-issue-message: >
|
|
||||||
There hasn't been any activity on this issue recently. To keep our
|
|
||||||
backlog manageable we have to clean old issues, as many of them have
|
|
||||||
already been resolved with the latest updates.
|
|
||||||
|
|
||||||
Please make sure to update to the latest version and check if that
|
|
||||||
solves the issue. Let us know if that works for you by adding a
|
|
||||||
comment 👍
|
|
||||||
|
|
||||||
This issue has now been marked as stale and will be closed if no
|
|
||||||
further activity occurs. Thank you for your contributions.
|
|
||||||
|
|
||||||
stale-pr-label: "stale"
|
|
||||||
exempt-pr-labels: "no-stale,pinned"
|
|
||||||
stale-pr-message: >
|
|
||||||
There hasn't been any activity on this pull request recently. This
|
|
||||||
pull request has been automatically marked as stale because of that
|
|
||||||
and will be closed if no further activity occurs within 7 days.
|
|
||||||
|
|
||||||
Thank you for your contributions.
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"MD013": {
|
|
||||||
"line_length": 100,
|
|
||||||
"code_block_line_length": 120,
|
|
||||||
"tables": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# ignore files completely
|
|
||||||
.continue/rules/**/*.md
|
|
||||||
23
.yamllint
23
.yamllint
@@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
# This is my first, very own configuration file for yamllint!
|
|
||||||
# It extends the default conf by adjusting some options.
|
|
||||||
|
|
||||||
extends: default
|
|
||||||
|
|
||||||
rules:
|
|
||||||
comments-indentation: disable # don't bother me with this rule
|
|
||||||
truthy:
|
|
||||||
allowed-values: ['true', 'false', 'yes', 'no', 'on']
|
|
||||||
comments:
|
|
||||||
min-spaces-from-content: 1
|
|
||||||
|
|
||||||
braces:
|
|
||||||
max-spaces-inside: 1
|
|
||||||
|
|
||||||
octal-values:
|
|
||||||
forbid-implicit-octal: true
|
|
||||||
forbid-explicit-octal: true
|
|
||||||
|
|
||||||
line-length:
|
|
||||||
max: 120
|
|
||||||
allow-non-breakable-words: true
|
|
||||||
282
README.md
282
README.md
@@ -1,110 +1,51 @@
|
|||||||
# ansible_proxmox_WOL
|
# ansible_proxmox_WOL
|
||||||
|
|
||||||
An Ansible role that configures **persistent Wake‑on‑LAN (WOL)** on Proxmox VE hosts.
|
A robust, idempotent Ansible role for enabling persistent Wake-on-LAN (WOL) on Proxmox VE servers. This role automatically detects physical network interfaces with WOL capability using Ansible facts and persistently enables WOL via udev rules.
|
||||||
It discovers all physical Ethernet interfaces, validates WOL support, and then enables or disables
|
|
||||||
WOL on the interfaces that back the bridges you specify. Unlike many WOL setups that rely on
|
|
||||||
*udev* rules, this role uses a lightweight **systemd template unit** (`wol@.service`) so the setting
|
|
||||||
is applied automatically each time an interface comes up, and it survives reboots without any extra
|
|
||||||
steps.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
- [Features](#features)
|
|
||||||
- [Prerequisites](#prerequisites)
|
|
||||||
- [Role Variables](#role-variables)
|
|
||||||
- [How It Works](#how-it-works)
|
|
||||||
- [Usage](#usage)
|
|
||||||
- [Common Proxmox Scenarios](#common-proxmox-scenarios)
|
|
||||||
- [Troubleshooting](#troubleshooting)
|
|
||||||
- [License](#license)
|
|
||||||
- [Author](#author)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
| Feature | Description |
|
✅ **Fully Idempotent**: Checks current WOL status and only applies changes when needed
|
||||||
|---------|-------------|
|
✅ **Bridge Support**: Automatically detects physical interfaces backing configured bridges
|
||||||
| ✅ Fully idempotent | Only touches an interface if the desired WOL mode differs from what `ethtool` currently reports. |
|
✅ **Bond0 Detection**: Automatically detects and configures bonded interfaces
|
||||||
| ✅ Multiple bridge support | Pass a single string or a list of bridge names to `wol_bridges`. |
|
✅ **Ansible Facts-Based**: Uses Ansible facts to detect and validate WOL-capable interfaces
|
||||||
| ✅ Bond0 detection | If a bridge is built on a bond (e.g., `bond0`), all slaves receive the same WOL configuration. |
|
✅ **Persistent**: Uses udev rules for persistence across reboots
|
||||||
| ✅ Facts‑driven | Uses Ansible facts (`ansible_interfaces`) to filter out virtual and non‑Ethernet devices. |
|
✅ **Comprehensive Validation**: Verifies WOL capability before configuration
|
||||||
| ✅ Persistent via systemd | WOL is enforced by a `wol@.service` template that is started for each enabled interface. |
|
✅ **Detailed Reporting**: Shows configuration status and MAC addresses for WOL senders
|
||||||
| ✅ Comprehensive validation | Each interface is queried with `ethtool` to confirm real WOL support before making any changes. |
|
|
||||||
| ✅ Detailed reporting | The role prints a summary of every interface it touched, including the MAC addresses of WOL‑capable senders when `wol_report_mac` is `true`. |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
| Requirement | How the role satisfies it |
|
|
||||||
|-------------|---------------------------|
|
|
||||||
| **Proxmox VE host** | Target host runs Debian‑based Proxmox (the role uses Debian/Proxmox defaults). |
|
|
||||||
| **Ansible ≥ 2.9** | The role only uses built‑in modules (`setup`, `package`, `command`, `template`, `systemd`). |
|
|
||||||
| **ethtool** | The role installs the `ethtool` package if it is not already present. |
|
|
||||||
| **Root / sudo access** | All tasks modify network configuration; `become: true` is required. |
|
|
||||||
| **BIOS/WMI WOL** | WOL must be enabled in the host BIOS and the NIC driver must expose the `Wake‑On‑LAN` flag. |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Role Variables
|
## Role Variables
|
||||||
|
|
||||||
```yaml
|
| Variable | Default | Type | Description |
|
||||||
# defaults/main.yml
|
|----------|---------|------|-------------|
|
||||||
wol_bridges: vmbr0 # string or list – bridges that should have WOL enabled
|
| `wol_bridges` | `vmbr0` | string/list | Bridge interface(s) to enable WOL on. Can be a single bridge as string or multiple bridges as a list. |
|
||||||
wol_mode: "g" # "g"=magic packet (recommended), "d"=disable, "p"/"u"/"m"/"b" for other modes
|
| `wol_mode` | `g` | string | WOL mode: `g` (magic packet - recommended), `d` (disable), `p` (physical activity), `u` (unicast), `m` (multicast), `b` (broadcast) |
|
||||||
wol_verify: true # Verify the interface state after changes
|
| `wol_verify` | `true` | boolean | Verify WOL status after configuration and display results |
|
||||||
wol_report_mac: true # Include MAC addresses of WOL-capable senders in the report
|
| `wol_report_mac` | `true` | boolean | Include MAC addresses in configuration report |
|
||||||
```
|
|
||||||
|
|
||||||
| Variable | Default | Type | Description |
|
|
||||||
|----------------|---------|-----------|-------------|
|
|
||||||
| `wol_bridges` | `vmbr0` | string/list | Bridge(s) to configure. If you pass a string, the role treats it as a single‑item list. |
|
|
||||||
| `wol_mode` | `"g"` | string | Desired WOL mode. See the variable table above for valid options. |
|
|
||||||
| `wol_verify` | `true` | bool | Whether to run `ethtool` again after the changes and include the result in the final report. |
|
|
||||||
| `wol_report_mac` | `true` | bool | Whether to list the MAC address of each NIC that will send WOL packets. |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
1. **Package Install** – Ensures the `ethtool` binary is present.
|
1. **Package Installation**: Ensures `ethtool` is installed for WOL management
|
||||||
2. **Interface Discovery** – Uses `ansible_facts.ansible_interfaces` to collect *all* interfaces,
|
2. **Interface Discovery**: Uses Ansible facts to identify all physical Ethernet interfaces
|
||||||
then filters out virtual ones (`veth*`, `tap*`, `docker*`, etc.).
|
3. **Bridge Mapping**: Detects physical interfaces backing configured bridges
|
||||||
3. **WOL Validation** – For each remaining physical NIC, `ethtool <iface> | grep 'Wake-on'`
|
4. **Bond0 Detection**: Identifies bonded interfaces and their slaves
|
||||||
is used to confirm that the NIC supports WOL.
|
5. **WOL Validation**: Tests each interface for Wake-on-LAN capability using ethtool
|
||||||
4. **Bridge Mapping** – Resolves each bridge name in `wol_bridges` to the physical interface(s).
|
6. **Idempotency Check**: Reads current WOL status to avoid redundant changes
|
||||||
If a bridge is built on a bond (e.g., `bond0`), every slave is treated as a candidate.
|
7. **Enable WOL**: Applies WOL settings only to interfaces that need it
|
||||||
5. **Idempotency Check** – The current WOL state (`wol_enabled`) is compared to `wol_mode`.
|
8. **Persist Settings**: Creates udev rules for persistence across reboots
|
||||||
6. **Apply WOL** –
|
9. **Reload Udev**: Reloads udev rules and triggers network interface refresh
|
||||||
- If `wol_mode` ≠ `'d'` and the current mode differs, `ethtool -s <iface> wol <mode>` is run.
|
10. **Verification & Reporting**: Displays WOL configuration status and MAC addresses
|
||||||
- If `wol_mode` is `'d'`, the role ensures WOL is disabled.
|
|
||||||
7. **Deploy systemd template** – Copies `templates/wol@.service.j2` to `/etc/systemd/system/wol@.service`.
|
|
||||||
The template contains `ExecStart=/usr/sbin/ethtool -s %I wol {{ wol_mode }}`.
|
|
||||||
8. **Enable service per interface** – For every interface, the role starts the unit
|
|
||||||
`wol@<iface>.service` and enables it to run on boot.
|
|
||||||
9. **Report** – A final summary is printed, optionally listing MAC addresses if `wol_report_mac`
|
|
||||||
is `true`.
|
|
||||||
|
|
||||||
---
|
## Usage Examples
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Basic Playbook
|
|
||||||
|
|
||||||
|
### Basic Single Bridge (Auto-Detection)
|
||||||
```yaml
|
```yaml
|
||||||
- hosts: proxmox
|
- hosts: proxmox
|
||||||
become: true
|
become: true
|
||||||
roles:
|
roles:
|
||||||
- ansible_proxmox_WOL
|
- ansible_proxmox_WOL
|
||||||
```
|
```
|
||||||
|
Automatically configures WOL for the default `vmbr0` bridge.
|
||||||
> **Result** – WOL is automatically enabled on the physical NIC that backs the default `vmbr0` bridge.
|
|
||||||
|
|
||||||
### Multiple Bridges
|
### Multiple Bridges
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- hosts: proxmox
|
- hosts: proxmox
|
||||||
become: true
|
become: true
|
||||||
@@ -116,25 +57,9 @@ is `true`.
|
|||||||
- vmbr1
|
- vmbr1
|
||||||
- vmbr2
|
- vmbr2
|
||||||
```
|
```
|
||||||
|
Configures WOL for multiple bridge interfaces simultaneously.
|
||||||
|
|
||||||
> **Result** – All three bridges are processed; the physical NICs that belong to each bridge
|
### Custom Bridge with Verification Disabled
|
||||||
> receive the configured WOL mode.
|
|
||||||
|
|
||||||
### Disable WOL
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: proxmox
|
|
||||||
become: true
|
|
||||||
roles:
|
|
||||||
- role: ansible_proxmox_WOL
|
|
||||||
vars:
|
|
||||||
wol_mode: d
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Result** – WOL is disabled on every physical NIC that the role discovered, regardless of bridge.
|
|
||||||
|
|
||||||
### Turn Off Verification
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- hosts: proxmox
|
- hosts: proxmox
|
||||||
become: true
|
become: true
|
||||||
@@ -145,38 +70,151 @@ is `true`.
|
|||||||
wol_verify: false
|
wol_verify: false
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Result** – WOL is set on `vmbr1`’s backing NIC(s) but the role does not perform a post‑change check.
|
### Disable WOL
|
||||||
|
```yaml
|
||||||
|
- hosts: proxmox
|
||||||
|
become: true
|
||||||
|
roles:
|
||||||
|
- role: ansible_proxmox_WOL
|
||||||
|
vars:
|
||||||
|
wol_mode: d
|
||||||
|
```
|
||||||
|
|
||||||
---
|
## Bond0 Support
|
||||||
|
|
||||||
|
The role automatically detects if configured bridges are backed by bonded interfaces (bond0). When bond0 is detected:
|
||||||
|
|
||||||
|
- The underlying physical slave interfaces are identified
|
||||||
|
- All slaves are configured with the same WOL settings
|
||||||
|
- The configuration is displayed in the summary report
|
||||||
|
|
||||||
|
Example output when bond0 is detected:
|
||||||
|
```
|
||||||
|
Bond0 Detected: Yes
|
||||||
|
Bond0 Slaves: eth0, eth1
|
||||||
|
Physical Interfaces: bond0
|
||||||
|
```
|
||||||
|
|
||||||
## Common Proxmox Scenarios
|
## Common Proxmox Scenarios
|
||||||
|
|
||||||
| Scenario | Bridge / NIC Layout | What the role does |
|
### Scenario 1: Standard vmbr0 Setup
|
||||||
|----------|-------------------|------------------|
|
```
|
||||||
| **Standard vmbr0** | `eno1` → `vmbr0` | Enables WOL on `eno1`. |
|
Physical NIC (eno1) → vmbr0 bridge
|
||||||
| **Bonded NICs** | `eno1`, `eno2` → `bond0` → `vmbr0` | Detects `bond0` and sets WOL on *both* slaves. |
|
```
|
||||||
| **Multiple Bridges** | - `eno1` → `vmbr0` - `eno2` → `vmbr1` - `eno3`, `eno4` → `bond0` → `vmbr2` | One role run configures all three bridges automatically. |
|
The role automatically configures `eno1` with WOL settings.
|
||||||
|
|
||||||
---
|
### Scenario 2: Bonded Interface
|
||||||
|
```
|
||||||
|
Physical NICs (eno1, eno2) → bond0 → vmbr0 bridge
|
||||||
|
```
|
||||||
|
The role detects bond0 and applies WOL to bonded slaves.
|
||||||
|
|
||||||
|
### Scenario 3: Multiple Bridges
|
||||||
|
```
|
||||||
|
eno1 → vmbr0
|
||||||
|
eno2 → vmbr1
|
||||||
|
bond0 (eno3, eno4) → vmbr2
|
||||||
|
```
|
||||||
|
Configure all bridges with one role application:
|
||||||
|
```yaml
|
||||||
|
wol_bridges:
|
||||||
|
- vmbr0
|
||||||
|
- vmbr1
|
||||||
|
- vmbr2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Proxmox VE** host with bridge interfaces configured
|
||||||
|
- **Ansible** 2.9+
|
||||||
|
- **ethtool** package (installed automatically by role)
|
||||||
|
- **Root/sudo access** on target host (required for udev and ethtool)
|
||||||
|
- **BIOS Configuration**:
|
||||||
|
- Wake-on-LAN enabled in BIOS
|
||||||
|
- ErP (Energy-Related Products) disabled in BIOS
|
||||||
|
|
||||||
|
## Idempotency
|
||||||
|
|
||||||
|
This role is fully idempotent. Running it multiple times has the same effect as running it once:
|
||||||
|
|
||||||
|
- ✅ Only enables WOL on interfaces that don't already have it enabled
|
||||||
|
- ✅ Skips udev rule reload if rules haven't changed
|
||||||
|
- ✅ Uses `changed_when` conditions to accurately report actual changes
|
||||||
|
- ✅ Safe to include in recurring Ansible playbooks and AWX workflows
|
||||||
|
|
||||||
|
## Safety
|
||||||
|
|
||||||
|
- **Non-Destructive**: Never disables interfaces or changes bridge configuration
|
||||||
|
- **Validation**: Verifies NIC WOL capability before making changes
|
||||||
|
- **Error Handling**: Fails gracefully with clear error messages if:
|
||||||
|
- Bridges cannot be detected
|
||||||
|
- Physical NICs cannot be found
|
||||||
|
- NICs don't support Wake-on-LAN
|
||||||
|
- **Check Mode Support**: Fully compatible with `--check` mode for safe preview
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
|
||||||
|
### Persistence Method
|
||||||
|
WOL settings are persisted using udev rules at `/etc/udev/rules.d/90-wol.rules`. This ensures WOL is re-enabled whenever network interfaces are added or the system reboots.
|
||||||
|
|
||||||
|
Example generated udev rule:
|
||||||
|
```
|
||||||
|
ACTION=="add", SUBSYSTEM=="net", KERNEL=="eno1", RUN+="/sbin/ethtool -s eno1 wol g"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Detection Logic
|
||||||
|
1. **Interface Discovery**: Uses Ansible facts to enumerate all network interfaces
|
||||||
|
2. **Bridge Mapping**: Identifies physical interfaces backing configured bridges using `bridge link show`
|
||||||
|
3. **Bond0 Detection**: Detects bonded interfaces and extracts slave information from `/proc/net/bonding/bond0`
|
||||||
|
4. **WOL Capability Testing**: Tests each physical interface with ethtool to verify WOL support
|
||||||
|
5. **Idempotency Check**: Reads current WOL status to avoid redundant changes
|
||||||
|
6. **Enable WOL**: Applies WOL settings only to interfaces that need it
|
||||||
|
7. **Persist Settings**: Creates/updates udev rules for persistence
|
||||||
|
8. **Reload Udev**: Reloads udev rules and triggers network interface refresh
|
||||||
|
9. **Verification & Reporting**: Displays WOL configuration status and MAC addresses
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
| Problem | Likely Cause | Fix |
|
### "No network interfaces found that support Wake-on-LAN"
|
||||||
|---------|--------------|-----|
|
- Check BIOS settings to ensure WOL is enabled
|
||||||
| **No interfaces found that support WOL** | BIOS WOL disabled, NIC driver doesn’t expose the feature, or interface isn’t a physical NIC. | Enable WOL in BIOS, run `ansible -m setup <host> \| grep ansible_interfaces`. |
|
- Verify NIC drivers support WOL: `ethtool <interface>`
|
||||||
| **Unable to detect bridge backing NIC(s)** | Bridge doesn’t exist or the NIC isn’t a member of it. | Verify with `bridge link show` / `brctl show`. |
|
- Some NICs may require specific BIOS settings or driver parameters
|
||||||
| **WOL not persisting after reboot** | `wol@.service` isn’t enabled, or `ethtool` isn’t installed. | Ensure the role ran successfully, check `/etc/systemd/system/wol@.service` and `systemctl status wol@<iface>.service`. |
|
- Check if interfaces are properly detected: `ansible -m setup <host> | grep ansible_interfaces`
|
||||||
| **Bond0 not detected** | Bond configuration file missing or wrong. | Check `/proc/net/bonding/bond0`. |
|
|
||||||
| **WOL mode unsupported** | NIC driver only supports a subset of modes. | Try a different `wol_mode` value (e.g., `p`, `u`, `m`, `b`). |
|
|
||||||
|
|
||||||
---
|
### "Unable to detect physical NIC backing bridge(s)"
|
||||||
|
- Verify bridges exist: `bridge link show`
|
||||||
|
- Check bridge configuration: `brctl show`
|
||||||
|
- Ensure physical NIC is member of bridge
|
||||||
|
- Confirm the backing interface supports WOL (listed in "Available WOL-capable interfaces")
|
||||||
|
|
||||||
|
### "Does not support Wake-on-LAN"
|
||||||
|
- Check NIC capabilities: `ethtool <interface>`
|
||||||
|
- Verify BIOS has WOL enabled for the specific NIC
|
||||||
|
- Some NICs have disabled WOL by default (check driver documentation)
|
||||||
|
- Try different WOL modes: `p`, `u`, `m`, or `b`
|
||||||
|
|
||||||
|
### WOL not persisting after reboot
|
||||||
|
- Check udev rules: `cat /etc/udev/rules.d/90-wol.rules`
|
||||||
|
- Verify ethtool installed: `which ethtool`
|
||||||
|
- Check system logs: `journalctl -u systemd-udevd -b`
|
||||||
|
- Ensure udev service is running: `systemctl status systemd-udevd`
|
||||||
|
|
||||||
|
### Bond0 not detected
|
||||||
|
- Check bond status: `cat /proc/net/bonding/bond0`
|
||||||
|
- Verify bond is backing the configured bridge
|
||||||
|
- Check bond slave interfaces support WOL individually
|
||||||
|
|
||||||
|
## Notes for Proxmox Admins
|
||||||
|
|
||||||
|
- **Default Bridge**: Proxmox typically uses `vmbr0` as the default management bridge
|
||||||
|
- **No DHCP Changes**: This role only configures WOL; it doesn't modify IP configuration
|
||||||
|
- **Performance Impact**: WOL has negligible performance impact
|
||||||
|
- **Network Redundancy**: If using bonds or multiple bridges, all configured interfaces will be enabled for WOL
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
Ansible Proxmox WOL Contributors
|
Ansible Proxmox WOL Contributors
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
---
|
---
|
||||||
|
# ============================================================
|
||||||
|
# Bridge interfaces to enable Wake-on-LAN on
|
||||||
|
# Can be a string (single bridge) or list (multiple bridges)
|
||||||
|
# Supports detection of physical NICs backing bridges
|
||||||
|
# ============================================================
|
||||||
|
wol_bridges: vmbr0
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# WOL mode options:
|
# WOL mode options:
|
||||||
# g = magic packet (most common, highly recommended)
|
# g = magic packet (most common, highly recommended)
|
||||||
@@ -18,5 +25,3 @@ wol_verify: true
|
|||||||
|
|
||||||
# Report MAC addresses for WOL packet senders
|
# Report MAC addresses for WOL packet senders
|
||||||
wol_report_mac: true
|
wol_report_mac: true
|
||||||
|
|
||||||
wol_port: 9
|
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
---
|
---
|
||||||
- name: Reload systemd
|
- name: Reload systemd
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
- name: Reload systemd and restart WOL
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: wol
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
enabled: true
|
||||||
|
state: restarted
|
||||||
|
|
||||||
|
- name: Reload_udev_rules
|
||||||
|
ansible.builtin.command: udevadm control --reload
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Trigger_udev_net
|
||||||
|
ansible.builtin.command: udevadm trigger --subsystem-match=net
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
|||||||
231
tasks/main.yml
231
tasks/main.yml
@@ -4,9 +4,7 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
- name: Install required packages
|
- name: Install required packages
|
||||||
ansible.builtin.apt:
|
ansible.builtin.apt:
|
||||||
name:
|
name: ethtool
|
||||||
- ethtool
|
|
||||||
- wakeonlan
|
|
||||||
state: present
|
state: present
|
||||||
update_cache: true
|
update_cache: true
|
||||||
|
|
||||||
@@ -28,132 +26,161 @@
|
|||||||
# ansible.builtin.set_fact:
|
# ansible.builtin.set_fact:
|
||||||
# en_interfaces: "{{ ansible_facts.interfaces | select('match', '^eth|^ens|^enp') | unique | list }}"
|
# en_interfaces: "{{ ansible_facts.interfaces | select('match', '^eth|^ens|^enp') | unique | list }}"
|
||||||
|
|
||||||
- name: Get interfaces starting with "en, "eth" or "nic"
|
- name: Get interfaces starting with "en" or "eth"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
en_interfaces: >-
|
en_interfaces: >-
|
||||||
{{
|
{{
|
||||||
ansible_facts.interfaces
|
ansible_facts.interfaces
|
||||||
| select('match', '^(eth|en|nic)')
|
| select('match', '^(eth|en)')
|
||||||
| list
|
| list
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: Display debug selected interfaces
|
# ============================================================
|
||||||
ansible.builtin.debug:
|
# Detect physical interfaces backing configured bridges
|
||||||
msg: >
|
# ============================================================
|
||||||
{{ en_interfaces }}
|
- name: Get physical interfaces for configured bridges
|
||||||
|
ansible.builtin.command: bridge link show {{ item }}
|
||||||
- name: Check supported Wake-on-LAN modes
|
register: bridge_links
|
||||||
ansible.builtin.shell: |
|
loop: "{{ wol_bridges | list }}"
|
||||||
set -o pipefail
|
|
||||||
ethtool {{ item }} | grep 'Supports Wake-on' | tail -1 | awk '{print $3}'
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: false
|
|
||||||
loop: "{{ en_interfaces }}"
|
|
||||||
register: wol_supported
|
|
||||||
when: en_interfaces | length > 0
|
|
||||||
|
|
||||||
- name: WOL | Check if enabled
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -o pipefail
|
|
||||||
ethtool {{ item }} | grep 'Wake-on' | tail -1 | awk '{print substr($0,length,1)}'
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
loop: "{{ en_interfaces }}"
|
|
||||||
register: wol_enabled
|
|
||||||
when: en_interfaces | length > 0
|
|
||||||
|
|
||||||
- name: "Set Wake-on-LAN to {{ wol_mode }}"
|
- name: Extract physical interfaces from bridge info
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
bridge_physical: >-
|
||||||
|
{{
|
||||||
|
bridge_links.results
|
||||||
|
| selectattr('rc', 'equalto', 0)
|
||||||
|
| map(attribute='stdout_lines')
|
||||||
|
| flatten
|
||||||
|
| map('regex_replace', '^\\d+: ([^ ]+).*', '\\1')
|
||||||
|
| select
|
||||||
|
| unique
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Check for bond0 and get slaves
|
||||||
|
# ============================================================
|
||||||
|
- name: Check if bond0 exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /proc/net/bonding/bond0
|
||||||
|
register: bond0_stat
|
||||||
|
|
||||||
|
- name: Get bond0 slaves
|
||||||
|
ansible.builtin.command: cat /proc/net/bonding/bond0 | grep "Slave Interface" | awk '{print $3}'
|
||||||
|
register: bond0_slaves
|
||||||
|
changed_when: false
|
||||||
|
when: bond0_stat.stat.exists
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Set final list of interfaces to configure
|
||||||
|
# ============================================================
|
||||||
|
- name: Set final interfaces
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
wol_final_interfaces: >-
|
||||||
|
{{
|
||||||
|
(bridge_physical if bridge_physical else en_interfaces)
|
||||||
|
+ (bond0_slaves.stdout_lines if bond0_stat.stat.exists else [])
|
||||||
|
| unique
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
|
||||||
|
- name: Display selected interfaces
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Interfaces to configure for WOL: {{ wol_final_interfaces }}"
|
||||||
|
|
||||||
|
- name: Check supported Wake-on-LAN modes
|
||||||
|
ansible.builtin.shell: "ethtool {{ item }} | grep 'Supports Wake-on' | tail -1 | awk '{print $3}'"
|
||||||
|
loop: "{{ wol_final_interfaces }}"
|
||||||
|
register: wol_supported
|
||||||
|
changed_when: false
|
||||||
|
when: wol_final_interfaces | length > 0
|
||||||
|
|
||||||
|
- name: Check if WOL is enabled
|
||||||
|
ansible.builtin.shell: "ethtool {{ item }} | grep 'Wake-on' | tail -1 | awk '{print substr($0,length,1)}'"
|
||||||
|
register: wol_enabled
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
loop: "{{ wol_final_interfaces }}"
|
||||||
|
when: wol_final_interfaces | length > 0
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Enable or disable WOL as needed
|
||||||
|
# ============================================================
|
||||||
|
- name: Set Wake-on-LAN mode
|
||||||
ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}"
|
ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}"
|
||||||
loop: "{{ en_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}"
|
loop: "{{ wol_final_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.0 }}"
|
label: "{{ item.0 }}"
|
||||||
when:
|
when:
|
||||||
|
- item.1.stdout is defined
|
||||||
|
- item.2.stdout is defined
|
||||||
- wol_mode not in item.1.stdout
|
- wol_mode not in item.1.stdout
|
||||||
- wol_mode in item.2.stdout
|
- wol_mode in item.2.stdout
|
||||||
changed_when: true
|
|
||||||
|
|
||||||
- name: "Disable Wake-on-LAN"
|
# ============================================================
|
||||||
ansible.builtin.command: "ethtool -s {{ item.0 }} wol {{ wol_mode }}"
|
# Create udev rules for persistence
|
||||||
loop: "{{ en_interfaces | zip(wol_enabled.results, wol_supported.results) | list }}"
|
# ============================================================
|
||||||
loop_control:
|
- name: Create udev rule for WOL persistence
|
||||||
label: "{{ item.0 }}"
|
|
||||||
when:
|
|
||||||
- wol_mode == 'd'
|
|
||||||
- wol_mode not in item.1.stdout
|
|
||||||
changed_when: true
|
|
||||||
|
|
||||||
- name: Deploy wol systemd template
|
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: templates/wol@.service.j2
|
src: 90-wol.rules.j2
|
||||||
dest: /etc/systemd/system/wol@.service
|
dest: /etc/udev/rules.d/90-wol.rules
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
notify: Reload systemd
|
notify:
|
||||||
when: en_interfaces | length > 0
|
- Reload_udev_rules
|
||||||
|
- Trigger_udev_net
|
||||||
|
|
||||||
- name: Enable WOL systemd unit for each interface
|
|
||||||
ansible.builtin.systemd:
|
|
||||||
name: "wol@{{ item }}.service"
|
|
||||||
enabled: true
|
|
||||||
state: started
|
|
||||||
loop: "{{ en_interfaces }}"
|
|
||||||
when: en_interfaces | length > 0
|
|
||||||
|
|
||||||
- name: Get MAC addresses
|
|
||||||
|
# ============================================================
|
||||||
|
# Verification & Reporting
|
||||||
|
# ============================================================
|
||||||
|
- name: Verify Wake-on-LAN status
|
||||||
|
ansible.builtin.command: "ethtool {{ item }}"
|
||||||
|
register: wol_status
|
||||||
|
changed_when: false
|
||||||
|
loop: "{{ wol_final_interfaces }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item }}"
|
||||||
|
when: wol_verify and wol_final_interfaces | length > 0
|
||||||
|
|
||||||
|
- name: Display WOL status per interface
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: >
|
||||||
|
Interface {{ item.item }} WOL Status:
|
||||||
|
{{ item.stdout_lines | select('search', 'Wake-on:') | first | default('Status Unknown') }}
|
||||||
|
loop: "{{ wol_status.results | default([]) }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.item }}"
|
||||||
|
when: wol_verify
|
||||||
|
|
||||||
|
- name: Get MAC addresses for all interfaces
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
wol_mac_addresses: >-
|
wol_mac_addresses: >-
|
||||||
{{ wol_mac_addresses | default([]) + [ hostvars[inventory_hostname]['ansible_' ~ item].macaddress ] }}
|
{{
|
||||||
loop: "{{ en_interfaces }}"
|
wol_final_interfaces
|
||||||
when: en_interfaces | length > 0
|
| map('extract', ansible_facts, attribute='macaddress')
|
||||||
|
| list
|
||||||
|
}}
|
||||||
|
|
||||||
- name: Report WOL configuration
|
- name: Report WOL configuration
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: |
|
msg: |
|
||||||
Wake-on-LAN Configuration Summary:
|
Wake-on-LAN Configuration Summary:
|
||||||
===================================
|
===================================
|
||||||
Physical Interfaces: {{ en_interfaces | join(', ') }}
|
Bridges Configured: {{ wol_bridges | join(', ') }}
|
||||||
|
Physical Interfaces: {{ wol_final_interfaces | join(', ') }}
|
||||||
WOL Mode: {{ wol_mode }}
|
WOL Mode: {{ wol_mode }}
|
||||||
MAC Addresses: {{ wol_mac_addresses | join(', ') }}
|
{% if bond0_stat.stat.exists %}
|
||||||
|
Bond0 Detected: Yes
|
||||||
- name: Start tcpdump to capture WOL packet
|
Bond0 Slaves: {{ bond0_slaves.stdout_lines | join(', ') }}
|
||||||
become: true
|
{% endif %}
|
||||||
ansible.builtin.shell: |
|
{% if wol_report_mac and wol_mac_addresses | length > 0 %}
|
||||||
timeout 10 tcpdump -i {{ en_interfaces[0] }} -nn -c 1 \
|
MAC Addresses:
|
||||||
'udp and port {{ wol_port }} and (udp[8:4] = 0xffffffff)'
|
{% for iface, mac in (wol_final_interfaces | zip(wol_mac_addresses) | list) %}
|
||||||
register: tcpdump_result
|
- {{ iface }}: {{ mac | default('Unable to detect') }}
|
||||||
async: 12
|
{% endfor %}
|
||||||
poll: 0
|
{% endif %}
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Give tcpdump time to start
|
|
||||||
ansible.builtin.pause:
|
|
||||||
seconds: 1
|
|
||||||
|
|
||||||
# - name: Send WOL packet via shell
|
|
||||||
# ansible.builtin.shell: wakeonlan {{ wol_mac_addresses[0] }}
|
|
||||||
# delegate_to: localhost
|
|
||||||
|
|
||||||
- name: Send Wake-on-LAN packet from localhost
|
|
||||||
community.general.wakeonlan:
|
|
||||||
mac: "{{ wol_mac_addresses[0] }}"
|
|
||||||
port: "{{ wol_port }}"
|
|
||||||
broadcast: 255.255.255.255
|
|
||||||
# delegate_to: localhost
|
|
||||||
|
|
||||||
- name: Wait for tcpdump to finish
|
|
||||||
ansible.builtin.async_status:
|
|
||||||
jid: "{{ tcpdump_result.ansible_job_id }}"
|
|
||||||
register: tcpdump_status
|
|
||||||
until: tcpdump_status.finished
|
|
||||||
retries: 12
|
|
||||||
delay: 1
|
|
||||||
|
|
||||||
- name: Check if WOL packet was received
|
|
||||||
ansible.builtin.assert:
|
|
||||||
that:
|
|
||||||
- tcpdump_status.rc == 0
|
|
||||||
success_msg: "✅ Wake-on-LAN magic packet received by host"
|
|
||||||
fail_msg: "❌ Wake-on-LAN magic packet NOT detected"
|
|
||||||
changed_when: tcpdump_status.rc == 0
|
|
||||||
|
|||||||
3
templates/90-wol.rules.j2
Normal file
3
templates/90-wol.rules.j2
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{% for interface in wol_final_interfaces %}
|
||||||
|
ACTION=="add", SUBSYSTEM=="net", KERNEL=="{{ interface }}", RUN+="/sbin/ethtool -s {{ interface }} wol {{ wol_mode }}"
|
||||||
|
{% endfor %}
|
||||||
18
templates/wol-interfaces.service.j2
Normal file
18
templates/wol-interfaces.service.j2
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Set Wake-on-LAN on network interfaces
|
||||||
|
After=network.target
|
||||||
|
Wants=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash -c '{% set cmds = [] %}
|
||||||
|
{% for intf, enabled, supported in en_interfaces | zip(wol_enabled.results, wol_supported.results) %}
|
||||||
|
{% if wol_mode in supported.stdout and wol_mode not in enabled.stdout %}
|
||||||
|
{% set _ = cmds.append("/sbin/ethtool -s " ~ intf ~ " wol " ~ wol_mode) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{{ cmds | join("; ") if cmds | length > 0 else ":" }}'
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
11
templates/wol.service.j2
Normal file
11
templates/wol.service.j2
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Enable Wake-on-LAN on {{ wol_final_interface }}
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/sbin/ethtool -s {{ wol_final_interface }} wol {{ wol_mode }}
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# /etc/systemd/system/wol@.service
|
|
||||||
|
|
||||||
[Unit]
|
|
||||||
Description=Wake‑on‑LAN configuration for interface %I
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
ExecStart=/usr/sbin/ethtool -s %I wol {{ wol_mode }}
|
|
||||||
RemainAfterExit=yes
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
Reference in New Issue
Block a user