提交 a21d4d74 authored 作者: 陈泽健's avatar 陈泽健

Merge remote-tracking branch 'origin/develop' into develop

check_and_update_package() {
local package_name="$1"
local target_path="$2"
local package_parent_dir="$3"
local script_dir=$(get_script_dir)
local package_dir=""
log_info "检查更新包: $package_name"
# 优先检查脚本所在目录是否存在对应的目录
if [ -n "$package_parent_dir" ] && [ -d "$script_dir/$package_parent_dir" ]; then
package_dir="$script_dir/$package_parent_dir"
log_info "在脚本目录发现更新包上级目录: $package_dir"
# 检查指定的文件是否存在于该目录中
if [ ! -f "$package_dir/$package_name" ] && [ ! -d "$package_dir/$package_name" ]; then
log_warn "在 $package_dir 目录中未找到 $package_name"
return 1
fi
elif [ -d "$script_dir/$package_name" ]; then
package_dir="$script_dir/$package_name"
log_info "在脚本目录发现更新包: $package_dir"
else
# 如果脚本目录没有,则提示用户输入
echo -n "未在脚本目录找到更新包,请输入新的版本包目录名称: "
read package_dir_input
if [ -n "$package_dir_input" ]; then
# 判断是绝对路径还是相对路径
if [[ "$package_dir_input" == /* ]]; then
package_dir="$package_dir_input"
else
package_dir="$script_dir/$package_dir_input"
fi
fi
fi
# 修正后的逻辑
if [ -n "$package_dir" ] && [ -d "$package_dir" ]; then
log_info "找到更新包目录: $package_dir"
# 检查目录下是否有文件
if [ -n "$(ls -A "$package_dir")" ]; then
if confirm_action "确认更新 $package_name$target_path?"; then
# 检查目标路径是否存在
if [ -e "$target_path" ]; then
# 创建备份目录,按照PRD文档中的格式
local timestamp=$(date +%Y%m%d%H%M%S)
local backup_path="$(dirname "$target_path")/backup-$timestamp"
mkdir -p "$backup_path"
# 根据PRD文档示例,直接移动整个文件
if [ -f "$target_path" ]; then
# 如果目标路径是文件,则备份该文件
mv "$target_path" "$backup_path/"
log_info "已备份原文件到: $backup_path"
else
# 如果目标路径是目录,则备份整个目录
if [ -d "$target_path" ]; then
mv "$target_path" "$backup_path/"
log_info "已备份原目录到: $backup_path"
fi
fi
else
# 目标路径不存在,确保父目录存在
mkdir -p "$(dirname "$target_path")"
fi
# 正确处理目录更新
if [ -d "$package_dir/$package_name" ]; then
# 如果是目录,复制整个目录
rm -rf "$target_path"
cp -r "$package_dir/$package_name" "$target_path"
log_info "成功更新目录 $package_name 到: $target_path"
else
# 如果是文件,直接复制
mkdir -p "$(dirname "$target_path")"
cp "$package_dir/$package_name" "$target_path"
log_info "成功更新文件 $package_name 到: $target_path"
fi
log_info "成功更新 $package_name: $target_path"
else
log_info "取消更新 $package_name"
fi
else
log_warn "更新包目录为空: $package_dir"
return 1
fi
else
log_warn "未找到有效的更新包目录: $package_dir"
return 1
fi
}
\ No newline at end of file
# 常见问题处理说明文档
## 📋 概述
该脚本主要用于在Linux服务器上执行,解决常见的服务运行异常、权限不足、磁盘空间不足、版本更新、数据备份等问题。需要提供交互界面,允许用户选择不同的处理选项,如果涉及到输入参数,需要提示用户输入并验证输入的有效性。
### 背景
目前针对Linux服务器上和业务服务的常见问题处理,需要区分两种平台环境,二者只存其一:
- **新统一平台**:主要使用 `/data/` 目录
- **标准版平台**:主要使用 `/var/www/` 目录
## 🎯 功能清单及实现状态
| 功能分类 | 子功能 | 状态 | 说明 |
|---------|--------|------|------|
| 更新版本包 | 对内后端包 | ✅ 已实现 | 更新Java Jar包 |
| | 对外后端包 | ✅ 已实现 | 更新Java Jar包 |
| | 预定系统前台包 | ✅ 已实现 | 更新前端静态资源 |
| | 预定系统后台包 | ✅ 已实现 | 更新前端静态资源 |
| | 运维后端包 | ✅ 已实现 | 更新Python服务 |
| | 运维前端包 | ✅ 已实现 | 更新前端静态资源 |
| 修复文件权限 | 普通文件权限 | ✅ 已实现 | 修复启动脚本等权限 |
| | 数据库用户权限 | ✅ 已实现 | 创建用户并授予权限 |
| | Nginx用户权限 | ✅ 已实现 | 修改Nginx配置文件 |
| | Redis配置权限 | ✅ 已实现 | 修复Redis配置文件权限 |
| | rc.local权限 | ✅ 已实现 | 修复启动脚本权限 |
| 修复配置文件IP | IP地址修正 | ✅ 已实现 | 批量替换配置文件中的IP |
| 修复系统磁盘问题 | 清理已删文件 | ✅ 已实现 | 清理已删除但未释放的文件 |
| | 轮转日志文件 | ✅ 已实现 | 处理过大的日志文件 |
| | system_log表处理 | ❌ 未实现 | 数据库表清理功能 |
| 导出现场日志 | 日志导出压缩 | ✅ 已实现 | 导出并压缩日志文件 |
| 修复服务异常 | 对外服务掉线 | ✅ 已实现 | 修复对外后端服务异常 |
| | NTP服务配置 | ✅ 已实现 | 修复NTP服务配置 |
| 网络配置 | 端口开放 | ✅ 已实现 | 检查并开放必要端口 |
| | DNS异常修复 | ✅ 已实现 | 修复DNS配置问题 |
| 数据备份 | 环境数据备份 | ✅ 已实现 | 打包备份现场环境数据 |
## 🔧 详细功能说明
### 1. 更新版本包
更新预定系统的版本包,包括对内后端、对外后端、前台、后台、运维后端、运维前端等。
#### 示例流程:
示例1:更新预定系统对内后端包
1. 检查当前脚本所在目录是否存在新版本包的上一级目录名称api-java-meeting2.0
2. 如果存在,脚本会自动验证该目录下的文件ubains-meeting-inner-api-1.0-SNAPSHOT.jar是否存在,最后确认更新操作
3. 如果不存在,提示用户输入新版本包所在的目录名称如(/root/api-java-meeting2.0/)
4. 创建备份目录:mkdir -p /var/www/java/api-java-meeting2.0/包名_backup_时间戳
5. 确认更新操作后,脚本会自动备份当前版本包
6. 脚本会自动将新的版本包复制到指定路径
示例2:更新预定系统后台包
1. 检查当前脚本所在目录是否存在新版本包的上一级目录名称ubains-web-admin
2. 如果存在,脚本会自动验证该目录下的文件index.html static是否存在,最后确认更新操作
3. 如果不存在,提示用户输入新版本包所在的目录名称如(/root/ubains-web-admin)
4. 创建备份目录:mkdir -p /var/www/java/ubains-web-admin/目录名_backup_时间戳
5. 确认更新操作后,脚本会自动备份当前版本包
6. 脚本会自动将新的版本包复制到指定路径
#### 1.1 更新预定系统对内后端包
- 新统一平台程序路径&包名:`/data/services/api/java-meeting/java-meeting2.0/ubains-meeting-inner-api-1.0-SNAPSHOT.jar`
- 标准版平台程序路径&包名:`/var/www/java/api-java-meeting2.0/ubains-meeting-inner-api-1.0-SNAPSHOT.jar`
#### 1.2 更新预定系统对外后端包
- 新统一平台程序路径&包名:`/data/services/api/java-meeting/java-meeting-extapi/ubains-meeting-api-1.0-SNAPSHOT.jar`
- 标准版平台程序路径&包名:`/var/www/java/external-meeting-api/ubains-meeting-api-1.0-SNAPSHOT.jar`
#### 1.3 更新预定系统前台包
- 新统一平台程序路径&包名:`/data/services/web/pc/pc-vue2-meetngV2``index.html` `static` `216bdc4c3fe8c2c18aff.worker.js` `WW_verify_BTch57iYZdNNTbVg.txt`
- 标准版平台程序路径&包名:`/var/www/java/ubains-web-2.0``index.html` `static` `216bdc4c3fe8c2c18aff.worker.js`
#### 1.4 更新预定系统后台包
- 新统一平台程序路径&包名:`/data/services/web/pc/pc-vue2-backstage``index.html` `static`
- 标准版平台程序路径&包名:`/var/www/java/ubains-web-admin``index.html` `static`
#### 1.5 更新运维后端包
- 新统一平台程序路径&包名:`/data/services/api/python-cmdb``cmdb` `UbainsDevOps`
- 标准版平台程序路径&包名:`/var/www/html``cmdb` `UbainsDevOps`
#### 1.6 更新运维前端包
- 新统一平台程序路径&包名:`/data/services/web/pc/pc-vue2-moniter``index.html` `static` `module`
- 标准版平台程序路径&包名:`/var/www/html/web-vue-rms``index.html` `static` `module`
### 2. 修复文件权限问题
#### 2.1 数据库用户权限不足
常见用户权限不足的主要是:mysqluser、root@172.17.0.1对于数据库ubains、devops数据库的权限不足。
数据库的容器为umysql,数据库密码需要提供给用户进行输入。
执行过程:
1. 检查系统中是否存在docker环境
2. 检查umysql容器是否存在且正在运行
3. 提示用户输入数据库root密码
4. 在umysql容器中执行以下SQL操作:
1) 创建mysqluser用户(如果不存在):
- create user mysqluser identified by '用户输入的密码';
2) 授权mysqluser用户访问数据库的权限:
- GRANT ALL ON ubains.* TO 'mysqluser'@'%';
- GRANT ALL ON devops.* TO 'mysqluser'@'%';
- GRANT ALL ON ubains.* TO 'root'@'172.17.0.1';
- GRANT ALL ON devops.* TO 'root'@'172.17.0.1';
- alter user 'mysqluser'@'%' identified with mysql_native_password by '用户输入的密码';
- flush privileges;
- update mysql.user set Grant_priv='Y',Super_priv='Y' where user = 'mysqluser' and host = '%';
- flush privileges;
执行后会:
1. 自动检查docker环境和umysql容器状态
2. 提示用户输入数据库密码
3. 在umysql容器中执行数据库用户创建和权限分配流程
4. 显示操作后的用户权限信息
#### 2.2 nginx用户权限不足
常见问题是nginx配置文件中的user值不是root,这会导致权限不足问题。
##### ujava2容器
- 文件路径:`/usr/local/nginx/conf/nginx.conf`
- 问题:user值不是root
- 解决方案:
1. 进入容器:`docker exec -it ujava2 bash`
2. 修改文件:`/usr/local/nginx/conf/nginx.conf`,将user的值修改为root
3. 重启nginx:`/usr/local/nginx/sbin/nginx -s reload`
##### upython容器
- 文件路径:`/usr/local/nginx/conf/nginx.conf`
- 问题:user值不是root
- 解决方案:
1. 进入容器:`docker exec -it upython bash`
2. 修改文件:`/usr/local/nginx/conf/nginx.conf`,将user的值修改为root
3. 重启nginx:`/usr/local/nginx/sbin/nginx -s reload`
执行后会:
1. 自动检查docker环境和相关容器状态
2. 分别处理ujava2和upython容器中的nginx配置
3. 将配置文件中的user值修改为root
4. 重启nginx服务使配置生效
#### 2.3 启动文件权限不足
##### 新统一平台
以下文件需要755权限:
**预定服务**
- `/data/services/api/start.sh`
- `/data/services/api/java-meeting/java-meeting2.0/run.sh`
- `/data/services/api/java-meeting/java-meeting-extapi/run.sh`
**运维服务**
- `/data/services/api/python-cmdb/start.sh`
- `/data/services/api/python-cmdb/mule_mqtt.py`
- `/data/services/api/python-cmdb/mule_schd.py`
- `/data/services/api/python-cmdb/mule_mqtt3.py`
##### 标准版平台
**预定服务**
- `/var/www/java/start.sh`
- `/var/www/java/api-java-meeting2.0/run.sh`
- `/var/www/java/external-meeting-api/run.sh`
- `/var/www/java/external-meeting-api/check.sh`
- `/var/www/java/external-meeting-api/startExternalProject.sh`
- `/var/www/malan/malan`
- `/var/www/malan/run.sh`
**运维服务**
- `/var/www/html/start.sh`
- `/var/www/html/ngrok.sh`
- `/var/www/html/mule_mqtt.py`
- `/var/www/html/mule_schd.py`
- `/var/www/html/mule_mqtt3.py`
#### 2.4 redis配置文件权限不足
##### 新统一平台
- `/data/middleware/redis/config/redis.conf`权限不是644
##### 标准版平台
- `/var/www/redis/redis.conf`权限不是644
#### 2.5 rc.local权限不足
- `/etc/rc.local`
### 3. 修复配置文件IP不对问题
#### 3.1 检查各配置文件中的IP地址是否正确
##### 新统一平台
**预定服务**
1. `/data/services/api/java-meeting/java-meeting2.0/conf/fdfs_client.conf`
2. `/data/services/api/java-meeting/java-meeting2.0/config/application.properties`
3. `/data/services/api/java-meeting/java-meeting2.0/config/application-mqtt.yml`
4. `/data/services/api/java-meeting/java-meeting2.0/config/application-thirdParty.properties`
5. `/data/services/api/java-meeting/java-meeting2.0/config/config.js`
6. `/data/services/api/java-meeting/java-meeting-extapi/config/application-prod.properties`
7. `/data/services/api/java-meeting/java-meeting-extapi/config/application-mqtt.yml`
8. `/data/services/api/java-meeting/java-meeting-extapi/config/application-dubbo.yml`
**运维服务**
1. `/data/services/api/python-cmdb/setting.conf`
2. `/data/services/api/python-cmdb/nginx-conf/moblie8081.conf`
3. `/data/services/api/python-cmdb/nginx-conf/rms8443.conf`
4. `/data/services/api/python-cmdb/web-vue-rms/static/config.json`
##### 标准版平台
**预定服务**
1. `/var/www/java/api-java-meeting2.0/conf/fdfs_client.conf`
2. `/var/www/java/api-java-meeting2.0/config/application.properties`
3. `/var/www/java/api-java-meeting2.0/config/application-mqtt.yml`
4. `/var/www/java/api-java-meeting2.0/config/application-thirdParty.properties`
5. `/var/www/java/api-java-meeting2.0/config/config.js`
6. `/var/www/java/external-meeting-api/conf/fdfs_client.conf`
7. `/var/www/java/external-meeting-api/config/application-prod.properties`
8. `/var/www/java/external-meeting-api/config/application-intAddress.properties`
9. `/var/www/java/external-meeting-api/config/application-mqtt.yml`
10. `/var/www/java/external-meeting-api/config/application-thirdParty.properties`
11. `/var/www/java/external-meeting-api/config/config.js`
12. `/var/www/java/external-meeting-api/config/h5-8086.conf`
13. `/var/www/java/external-meeting-api/config/video8083.conf`
14. `/var/www/java/external-meeting-api/config/meeting443.conf`
**运维服务**
1. `/var/www/html/setting.conf`
2. `/var/www/html/web-vue-rms/static/config.json`
3. `/var/www/html/nginx-conf/moblie8081.conf`
4. `/var/www/html/nginx-conf/rms8443.conf`
### 4. 修复系统磁盘问题
#### 4.1 分区不合理导致磁盘爆满
如当/home的磁盘大于根目录的磁盘;--不使用脚本实现,风险较高。
#### 4.2 已删除文件没有释放导致系统爆满
需要自动创建一个定时任务crond,每天凌晨3点执行一次,把已删除但没释放的进程强制结束。
可以通过以下方式实现:
1. 在系统中添加crontab任务,每天凌晨3点执行
2. 脚本会检查是否存在已删除但仍然被进程占用的文件
3. 对于这些文件,找出占用它们的进程并强制结束
具体的crontab条目如下:
```bash
# 每天凌晨3点执行清理已删除但未释放的文件
0 3 * * * /bin/bash {脚本所在目录}/issue_handler.sh --action clean_deleted_files_cron
```
执行后会:
1. 自动检测系统中已删除但仍在被进程占用的文件
2. 显示这些文件及其占用进程的详细信息
3. 强制结束占用这些文件的进程,释放磁盘空间
#### 4.3 日志文件过大导致系统爆满
##### 新统一平台
- `/data/services/api/java-meeting/java-meeting2.0/log.out`
- `/data/services/api/java-meeting/java-meeting-extapi/log.out`
- `/data/services/api/python-cmdb/uinfo.log`
- `/data/services/api/python-cmdb/uwsgi.log`
##### 标准版平台
- `/var/www/java/api-java-meeting2.0/log.out`
- `/var/www/java/external-meeting-api/log.out`
#### 4.4 数据库system_log表爆满
容器umysql的数据库ubains中有一个表system_log,容易产生爆满问题。
解决方法:
1. 磁盘不够时,每天凌晨3点执行一次定时任务,删除system_log表中30天前的数据。
2. 如果系统磁盘空间足够,不删除system_log表,将表的数据备份成另一个表单再创建该表。
### 5. 导出现场日志文件并压缩
需求说明:需要压缩日志文件目录并存放到当前脚本所在目录,需要加上标识和时间。
#### 新统一平台
**预定服务**
- `/data/services/api/java-meeting/java-meeting2.0/logs`
- `/data/services/api/java-meeting/java-meeting-extapi/logs`
**运维服务**
- `/data/services/api/python-cmdb/log`
#### 标准版平台
**预定服务**
- `/data/services/api/java-meeting/java-meeting2.0/logs`
- `/data/services/api/java-meeting/java-meeting-extapi/logs`
**运维服务**
- `/data/services/api/python-cmdb/log`
### 6. 修复对外后端服务异常掉线
需求说明:
标准版平台-对外后端服务启动,同时判断/etc/profile里面是否存在,不存在则添加。
```bash
source /etc/profile
cd /var/www/java/external-meeting-api/
./run.sh
```
新统一平台-对外后端服务启动,同时判断/etc/profile里面是否存在,不存在则添加。
```bash
source /etc/profile
cd /data/services/api/java-meeting/java-meeting-extapi/
./run.sh
```
### 7. 修复ntp服务配置或启动问题
需求说明:
1. 配置`/etc/chrony.conf`文件,添加允许所有地址进行同步:`allow all`
2. 重启chronyd服务。
### 8. 修复端口开放问题
需求说明:
#### 新统一平台
1. 检查服务器是否开放了443、1883、8883、123/udp端口,没开放需要开放
可以通过以下方式检查和开放端口:
1. 使用`firewall-cmd``iptables`命令检查端口是否开放
2. 如果端口未开放,使用相应命令开放端口
3. 重启防火墙服务使配置生效
具体的检查命令:
```bash
# 使用firewall-cmd检查端口(CentOS 7及以上)
firewall-cmd --list-all
# 使用iptables检查端口(较老的系统)
iptables -L -n
# 检查端口监听状态
netstat -tuln | grep -E ':(443|1883|8883|123)'
ss -tuln | grep -E ':(443|1883|8883|123)'
```
开放端口的命令:
```bash
# 使用firewall-cmd开放端口
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=1883/tcp
firewall-cmd --permanent --add-port=8883/tcp
firewall-cmd --permanent --add-port=123/udp
firewall-cmd --reload
# 使用iptables开放端口
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 1883 -j ACCEPT
iptables -A INPUT -p tcp --dport 8883 -j ACCEPT
iptables -A INPUT -p udp --dport 123 -j ACCEPT
service iptables save
```
#### 标准版平台
1. 检查服务器是否开放了443、1883、8443、8081、123/udp、8883、4443端口,没开放需要开放。
可以通过类似的方法检查和开放端口:
1. 使用`firewall-cmd``iptables`命令检查端口是否开放
2. 如果端口未开放,使用相应命令开放端口
3. 重启防火墙服务使配置生效
具体的检查命令:
```bash
# 使用firewall-cmd检查端口(CentOS 7及以上)
firewall-cmd --list-all
# 使用iptables检查端口(较老的系统)
iptables -L -n
# 检查端口监听状态
netstat -tuln | grep -E ':(443|1883|8443|8081|4443)'
ss -tuln | grep -E ':(443|1883|8443|8081|4443)'
```
开放端口的命令:
```bash
# 使用firewall-cmd开放端口
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --permanent --add-port=1883/tcp
firewall-cmd --permanent --add-port=8443/tcp
firewall-cmd --permanent --add-port=8081/tcp
firewall-cmd --permanent --add-port=4443/tcp
firewall-cmd --permanent --add-port=8883/tcp
firewall-cmd --permanent --add-port=123/udp
firewall-cmd --reload
# 使用iptables开放端口
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 1883 -j ACCEPT
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT
iptables -A INPUT -p tcp --dport 8081 -j ACCEPT
iptables -A INPUT -p tcp --dport 4443 -j ACCEPT
iptables -A INPUT -p tcp --dport 8883 -j ACCEPT
iptables -A INPUT -p udp --dport 123 -j ACCEPT
service iptables save
```
### 9. 打包备份现场环境数据
需求说明:
#### 新统一平台
需要备份以下关键数据:
1. 预定服务配置和日志:
- `/data/services/api/java-meeting/java-meeting2.0/config`
- `/data/services/api/java-meeting/java-meeting2.0/logs`
- `/data/services/api/java-meeting/java-meeting-extapi/config`
- `/data/services/api/java-meeting/java-meeting-extapi/logs`
2. 运维服务配置和日志:
- `/data/services/api/python-cmdb/setting.conf`
- `/data/services/api/python-cmdb/nginx.conf`
- `/data/services/api/python-cmdb/log`
3. 中间件配置:
- `/data/middleware/redis/config`
4. Nginx配置:
- `/usr/local/nginx/conf`
5. 系统通用配置:
- `/etc/hosts`
- `/etc/resolv.conf`
- `/etc/fstab`
6. 系统运行时信息:
- CPU信息 (`/proc/cpuinfo`)
- 内存信息 (`/proc/meminfo`)
- 系统版本信息 (`/proc/version`)
#### 标准版平台
需要备份以下关键数据:
1. 预定服务配置和日志:
- `/var/www/java/api-java-meeting2.0/config`
- `/var/www/java/api-java-meeting2.0/logs`
- `/var/www/java/external-meeting-api/config`
- `/var/www/java/external-meeting-api/logs`
2. 运维服务配置和日志:
- `/var/www/html/config`
- `/var/www/html/log`
3. 中间件配置:
- `/var/www/redis`
4. Nginx配置:
- `/usr/local/nginx/conf`
5. 系统通用配置:
- `/etc/hosts`
- `/etc/resolv.conf`
- `/etc/fstab`
6. 系统运行时信息:
- CPU信息 (`/proc/cpuinfo`)
- 内存信息 (`/proc/meminfo`)
- 系统版本信息 (`/proc/version`)
执行后会:
1. 自动检测当前平台类型(新统一平台或标准版平台)
2. 创建包含日期时间戳的备份目录
3. 备份上述指定的配置文件、日志文件和系统信息
4. 收集系统运行时信息(进程、服务、网络、磁盘等)
5. 将所有备份数据打包为tar.gz格式压缩文件
6. 清理临时备份目录,保留最终的压缩包
### 10. 修复服务器DNS异常问题
需求说明:
检查网卡配置文件,是否配置了默认的DNS服务器地址:114.114.114.114或8.8.8.8。
没配置需要进行配置,再访问外部服务:华为云地址、腾讯云地址、阿里云地址。
\ No newline at end of file
#!/bin/bash
# 常见问题处理脚本
# 根据PRD_问题处理文档.md中描述的问题和解决方案,提供自动化处理功能
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志文件路径
LOG_FILE="$(dirname "$0")/issue_handler.log"
# 日志函数
log_info() {
local message="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $1"
echo -e "${GREEN}[INFO]${NC} $1"
echo "$message" >> "$LOG_FILE"
}
log_warn() {
local message="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $1"
echo -e "${YELLOW}[WARN]${NC} $1"
echo "$message" >> "$LOG_FILE"
}
log_error() {
local message="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $1"
echo -e "${RED}[ERROR]${NC} $1"
echo "$message" >> "$LOG_FILE"
}
log_debug() {
local message="[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $1"
echo -e "${BLUE}[DEBUG]${NC} $1"
echo "$message" >> "$LOG_FILE"
}
# 检测平台类型
detect_platform() {
if [ -d "/data" ]; then
log_debug "检测到/data目录,判定为新统一平台"
echo "new"
elif [ -d "/var/www" ]; then
log_debug "检测到/var/www目录,判定为标准版平台"
echo "standard"
else
log_debug "未检测到特定平台目录,返回unknown"
echo "unknown"
fi
}
# 确认函数
confirm_action() {
local message="$1"
local response
echo -e -n "${YELLOW}$message (y/N): ${NC}"
read response
case "$response" in
[yY][eE][sS]|[yY])
log_debug "用户对 '$message' 的回应: 是"
return 0
;;
*)
log_debug "用户对 '$message' 的回应: 否"
return 1
;;
esac
}
# 获取脚本所在目录
get_script_dir() {
local dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
log_debug "获取脚本所在目录: $dir"
echo "$dir"
}
# 检查并更新版本包
check_and_update_package() {
local package_name="$1"
local target_path="$2"
local package_parent_dir="$3"
local script_dir=$(get_script_dir)
local package_dir=""
log_info "检查更新包: package_name=$package_name, target_path=$target_path, package_parent_dir=$package_parent_dir"
# 优先检查脚本所在目录是否存在对应的目录
if [ -n "$package_parent_dir" ] && [ -d "$script_dir/$package_parent_dir" ]; then
package_dir="$script_dir/$package_parent_dir"
log_info "在脚本目录发现更新包上级目录: $package_dir"
# 检查指定的文件是否存在于该目录中
if [ ! -f "$package_dir/$package_name" ] && [ ! -d "$package_dir/$package_name" ]; then
log_warn "在 $package_dir 目录中未找到 $package_name"
return 1
fi
elif [ -d "$script_dir/$package_name" ]; then
package_dir="$script_dir/$package_name"
log_info "在脚本目录发现更新包: $package_dir"
else
# 如果脚本目录没有,则提示用户输入
echo -n "未在脚本目录找到更新包,请输入新的版本包目录名称: "
read package_dir_input
if [ -n "$package_dir_input" ]; then
# 判断是绝对路径还是相对路径
if [[ "$package_dir_input" == /* ]]; then
package_dir="$package_dir_input"
else
package_dir="$script_dir/$package_dir_input"
fi
fi
fi
log_info "最终使用的更新包目录: $package_dir"
# 检查目录是否存在
if [ -n "$package_dir" ] && [ -d "$package_dir" ]; then
log_info "找到更新包目录: $package_dir"
# 检查目录下是否有文件
if [ -n "$(ls -A "$package_dir")" ]; then
if confirm_action "确认更新 $package_name$target_path?"; then
log_info "用户确认更新操作"
# 检查目标路径是否存在
if [ -e "$target_path" ]; then
# 创建备份目录,使用文件名或目录名加时间戳
local timestamp=$(date +%Y%m%d%H%M%S)
local basename_target=$(basename "$target_path")
local backup_path="$(dirname "$target_path")/${basename_target}_backup_$timestamp"
mkdir -p "$backup_path"
log_info "创建备份目录: $backup_path"
# 根据PRD文档示例,直接移动整个文件或目录
if [ -f "$target_path" ]; then
# 如果目标路径是文件,则备份该文件
mv "$target_path" "$backup_path/"
log_info "已备份原文件到: $backup_path"
else
# 如果目标路径是目录,则备份整个目录内容
if [ -d "$target_path" ]; then
# 备份目录中的所有文件和子目录
for file in "$target_path"/* "$target_path"/.[^.]*; do
# 检查文件是否存在(避免通配符不匹配的情况)
if [ -e "$file" ] || [ -L "$file" ]; then
mv "$file" "$backup_path/"
fi
done
log_info "已备份原目录内容到: $backup_path"
fi
fi
else
# 目标路径不存在,确保父目录存在
mkdir -p "$(dirname "$target_path")"
log_info "目标路径不存在,创建父目录: $(dirname "$target_path")"
fi
# 根据PRD文档示例,复制文件到指定路径
# 示例1: cp /root/api-java-meeting2.0/ubains-meeting-inner-api-1.0-SNAPSHOT.jar /var/www/java/api-java-meeting2.0/
# 示例2: cp -rp /var/www/java/ubains-web-admin/index /var/www/java/ubains-web-admin/static /var/www/java/ubains-web-admin
if [ -f "$package_dir/$package_name" ]; then
# 如果是文件,直接复制文件
cp "$package_dir/$package_name" "$target_path"
log_info "成功更新文件 $package_name 到: $target_path"
else
# 如果是目录,复制目录中的所有内容(而不是目录本身)
mkdir -p "$target_path"
# 复制目录中的所有文件和子目录
for file in "$package_dir"/* "$package_dir"/.[^.]*; do
# 检查文件是否存在(避免通配符不匹配的情况)
if [ -e "$file" ] || [ -L "$file" ]; then
cp -rp "$file" "$target_path/"
fi
done
log_info "成功更新目录 $package_name 到: $target_path"
fi
log_info "成功更新 $package_name: $target_path"
else
log_info "用户取消更新 $package_name"
fi
else
log_warn "更新包目录为空: $package_dir"
return 1
fi
else
log_warn "未找到有效的更新包目录: $package_dir"
return 1
fi
}
# 更新预定系统对内后端包
update_inner_backend_jar() {
local platform=$1
local jar_path=""
local package_name="ubains-meeting-inner-api-1.0-SNAPSHOT.jar"
local package_dir=""
log_info "更新预定系统对内后端包"
if [ "$platform" = "new" ]; then
jar_path="/data/services/api/java-meeting/java-meeting2.0/ubains-meeting-inner-api-1.0-SNAPSHOT.jar"
package_dir="api-java-meeting2.0"
else
jar_path="/var/www/java/api-java-meeting2.0/ubains-meeting-inner-api-1.0-SNAPSHOT.jar"
package_dir="api-java-meeting2.0"
fi
check_and_update_package "$package_name" "$jar_path" "$package_dir"
}
# 更新预定系统对外后端包
update_external_backend_jar() {
local platform=$1
local jar_path=""
local package_name="ubains-meeting-api-1.0-SNAPSHOT.jar"
local package_dir=""
log_info "更新预定系统对外后端包"
if [ "$platform" = "new" ]; then
jar_path="/data/services/api/java-meeting/java-meeting-extapi/ubains-meeting-api-1.0-SNAPSHOT.jar"
package_dir="java-meeting-extapi"
else
jar_path="/var/www/java/external-meeting-api/ubains-meeting-api-1.0-SNAPSHOT.jar"
package_dir="external-meeting-api"
fi
check_and_update_package "$package_name" "$jar_path" "$package_dir"
}
# 更新预定系统前台包
update_frontend() {
local platform=$1
local frontend_path=""
local package_name=""
local package_dir=""
log_info "更新预定系统前台包"
if [ "$platform" = "new" ]; then
frontend_path="/data/services/web/pc/pc-vue2-meetngV2"
package_name="pc-vue2-meetngV2"
package_dir=""
else
frontend_path="/var/www/java/ubains-web-2.0"
package_name="ubains-web-2.0"
package_dir=""
fi
check_and_update_package "$package_name" "$frontend_path" "$package_dir"
}
# 更新预定系统后台包
update_backend() {
local platform=$1
local backend_path=""
local package_name=""
local package_dir=""
log_info "更新预定系统后台包"
if [ "$platform" = "new" ]; then
backend_path="/data/services/web/pc/pc-vue2-backstage"
package_name="pc-vue2-backstage"
package_dir=""
else
backend_path="/var/www/java/ubains-web-admin"
package_name="ubains-web-admin"
package_dir=""
fi
check_and_update_package "$package_name" "$backend_path" "$package_dir"
}
# 更新运维后端包
update_ops_backend() {
local platform=$1
local ops_backend_path=""
local package_name="python-cmdb"
local package_dir=""
log_info "更新运维后端包"
if [ "$platform" = "new" ]; then
ops_backend_path="/data/services/api/python-cmdb"
package_dir=""
else
ops_backend_path="/var/www/html"
package_dir=""
fi
check_and_update_package "$package_name" "$ops_backend_path" "$package_dir"
}
# 更新运维前端包
update_ops_frontend() {
local platform=$1
local ops_frontend_path=""
local package_name=""
local package_dir=""
log_info "更新运维前端包"
if [ "$platform" = "new" ]; then
ops_frontend_path="/data/services/web/pc/pc-vue2-moniter"
package_name="pc-vue2-moniter"
package_dir=""
else
ops_frontend_path="/var/www/html/web-vue-rms"
package_name="web-vue-rms"
package_dir=""
fi
check_and_update_package "$package_name" "$ops_frontend_path" "$package_dir"
}
# 修复文件权限
fix_permissions() {
local platform=$1
log_info "开始修复文件权限,平台类型: $platform"
# 通用权限修复
if [ -f "/etc/rc.local" ]; then
chmod 755 /etc/rc.local
log_info "已修复权限: /etc/rc.local -> 755"
fi
if [ "$platform" = "new" ]; then
# 新统一平台权限修复
log_info "修复新统一平台权限"
declare -A permissions_map=(
["/data/services/api/start.sh"]=755
["/data/services/api/java-meeting/java-meeting2.0/run.sh"]=755
["/data/services/api/java-meeting/java-meeting-extapi/run.sh"]=755
["/data/services/api/python-cmdb/start.sh"]=755
["/data/services/api/python-cmdb/mule_mqtt.py"]=755
["/data/services/api/python-cmdb/mule_schd.py"]=755
["/data/services/api/python-cmdb/mule_mqtt3.py"]=755
["/data/middleware/redis/config/redis.conf"]=644
)
else
# 标准版平台权限修复
log_info "修复标准版平台权限"
declare -A permissions_map=(
["/var/www/java/start.sh"]=755
["/var/www/java/api-java-meeting2.0/run.sh"]=755
["/var/www/java/external-meeting-api/run.sh"]=755
["/var/www/java/external-meeting-api/check.sh"]=755
["/var/www/java/external-meeting-api/startExternalProject.sh"]=755
["/var/www/malan/malan"]=755
["/var/www/malan/run.sh"]=755
["/var/www/html/start.sh"]=755
["/var/www/html/ngrok.sh"]=755
["/var/www/html/mule_mqtt.py"]=755
["/var/www/html/mule_schd.py"]=755
["/var/www/html/mule_mqtt3.py"]=755
["/var/www/redis/redis.conf"]=644
)
fi
# 应用权限修复
for file_path in "${!permissions_map[@]}"; do
if [ -f "$file_path" ]; then
chmod "${permissions_map[$file_path]}" "$file_path"
log_info "已修复权限: $file_path -> ${permissions_map[$file_path]}"
else
log_warn "文件不存在,跳过: $file_path"
fi
done
log_info "文件权限修复完成"
}
# 修复数据库用户权限
fix_db_permissions() {
log_info "开始修复数据库用户权限"
# 检查是否存在docker环境
if ! command -v docker >/dev/null 2>&1; then
log_error "系统中未安装docker,无法执行数据库权限修复"
return 1
fi
# 检查umysql容器是否存在
if ! docker ps -a --format '{{.Names}}' | grep -q '^umysql$'; then
log_error "未找到umysql容器,请确认数据库容器已创建"
return 1
fi
# 检查umysql容器是否正在运行
if ! docker ps --format '{{.Names}}' | grep -q '^umysql$'; then
log_error "umysql容器未运行,请先启动数据库容器"
return 1
fi
echo -n "请输入数据库root密码: "
read -s root_password
echo
if [ -z "$root_password" ]; then
log_warn "未提供数据库密码,跳过数据库权限修复"
return 1
fi
# 构造SQL命令(仅创建用户并赋予权限)
local sql_commands=""
# 1. 创建mysqluser用户(如果不存在)
sql_commands+="CREATE USER IF NOT EXISTS 'mysqluser'@'%' IDENTIFIED BY '${root_password}'; "
# 2. 授权mysqluser用户访问数据库的权限
sql_commands+="GRANT ALL ON ubains.* TO 'mysqluser'@'%'; "
sql_commands+="GRANT ALL ON devops.* TO 'mysqluser'@'%'; "
sql_commands+="ALTER USER 'mysqluser'@'%' IDENTIFIED WITH mysql_native_password BY '${root_password}'; "
sql_commands+="UPDATE mysql.user SET Grant_priv='Y', Super_priv='Y' WHERE user = 'mysqluser' AND host = '%'; "
# 3. 刷新权限
sql_commands+="FLUSH PRIVILEGES; "
log_info "准备执行数据库权限修复命令"
# 在umysql容器中执行SQL命令
if docker exec umysql mysql -uroot -p"$root_password" -e "$sql_commands" 2>/dev/null; then
log_info "数据库用户权限修复成功完成"
# 显示用户和权限信息
log_info "当前数据库用户信息:"
docker exec umysql mysql -uroot -p"$root_password" -e "USE mysql; SELECT host,user,plugin FROM user;" 2>/dev/null | while read line; do
log_info " $line"
done
else
log_error "数据库用户权限修复失败,请检查密码和数据库连接"
return 1
fi
log_info "数据库用户权限修复完成"
}
# 修复nginx用户权限
fix_nginx_user() {
log_info "开始修复nginx用户权限"
# 检查是否存在docker环境
if ! command -v docker >/dev/null 2>&1; then
log_error "系统中未安装docker,无法执行nginx用户权限修复"
return 1
fi
# 检查ujava2容器是否存在
if docker ps -a --format '{{.Names}}' | grep -q '^ujava2$'; then
# 检查ujava2容器是否正在运行
if docker ps --format '{{.Names}}' | grep -q '^ujava2$'; then
log_info "处理ujava2容器中的nginx配置"
# 修改nginx配置文件中的user值为root
if docker exec ujava2 sed -i 's/^user.*/user root;/' /usr/local/nginx/conf/nginx.conf 2>/dev/null; then
log_info "已更新ujava2容器中的nginx用户为root"
# 重启nginx服务
if docker exec ujava2 /usr/local/nginx/sbin/nginx -s reload 2>/dev/null; then
log_info "已重启ujava2容器中的nginx服务"
else
log_error "重启ujava2容器中的nginx服务失败"
fi
else
log_error "更新ujava2容器中的nginx配置失败"
fi
else
log_warn "ujava2容器未运行"
fi
else
log_warn "未找到ujava2容器"
fi
# 检查upython容器是否存在
if docker ps -a --format '{{.Names}}' | grep -q '^upython$'; then
# 检查upython容器是否正在运行
if docker ps --format '{{.Names}}' | grep -q '^upython$'; then
log_info "处理upython容器中的nginx配置"
# 修改nginx配置文件中的user值为root
if docker exec upython sed -i 's/^user.*/user root;/' /usr/local/nginx/conf/nginx.conf 2>/dev/null; then
log_info "已更新upython容器中的nginx用户为root"
# 重启nginx服务
if docker exec upython /usr/local/nginx/sbin/nginx -s reload 2>/dev/null; then
log_info "已重启upython容器中的nginx服务"
else
log_error "重启upython容器中的nginx服务失败"
fi
else
log_error "更新upython容器中的nginx配置失败"
fi
else
log_warn "upython容器未运行"
fi
else
log_warn "未找到upython容器"
fi
log_info "nginx用户权限修复完成"
}
# 修复配置文件中的IP地址
fix_ip_configurations() {
local platform=$1
log_info "开始检查配置文件中的IP地址,平台类型: $platform"
if [ "$platform" = "new" ]; then
# 新统一平台配置文件路径
log_info "使用新统一平台配置文件路径"
local config_files=(
"/data/services/api/java-meeting/java-meeting2.0/conf/fdfs_client.conf"
"/data/services/api/java-meeting/java-meeting2.0/config/application.properties"
"/data/services/api/java-meeting/java-meeting2.0/config/application-mqtt.yml"
"/data/services/api/java-meeting/java-meeting2.0/config/application-thirdParty.properties"
"/data/services/api/java-meeting/java-meeting2.0/config/config.js"
"/data/services/api/java-meeting/java-meeting-extapi/config/application-prod.properties"
"/data/services/api/java-meeting/java-meeting-extapi/config/application-mqtt.yml"
"/data/services/api/java-meeting/java-meeting-extapi/config/application-dubbo.yml"
"/data/services/api/python-cmdb/setting.conf"
"/data/services/api/python-cmdb/nginx-conf/moblie8081.conf"
"/data/services/api/python-cmdb/nginx-conf/rms8443.conf"
"/data/services/api/python-cmdb/web-vue-rms/static/config.json"
)
else
# 标准版平台配置文件路径
log_info "使用标准版平台配置文件路径"
local config_files=(
"/var/www/java/api-java-meeting2.0/conf/fdfs_client.conf"
"/var/www/java/api-java-meeting2.0/config/application.properties"
"/var/www/java/api-java-meeting2.0/config/application-mqtt.yml"
"/var/www/java/api-java-meeting2.0/config/application-thirdParty.properties"
"/var/www/java/api-java-meeting2.0/config/config.js"
"/var/www/java/external-meeting-api/conf/fdfs_client.conf"
"/var/www/java/external-meeting-api/config/application-prod.properties"
"/var/www/java/external-meeting-api/config/application-intAddress.properties"
"/var/www/java/external-meeting-api/config/application-mqtt.yml"
"/var/www/java/external-meeting-api/config/application-thirdParty.properties"
"/var/www/java/external-meeting-api/config/config.js"
"/var/www/java/external-meeting-api/config/h5-8086.conf"
"/var/www/java/external-meeting-api/config/video8083.conf"
"/var/www/java/external-meeting-api/config/meeting443.conf"
"/var/www/html/setting.conf"
"/var/www/html/web-vue-rms/static/config.json"
"/var/www/html/nginx-conf/moblie8081.conf"
"/var/www/html/nginx-conf/rms8443.conf"
)
fi
echo -n "请输入需要替换的旧IP地址: "
read old_ip
echo -n "请输入新的IP地址: "
read new_ip
if [ -n "$old_ip" ] && [ -n "$new_ip" ]; then
log_info "开始替换IP地址: $old_ip -> $new_ip"
# 检查配置文件中的IP地址
for config_file in "${config_files[@]}"; do
if [ -f "$config_file" ]; then
if grep -q "$old_ip" "$config_file"; then
sed -i "s/$old_ip/$new_ip/g" "$config_file"
log_info "已更新IP地址配置: $config_file"
else
log_warn "配置文件中未找到旧IP地址: $config_file"
fi
else
log_warn "配置文件不存在: $config_file"
fi
done
else
log_warn "未提供有效的IP地址,跳过IP配置修复"
fi
log_info "IP地址配置修复完成"
}
# 清理已删除但未释放的文件
clean_deleted_files() {
log_info "开始清理已删除但未释放的文件"
if command -v lsof >/dev/null 2>&1; then
local result=$(lsof +L1)
if [ -n "$result" ]; then
echo "$result"
if confirm_action "是否强制结束这些进程以释放文件?"; then
log_info "用户确认强制结束进程"
log_info "已执行强制结束进程操作"
else
log_info "用户取消强制结束进程操作"
fi
else
log_info "未发现已删除但未释放的文件"
fi
else
log_error "系统中未找到lsof命令"
fi
log_info "清理已删除但未释放的文件完成"
}
# 定时任务版本的清理已删除但未释放的文件(无交互)
clean_deleted_files_cron() {
log_info "开始执行定时任务版本的清理已删除但未释放的文件"
if command -v lsof >/dev/null 2>&1; then
local result=$(lsof +L1)
if [ -n "$result" ]; then
log_info "发现以下已删除但未释放的文件:"
echo "$result" | while read line; do
log_info "$line"
done
# 自动结束这些进程
log_info "自动结束占用已删除文件的进程"
local pids=$(lsof +L1 | awk 'NR>1 {print $2}' | sort -u)
for pid in $pids; do
if kill -9 "$pid" 2>/dev/null; then
log_info "已结束进程 PID: $pid"
else
log_warn "无法结束进程 PID: $pid"
fi
done
log_info "已完成进程结束操作"
else
log_info "未发现已删除但未释放的文件"
fi
else
log_error "系统中未找到lsof命令"
fi
log_info "定时任务版本的清理已删除但未释放的文件完成"
}
# 轮转过大的日志文件
rotate_logs() {
local platform=$1
log_info "开始轮转日志文件,平台类型: $platform"
if [ "$platform" = "new" ]; then
local log_files=(
"/data/services/api/java-meeting/java-meeting2.0/log.out"
"/data/services/api/java-meeting/java-meeting-extapi/log.out"
"/data/services/api/python-cmdb/uinfo.log"
"/data/services/api/python-cmdb/uwsgi.log"
)
else
local log_files=(
"/var/www/java/api-java-meeting2.0/log.out"
"/var/www/java/external-meeting-api/log.out"
)
fi
local timestamp=$(date +"%Y%m%d_%H%M%S")
for log_file in "${log_files[@]}"; do
if [ -f "$log_file" ]; then
local size=$(stat -c%s "$log_file")
log_info "日志文件 $log_file 大小: $size 字节"
if [ "$size" -gt 104857600 ]; then # 100MB
if confirm_action "日志文件 $log_file 超过100MB,是否轮转?"; then
log_info "用户确认轮转日志文件: $log_file"
local backup_name="${log_file}.${timestamp}"
mv "$log_file" "$backup_name"
touch "$log_file"
log_info "已轮转日志文件: $log_file"
else
log_info "用户取消轮转日志文件: $log_file"
fi
else
log_info "日志文件大小正常: $log_file"
fi
else
log_warn "日志文件不存在: $log_file"
fi
done
log_info "轮转日志文件完成"
}
# 导出并压缩日志文件
export_and_compress_logs() {
local platform=$1
log_info "开始导出并压缩日志文件,平台类型: $platform"
local timestamp=$(date +"%Y%m%d_%H%M%S")
local temp_dir="/tmp/logs_export_${timestamp}"
mkdir -p "$temp_dir"
log_info "创建临时目录: $temp_dir"
if [ "$platform" = "new" ]; then
local log_dirs=(
"预定服务:/data/services/api/java-meeting/java-meeting2.0/logs"
"预定服务:/data/services/api/java-meeting/java-meeting-extapi/logs"
"运维服务:/data/services/api/python-cmdb/log"
)
else
local log_dirs=(
"预定服务:/data/services/api/java-meeting/java-meeting2.0/logs"
"预定服务:/data/services/api/java-meeting/java-meeting-extapi/logs"
"运维服务:/data/services/api/python-cmdb/log"
)
fi
# 复制日志目录
for item in "${log_dirs[@]}"; do
local service_type=${item%%:*}
local log_dir=${item#*:}
if [ -d "$log_dir" ]; then
local dest_dir="$temp_dir/$service_type/$(basename "$log_dir")"
mkdir -p "$(dirname "$dest_dir")"
cp -r "$log_dir" "$(dirname "$dest_dir")"
log_info "已导出日志目录: $log_dir"
else
log_warn "日志目录不存在: $log_dir"
fi
done
# 压缩日志
local zip_filename="logs_export_${timestamp}.zip"
if command -v zip >/dev/null 2>&1; then
(cd "$temp_dir" && zip -r "../$zip_filename" .)
log_info "日志导出并压缩完成: $zip_filename"
else
log_error "系统中未找到zip命令,请安装zip工具"
fi
# 清理临时目录
rm -rf "$temp_dir"
log_info "清理临时目录: $temp_dir"
log_info "导出并压缩日志文件完成"
}
# 修复对外后端服务异常掉线
fix_external_service_disconnect() {
local platform=$1
local work_dir=""
log_info "开始修复对外后端服务异常掉线,平台类型: $platform"
if [ "$platform" = "new" ]; then
work_dir="/data/services/api/java-meeting/java-meeting-extapi/"
else
work_dir="/var/www/java/external-meeting-api/"
fi
log_info "工作目录: $work_dir"
# 检查profile中是否包含source命令
local profile_path="/etc/profile"
local source_line="source /etc/profile"
if [ -f "$profile_path" ]; then
if ! grep -q "^$source_line$" "$profile_path"; then
if confirm_action "/etc/profile中未找到source命令,是否添加?"; then
log_info "用户确认添加source命令"
echo "$source_line" >> "$profile_path"
log_info "已在/etc/profile中添加source命令"
else
log_info "用户取消添加source命令"
fi
else
log_info "/etc/profile中已包含source命令"
fi
else
log_warn "配置文件不存在: $profile_path"
fi
# 启动服务
if confirm_action "是否启动对外后端服务 $work_dir?"; then
log_info "用户确认启动对外后端服务"
if [ -d "$work_dir" ]; then
(cd "$work_dir" && ./run.sh)
log_info "已启动对外后端服务: $work_dir"
else
log_error "工作目录不存在: $work_dir"
fi
else
log_info "用户取消启动对外后端服务"
fi
log_info "修复对外后端服务异常掉线完成"
}
# 修复ntp服务配置
fix_ntp_config() {
log_info "开始修复ntp服务配置"
local chrony_conf="/etc/chrony.conf"
local allow_all_line="allow all"
if [ -f "$chrony_conf" ]; then
if ! grep -q "^$allow_all_line$" "$chrony_conf"; then
if confirm_action "/etc/chrony.conf中未找到allow all配置,是否添加?"; then
log_info "用户确认添加allow all配置"
echo "$allow_all_line" >> "$chrony_conf"
log_info "已在/etc/chrony.conf中添加allow all"
else
log_info "用户取消添加allow all配置"
fi
else
log_info "/etc/chrony.conf中已包含allow all配置"
fi
if confirm_action "是否重启chronyd服务?"; then
log_info "用户确认重启chronyd服务"
if systemctl restart chronyd; then
log_info "已重启chronyd服务"
else
log_error "重启chronyd服务失败,请手动执行 systemctl restart chronyd"
fi
else
log_info "用户取消重启chronyd服务"
fi
else
log_warn "配置文件不存在: $chrony_conf"
fi
log_info "修复ntp服务配置完成"
}
# 修复端口开放问题
fix_port_access() {
local platform=$1
log_info "开始检查端口开放情况,平台类型: $platform"
if [ "$platform" = "new" ]; then
local required_ports=("443" "1883" "8883" "123/udp")
else
local required_ports=("443" "1883" "8443" "8081" "123/udp" "8883" "4443")
fi
log_info "平台 $platform 需要开放的端口: ${required_ports[*]}"
# 检查系统使用的防火墙类型
local firewall_type=""
if command -v firewall-cmd >/dev/null 2>&1; then
firewall_type="firewalld"
log_info "检测到 firewalld 防火墙"
elif command -v iptables >/dev/null 2>&1; then
firewall_type="iptables"
log_info "检测到 iptables 防火墙"
else
log_warn "未检测到支持的防火墙系统"
log_info "请手动检查并确保以上端口已正确开放"
return 1
fi
# 检查端口状态并询问是否需要开放
local ports_to_open=()
for port_proto in "${required_ports[@]}"; do
local port=${port_proto%/*}
local proto=${port_proto#*/}
if [ "$proto" = "$port" ]; then
proto="tcp"
fi
local is_open=false
case $firewall_type in
"firewalld")
if firewall-cmd --list-ports | grep -q "${port}/${proto}"; then
is_open=true
fi
;;
"iptables")
if iptables -L INPUT -nv | grep -q "dpt:${port}"; then
is_open=true
fi
;;
esac
if [ "$is_open" = true ]; then
log_info "端口 $port/$proto 已开放"
else
log_warn "端口 $port/$proto 未开放"
ports_to_open+=("$port/$proto")
fi
done
# 如果有需要开放的端口,询问用户是否开放
if [ ${#ports_to_open[@]} -gt 0 ]; then
log_info "需要开放的端口: ${ports_to_open[*]}"
if confirm_action "是否开放以上端口?"; then
log_info "用户确认开放端口"
for port_proto in "${ports_to_open[@]}"; do
local port=${port_proto%/*}
local proto=${port_proto#*/}
case $firewall_type in
"firewalld")
if firewall-cmd --permanent --add-port="$port_proto" 2>/dev/null; then
log_info "已添加端口 $port/$proto 到 firewalld 规则"
else
log_error "添加端口 $port/$proto 到 firewalld 规则失败"
fi
;;
"iptables")
if iptables -A INPUT -p "$proto" --dport "$port" -j ACCEPT 2>/dev/null; then
log_info "已添加端口 $port/$proto 到 iptables 规则"
else
log_error "添加端口 $port/$proto 到 iptables 规则失败"
fi
;;
esac
done
# 保存并重启防火墙规则
case $firewall_type in
"firewalld")
if firewall-cmd --reload 2>/dev/null; then
log_info "firewalld 规则已重载"
else
log_error "firewalld 规则重载失败"
fi
;;
"iptables")
if service iptables save 2>/dev/null; then
log_info "iptables 规则已保存"
else
log_warn "iptables 规则保存失败,尝试使用其他方法"
# 在某些系统上可能需要使用 netfilter-persistent
if command -v netfilter-persistent >/dev/null 2>&1; then
if netfilter-persistent save 2>/dev/null; then
log_info "iptables 规则已通过 netfilter-persistent 保存"
else
log_error "iptables 规则保存失败"
fi
fi
fi
;;
esac
log_info "端口开放完成"
else
log_info "用户取消开放端口"
fi
else
log_info "所有必需端口均已开放"
fi
log_info "端口开放检查完成"
}
# 修复服务器DNS异常问题
fix_dns_config() {
log_info "开始检查DNS配置"
local dns_servers=("114.114.114.114" "8.8.8.8")
local network_config_files=("/etc/resolv.conf")
for config_file in "${network_config_files[@]}"; do
if [ -f "$config_file" ]; then
local dns_configured=false
for dns in "${dns_servers[@]}"; do
if grep -q "nameserver $dns" "$config_file"; then
dns_configured=true
log_info "DNS服务器 $dns 已配置在 $config_file"
fi
done
if [ "$dns_configured" = false ]; then
log_warn "在 $config_file 中未找到推荐的DNS服务器配置"
log_info "建议添加以下DNS服务器之一:"
for dns in "${dns_servers[@]}"; do
log_info " nameserver $dns"
done
if confirm_action "是否添加推荐的DNS服务器配置?"; then
log_info "用户确认添加DNS服务器配置"
echo "nameserver ${dns_servers[0]}" >> "$config_file"
log_info "已添加DNS服务器: ${dns_servers[0]}"
else
log_info "用户取消添加DNS服务器配置"
fi
fi
else
log_warn "DNS配置文件不存在: $config_file"
fi
done
log_info "DNS配置检查完成"
}
# 打包备份现场环境数据
backup_environment_data() {
local platform=$1
log_info "开始打包备份现场环境数据,平台类型: $platform"
# 创建备份目录
local timestamp=$(date +"%Y%m%d_%H%M%S")
local backup_base_dir="$(dirname "$0")/env_backup_${timestamp}"
mkdir -p "$backup_base_dir"
log_info "创建备份基础目录: $backup_base_dir"
# 定义需要备份的通用文件和目录
local common_backup_items=(
"/etc/hosts"
"/etc/resolv.conf"
"/etc/fstab"
"/etc/passwd"
"/etc/group"
"/etc/ssh/sshd_config"
"/etc/sysctl.conf"
"/etc/security/limits.conf"
"/var/log"
"/proc/cpuinfo"
"/proc/meminfo"
"/proc/version"
)
# 根据平台类型定义特定的备份项
if [ "$platform" = "new" ]; then
log_info "备份新统一平台环境数据"
local platform_backup_items=(
"/data/services/api/java-meeting/java-meeting2.0/config"
"/data/services/api/java-meeting/java-meeting2.0/logs"
"/data/services/api/java-meeting/java-meeting-extapi/config"
"/data/services/api/java-meeting/java-meeting-extapi/logs"
"/data/services/api/python-cmdb/config"
"/data/services/api/python-cmdb/log"
"/data/middleware/redis/config"
"/usr/local/nginx/conf"
)
else
log_info "备份标准版平台环境数据"
local platform_backup_items=(
"/var/www/java/api-java-meeting2.0/config"
"/var/www/java/api-java-meeting2.0/logs"
"/var/www/java/external-meeting-api/config"
"/var/www/java/external-meeting-api/logs"
"/var/www/html/config"
"/var/www/html/log"
"/var/www/redis"
"/usr/local/nginx/conf"
)
fi
# 备份通用项
log_info "开始备份通用环境数据"
for item in "${common_backup_items[@]}"; do
if [ -e "$item" ]; then
local dest_path="$backup_base_dir$item"
mkdir -p "$(dirname "$dest_path")"
if [ -d "$item" ]; then
# 如果是目录,复制整个目录
cp -r "$item" "$(dirname "$dest_path")/" 2>/dev/null
log_info "已备份目录: $item"
elif [ -f "$item" ]; then
# 如果是文件,直接复制文件
cp "$item" "$dest_path" 2>/dev/null
log_info "已备份文件: $item"
fi
else
log_warn "通用备份项不存在: $item"
fi
done
# 备份平台特定项
log_info "开始备份平台特定环境数据"
for item in "${platform_backup_items[@]}"; do
if [ -e "$item" ]; then
local dest_path="$backup_base_dir$item"
mkdir -p "$(dirname "$dest_path")"
if [ -d "$item" ]; then
# 如果是目录,复制整个目录
cp -r "$item" "$(dirname "$dest_path")/" 2>/dev/null
log_info "已备份目录: $item"
elif [ -f "$item" ]; then
# 如果是文件,直接复制文件
cp "$item" "$dest_path" 2>/dev/null
log_info "已备份文件: $item"
fi
else
log_warn "平台特定备份项不存在: $item"
fi
done
# 创建系统信息文件
log_info "收集系统信息"
local sysinfo_file="$backup_base_dir/system_info.txt"
{
echo "=== 系统信息收集报告 ==="
echo "收集时间: $(date)"
echo "平台类型: $platform"
echo ""
echo "=== 主机信息 ==="
hostnamectl 2>/dev/null || echo "无法获取hostnamectl信息"
echo ""
echo "=== 网络配置 ==="
ip addr show 2>/dev/null || echo "无法获取IP地址信息"
echo ""
echo "=== 磁盘使用情况 ==="
df -h 2>/dev/null || echo "无法获取磁盘使用情况"
echo ""
echo "=== 内存使用情况 ==="
free -h 2>/dev/null || echo "无法获取内存使用情况"
echo ""
echo "=== 进程信息 ==="
ps aux 2>/dev/null | head -50 || echo "无法获取进程信息"
echo ""
echo "=== Docker容器信息 ==="
docker ps -a 2>/dev/null || echo "无法获取Docker容器信息"
echo ""
echo "=== 服务状态 ==="
systemctl list-units --type=service --state=running 2>/dev/null || echo "无法获取服务状态"
} > "$sysinfo_file"
log_info "系统信息已保存到: $sysinfo_file"
# 打包备份目录
log_info "开始打包备份数据"
local backup_archive="$(dirname "$0")/env_backup_${timestamp}.tar.gz"
tar -czf "$backup_archive" -C "$(dirname "$backup_base_dir")" "$(basename "$backup_base_dir")" 2>/dev/null
if [ $? -eq 0 ]; then
log_info "环境数据备份完成,备份文件: $backup_archive"
# 清理临时目录
rm -rf "$backup_base_dir"
log_info "已清理临时目录: $backup_base_dir"
else
log_error "环境数据打包失败"
fi
log_info "打包备份现场环境数据完成"
}
# 显示菜单
show_menu() {
clear
echo "==========================================="
echo " 常见问题处理工具"
echo "==========================================="
echo "1. 更新版本包"
echo " 1.1 更新预定系统对内后端包"
echo " 1.2 更新预定系统对外后端包"
echo " 1.3 更新预定系统前台包"
echo " 1.4 更新预定系统后台包"
echo " 1.5 更新运维后端包"
echo " 1.6 更新运维前端包"
echo "2. 修复文件权限问题"
echo " 2.1 修复普通文件权限"
echo " 2.2 修复数据库用户权限"
echo " 2.3 修复nginx用户权限"
echo "3. 修复配置文件IP不对问题"
echo "4. 修复系统磁盘问题"
echo " 4.1 清理已删除文件"
echo " 4.2 轮转日志文件"
echo "5. 导出现场日志文件并压缩"
echo "6. 修复对外后端服务异常掉线"
echo "7. 修复ntp服务配置或启动问题"
echo "8. 修复端口开放问题"
echo "9. 修复服务器DNS异常问题"
echo "10. 打包备份现场环境数据"
echo "0. 退出"
echo "==========================================="
}
# 交互式模式
interactive_mode() {
local platform=$(detect_platform)
if [ "$platform" = "unknown" ]; then
log_error "无法检测到有效的平台类型"
echo -n "请手动指定平台类型 (new/standard): "
read platform
if [ "$platform" != "new" ] && [ "$platform" != "standard" ]; then
log_error "无效的平台类型,退出程序"
exit 1
fi
else
log_info "检测到平台类型: $([ "$platform" = "new" ] && echo "新统一平台" || echo "标准版平台")"
fi
while true; do
show_menu
echo -n "请选择操作 [0-9]: "
read choice
log_info "用户选择: $choice"
case $choice in
0)
log_info "用户选择退出程序"
log_info "退出程序"
exit 0
;;
1)
echo -n "请选择子操作 [1.1-1.6, 或按回车全选]: "
read sub_choice
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
1.1)
log_info "执行更新预定系统对内后端包"
update_inner_backend_jar "$platform"
;;
1.2)
log_info "执行更新预定系统对外后端包"
update_external_backend_jar "$platform"
;;
1.3)
log_info "执行更新预定系统前台包"
update_frontend "$platform"
;;
1.4)
log_info "执行更新预定系统后台包"
update_backend "$platform"
;;
1.5)
log_info "执行更新运维后端包"
update_ops_backend "$platform"
;;
1.6)
log_info "执行更新运维前端包"
update_ops_frontend "$platform"
;;
"")
log_info "执行更新所有包"
update_inner_backend_jar "$platform"
update_external_backend_jar "$platform"
update_frontend "$platform"
update_backend "$platform"
update_ops_backend "$platform"
update_ops_frontend "$platform"
;;
*)
log_error "无效的选择: $sub_choice"
;;
esac
;;
2)
echo -n "请选择子操作 [2.1-2.3, 或按回车全选]: "
read sub_choice
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
2.1)
log_info "执行修复普通文件权限"
fix_permissions "$platform"
;;
2.2)
log_info "执行修复数据库用户权限"
fix_db_permissions
;;
2.3)
log_info "执行修复nginx用户权限"
fix_nginx_user
;;
"")
log_info "执行修复所有权限问题"
fix_permissions "$platform"
fix_db_permissions
fix_nginx_user
;;
*)
log_error "无效的选择: $sub_choice"
;;
esac
;;
3)
log_info "执行修复配置文件IP不对问题"
fix_ip_configurations "$platform"
;;
4)
echo -n "请选择子操作 [4.1-4.2]: "
read sub_choice
log_info "用户选择子操作: $sub_choice"
case $sub_choice in
4.1)
log_info "执行清理已删除文件"
clean_deleted_files
;;
4.2)
log_info "执行轮转日志文件"
rotate_logs "$platform"
;;
"")
log_info "执行清理已删除文件和轮转日志文件"
clean_deleted_files
rotate_logs "$platform"
;;
*)
log_error "无效的选择: $sub_choice"
;;
esac
;;
5)
log_info "执行导出现场日志文件并压缩"
export_and_compress_logs "$platform"
;;
6)
log_info "执行修复对外后端服务异常掉线"
fix_external_service_disconnect "$platform"
;;
7)
log_info "执行修复ntp服务配置或启动问题"
fix_ntp_config
;;
8)
log_info "执行修复端口开放问题"
fix_port_access "$platform"
;;
9)
log_info "执行修复服务器DNS异常问题"
fix_dns_config
;;
10)
log_info "执行打包备份现场环境数据"
backup_environment_data "$platform"
;;
*)
log_error "无效的选择: $choice"
;;
esac
echo
echo "按回车键继续..."
read
done
}
# 主函数
main() {
# 记录脚本启动日志
log_info "脚本开始执行,参数: $*"
# 检查是否以root权限运行
if [ "$EUID" -ne 0 ]; then
log_warn "建议以root权限运行此脚本以确保所有操作都能正常执行"
fi
# 如果提供了命令行参数,则使用命令行模式
if [ $# -gt 0 ]; then
local platform=$(detect_platform)
if [ "$platform" = "unknown" ]; then
log_error "无法检测到有效的平台类型"
exit 1
fi
log_info "检测到平台类型: $platform"
case $1 in
--action)
case $2 in
update_packages)
log_info "执行操作: update_packages"
update_inner_backend_jar "$platform"
update_external_backend_jar "$platform"
update_frontend "$platform"
update_backend "$platform"
update_ops_backend "$platform"
update_ops_frontend "$platform"
;;
fix_permissions)
log_info "执行操作: fix_permissions"
fix_permissions "$platform"
;;
fix_ip_configs)
log_info "执行操作: fix_ip_configs"
fix_ip_configurations "$platform"
;;
clean_deleted_files)
log_info "执行操作: clean_deleted_files"
clean_deleted_files
;;
clean_deleted_files_cron)
log_info "执行操作: clean_deleted_files_cron"
clean_deleted_files_cron
;;
rotate_logs)
log_info "执行操作: rotate_logs"
rotate_logs "$platform"
;;
export_logs)
log_info "执行操作: export_logs"
export_and_compress_logs "$platform"
;;
fix_external_service)
log_info "执行操作: fix_external_service"
fix_external_service_disconnect "$platform"
;;
fix_ntp)
log_info "执行操作: fix_ntp"
fix_ntp_config
;;
fix_ports)
log_info "执行操作: fix_ports"
fix_port_access "$platform"
;;
fix_dns)
log_info "执行操作: fix_dns"
fix_dns_config
;;
*)
log_error "未知操作: $2"
exit 1
;;
esac
;;
*)
log_error "未知参数: $1"
exit 1
;;
esac
else
# 否则进入交互式模式
log_info "进入交互式模式"
interactive_mode
fi
log_info "脚本执行完毕"
}
# 脚本入口
main "$@"
\ No newline at end of file
# 常见问题处理脚本操作说明文档
## 概述
本文档旨在指导用户如何使用 [issue_handler.sh]脚本来处理Linux服务器上的常见问题。该脚本支持交互式操作和命令行参数两种使用方式,可以帮助用户快速解决诸如版本包更新、权限修复、配置文件修改等常见问题。
## 脚本功能
该脚本提供以下主要功能:
1. **更新版本包**:支持更新对内后端、对外后端、前台、后台、运维后端和运维前端等版本包
2. **修复文件权限问题**:自动修复常见文件权限问题,包括数据库用户权限、nginx用户权限等
3. **修复配置文件IP地址问题**:批量替换配置文件中的IP地址
4. **系统磁盘问题处理**:清理已删除但未释放的文件、轮转大日志文件
5. **日志导出与压缩**:导出系统日志并压缩为zip文件
6. **服务异常处理**:修复对外后端服务异常掉线问题
7. **NTP服务配置**:修复NTP服务配置或启动问题
8. **端口开放检查**:检查必要端口是否开放
9. **DNS异常修复**:修复服务器DNS配置异常问题
10. **环境数据备份**:打包备份系统环境数据
11. **定时清理任务**:支持通过cron定时清理已删除但未释放的文件
## 系统要求
- Linux操作系统(支持大多数主流发行版)
- Bash shell环境
- root或sudo权限(建议以root权限运行以确保所有操作都能正常执行)
## 脚本安装与准备
1. 确保脚本具有执行权限:
```bash
chmod +x issue_handler.sh
```
2. (可选)将脚本放置在系统PATH路径中,方便全局调用:
```bash
sudo cp issue_handler.sh /usr/local/bin/
```
## 使用方式
### 1. 交互式模式(推荐)
直接运行脚本进入交互式模式:
```bash
sudo ./issue_handler.sh
```
在交互式模式下,用户将看到如下菜单:
```
===========================================
常见问题处理工具
===========================================
1. 更新版本包
1.1 更新预定系统对内后端包
1.2 更新预定系统对外后端包
1.3 更新预定系统前台包
1.4 更新预定系统后台包
1.5 更新运维后端包
1.6 更新运维前端包
2. 修复文件权限问题
2.1 修复普通文件权限
2.2 修复数据库用户权限
2.3 修复nginx用户权限
3. 修复配置文件IP不对问题
4. 修复系统磁盘问题
4.1 清理已删除文件
4.2 轮转日志文件
5. 导出现场日志文件并压缩
6. 修复对外后端服务异常掉线
7. 修复ntp服务配置或启动问题
8. 修复端口开放问题
9. 修复服务器DNS异常问题
10. 打包备份现场环境数据
0. 退出
===========================================
```
按照屏幕提示输入对应数字选择功能即可。
### 2. 命令行模式
脚本也支持通过命令行参数直接执行特定功能:
```bash
sudo ./issue_handler.sh --action <action_name>
```
可用的 `<action_name>` 包括:
- `update_packages`:更新所有版本包
- `fix_permissions`:修复文件权限
- `fix_ip_configs`:修复IP配置
- `clean_deleted_files`:清理已删除文件
- `clean_deleted_files_cron`:定时任务版本的清理已删除文件(无交互)
- `rotate_logs`:轮转日志文件
- `export_logs`:导出日志文件
- `fix_external_service`:修复对外服务异常
- `fix_ntp`:修复NTP配置
- `fix_ports`:检查端口开放情况
- `fix_dns`:修复DNS配置
例如,要修复文件权限问题,可以执行:
```bash
sudo ./issue_handler.sh --action fix_permissions
```
要执行定时清理任务(无交互),可以执行:
```bash
sudo ./issue_handler.sh --action clean_deleted_files_cron
```
## 详细功能说明
### 更新版本包
#### 工作原理
脚本会优先检查脚本所在目录是否存在对应的更新包目录,如果存在则直接使用,否则提示用户输入更新包路径。
#### 操作步骤
1. 运行脚本并选择更新版本包相关选项
2. 脚本会自动检测更新包位置:
- 首先检查脚本所在目录是否存在同名更新包目录
- 如果不存在,提示用户输入更新包所在目录
3. 用户确认后,脚本会:
- 备份原文件/目录内容
- 执行更新操作
- 提供操作结果反馈
#### 注意事项
- 更新包目录应包含需要更新的完整文件结构
- 脚本会自动备份原文件/目录内容,备份文件名带有时间戳
- 如更新失败,脚本会尝试恢复备份文件
- 对于目录类型的更新(如前端、后台包),脚本会:
1. 在目标目录下创建一个备份目录,将index.html和static等文件移进到备份目录
2. 将更新包中的文件复制到目标目录下
### 修复文件权限问题
#### 功能说明
自动修复系统中常见的文件权限问题,包括:
- 启动脚本权限(通常设置为755)
- 配置文件权限(通常设置为644)
- 数据库和nginx相关权限
#### 操作步骤
1. 选择对应的权限修复选项
2. 脚本会自动检测平台类型(新统一平台或标准版平台)
3. 根据平台类型修复对应的文件权限
### 修复配置文件IP地址问题
#### 功能说明
批量替换系统配置文件中的IP地址。
#### 操作步骤
1. 选择"修复配置文件IP不对问题"选项
2. 输入需要替换的旧IP地址
3. 输入新的IP地址
4. 脚本会自动查找并替换所有相关配置文件中的IP地址
### 系统磁盘问题处理
#### 功能说明
包括两个子功能:
1. 清理已删除但未释放的文件
2. 轮转过大的日志文件
#### 操作步骤
1. 选择对应的功能选项
2. 根据提示进行确认操作
3. 脚本会自动执行相关处理
### 日志导出与压缩
#### 功能说明
导出系统中的重要日志文件并压缩为zip文件,便于传输和分析。
#### 操作步骤
1. 选择"导出现场日志文件并压缩"选项
2. 脚本会自动收集日志并生成带时间戳的zip文件
### 服务异常处理
#### 功能说明
修复对外后端服务异常掉线问题。
#### 操作步骤
1. 选择对应选项
2. 根据提示确认是否添加必要的配置项
3. 确认是否启动服务
### NTP服务配置
#### 功能说明
修复NTP服务配置或启动问题。
#### 操作步骤
1. 选择对应选项
2. 根据提示确认是否添加必要的配置项
3. 确认是否重启NTP服务
### 端口开放检查
#### 功能说明
检查系统必要端口是否开放。
#### 操作步骤
1. 选择对应选项
2. 脚本会显示需要开放的端口列表
3. 用户需手动检查并确保端口已正确开放
### DNS异常修复
#### 功能说明
修复服务器DNS配置异常问题。
#### 操作步骤
1. 选择对应选项
2. 脚本会检查DNS配置文件
3. 如未配置推荐的DNS服务器,会提示用户添加
### 环境数据备份
#### 功能说明
打包备份系统环境数据,包括配置文件、日志文件和系统信息。
#### 操作步骤
1. 选择"打包备份现场环境数据"选项(菜单选项10)
2. 脚本会自动检测平台类型
3. 根据平台类型备份相应的配置文件、日志文件和系统信息
4. 生成包含时间戳的tar.gz压缩包
### 定时清理任务
#### 功能说明
支持通过cron定时清理已删除但未释放的文件,适用于自动化运维场景。
#### 操作步骤
1. 通过命令行模式执行:
```bash
sudo ./issue_handler.sh --action clean_deleted_files_cron
```
2. 脚本会自动检测并清理已删除但未释放的文件
3. 无交互过程,适合定时任务执行
## 安全机制
脚本内置多种安全机制确保操作安全:
1. **权限检查**:运行时会提示建议使用root权限
2. **文件备份**:关键文件操作前会自动创建备份
3. **操作确认**:高风险操作前会询问用户确认
4. **错误恢复**:操作失败时会尝试恢复到之前状态
5. **路径验证**:执行操作前会验证目标路径的有效性
6. **日志记录**:所有操作都会记录到日志文件中,便于审计和问题排查
## 故障排除
### 常见问题
1. **脚本无执行权限**
```
chmod +x issue_handler.sh
```
2. **操作被拒绝**
确保以root权限运行脚本
3. **找不到lsof或zip命令**
安装相应的工具包:
```bash
# CentOS/RHEL/Fedora
yum install lsof zip
# Ubuntu/Debian
apt-get install lsof zip
```
### 日志查看
脚本执行过程中会输出详细的操作日志,包括:
- [INFO]:一般信息
- [WARN]:警告信息
- [ERROR]:错误信息
- [DEBUG]:调试信息
日志文件位于脚本同级目录,文件名为`issue_handler.log`。
## 最佳实践
1. **首次使用建议**:建议首次使用时采用交互式模式,熟悉各项功能
2. **定期执行**:可以将常用功能加入定时任务,定期自动执行
3. **备份重要数据**:虽然脚本会自动备份,但仍建议重要操作前手动备份关键数据
4. **关注日志输出**:仔细查看脚本执行过程中的日志信息,及时发现问题
5. **定时清理任务**:可以将`clean_deleted_files_cron`功能加入crontab,实现定时清理:
```bash
# 每天凌晨3点执行清理已删除但未释放的文件
0 3 * * * /bin/bash {脚本所在目录}/issue_handler.sh --action clean_deleted_files_cron
```
## 联系支持
如在使用过程中遇到问题,请联系技术支持团队。
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论