Files
ansible-deploy/internal/services/templates.go
T
cnbugs 1e6ac95cdb feat: v2.0 全面升级 - SSH密钥管理/模板中心/文件分发/全新UI
- 新增SSH密钥库管理(集中托管私钥、自动指纹识别)
- 新增模板中心(24个预置模板,7大分类,一键创建Playbook)
- 新增文件分发功能(内容/文件双模式,权限设置)
- 新增系统信息接口(版本/主机数/运行时间)
- 主机支持密码/SSH密钥双认证方式
- 全新暗色玻璃拟态UI(侧边栏导航、SSE实时日志流)
- 修复UpdateHost ID丢失bug
- 添加.gitignore排除敏感数据
2026-07-30 22:49:13 +08:00

1659 lines
46 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package services
// PlaybookTemplate Playbook模板定义
type PlaybookTemplate struct {
ID string `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
Description string `json:"description"`
Icon string `json:"icon"`
Content string `json:"content"`
Tags []string `json:"tags"`
}
// TemplateCategory 模板分类
type TemplateCategory struct {
ID string `json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
Count int `json:"count"`
}
// GetTemplateCategories 获取所有模板分类
func GetTemplateCategories() []TemplateCategory {
cats := map[string]TemplateCategory{}
for _, t := range GetPlaybookTemplates() {
c, ok := cats[t.Category]
if !ok {
c = TemplateCategory{ID: t.Category, Name: categoryNames[t.Category], Icon: categoryIcons[t.Category]}
}
c.Count++
cats[t.Category] = c
}
var result []TemplateCategory
// 按固定顺序输出
order := []string{"system", "web", "database", "container", "devops", "security", "monitoring"}
for _, id := range order {
if c, ok := cats[id]; ok {
result = append(result, c)
}
}
return result
}
var categoryNames = map[string]string{
"system": "系统管理",
"web": "Web服务",
"database": "数据库",
"container": "容器化",
"devops": "DevOps",
"security": "安全加固",
"monitoring": "监控告警",
}
var categoryIcons = map[string]string{
"system": "🖥️",
"web": "🌐",
"database": "🗄️",
"container": "🐳",
"devops": "🔧",
"security": "🔒",
"monitoring": "📊",
}
// GetPlaybookTemplates 获取所有Playbook模板
func GetPlaybookTemplates() []PlaybookTemplate {
return []PlaybookTemplate{
// ===== 系统管理 =====
{
ID: "update-packages", Name: "系统包更新", Category: "system",
Description: "自动更新系统软件包,支持Debian/RedHat系列",
Icon: "📦", Tags: []string{"update", "apt", "yum"},
Content: `---
- name: 系统包更新
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
update_cache: yes
upgrade_type: dist # dist(完整升级) 或 safe(安全升级)
tasks:
- name: 更新apt缓存
apt:
update_cache: yes
when: ansible_os_family == "Debian"
- name: 升级所有包(Debian)
apt:
upgrade: "{{ upgrade_type }}"
autoremove: yes
autoclean: yes
when: ansible_os_family == "Debian"
- name: 更新yum缓存
yum:
update_cache: yes
when: ansible_os_family == "RedHat"
- name: 升级所有包(RedHat)
yum:
name: "*"
state: latest
when: ansible_os_family == "RedHat"
- name: 检查是否需要重启
stat:
path: /var/run/reboot-required
register: reboot_required
when: ansible_os_family == "Debian"
- name: 提示重启
debug:
msg: "⚠️ 系统需要重启以完成更新"
when: ansible_os_family == "Debian" and reboot_required.stat.exists
`,
},
{
ID: "check-system", Name: "系统信息采集", Category: "system",
Description: "采集操作系统、硬件、网络等详细信息",
Icon: "🔍", Tags: []string{"info", "facts", "inventory"},
Content: `---
- name: 系统信息采集
hosts: "{{ target_hosts | default('all') }}"
gather_facts: yes
tasks:
- name: 操作系统信息
debug:
msg: |
══════════ 系统信息 ══════════
主机名: {{ ansible_facts['hostname'] }}
系统: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}
内核: {{ ansible_facts['kernel'] }}
架构: {{ ansible_facts['architecture'] }}
CPU: {{ ansible_facts['processor_vcpus'] }} vCPUs
内存: {{ (ansible_facts['memtotal_mb'] / 1024) | round(2) }} GB
IP: {{ ansible_facts['default_ipv4']['address'] | default('N/A') }}
═══════════════════════════════
- name: 磁盘使用
shell: df -h | grep -E '^/dev/'
register: disk_info
- name: 显示磁盘
debug:
msg: "{{ disk_info.stdout_lines }}"
- name: 运行时间
shell: uptime -p
register: uptime_info
- name: 显示运行时间
debug:
msg: "运行时间: {{ uptime_info.stdout }}"
`,
},
{
ID: "check-resources", Name: "资源监控检查", Category: "system",
Description: "检查CPU/内存/磁盘使用率,超阈值告警",
Icon: "📈", Tags: []string{"monitor", "cpu", "memory", "disk"},
Content: `---
- name: 资源监控检查
hosts: "{{ target_hosts | default('all') }}"
gather_facts: yes
vars:
warn_threshold: 80
crit_threshold: 90
tasks:
- name: 获取CPU使用率
shell: top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1
register: cpu_result
changed_when: false
- name: 获取内存使用率
shell: free | grep Mem | awk '{printf "%.0f", $3/$2*100}'
register: mem_result
changed_when: false
- name: 获取磁盘使用率
shell: df -h / | tail -1 | awk '{print $5}' | tr -d '%'
register: disk_result
changed_when: false
- name: 显示资源报告
debug:
msg: |
═══════ {{ inventory_hostname }} 资源报告 ═══════
CPU 使用率: {{ cpu_result.stdout }}%
内存使用率: {{ mem_result.stdout }}%
磁盘使用率: {{ disk_result.stdout }}%
告警阈值: {{ warn_threshold }}% / 严重: {{ crit_threshold }}%
═══════════════════════════════════════
- name: 严重告警
fail:
msg: "🚨 严重: {{ inventory_hostname }} 资源使用率超过 {{ crit_threshold }}%"
when: >
(cpu_result.stdout | int >= crit_threshold) or
(mem_result.stdout | int >= crit_threshold) or
(disk_result.stdout | int >= crit_threshold)
`,
},
{
ID: "log-cleanup", Name: "日志清理", Category: "system",
Description: "清理系统日志、临时文件,释放磁盘空间",
Icon: "🧹", Tags: []string{"cleanup", "log", "disk"},
Content: `---
- name: 日志清理
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
log_retention_days: 30
tmp_retention_days: 7
tasks:
- name: 清理journal日志
shell: journalctl --vacuum-time={{ log_retention_days }}d
register: journal_result
changed_when: "'Vacuuming' in journal_result.stdout"
- name: 清理旧日志文件
find:
paths: /var/log
patterns: "*.gz,*.old,*.[0-9]"
age: "{{ log_retention_days }}d"
register: old_logs
- name: 删除旧日志
file:
path: "{{ item.path }}"
state: absent
loop: "{{ old_logs.files }}"
- name: 清理临时文件
find:
paths: /tmp
age: "{{ tmp_retention_days }}d"
register: tmp_files
- name: 删除临时文件
file:
path: "{{ item.path }}"
state: absent
loop: "{{ tmp_files.files }}"
ignore_errors: yes
- name: 清理apt缓存
apt:
autoclean: yes
when: ansible_os_family == "Debian"
- name: 显示磁盘空间
shell: df -h /
register: disk_after
- name: 清理完成
debug:
msg: "{{ disk_after.stdout_lines }}"
`,
},
{
ID: "time-sync", Name: "时间同步(NTP)", Category: "system",
Description: "配置NTP时间同步,确保集群时间一致",
Icon: "⏰", Tags: []string{"ntp", "time", "chrony"},
Content: `---
- name: 时间同步配置
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
ntp_servers:
- ntp.aliyun.com
- ntp1.aliyun.com
- pool.ntp.org
tasks:
- name: 安装chrony
package:
name: chrony
state: present
- name: 配置NTP服务器
lineinfile:
path: /etc/chrony.conf
regexp: "^server "
line: "server {{ item }} iburst"
create: yes
loop: "{{ ntp_servers }}"
- name: 启动chrony
service:
name: chronyd
state: started
enabled: yes
- name: 验证时间同步
shell: chronyc tracking
register: chrony_status
changed_when: false
- name: 显示同步状态
debug:
msg: "{{ chrony_status.stdout_lines }}"
`,
},
// ===== Web服务 =====
{
ID: "deploy-nginx", Name: "部署Nginx", Category: "web",
Description: "安装配置Nginx,支持自定义站点和反向代理",
Icon: "🌐", Tags: []string{"nginx", "web", "proxy"},
Content: `---
- name: 部署Nginx
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
nginx_worker_processes: auto
nginx_worker_connections: 1024
server_name: localhost
listen_port: 80
proxy_pass: ""
root_dir: /var/www/html
tasks:
- name: 安装Nginx
package:
name: nginx
state: present
- name: 创建网站目录
file:
path: "{{ root_dir }}"
state: directory
owner: www-data
group: www-data
mode: '0755'
when: ansible_os_family == "Debian"
- name: 创建网站目录(RedHat)
file:
path: "{{ root_dir }}"
state: directory
owner: nginx
group: nginx
mode: '0755'
when: ansible_os_family == "RedHat"
- name: 部署默认页面
copy:
content: |
<!DOCTYPE html>
<html><head><title>{{ server_name }}</title></head>
<body><h1>Deployed by Ansible Deploy</h1>
<p>Server: {{ inventory_hostname }}</p></body></html>
dest: "{{ root_dir }}/index.html"
when: proxy_pass == ""
- name: 配置Nginx站点
copy:
content: |
server {
listen {{ listen_port }};
server_name {{ server_name }};
{% if proxy_pass != "" %}
location / {
proxy_pass {{ proxy_pass }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
{% else %}
root {{ root_dir }};
index index.html;
location / {
try_files $uri $uri/ =404;
}
{% endif %}
}
dest: /etc/nginx/conf.d/{{ server_name }}.conf
notify: Reload Nginx
- name: 启动Nginx
service:
name: nginx
state: started
enabled: yes
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
`,
},
{
ID: "deploy-apache", Name: "部署Apache", Category: "web",
Description: "安装配置Apache HTTP Server",
Icon: "🪶", Tags: []string{"apache", "httpd", "web"},
Content: `---
- name: 部署Apache
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
server_name: localhost
listen_port: 80
document_root: /var/www/html
tasks:
- name: 安装Apache(Debian)
apt:
name: apache2
state: present
when: ansible_os_family == "Debian"
- name: 安装Apache(RedHat)
yum:
name: httpd
state: present
when: ansible_os_family == "RedHat"
- name: 创建网站目录
file:
path: "{{ document_root }}"
state: directory
mode: '0755'
- name: 部署测试页面
copy:
content: "<h1>Apache on {{ inventory_hostname }}</h1>"
dest: "{{ document_root }}/index.html"
- name: 启动Apache(Debian)
service:
name: apache2
state: started
enabled: yes
when: ansible_os_family == "Debian"
- name: 启动Apache(RedHat)
service:
name: httpd
state: started
enabled: yes
when: ansible_os_family == "RedHat"
`,
},
// ===== 数据库 =====
{
ID: "deploy-mysql", Name: "部署MySQL", Category: "database",
Description: "安装MySQL/MariaDB,配置root密码和基础优化",
Icon: "🐬", Tags: []string{"mysql", "mariadb", "database"},
Content: `---
- name: 部署MySQL
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
mysql_root_password: "ChangeMe@2024"
mysql_port: 3306
mysql_max_connections: 500
mysql_datadir: /var/lib/mysql
tasks:
- name: 安装MySQL(Debian)
apt:
name:
- mysql-server
- mysql-client
- python3-pymysql
state: present
when: ansible_os_family == "Debian"
- name: 安装MariaDB(RedHat)
yum:
name:
- mariadb-server
- mariadb
- python3-PyMySQL
state: present
when: ansible_os_family == "RedHat"
- name: 启动MySQL
service:
name: "{{ 'mysql' if ansible_os_family == 'Debian' else 'mariadb' }}"
state: started
enabled: yes
- name: 设置root密码
shell: |
mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '{{ mysql_root_password }}'; FLUSH PRIVILEGES;"
ignore_errors: yes
no_log: true
- name: 优化配置
copy:
content: |
[mysqld]
port = {{ mysql_port }}
max_connections = {{ mysql_max_connections }}
datadir = {{ mysql_datadir }}
innodb_buffer_pool_size = 256M
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
dest: /etc/mysql/conf.d/optimize.cnf
when: ansible_os_family == "Debian"
notify: Restart MySQL
- name: 验证MySQL
shell: mysql -u root -p{{ mysql_root_password }} -e "SELECT VERSION();"
register: mysql_version
changed_when: false
no_log: true
- name: 显示版本
debug:
msg: "MySQL版本: {{ mysql_version.stdout_lines[-1] | default('unknown') }}"
handlers:
- name: Restart MySQL
service:
name: "{{ 'mysql' if ansible_os_family == 'Debian' else 'mariadb' }}"
state: restarted
`,
},
{
ID: "deploy-redis", Name: "部署Redis", Category: "database",
Description: "安装Redis,配置密码、内存限制和持久化",
Icon: "🔴", Tags: []string{"redis", "cache", "database"},
Content: `---
- name: 部署Redis
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
redis_port: 6379
redis_password: "ChangeMe@2024"
redis_maxmemory: "512mb"
redis_maxmemory_policy: allkeys-lru
redis_bind: "0.0.0.0"
tasks:
- name: 安装Redis
package:
name: redis-server
state: present
when: ansible_os_family == "Debian"
- name: 安装Redis(RedHat)
yum:
name: redis
state: present
when: ansible_os_family == "RedHat"
- name: 配置Redis
lineinfile:
path: /etc/redis/redis.conf
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^bind ', line: 'bind {{ redis_bind }}' }
- { regexp: '^port ', line: 'port {{ redis_port }}' }
- { regexp: '^requirepass ', line: 'requirepass {{ redis_password }}' }
- { regexp: '^maxmemory ', line: 'maxmemory {{ redis_maxmemory }}' }
- { regexp: '^maxmemory-policy ', line: 'maxmemory-policy {{ redis_maxmemory_policy }}' }
notify: Restart Redis
- name: 启动Redis
service:
name: "{{ 'redis-server' if ansible_os_family == 'Debian' else 'redis' }}"
state: started
enabled: yes
- name: 验证Redis
shell: redis-cli -a {{ redis_password }} ping
register: redis_ping
changed_when: false
no_log: true
- name: 显示状态
debug:
msg: "Redis状态: {{ redis_ping.stdout }}"
handlers:
- name: Restart Redis
service:
name: "{{ 'redis-server' if ansible_os_family == 'Debian' else 'redis' }}"
state: restarted
`,
},
{
ID: "deploy-postgresql", Name: "部署PostgreSQL", Category: "database",
Description: "安装PostgreSQL,配置用户和基础优化",
Icon: "🐘", Tags: []string{"postgresql", "postgres", "database"},
Content: `---
- name: 部署PostgreSQL
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
postgres_version: "15"
postgres_password: "ChangeMe@2024"
postgres_port: 5432
postgres_max_connections: 200
tasks:
- name: 安装PostgreSQL(Debian)
apt:
name:
- postgresql
- postgresql-contrib
- python3-psycopg2
state: present
when: ansible_os_family == "Debian"
- name: 安装PostgreSQL(RedHat)
yum:
name:
- postgresql-server
- postgresql-contrib
- python3-psycopg2
state: present
when: ansible_os_family == "RedHat"
- name: 初始化数据库(RedHat)
shell: postgresql-setup --initdb
when: ansible_os_family == "RedHat"
ignore_errors: yes
- name: 启动PostgreSQL
service:
name: postgresql
state: started
enabled: yes
- name: 设置postgres密码
become_user: postgres
shell: psql -c "ALTER USER postgres PASSWORD '{{ postgres_password }}';"
no_log: true
- name: 验证安装
become_user: postgres
shell: psql -c "SELECT version();"
register: pg_version
changed_when: false
- name: 显示版本
debug:
msg: "{{ pg_version.stdout_lines[0] | default('PostgreSQL installed') }}"
`,
},
// ===== 容器化 =====
{
ID: "deploy-docker", Name: "部署Docker", Category: "container",
Description: "安装Docker CE + Docker Compose,配置镜像加速",
Icon: "🐳", Tags: []string{"docker", "container", "compose"},
Content: `---
- name: 部署Docker
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
docker_mirror: "https://mirror.ccs.tencentyun.com"
docker_data_root: /var/lib/docker
docker_log_max_size: "100m"
docker_log_max_file: "3"
tasks:
- name: 安装依赖(Debian)
apt:
name:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
state: present
when: ansible_os_family == "Debian"
- name: 添加Docker GPG密钥
shell: |
curl -fsSL https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
when: ansible_os_family == "Debian"
ignore_errors: yes
- name: 添加Docker仓库
shell: |
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable" > /etc/apt/sources.list.d/docker.list
when: ansible_os_family == "Debian"
- name: 安装Docker(Debian)
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-compose-plugin
state: present
update_cache: yes
when: ansible_os_family == "Debian"
- name: 安装Docker(RedHat)
yum:
name:
- docker
- docker-compose-plugin
state: present
when: ansible_os_family == "RedHat"
- name: 配置Docker
copy:
content: |
{
"data-root": "{{ docker_data_root }}",
"registry-mirrors": ["{{ docker_mirror }}"],
"log-driver": "json-file",
"log-opts": {
"max-size": "{{ docker_log_max_size }}",
"max-file": "{{ docker_log_max_file }}"
},
"storage-driver": "overlay2",
"live-restore": true
}
dest: /etc/docker/daemon.json
notify: Restart Docker
- name: 启动Docker
service:
name: docker
state: started
enabled: yes
- name: 添加用户到docker组
user:
name: "{{ ansible_user }}"
groups: docker
append: yes
ignore_errors: yes
- name: 验证Docker
shell: docker version --format '{{.Server.Version}}'
register: docker_ver
changed_when: false
- name: 显示版本
debug:
msg: "Docker版本: {{ docker_ver.stdout }}"
handlers:
- name: Restart Docker
service:
name: docker
state: restarted
`,
},
{
ID: "deploy-portainer", Name: "部署Portainer", Category: "container",
Description: "部署Portainer CE容器管理面板",
Icon: "🎛️", Tags: []string{"portainer", "docker", "ui"},
Content: `---
- name: 部署Portainer
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
portainer_port: 9443
portainer_data: /opt/portainer
tasks:
- name: 创建数据目录
file:
path: "{{ portainer_data }}"
state: directory
- name: 拉取并启动Portainer
shell: |
docker volume create portainer_data
docker run -d \
-p 8000:8000 \
-p {{ portainer_port }}:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
register: portainer_result
ignore_errors: yes
- name: 显示访问地址
debug:
msg: "Portainer已部署: https://{{ ansible_host | default(inventory_hostname) }}:{{ portainer_port }}"
`,
},
// ===== DevOps =====
{
ID: "deploy-nodejs", Name: "部署Node.js", Category: "devops",
Description: "安装Node.js + PM2进程管理器",
Icon: "💚", Tags: []string{"nodejs", "npm", "pm2"},
Content: `---
- name: 部署Node.js
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
node_version: "20"
install_pm2: true
tasks:
- name: 安装NodeSource仓库
shell: |
curl -fsSL https://deb.nodesource.com/setup_{{ node_version }}.x | bash -
when: ansible_os_family == "Debian"
- name: 安装Node.js(Debian)
apt:
name: nodejs
state: present
update_cache: yes
when: ansible_os_family == "Debian"
- name: 安装Node.js(RedHat)
yum:
name: nodejs
state: present
when: ansible_os_family == "RedHat"
- name: 安装PM2
npm:
name: pm2
global: yes
when: install_pm2
- name: 设置PM2开机启动
shell: pm2 startup systemd -u {{ ansible_user }} --hp /home/{{ ansible_user }}
when: install_pm2
ignore_errors: yes
- name: 验证安装
shell: node --version && npm --version
register: node_ver
changed_when: false
- name: 显示版本
debug:
msg: "{{ node_ver.stdout_lines }}"
`,
},
{
ID: "deploy-python-app", Name: "部署Python应用", Category: "devops",
Description: "配置Python环境 + Gunicorn + Systemd服务",
Icon: "🐍", Tags: []string{"python", "gunicorn", "flask", "django"},
Content: `---
- name: 部署Python应用
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
app_name: myapp
app_dir: /opt/myapp
python_version: python3
venv_dir: /opt/myapp/venv
gunicorn_port: 8000
gunicorn_workers: 4
app_user: www-data
tasks:
- name: 安装Python和依赖
package:
name:
- "{{ python_version }}"
- "{{ python_version }}-venv"
- python3-pip
state: present
- name: 创建应用目录
file:
path: "{{ app_dir }}"
state: directory
owner: "{{ app_user }}"
mode: '0755'
- name: 创建虚拟环境
shell: "{{ python_version }} -m venv {{ venv_dir }}"
args:
creates: "{{ venv_dir }}/bin/activate"
- name: 安装Gunicorn
pip:
name: gunicorn
virtualenv: "{{ venv_dir }}"
- name: 创建Systemd服务
copy:
content: |
[Unit]
Description={{ app_name }} Gunicorn Service
After=network.target
[Service]
User={{ app_user }}
WorkingDirectory={{ app_dir }}
ExecStart={{ venv_dir }}/bin/gunicorn --workers {{ gunicorn_workers }} --bind 0.0.0.0:{{ gunicorn_port }} app:app
Restart=always
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/{{ app_name }}.service
notify: Restart App
- name: 启动服务
systemd:
name: "{{ app_name }}"
state: started
enabled: yes
daemon_reload: yes
handlers:
- name: Restart App
systemd:
name: "{{ app_name }}"
state: restarted
daemon_reload: yes
`,
},
{
ID: "backup-data", Name: "数据备份", Category: "devops",
Description: "定时备份指定目录到本地或远程",
Icon: "💾", Tags: []string{"backup", "cron", "archive"},
Content: `---
- name: 数据备份
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
backup_source: /data
backup_dest: /backup
backup_retention_days: 7
backup_hour: "2"
backup_minute: "0"
tasks:
- name: 创建备份目录
file:
path: "{{ backup_dest }}"
state: directory
mode: '0700'
- name: 创建备份脚本
copy:
content: |
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="{{ backup_dest }}/backup_${DATE}.tar.gz"
tar -czf "$BACKUP_FILE" {{ backup_source }} 2>/dev/null
find {{ backup_dest }} -name "backup_*.tar.gz" -mtime +{{ backup_retention_days }} -delete
echo "Backup completed: $BACKUP_FILE"
dest: /usr/local/bin/backup.sh
mode: '0755'
- name: 配置定时任务
cron:
name: "daily-backup"
hour: "{{ backup_hour }}"
minute: "{{ backup_minute }}"
job: "/usr/local/bin/backup.sh >> /var/log/backup.log 2>&1"
- name: 立即执行一次备份
shell: /usr/local/bin/backup.sh
register: backup_result
- name: 备份结果
debug:
msg: "{{ backup_result.stdout }}"
`,
},
// ===== 安全加固 =====
{
ID: "security-hardening", Name: "安全加固", Category: "security",
Description: "SSH加固、防火墙配置、禁用root远程登录",
Icon: "🔒", Tags: []string{"security", "ssh", "firewall", "hardening"},
Content: `---
- name: 安全加固
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
ssh_port: 22
disable_root_login: true
enable_firewall: true
allowed_ssh_users: []
tasks:
- name: 修改SSH端口
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?Port "
line: "Port {{ ssh_port }}"
notify: Restart SSH
- name: 禁用root登录
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PermitRootLogin "
line: "PermitRootLogin no"
when: disable_root_login
notify: Restart SSH
- name: 禁用密码认证(仅密钥)
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PasswordAuthentication "
line: "PasswordAuthentication no"
notify: Restart SSH
- name: 设置SSH超时
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?ClientAliveInterval "
line: "ClientAliveInterval 300"
notify: Restart SSH
- name: 安装UFW(Debian)
apt:
name: ufw
state: present
when: ansible_os_family == "Debian" and enable_firewall
- name: 配置UFW规则
shell: |
ufw allow {{ ssh_port }}/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
when: ansible_os_family == "Debian" and enable_firewall
- name: 安装fail2ban
package:
name: fail2ban
state: present
ignore_errors: yes
- name: 启动fail2ban
service:
name: fail2ban
state: started
enabled: yes
ignore_errors: yes
- name: 加固完成
debug:
msg: "✅ 安全加固完成 - SSH端口: {{ ssh_port }}, Root登录: {{ '禁用' if disable_root_login else '允许' }}"
handlers:
- name: Restart SSH
service:
name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}"
state: restarted
`,
},
{
ID: "ssl-cert", Name: "SSL证书部署", Category: "security",
Description: "使用Certbot自动申请Let's Encrypt证书",
Icon: "📜", Tags: []string{"ssl", "https", "certbot", "letsencrypt"},
Content: `---
- name: SSL证书部署
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
domain: example.com
email: admin@example.com
webroot: /var/www/html
tasks:
- name: 安装Certbot
package:
name:
- certbot
- python3-certbot-nginx
state: present
- name: 申请证书
shell: |
certbot certonly --webroot -w {{ webroot }} \
-d {{ domain }} \
--email {{ email }} \
--agree-tos --non-interactive
args:
creates: /etc/letsencrypt/live/{{ domain }}/fullchain.pem
- name: 配置自动续期
cron:
name: "certbot-renew"
hour: "3"
minute: "30"
job: "certbot renew --quiet --post-hook 'systemctl reload nginx'"
- name: 证书信息
shell: openssl x509 -in /etc/letsencrypt/live/{{ domain }}/fullchain.pem -noout -dates
register: cert_info
changed_when: false
ignore_errors: yes
- name: 显示证书
debug:
msg: "{{ cert_info.stdout_lines | default(['证书已申请']) }}"
`,
},
// ===== 监控告警 =====
{
ID: "deploy-node-exporter", Name: "部署Node Exporter", Category: "monitoring",
Description: "部署Prometheus Node Exporter采集主机指标",
Icon: "📡", Tags: []string{"prometheus", "monitoring", "exporter"},
Content: `---
- name: 部署Node Exporter
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
exporter_version: "1.7.0"
exporter_port: 9100
tasks:
- name: 创建用户
user:
name: node_exporter
system: yes
shell: /usr/sbin/nologin
create_home: no
- name: 下载Node Exporter
get_url:
url: "https://github.com/prometheus/node_exporter/releases/download/v{{ exporter_version }}/node_exporter-{{ exporter_version }}.linux-amd64.tar.gz"
dest: /tmp/node_exporter.tar.gz
- name: 解压
unarchive:
src: /tmp/node_exporter.tar.gz
dest: /tmp
remote_src: yes
- name: 安装二进制
copy:
src: "/tmp/node_exporter-{{ exporter_version }}.linux-amd64/node_exporter"
dest: /usr/local/bin/node_exporter
mode: '0755'
remote_src: yes
- name: 创建Systemd服务
copy:
content: |
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter --web.listen-address=:{{ exporter_port }}
Restart=always
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/node_exporter.service
- name: 启动服务
systemd:
name: node_exporter
state: started
enabled: yes
daemon_reload: yes
- name: 验证
shell: curl -s http://localhost:{{ exporter_port }}/metrics | head -5
register: metrics
changed_when: false
- name: 显示状态
debug:
msg: "Node Exporter运行在端口 {{ exporter_port }}"
`,
},
{
ID: "deploy-grafana", Name: "部署Grafana", Category: "monitoring",
Description: "部署Grafana可视化监控面板",
Icon: "📊", Tags: []string{"grafana", "dashboard", "visualization"},
Content: `---
- name: 部署Grafana
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
grafana_port: 3000
grafana_admin_password: "admin123"
tasks:
- name: 安装依赖
apt:
name:
- apt-transport-https
- software-properties-common
state: present
when: ansible_os_family == "Debian"
- name: 添加Grafana仓库
shell: |
curl -fsSL https://apt.grafana.com/gpg.key | gpg --dearmor -o /usr/share/keyrings/grafana.gpg
echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main" > /etc/apt/sources.list.d/grafana.list
when: ansible_os_family == "Debian"
- name: 安装Grafana
apt:
name: grafana
state: present
update_cache: yes
when: ansible_os_family == "Debian"
- name: 配置端口
lineinfile:
path: /etc/grafana/grafana.ini
regexp: "^;?http_port"
line: "http_port = {{ grafana_port }}"
- name: 启动Grafana
service:
name: grafana-server
state: started
enabled: yes
- name: 显示访问信息
debug:
msg: "Grafana: http://{{ ansible_host | default(inventory_hostname) }}:{{ grafana_port }} (admin/{{ grafana_admin_password }})"
`,
},
// ===== 系统管理(新增) =====
{
ID: "host-connectivity", Name: "主机连通性测试", Category: "system",
Description: "批量检测主机SSH连通性、DNS解析、端口可达性",
Icon: "🔗", Tags: []string{"ping", "connectivity", "network", "check"},
Content: `---
- name: 主机连通性测试
hosts: "{{ target_hosts | default('all') }}"
gather_facts: no
tasks:
- name: Ansible Ping 测试
ping:
register: ping_result
ignore_errors: yes
- name: 检测SSH端口
wait_for:
host: "{{ ansible_host | default(inventory_hostname) }}"
port: "{{ ansible_port | default(22) }}"
timeout: 5
delegate_to: localhost
register: ssh_port
ignore_errors: yes
- name: 检测DNS解析
shell: nslookup {{ inventory_hostname }} 2>/dev/null || host {{ inventory_hostname }} 2>/dev/null || echo "DNS解析失败"
delegate_to: localhost
register: dns_result
changed_when: false
ignore_errors: yes
- name: 检测常用端口
wait_for:
host: "{{ ansible_host | default(inventory_hostname) }}"
port: "{{ item }}"
timeout: 3
delegate_to: localhost
loop: [80, 443]
register: port_scan
ignore_errors: yes
- name: 输出连通性报告
debug:
msg: |
═══════ {{ inventory_hostname }} 连通性报告 ═══════
SSH Ping: {{ ' 成功' if ping_result is succeeded else ' 失败' }}
SSH 端口: {{ ' 开放' if ssh_port is succeeded else ' 不可达' }}
DNS 解析: {{ dns_result.stdout | default('N/A') }}
HTTP(80): {{ ' 开放' if port_scan.results[0] is succeeded else ' 关闭' }}
HTTPS(443): {{ ' 开放' if port_scan.results[1] is succeeded else ' 关闭' }}
═══════════════════════════════════════
`,
},
{
ID: "ubuntu-multi-ip", Name: "Ubuntu 22.04 多IP配置", Category: "system",
Description: "通过Netplan为Ubuntu 22.04配置多IP地址(主IP+辅助IP",
Icon: "🌐", Tags: []string{"ubuntu", "netplan", "network", "multi-ip"},
Content: `---
- name: Ubuntu 22.04 多IP地址配置
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
# 主网卡名称(根据实际修改)
primary_nic: ens192
# 主IP配置
primary_ip: "192.168.1.100/24"
primary_gateway: "192.168.1.1"
primary_dns:
- 223.5.5.5
- 119.29.29.29
# 辅助IP列表(可添加多个)
secondary_ips:
- "192.168.1.101/24"
- "10.0.0.100/16"
tasks:
- name: 确认系统版本
assert:
that:
- ansible_distribution == "Ubuntu"
- ansible_distribution_version is version('22.04', '>=')
fail_msg: "此模板仅适用于 Ubuntu 22.04+"
success_msg: "系统版本: {{ ansible_distribution }} {{ ansible_distribution_version }}"
- name: 备份现有Netplan配置
shell: |
mkdir -p /etc/netplan/backup
cp /etc/netplan/*.yaml /etc/netplan/backup/ 2>/dev/null || true
args:
creates: /etc/netplan/backup
- name: 生成Netplan配置
copy:
content: |
network:
version: 2
ethernets:
{{ primary_nic }}:
addresses:
- {{ primary_ip }}
{% for ip in secondary_ips %}
- {{ ip }}
{% endfor %}
routes:
- to: default
via: {{ primary_gateway }}
nameservers:
addresses:
{% for dns in primary_dns %}
- {{ dns }}
{% endfor %}
dest: /etc/netplan/01-multi-ip.yaml
mode: '0600'
register: netplan_config
- name: 验证Netplan配置语法
shell: netplan try --timeout=10
environment:
NETPLAN_TRY_TIMEOUT: "10"
ignore_errors: yes
register: netplan_try
- name: 应用Netplan配置
shell: netplan apply
when: netplan_config is changed
- name: 等待网络恢复
wait_for:
host: "{{ primary_ip | ansible.utils.ipaddr('address') }}"
port: 22
timeout: 30
delegate_to: localhost
when: netplan_config is changed
ignore_errors: yes
- name: 验证IP配置
shell: ip addr show {{ primary_nic }} | grep "inet "
register: ip_verify
changed_when: false
- name: 显示配置结果
debug:
msg: |
═══════ 多IP配置完成 ═══════
网卡: {{ primary_nic }}
主IP: {{ primary_ip }}
网关: {{ primary_gateway }}
辅助IP:
{% for ip in secondary_ips %}
- {{ ip }}
{% endfor %}
当前IP列表:
{{ ip_verify.stdout }}
═══════════════════════════
`,
},
{
ID: "ipmitool-bmc", Name: "IPMI配置BMC地址", Category: "system",
Description: "使用ipmitool配置服务器BMC/IPMI管理口IP地址",
Icon: "🔧", Tags: []string{"ipmi", "bmc", "ipmitool", "hardware"},
Content: `---
- name: IPMI配置BMC地址
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
# BMC网络配置
bmc_ip: "10.10.10.100"
bmc_netmask: "255.255.255.0"
bmc_gateway: "10.10.10.1"
# BMC用户配置
bmc_user: "admin"
bmc_password: "Admin@123"
bmc_channel: 1
# 是否启用DHCP(设为true则忽略上面的静态IP配置)
bmc_dhcp: false
tasks:
- name: 安装ipmitool
package:
name: ipmitool
state: present
- name: 加载IPMI内核模块
modprobe:
name: "{{ item }}"
state: present
loop:
- ipmi_devintf
- ipmi_si
ignore_errors: yes
- name: 查看当前BMC配置
shell: ipmitool lan print {{ bmc_channel }}
register: bmc_current
changed_when: false
ignore_errors: yes
- name: 显示当前BMC信息
debug:
msg: "{{ bmc_current.stdout_lines | default(['无法读取BMC信息']) }}"
- name: 设置BMC为静态IP
shell: ipmitool lan set {{ bmc_channel }} ipsrc static
when: not bmc_dhcp
- name: 配置BMC IP地址
shell: ipmitool lan set {{ bmc_channel }} ipaddr {{ bmc_ip }}
when: not bmc_dhcp
- name: 配置BMC子网掩码
shell: ipmitool lan set {{ bmc_channel }} netmask {{ bmc_netmask }}
when: not bmc_dhcp
- name: 配置BMC默认网关
shell: ipmitool lan set {{ bmc_channel }} defgw ipaddr {{ bmc_gateway }}
when: not bmc_dhcp
- name: 设置BMC为DHCP模式
shell: ipmitool lan set {{ bmc_channel }} ipsrc dhcp
when: bmc_dhcp
- name: 配置BMC用户密码
shell: |
ipmitool user set name {{ bmc_channel }} 2 {{ bmc_user }} 2>/dev/null || true
ipmitool user set password 2 {{ bmc_password }}
ipmitool user enable 2
ipmitool channel setaccess {{ bmc_channel }} 2 privilege=4
no_log: true
ignore_errors: yes
- name: 验证BMC配置
shell: ipmitool lan print {{ bmc_channel }}
register: bmc_verify
changed_when: false
- name: 显示最终配置
debug:
msg: |
═══════ BMC配置完成 ═══════
模式: {{ 'DHCP' if bmc_dhcp else '静态IP' }}
IP: {{ bmc_ip }}
掩码: {{ bmc_netmask }}
网关: {{ bmc_gateway }}
用户: {{ bmc_user }}
═══════════════════════════
{{ bmc_verify.stdout }}
`,
},
{
ID: "apt-install", Name: "APT软件安装", Category: "system",
Description: "通过apt批量安装/卸载软件包,支持指定版本和仓库",
Icon: "📦", Tags: []string{"apt", "install", "package", "debian"},
Content: `---
- name: APT软件安装
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
# 要安装的软件包列表
packages_install:
- vim
- curl
- wget
- htop
- net-tools
- tree
- unzip
- git
# 要卸载的软件包列表
packages_remove: []
# 是否更新缓存
update_cache: yes
# 是否自动清理
autoremove: yes
# 安装推荐包
install_recommends: no
# 指定版本(可选,格式: "package=version"
# 例: packages_install: ["nginx=1.18.0-0ubuntu1"]
tasks:
- name: 确认Debian系统
assert:
that: ansible_os_family == "Debian"
fail_msg: "此模板仅适用于 Debian/Ubuntu 系统"
- name: 更新APT缓存
apt:
update_cache: yes
cache_valid_time: 3600
when: update_cache
- name: 安装软件包
apt:
name: "{{ packages_install }}"
state: present
install_recommends: "{{ install_recommends }}"
register: install_result
when: packages_install | length > 0
- name: 卸载软件包
apt:
name: "{{ packages_remove }}"
state: absent
purge: yes
when: packages_remove | length > 0
- name: 自动清理
apt:
autoremove: yes
autoclean: yes
when: autoremove
- name: 验证安装结果
shell: dpkg -l {{ packages_install | join(' ') }} 2>/dev/null | grep "^ii" | awk '{print $2, $3}'
register: verify_result
changed_when: false
when: packages_install | length > 0
- name: 显示安装报告
debug:
msg: |
═══════ APT安装报告 ═══════
已安装: {{ packages_install | length }} 个包
已卸载: {{ packages_remove | length }} 个包
变更: {{ install_result.changed | default(false) }}
{% if verify_result is defined and verify_result.stdout_lines is defined %}
已确认:
{% for line in verify_result.stdout_lines %}
{{ line }}
{% endfor %}
{% endif %}
═══════════════════════════
`,
},
{
ID: "dpkg-install", Name: "DPKG软件安装", Category: "system",
Description: "通过dpkg安装本地.deb包,支持URL下载和依赖修复",
Icon: "📥", Tags: []string{"dpkg", "deb", "install", "offline"},
Content: `---
- name: DPKG软件安装
hosts: "{{ target_hosts | default('all') }}"
become: yes
vars:
# 本地deb包路径列表(服务器上的路径)
local_deb_files: []
# 远程URL列表(会自动下载后安装)
remote_deb_urls: []
# 下载临时目录
download_dir: /tmp/dpkg_install
# 安装后是否修复依赖
fix_dependencies: yes
# 是否保留下载的deb文件
keep_deb_files: no
tasks:
- name: 确认Debian系统
assert:
that: ansible_os_family == "Debian"
fail_msg: "此模板仅适用于 Debian/Ubuntu 系统"
- name: 创建下载目录
file:
path: "{{ download_dir }}"
state: directory
mode: '0755'
when: remote_deb_urls | length > 0
- name: 下载远程deb包
get_url:
url: "{{ item }}"
dest: "{{ download_dir }}/{{ item | basename }}"
mode: '0644'
loop: "{{ remote_deb_urls }}"
register: download_result
when: remote_deb_urls | length > 0
- name: 安装本地deb包
apt:
deb: "{{ item }}"
state: present
loop: "{{ local_deb_files }}"
register: local_install
when: local_deb_files | length > 0
- name: 安装下载的deb包
apt:
deb: "{{ download_dir }}/{{ item | basename }}"
state: present
loop: "{{ remote_deb_urls }}"
register: remote_install
when: remote_deb_urls | length > 0
- name: 修复依赖关系
apt:
update_cache: yes
force_apt_get: yes
shell: apt-get install -f -y
when: fix_dependencies
ignore_errors: yes
- name: 清理下载文件
file:
path: "{{ download_dir }}"
state: absent
when: not keep_deb_files and remote_deb_urls | length > 0
- name: 显示安装报告
debug:
msg: |
═══════ DPKG安装报告 ═══════
本地包: {{ local_deb_files | length }}
远程包: {{ remote_deb_urls | length }}
{% if local_deb_files | length > 0 %}
本地安装:
{% for f in local_deb_files %}
{{ f }}
{% endfor %}
{% endif %}
{% if remote_deb_urls | length > 0 %}
远程安装:
{% for u in remote_deb_urls %}
{{ u | basename }}
{% endfor %}
{% endif %}
依赖修复: {{ '是' if fix_dependencies else '否' }}
═══════════════════════════
`,
},
}
}