文章目录
1. 远程管理服务
1. 基础概念
1. 什么是 ssh
- 安全的远程连接,数据信息加密,默认端口 22,ssh 服务默认可以用 root 用户远程连接
- 工作原理:客户端执行远程连接命令,客户端和服务端建立三次握手,服务端让客户端进行确认是否接收服务端公钥信息,客户端进行公钥确认,接收到公钥信息,服务端让客户端确认登录用户密码信息,客户端进行密码信息确认,客户端、服务端远程连接建立成功
- 私钥和公钥的作用
- 利用私钥和公钥对数据信息进行加密处理
- 利用公钥和私钥进行用户认证
2. 什么是 Telnet
- 不安全的远程连接,数据信息明文,默认端口 23,ssh 服务默认不可以用 root 用户远程连接,网络设备连接
2. SSH 远程连接方式
1. 口令连接
- 比较麻烦,连接不太安全
2. 秘钥连接
- 连接方便,连接比较安全
- 秘钥连接过程
- 客户端(管理端) 执行命令创建秘钥对
- 客户端(管理端)建立远程连接,发送公钥信息
- 客户端(管理端)再次建立连接
- 服务端(被管理端)发送公钥质询信息
- 客户端(管理端)处理公钥质询信息,将质询结果返回给服务端
- 服务端(被管理端)接收质询结果,建立好远程连接
3. ssh 实现基于秘钥连接的部署
-
管理端创建秘钥对信息
`ssh-keygen` -t dsa Generating public/private dsa key pair. Enter file in which to save the key (/root/.ssh/id_dsa): Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in # /root/.ssh/id_dsa. Your public key has been saved in # /root/.ssh/id_dsa.pub. -
管理端需要将公钥信息进行分发
ssh-copy-id -i /root/.ssh/id_dsa.pub root@172.16.1.130 -
进行远程连接测试
ssh nfs01 # 不用输入密码信息可以直接连接 -
分发公钥脚本
#!/bin/bash for ip in {131..141} do sshpass -p1 ssh-copy-id -i /root/.ssh/id_dsa.pub root@172.16.1.$ip -p 22 "-o StrictHos" if [ $? -eq 0 ];then echo "$i 分发成功" else echo "$i 分发失败" fi done ## sshpass 免交互输入密码,需要下载这个软件 ## -p 指定端口号 ## "-o StrictHos" 免交互确认
4. SSH 配置文件
vim /etc/ssh/sshd_config
Port 22 # 服务端口信息
ListenAddress 0.0.0.0 # 监听地址 指定一块网卡作为监听地址,只能指定本机网卡
PermitEmptyPasswords # 是否允许空密码远程登录
PermitRootLogin # 是否禁止 root 用户进行远程连接,建议改为 no
GSSAPIAuthentication # 是否开启 GSSAPI 认证功能,不用的时候关闭
UseDNS # 是否开启反向DNS解析,建议关闭,影响连接速度
5. SSH远程服务防范入侵的案例
- 用密钥登录,不用密码登陆
- 牤牛阵法:解决SSH安全问题
a.防火墙封闭SSH,指定源IP限制(局域网、信任公网)
b.开启SSH只监听本地内网IP(ListenAddress 172.16.1.61)。 - 尽量不给服务器外网IP
- 最小化(软件安装-授权)
- 给系统的重要文件或命令做一个指纹
- 给他锁上
chattr +i
6. SFTP 的命令总结
sftp 172.16.1.41 ## 远程登录
ls #查看远程ftp服务器信息
cd #查看远程ftp服务器信息
lls #查看本地ftp客户端信息
lcd #查看本地ftp客户端信息
get #下载信息
put #上传信息
help #查看命令帮助
bye #退出ftp连接
2. 批量管理服务
1. 基础知识
1. ansible 批量管理服务概念
- 是基于Python语言开发的自动化软件工具
- 是基于 SSH 远程管理服务实现远程主机批量管理
2. ansible 批量管理服务特点
- 管理端不需要启动服务程序
- 管理端不需要编写配置文件
- 受控端不需要安装软件程序(
libselinux-python) - 受控端不需要启动服务程序
- 服务程序管理操作模块众多
- 利用剧本编写来实现自动化
3. ansible 批量管理服务的意义
- 提高工作的效率
- 提高工作准确度
- 减少维护的成本
- 减少重复性工作
4.ansible批量管理服务功能
- 可以实现批量系统操作配置
- 可以实现批量软件服务部署
- 可以实现批量文件数据分发
- 可以实现批量系统信息收集
2. ansible 批量管理服务部署
-
管理端服务器
-
安装部署软件
`yum` install -y ansible -
编写主机清单文件
vim /etc/ansible/hosts [添加内容如下] nfs01 backup [精致的结尾] -
主机清单的多种配置方式
-
第一种方式: 分组配置主机信息
[web] 172.16.1.7 172.16.1.8 172.16.1.9 -
第二种方式: 主机名符号匹配配置
[web] 172.16.1.[7:9] -
第三种方式: 跟上非标准远程端口
[web] 172.16.1.7:52113 -
第四种方式: 主机使用特殊的变量
[web] web01 ansible_ssh_host=172.16.1.7 ansible_ssh_port=52113 ansible_ssh_user=root ansible_ssh_pass=123456 -
第五种方式: 主机组名嵌入配置
[rsync:children] # 嵌入子组信息 rsync_server rsync_client [rsync_server] 172.16.1.41 [rsync_client] 172.16.1.31 172.16.1.7 [web:vars] # 嵌入式变量信息 ansible_ssh_host=172.16.1.7 ansible_ssh_port=52113 ansible_ssh_user=root ansible_ssh_pass=123456 [web] web01 主机清单的配置方法: https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
-
-
3. ansible 批量管理服务应用
-
官方网站:https://docs.ansible.com/ansible/2.7/modules/modules_by_category.html
-
ansible学习帮助手册`ansible-doc` -l # 列出模块使用简介 `ansible-doc` -s command # 指定一个模块的详细说明 `ansible-doc` command # 查询模块在剧本中的应用方法 -
模块应用的语法格式:
`ansible` 主机名称/主机组名称/IP/all -m('指定应用的模块信息') 模块名称 -a('指定动作信息') "执行什么命令"
1. 模块一:command (默认模块)
command - Executes a command on a remote node
#在一个远程主机上执行一个命令
## 简单用法
`ansible` nfs01 -m command -a "hostname -i"
## 扩展应用
1. `chdir` 在命令执行之前对目录进行切换,默认家目录
[root@man tmp]# ansible nfs01 -m command -a "chdir=/tmp touch gx.txt"
nfs01 | CHANGED | rc=0 >>
2. `creates` 如果文件存在了,不执行命令操作
ansible nfs01 -m command -a "creates=/tmp/gx.txt chdir=/tmp touch gx01.txt"
nfs01 | SUCCESS | rc=0 >>
skipped, since /tmp/gx.txt exists
3. `removes` 如果文件存在了,就执行命令操作
ansible nfs01 -m command -a "removes=/tmp/gx.txt chdir=/tmp touch gx01.txt"
nfs01 | CHANGED | rc=0 >>
4. `free_form(require)` 使用 command 模块的时候, -a 参数
后面必须写上一个合法的Linux命令信息
### 注意事项:有些符号信息无法识别:<,>,|,&
2. 模块二:shell (万能模块)
command - Execute commands in nodes
#在节点上执行操作
## 简单用法
`ansible` nfs01 -m shell -a "hostname -i"
示例:`ansible` nfs01 -m shell -a "hostname -i"
nfs01 | CHANGED | rc=0 >>
172.16.1.130
## 扩展应用
1. `chdir` 在命令执行之前对目录进行切换,默认家目录
[root@man tmp]# ansible nfs01 -m shell -a "chdir=/tmp touch gx.txt"
nfs01 | CHANGED | rc=0 >>
2. `creates` 如果文件存在了,不执行命令操作
ansible nfs01 -m shell -a "creates=/tmp/gx.txt chdir=/tmp touch gx01.txt"
nfs01 | SUCCESS | rc=0 >>
skipped, since /tmp/gx.txt exists
3. `removes` 如果文件存在了,就执行命令操作
ansible nfs01 -m shell -a "removes=/tmp/gx.txt chdir=/tmp touch gx01.txt"
nfs01 | CHANGED | rc=0 >>
4. `free_form(require)` 使用 command 模块的时候, -a 参数
后面必须写上一个合法的Linux命令信息
5. 可以识别 command 模块识别不了的符号
ansible nfs01 -m shell -a "echo 123 > /tmp/gx.txt"
nfs01 | CHANGED | rc=0 >>
6. 安装 htop
1) 编写脚本文件
vim /server/scripts/yum_htop.sh
[编写以下下内容]
#!/bin/bash
yum install -y htop
[精致的结尾]
2)更改文件属性
3)将脚本发送到远程主机
4)运行 `ansible` 命令执行脚本
3. 模块三:script
## 专门执行脚本的模块
# 安装 htop
1) 编写脚本文件
vim /server/scripts/yum_htop.sh
[编写以下下内容]
#!/bin/bash
yum install -y htop
[精致的结尾]
4)运行 `ansible` 命令执行脚本
`ansible` nfs01 -m script -a "/server/scripts/yum_htop.sh"
## 其他用法和 command 基本一致
4. 模块四:copy (文件类型模块)
copy - Copies files to remote locations
# 将数据信息进行批量分发
## 简单用法
ansible nfs01 -m copy -a "src=/tmp/result.txt dest=/tmp"
# src 为指定那个文件;dest 为传到那个目录下
## 扩展应用
1.在传输文件时修改文件的属主和属组信息
ansible nfs01 -m copy -a "src=/tmp/result.txt dest=/tmp owner=gx group=gx"
2. 在传输文件时修改文件的权限信息
ansible nfs01 -m copy -a "src=/tmp/result.txt dest=/tmp mode=777"
3. 在传输数据文件信息时对远程主机源文件进行备份
ansible nfs01 -m copy -a "src=/tmp/result.txt dest=/tmp backup=yes"
4. 创建一个文件并直接编辑文件的信息
ansible nfs01 -m copy -a "content='hello world' dest=/tmp/ansible.txt "
5. 将远程服务器上 /etc/hosts 复制到 /tmp 下
ansible nfs01 -m copy -a "src=/etc/hosts dest=/tmp/ remote_src=yes"
6. 复制目录
ansible nfs01 -m copy -a "src=/test dest=/tmp/" # 传输 test 整个目录
ansible nfs01 -m copy -a "src=/test/ dest=/tmp/" # 传输test 目录下的所有文件
5. 模块五:file(文件类型模块)
file - set attributes of files
# 设置文件属性信息
## 基本用法
`ansible` nfs01 -m file -a "dest=/tmp/hosts owner=gx group=gx mode=777"
## 扩展用法
1. 可以利用模块创建数据信息(如 文件、目录、链接文件)
1.1 创建目录信息 state=directory
`ansible` nfs01 -m -a "dest=/tmp/test state=directory"
1.2 创建文件信息 state=touch
ansible nfs01 -m file -a "dest=/tmp/test/a.txt state=touch"
1.3 创建软连接信息 state=link
ansible nfs01 -m file -a "src=/tmp/test/a.txt dest=/tmp/test/a_link.txt state=link"
1.4 创建硬链接信息 state=hard # src 源文件 ;dest 目标文件
ansible nfs01 -m file -a "src=/tmp/test/a.txt dest=/tmp/test/a_hard.txt state=hard"
1.5 检查创建的数据信息是否存在 state=file
ansible nfs01 -m file -a " dest=/tmp/test/a_link.txt state=file"
1.6 删除一个文件或目录
ansible nfs01 -m file -a " dest=/tmp/test state=absent"
6. 模块六:yum
## 基本用法
`ansible` nfs01 -m yum -a "name=iotop state=installed"
name= # 指定安装软件的名称
state= # 指定对软件的操作
`installed present latest` # 安装软件
`absent removed` # 卸载软件
7. 模块七:service
service 模块:管理服务器的运行状态 停止 开启 重启
name= # 指定管理软件的名称
state= # 指定服务的状态
-started # 启动
-restarted # 重启
-stopped # 停止
enabled= # 指定服务是否开机自启
ansible nfs01 -m service -a "name=nfs state=stopped"
8. 模块八:cron
`cron` 模块: # 批量设置多个主机的定时任务信息
crontab -e
` * * * * * 定时任务动作 `
# 分 时 日 月 周
-minute: # 设置分钟信息( 0-59, *, */2, etc )
-hour: # 设置小时信息( 0-23, *, */2, etc )
-day: # 设置日期信息 ( 1-31, *, */2, etc )
-month: # 设置月份信息 ( 1-12, *, */2, etc )
-weekday: # 设置周信息 ( 0-6 for Sunday-Saturday, *, etc )
job # 用于定义定时任务需要干的事情
## 基本用法
`ansible` nfs01 -m cron -a "minute=2 job='/usr/sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1' "
## 扩展用法
1. 给定时任务添加注释
`ansible` nfs01 -m cron -a "name='time sys' minute=2 job='/usr/sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1' "
2. 删除定时任务
ansible nfs01 -m cron -a "name='time sys' state=absent "
3. 注释定时任务
ansible nfs01 -m cron -a "name='time sys'minute=2 job='/usr/sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1' disabled=yes "
9. 模块九:mount
`mount` # 批量进行挂载操作
src= # 需要挂载的存储设备或者文件信息
path= # 指定目标挂载点的目录
fstype= # 指定挂载时的文件系统类型
state=
-present # 进行挂载 不会立即挂载并修改 fstab 文件
-mounted # 进行挂载 立即挂载并修改 fstab 文件
-absent # 进行卸载 立即卸载并删除 fstab 文件
-unmounted # 进行卸载 立即卸载但不删除 fstab 文件
`ansible` backup -m mount -a "src=nfs01:/data path=/mnt state=mounted fstype=nfs"
10. 模块十:user
`user` # 实现批量创建用户
## 基本用法
`ansible` nfs01 -m user -a "name=mz"
## 扩展用法:
1. 指定用户uid信息
`ansible` 172.16.1.31 -m user -a "name=oldboy02 uid=6666"
2. 指定用户组信息
`ansible` 172.16.1.31 -m user -a "name=oldboy03 group=oldboy02"
`ansible` 172.16.1.31 -m user -a "name=oldboy04 groups=oldboy02"
3. 批量创建虚拟用户
ansible 172.16.1.31 -m user -a "name=rsync create_home=no shell=/sbin/nologin"
4) 给指定用户创建密码
# PS: 利用ansible程序user模块设置用户密码信息,需要将密码明文信息转换为密文信息进行设置
# 生成密文密码信息方法:
# 方法一:
`ansible` all -i localhost, -m debug -a "msg={{ '密码信息123456' | password_hash('sha512', 'oldboy') }}"
`ansible` all -i localhost, -m debug -a "msg={{ '123456' | password_hash('sha512', 'oldboy') }}"
localhost | SUCCESS => {
"msg": "$6$oldboy$MVd3DevkLcimrBLdMICrBY8HF82Wtau5cI8D2w4Zs6P1cCfMTcnnyAmmJc7mQaE9zuHxk8JFTRgYMGv9uKW7j1"
}
# 方法二:
`yum` install -y python-pip
`pip install` passlib
`python` -c "from passlib.hash import sha512_crypt; import getpass; print(sha512_crypt.using(rounds=5000).hash(getpass.getpass()))"
Password:
$6$rJJeiIerQ8p2eR82$uE2701X7vY44voF4j4tIQuUawmTNHEZhs26nKOL0z39LWyvIvZrHPM52Ivu9FgExlTFgz1VTOCSG7KhxJ9Tqk.
`ansible` 172.16.1.31 -m user -a 'name=oldboy08 password=$6$oldboy$MVd3DevkLcimrBLdMICrBY8HF82Wtau5cI8D2w4Zs6P1cCfMTcnnyAmmJc7mQaE9zuHxk8JFTRgYMGv9uKW7j1'
4. ansible 剧本编写
1. 什么是剧本
- 所谓剧本就是 ansible 命令的集合,主要形式为那个主机干了什么事情
2. 剧本的书写规范
- 并列关系用
-【横线空格】标齐 - 不同等级用两个空格表示
hosts、tasks、模块名 后面要用:【分号空格】
### 简单的示例
- hosts: nfs01
tasks:
- name: create a file # 注释
- file: dest=/tmp/yml01.txt state=touch
- file: dest=/tmp/yml02.txt state=touch
- hosts: backup
tasks:
- file: dest=/tmp/yml03.txt state=touch
- file: dest=/tmp/yml04.txt state=touch
3. 剧本变量声明
-
直接在剧本文件中编写
vars: var_name: var_key -
在命令行中编写
`ansible-playbook` -e var_name=var_key *.yml -
在主机清单中编写
[rsync_server] backup [rsync_server:vars] var_name=var_key -
三种变量的优先级
命令行 > 剧本中 > 主机清单中
4. 在剧本中设置注册信息
- name: 06 -- start rsync
service: name=rsyncd state=started enabled=yes
register: get_message # 给上一个命令的输出信息赋值
- name: 08 -- print rsync message
debug: msg={{get_message.status.ActiveState}} # 输出变量信息
5. 在剧本中设置判断信息
- hosts: all
tasks:
- name: 01 -- test
file: dest=/tmp/if.txt state=touch
### when: (ansible_hostname == "nfs01" )
6. 在剧本中设置循环
- hosts: all
tasks:
- name: 01 -- test
file: dest=/tmp/{{item.name}}{{item.num}}.txt state=touch
with_items:
- {name: 'gx',num: '01'}
- {name: 'mz',num: '02'}
7. 在剧本中设置错误的忽略
- hosts: nfs01
tasks:
- name: 01 -- test
file: det=/tmp/igore01.txt state=touch
# ignore_errors: yes
- name: 02 -- test
file: dest=/tmp/igore.txt state=touch
8. 在剧本中设置标签
- hosts: nfs01
tasks:
- name: 01 -- test01
file: det=/tmp/igore01.txt state=touch
# tags: test01
- name: 02 -- test02
file: dest=/tmp/igore.txt state=touch
`ansible-playbook` -t test01 t.yml # 只执行有 test01 这个标签的命令
ansible-playbook --skip-tags=test01 t.yml # 除了 test01 这个标签的都执行
9. 在剧本中设置触发信息
### 触发动作只有客户端 有改动 的命令起作用,即命令的输出信息为黄色
- hosts: nfs01
tasks:
- name: 01 -- test01
file: dest=/tmp/test state=directory
# notify: dir is already create
#handlers:
# - name: dir is already create
# file: dest=/tmp/test/a.txt state=touch
10. 剧本整合
-
方式一
- include: f1.yml - include: f2.yml -
方式二
- import_playbook: f1.yml - import_playbook: f2.yml
11. ansible 程序角色功能(roles)
以安装 nfs 为例
-
规范目录结构
cd /etc/ansible/roles mkdir -p nfs/{files,tasks,vars,templates,handlers} └── nfs ├── files # 保存需要分发的文件目录 ├── handlers # 保存触发器配置文件 ├── tasks # 保存要执行的动作文件 ├── templates # 保存需要分发的模板文件 └── vars # 保存变量信息文件 -
在
roles目录中编写相关文件-
编辑
tasks下的main.yml文件vim nfs/files/main.yml --------------------------------------------------------------------------- - name: server - 01 -- install software yum: name: ["nfs-utils","rpcbind"] state: installed - name: server - 02 - create exports file copy: src=exports dest=/etc/exports notify: restart software - name: server - 03 - create nfs user user: name=nfsnobody create_home=no shell=/sbin/nologin - name: server - 04 - create nfs dir file: dest={{data_dir}} state=directory owner=nfsnobody group=nfsnobody - name: server - 05 - start rpcbind service: name="{{item}}" state=started enabled=yes with_items: - rpcbind - nfs --------------------------------------------------------------------------- -
编辑
vars下的main.yml文件vim nfs/vars/main.yml -------------------------- data_dir: /data -------------------------- -
编辑
files下要分发的文件echo "/data 172.16.1.0/24(rw,sync)" > nfs/files/exports -
编辑
handlers下的main.yml文件vim nfs/handlers/handlers/main.yml --------------------------------------------- - name: restart software service: name="{{item}}" state=restarted with_items: - rpcbind - nfs --------------------------------------------- -
编辑主剧本文件
vim nfs/site.yml ----------------------- - hosts: nfs-server roles: - nfs ----------------------- -
变量优化设置
mv nfs/files/exports nfs/templates/ vim nfs/tasks/main.yml copy: src=exports dest=/etc/exports 改为 template: src=exports dest=/etc/exports cat nfs/vars/main.yml data_dir: /data ip_addr: 192.168.80.0 cat nfs/templates/exports /data 172.16.1.0/24(rw,sync) /data {{ip_addr}}/24(rw,sync)
-
4. ansible 服务架构信息
- 主机清单配置
- 软件模块信息
- 基于秘钥连接主机
- 主机需要关闭 selinux
- 软件剧本功能
5. ansible 命令的输出信息部分解释
-
颜色说明:
01. 绿色信息: 查看主机信息/对主机未做改动 02. 黄色信息: 对主机数据信息做了修改 03. 红色信息: 命令执行出错了 04. 粉色信息: 忠告信息 05. 蓝色信息: 显示ansible命令执行的过程 -
调用复制模块的输出说明
nsible 172.16.1.31 -m copy -a "src=/etc/hosts dest=/etc/" 172.16.1.31 | CHANGED => { #对哪台主机进行操作 "changed": true, #是否对主机信息进行改变 "checksum": "6ed7f68a1d6b4b36c1418338b2001e421eeba270", #生成一个文件校验码==MD5数值 "dest": "/etc/hosts", #显示目标路径信息 "gid": 0, #显示复制后文件gid信息 "group": "root", #显示复制后文件属组信息 "md5sum": "7afd7b74854f0aaab646b3e932f427c0", #生成一个文件校验码==MD5数值 "mode": "0644", #显示复制后文件权限信息 "owner": "root", #显示复制后文件属主信息 "size": 401, #显示文件的大小信息 "src": "/root/.ansible/tmp/ansible-tmp-1557804498.23-26487341925325/source", "state": "file", #显示文件的类型信息 "uid": 0 #显示复制后文件uid信息 }
6. 远程主机无法管理问题分析
- 管理端没有分发好主机的公钥
- 被管理端远程服务出现问题 — 端口、防火墙
- 被管理端进程出现僵死情况
/usr/sbin/sshd -D— 负责建立远程连接sshd: root@pts/0— 用于维护远程连接(windows--linux)sshd: root@notty— 用于维护远程连接(ansible–被管理端)
7. crontab 定时任务
1. 表达格式
秒数 分钟 小时 日期 月份 星期 年份(可为空)
# 秒数
# 允许值范围 0-59 (不允许为空)
# 允许符号 , - * /
# , 代表在指定的秒数触发,例如:“0,15,45” 代表在0秒,15秒和45秒触发
# - 代表在指定的范围触发,例如:“5-12” 代表在5秒开始触发,在12秒结束,每秒触发一次。
# * 代表每隔一秒就触发
# / 代表触发步进(step),/ 前面的代表初始值(* 等同于 0),后面的值代表偏移量。例如:“2/10” 从2秒开始,每隔10秒触发一次。而 “2-40/10” 代表从2开始,每隔10秒触发一次,40秒时结束。
# 分钟
# 允许值范围:0-59(不允许为空)
# 允许符号:, - * /
# 小时
# 允许值范围:0-23 (不允许为空值,若值不合法,调度器抛出 SchedulerException 异常)
# 允许符号:, - * /
# 日期
# 允许值范围:1-12 (不允许为空值,若值不合法,调度器抛出 SchedulerException 异常)
# 允许符号:, - * /
# 星期
# 允许值范围:1-7 (不允许为空 注意:1 代表星期天,7 代表星期六)
# 允许符号:, - * / #
# “#” 前代表本月的第几个星期,“#” 后代表星期几。例如:“2#2” 本月的第二个星期的星期一。
# 年
# 允许值范围:1970-2099(允许为空)
# 允许符号:, - * /
## 注意事项:
1. 只有年份可以为空,其他的不能为空
2. 有时候我们仅用日期或星期,这时候就可以使用 ? 将不使用的日期或星期表示互斥。
3. 其中最常用的格式为:分时日月星
2. 使用方法
# 首先要启动和开机自启
systemctl start crond && systemctl enable crond
# 查看当前的任务
crontab -l
# 书写任务
crontab -e # 然后直接写就行了,保存退出
echo '表达格式 + 任务' >>/var/spool/cron/root
# 删除任务
crontab -r # 全部删除,谨慎使用。

801

被折叠的 条评论
为什么被折叠?



