mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
v2 beta
This commit is contained in:
parent
6e9a3222ce
commit
940989b6e9
@ -15,6 +15,6 @@ search = version="{current_version}"
|
||||
replace = version="{new_version}"
|
||||
|
||||
[bumpversion:file:PKGBUILD]
|
||||
search = pkgver="{current_version}"
|
||||
replace = pkgver="{new_version}"
|
||||
search = pkgver={current_version}
|
||||
replace = pkgver={new_version}
|
||||
|
||||
|
||||
@ -20,7 +20,8 @@ all:
|
||||
|
||||
|
||||
run:
|
||||
docker build --rm --tag $(TESTENV_IMAGE) -f testenv/Dockerfile .
|
||||
sudo modprobe loop
|
||||
docker build $(TESTENV_OPTS) --rm --tag $(TESTENV_IMAGE) -f testenv/Dockerfile .
|
||||
- docker run --rm \
|
||||
--volume `pwd`/kvmd:/kvmd:ro \
|
||||
--volume `pwd`/web:/usr/share/kvmd/web:ro \
|
||||
|
||||
@ -2,26 +2,26 @@
|
||||
# Author: Maxim Devaev <mdevaev@gmail.com>
|
||||
|
||||
|
||||
pkgname="kvmd"
|
||||
pkgver="0.66"
|
||||
pkgrel="1"
|
||||
pkgname=kvmd
|
||||
pkgver=0.66
|
||||
pkgrel=1
|
||||
pkgdesc="The main Pi-KVM daemon"
|
||||
arch=("any")
|
||||
url="https://github.com/pi-kvm/pi-kvm"
|
||||
license=("GPL")
|
||||
license=(GPL)
|
||||
arch=(any)
|
||||
depends=(
|
||||
"python"
|
||||
"python-yaml"
|
||||
"python-aiohttp"
|
||||
"python-aiofiles"
|
||||
"python-pyudev"
|
||||
"python-raspberry-gpio"
|
||||
"python-pyserial"
|
||||
"python-setproctitle"
|
||||
python
|
||||
python-yaml
|
||||
python-aiohttp
|
||||
python-aiofiles
|
||||
python-pyudev
|
||||
python-raspberry-gpio
|
||||
python-pyserial
|
||||
python-setproctitle
|
||||
)
|
||||
makedepends=("python-setuptools")
|
||||
makedepends=(python-setuptools)
|
||||
source=("$url/archive/v$pkgver.tar.gz")
|
||||
md5sums=("SKIP")
|
||||
md5sums=(SKIP)
|
||||
|
||||
|
||||
build() {
|
||||
@ -34,9 +34,9 @@ build() {
|
||||
|
||||
package() {
|
||||
cd $srcdir/$pkgname-build
|
||||
python setup.py install --root=$pkgdir
|
||||
install -Dm644 configs/kvmd.service "$pkgdir"/usr/lib/systemd/system/kvmd.service
|
||||
mkdir -p "$pkgdir"/usr/share/kvmd
|
||||
cp -r web "$pkgdir"/usr/share/kvmd
|
||||
cp -r configs "$pkgdir"/usr/share/kvmd
|
||||
python setup.py install --root="$pkgdir"
|
||||
install -Dm644 configs/kvmd.service "$pkgdir/usr/lib/systemd/system/kvmd.service"
|
||||
mkdir -p "$pkgdir/usr/share/kvmd"
|
||||
cp -r web "$pkgdir/usr/share/kvmd"
|
||||
cp -r configs "$pkgdir/usr/share/kvmd"
|
||||
}
|
||||
|
||||
@ -36,15 +36,21 @@ kvmd:
|
||||
init_restart_after: 1.0
|
||||
shutdown_delay: 10.0
|
||||
|
||||
resolutions:
|
||||
- 800x600 - 720x576
|
||||
quality: 80
|
||||
|
||||
cmd:
|
||||
- "/usr/bin/mjpg_streamer"
|
||||
- "-i"
|
||||
- "input_uvc.so -d /dev/kvmd-streamer -e 2 -t pal -y -n -r {resolution}"
|
||||
- "-o"
|
||||
- "output_http.so -l localhost -p 8082"
|
||||
- "/usr/bin/ustreamer"
|
||||
- "--device=/dev/kvmd-streamer"
|
||||
- "--tv-standard=pal"
|
||||
- "--format=yuyv"
|
||||
- "--encoder=omx"
|
||||
- "--jpeg-quality={quality}"
|
||||
- "--width=720"
|
||||
- "--height=576"
|
||||
- "--fake-width=800"
|
||||
- "--fake-height=600"
|
||||
- "--host=localhost"
|
||||
- "--port=8082"
|
||||
|
||||
logging:
|
||||
version: 1
|
||||
|
||||
72
kvmd/configs/kvmd/v2.yaml
Normal file
72
kvmd/configs/kvmd/v2.yaml
Normal file
@ -0,0 +1,72 @@
|
||||
kvmd:
|
||||
server:
|
||||
host: localhost
|
||||
port: 8081
|
||||
heartbeat: 3.0
|
||||
|
||||
hid:
|
||||
device: /dev/ttyAMA0
|
||||
speed: 115200
|
||||
|
||||
atx:
|
||||
pinout:
|
||||
power_led: 16
|
||||
hdd_led: 12
|
||||
power_switch: 26
|
||||
reset_switch: 20
|
||||
|
||||
click_delay: 0.1
|
||||
long_click_delay: 5.5
|
||||
|
||||
state_poll: 0.1
|
||||
|
||||
msd:
|
||||
device: "/dev/kvmd-msd"
|
||||
init_delay: 2.0
|
||||
write_meta: true
|
||||
chunk_size: 65536
|
||||
|
||||
streamer:
|
||||
pinout:
|
||||
cap: -1
|
||||
conv: -1
|
||||
|
||||
sync_delay: 0.0
|
||||
init_delay: 1.0
|
||||
init_restart_after: 0.0
|
||||
shutdown_delay: 10.0
|
||||
|
||||
quality: 80
|
||||
|
||||
cmd:
|
||||
- "/usr/bin/ustreamer"
|
||||
- "--device=/dev/kvmd-streamer"
|
||||
- "--format=uyvy"
|
||||
- "--encoder=omx"
|
||||
- "--jpeg-quality={quality}"
|
||||
- "--dv-timings"
|
||||
- "--host=localhost"
|
||||
- "--port=8082"
|
||||
|
||||
logging:
|
||||
version: 1
|
||||
disable_existing_loggers: false
|
||||
|
||||
formatters:
|
||||
console:
|
||||
(): logging.Formatter
|
||||
style: "{"
|
||||
datefmt: "%H:%M:%S"
|
||||
format: "[{asctime}] {name:20.20} {levelname:>7} --- {message}"
|
||||
|
||||
handlers:
|
||||
console:
|
||||
level: DEBUG
|
||||
class: logging.StreamHandler
|
||||
stream: ext://sys.stdout
|
||||
formatter: console
|
||||
|
||||
root:
|
||||
level: INFO
|
||||
handlers:
|
||||
- console
|
||||
@ -31,7 +31,7 @@ http {
|
||||
server localhost:8081 fail_timeout=0s max_fails=0;
|
||||
}
|
||||
|
||||
upstream mjpg_streamer {
|
||||
upstream ustreamer {
|
||||
server localhost:8082 fail_timeout=0s max_fails=0;
|
||||
}
|
||||
|
||||
@ -112,9 +112,9 @@ http {
|
||||
include /etc/nginx/proxy-params.conf;
|
||||
}
|
||||
|
||||
location ~ ^/streamer/(snapshot|stream)(?:/(.*))?$ {
|
||||
rewrite /streamer/?(.*)(?:/(.*))?$ /?action=$1 break;
|
||||
proxy_pass http://mjpg_streamer;
|
||||
location /streamer {
|
||||
rewrite /streamer/?(.*) /$1 break;
|
||||
proxy_pass http://ustreamer;
|
||||
include /etc/nginx/proxy-params.conf;
|
||||
proxy_buffering off;
|
||||
proxy_ignore_headers X-Accel-Buffering;
|
||||
|
||||
@ -49,7 +49,7 @@ def main() -> None:
|
||||
sync_delay=float(config["streamer"]["sync_delay"]),
|
||||
init_delay=float(config["streamer"]["init_delay"]),
|
||||
init_restart_after=float(config["streamer"]["init_restart_after"]),
|
||||
resolutions=config["streamer"]["resolutions"],
|
||||
quality=int(config["streamer"]["quality"]),
|
||||
cmd=list(map(str, config["streamer"]["cmd"])),
|
||||
loop=loop,
|
||||
)
|
||||
|
||||
@ -128,7 +128,7 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
self.__system_tasks: List[asyncio.Task] = []
|
||||
|
||||
self.__reset_streamer = False
|
||||
self.__streamer_resolution = streamer.get_current_resolution()
|
||||
self.__streamer_quality = streamer.get_current_quality()
|
||||
|
||||
def run(self, host: str, port: int) -> None:
|
||||
self.__hid.start()
|
||||
@ -166,7 +166,7 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
|
||||
# ===== INFO
|
||||
|
||||
async def __info_handler(self, _: aiohttp.web.Request) -> aiohttp.web.WebSocketResponse:
|
||||
async def __info_handler(self, _: aiohttp.web.Request) -> aiohttp.web.Response:
|
||||
return _json(_get_system_info())
|
||||
|
||||
# ===== WEBSOCKET
|
||||
@ -305,12 +305,15 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
|
||||
@_wrap_exceptions_for_web("Can't set stream params")
|
||||
async def __streamer_set_params_handler(self, request: aiohttp.web.Request) -> aiohttp.web.Response:
|
||||
resolution = request.query.get("resolution")
|
||||
if resolution:
|
||||
if resolution in self.__streamer.get_available_resolutions():
|
||||
self.__streamer_resolution = resolution
|
||||
else:
|
||||
raise BadRequest("Unknown resolution %r" % (resolution))
|
||||
quality = request.query.get("quality")
|
||||
if quality:
|
||||
try:
|
||||
quality_int = int(quality)
|
||||
if not (1 <= quality_int <= 100):
|
||||
raise ValueError()
|
||||
except Exception:
|
||||
raise BadRequest("Invalid quality %r" % (quality))
|
||||
self.__streamer_quality = quality_int
|
||||
return _json()
|
||||
|
||||
async def __streamer_reset_handler(self, _: aiohttp.web.Request) -> aiohttp.web.Response:
|
||||
@ -356,7 +359,7 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
cur = len(self.__sockets)
|
||||
if prev == 0 and cur > 0:
|
||||
if not self.__streamer.is_running():
|
||||
await self.__streamer.start(self.__streamer_resolution)
|
||||
await self.__streamer.start(self.__streamer_quality)
|
||||
await self.__broadcast_event("streamer_state", **self.__streamer.get_state())
|
||||
elif prev > 0 and cur == 0:
|
||||
shutdown_at = time.time() + self.__streamer_shutdown_delay
|
||||
@ -365,10 +368,10 @@ class Server: # pylint: disable=too-many-instance-attributes
|
||||
await self.__streamer.stop()
|
||||
await self.__broadcast_event("streamer_state", **self.__streamer.get_state())
|
||||
|
||||
if self.__reset_streamer or self.__streamer_resolution != self.__streamer.get_current_resolution():
|
||||
if self.__reset_streamer or self.__streamer_quality != self.__streamer.get_current_quality():
|
||||
if self.__streamer.is_running():
|
||||
await self.__streamer.stop()
|
||||
await self.__streamer.start(self.__streamer_resolution, no_init_restart=True)
|
||||
await self.__streamer.start(self.__streamer_quality, no_init_restart=True)
|
||||
await self.__broadcast_event("streamer_state", **self.__streamer.get_state())
|
||||
self.__reset_streamer = False
|
||||
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import asyncio
|
||||
import asyncio.subprocess
|
||||
|
||||
from collections import OrderedDict as odict
|
||||
|
||||
from typing import List
|
||||
from typing import Dict
|
||||
from typing import Optional
|
||||
@ -21,10 +19,8 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
sync_delay: float,
|
||||
init_delay: float,
|
||||
init_restart_after: float,
|
||||
|
||||
resolutions: List[str],
|
||||
quality: int,
|
||||
cmd: List[str],
|
||||
|
||||
loop: asyncio.AbstractEventLoop,
|
||||
) -> None:
|
||||
|
||||
@ -33,26 +29,18 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
self.__sync_delay = sync_delay
|
||||
self.__init_delay = init_delay
|
||||
self.__init_restart_after = init_restart_after
|
||||
|
||||
self.__resolutions = odict([
|
||||
(display, (real or display))
|
||||
for (display, real) in [
|
||||
(tuple(map(str.lower, map(str.strip, resolution.split("-", maxsplit=1)))) + ("",))[:2]
|
||||
for resolution in resolutions
|
||||
]
|
||||
])
|
||||
self.__resolution = list(self.__resolutions)[0]
|
||||
self.__quality = quality
|
||||
self.__cmd = cmd
|
||||
|
||||
self.__loop = loop
|
||||
|
||||
self.__proc_task: Optional[asyncio.Task] = None
|
||||
|
||||
async def start(self, resolution: str, no_init_restart: bool=False) -> None:
|
||||
async def start(self, quality: int, no_init_restart: bool=False) -> None:
|
||||
logger = get_logger()
|
||||
logger.info("Starting streamer ...")
|
||||
assert resolution in self.__resolutions, (resolution, self.__resolutions)
|
||||
self.__resolution = resolution
|
||||
assert 1 <= quality <= 100
|
||||
self.__quality = quality
|
||||
await self.__inner_start()
|
||||
if self.__init_restart_after > 0.0 and not no_init_restart:
|
||||
logger.info("Stopping streamer to restart ...")
|
||||
@ -67,22 +55,13 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
def is_running(self) -> bool:
|
||||
return bool(self.__proc_task)
|
||||
|
||||
def get_current_resolution(self) -> str:
|
||||
return self.__resolution
|
||||
|
||||
def get_available_resolutions(self) -> List[str]:
|
||||
return list(self.__resolutions)
|
||||
def get_current_quality(self) -> int:
|
||||
return self.__quality
|
||||
|
||||
def get_state(self) -> Dict:
|
||||
(width, height) = tuple(map(int, self.__resolution.split("x")))
|
||||
return {
|
||||
"is_running": self.is_running(),
|
||||
"size": {
|
||||
"width": width,
|
||||
"height": height,
|
||||
},
|
||||
"resolution": self.__resolution,
|
||||
"resolutions": list(self.__resolutions),
|
||||
"quality": self.__quality,
|
||||
}
|
||||
|
||||
async def cleanup(self) -> None:
|
||||
@ -118,7 +97,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
||||
while True: # pylint: disable=too-many-nested-blocks
|
||||
proc: Optional[asyncio.subprocess.Process] = None # pylint: disable=no-member
|
||||
try:
|
||||
cmd = [part.format(resolution=self.__resolutions[self.__resolution]) for part in self.__cmd]
|
||||
cmd = [part.format(quality=self.__quality) for part in self.__cmd]
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
*cmd,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
|
||||
@ -33,7 +33,7 @@ RUN pacman -Syy \
|
||||
python-pip \
|
||||
nginx-mainline \
|
||||
nginx-mainline-mod-lua \
|
||||
mjpg-streamer \
|
||||
ustreamer \
|
||||
socat \
|
||||
&& pacman -Sc --noconfirm
|
||||
|
||||
|
||||
@ -36,17 +36,16 @@ kvmd:
|
||||
init_restart_after: 1.0
|
||||
shutdown_delay: 10.0
|
||||
|
||||
resolutions:
|
||||
- 640x480
|
||||
- 800x600
|
||||
- 1024x768
|
||||
quality: 80
|
||||
|
||||
cmd:
|
||||
- "/usr/bin/mjpg_streamer"
|
||||
- "-i"
|
||||
- "input_uvc.so -d /dev/kvmd-streamer -e 2 -y -n -r {resolution}"
|
||||
- "-o"
|
||||
- "output_http.so -l 0.0.0.0 -p 8082"
|
||||
- "/usr/bin/ustreamer"
|
||||
- "--device=/dev/kvmd-streamer"
|
||||
- "--jpeg-quality={quality}"
|
||||
- "--width=800"
|
||||
- "--height=600"
|
||||
- "--host=0.0.0.0"
|
||||
- "--port=8082"
|
||||
|
||||
logging:
|
||||
version: 1
|
||||
|
||||
@ -35,7 +35,7 @@ div.stream-box-mouse-enabled {
|
||||
cursor: url("../svg/stream-mouse-cursor.svg"), pointer;
|
||||
}
|
||||
|
||||
select#stream-resolution-select {
|
||||
select#stream-quality-select {
|
||||
margin: 8px 0 8px 0;
|
||||
}
|
||||
|
||||
|
||||
@ -75,9 +75,9 @@
|
||||
</div>
|
||||
<hr>
|
||||
<div data-dont-hide-menu class="ctl-dropdown-content-text">
|
||||
Resolution:
|
||||
<select disabled id="stream-resolution-select">
|
||||
<option>640x480</option>
|
||||
Quality:
|
||||
<select disabled id="stream-quality-select">
|
||||
<option>80%</option>
|
||||
</select>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
@ -5,8 +5,7 @@ function Stream() {
|
||||
|
||||
var __prev_state = false;
|
||||
|
||||
var __resolution = "640x480";
|
||||
var __resolutions = ["640x480"];
|
||||
var __quality = 80;
|
||||
|
||||
var __normal_size = {width: 640, height: 480};
|
||||
var __size_factor = 1;
|
||||
@ -14,8 +13,13 @@ function Stream() {
|
||||
var __init__ = function() {
|
||||
$("stream-led").title = "Stream inactive";
|
||||
|
||||
var quality = 10;
|
||||
for (; quality <= 100; quality += 10) {
|
||||
$("stream-quality-select").innerHTML += "<option value=\"" + quality + "\">" + quality + "%</option>";
|
||||
}
|
||||
|
||||
tools.setOnClick($("stream-reset-button"), __clickResetButton);
|
||||
$("stream-resolution-select").onchange = __changeResolution;
|
||||
$("stream-quality-select").onchange = __changeQuality;
|
||||
$("stream-size-slider").oninput = __resize;
|
||||
$("stream-size-slider").onchange = __resize;
|
||||
|
||||
@ -27,12 +31,10 @@ function Stream() {
|
||||
// XXX: In current implementation we don't need this event because Stream() has own state poller
|
||||
|
||||
var __startPoller = function() {
|
||||
var http = tools.makeRequest("GET", "/streamer/snapshot", function() {
|
||||
if (http.readyState === 2 || http.readyState === 4) {
|
||||
var status = http.status;
|
||||
http.onreadystatechange = null;
|
||||
http.abort();
|
||||
if (status !== 200) {
|
||||
var http = tools.makeRequest("GET", "/streamer/ping", function() {
|
||||
if (http.readyState === 4) {
|
||||
var response = (http.status === 200 ? JSON.parse(http.responseText) : null);
|
||||
if (http.status !== 200 || !response.stream.online) {
|
||||
tools.info("Refreshing stream ...");
|
||||
__prev_state = false;
|
||||
$("stream-image").className = "stream-image-inactive";
|
||||
@ -40,8 +42,9 @@ function Stream() {
|
||||
$("stream-led").className = "led-off";
|
||||
$("stream-led").title = "Stream inactive";
|
||||
$("stream-reset-button").disabled = true;
|
||||
$("stream-resolution-select").disabled = true;
|
||||
} else if (!__prev_state) {
|
||||
$("stream-quality-select").disabled = true;
|
||||
} else if (http.status === 200 && !__prev_state) {
|
||||
__normal_size = response.stream.resolution;
|
||||
__refreshImage();
|
||||
__prev_state = true;
|
||||
$("stream-image").className = "stream-image-active";
|
||||
@ -49,6 +52,7 @@ function Stream() {
|
||||
$("stream-led").className = "led-on";
|
||||
$("stream-led").title = "Stream is active";
|
||||
$("stream-reset-button").disabled = false;
|
||||
$("stream-quality-select").disabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -66,11 +70,11 @@ function Stream() {
|
||||
});
|
||||
};
|
||||
|
||||
var __changeResolution = function() {
|
||||
var resolution = $("stream-resolution-select").value;
|
||||
if (__resolution != resolution) {
|
||||
$("stream-resolution-select").disabled = true;
|
||||
var http = tools.makeRequest("POST", "/kvmd/streamer/set_params?resolution=" + resolution, function() {
|
||||
var __changeQuality = function() {
|
||||
var quality = parseInt($("stream-quality-select").value);
|
||||
if (__quality != quality) {
|
||||
$("stream-quality-select").disabled = true;
|
||||
var http = tools.makeRequest("POST", "/kvmd/streamer/set_params?quality=" + quality, function() {
|
||||
if (http.readyState === 4) {
|
||||
if (http.status !== 200) {
|
||||
ui.error("Can't configure stream:<br>", http.responseText);
|
||||
@ -99,25 +103,14 @@ function Stream() {
|
||||
if (http.readyState === 4 && http.status === 200) {
|
||||
var result = JSON.parse(http.responseText).result;
|
||||
|
||||
if (__resolutions != result.resolutions) {
|
||||
tools.info("Resolutions list changed:", result.resolutions);
|
||||
$("stream-resolution-select").innerHTML = "";
|
||||
result.resolutions.forEach(function(resolution) {
|
||||
$("stream-resolution-select").innerHTML += "<option value=\"" + resolution + "\">" + resolution + "</option>";
|
||||
});
|
||||
$("stream-resolution-select").disabled = (result.resolutions.length == 1);
|
||||
__resolutions = result.resolutions;
|
||||
if (__quality != result.quality) {
|
||||
tools.info("Quality changed:", result.quality);
|
||||
document.querySelector("#stream-quality-select [value=\"" + result.quality + "\"]").selected = true;
|
||||
__quality = result.quality;
|
||||
}
|
||||
|
||||
if (__resolution != result.resolution) {
|
||||
tools.info("Resolution changed:", result.resolution);
|
||||
document.querySelector("#stream-resolution-select [value=\"" + result.resolution + "\"]").selected = true;
|
||||
__resolution = result.resolution;
|
||||
}
|
||||
|
||||
__normal_size = result.size;
|
||||
__applySizeFactor();
|
||||
$("stream-image").src = "/streamer/stream/" + new Date().getTime();
|
||||
$("stream-image").src = "/streamer/stream?t=" + new Date().getTime();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
21
os/Makefile
21
os/Makefile
@ -9,7 +9,12 @@ WEBUI_ADMIN_PASSWD ?= admin
|
||||
|
||||
# =====
|
||||
_BUILD_DIR = ./.build
|
||||
_KVMD_VERSION = $(shell bash -c 'source ../kvmd/PKGBUILD; echo $$pkgver')
|
||||
|
||||
define fetch_version
|
||||
curl --silent "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=$(1)" \
|
||||
| grep "^pkgver=" \
|
||||
| grep -Po "\d+\.\d+[^\"']*"
|
||||
endef
|
||||
|
||||
|
||||
# =====
|
||||
@ -21,24 +26,30 @@ v1:
|
||||
make _pikvm PIKVM_PLATFORM=v1 PI_BOARD=rpi-2
|
||||
|
||||
|
||||
v2:
|
||||
make _pikvm PIKVM_PLATFORM=v2 PI_BOARD=rpi-2
|
||||
|
||||
|
||||
shell:
|
||||
cd $(_BUILD_DIR) && make shell
|
||||
|
||||
|
||||
_pikvm: $(_BUILD_DIR)
|
||||
rm -rf $(_BUILD_DIR)/stages/pikvm
|
||||
rm -rf $(_BUILD_DIR)/stages/pikvm-*
|
||||
rm -rf $(_BUILD_DIR)/builder/scripts/pikvm
|
||||
cp -a platforms/$(PIKVM_PLATFORM) $(_BUILD_DIR)/stages/pikvm
|
||||
cp -a platforms/common $(_BUILD_DIR)/stages/pikvm-common
|
||||
cp -a platforms/$(PIKVM_PLATFORM) $(_BUILD_DIR)/stages/pikvm-$(PIKVM_PLATFORM)
|
||||
cd $(_BUILD_DIR) && make binfmt && make _rpi \
|
||||
BUILD_OPTS=" $(BUILD_OPTS) \
|
||||
--build-arg KVMD_VERSION=$(_KVMD_VERSION) \
|
||||
--build-arg USTREAMER_VERSION=$(call fetch_version, ustreamer) \
|
||||
--build-arg KVMD_VERSION=$(call fetch_version, kvmd) \
|
||||
--build-arg NEW_SSH_KEYGEN=$(shell uuidgen) \
|
||||
--build-arg WEBUI_ADMIN_PASSWD='$(WEBUI_ADMIN_PASSWD)' \
|
||||
--build-arg NEW_HTTPS_CERT=$(shell uuidgen) \
|
||||
" \
|
||||
PROJECT=pikvm \
|
||||
BOARD=$(PI_BOARD) \
|
||||
STAGES="__init__ os watchdog ro pikvm rootssh __cleanup__" \
|
||||
STAGES="__init__ os watchdog ro pikvm-common pikvm-$(PIKVM_PLATFORM) rootssh __cleanup__" \
|
||||
LOCALE=$(LOCALE) \
|
||||
TIMEZONE=$(TIMEZONE)
|
||||
|
||||
|
||||
51
os/platforms/common/Dockerfile.part
Normal file
51
os/platforms/common/Dockerfile.part
Normal file
@ -0,0 +1,51 @@
|
||||
RUN pkg-install \
|
||||
nginx-mainline \
|
||||
apache-tools \
|
||||
raspberrypi-firmware \
|
||||
v4l-utils \
|
||||
python \
|
||||
python-raspberry-gpio \
|
||||
customizepkg
|
||||
RUN systemctl enable nginx
|
||||
|
||||
COPY stages/pikvm-common/customizepkg.nginx /etc/customizepkg.d/nginx-mainline-mod-ndk
|
||||
COPY stages/pikvm-common/customizepkg.nginx /etc/customizepkg.d/nginx-mainline-mod-lua
|
||||
RUN env MAKEPKGOPTS="--skipchecksums --skippgpcheck" pkg-install nginx-mainline-mod-lua
|
||||
|
||||
ARG USTREAMER_VERSION
|
||||
ENV USTREAMER_VERSION $USTREAMER_VERSION
|
||||
RUN echo $USTREAMER_VERSION
|
||||
RUN pkg-install ustreamer
|
||||
|
||||
ARG KVMD_VERSION
|
||||
ENV KVMD_VERSION $KVMD_VERSION
|
||||
RUN echo $KVMD_VERSION
|
||||
RUN pkg-install kvmd
|
||||
RUN systemctl enable kvmd
|
||||
|
||||
COPY stages/pikvm-common/sysctl.conf /etc/sysctl.d/99-pikvm.conf
|
||||
COPY stages/pikvm-common/motd /etc/
|
||||
|
||||
RUN sed -i -e "s/console=ttyAMA0\,115200//g" /boot/cmdline.txt \
|
||||
&& sed -i -e "s/kgdboc=ttyAMA0\,115200//g" /boot/cmdline.txt
|
||||
RUN systemctl mask serial-getty@ttyAMA0.service
|
||||
|
||||
RUN rm -rf /etc/nginx/* \
|
||||
&& cp /usr/share/kvmd/configs/nginx/* /etc/nginx/ \
|
||||
&& sed -i -e "s/^#PROD//g" /etc/nginx/nginx.conf
|
||||
|
||||
ARG WEBUI_ADMIN_PASSWD
|
||||
ENV WEBUI_ADMIN_PASSWD $WEBUI_ADMIN_PASSWD
|
||||
RUN echo "$WEBUI_ADMIN_PASSWD" | htpasswd -ci /etc/nginx/htpasswd admin
|
||||
|
||||
ARG NEW_HTTPS_CERT
|
||||
ENV NEW_HTTPS_CERT $NEW_HTTPS_CERT
|
||||
RUN echo $NEW_HTTPS_CERT
|
||||
RUN mkdir /etc/nginx/ssl \
|
||||
&& cd /etc/nginx/ssl \
|
||||
&& openssl req -new -x509 -nodes -newkey rsa:4096 -keyout server.key -out server.crt -days 3650 \
|
||||
-subj "/C=RU/ST=Moscow/L=Moscow/O=Pi-KVM/OU=Pi-KVM/CN=localhost" \
|
||||
&& chmod 400 server.key \
|
||||
&& chmod 444 server.crt \
|
||||
&& chmod 750 /etc/nginx/ssl \
|
||||
&& chown -R root:http /etc/nginx/ssl
|
||||
@ -1,48 +1,4 @@
|
||||
RUN pkg-install \
|
||||
nginx-mainline \
|
||||
apache-tools \
|
||||
mjpg-streamer \
|
||||
python \
|
||||
python-raspberry-gpio \
|
||||
customizepkg
|
||||
RUN systemctl enable nginx
|
||||
COPY stages/pikvm-v1/config.txt /boot/
|
||||
COPY stages/pikvm-v1/udev.rules /etc/udev/rules.d/pikvm.rules
|
||||
|
||||
COPY stages/pikvm/customizepkg.nginx /etc/customizepkg.d/nginx-mainline-mod-ndk
|
||||
COPY stages/pikvm/customizepkg.nginx /etc/customizepkg.d/nginx-mainline-mod-lua
|
||||
RUN env MAKEPKGOPTS="--skipchecksums --skippgpcheck" pkg-install nginx-mainline-mod-lua
|
||||
|
||||
ARG KVMD_VERSION
|
||||
ENV KVMD_VERSION $KVMD_VERSION
|
||||
RUN echo $KVMD_VERSION
|
||||
RUN pkg-install kvmd
|
||||
RUN systemctl enable kvmd
|
||||
|
||||
COPY stages/pikvm/config.txt /boot/
|
||||
COPY stages/pikvm/sysctl.conf /etc/sysctl.d/99-pikvm.conf
|
||||
COPY stages/pikvm/udev.rules /etc/udev/rules.d/pikvm.rules
|
||||
COPY stages/pikvm/motd /etc/
|
||||
|
||||
RUN sed -i -e "s/console=ttyAMA0\,115200//g" /boot/cmdline.txt \
|
||||
&& sed -i -e "s/kgdboc=ttyAMA0\,115200//g" /boot/cmdline.txt
|
||||
RUN systemctl mask serial-getty@ttyAMA0.service
|
||||
|
||||
RUN rm -rf /etc/nginx/* \
|
||||
&& cp /usr/share/kvmd/configs/nginx/* /etc/nginx/ \
|
||||
&& sed -i -e "s/^#PROD//g" /etc/nginx/nginx.conf
|
||||
RUN cp /usr/share/kvmd/configs/kvmd/v1.yaml /etc/kvmd.yaml
|
||||
|
||||
ARG WEBUI_ADMIN_PASSWD
|
||||
ENV WEBUI_ADMIN_PASSWD $WEBUI_ADMIN_PASSWD
|
||||
RUN echo "$WEBUI_ADMIN_PASSWD" | htpasswd -ci /etc/nginx/htpasswd admin
|
||||
|
||||
ARG NEW_HTTPS_CERT
|
||||
ENV NEW_HTTPS_CERT $NEW_HTTPS_CERT
|
||||
RUN echo $NEW_HTTPS_CERT
|
||||
RUN mkdir /etc/nginx/ssl \
|
||||
&& cd /etc/nginx/ssl \
|
||||
&& openssl req -new -x509 -nodes -newkey rsa:4096 -keyout server.key -out server.crt -days 3650 \
|
||||
-subj "/C=RU/ST=Moscow/L=Moscow/O=Pi-KVM/OU=Pi-KVM/CN=localhost" \
|
||||
&& chmod 400 server.key \
|
||||
&& chmod 444 server.crt \
|
||||
&& chmod 750 /etc/nginx/ssl \
|
||||
&& chown -R root:http /etc/nginx/ssl
|
||||
|
||||
11
os/platforms/v2/Dockerfile.part
Normal file
11
os/platforms/v2/Dockerfile.part
Normal file
@ -0,0 +1,11 @@
|
||||
RUN pkg-install \
|
||||
dkms \
|
||||
tc358743-dkms
|
||||
|
||||
RUN sed -i -e "s/rootwait/cma=128M rootwait/g" /boot/cmdline.txt
|
||||
|
||||
COPY stages/pikvm-v2/config.txt /boot/
|
||||
COPY stages/pikvm-v2/udev.rules /etc/udev/rules.d/pikvm.rules
|
||||
COPY stages/pikvm-v2/modules.load /etc/modules-load.d/pikvm.conf
|
||||
|
||||
RUN cp /usr/share/kvmd/configs/kvmd/v2.yaml /etc/kvmd.yaml
|
||||
5
os/platforms/v2/config.txt
Normal file
5
os/platforms/v2/config.txt
Normal file
@ -0,0 +1,5 @@
|
||||
gpu_mem=16
|
||||
start_x=1
|
||||
enable_uart=1
|
||||
dtoverlay=tc358743,i2c_pins_28_29=1
|
||||
dtparam=act_led_gpio=27
|
||||
1
os/platforms/v2/modules.load
Normal file
1
os/platforms/v2/modules.load
Normal file
@ -0,0 +1 @@
|
||||
tc358743
|
||||
4
os/platforms/v2/udev.rules
Normal file
4
os/platforms/v2/udev.rules
Normal file
@ -0,0 +1,4 @@
|
||||
# https://unix.stackexchange.com/questions/66901/how-to-bind-usb-device-under-a-static-name
|
||||
# https://wiki.archlinux.org/index.php/Udev#Setting_static_device_names
|
||||
KERNEL=="video[0-9]*", SUBSYSTEM=="video4linux", KERNELS=="soc", SYMLINK+="kvmd-streamer"
|
||||
KERNEL=="sd[a-z]", SUBSYSTEM=="block", KERNELS=="1-1.4:1.0", SYMLINK+="kvmd-msd"
|
||||
Loading…
x
Reference in New Issue
Block a user