mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-03-15 23:46:51 +08:00
Compare commits
17 Commits
v250316
...
onecloud-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6002dfd9c7 | ||
|
|
cf6addeb0f | ||
|
|
8560a46f17 | ||
|
|
d4b4cdc492 | ||
|
|
687cea3658 | ||
|
|
12c7566581 | ||
|
|
10fb78abe6 | ||
|
|
1642ce73a0 | ||
|
|
64c83be0a4 | ||
|
|
76ca81bbfd | ||
|
|
ed7b2e5b33 | ||
|
|
a92a6f2811 | ||
|
|
3d58f6dd21 | ||
|
|
50022e7353 | ||
|
|
ff4f04d936 | ||
|
|
413fce72ec | ||
|
|
842238009e |
36
.github/ISSUE_TEMPLATE/bug-反馈.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug-反馈.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: BUG 反馈
|
||||
about: 反馈你所遇到的软件 BUG 或其他错误
|
||||
title: "[BUG]"
|
||||
labels: BUG
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### **Bug 反馈**
|
||||
|
||||
**问题描述**
|
||||
请清晰描述您遇到的问题。例如:软件无法启动、特定功能报错或表现异常等。
|
||||
|
||||
**复现步骤**
|
||||
请提供可复现此问题的详细步骤:
|
||||
1. 前往 '...'
|
||||
2. 点击 '....'
|
||||
3. 滚动到 '....'
|
||||
4. 发现错误
|
||||
|
||||
**日志信息**
|
||||
如果程序崩溃或报错,请在此处粘贴相关的日志。
|
||||
- **整合包镜像**: `systemctl status kvmd` 或 `journalctl -xeu kvmd`
|
||||
- **Docker 镜像**: `docker logs kvmd`
|
||||
|
||||
**系统环境**
|
||||
- **运行方式**: (例如:整合包镜像 / Docker)
|
||||
- **镜像版本**: (Docker 镜像请提供版本号)
|
||||
- **操作系统**: (例如:Debian 12)
|
||||
|
||||
**尝试过的解决方法**
|
||||
请简要描述您为解决此问题已尝试过的方法及其结果。如果未尝试,可留空。
|
||||
|
||||
**补充信息**
|
||||
可以附加截图、录屏或其他有助于理解问题的信息。
|
||||
25
.github/ISSUE_TEMPLATE/功能请求与设备适配.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/功能请求与设备适配.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: 功能请求与设备适配
|
||||
about: 请求新的功能或适配新的平台
|
||||
title: "[功能/适配]"
|
||||
labels: 特性
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**功能描述**
|
||||
请详细描述您期望的新功能应该是什么样子。
|
||||
- **对于新功能**:它应该如何工作?有哪些关键特性?
|
||||
- **对于新平台适配**:请提供该平台的具体信息(如设备型号、系统版本、相关链接等)。
|
||||
|
||||
**期望的效果**
|
||||
当该功能实现或平台适配完成后,您期望达到怎样的理想效果?可以像下面这样列出关键点:
|
||||
- [ ] 用户可以...
|
||||
- [ ] 系统能够...
|
||||
- [ ] 解决了之前的...问题
|
||||
|
||||
**我能提供的帮助**
|
||||
为了让这个想法更快成为现实,您可以提供哪些帮助?没有则填写无。
|
||||
- [ ] 我可以参与后续的功能测试
|
||||
- [ ] 我可以提供(临时的)远程调试环境(如 SSH、远程桌面)
|
||||
- [ ] 其他:...
|
||||
23
.github/workflows/arduino-hid.yml
vendored
23
.github/workflows/arduino-hid.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: Arduino HID CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: python
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare platformio
|
||||
run: pip install platformio
|
||||
|
||||
- name: Build all
|
||||
run: make -C hid/arduino _build_all
|
||||
74
.github/workflows/build_img.yaml
vendored
Normal file
74
.github/workflows/build_img.yaml
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
name: Build One-KVM Image
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
device_target:
|
||||
description: 'Target device name'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- onecloud
|
||||
- cumebox2
|
||||
- chainedbox
|
||||
- vm
|
||||
- e900v22c
|
||||
- octopus-flanet
|
||||
- all
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
container:
|
||||
image: node:18
|
||||
options: --user root --privileged
|
||||
env:
|
||||
TZ: Asia/Shanghai
|
||||
volumes:
|
||||
- /dev:/dev
|
||||
- /mnt/nfs/lfs/:/mnt/nfs/lfs/
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get install -y --no-install-recommends \
|
||||
sudo tzdata docker.io qemu-utils qemu-user-static binfmt-support parted e2fsprogs \
|
||||
curl tar python3 python3-pip rsync git android-sdk-libsparse-utils coreutils zerofree
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime
|
||||
echo $TZ > /etc/timezone
|
||||
update-binfmts --enable
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
|
||||
- name: Build image
|
||||
run: |
|
||||
echo "BUILD_DATE=$(date +%y%m%d)" >> $GITHUB_ENV
|
||||
|
||||
chmod +x build/build_img.sh
|
||||
|
||||
echo "Starting build for target: ${{ github.event.inputs.device_target }}"
|
||||
bash build/build_img.sh ${{ github.event.inputs.device_target }}
|
||||
|
||||
echo "Build script finished."
|
||||
env:
|
||||
CI_PROJECT_DIR: ${{ github.workspace }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: onekvm-image-${{ github.event.inputs.device_target }}-${{ env.BUILD_DATE }}
|
||||
path: |
|
||||
${{ github.workspace }}/output/*.img
|
||||
${{ github.workspace }}/output/*.vmdk
|
||||
${{ github.workspace }}/output/*.vdi
|
||||
${{ github.workspace }}/output/*.burn.img
|
||||
if-no-files-found: ignore
|
||||
env:
|
||||
CI_PROJECT_DIR: ${{ github.workspace }}
|
||||
83
.github/workflows/docker-build.yaml
vendored
Normal file
83
.github/workflows/docker-build.yaml
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- dev
|
||||
- latest
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
container:
|
||||
image: node:18
|
||||
env:
|
||||
TZ: Asia/Shanghai
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get install -y --no-install-recommends \
|
||||
sudo tzdata docker.io qemu-utils qemu-user-static binfmt-support parted e2fsprogs \
|
||||
curl tar python3 python3-pip rsync git android-sdk-libsparse-utils coreutils zerofree
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime
|
||||
echo $TZ > /etc/timezone
|
||||
update-binfmts --enable
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
|
||||
- name: Install Docker Buildx
|
||||
run: |
|
||||
# 创建插件目录
|
||||
mkdir -p ~/.docker/cli-plugins
|
||||
# 下载 buildx 二进制文件
|
||||
BUILDX_VERSION="v0.11.2"
|
||||
curl -L "https://github.com/docker/buildx/releases/download/${BUILDX_VERSION}/buildx-${BUILDX_VERSION}.linux-amd64" -o ~/.docker/cli-plugins/docker-buildx
|
||||
chmod +x ~/.docker/cli-plugins/docker-buildx
|
||||
# 验证安装
|
||||
docker buildx version
|
||||
|
||||
#- name: Install QEMU
|
||||
# run: |
|
||||
# 安装 QEMU 模拟器
|
||||
#docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
# 验证 QEMU 安装
|
||||
#docker buildx inspect --bootstrap
|
||||
|
||||
- name: Create and use new builder instance
|
||||
run: |
|
||||
# 创建新的 builder 实例
|
||||
docker buildx create --name mybuilder --driver docker-container --bootstrap
|
||||
# 使用新创建的 builder
|
||||
docker buildx use mybuilder
|
||||
# 验证支持的平台
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
- name: Build multi-arch image
|
||||
run: |
|
||||
# 构建多架构镜像
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64,linux/arm/v7 \
|
||||
--file ./build/Dockerfile \
|
||||
--tag silentwind/kvmd:${{ github.event.inputs.version }} \
|
||||
.
|
||||
|
||||
#- name: Login to DockerHub
|
||||
# uses: docker/login-action@v2
|
||||
# with:
|
||||
# username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
# password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
|
||||
41
.github/workflows/pico-hid-release.yml
vendored
41
.github/workflows/pico-hid-release.yml
vendored
@@ -1,41 +0,0 @@
|
||||
name: Pico HID Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Installing deps ...
|
||||
run: sudo apt-get install cmake gcc-arm-none-eabi build-essential
|
||||
|
||||
- name: Building ...
|
||||
run: make -C hid/pico all
|
||||
|
||||
- name: Releasing ...
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Uploading firmware ...
|
||||
id: upload-release-asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./hid/pico/hid.uf2
|
||||
asset_name: pico-hid.uf2
|
||||
asset_content_type: application/octet-stream
|
||||
20
.github/workflows/pico-hid.yml
vendored
20
.github/workflows/pico-hid.yml
vendored
@@ -1,20 +0,0 @@
|
||||
name: Pico HID CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Installing deps ...
|
||||
run: sudo apt-get install cmake gcc-arm-none-eabi build-essential
|
||||
|
||||
- name: Running tests ...
|
||||
run: make -C hid/pico all
|
||||
20
.github/workflows/tox.yml
vendored
20
.github/workflows/tox.yml
vendored
@@ -1,20 +0,0 @@
|
||||
name: TOX CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Building testenv ...
|
||||
run: make testenv
|
||||
|
||||
- name: Running tests ...
|
||||
run: make tox CMD="tox -c testenv/tox.ini"
|
||||
279
README.md
279
README.md
@@ -1,61 +1,97 @@
|
||||
<h3 align=center><img src="https://github.com/mofeng-git/Build-Armbian/assets/62919083/add9743a-0987-4e8a-b2cb-62121f236582" alt="logo" width="300"><br></h3>
|
||||
<h3 align=center><a href="https://github.com/mofeng-git/One-KVM/blob/master/README.md">简体中文</a> </h3>
|
||||
<p align=right> </p>
|
||||
<div align="center">
|
||||
<img src="https://github.com/mofeng-git/Build-Armbian/assets/62919083/add9743a-0987-4e8a-b2cb-62121f236582" alt="One-KVM Logo" width="300">
|
||||
<h1>One-KVM</h1>
|
||||
<p><strong>基于 PiKVM 的 DIY IP-KVM 解决方案</strong></p>
|
||||
|
||||
[](https://github.com/mofeng-git/One-KVM/stargazers)
|
||||
[](https://github.com/mofeng-git/One-KVM/network/members)
|
||||
[](https://github.com/mofeng-git/One-KVM/issues)
|
||||
[](https://github.com/mofeng-git/One-KVM/blob/master/LICENSE)
|
||||
|
||||
<p>
|
||||
<a href="https://one-kvm.mofeng.run">📖 详细文档</a> •
|
||||
<a href="https://kvmd-demo.mofeng.run">🚀 在线演示</a> •
|
||||
<a href="#快速开始">⚡ 快速开始</a> •
|
||||
<a href="#功能介绍">📊 功能介绍</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
### 介绍
|
||||
---
|
||||
|
||||
One-KVM 是基于廉价计算机硬件和 [PiKVM]((https://github.com/pikvm/pikvm)) 软件二次开发的 BIOS 级远程控制项目。可以实现远程管理服务器或工作站,无需在被控机安装软件调整设置,实现无侵入式控制,适用范围广泛。
|
||||
## 📋 目录
|
||||
|
||||
使用文档:[https://one-kvm.mofeng.run](https://one-kvm.mofeng.run)
|
||||
- [项目概述](#项目概述)
|
||||
- [功能介绍](#功能介绍)
|
||||
- [快速开始](#快速开始)
|
||||
- [贡献指南](#贡献指南)
|
||||
- [其他](#其他)
|
||||
|
||||
演示网站:[https://kvmd-demo.mofeng.run](https://kvmd-demo.mofeng.run)
|
||||
## 📖 项目概述
|
||||
|
||||

|
||||
**One-KVM** 是基于开源 [PiKVM](https://github.com/pikvm/pikvm) 项目进行二次开发的 DIY IP-KVM 解决方案。该方案利用成本较低的硬件设备,实现 BIOS 级别的远程服务器或工作站管理功能。
|
||||
|
||||
### 软件功能
|
||||
### 应用场景
|
||||
|
||||
表格仅为 One-KVM 与其他基于 PiKVM 的项目的功能对比,无不良导向,如有错漏请联系更正。
|
||||
- **家庭实验室主机管理** - 远程管理服务器和开发设备
|
||||
- **服务器远程维护** - 无需物理接触即可进行系统维护
|
||||
- **系统故障处理** - 远程解决系统启动和 BIOS 相关问题
|
||||
|
||||
| 功能 | One-KVM | PiKVM | ArmKVM | BLIKVM |
|
||||
| :-------------------: | :-------------: | :-----------------------: | :---------: | :---------: |
|
||||
| 系统开源 | √ | √ | √ | √ |
|
||||
| 简体中文 WebUI | √ | x | √ | √ |
|
||||
| 远程视频流 | MJPEG/H.264 | MJPEG/H.264 | MJPEG/H.264 | MJPEG/H.264 |
|
||||
| H.264 视频编码 | CPU | GPU | 未知 | GPU |
|
||||
| 远程音频流 | √ | √ | √ | √ |
|
||||
| 远程鼠键控制 | OTG/CH9329 | OTG/CH9329/Pico/Bluetooth | OTG | OTG |
|
||||
| VNC 控制 | √ | √ | √ | √ |
|
||||
| ATX 电源控制 | GPIO/USB 继电器 | GPIO | GPIO | GPIO |
|
||||
| 虚拟存储驱动器挂载 | √ | √ | √ | √ |
|
||||
| 2.2G 以上 CD-ROM 挂载 | x | x | √ | √ |
|
||||
| WOL 远程唤醒 | √ | √ | √ | √ |
|
||||
| 网页剪切板 | √ | √ | √ | √ |
|
||||
| OCR 文字识别 | √ | √ | √ | √ |
|
||||
| 网页终端 | √ | √ | √ | √ |
|
||||
| 网络串口终端 | x | x | √ | √ |
|
||||
| HDMI 切换器支持 | √ | √ | √ | √ |
|
||||
| 视频录制 | √ | x | x | x |
|
||||
| Docker 部署 | √ | x | x | x |
|
||||
| 官方商业化成品 | x | √ | √ | √ |
|
||||
| 技术支持 | √ | √ | √ | √ |
|
||||

|
||||
|
||||
### 快速开始
|
||||
## 📊 功能介绍
|
||||
|
||||
更多详细内容可以查阅 [One-KVM文档](https://one-kvm.mofeng.run/)。
|
||||
### 核心特性
|
||||
|
||||
**方式一:Docker 镜像部署(推荐)**
|
||||
| 特性 | 描述 | 优势 |
|
||||
|------|------|------|
|
||||
| **无侵入性** | 无需在目标机器上安装软件或驱动 | 不依赖操作系统,可访问 BIOS/UEFI 设置 |
|
||||
| **成本效益** | 利用常见硬件设备(如电视盒子、开发板等) | 降低 KVM over IP 的实现成本 |
|
||||
| **功能扩展** | 在 PiKVM 基础上增加实用功能 | Docker 部署、视频录制、中文界面 |
|
||||
| **部署方式** | 支持 Docker 部署和硬件整合包 | 为特定硬件平台提供预配置方案 |
|
||||
|
||||
Docker 版本可以使用 OTG 或 CH9329 作为虚拟 HID ,支持 amd64、arm64、armv7 架构的 Linux 系统安装。
|
||||
### 项目限制
|
||||
|
||||
**脚本部署**
|
||||
本项目为个人维护的开源项目,资源有限,无商业运营计划
|
||||
|
||||
- 不提供内置免费内网穿透服务,相关问题请自行解决
|
||||
- 不提供24×7小时技术支持服务
|
||||
- 不承诺系统稳定性和合规性,使用风险需自行承担
|
||||
- 尽力优化用户体验,但仍需要一定的技术基础
|
||||
|
||||
### 功能对比
|
||||
|
||||
> 💡 **说明:** 以下表格展示了 One-KVM 与其他基于 PiKVM 项目的功能对比,仅供参考。如有遗漏或错误,欢迎联系更正。
|
||||
|
||||
| 功能特性 | One-KVM | PiKVM | ArmKVM | BLIKVM |
|
||||
|:--------:|:-------:|:-----:|:------:|:------:|
|
||||
| 简体中文 WebUI | ✅ | ❌ | ✅ | ✅ |
|
||||
| 远程视频流 | MJPEG/H.264 | MJPEG/H.264 | MJPEG/H.264 | MJPEG/H.264 |
|
||||
| H.264 视频编码 | CPU | GPU | 未知 | GPU |
|
||||
| 远程音频流 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 远程鼠键控制 | OTG/CH9329 | OTG/CH9329/Pico/Bluetooth | OTG | OTG |
|
||||
| VNC 控制 | ✅ | ✅ | ✅ | ✅ |
|
||||
| ATX 电源控制 | GPIO/USB 继电器 | GPIO | GPIO | GPIO |
|
||||
| 虚拟存储驱动器挂载 | ✅ | ✅ | ✅ | ✅ |
|
||||
| 网页终端 | ✅ | ✅ | ✅ | ✅ |
|
||||
| Docker 部署 | ✅ | ❌ | ❌ | ❌ |
|
||||
| 商业化运营 | ❌ | ✅ | ✅ | ✅ |
|
||||
|
||||
## ⚡ 快速开始
|
||||
|
||||
### 方式一:Docker 镜像部署(推荐)
|
||||
|
||||
Docker 版本支持 OTG 或 CH9329 作为虚拟 HID,兼容 amd64、arm64、armv7 架构的 Linux 系统。
|
||||
|
||||
#### 一键脚本部署
|
||||
|
||||
```bash
|
||||
curl -sSL https://one-kvm.mofeng.run/quick_start.sh -o quick_start.sh && bash quick_start.sh
|
||||
```
|
||||
|
||||
**手动部署**
|
||||
#### 手动部署
|
||||
|
||||
**使用 OTG 作为虚拟 HID:**
|
||||
|
||||
如果使用 OTG 作为虚拟 HID,可以使用如下部署命令:
|
||||
```bash
|
||||
sudo docker run --name kvmd -itd --privileged=true \
|
||||
-v /lib/modules:/lib/modules:ro -v /dev:/dev \
|
||||
@@ -64,7 +100,8 @@ sudo docker run --name kvmd -itd --privileged=true \
|
||||
silentwind0/kvmd
|
||||
```
|
||||
|
||||
如果使用 CH9329 作为虚拟 HID,可以使用如下部署命令:
|
||||
**使用 CH9329 作为虚拟 HID:**
|
||||
|
||||
```bash
|
||||
sudo docker run --name kvmd -itd \
|
||||
--device /dev/video0:/dev/video0 \
|
||||
@@ -74,79 +111,159 @@ sudo docker run --name kvmd -itd \
|
||||
silentwind0/kvmd
|
||||
```
|
||||
|
||||
**方式二:直刷 One-KVM 整合包**
|
||||
### 方式二:直刷 One-KVM 整合包
|
||||
|
||||
对于部分平台硬件,本项目制作了深度适配的 One-KVM 打包镜像,开箱即用,刷好后启动设备就可以开始使用 One-KVM。免费 One-KVM 整合包也可以在本项目 Releases 页可以找到。
|
||||
针对特定硬件平台,提供了预配置的 One-KVM 打包镜像,简化部署流程,实现开箱即用。
|
||||
|
||||
| 整合包适配概况 | | | |
|
||||
| :-------------: | :-------------: | :-------------: | :-------------: |
|
||||
| **固件型号** | **固件代号** | **硬件情况** | **最新版本** |
|
||||
| 玩客云 | Onecloud | USB 采集卡、OTG | 241018 |
|
||||
| 私家云二代 | Cumebox2 | USB 采集卡、OTG | 241004 |
|
||||
| Vmare | Vmare-uefi | USB 采集卡、CH9329 | 241004 |
|
||||
| Virtualbox | Virtualbox-uefi | USB 采集卡、CH9329 | 241004 |
|
||||
| s905l3a 通用包 | E900v22c | USB 采集卡、OTG | 241004 |
|
||||
| 我家云 | Chainedbox | USB 采集卡、OTG | 241004 |
|
||||
| 龙芯久久派 | 2k0300 | USB 采集卡、CH9329 | 241025 |
|
||||
#### 固件下载
|
||||
|
||||
### 赞助方式
|
||||
**GitHub 下载:**
|
||||
- **GitHub Releases:** [https://github.com/mofeng-git/One-KVM/releases](https://github.com/mofeng-git/One-KVM/releases)
|
||||
|
||||
这个项目基于众多开源项目二次开发,作者为此花费了大量的时间和精力进行测试和维护。若此项目对您有用,您可以考虑通过 **[为爱发电](https://afdian.com/a/silentwind)** 赞助一笔小钱支持作者。作者将能有更多的金钱来测试和维护 One-KVM 的各种配置,并在项目上投入更多的时间和精力。
|
||||
**其他下载方式:**
|
||||
- **免登录下载:** [https://pan.huang1111.cn/s/mxkx3T1](https://pan.huang1111.cn/s/mxkx3T1) (由 Huang1111公益计划 提供)
|
||||
- **百度网盘:** [https://pan.baidu.com/s/166-2Y8PBF4SbHXFkGmFJYg?pwd=o9aj](https://pan.baidu.com/s/166-2Y8PBF4SbHXFkGmFJYg?pwd=o9aj) (提取码:o9aj)
|
||||
|
||||
**感谢名单**
|
||||
#### 支持的硬件平台
|
||||
|
||||
| 固件型号 | 固件代号 | 硬件配置 | 最新版本 | 状态 |
|
||||
|:--------:|:--------:|:--------:|:--------:|:----:|
|
||||
| 玩客云 | Onecloud | USB 采集卡、OTG | 241018 | ✅ |
|
||||
| 私家云二代 | Cumebox2 | USB 采集卡、OTG | 241004 | ✅ |
|
||||
| Vmare | Vmare-uefi | USB 采集卡、CH9329 | 241004 | ✅ |
|
||||
| Virtualbox | Virtualbox-uefi | USB 采集卡、CH9329 | 241004 | ✅ |
|
||||
| s905l3a 通用包 | E900v22c | USB 采集卡、OTG | 241004 | ✅ |
|
||||
| 我家云 | Chainedbox | USB 采集卡、OTG | 241004 | ✅ |
|
||||
| 龙芯久久派 | 2k0300 | USB 采集卡、CH9329 | 241025 | ✅ |
|
||||
|
||||
## 🤝 贡献指南
|
||||
|
||||
欢迎各种形式的贡献!
|
||||
|
||||
### 如何贡献
|
||||
|
||||
1. **Fork 本仓库**
|
||||
2. **创建功能分支:** `git checkout -b feature/AmazingFeature`
|
||||
3. **提交更改:** `git commit -m 'Add some AmazingFeature'`
|
||||
4. **推送到分支:** `git push origin feature/AmazingFeature`
|
||||
5. **提交 Pull Request**
|
||||
|
||||
### 报告问题
|
||||
|
||||
如果您发现了问题,请:
|
||||
1. 使用 [GitHub Issues](https://github.com/mofeng-git/One-KVM/issues) 报告
|
||||
2. 提供详细的错误信息和复现步骤
|
||||
3. 包含您的硬件配置和系统信息
|
||||
|
||||
### 赞助支持
|
||||
|
||||
本项目基于多个优秀开源项目进行二次开发,作者投入了大量时间进行测试和维护。如果您觉得这个项目有价值,欢迎通过 **[为爱发电](https://afdian.com/a/silentwind)** 支持项目发展。
|
||||
|
||||
#### 感谢名单
|
||||
|
||||
<details>
|
||||
<summary><strong>点击查看感谢名单</strong></summary>
|
||||
|
||||
浩龙的电子嵌入式之路(赞助)
|
||||
- 浩龙的电子嵌入式之路
|
||||
|
||||
Tsuki(赞助)
|
||||
- Tsuki
|
||||
|
||||
H_xiaoming
|
||||
- H_xiaoming
|
||||
|
||||
0蓝蓝0
|
||||
- 0蓝蓝0
|
||||
|
||||
fairybl
|
||||
- fairybl
|
||||
|
||||
Will
|
||||
- Will
|
||||
|
||||
浩龙的电子嵌入式之路
|
||||
- 浩龙的电子嵌入式之路
|
||||
|
||||
自.知
|
||||
- 自.知
|
||||
|
||||
观棋不语٩ ི۶
|
||||
- 观棋不语٩ ི۶
|
||||
|
||||
爱发电用户_a57a4
|
||||
- 爱发电用户_a57a4
|
||||
|
||||
爱发电用户_2c769
|
||||
- 爱发电用户_2c769
|
||||
|
||||
霜序
|
||||
- 霜序
|
||||
|
||||
[远方](https://runyf.cn/)(闲鱼用户名:小远技术店铺)
|
||||
- 远方(闲鱼用户名:小远技术店铺)
|
||||
|
||||
爱发电用户_399fc
|
||||
- 爱发电用户_399fc
|
||||
|
||||
[斐斐の](https://www.mmuaa.com/)
|
||||
- 斐斐の
|
||||
|
||||
爱发电用户_09451
|
||||
- 爱发电用户_09451
|
||||
|
||||
超高校级的錆鱼
|
||||
- 超高校级的錆鱼
|
||||
|
||||
爱发电用户_08cff
|
||||
- 爱发电用户_08cff
|
||||
|
||||
guoke
|
||||
- guoke
|
||||
|
||||
mgt
|
||||
- mgt
|
||||
|
||||
- 姜沢掵
|
||||
|
||||
- ui_beam
|
||||
|
||||
- 爱发电用户_c0dd7
|
||||
|
||||
- 爱发电用户_dnjK
|
||||
|
||||
- 忍者胖猪
|
||||
|
||||
- 永遠の願い
|
||||
|
||||
- 爱发电用户_GBrF
|
||||
|
||||
- 爱发电用户_fd65c
|
||||
|
||||
- 爱发电用户_vhNa
|
||||
|
||||
- 爱发电用户_Xu6S
|
||||
|
||||
- moss
|
||||
|
||||
- woshididi
|
||||
|
||||
- 爱发电用户_a0fd1
|
||||
|
||||
- 爱发电用户_f6bH
|
||||
|
||||
- 码农
|
||||
|
||||
- 爱发电用户_6639f
|
||||
|
||||
- jeron
|
||||
|
||||
- 爱发电用户_CN7y
|
||||
|
||||
- 爱发电用户_Up6w
|
||||
|
||||
- 爱发电用户_e3202
|
||||
|
||||
- ......
|
||||
|
||||
......
|
||||
</details>
|
||||
|
||||
本项目使用了下列开源项目:
|
||||
1. [pikvm/pikvm: Open and inexpensive DIY IP-KVM based on Raspberry Pi (github.com)](https://github.com/pikvm/pikvm)
|
||||
#### 赞助商
|
||||
|
||||
### 项目状态
|
||||
本项目得到以下赞助商的支持:
|
||||
|
||||
[](https://star-history.com/#mofeng-git/One-KVM&Date)
|
||||
**CDN 加速及安全防护:**
|
||||
- **[Tencent EdgeOne](https://edgeone.ai/zh?from=github)** - 提供 CDN 加速及安全防护服务
|
||||
|
||||

|
||||

|
||||
|
||||
**文件存储服务:**
|
||||
- **[Huang1111公益计划](https://pan.huang1111.cn/s/mxkx3T1)** - 提供免登录下载服务
|
||||
|
||||
## 📚 其他
|
||||
|
||||
### 使用的开源项目
|
||||
|
||||
本项目基于以下优秀开源项目进行二次开发:
|
||||
|
||||
- [PiKVM](https://github.com/pikvm/pikvm) - 开源的 DIY IP-KVM 解决方案
|
||||
@@ -82,14 +82,14 @@ RUN git clone --depth=1 https://gitlab.freedesktop.org/libnice/libnice /tmp/libn
|
||||
&& tar xf libsrtp-2.2.0.tar.gz \
|
||||
&& cd libsrtp-2.2.0 \
|
||||
&& ./configure --prefix=/usr --enable-openssl \
|
||||
&& make shared_library && make install \
|
||||
&& make shared_library -j && make install \
|
||||
&& cd /tmp \
|
||||
&& rm -rf /tmp/libsrtp* \
|
||||
&& git clone --depth=1 https://libwebsockets.org/repo/libwebsockets /tmp/libwebsockets \
|
||||
&& cd /tmp/libwebsockets \
|
||||
&& mkdir build && cd build \
|
||||
&& cmake -DLWS_MAX_SMP=1 -DLWS_WITHOUT_EXTENSIONS=0 -DCMAKE_INSTALL_PREFIX:PATH=/usr -DCMAKE_C_FLAGS="-fpic" .. \
|
||||
&& make && make install \
|
||||
&& make -j && make install \
|
||||
&& cd /tmp \
|
||||
&& rm -rf /tmp/libwebsockets \
|
||||
&& git clone --depth=1 https://github.com/meetecho/janus-gateway.git /tmp/janus-gateway \
|
||||
@@ -98,7 +98,7 @@ RUN git clone --depth=1 https://gitlab.freedesktop.org/libnice/libnice /tmp/libn
|
||||
&& ./configure --enable-static --enable-websockets --enable-plugin-audiobridge \
|
||||
--disable-data-channels --disable-rabbitmq --disable-mqtt --disable-all-plugins \
|
||||
--disable-all-loggers --prefix=/usr \
|
||||
&& make && make install \
|
||||
&& make -j && make install \
|
||||
&& cd /tmp \
|
||||
&& rm -rf /tmp/janus-gateway
|
||||
|
||||
@@ -116,4 +116,4 @@ RUN mkdir /tmp/lib \
|
||||
&& cp libevent_core-*.so.7 libbsd.so.0 libevent_pthreads-*.so.7 libspeexdsp.so.1 \
|
||||
libevent-*.so.7 libjpeg.so.62 libx264.so.164 libyuv.so.0 libnice.so.10 \
|
||||
/usr/lib/libsrtp2.so.1 /usr/lib/libwebsockets.so.19 \
|
||||
/tmp/lib/
|
||||
/tmp/lib/
|
||||
|
||||
499
build/build_img.sh
Normal file → Executable file
499
build/build_img.sh
Normal file → Executable file
@@ -1,368 +1,169 @@
|
||||
#!/bin/bash
|
||||
# ========================================================================== #
|
||||
# #
|
||||
# KVMD - The main PiKVM daemon. #
|
||||
# #
|
||||
# Copyright (C) 2023-2025 SilentWind <mofeng654321@hotmail.com> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# ========================================================================== #
|
||||
|
||||
SRCPATH=/mnt/nas/src
|
||||
BOOTFS=/tmp/bootfs
|
||||
ROOTFS=/tmp/rootfs
|
||||
OUTPUTDIR=/mnt/nas/src/output
|
||||
LOOPDEV=/dev/loop10
|
||||
DATE=240303
|
||||
# --- 配置 ---
|
||||
# 允许通过环境变量覆盖默认路径
|
||||
SRCPATH="${SRCPATH:-/mnt/nfs/lfs/src}"
|
||||
BOOTFS="${BOOTFS:-/tmp/bootfs}"
|
||||
ROOTFS="${ROOTFS:-/tmp/rootfs}"
|
||||
OUTPUTDIR="${OUTPUTDIR:-/mnt/nfs/lfs/src/output}"
|
||||
TMPDIR="${TMPDIR:-$SRCPATH/tmp}"
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
write_meta() {
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c "sed -i 's/localhost.localdomain/$1/g' /etc/kvmd/meta.yaml"
|
||||
}
|
||||
# 全局变量
|
||||
LOOPDEV=""
|
||||
ROOTFS_MOUNTED=0
|
||||
BOOTFS_MOUNTED=0
|
||||
PROC_MOUNTED=0
|
||||
SYS_MOUNTED=0
|
||||
DEV_MOUNTED=0
|
||||
DOCKER_CONTAINER_NAME="to_build_rootfs_$$"
|
||||
PREBUILT_DIR="/tmp/prebuilt_binaries"
|
||||
|
||||
mount_rootfs() {
|
||||
mkdir $ROOTFS $SRCPATH/tmp/rootfs
|
||||
sudo mount $LOOPDEV $ROOTFS || exit -1
|
||||
sudo mount -t proc proc $ROOTFS/proc || exit -1
|
||||
sudo mount -t sysfs sys $ROOTFS/sys || exit -1
|
||||
sudo mount -o bind /dev $ROOTFS/dev || exit -1
|
||||
}
|
||||
# --- 引入模块化脚本 ---
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
source "$SCRIPT_DIR/functions/common.sh"
|
||||
source "$SCRIPT_DIR/functions/devices.sh"
|
||||
source "$SCRIPT_DIR/functions/install.sh"
|
||||
source "$SCRIPT_DIR/functions/packaging.sh"
|
||||
|
||||
umount_rootfs() {
|
||||
sudo umount $ROOTFS/sys
|
||||
sudo umount $ROOTFS/dev
|
||||
sudo umount $ROOTFS/proc
|
||||
sudo umount $ROOTFS
|
||||
sudo zerofree $LOOPDEV
|
||||
sudo losetup -d $LOOPDEV
|
||||
sudo docker rm to_build_rootfs
|
||||
sudo rm -rf $SRCPATH/tmp/rootfs/*
|
||||
}
|
||||
# 获取日期与Git版本
|
||||
GIT_COMMIT_ID=$(get_git_commit_id)
|
||||
DATE=$(date +%y%m%d)
|
||||
if [ -n "$GIT_COMMIT_ID" ]; then
|
||||
DATE="${DATE}-${GIT_COMMIT_ID}"
|
||||
fi
|
||||
|
||||
parpare_dns() {
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
mkdir -p /run/systemd/resolve/ \
|
||||
&& touch /run/systemd/resolve/stub-resolv.conf \
|
||||
&& printf '%s\n' 'nameserver 1.1.1.1' 'nameserver 1.0.0.1' > /etc/resolv.conf \
|
||||
&& bash <(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh) \
|
||||
--source mirrors.tuna.tsinghua.edu.cn --updata-software false --web-protocol http "
|
||||
}
|
||||
# --- 注册清理函数 ---
|
||||
# 在脚本退出、收到错误信号、中断信号、终止信号时执行 cleanup
|
||||
trap cleanup EXIT ERR INT TERM
|
||||
|
||||
delete_armbain_verify(){
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c "echo 'deb http://mirrors.ustc.edu.cn/armbian bullseye main bullseye-utils bullseye-desktop' > /etc/apt/sources.list.d/armbian.list "
|
||||
}
|
||||
# --- 构建流程函数 ---
|
||||
|
||||
config_file() {
|
||||
|
||||
sudo mkdir -p $ROOTFS/etc/kvmd/override.d $ROOTFS/etc/kvmd/vnc $ROOTFS/var/lib/kvmd/msd $ROOTFS/opt/vc/bin $ROOTFS/usr/share/kvmd $ROOTFS/One-KVM \
|
||||
$ROOTFS/usr/share/janus/javascript $ROOTFS/usr/lib/ustreamer/janus $ROOTFS/run/kvmd $ROOTFS/var/lib/kvmd/msd/images $ROOTFS/var/lib/kvmd/msd/meta \
|
||||
$ROOTFS/tmp/wheel/ $ROOTFS/usr/lib/janus/transports/ $ROOTFS/usr/lib/janus/loggers
|
||||
sudo rsync -a --exclude={src,.github} . $ROOTFS/One-KVM
|
||||
sudo cp -r configs/kvmd/* configs/nginx configs/janus $ROOTFS/etc/kvmd
|
||||
sudo cp -r web extras contrib/keymaps $ROOTFS/usr/share/kvmd
|
||||
sudo cp testenv/fakes/vcgencmd $ROOTFS/usr/bin/
|
||||
sudo cp -r testenv/js/* $ROOTFS/usr/share/janus/javascript/
|
||||
sudo cp build/platform/$1 $ROOTFS/usr/share/kvmd/platform
|
||||
if [ -f "$SRCPATH/image/$1/rc.local" ]; then
|
||||
sudo cp $SRCPATH/image/$1/rc.local $ROOTFS/etc/
|
||||
fi
|
||||
build_target() {
|
||||
local target="$1"
|
||||
local build_time=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
echo "=================================================="
|
||||
echo "信息:构建目标: $target"
|
||||
echo "信息:构建时间: $build_time"
|
||||
echo "=================================================="
|
||||
|
||||
sudo docker pull --platform linux/$2 registry.cn-hangzhou.aliyuncs.com/silentwind/kvmd-stage-0
|
||||
sudo docker create --name to_build_rootfs registry.cn-hangzhou.aliyuncs.com/silentwind/kvmd-stage-0
|
||||
sudo docker export to_build_rootfs | sudo tar -xvf - -C $SRCPATH/tmp/rootfs
|
||||
sudo cp $SRCPATH/tmp/rootfs/tmp/lib/* $ROOTFS/lib/*-linux-*/
|
||||
sudo cp $SRCPATH/tmp/rootfs/tmp/ustreamer/ustreamer $SRCPATH/tmp/rootfs/tmp/ustreamer/ustreamer-dump $SRCPATH/tmp/rootfs/usr/bin/janus $ROOTFS/usr/bin/
|
||||
sudo cp $SRCPATH/tmp/rootfs/tmp/ustreamer/janus/libjanus_ustreamer.so $ROOTFS/usr/lib/ustreamer/janus/
|
||||
sudo cp $SRCPATH/tmp/rootfs/tmp/wheel/*.whl $ROOTFS/tmp/wheel/
|
||||
sudo cp $SRCPATH/tmp/rootfs/usr/lib/janus/transports/* $ROOTFS/usr/lib/janus/transports/
|
||||
# 设置全局变量,供后续函数使用
|
||||
TARGET_DEVICE_NAME="$target"
|
||||
NEED_PREPARE_DNS=false # 默认不需要准备 DNS
|
||||
|
||||
sudo mv $ROOTFS/etc/apt/apt.conf.d/50apt-file.conf{,.disabled}
|
||||
}
|
||||
|
||||
pack_img() {
|
||||
sudo mv $SRCPATH/tmp/rootfs.img $OUTPUTDIR/One-KVM_by-SilentWind_$1_$DATE.img
|
||||
if [ "$1" = "Vm" ]; then
|
||||
sudo qemu-img convert -f raw -O vmdk $OUTPUTDIR/One-KVM_by-SilentWind_Vm_$DATE.img $OUTPUTDIR/One-KVM_by-SilentWind_Vmare-uefi_$DATE.vmdk
|
||||
sudo qemu-img convert -f raw -O vdi $OUTPUTDIR/One-KVM_by-SilentWind_Vm_$DATE.img $OUTPUTDIR/One-KVM_by-SilentWind_Virtualbox-uefi_$DATE.vdi
|
||||
fi
|
||||
}
|
||||
|
||||
onecloud_rootfs() {
|
||||
$SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64 unpack $SRCPATH/image/onecloud/Armbian_by-SilentWind_24.5.0-trunk_Onecloud_bookworm_legacy_5.9.0-rc7_minimal.burn.img $SRCPATH/tmp
|
||||
simg2img $SRCPATH/tmp/6.boot.PARTITION.sparse $SRCPATH/tmp/bootfs.img
|
||||
simg2img $SRCPATH/tmp/7.rootfs.PARTITION.sparse $SRCPATH/tmp/rootfs.img
|
||||
mkdir $BOOTFS
|
||||
sudo losetup $LOOPDEV $SRCPATH/tmp/bootfs.img || exit -1
|
||||
sudo mount $LOOPDEV $BOOTFS
|
||||
sudo cp $SRCPATH/image/onecloud/meson8b-onecloud-fix.dtb $BOOTFS/dtb/meson8b-onecloud.dtb
|
||||
sudo umount $BOOTFS
|
||||
sudo losetup -d $LOOPDEV
|
||||
dd if=/dev/zero of=/tmp/add.img bs=1M count=256 && cat /tmp/add.img >> $SRCPATH/tmp/rootfs.img && rm /tmp/add.img
|
||||
e2fsck -f $SRCPATH/tmp/rootfs.img && resize2fs $SRCPATH/tmp/rootfs.img
|
||||
sudo losetup $LOOPDEV $SRCPATH/tmp/rootfs.img
|
||||
}
|
||||
|
||||
cumebox2_rootfs() {
|
||||
cp $SRCPATH/image/cumebox2/Armbian_24.8.1_Khadas-vim1_bookworm_current_6.6.47_minimal.img $SRCPATH/tmp/rootfs.img
|
||||
dd if=/dev/zero of=/tmp/add.img bs=1M count=1500 && cat /tmp/add.img >> $SRCPATH/tmp/rootfs.img && rm /tmp/add.img
|
||||
sudo parted -s $SRCPATH/tmp/rootfs.img resizepart 1 100% || exit -1
|
||||
sudo losetup --offset $((8192*512)) $LOOPDEV $SRCPATH/tmp/rootfs.img || exit -1
|
||||
sudo e2fsck -f $LOOPDEV && sudo resize2fs $LOOPDEV
|
||||
}
|
||||
|
||||
chainedbox_rootfs_and_fix_dtb() {
|
||||
cp $SRCPATH/image/chainedbox/Armbian_24.11.0_rockchip_chainedbox_bookworm_6.1.112_server_2024.10.02_add800m.img $SRCPATH/tmp/rootfs.img
|
||||
mkdir $BOOTFS
|
||||
sudo losetup --offset $((32768*512)) $LOOPDEV $SRCPATH/tmp/rootfs.img || exit -1
|
||||
sudo mount $LOOPDEV $BOOTFS
|
||||
sudo cp $SRCPATH/image/chainedbox/rk3328-l1pro-1296mhz-fix.dtb $BOOTFS/dtb/rockchip/rk3328-l1pro-1296mhz.dtb
|
||||
sudo umount $BOOTFS
|
||||
sudo losetup -d $LOOPDEV
|
||||
sudo losetup --offset $((1081344*512)) $LOOPDEV $SRCPATH/tmp/rootfs.img
|
||||
}
|
||||
|
||||
vm_rootfs() {
|
||||
cp $SRCPATH/image/vm/Armbian_24.8.1_Uefi-x86_bookworm_current_6.6.47_minimal_add1g.img $SRCPATH/tmp/rootfs.img
|
||||
sudo losetup --offset $((540672*512)) $LOOPDEV $SRCPATH/tmp/rootfs.img || exit -1
|
||||
}
|
||||
|
||||
e900v22c_rootfs() {
|
||||
cp $SRCPATH/image/e900v22c/Armbian_23.08.0_amlogic_s905l3a_bookworm_5.15.123_server_2023.08.01.img $SRCPATH/tmp/rootfs.img
|
||||
dd if=/dev/zero of=/tmp/add.img bs=1M count=400 && cat /tmp/add.img >> $SRCPATH/tmp/rootfs.img && rm /tmp/add.img
|
||||
sudo parted -s $SRCPATH/tmp/rootfs.img resizepart 2 100% || exit -1
|
||||
sudo losetup --offset $((532480*512)) $LOOPDEV $SRCPATH/tmp/rootfs.img || exit -1
|
||||
sudo e2fsck -f $LOOPDEV && sudo resize2fs $LOOPDEV
|
||||
}
|
||||
|
||||
|
||||
octopus-flanet_rootfs() {
|
||||
cp $SRCPATH/image/octopus-flanet/Armbian_24.11.0_amlogic_s912_bookworm_6.1.114_server_2024.11.01.img $SRCPATH/tmp/rootfs.img
|
||||
mkdir $BOOTFS
|
||||
sudo losetup --offset $((8192*512)) $LOOPDEV $SRCPATH/tmp/rootfs.img || exit -1
|
||||
sudo mount $LOOPDEV $BOOTFS
|
||||
sudo sed -i "s/meson-gxm-octopus-planet.dtb/meson-gxm-khadas-vim2.dtb/g" $BOOTFS/uEnv.txt
|
||||
sudo umount $BOOTFS
|
||||
sudo losetup -d $LOOPDEV
|
||||
dd if=/dev/zero of=/tmp/add.img bs=1M count=400 && cat /tmp/add.img >> $SRCPATH/tmp/rootfs.img && rm /tmp/add.img
|
||||
sudo parted -s $SRCPATH/tmp/rootfs.img resizepart 2 100% || exit -1
|
||||
sudo losetup --offset $((1056768*512)) $LOOPDEV $SRCPATH/tmp/rootfs.img || exit -1
|
||||
sudo e2fsck -f $LOOPDEV && sudo resize2fs $LOOPDEV
|
||||
}
|
||||
|
||||
|
||||
config_cumebox2_file() {
|
||||
sudo mkdir $ROOTFS/etc/oled
|
||||
sudo cp $SRCPATH/image/cumebox2/v-fix.dtb $ROOTFS/boot/dtb/amlogic/meson-gxl-s905x-khadas-vim.dtb
|
||||
sudo cp $SRCPATH/image/cumebox2/ssd $ROOTFS/usr/bin/
|
||||
sudo cp $SRCPATH/image/cumebox2/config.json $ROOTFS/etc/oled/config.json
|
||||
}
|
||||
|
||||
config_octopus-flanet_file() {
|
||||
sudo cp $SRCPATH/image/octopus-flanet/model_database.conf $ROOTFS/etc/model_database.conf
|
||||
}
|
||||
|
||||
instal_one-kvm() {
|
||||
#$1 arch; $2 deivce: "gpio" or "video1"; $3 network: "systemd-networkd",default is network-manager
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
df -h \
|
||||
&& apt-get update \
|
||||
&& apt install -y --no-install-recommends libxkbcommon-x11-0 nginx tesseract-ocr tesseract-ocr-eng tesseract-ocr-chi-sim iptables \
|
||||
curl kmod libmicrohttpd12 libjansson4 libssl3 libsofia-sip-ua0 libglib2.0-0 libopus0 libogg0 libcurl4 libconfig9 python3-pip \
|
||||
&& apt clean \
|
||||
&& rm -rf /var/lib/apt/lists/* "
|
||||
|
||||
if [ "$3" = "systemd-networkd" ]; then
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
echo -e '[Match]\nName=eth0\n\n[Network]\nDHCP=yes\n\n[Link]\nMACAddress=B6:AE:B3:21:42:0C' > /etc/systemd/network/99-eth0.network \
|
||||
&& systemctl mask NetworkManager \
|
||||
&& systemctl unmask systemd-networkd \
|
||||
&& systemctl enable systemd-networkd systemd-resolved "
|
||||
fi
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
pip3 install --no-cache-dir --break-system-packages /tmp/wheel/*.whl \
|
||||
&& pip3 cache purge \
|
||||
&& rm -r /tmp/wheel "
|
||||
|
||||
#pip3 install --target=/usr/lib/python3/dist-packages --break-system-packages pyfatfs -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
|
||||
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
cd /One-KVM \
|
||||
&& python3 setup.py install \
|
||||
&& bash scripts/kvmd-gencert --do-the-thing \
|
||||
&& bash scripts/kvmd-gencert --do-the-thing --vnc \
|
||||
&& kvmd-nginx-mkconf /etc/kvmd/nginx/nginx.conf.mako /etc/kvmd/nginx/nginx.conf \
|
||||
&& kvmd -m "
|
||||
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
cat /One-KVM/configs/os/sudoers/v2-hdmiusb >> /etc/sudoers \
|
||||
&& cat /One-KVM/configs/os/udev/v2-hdmiusb-rpi4.rules > /etc/udev/rules.d/99-kvmd.rules \
|
||||
&& echo 'libcomposite' >> /etc/modules \
|
||||
&& mv /usr/local/bin/kvmd* /usr/bin \
|
||||
&& cp /One-KVM/configs/os/services/* /etc/systemd/system/ \
|
||||
&& cp /One-KVM/configs/os/tmpfiles.conf /usr/lib/tmpfiles.d/ \
|
||||
&& mv /etc/kvmd/supervisord.conf /etc/supervisord.conf \
|
||||
&& chmod +x /etc/update-motd.d/* \
|
||||
&& echo 'kvmd ALL=(ALL) NOPASSWD: /etc/kvmd/custom_atx/gpio.sh' >> /etc/sudoers \
|
||||
&& echo 'kvmd ALL=(ALL) NOPASSWD: /etc/kvmd/custom_atx/usbrelay_hid.sh' >> /etc/sudoers \
|
||||
&& systemd-sysusers /One-KVM/configs/os/sysusers.conf \
|
||||
&& systemd-sysusers /One-KVM/configs/os/kvmd-webterm.conf \
|
||||
&& ln -sf /usr/share/tesseract-ocr/*/tessdata /usr/share/tessdata \
|
||||
&& sed -i 's/8080/80/g' /etc/kvmd/override.yaml \
|
||||
&& sed -i 's/4430/443/g' /etc/kvmd/override.yaml \
|
||||
&& chown kvmd -R /var/lib/kvmd/msd/ \
|
||||
&& systemctl enable kvmd kvmd-otg kvmd-nginx kvmd-vnc kvmd-ipmi kvmd-webterm kvmd-janus kvmd-media \
|
||||
&& systemctl disable nginx \
|
||||
&& rm -r /One-KVM "
|
||||
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
curl https://gh.llkk.cc/https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.$1 -L -o /usr/bin/ttyd \
|
||||
&& chmod +x /usr/bin/ttyd \
|
||||
&& mkdir -p /home/kvmd-webterm \
|
||||
&& chown kvmd-webterm /home/kvmd-webterm "
|
||||
|
||||
if [ "$1" = "x86_64" ]; then
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
systemctl disable kvmd-otg \
|
||||
&& sed -i '2c ATX=USBRELAY_HID' /etc/kvmd/atx.sh \
|
||||
&& sed -i 's/device: \/dev\/ttyUSB0/device: \/dev\/kvmd-hid/g' /etc/kvmd/override.yaml "
|
||||
else
|
||||
if [ "$2" = "gpio" ]; then
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
sed -i '2c ATX=GPIO' /etc/kvmd/atx.sh \
|
||||
&& sed -i 's/SHUTDOWNPIN/gpiochip1 7/g' /etc/kvmd/custom_atx/gpio.sh \
|
||||
&& sed -i 's/REBOOTPIN/gpiochip0 11/g' /etc/kvmd/custom_atx/gpio.sh "
|
||||
else
|
||||
sudo chroot --userspec "root:root" $ROOTFS sed -i '2c ATX=USBRELAY_HID' /etc/kvmd/atx.sh
|
||||
|
||||
fi
|
||||
if [ "$2" = "video1" ]; then
|
||||
sudo chroot --userspec "root:root" $ROOTFS sed -i 's/\/dev\/video0/\/dev\/video1/g' /etc/kvmd/override.yaml
|
||||
fi
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c " \
|
||||
sed -i 's/ch9329/otg/g' /etc/kvmd/override.yaml \
|
||||
&& sed -i 's/device: \/dev\/ttyUSB0//g' /etc/kvmd/override.yaml \
|
||||
&& sed -i 's/#type: otg/type: otg/g' /etc/kvmd/override.yaml "
|
||||
fi
|
||||
|
||||
sudo chroot --userspec "root:root" $ROOTFS bash -c "df -h"
|
||||
}
|
||||
|
||||
pack_img_onecloud() {
|
||||
sudo rm $SRCPATH/tmp/7.rootfs.PARTITION.sparse
|
||||
sudo img2simg $SRCPATH/tmp/rootfs.img $SRCPATH/tmp/7.rootfs.PARTITION.sparse
|
||||
sudo $SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64 pack $OUTPUTDIR/One-KVM_by-SilentWind_Onecloud_$DATE.burn.img $SRCPATH/tmp/
|
||||
sudo rm $SRCPATH/tmp/*
|
||||
}
|
||||
|
||||
#build function
|
||||
|
||||
onecloud() {
|
||||
onecloud_rootfs
|
||||
mount_rootfs
|
||||
config_file "onecloud" "arm"
|
||||
instal_one-kvm armhf gpio systemd-networkd
|
||||
write_meta "onecloud"
|
||||
umount_rootfs
|
||||
pack_img_onecloud
|
||||
}
|
||||
|
||||
cumebox2() {
|
||||
cumebox2_rootfs
|
||||
mount_rootfs
|
||||
config_file "cumebox2" "aarch64"
|
||||
config_cumebox2_file
|
||||
parpare_dns
|
||||
instal_one-kvm aarch64 video1
|
||||
write_meta "cumebox2"
|
||||
umount_rootfs
|
||||
pack_img "Cumebox2"
|
||||
}
|
||||
|
||||
chainedbox() {
|
||||
chainedbox_rootfs_and_fix_dtb
|
||||
mount_rootfs
|
||||
config_file "chainedbox" "aarch64"
|
||||
parpare_dns
|
||||
instal_one-kvm aarch64 video1
|
||||
write_meta "chainedbox"
|
||||
umount_rootfs
|
||||
pack_img "Chainedbox"
|
||||
}
|
||||
|
||||
vm() {
|
||||
vm_rootfs
|
||||
mount_rootfs
|
||||
config_file "vm" "amd64"
|
||||
parpare_dns
|
||||
instal_one-kvm x86_64
|
||||
write_meta "vm"
|
||||
umount_rootfs
|
||||
pack_img "Vm"
|
||||
}
|
||||
|
||||
e900v22c() {
|
||||
e900v22c_rootfs
|
||||
mount_rootfs
|
||||
config_file "e900v22c" "aarch64"
|
||||
instal_one-kvm aarch64 video1
|
||||
write_meta "e900v22c"
|
||||
umount_rootfs
|
||||
pack_img "E900v22c"
|
||||
}
|
||||
|
||||
octopus_flanet() {
|
||||
octopus-flanet_rootfs
|
||||
mount_rootfs
|
||||
config_file "octopus-flanet" "aarch64"
|
||||
config_octopus-flanet_file
|
||||
parpare_dns
|
||||
instal_one-kvm aarch64 video1
|
||||
write_meta "octopus-flanet"
|
||||
umount_rootfs
|
||||
pack_img "Octopus-Flanet"
|
||||
}
|
||||
|
||||
if [ "$1" = "all" ]; then
|
||||
onecloud
|
||||
cumebox2
|
||||
chainedbox
|
||||
vm
|
||||
e900v22c
|
||||
octopus_flanet
|
||||
else
|
||||
case $1 in
|
||||
onecloud)
|
||||
onecloud
|
||||
case "$target" in
|
||||
onecloud)
|
||||
onecloud_rootfs
|
||||
local arch="armhf"
|
||||
local device_type="gpio"
|
||||
local network_type="systemd-networkd"
|
||||
;;
|
||||
cumebox2)
|
||||
cumebox2
|
||||
cumebox2)
|
||||
cumebox2_rootfs
|
||||
local arch="aarch64"
|
||||
local device_type="video1"
|
||||
local network_type="" # 默认 NetworkManager
|
||||
NEED_PREPARE_DNS=true
|
||||
;;
|
||||
chainedbox)
|
||||
chainedbox
|
||||
chainedbox)
|
||||
chainedbox_rootfs_and_fix_dtb
|
||||
local arch="aarch64"
|
||||
local device_type="video1"
|
||||
local network_type=""
|
||||
NEED_PREPARE_DNS=true
|
||||
;;
|
||||
vm)
|
||||
vm
|
||||
vm)
|
||||
vm_rootfs
|
||||
local arch="amd64"
|
||||
local device_type=""
|
||||
local network_type=""
|
||||
NEED_PREPARE_DNS=true
|
||||
;;
|
||||
e900v22c)
|
||||
e900v22c
|
||||
e900v22c)
|
||||
e900v22c_rootfs
|
||||
local arch="aarch64"
|
||||
local device_type="video1"
|
||||
local network_type=""
|
||||
NEED_PREPARE_DNS=true
|
||||
;;
|
||||
octopus-flanet)
|
||||
octopus_flanet
|
||||
octopus-flanet)
|
||||
octopus_flanet_rootfs
|
||||
local arch="aarch64"
|
||||
local device_type="video1"
|
||||
local network_type=""
|
||||
NEED_PREPARE_DNS=true
|
||||
;;
|
||||
*)
|
||||
echo "Do no thing."
|
||||
*)
|
||||
echo "错误:未知或不支持的目标 '$target'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
mount_rootfs
|
||||
|
||||
install_and_configure_kvmd "$arch" "$device_type" "$network_type"
|
||||
|
||||
write_meta "$target"
|
||||
|
||||
unmount_all
|
||||
|
||||
case "$target" in
|
||||
onecloud)
|
||||
pack_img_onecloud
|
||||
;;
|
||||
vm)
|
||||
pack_img "Vm"
|
||||
;;
|
||||
cumebox2)
|
||||
pack_img "Cumebox2"
|
||||
;;
|
||||
chainedbox)
|
||||
pack_img "Chainedbox"
|
||||
;;
|
||||
e900v22c)
|
||||
pack_img "E900v22c"
|
||||
;;
|
||||
octopus-flanet)
|
||||
pack_img "Octopus-Flanet"
|
||||
;;
|
||||
*)
|
||||
echo "错误:未知的打包类型 for '$target'" >&2
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "=================================================="
|
||||
echo "信息:目标 $target 构建完成!"
|
||||
echo "=================================================="
|
||||
}
|
||||
|
||||
# --- 主逻辑 ---
|
||||
|
||||
# 检查是否提供了目标参数
|
||||
if [ -z "$1" ]; then
|
||||
echo "用法: $0 <target|all>"
|
||||
echo "可用目标: onecloud, cumebox2, chainedbox, vm, e900v22c, octopus-flanet"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 设置脚本立即退出模式
|
||||
set -eo pipefail
|
||||
|
||||
# 检查必要的外部工具
|
||||
check_required_tools "$1"
|
||||
|
||||
# 执行构建
|
||||
if [ "$1" = "all" ]; then
|
||||
echo "信息:开始构建所有目标..."
|
||||
build_target "onecloud"
|
||||
build_target "cumebox2"
|
||||
build_target "chainedbox"
|
||||
build_target "vm"
|
||||
build_target "e900v22c"
|
||||
build_target "octopus-flanet"
|
||||
echo "信息:所有目标构建完成。"
|
||||
else
|
||||
build_target "$1"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
195
build/functions/common.sh
Executable file
195
build/functions/common.sh
Executable file
@@ -0,0 +1,195 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- 辅助函数 ---
|
||||
|
||||
# 获取 Git 提交 ID
|
||||
get_git_commit_id() {
|
||||
if git rev-parse --is-inside-work-tree &>/dev/null; then
|
||||
git rev-parse --short HEAD 2>/dev/null || echo ""
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# 查找并设置一个可用的 loop 设备
|
||||
find_loop_device() {
|
||||
echo "信息:查找可用的 loop 设备..."
|
||||
# 只使用 --find 来获取设备名
|
||||
LOOPDEV=$(sudo losetup --find)
|
||||
if [[ -z "$LOOPDEV" || ! -e "$LOOPDEV" ]]; then
|
||||
echo "错误:再次尝试后仍无法找到可用的 loop 设备。" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "信息:找到可用 loop 设备名:$LOOPDEV"
|
||||
}
|
||||
|
||||
# 检查并创建目录
|
||||
ensure_dir() {
|
||||
if [[ ! -d "$1" ]]; then
|
||||
echo "信息:创建目录 $1 ..."
|
||||
sudo mkdir -p "$1" || { echo "错误:创建目录 $1 失败" >&2; exit 1; }
|
||||
fi
|
||||
}
|
||||
|
||||
# 执行 chroot 命令
|
||||
run_in_chroot() {
|
||||
echo "信息:在 chroot 环境 ($ROOTFS) 中执行命令..."
|
||||
sudo chroot --userspec "root:root" "$ROOTFS" bash -ec "$1" || { echo "错误:在 chroot 环境中执行命令失败" >&2; exit 1; }
|
||||
echo "信息:chroot 命令执行完成。"
|
||||
}
|
||||
|
||||
# --- 清理函数 ---
|
||||
cleanup() {
|
||||
echo "信息:执行清理操作..."
|
||||
# 尝试卸载 chroot 环境下的挂载点
|
||||
if [[ "$DEV_MOUNTED" -eq 1 ]]; then
|
||||
echo "信息:卸载 $ROOTFS/dev ..."
|
||||
sudo umount "$ROOTFS/dev" || echo "警告:卸载 $ROOTFS/dev 失败,可能已被卸载"
|
||||
DEV_MOUNTED=0
|
||||
fi
|
||||
if [[ "$SYS_MOUNTED" -eq 1 ]]; then
|
||||
echo "信息:卸载 $ROOTFS/sys ..."
|
||||
sudo umount "$ROOTFS/sys" || echo "警告:卸载 $ROOTFS/sys 失败,可能已被卸载"
|
||||
SYS_MOUNTED=0
|
||||
fi
|
||||
if [[ "$PROC_MOUNTED" -eq 1 ]]; then
|
||||
echo "信息:卸载 $ROOTFS/proc ..."
|
||||
sudo umount "$ROOTFS/proc" || echo "警告:卸载 $ROOTFS/proc 失败,可能已被卸载"
|
||||
PROC_MOUNTED=0
|
||||
fi
|
||||
|
||||
# 尝试卸载主根文件系统
|
||||
if [[ "$ROOTFS_MOUNTED" -eq 1 && -d "$ROOTFS" ]]; then
|
||||
echo "信息:卸载 $ROOTFS ..."
|
||||
sudo umount "$ROOTFS" || sudo umount -l "$ROOTFS" || echo "警告:卸载 $ROOTFS 失败"
|
||||
ROOTFS_MOUNTED=0
|
||||
fi
|
||||
# 尝试卸载引导文件系统 (如果使用)
|
||||
if [[ "$BOOTFS_MOUNTED" -eq 1 && -d "$BOOTFS" ]]; then
|
||||
echo "信息:卸载 $BOOTFS ..."
|
||||
sudo umount "$BOOTFS" || sudo umount -l "$BOOTFS" || echo "警告:卸载 $BOOTFS 失败"
|
||||
BOOTFS_MOUNTED=0
|
||||
fi
|
||||
|
||||
# 尝试分离 loop 设备
|
||||
if [[ -n "$LOOPDEV" && -b "$LOOPDEV" ]]; then
|
||||
echo "信息:尝试 zerofree $LOOPDEV ..."
|
||||
sudo zerofree "$LOOPDEV" || echo "警告:zerofree $LOOPDEV 失败,可能文件系统不支持或未干净卸载"
|
||||
echo "信息:分离 loop 设备 $LOOPDEV ..."
|
||||
sudo losetup -d "$LOOPDEV" || echo "警告:分离 $LOOPDEV 失败"
|
||||
LOOPDEV=""
|
||||
fi
|
||||
|
||||
# 尝试删除 Docker 容器
|
||||
echo "信息:检查并删除 Docker 容器 $DOCKER_CONTAINER_NAME ..."
|
||||
if sudo docker ps -a --format '{{.Names}}' | grep -q "^${DOCKER_CONTAINER_NAME}$"; then
|
||||
sudo docker rm -f "$DOCKER_CONTAINER_NAME" || echo "警告:删除 Docker 容器 $DOCKER_CONTAINER_NAME 失败"
|
||||
else
|
||||
echo "信息:Docker 容器 $DOCKER_CONTAINER_NAME 不存在或已被删除。"
|
||||
fi
|
||||
|
||||
# 清理临时目录和挂载点目录
|
||||
echo "信息:清理临时文件和目录..."
|
||||
sudo rm -rf "$PREBUILT_DIR"
|
||||
# 只删除挂载点目录本身
|
||||
if [[ -d "$ROOTFS" ]]; then
|
||||
sudo rmdir "$ROOTFS" || echo "警告:删除目录 $ROOTFS 失败,可能非空"
|
||||
fi
|
||||
if [[ -d "$BOOTFS" ]]; then
|
||||
sudo rmdir "$BOOTFS" || echo "警告:删除目录 $BOOTFS 失败,可能非空"
|
||||
fi
|
||||
|
||||
echo "信息:清理完成。"
|
||||
}
|
||||
|
||||
# 在打包镜像前调用此函数,确保干净卸载所有挂载点和loop设备
|
||||
unmount_all() {
|
||||
echo "信息:执行卸载操作,准备打包..."
|
||||
# 卸载 chroot 环境下的挂载点
|
||||
if [[ "$DEV_MOUNTED" -eq 1 ]]; then
|
||||
echo "信息:卸载 $ROOTFS/dev ..."
|
||||
sudo umount "$ROOTFS/dev" || echo "警告:卸载 $ROOTFS/dev 失败,可能已被卸载"
|
||||
DEV_MOUNTED=0
|
||||
fi
|
||||
if [[ "$SYS_MOUNTED" -eq 1 ]]; then
|
||||
echo "信息:卸载 $ROOTFS/sys ..."
|
||||
sudo umount "$ROOTFS/sys" || echo "警告:卸载 $ROOTFS/sys 失败,可能已被卸载"
|
||||
SYS_MOUNTED=0
|
||||
fi
|
||||
if [[ "$PROC_MOUNTED" -eq 1 ]]; then
|
||||
echo "信息:卸载 $ROOTFS/proc ..."
|
||||
sudo umount "$ROOTFS/proc" || echo "警告:卸载 $ROOTFS/proc 失败,可能已被卸载"
|
||||
PROC_MOUNTED=0
|
||||
fi
|
||||
|
||||
# 卸载主根文件系统
|
||||
if [[ "$ROOTFS_MOUNTED" -eq 1 && -d "$ROOTFS" ]]; then
|
||||
echo "信息:卸载 $ROOTFS ..."
|
||||
sudo umount "$ROOTFS" || sudo umount -l "$ROOTFS" || echo "警告:卸载 $ROOTFS 失败"
|
||||
ROOTFS_MOUNTED=0
|
||||
fi
|
||||
|
||||
# 尝试分离 loop 设备前执行 zerofree(如果文件系统支持)
|
||||
if [[ -n "$LOOPDEV" && -b "$LOOPDEV" ]]; then
|
||||
echo "信息:尝试 zerofree $LOOPDEV ..."
|
||||
sudo zerofree "$LOOPDEV" || echo "警告:zerofree $LOOPDEV 失败,可能文件系统不支持或未干净卸载"
|
||||
echo "信息:分离 loop 设备 $LOOPDEV ..."
|
||||
sudo losetup -d "$LOOPDEV" || echo "警告:分离 $LOOPDEV 失败"
|
||||
LOOPDEV=""
|
||||
fi
|
||||
|
||||
sudo rm -rf "$PREBUILT_DIR"
|
||||
|
||||
echo "信息:卸载操作完成,可以安全打包镜像。"
|
||||
}
|
||||
|
||||
# 挂载根文件系统
|
||||
mount_rootfs() {
|
||||
echo "信息:挂载根文件系统到 $ROOTFS ..."
|
||||
ensure_dir "$ROOTFS"
|
||||
sudo mount "$LOOPDEV" "$ROOTFS" || { echo "错误:挂载 $LOOPDEV 到 $ROOTFS 失败" >&2; exit 1; }
|
||||
ROOTFS_MOUNTED=1
|
||||
|
||||
echo "信息:挂载 proc, sys, dev 到 chroot 环境..."
|
||||
ensure_dir "$ROOTFS/proc"
|
||||
sudo mount -t proc proc "$ROOTFS/proc" || { echo "错误:挂载 proc 到 $ROOTFS/proc 失败" >&2; exit 1; }
|
||||
PROC_MOUNTED=1
|
||||
|
||||
ensure_dir "$ROOTFS/sys"
|
||||
sudo mount -t sysfs sys "$ROOTFS/sys" || { echo "错误:挂载 sys 到 $ROOTFS/sys 失败" >&2; exit 1; }
|
||||
SYS_MOUNTED=1
|
||||
|
||||
ensure_dir "$ROOTFS/dev"
|
||||
sudo mount -o bind /dev "$ROOTFS/dev" || { echo "错误:绑定挂载 /dev 到 $ROOTFS/dev 失败" >&2; exit 1; }
|
||||
DEV_MOUNTED=1
|
||||
echo "信息:根文件系统及虚拟文件系统挂载完成。"
|
||||
}
|
||||
|
||||
# 设置元数据
|
||||
write_meta() {
|
||||
local hostname="$1"
|
||||
echo "信息:在 chroot 环境中设置主机名/元数据为 $hostname ..."
|
||||
run_in_chroot "sed -i 's/localhost.localdomain/$hostname/g' /etc/kvmd/meta.yaml"
|
||||
}
|
||||
|
||||
# 检查必要的外部工具
|
||||
check_required_tools() {
|
||||
local required_tools="sudo docker losetup mount umount parted e2fsck resize2fs qemu-img curl tar python3 pip3 rsync git simg2img img2simg dd cat rm mkdir mv cp sed chmod chown ln grep printf id"
|
||||
|
||||
for cmd in $required_tools; do
|
||||
if ! command -v "$cmd" &> /dev/null; then
|
||||
echo "错误:必需的命令 '$cmd' 未找到。请安装相应软件包。" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# 检查特定工具 (如果脚本中使用了)
|
||||
if ! command -v "$SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64" &> /dev/null && [[ "$1" == "onecloud" || "$1" == "all" ]]; then
|
||||
if [ -f "$SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64" ]; then
|
||||
echo "信息:找到 AmlImg 工具,尝试设置执行权限..."
|
||||
sudo chmod +x "$SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64" || echo "警告:设置 AmlImg 执行权限失败"
|
||||
else
|
||||
echo "错误:构建 onecloud 需要 '$SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64',但未找到。" >&2
|
||||
fi
|
||||
fi
|
||||
}
|
||||
212
build/functions/devices.sh
Executable file
212
build/functions/devices.sh
Executable file
@@ -0,0 +1,212 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- 设备特定的 Rootfs 准备函数 ---
|
||||
|
||||
onecloud_rootfs() {
|
||||
local unpacker="$SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64"
|
||||
local source_image="$SRCPATH/image/onecloud/Armbian_by-SilentWind_24.5.0-trunk_Onecloud_bookworm_legacy_5.9.0-rc7_minimal.burn.img"
|
||||
local bootfs_img="$TMPDIR/bootfs.img"
|
||||
local rootfs_img="$TMPDIR/rootfs.img"
|
||||
local bootfs_sparse="$TMPDIR/6.boot.PARTITION.sparse"
|
||||
local rootfs_sparse="$TMPDIR/7.rootfs.PARTITION.sparse"
|
||||
local bootfs_loopdev="" # 存储 bootfs 使用的 loop 设备
|
||||
local add_size_mb=400
|
||||
|
||||
echo "信息:准备 Onecloud Rootfs..."
|
||||
ensure_dir "$TMPDIR"
|
||||
ensure_dir "$BOOTFS"
|
||||
|
||||
echo "信息:解包 Onecloud burn 镜像..."
|
||||
sudo "$unpacker" unpack "$source_image" "$TMPDIR" || { echo "错误:解包失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:转换 bootfs 和 rootfs sparse 镜像到 raw 格式..."
|
||||
sudo simg2img "$bootfs_sparse" "$bootfs_img" || { echo "错误:转换 bootfs sparse 镜像失败" >&2; exit 1; }
|
||||
sudo simg2img "$rootfs_sparse" "$rootfs_img" || { echo "错误:转换 rootfs sparse 镜像失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:挂载 bootfs 并修复 DTB..."
|
||||
find_loop_device # 查找一个 loop 设备给 bootfs
|
||||
bootfs_loopdev="$LOOPDEV" # 保存这个设备名
|
||||
echo "信息:将 $bootfs_img 关联到 $bootfs_loopdev..."
|
||||
sudo losetup "$bootfs_loopdev" "$bootfs_img" || { echo "错误:关联 bootfs 镜像到 $bootfs_loopdev 失败" >&2; exit 1; }
|
||||
sudo mount "$bootfs_loopdev" "$BOOTFS" || { echo "错误:挂载 bootfs ($bootfs_loopdev) 失败" >&2; exit 1; }
|
||||
BOOTFS_MOUNTED=1
|
||||
sudo cp "$SRCPATH/image/onecloud/meson8b-onecloud-fix.dtb" "$BOOTFS/dtb/meson8b-onecloud.dtb" || { echo "错误:复制修复后的 DTB 文件失败" >&2; exit 1; }
|
||||
sudo umount "$BOOTFS" || { echo "警告:卸载 bootfs ($BOOTFS) 失败" >&2; BOOTFS_MOUNTED=0; } # 卸载失败不应中断流程
|
||||
BOOTFS_MOUNTED=0
|
||||
echo "信息:分离 bootfs loop 设备 $bootfs_loopdev..."
|
||||
sudo losetup -d "$bootfs_loopdev" || { echo "警告:分离 bootfs loop 设备 $bootfs_loopdev 失败" >&2; }
|
||||
# bootfs_loopdev 对应的设备现在是空闲的
|
||||
|
||||
echo "信息:扩展 rootfs 镜像 (${add_size_mb}MB)..."
|
||||
sudo dd if=/dev/zero bs=1M count="$add_size_mb" >> "$rootfs_img" || { echo "错误:扩展 rootfs 镜像失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:检查并调整 rootfs 文件系统大小 (在文件上)..."
|
||||
# 注意:e2fsck/resize2fs 现在直接操作镜像文件,而不是 loop 设备
|
||||
sudo e2fsck -f -y "$rootfs_img" || { echo "警告:e2fsck 检查 rootfs 镜像文件失败" >&2; exit 1; }
|
||||
sudo resize2fs "$rootfs_img" || { echo "错误:resize2fs 调整 rootfs 镜像文件大小失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:设置 rootfs loop 设备..."
|
||||
find_loop_device # 重新查找一个可用的 loop 设备 (可能是刚才释放的那个)
|
||||
echo "信息:将 $rootfs_img 关联到 $LOOPDEV..."
|
||||
sudo losetup "$LOOPDEV" "$rootfs_img" || { echo "错误:关联 rootfs 镜像到 $LOOPDEV 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:Onecloud Rootfs 准备完成。 Loop 设备 $LOOPDEV 已关联 $rootfs_img"
|
||||
}
|
||||
|
||||
cumebox2_rootfs() {
|
||||
local source_image="$SRCPATH/image/cumebox2/Armbian_25.2.2_Khadas-vim1_bookworm_current_6.12.17_minimal.img"
|
||||
local target_image="$TMPDIR/rootfs.img"
|
||||
local offset=$((8192 * 512))
|
||||
|
||||
echo "信息:准备 Cumebox2 Rootfs..."
|
||||
ensure_dir "$TMPDIR"
|
||||
cp "$source_image" "$target_image" || { echo "错误:复制 Cumebox2 原始镜像失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:调整镜像分区大小..."
|
||||
sudo parted -s "$target_image" resizepart 1 100% || { echo "错误:使用 parted 调整分区大小失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:设置带偏移量的 loop 设备..."
|
||||
find_loop_device # 查找设备名
|
||||
echo "信息:将 $target_image (偏移 $offset) 关联到 $LOOPDEV..."
|
||||
sudo losetup --offset "$offset" "$LOOPDEV" "$target_image" || { echo "错误:设置带偏移量的 loop 设备 $LOOPDEV 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:检查并调整文件系统大小 (在 loop 设备上)..."
|
||||
sudo e2fsck -f -y "$LOOPDEV" || { echo "警告:e2fsck 检查 $LOOPDEV 失败" >&2; exit 1; }
|
||||
sudo resize2fs "$LOOPDEV" || { echo "错误:resize2fs 调整 $LOOPDEV 大小失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:Cumebox2 Rootfs 准备完成,loop 设备 $LOOPDEV 已就绪。"
|
||||
}
|
||||
|
||||
chainedbox_rootfs_and_fix_dtb() {
|
||||
local source_image="$SRCPATH/image/chainedbox/Armbian_24.11.0_rockchip_chainedbox_bookworm_6.1.112_server_2024.10.02_add800m.img"
|
||||
local target_image="$TMPDIR/rootfs.img"
|
||||
local boot_offset=$((32768 * 512))
|
||||
local rootfs_offset=$((1081344 * 512))
|
||||
local bootfs_loopdev=""
|
||||
|
||||
echo "信息:准备 Chainedbox Rootfs 并修复 DTB..."
|
||||
ensure_dir "$TMPDIR"; ensure_dir "$BOOTFS"
|
||||
cp "$source_image" "$target_image" || { echo "错误:复制 Chainedbox 原始镜像失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:挂载 boot 分区并修复 DTB..."
|
||||
find_loop_device # 找 loop 给 boot
|
||||
bootfs_loopdev="$LOOPDEV"
|
||||
echo "信息:将 $target_image (偏移 $boot_offset) 关联到 $bootfs_loopdev..."
|
||||
sudo losetup --offset "$boot_offset" "$bootfs_loopdev" "$target_image" || { echo "错误:设置 boot 分区 loop 设备 $bootfs_loopdev 失败" >&2; exit 1; }
|
||||
sudo mount "$bootfs_loopdev" "$BOOTFS" || { echo "错误:挂载 boot 分区 ($bootfs_loopdev) 失败" >&2; exit 1; }
|
||||
BOOTFS_MOUNTED=1
|
||||
sudo cp "$SRCPATH/image/chainedbox/rk3328-l1pro-1296mhz-fix.dtb" "$BOOTFS/dtb/rockchip/rk3328-l1pro-1296mhz.dtb" || { echo "错误:复制修复后的 DTB 文件失败" >&2; exit 1; }
|
||||
sudo umount "$BOOTFS" || { echo "警告:卸载 boot 分区 ($BOOTFS) 失败" >&2; BOOTFS_MOUNTED=0; }
|
||||
BOOTFS_MOUNTED=0
|
||||
echo "信息:分离 boot loop 设备 $bootfs_loopdev..."
|
||||
sudo losetup -d "$bootfs_loopdev" || { echo "警告:分离 boot 分区 loop 设备 $bootfs_loopdev 失败" >&2; }
|
||||
|
||||
echo "信息:设置 rootfs 分区的 loop 设备..."
|
||||
find_loop_device # 找 loop 给 rootfs
|
||||
echo "信息:将 $target_image (偏移 $rootfs_offset) 关联到 $LOOPDEV..."
|
||||
sudo losetup --offset "$rootfs_offset" "$LOOPDEV" "$target_image" || { echo "错误:设置 rootfs 分区 loop 设备 $LOOPDEV 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:Chainedbox Rootfs 准备完成,loop 设备 $LOOPDEV 已就绪。"
|
||||
}
|
||||
|
||||
vm_rootfs() {
|
||||
local source_image="$SRCPATH/image/vm/Armbian_25.2.1_Uefi-x86_bookworm_current_6.12.13_minimal.img"
|
||||
local target_image="$TMPDIR/rootfs.img"
|
||||
local offset=$((540672 * 512))
|
||||
|
||||
echo "信息:准备 Vm Rootfs..."
|
||||
ensure_dir "$TMPDIR"
|
||||
cp "$source_image" "$target_image" || { echo "错误:复制 Vm 原始镜像失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:设置带偏移量的 loop 设备..."
|
||||
find_loop_device # 查找设备名
|
||||
echo "信息:将 $target_image (偏移 $offset) 关联到 $LOOPDEV..."
|
||||
sudo losetup --offset "$offset" "$LOOPDEV" "$target_image" || { echo "错误:设置带偏移量的 loop 设备 $LOOPDEV 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:Vm Rootfs 准备完成,loop 设备 $LOOPDEV 已就绪。"
|
||||
}
|
||||
|
||||
e900v22c_rootfs() {
|
||||
local source_image="$SRCPATH/image/e900v22c/Armbian_23.08.0_amlogic_s905l3a_bookworm_5.15.123_server_2023.08.01.img"
|
||||
local target_image="$TMPDIR/rootfs.img"
|
||||
local offset=$((532480 * 512))
|
||||
local add_size_mb=400
|
||||
|
||||
echo "信息:准备 E900V22C Rootfs..."
|
||||
ensure_dir "$TMPDIR"
|
||||
cp "$source_image" "$target_image" || { echo "错误:复制 E900V22C 原始镜像失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:扩展镜像文件 (${add_size_mb}MB)..."
|
||||
sudo dd if=/dev/zero bs=1M count="$add_size_mb" >> "$target_image" || { echo "错误:扩展镜像文件失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:调整镜像分区大小 (分区 2)..."
|
||||
sudo parted -s "$target_image" resizepart 2 100% || { echo "错误:使用 parted 调整分区 2 大小失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:设置带偏移量的 loop 设备..."
|
||||
find_loop_device # 查找设备名
|
||||
echo "信息:将 $target_image (偏移 $offset) 关联到 $LOOPDEV..."
|
||||
sudo losetup --offset "$offset" "$LOOPDEV" "$target_image" || { echo "错误:设置带偏移量的 loop 设备 $LOOPDEV 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:检查并调整文件系统大小 (在 loop 设备上)..."
|
||||
sudo e2fsck -f -y "$LOOPDEV" || { echo "警告:e2fsck 检查 $LOOPDEV 失败" >&2; exit 1; }
|
||||
sudo resize2fs "$LOOPDEV" || { echo "错误:resize2fs 调整 $LOOPDEV 大小失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:E900V22C Rootfs 准备完成,loop 设备 $LOOPDEV 已就绪。"
|
||||
}
|
||||
|
||||
octopus_flanet_rootfs() {
|
||||
local source_image="$SRCPATH/image/octopus-flanet/Armbian_24.11.0_amlogic_s912_bookworm_6.1.114_server_2024.11.01.img"
|
||||
local target_image="$TMPDIR/rootfs.img"
|
||||
local boot_offset=$((8192 * 512))
|
||||
local rootfs_offset=$((1056768 * 512))
|
||||
local add_size_mb=400
|
||||
local bootfs_loopdev=""
|
||||
|
||||
echo "信息:准备 Octopus-Planet Rootfs..."
|
||||
ensure_dir "$TMPDIR"; ensure_dir "$BOOTFS"
|
||||
cp "$source_image" "$target_image" || { echo "错误:复制 Octopus-Planet 原始镜像失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:挂载 boot 分区并修改 uEnv.txt (使用 VIM2 DTB)..."
|
||||
find_loop_device # 找 loop 给 boot
|
||||
bootfs_loopdev="$LOOPDEV"
|
||||
echo "信息:将 $target_image (偏移 $boot_offset) 关联到 $bootfs_loopdev..."
|
||||
sudo losetup --offset "$boot_offset" "$bootfs_loopdev" "$target_image" || { echo "错误:设置 boot 分区 loop 设备 $bootfs_loopdev 失败" >&2; exit 1; }
|
||||
sudo mount "$bootfs_loopdev" "$BOOTFS" || { echo "错误:挂载 boot 分区 ($bootfs_loopdev) 失败" >&2; exit 1; }
|
||||
BOOTFS_MOUNTED=1
|
||||
sudo sed -i "s/meson-gxm-octopus-planet.dtb/meson-gxm-khadas-vim2.dtb/g" "$BOOTFS/uEnv.txt" || { echo "错误:修改 uEnv.txt 失败" >&2; exit 1; }
|
||||
sudo umount "$BOOTFS" || { echo "警告:卸载 boot 分区 ($BOOTFS) 失败" >&2; BOOTFS_MOUNTED=0; }
|
||||
BOOTFS_MOUNTED=0
|
||||
echo "信息:分离 boot loop 设备 $bootfs_loopdev..."
|
||||
sudo losetup -d "$bootfs_loopdev" || { echo "警告:分离 boot 分区 loop 设备 $bootfs_loopdev 失败" >&2; }
|
||||
|
||||
echo "信息:调整镜像分区大小 (分区 2)..."
|
||||
sudo parted -s "$target_image" resizepart 2 100% || { echo "错误:使用 parted 调整分区 2 大小失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:设置 rootfs 分区的 loop 设备..."
|
||||
find_loop_device # 找 loop 给 rootfs
|
||||
echo "信息:将 $target_image (偏移 $rootfs_offset) 关联到 $LOOPDEV..."
|
||||
sudo losetup --offset "$rootfs_offset" "$LOOPDEV" "$target_image" || { echo "错误:设置 rootfs 分区 loop 设备 $LOOPDEV 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:检查并调整文件系统大小 (在 loop 设备上)..."
|
||||
sudo e2fsck -f -y "$LOOPDEV" || { echo "警告:e2fsck 检查 $LOOPDEV 失败" >&2; exit 1; }
|
||||
sudo resize2fs "$LOOPDEV" || { echo "错误:resize2fs 调整 $LOOPDEV 大小失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:Octopus-Planet Rootfs 准备完成,loop 设备 $LOOPDEV 已就绪。"
|
||||
}
|
||||
|
||||
# --- 特定设备的文件配置函数 ---
|
||||
|
||||
config_cumebox2_files() {
|
||||
echo "信息:为 Cumebox2 配置特定文件 (OLED, DTB)..."
|
||||
ensure_dir "$ROOTFS/etc/oled"
|
||||
# 注意 DTB 路径可能需要根据实际 Armbian 版本调整
|
||||
sudo cp "$SRCPATH/image/cumebox2/v-fix.dtb" "$ROOTFS/boot/dtb/amlogic/meson-gxl-s905x-khadas-vim.dtb" || echo "警告:复制 Cumebox2 DTB 失败"
|
||||
sudo cp "$SRCPATH/image/cumebox2/ssd" "$ROOTFS/usr/bin/" || echo "警告:复制 Cumebox2 ssd 脚本失败"
|
||||
sudo chmod +x "$ROOTFS/usr/bin/ssd" || echo "警告:设置 ssd 脚本执行权限失败"
|
||||
sudo cp "$SRCPATH/image/cumebox2/config.json" "$ROOTFS/etc/oled/config.json" || echo "警告:复制 OLED 配置文件失败"
|
||||
}
|
||||
|
||||
config_octopus_flanet_files() {
|
||||
echo "信息:为 Octopus-Planet 配置特定文件 (model_database.conf)..."
|
||||
sudo cp "$SRCPATH/image/octopus-flanet/model_database.conf" "$ROOTFS/etc/model_database.conf" || echo "警告:复制 model_database.conf 失败"
|
||||
}
|
||||
313
build/functions/install.sh
Executable file
313
build/functions/install.sh
Executable file
@@ -0,0 +1,313 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- 预准备 ---
|
||||
|
||||
prepare_dns_and_mirrors() {
|
||||
echo "信息:在 chroot 环境中准备 DNS 和更换软件源..."
|
||||
run_in_chroot "
|
||||
mkdir -p /run/systemd/resolve/ \\
|
||||
&& touch /run/systemd/resolve/stub-resolv.conf \\
|
||||
&& printf '%s\\n' 'nameserver 1.1.1.1' 'nameserver 1.0.0.1' > /etc/resolv.conf \\
|
||||
&& echo '信息:尝试更换镜像源...' \\
|
||||
&& bash <(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh) \\
|
||||
--source mirrors.tuna.tsinghua.edu.cn --upgrade-software false --web-protocol http || echo '警告:更换镜像源脚本执行失败,可能网络不通或脚本已更改'
|
||||
"
|
||||
}
|
||||
|
||||
delete_armbian_verify(){
|
||||
echo "信息:在 chroot 环境中修改 Armbian 软件源..."
|
||||
run_in_chroot "echo 'deb http://mirrors.ustc.edu.cn/armbian bullseye main bullseye-utils bullseye-desktop' > /etc/apt/sources.list.d/armbian.list"
|
||||
}
|
||||
|
||||
prepare_external_binaries() {
|
||||
local platform="$1" # linux/armhf or linux/amd64 or linux/aarch64
|
||||
local docker_image="registry.cn-hangzhou.aliyuncs.com/silentwind/kvmd-stage-0"
|
||||
|
||||
echo "信息:准备外部预编译二进制文件 (平台: $platform)..."
|
||||
ensure_dir "$PREBUILT_DIR"
|
||||
|
||||
echo "信息:拉取 Docker 镜像 $docker_image (平台: $platform)..."
|
||||
sudo docker pull --platform "$platform" "$docker_image" || { echo "错误:拉取 Docker 镜像 $docker_image 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:创建 Docker 容器 $DOCKER_CONTAINER_NAME ..."
|
||||
sudo docker create --name "$DOCKER_CONTAINER_NAME" "$docker_image" || { echo "错误:创建 Docker 容器 $DOCKER_CONTAINER_NAME 失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:从 Docker 容器导出文件到 $PREBUILT_DIR ..."
|
||||
sudo docker export "$DOCKER_CONTAINER_NAME" | sudo tar -xf - -C "$PREBUILT_DIR" || { echo "错误:导出并解压 Docker 容器内容失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:预编译二进制文件准备完成,存放于 $PREBUILT_DIR"
|
||||
|
||||
# 删除 Docker 容器
|
||||
sudo docker rm -f "$DOCKER_CONTAINER_NAME" || { echo "错误:删除 Docker 容器 $DOCKER_CONTAINER_NAME 失败" >&2; exit 1; }
|
||||
}
|
||||
|
||||
config_base_files() {
|
||||
local platform_id="$1" # e.g., "onecloud", "cumebox2"
|
||||
echo "信息:配置基础文件和目录结构 ($platform_id)..."
|
||||
|
||||
echo "信息:创建 KVMD 相关目录..."
|
||||
ensure_dir "$ROOTFS/etc/kvmd/override.d"
|
||||
ensure_dir "$ROOTFS/etc/kvmd/vnc"
|
||||
ensure_dir "$ROOTFS/var/lib/kvmd/msd/images"
|
||||
ensure_dir "$ROOTFS/var/lib/kvmd/msd/meta"
|
||||
ensure_dir "$ROOTFS/opt/vc/bin"
|
||||
ensure_dir "$ROOTFS/usr/share/kvmd"
|
||||
ensure_dir "$ROOTFS/One-KVM"
|
||||
ensure_dir "$ROOTFS/usr/share/janus/javascript"
|
||||
ensure_dir "$ROOTFS/usr/lib/ustreamer/janus"
|
||||
ensure_dir "$ROOTFS/run/kvmd"
|
||||
ensure_dir "$ROOTFS/tmp/wheel/"
|
||||
ensure_dir "$ROOTFS/usr/lib/janus/transports/"
|
||||
ensure_dir "$ROOTFS/usr/lib/janus/loggers"
|
||||
|
||||
echo "信息:复制 One-KVM 源码..."
|
||||
sudo rsync -a --exclude={.git,.github,output,tmp} . "$ROOTFS/One-KVM/" || { echo "错误:复制 One-KVM 源码失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:复制配置文件..."
|
||||
sudo cp -r configs/kvmd/* configs/nginx configs/janus "$ROOTFS/etc/kvmd/"
|
||||
sudo cp -r web extras contrib/keymaps "$ROOTFS/usr/share/kvmd/"
|
||||
sudo cp testenv/fakes/vcgencmd "$ROOTFS/usr/bin/"
|
||||
sudo cp -r testenv/js/* "$ROOTFS/usr/share/janus/javascript/"
|
||||
sudo cp "build/platform/$platform_id" "$ROOTFS/usr/share/kvmd/platform" || { echo "错误:复制平台文件 build/platform/$platform_id 失败" >&2; exit 1; }
|
||||
sudo cp scripts/kvmd-gencert scripts/kvmd-bootconfig scripts/kvmd-certbot scripts/kvmd-udev-hdmiusb-check scripts/kvmd-udev-restart-pass build/scripts/kvmd-firstrun.sh "$ROOTFS/usr/bin/"
|
||||
sudo chmod +x "$ROOTFS/usr/bin/kvmd-gencert" "$ROOTFS/usr/bin/kvmd-bootconfig" "$ROOTFS/usr/bin/kvmd-certbot" "$ROOTFS/usr/bin/kvmd-udev-hdmiusb-check" "$ROOTFS/usr/bin/kvmd-udev-restart-pass" "$ROOTFS/usr/bin/kvmd-firstrun.sh"
|
||||
|
||||
if [ -f "$SRCPATH/image/$platform_id/rc.local" ]; then
|
||||
echo "信息:复制设备特定的 rc.local 文件..."
|
||||
sudo cp "$SRCPATH/image/$platform_id/rc.local" "$ROOTFS/etc/"
|
||||
fi
|
||||
|
||||
echo "信息:从预编译目录复制二进制文件和库..."
|
||||
sudo cp "$PREBUILT_DIR/tmp/lib/"* "$ROOTFS/lib/"*-linux-*/ || echo "警告:复制 /tmp/lib/* 失败,可能源目录或目标目录不存在或不匹配"
|
||||
sudo cp "$PREBUILT_DIR/tmp/ustreamer/ustreamer" "$PREBUILT_DIR/tmp/ustreamer/ustreamer-dump" "$PREBUILT_DIR/usr/bin/janus" "$ROOTFS/usr/bin/" || { echo "错误:复制 ustreamer/janus 二进制文件失败" >&2; exit 1; }
|
||||
sudo cp "$PREBUILT_DIR/tmp/ustreamer/janus/libjanus_ustreamer.so" "$ROOTFS/usr/lib/ustreamer/janus/" || { echo "错误:复制 libjanus_ustreamer.so 失败" >&2; exit 1; }
|
||||
sudo cp "$PREBUILT_DIR/tmp/wheel/"*.whl "$ROOTFS/tmp/wheel/" || { echo "错误:复制 Python wheel 文件失败" >&2; exit 1; }
|
||||
sudo cp "$PREBUILT_DIR/usr/lib/janus/transports/"* "$ROOTFS/usr/lib/janus/transports/" || { echo "错误:复制 Janus transports 失败" >&2; exit 1; }
|
||||
|
||||
# 禁用 apt-file
|
||||
if [ -f "$ROOTFS/etc/apt/apt.conf.d/50apt-file.conf" ]; then
|
||||
echo "信息:禁用 apt-file 配置..."
|
||||
sudo mv "$ROOTFS/etc/apt/apt.conf.d/50apt-file.conf" "$ROOTFS/etc/apt/apt.conf.d/50apt-file.conf.disabled"
|
||||
fi
|
||||
echo "信息:基础文件配置完成。"
|
||||
}
|
||||
|
||||
# --- KVMD 安装与配置 ---
|
||||
|
||||
install_base_packages() {
|
||||
echo "信息:在 chroot 环境中更新源并安装基础软件包..."
|
||||
run_in_chroot "
|
||||
apt-get update && \\
|
||||
apt install -y --no-install-recommends \\
|
||||
libxkbcommon-x11-0 nginx tesseract-ocr tesseract-ocr-eng tesseract-ocr-chi-sim \\
|
||||
iptables network-manager curl kmod libmicrohttpd12 libjansson4 libssl3 \\
|
||||
libsofia-sip-ua0 libglib2.0-0 libopus0 libogg0 libcurl4 libconfig9 \\
|
||||
python3-pip net-tools && \\
|
||||
apt clean && \\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
"
|
||||
}
|
||||
|
||||
configure_network() {
|
||||
local network_type="$1" # "systemd-networkd" or others (default network-manager)
|
||||
if [ "$network_type" = "systemd-networkd" ]; then
|
||||
echo "信息:在 chroot 环境中配置 systemd-networkd..."
|
||||
|
||||
# 检查是否为onecloud平台,如果是则使用随机MAC地址生成机制
|
||||
if [ "$TARGET_DEVICE_NAME" = "onecloud" ]; then
|
||||
echo "信息:为onecloud平台配置随机MAC地址生成机制..."
|
||||
|
||||
# 复制MAC地址生成脚本
|
||||
sudo cp "$SCRIPT_DIR/scripts/generate-random-mac.sh" "$ROOTFS/usr/local/bin/"
|
||||
sudo chmod +x "$ROOTFS/usr/local/bin/generate-random-mac.sh"
|
||||
|
||||
# 复制systemd服务文件
|
||||
sudo cp "$SCRIPT_DIR/services/kvmd-generate-mac.service" "$ROOTFS/etc/systemd/system/"
|
||||
|
||||
# 创建初始网络配置文件(不包含MAC地址,将由脚本生成)
|
||||
run_in_chroot "
|
||||
echo -e '[Match]\\nName=eth0\\n\\n[Network]\\nDHCP=yes' > /etc/systemd/network/99-eth0.network && \\
|
||||
systemctl mask NetworkManager && \\
|
||||
systemctl unmask systemd-networkd && \\
|
||||
systemctl enable systemd-networkd systemd-resolved && \\
|
||||
systemctl enable kvmd-generate-mac.service
|
||||
"
|
||||
echo "信息:onecloud随机MAC地址生成机制配置完成"
|
||||
fi
|
||||
else
|
||||
echo "信息:使用默认的网络管理器 (NetworkManager)..."
|
||||
# 可能需要确保 NetworkManager 是启用的 (通常默认是)
|
||||
run_in_chroot "systemctl enable NetworkManager"
|
||||
fi
|
||||
}
|
||||
|
||||
install_python_deps() {
|
||||
echo "信息:在 chroot 环境中安装 Python 依赖 (wheels)..."
|
||||
run_in_chroot "
|
||||
pip3 install --no-cache-dir --break-system-packages /tmp/wheel/*.whl && \\
|
||||
pip3 cache purge && \\
|
||||
rm -rf /tmp/wheel
|
||||
"
|
||||
}
|
||||
|
||||
configure_kvmd_core() {
|
||||
echo "信息:在 chroot 环境中安装和配置 KVMD 核心..."
|
||||
|
||||
# 复制KVMD首次运行脚本和服务
|
||||
echo "信息:配置KVMD首次运行初始化服务..."
|
||||
sudo cp "build/services/kvmd-firstrun.service" "$ROOTFS/etc/systemd/system/"
|
||||
|
||||
# 安装KVMD但不执行需要在首次运行时完成的操作
|
||||
run_in_chroot "
|
||||
cd /One-KVM && \\
|
||||
python3 setup.py install && \\
|
||||
systemctl enable kvmd-firstrun.service
|
||||
"
|
||||
|
||||
echo "信息:KVMD核心安装完成,证书生成等初始化操作将在首次开机时执行"
|
||||
}
|
||||
|
||||
configure_system() {
|
||||
echo "信息:在 chroot 环境中配置系统级设置 (sudoers, udev, services)..."
|
||||
run_in_chroot "
|
||||
cat /One-KVM/configs/os/sudoers/v2-hdmiusb >> /etc/sudoers && \\
|
||||
cat /One-KVM/configs/os/udev/v2-hdmiusb-rpi4.rules > /etc/udev/rules.d/99-kvmd.rules && \\
|
||||
echo 'libcomposite' >> /etc/modules && \\
|
||||
mv /usr/local/bin/kvmd* /usr/bin/ || echo '信息:/usr/local/bin/kvmd* 未找到或移动失败,可能已在/usr/bin' && \\
|
||||
cp /One-KVM/configs/os/services/* /etc/systemd/system/ && \\
|
||||
cp /One-KVM/configs/os/tmpfiles.conf /usr/lib/tmpfiles.d/ && \\
|
||||
mv /etc/kvmd/supervisord.conf /etc/supervisord.conf && \\
|
||||
chmod +x /etc/update-motd.d/* || echo '警告:chmod /etc/update-motd.d/* 失败' && \\
|
||||
echo 'kvmd ALL=(ALL) NOPASSWD: /etc/kvmd/custom_atx/gpio.sh' >> /etc/sudoers && \\
|
||||
echo 'kvmd ALL=(ALL) NOPASSWD: /etc/kvmd/custom_atx/usbrelay_hid.sh' >> /etc/sudoers && \\
|
||||
systemd-sysusers /One-KVM/configs/os/sysusers.conf && \\
|
||||
systemd-sysusers /One-KVM/configs/os/kvmd-webterm.conf && \\
|
||||
ln -sf /usr/share/tesseract-ocr/*/tessdata /usr/share/tessdata || echo '警告:创建 tesseract 链接失败' && \\
|
||||
sed -i 's/8080/80/g' /etc/kvmd/override.yaml && \\
|
||||
sed -i 's/4430/443/g' /etc/kvmd/override.yaml && \\
|
||||
chown kvmd -R /var/lib/kvmd/msd/ && \\
|
||||
systemctl enable kvmd kvmd-otg kvmd-nginx kvmd-vnc kvmd-ipmi kvmd-webterm kvmd-janus kvmd-media && \\
|
||||
systemctl disable nginx && \\
|
||||
rm -rf /One-KVM
|
||||
"
|
||||
}
|
||||
|
||||
install_webterm() {
|
||||
local arch="$1" # armhf, aarch64, x86_64
|
||||
local ttyd_arch="$arch"
|
||||
|
||||
if [ "$arch" = "armhf" ]; then
|
||||
ttyd_arch="armv7"
|
||||
elif [ "$arch" = "amd64" ]; then
|
||||
ttyd_arch="x86_64" # ttyd 通常用 x86_64
|
||||
fi
|
||||
|
||||
echo "信息:在 chroot 环境中下载并安装 ttyd ($ttyd_arch)..."
|
||||
run_in_chroot "
|
||||
curl -L https://gh.llkk.cc/https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.${ttyd_arch} -o /usr/bin/ttyd && \\
|
||||
chmod +x /usr/bin/ttyd && \\
|
||||
mkdir -p /home/kvmd-webterm && \\
|
||||
chown kvmd-webterm /home/kvmd-webterm
|
||||
"
|
||||
}
|
||||
|
||||
apply_kvmd_tweaks() {
|
||||
local arch="$1" # armhf, aarch64, x86_64
|
||||
local device_type="$2" # "gpio" or "video1" or other
|
||||
local atx_setting=""
|
||||
local hid_setting=""
|
||||
|
||||
echo "信息:根据架构 ($arch) 和设备类型 ($device_type) 调整 KVMD 配置..."
|
||||
|
||||
if [ "$arch" = "x86_64" ] || [ "$arch" = "amd64" ]; then
|
||||
echo "信息:目标平台为 x86_64/amd64 架构,禁用 OTG,设置 ATX 为 USBRELAY_HID..."
|
||||
run_in_chroot "
|
||||
systemctl disable kvmd-otg && \\
|
||||
sed -i 's/^ATX=.*/ATX=USBRELAY_HID/' /etc/kvmd/atx.sh && \\
|
||||
sed -i 's/device: \/dev\/ttyUSB0/device: \/dev\/kvmd-hid/g' /etc/kvmd/override.yaml
|
||||
"
|
||||
else
|
||||
echo "信息::目标平台为 ARM 架构 ($arch)..."
|
||||
# ARM 架构,配置 HID 为 OTG
|
||||
hid_setting="otg"
|
||||
run_in_chroot "
|
||||
sed -i 's/#type: otg/type: otg/g' /etc/kvmd/override.yaml && \\
|
||||
sed -i 's/device: \/dev\/ttyUSB0/#device: \/dev\/ttyUSB0/g' /etc/kvmd/override.yaml # 注释掉 ttyUSB0
|
||||
"
|
||||
echo "信息:设置 HID 为 $hid_setting"
|
||||
run_in_chroot "sed -i 's/type: ch9329/type: $hid_setting/g' /etc/kvmd/override.yaml"
|
||||
|
||||
|
||||
# 根据 device_type 配置 ATX
|
||||
if [ "$device_type" = "gpio" ]; then
|
||||
echo "信息:电源控制设备类型为 gpio,设置 ATX 为 GPIO 并配置引脚..."
|
||||
atx_setting="GPIO"
|
||||
run_in_chroot "
|
||||
sed -i 's/^ATX=.*/ATX=GPIO/' /etc/kvmd/atx.sh && \\
|
||||
sed -i 's/SHUTDOWNPIN/gpiochip1 7/g' /etc/kvmd/custom_atx/gpio.sh && \\
|
||||
sed -i 's/REBOOTPIN/gpiochip0 11/g' /etc/kvmd/custom_atx/gpio.sh
|
||||
"
|
||||
else
|
||||
echo "信息:电源控制设备类型不是 gpio ($device_type),设置 ATX 为 USBRELAY_HID..."
|
||||
atx_setting="USBRELAY_HID"
|
||||
run_in_chroot "sed -i 's/^ATX=.*/ATX=USBRELAY_HID/' /etc/kvmd/atx.sh"
|
||||
fi
|
||||
|
||||
# 配置视频设备
|
||||
if [ "$device_type" = "video1" ]; then
|
||||
echo "信息:视频设备类型为 video1,设置视频设备为 /dev/video1..."
|
||||
run_in_chroot "sed -i 's|/dev/video0|/dev/video1|g' /etc/kvmd/override.yaml"
|
||||
elif [ "$device_type" = "kvmd-video" ]; then
|
||||
echo "信息:视频设备类型为 kvmd-video,设置视频设备为 /dev/kvmd-video..."
|
||||
run_in_chroot "sed -i 's|/dev/video0|/dev/kvmd-video|g' /etc/kvmd/override.yaml"
|
||||
else
|
||||
echo "信息:使用默认视频设备 /dev/video0..."
|
||||
fi
|
||||
fi
|
||||
echo "信息:KVMD 配置调整完成。"
|
||||
}
|
||||
|
||||
# --- 整体安装流程 ---
|
||||
install_and_configure_kvmd() {
|
||||
local arch="$1" # 架构: armhf, aarch64, x86_64/amd64
|
||||
local device_type="$2" # 设备特性: "gpio", "video1", "" (空或其他)
|
||||
local network_type="$3" # 网络配置: "systemd-networkd", "" (默认 network-manager)
|
||||
local host_arch="" # Docker 平台架构: arm, aarch64, amd64
|
||||
|
||||
# 映射架构名称
|
||||
case "$arch" in
|
||||
armhf) host_arch="arm" ;;
|
||||
aarch64) host_arch="arm64" ;; # docker aarch64 平台名是 arm64
|
||||
x86_64|amd64) host_arch="amd64"; arch="x86_64" ;; # 统一内部使用 x86_64
|
||||
*) echo "错误:不支持的架构 $arch"; exit 1 ;;
|
||||
esac
|
||||
|
||||
|
||||
prepare_external_binaries "linux/$host_arch"
|
||||
config_base_files "$TARGET_DEVICE_NAME" # 使用全局变量传递设备名
|
||||
|
||||
# 特定设备的额外文件配置 (如果存在)
|
||||
if declare -f "config_${TARGET_DEVICE_NAME}_files" > /dev/null; then
|
||||
echo "信息:执行特定设备的文件配置函数 config_${TARGET_DEVICE_NAME}_files ..."
|
||||
"config_${TARGET_DEVICE_NAME}_files"
|
||||
fi
|
||||
|
||||
# 某些镜像可能需要准备DNS和换源
|
||||
if [[ "$NEED_PREPARE_DNS" = true ]]; then
|
||||
prepare_dns_and_mirrors
|
||||
fi
|
||||
# 可选:强制使用特定armbian源
|
||||
# delete_armbian_verify
|
||||
|
||||
# 执行安装步骤
|
||||
install_base_packages
|
||||
configure_network "$network_type"
|
||||
install_python_deps
|
||||
configure_kvmd_core
|
||||
configure_system
|
||||
install_webterm "$arch" # 传递原始架构名给ttyd下载
|
||||
apply_kvmd_tweaks "$arch" "$device_type"
|
||||
|
||||
run_in_chroot "df -h" # 显示最终磁盘使用情况
|
||||
echo "信息:One-KVM 安装和配置完成。"
|
||||
}
|
||||
65
build/functions/packaging.sh
Executable file
65
build/functions/packaging.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- 打包函数 ---
|
||||
|
||||
pack_img() {
|
||||
local device_name_friendly="$1" # e.g., "Vm", "Cumebox2"
|
||||
local target_img_name="One-KVM_by-SilentWind_${device_name_friendly}_${DATE}.img"
|
||||
local source_img="$TMPDIR/rootfs.img"
|
||||
|
||||
echo "信息:开始打包镜像 ($device_name_friendly)..."
|
||||
ensure_dir "$OUTPUTDIR"
|
||||
|
||||
# 确保在打包前已经正确卸载了所有挂载点和loop设备
|
||||
if [[ "$ROOTFS_MOUNTED" -eq 1 || "$DEV_MOUNTED" -eq 1 || "$SYS_MOUNTED" -eq 1 || "$PROC_MOUNTED" -eq 1 || -n "$LOOPDEV" && -b "$LOOPDEV" ]]; then
|
||||
echo "警告:发现未卸载的挂载点或loop设备,尝试再次卸载..."
|
||||
unmount_all
|
||||
fi
|
||||
|
||||
echo "信息:移动镜像文件 $source_img 到 $OUTPUTDIR/$target_img_name ..."
|
||||
sudo mv "$source_img" "$OUTPUTDIR/$target_img_name" || { echo "错误:移动镜像文件失败" >&2; exit 1; }
|
||||
|
||||
if [ "$device_name_friendly" = "Vm" ]; then
|
||||
echo "信息:为 Vm 目标转换镜像格式 (vmdk, vdi)..."
|
||||
local raw_img="$OUTPUTDIR/$target_img_name"
|
||||
local vmdk_img="$OUTPUTDIR/One-KVM_by-SilentWind_Vmare-uefi_${DATE}.vmdk"
|
||||
local vdi_img="$OUTPUTDIR/One-KVM_by-SilentWind_Virtualbox-uefi_${DATE}.vdi"
|
||||
|
||||
echo "信息:转换为 VMDK..."
|
||||
sudo qemu-img convert -f raw -O vmdk "$raw_img" "$vmdk_img" || echo "警告:转换为 VMDK 失败"
|
||||
echo "信息:转换为 VDI..."
|
||||
sudo qemu-img convert -f raw -O vdi "$raw_img" "$vdi_img" || echo "警告:转换为 VDI 失败"
|
||||
fi
|
||||
echo "信息:镜像打包完成: $OUTPUTDIR/$target_img_name"
|
||||
}
|
||||
|
||||
pack_img_onecloud() {
|
||||
local target_img_name="One-KVM_by-SilentWind_Onecloud_${DATE}.burn.img"
|
||||
local rootfs_raw_img="$TMPDIR/rootfs.img"
|
||||
local rootfs_sparse_img="$TMPDIR/7.rootfs.PARTITION.sparse"
|
||||
local aml_packer="$SRCPATH/image/onecloud/AmlImg_v0.3.1_linux_amd64"
|
||||
|
||||
echo "信息:开始为 Onecloud 打包 burn 镜像..."
|
||||
ensure_dir "$OUTPUTDIR"
|
||||
|
||||
# 确保在打包前已经正确卸载了所有挂载点和loop设备
|
||||
if [[ "$ROOTFS_MOUNTED" -eq 1 || "$DEV_MOUNTED" -eq 1 || "$SYS_MOUNTED" -eq 1 || "$PROC_MOUNTED" -eq 1 || -n "$LOOPDEV" && -b "$LOOPDEV" ]]; then
|
||||
echo "警告:发现未卸载的挂载点或loop设备,尝试再次卸载..."
|
||||
unmount_all
|
||||
fi
|
||||
|
||||
echo "信息:将 raw rootfs 转换为 sparse image..."
|
||||
# 先删除可能存在的旧 sparse 文件
|
||||
sudo rm -f "$rootfs_sparse_img"
|
||||
sudo img2simg "$rootfs_raw_img" "$rootfs_sparse_img" || { echo "错误:img2simg 转换失败" >&2; exit 1; }
|
||||
sudo rm "$rootfs_raw_img" # 删除 raw 文件,因为它已被转换
|
||||
|
||||
echo "信息:使用 AmlImg 工具打包..."
|
||||
sudo chmod +x "$aml_packer"
|
||||
sudo "$aml_packer" pack "$OUTPUTDIR/$target_img_name" "$TMPDIR/" || { echo "错误:AmlImg 打包失败" >&2; exit 1; }
|
||||
|
||||
echo "信息:清理 Onecloud 临时文件..."
|
||||
sudo rm -f "$TMPDIR/6.boot.PARTITION.sparse" "$TMPDIR/7.rootfs.PARTITION.sparse" "$TMPDIR/dts.img"
|
||||
|
||||
echo "信息:Onecloud burn 镜像打包完成: $OUTPUTDIR/$target_img_name"
|
||||
}
|
||||
@@ -109,7 +109,7 @@ if [ ! -f /etc/kvmd/.init_flag ]; then
|
||||
log_info "已禁用 WebTerm 功能"
|
||||
rm -r /usr/share/kvmd/extras/webterm
|
||||
else
|
||||
cat >> /etc/supervisord.conf << EOF
|
||||
cat >> /etc/kvmd/supervisord.conf << EOF
|
||||
|
||||
[program:kvmd-webterm]
|
||||
command=/usr/local/bin/ttyd --interface=/run/kvmd/ttyd.sock --port=0 --writable /bin/bash -c '/etc/kvmd/armbain-motd; bash'
|
||||
@@ -125,14 +125,14 @@ EOF
|
||||
fi
|
||||
|
||||
if [ "$NOWEBTERMWRITE" == "1" ]; then
|
||||
sed -i "s/--writable//g" /etc/supervisord.conf
|
||||
sed -i "s/--writable//g" /etc/kvmd/supervisord.conf
|
||||
fi
|
||||
|
||||
if [ "$NOVNC" == "1" ]; then
|
||||
log_info "已禁用 VNC 功能"
|
||||
rm -r /usr/share/kvmd/extras/vnc
|
||||
else
|
||||
cat >> /etc/supervisord.conf << EOF
|
||||
cat >> /etc/kvmd/supervisord.conf << EOF
|
||||
|
||||
[program:kvmd-vnc]
|
||||
command=python -m kvmd.apps.vnc --run
|
||||
@@ -151,7 +151,7 @@ EOF
|
||||
log_info "已禁用IPMI功能"
|
||||
rm -r /usr/share/kvmd/extras/ipmi
|
||||
else
|
||||
cat >> /etc/supervisord.conf << EOF
|
||||
cat >> /etc/kvmd/supervisord.conf << EOF
|
||||
|
||||
[program:kvmd-ipmi]
|
||||
command=python -m kvmd.apps.ipmi --run
|
||||
@@ -241,4 +241,4 @@ if [ "$OTG" == "1" ]; then
|
||||
fi
|
||||
|
||||
log_info "One-KVM 配置文件准备完成,正在启动服务..."
|
||||
exec supervisord -c /etc/supervisord.conf
|
||||
exec supervisord -c /etc/kvmd/supervisord.conf
|
||||
64
build/scripts/generate-random-mac.sh
Normal file
64
build/scripts/generate-random-mac.sh
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 为onecloud平台生成随机MAC地址的一次性脚本
|
||||
# 此脚本在首次开机时执行,为eth0网卡生成并应用随机MAC地址
|
||||
|
||||
set -e
|
||||
|
||||
NETWORK_CONFIG="/etc/systemd/network/99-eth0.network"
|
||||
LOCK_FILE="/var/lib/kvmd/.mac-generated"
|
||||
|
||||
# 检查是否已经执行过
|
||||
if [ -f "$LOCK_FILE" ]; then
|
||||
echo "MAC地址已经生成过,跳过执行"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 生成随机MAC地址 (使用本地管理的MAC地址前缀)
|
||||
generate_random_mac() {
|
||||
# 使用本地管理的MAC地址前缀 (第二位设为2、6、A、E中的一个)
|
||||
# 这样可以避免与真实硬件MAC地址冲突
|
||||
printf "02:%02x:%02x:%02x:%02x:%02x\n" \
|
||||
$((RANDOM % 256)) \
|
||||
$((RANDOM % 256)) \
|
||||
$((RANDOM % 256)) \
|
||||
$((RANDOM % 256)) \
|
||||
$((RANDOM % 256))
|
||||
}
|
||||
|
||||
echo "正在为onecloud生成随机MAC地址..."
|
||||
|
||||
# 生成新的MAC地址
|
||||
NEW_MAC=$(generate_random_mac)
|
||||
echo "生成的MAC地址: $NEW_MAC"
|
||||
|
||||
# 备份原配置文件
|
||||
if [ -f "$NETWORK_CONFIG" ]; then
|
||||
cp "$NETWORK_CONFIG" "${NETWORK_CONFIG}.backup"
|
||||
fi
|
||||
|
||||
# 更新网络配置文件
|
||||
cat > "$NETWORK_CONFIG" << EOF
|
||||
[Match]
|
||||
Name=eth0
|
||||
|
||||
[Network]
|
||||
DHCP=yes
|
||||
|
||||
[Link]
|
||||
MACAddress=$NEW_MAC
|
||||
EOF
|
||||
|
||||
echo "已更新网络配置文件: $NETWORK_CONFIG"
|
||||
|
||||
# 创建锁定文件,防止重复执行
|
||||
mkdir -p "$(dirname "$LOCK_FILE")"
|
||||
echo "MAC地址生成时间: $(date)" > "$LOCK_FILE"
|
||||
|
||||
# 禁用此服务,确保只运行一次
|
||||
systemctl disable kvmd-generate-mac.service
|
||||
|
||||
echo "随机MAC地址生成完成: $NEW_MAC"
|
||||
echo "服务已自动禁用,下次开机不会再执行"
|
||||
|
||||
exit 0
|
||||
34
build/scripts/kvmd-firstrun.sh
Normal file
34
build/scripts/kvmd-firstrun.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
# KVMD首次运行初始化脚本
|
||||
# 在首次开机时执行KVMD服务启动前的必要初始化操作
|
||||
|
||||
set -e
|
||||
|
||||
LOCK_FILE="/var/lib/kvmd/.kvmd-firstrun-completed"
|
||||
|
||||
# 检查是否已经执行过
|
||||
[ -f "$LOCK_FILE" ] && { echo "[KVMD-FirstRun] 初始化已完成,跳过执行"; exit 0; }
|
||||
|
||||
echo "[KVMD-FirstRun] 开始KVMD首次运行初始化..."
|
||||
|
||||
# 1. 生成KVMD主证书
|
||||
echo "[KVMD-FirstRun] 生成KVMD主证书..."
|
||||
kvmd-gencert --do-the-thing
|
||||
|
||||
# 2. 生成VNC证书
|
||||
echo "[KVMD-FirstRun] 生成VNC证书..."
|
||||
kvmd-gencert --do-the-thing --vnc
|
||||
|
||||
# 3. 生成nginx配置文件
|
||||
echo "[KVMD-FirstRun] 生成nginx配置文件..."
|
||||
kvmd-nginx-mkconf /etc/kvmd/nginx/nginx.conf.mako /etc/kvmd/nginx/nginx.conf || echo "[KVMD-FirstRun] 警告: nginx配置生成失败"
|
||||
|
||||
# 创建锁定文件
|
||||
mkdir -p "$(dirname "$LOCK_FILE")"
|
||||
echo "KVMD首次运行初始化完成 - $(date)" > "$LOCK_FILE"
|
||||
|
||||
# 禁用服务
|
||||
systemctl disable kvmd-firstrun.service || echo "[KVMD-FirstRun] 警告: 服务禁用失败"
|
||||
|
||||
echo "[KVMD-FirstRun] 初始化完成!"
|
||||
26
build/services/kvmd-firstrun.service
Normal file
26
build/services/kvmd-firstrun.service
Normal file
@@ -0,0 +1,26 @@
|
||||
[Unit]
|
||||
Description=KVMD First Run Initialization (One-time)
|
||||
Documentation=https://github.com/your-repo/One-KVM
|
||||
Before=kvmd.service
|
||||
Before=kvmd-nginx.service
|
||||
Before=kvmd-otg.service
|
||||
Before=kvmd-vnc.service
|
||||
Before=kvmd-ipmi.service
|
||||
Before=kvmd-webterm.service
|
||||
Before=kvmd-janus.service
|
||||
Before=kvmd-media.service
|
||||
After=local-fs.target
|
||||
After=network.target
|
||||
Wants=local-fs.target
|
||||
ConditionPathExists=!/var/lib/kvmd/.kvmd-firstrun-completed
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/kvmd-firstrun.sh
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
TimeoutStartSec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
18
build/services/kvmd-generate-mac.service
Normal file
18
build/services/kvmd-generate-mac.service
Normal file
@@ -0,0 +1,18 @@
|
||||
[Unit]
|
||||
Description=Generate Random MAC Address for OneCloud (One-time)
|
||||
Documentation=https://github.com/your-repo/One-KVM
|
||||
Before=systemd-networkd.service
|
||||
Before=network-pre.target
|
||||
Wants=network-pre.target
|
||||
After=local-fs.target
|
||||
ConditionPathExists=!/var/lib/kvmd/.mac-generated
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/generate-random-mac.sh
|
||||
RemainAfterExit=yes
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,5 +1,5 @@
|
||||
general: {
|
||||
debug_level = 2
|
||||
debug_level = 4
|
||||
}
|
||||
nat: {
|
||||
nice_debug = false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
video: {
|
||||
sink = "kvmd::ustreamer::h264"
|
||||
}
|
||||
audio: {
|
||||
acap: {
|
||||
device = "hw:0"
|
||||
tc358743 = "/dev/video0"
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ kvmd:
|
||||
forever: true
|
||||
|
||||
desired_fps:
|
||||
default: 30
|
||||
default: 60
|
||||
max: 60
|
||||
|
||||
h264_bitrate:
|
||||
|
||||
33
supervisord.conf
Normal file
33
supervisord.conf
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
[program:kvmd-webterm]
|
||||
command=/usr/local/bin/ttyd --interface=/run/kvmd/ttyd.sock --port=0 --writable /bin/bash -c '/etc/kvmd/armbain-motd; bash'
|
||||
directory=/
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=14
|
||||
stopasgroup=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes = 0
|
||||
redirect_stderr=true
|
||||
|
||||
[program:kvmd-vnc]
|
||||
command=python -m kvmd.apps.vnc --run
|
||||
directory=/
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=11
|
||||
stopasgroup=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes = 0
|
||||
redirect_stderr=true
|
||||
|
||||
[program:kvmd-ipmi]
|
||||
command=python -m kvmd.apps.ipmi --run
|
||||
directory=/
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=12
|
||||
stopasgroup=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes = 0
|
||||
redirect_stderr=true
|
||||
Reference in New Issue
Block a user