Compare commits

...

119 Commits
v5.18 ... v7.20

Author SHA1 Message Date
Kroese
43ffa18a5f fix: Remove scsi parameter from virtio-blk-pci (#824) 2024-10-01 21:49:31 +02:00
Kroese
b131a32d0c buid: Pin Debian version (#818) 2024-09-27 14:40:56 +02:00
D-Jy
c81787b837 feat: Allow custom rendernode (#817) 2024-09-17 23:30:58 +02:00
Kroese
f9df3c6db6 feat: Update to VirtualDSM 7.2.2 (#815) 2024-09-11 19:20:43 +02:00
Liang Ying-Ruei
e383ec30e3 fix: Splits $USER_PORTS correctly by commas (#813) 2024-09-09 15:43:57 +02:00
Kroese
1197c4791e fix: Port forwarding warning (#809) 2024-09-05 18:58:23 +02:00
Kroese
106c684389 docs: Update package URL (#808) 2024-09-03 15:09:33 +02:00
Kroese
a199ced77b docs: Update package URL (#803) 2024-08-27 16:07:09 +02:00
Kroese
77ac73666e fix: Progress calculation (#799) 2024-08-18 17:55:07 +02:00
Kroese
64975557c2 fix: Validate lscpu output (#798) 2024-08-18 04:40:20 +02:00
Kroese
b62321806a docs: Fix badge (#796) 2024-08-13 20:51:55 +02:00
renovate[bot]
7c392082b1 chore(deps): update docker/build-push-action action to v6 (#775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-17 12:45:23 +02:00
Kroese
392e9a6417 docs: Networking (#774) 2024-06-16 06:09:26 +02:00
Kroese
fb5f684e7e fix: Don't set script with file descriptor (#772) 2024-06-14 04:35:40 +02:00
Kroese
0dbc794223 feat: Customize image filenames (#771) 2024-06-14 03:01:27 +02:00
Kroese
6295ed3b7b docs: Removed Kubevirt dependancy (#770) 2024-06-13 19:31:00 +02:00
Kroese
0f2d889858 fix: Assume GB when no unit is present (#769) 2024-06-13 18:59:13 +02:00
Kroese
60e6b01982 docs: Add markdown alerts (#768) 2024-06-13 18:31:25 +02:00
Kroese
1dc69f9e22 docs: Add GHCR badge (#767) 2024-06-11 23:26:38 +02:00
Kroese
fcca41ad93 docs: Readme (#766) 2024-06-11 21:48:18 +02:00
Kroese
9897747425 docs: Add icons (#765) 2024-06-11 21:06:38 +02:00
Kroese
4dbe9dcefd docs: KVM information (#764) 2024-06-11 19:56:14 +02:00
Kroese
be8bee90f2 feat: Implement usermode networking (#762) 2024-06-11 02:13:53 +02:00
Kroese
f8879029ec fix: Do not use IO threading for SATA disks (#760) 2024-06-09 18:34:55 +02:00
Kroese
7b491b3cee feat: Verify clocksource is set to TSC (#759) 2024-06-09 17:44:15 +02:00
Kroese
2ece865417 fix: Download error messages (#756) 2024-06-05 18:18:29 +02:00
Kroese
0d8c693c65 build: Update qemu-host to v2.05 (#755) 2024-06-05 14:32:21 +02:00
Kroese
9f7d1396b6 docs: Readme (#753) 2024-06-03 02:00:04 +02:00
Kroese
5ad323486e feat: Print QEMU version on boot (#752) 2024-06-02 23:00:40 +02:00
Kroese
19b4248929 feat: Print QEMU version on boot (#751) 2024-06-02 21:04:09 +02:00
Kroese
c135c4cac3 feat: Add automatic device type (#749) 2024-05-27 17:25:52 +02:00
Kroese
fb1751ff26 docs: Updated issue templates (#747) 2024-05-25 14:07:30 +02:00
Kroese
34f32d4ac6 docs: Docker CLI example (#746) 2024-05-22 07:55:38 +02:00
Kroese
36f1e47c0a fix: Check for Podman IP ranges (#745) 2024-05-21 13:48:05 +02:00
Kroese
c5dd5c2e46 feat: Print arguments in debug mode (#743) 2024-05-21 09:17:51 +02:00
Kroese
d1d920372a feat: Support more device types (#742) 2024-05-21 09:10:30 +02:00
Kroese
12d8fd3ed0 feat: Support Kubernetes interfaces (#741) 2024-05-21 07:44:44 +02:00
Kroese
729aed536e feat: Add flag to disable RAM check (#740) 2024-05-19 23:59:14 +02:00
Kroese
b588f8c90d feat: Display KVM warning on ARM64 (#739) 2024-05-19 21:19:58 +02:00
Kroese
1f1007a0f1 fix: Display reason for network failure (#738) 2024-05-17 16:09:47 +02:00
Kroese
2ec37e2802 docs: Docker CLI (#737) 2024-05-16 03:22:58 +02:00
Slavik
3126b3847b feat: Add Kubernetes manifest (#735) 2024-05-16 01:42:58 +02:00
Kroese
41e0157e9d docs: Update issue templates (#736) 2024-05-16 01:12:16 +02:00
Kroese
1d64410849 docs: Update issue template (#734) 2024-05-15 22:04:25 +02:00
Kroese
55034b0f40 feat: Additional disk device (#733) 2024-05-15 17:56:12 +02:00
Kroese
acffcf3774 docs: Remove restart policy (#732) 2024-05-15 17:23:09 +02:00
Kroese
fba0eb527b docs: Remove version from compose (#731) 2024-05-15 16:54:17 +02:00
Kroese
d9fc2714a6 build: Declare extra variable (#730) 2024-05-13 04:02:25 +02:00
Kroese
d1f1772d74 build: Optimize Dockerfile (#729) 2024-05-13 03:48:29 +02:00
Kroese
bf1d47e4f3 docs: Readme (#728) 2024-05-12 20:55:50 +02:00
Kroese
3da564dfd1 feat: Support install from local PAT file (#727) 2024-05-12 20:19:30 +02:00
Kroese
abd30b9d91 feat: Detect Windows and MacOS (#726) 2024-05-11 22:11:11 +02:00
Kroese
c86408cbd6 fix: Additional pass-through mounts (#722) 2024-05-08 23:23:17 +02:00
Kroese
1f51974c48 fix: Set download timeout (#719) 2024-05-04 17:24:21 +02:00
Kroese
29f4cde296 feat: Show download percentage (#718) 2024-05-04 16:34:30 +02:00
Kroese
c4a0035062 feat: Display RAM amount warning (#717) 2024-05-03 11:18:20 +02:00
Kroese
6724ddbd7d feat: Check the amount of RAM available (#716) 2024-05-02 20:21:21 +02:00
Kroese
8d8ed63122 docs: Disk pass-through (#715) 2024-05-01 11:57:56 +02:00
Kroese
6f4ea81907 feat: New disk pass-through method (#714) 2024-05-01 00:13:26 +02:00
Kroese
6d162744ec feat: Improved networking (#712) 2024-04-30 00:30:44 +02:00
Kroese
145b4aab5b docs: Update issue templates (#708) 2024-04-26 16:53:15 +02:00
Kroese
2e4eb56d0b fix: Curl error on Chinese mirror (#707) 2024-04-26 16:32:08 +02:00
Kroese
39c019193e fix: Curl error on Chinese mirror (#706) 2024-04-26 16:30:30 +02:00
Kroese
faec563b4a feat: Display kernel version (#704) 2024-04-26 13:59:51 +02:00
Kroese
9840f8e07a feat: Support ecryptfs filesystem (#703) 2024-04-26 06:04:48 +02:00
Kroese
3a5895fa0f build: Remove armv7 support (#702) 2024-04-26 04:16:46 +02:00
Kroese
1bac5c8a7f feat: Print system info (#701) 2024-04-25 14:31:49 +02:00
Kroese
dd76c60e2a fix: CPU detection (#697) 2024-04-22 16:48:41 +02:00
Kroese
ac78cc7dc5 feat: Display system info on boot (#696) 2024-04-22 16:29:23 +02:00
Kroese
66ac2d2002 docs: Update issue template (#692) 2024-04-17 19:03:17 +02:00
Kroese
0bd099d704 docs: Update issue templates (#691) 2024-04-17 18:32:43 +02:00
Kroese
d2dac3cfb4 docs: Add issue templates (#690) 2024-04-17 18:14:51 +02:00
Kroese
e81dc0f31d fix: Verify files are not empty (#689) 2024-04-16 15:35:35 +02:00
Kroese
5015597183 fix: Ignore empty MAC address (#688) 2024-04-13 23:33:17 +02:00
Kroese
64e2af9fa2 fix: Continue if file is missing (#682) 2024-04-08 09:54:42 +02:00
Kroese
debb4b69fc fix: Continue when range request fails (#680) 2024-04-08 04:53:30 +02:00
Kroese
c6d3dda171 docs: Readme (#677) 2024-04-07 01:59:50 +02:00
Kroese
7c0693c2ff build: Update qemu-host to v2.04 (#670) 2024-03-31 05:24:54 +02:00
Kroese
76355d4857 fix: TUN error message (#669) 2024-03-31 04:57:56 +02:00
Kroese
404aaadefc build: Dockerfile (#663) 2024-03-25 16:49:25 +01:00
Kroese
be027e10be fix: Disable IPv6 in Nginx (#662) 2024-03-25 13:53:30 +01:00
Kroese
1c8cad92f8 fix: Disable kernel networking in bridge mode (#656) 2024-03-12 01:50:43 +01:00
Kroese
fabb8ea3b7 docs: Readme (#650) 2024-02-28 20:43:27 +01:00
Kroese
2ee4abca54 docs: Docker run command (#647) 2024-02-28 08:51:55 +01:00
Kroese
5896928030 feat: Persistant MAC address (#646) 2024-02-28 08:40:00 +01:00
Kroese
8652544982 docs: Readme (#638) 2024-02-19 21:32:22 +01:00
Kroese
a70338ec3c feat: Print filesystem on error (#635) 2024-02-17 05:56:40 +01:00
Kroese
a84878abfc fix: Detect Mac Journal filesystem (#634) 2024-02-17 03:55:30 +01:00
Kroese
8421a391b7 fix: Prevent re-entry during shutdown (#633) 2024-02-16 16:03:37 +01:00
Kroese
f9340ec3d6 docs: Readme (#630) 2024-02-10 00:33:21 +01:00
Kroese
0cca9c5f83 feat: Disable CoW check on XFS (#629) 2024-02-09 23:53:18 +01:00
Kroese
13d60b7f47 build: Notify after build (#628) 2024-02-09 14:45:38 +01:00
Kroese
f74771a9cc fix: Convert MAC address to uppercase (#627) 2024-02-08 17:33:11 +01:00
Kroese
f24ba41930 fix: Convert dashes in custom MAC addresses (#626) 2024-02-08 17:03:30 +01:00
Kroese
f412580a4a feat: Add DNS entry for container (#624) 2024-02-07 22:26:29 +01:00
Kroese
5cde1b4438 feat: Set process name (#623) 2024-02-07 13:04:29 +01:00
Kroese
7cfb57b1bc docs: Readme (#621) 2024-02-05 16:18:13 +01:00
Kroese
a478b58f97 feat: Set KVM tick policy (#620) 2024-02-05 12:09:12 +01:00
Kroese
8297f4f880 fix: Support CPU's without SSE4 (#619) 2024-02-05 07:41:47 +01:00
Kroese
4c67343d33 feat: Enable L3 cache and multi-threaded TCG (#618) 2024-02-04 19:25:22 +01:00
Kroese
53cc6998f0 fix: CPU features 2024-02-02 22:44:43 +01:00
Kroese
d857d71e0d fix: Merge drive function (#614) 2024-02-01 11:05:33 +01:00
Kroese
003c2766ce docs: Readme (#613) 2024-01-31 04:28:24 +01:00
Kroese
78594098cc feat: Disable CoW check on ZFS (#612) 2024-01-31 03:54:40 +01:00
Kroese
3c31bc91e4 feat: Generate unique MAC address (#611) 2024-01-30 04:46:44 +01:00
Kroese
72141bab7a build: Lint Dockerfile (#610) 2024-01-29 11:51:28 +01:00
Kroese
bc52463aa4 fix: Process signal faster (#609) 2024-01-29 05:54:22 +01:00
Kroese
9fa68908a9 feat: Show download progress (#608) 2024-01-29 05:40:06 +01:00
Kroese
740dbec1b1 build: Exclude web folder (#607) 2024-01-29 02:29:05 +01:00
Kroese
440d203730 fix: Stylesheet (#606) 2024-01-29 02:27:04 +01:00
Kroese
1a83c67e2c feat: Font smoothing (#605) 2024-01-29 02:01:51 +01:00
Kroese
34a707a2a5 docs: Readme (#603) 2024-01-27 19:51:26 +01:00
Kroese
cabb2cdfc9 docs: Readme (#602) 2024-01-27 19:10:43 +01:00
Kroese
dc52ccf172 docs: Readme (#601) 2024-01-27 19:06:10 +01:00
Kroese
bdd7fec3c3 fix: Space after URL (#600) 2024-01-27 02:01:27 +01:00
Kroese
bd8b03d089 docs: Readme (#599) 2024-01-26 06:29:15 +01:00
Kroese
a10588b0ce fix: Check dnsmasq (#598) 2024-01-26 02:19:31 +01:00
renovate[bot]
3503b86e12 chore(deps): update peter-evans/dockerhub-description action to v4 (#597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-25 17:05:28 +01:00
Kroese
9e124980cd fix: Disk message (#596) 2024-01-25 17:02:50 +01:00
29 changed files with 1202 additions and 417 deletions

View File

@@ -6,7 +6,10 @@
.gitmodules
Dockerfile
Dockerfile.archive
compose.yml
compose.yaml
docker-compose.yml
docker-compose.yaml
*.md

39
.github/ISSUE_TEMPLATE/1-issue.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: "\U0001F6A8 Technical issue"
description: When you're experiencing problems using the container
body:
- type: input
id: os
attributes:
label: Operating system
description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: textarea
id: summary
attributes:
label: Description
description: A clear and concise description of your issue.
validations:
required: true
- type: textarea
id: compose
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
validations:
required: true
- type: textarea
id: log
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: Screenshots (optional)
description: Screenshots that might help to make the problem more clear.
validations:
required: false

37
.github/ISSUE_TEMPLATE/2-feature.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: "\U0001F680 Feature request"
description: Suggest an idea for improving the container
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: Is your proposal related to a problem?
description: |
Provide a clear and concise description of what the problem is.
For example, "I'm always frustrated when..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like.
description: |
Provide a clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered.
description: |
Let us know about other solutions you've tried or researched.
validations:
required: true
- type: textarea
id: context
attributes:
label: Additional context
description: |
Is there anything else you can add about the proposal?
You might want to link to related issues here, if you haven't already.

41
.github/ISSUE_TEMPLATE/3-bug.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: "\U0001F41E Bug report"
description: Create a report to help us improve the container
title: "[Bug]: "
labels: ["bug"]
body:
- type: input
id: os
attributes:
label: Operating system
description: Your Linux distribution (can be shown by `lsb_release -a`).
placeholder: e.g. Ubuntu 24.04
validations:
required: true
- type: textarea
id: summary
attributes:
label: Description
description: Describe the expected behaviour, the actual behaviour, and the steps to reproduce.
validations:
required: true
- type: textarea
id: compose
attributes:
label: Docker compose
description: The compose file (or otherwise the `docker run` command used).
validations:
required: true
- type: textarea
id: log
attributes:
label: Docker log
description: The logfile of the container (as shown by `docker logs dsm`).
validations:
required: true
- type: textarea
id: screenshot
attributes:
label: Screenshots (optional)
description: Screenshots that might help to make the problem more clear.
validations:
required: false

26
.github/ISSUE_TEMPLATE/4-question.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: "\U00002753 General question"
description: Questions about the container not related to an issue
title: "[Question]: "
labels: ["question"]
body:
- type: checkboxes
attributes:
label: Is your question not already answered in the FAQ?
description: Please read the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md) carefully to avoid asking duplicate questions.
options:
- label: I made sure the question is not listed in the [FAQ](https://github.com/vdsm/virtual-dsm/blob/master/readme.md).
required: true
- type: checkboxes
attributes:
label: Is this a general question and not a technical issue?
description: For questions related to issues you must use the [technical issue](https://github.com/vdsm/virtual-dsm/issues/new?assignees=&labels=&projects=&template=1-issue.yml) form instead. It contains all the right fields (system info, logfiles, etc.) we need in order to be able to help you.
options:
- label: I am sure my question is not about a technical issue.
required: true
- type: textarea
id: question
attributes:
label: Question
description: What's the question you have about the container?
validations:
required: true

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1 @@
blank_issues_enabled: false

View File

@@ -8,6 +8,10 @@ on:
paths-ignore:
- '**/*.md'
- '**/*.yml'
- '**/*.js'
- '**/*.css'
- '**/*.html'
- 'web/**'
- '.gitignore'
- '.dockerignore'
- '.github/**'
@@ -69,12 +73,12 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build Docker image
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
push: true
provenance: false
platforms: linux/amd64,linux/arm64,linux/arm
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
@@ -99,3 +103,15 @@ jobs:
url: ${{ secrets.GITLAB_URL }}
token: ${{ secrets.GITLAB_TOKEN }}
username: ${{ secrets.GITLAB_USERNAME }}
-
name: Send mail
uses: action-pack/send-mail@v1
with:
to: ${{secrets.MAILTO}}
from: Github Actions <${{secrets.MAILTO}}>
connection_url: ${{secrets.MAIL_CONNECTION}}
subject: Build of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} completed
body: |
The build job of ${{ github.event.repository.name }} v${{ steps.meta.outputs.version }} was completed successfully!
See https://github.com/${{ github.repository }}/actions for more information.

View File

@@ -7,8 +7,18 @@ jobs:
name: shellcheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
-
name: Checkout
uses: actions/checkout@v4
-
name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
env:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
env:
SHELLCHECK_OPTS: -x --source-path=src -e SC2001 -e SC2034 -e SC2064 -e SC2317 -e SC2153 -e SC2028
-
name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
ignore: DL3008,DL3003,DL3006
failure-threshold: warning

View File

@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
-
name: Docker Hub Description
uses: peter-evans/dockerhub-description@v3
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

View File

@@ -3,6 +3,7 @@ on:
pull_request:
paths:
- '**/*.sh'
- 'Dockerfile'
- '.github/workflows/test.yml'
- '.github/workflows/check.yml'

View File

@@ -1,4 +1,4 @@
FROM qemux/qemu-host as builder
FROM qemux/qemu-host:2.05 AS builder
# FROM golang as builder
# WORKDIR /
@@ -7,16 +7,18 @@ FROM qemux/qemu-host as builder
# RUN go mod download
# RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /qemu-host.bin .
FROM debian:trixie-slim
FROM debian:trixie-20240926-slim
ARG TARGETPLATFORM
ARG DEBCONF_NOWARNINGS "yes"
ARG DEBIAN_FRONTEND "noninteractive"
ARG DEBCONF_NONINTERACTIVE_SEEN "true"
ARG VERSION_ARG="0.0"
ARG DEBCONF_NOWARNINGS="yes"
ARG DEBIAN_FRONTEND="noninteractive"
ARG DEBCONF_NONINTERACTIVE_SEEN="true"
RUN if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi \
&& apt-get update \
&& apt-get --no-install-recommends -y install \
RUN set -eu && extra="" && \
if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi && \
apt-get update && \
apt-get --no-install-recommends -y install \
jq \
tini \
curl \
@@ -37,28 +39,24 @@ RUN if [ "$TARGETPLATFORM" != "linux/amd64" ]; then extra="qemu-user"; fi \
ca-certificates \
netcat-openbsd \
qemu-system-x86 \
"$extra" \
&& apt-get clean \
&& unlink /etc/nginx/sites-enabled/default \
&& sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
"$extra" && \
apt-get clean && \
unlink /etc/nginx/sites-enabled/default && \
sed -i 's/^worker_processes.*/worker_processes 1;/' /etc/nginx/nginx.conf && \
echo "$VERSION_ARG" > /run/version && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY ./src /run/
COPY ./web /var/www/
COPY --from=builder /qemu-host.bin /run/host.bin
RUN chmod +x /run/*.sh && chmod +x /run/*.bin
RUN mv /var/www/nginx.conf /etc/nginx/sites-enabled/web.conf
COPY --chmod=755 ./src /run/
COPY --chmod=755 ./web /var/www/
COPY --chmod=755 --from=builder /qemu-host.bin /run/host.bin
COPY --chmod=744 ./web/nginx.conf /etc/nginx/sites-enabled/web.conf
VOLUME /storage
EXPOSE 22 139 445 5000
ENV RAM_SIZE "1G"
ENV DISK_SIZE "16G"
ENV CPU_CORES "1"
ARG VERSION_ARG "0.0"
RUN echo "$VERSION_ARG" > /run/version
ENV RAM_SIZE="1G"
ENV DISK_SIZE="16G"
ENV CPU_CORES="1"
HEALTHCHECK --interval=60s --start-period=45s --retries=2 CMD /run/check.sh

View File

@@ -1,21 +1,15 @@
version: "3"
services:
dsm:
container_name: dsm
image: vdsm/virtual-dsm:latest
environment:
DISK_SIZE: "16G"
RAM_SIZE: "1G"
CPU_CORES: "1"
devices:
- /dev/kvm
device_cgroup_rules:
- 'c *:* rwm'
cap_add:
- NET_ADMIN
ports:
- 5000:5000
volumes:
- /var/dsm:/storage
restart: on-failure
stop_grace_period: 2m

59
kubernetes.yml Normal file
View File

@@ -0,0 +1,59 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dsm-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 16Gi
---
apiVersion: v1
kind: Pod
metadata:
name: dsm
labels:
name: dsm
spec:
terminationGracePeriodSeconds: 120 # the Kubernetes default is 30 seconds and it may be not enough
containers:
- name: dsm
image: vdsm/virtual-dsm
ports:
- containerPort: 5000
protocol: TCP
securityContext:
privileged: true
env:
- name: RAM_SIZE
value: 1G
- name: CPU_CORES
value: "1"
- name: DISK_SIZE
value: "16G" # Kubernetes uses Gi, but DSM uses GB
volumeMounts:
- mountPath: /storage
name: storage
- mountPath: /dev/kvm
name: dev-kvm
volumes:
- name: storage
persistentVolumeClaim:
claimName: dsm-pvc
- name: dev-kvm
hostPath:
path: /dev/kvm
---
apiVersion: v1
kind: Service
metadata:
name: dsm
spec:
type: NodePort
selector:
name: dsm
ports:
- name: tcp-5000
port: 5000
targetPort: 5000

317
readme.md
View File

@@ -1,31 +1,30 @@
<h1 align="center">Virtual DSM<br />
<div align="center">
<img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" />
<a href="https://github.com/vdsm/virtual-dsm"><img src="https://github.com/vdsm/virtual-dsm/raw/master/.github/screen.jpg" title="Screenshot" style="max-width:100%;" width="432" /></a>
</div>
<div align="center">
[![Build]][build_url]
[![Version]][tag_url]
[![Size]][tag_url]
[![Package]][pkg_url]
[![Pulls]][hub_url]
</div></h1>
Virtual DSM in a docker container.
Virtual DSM in a Docker container.
## Features
## Features
- Multiple disks
- KVM acceleration
- GPU pass-through
- Upgrades supported
## Usage
## Usage 🐳
Via `docker-compose.yml`
Via Docker Compose:
```yaml
version: "3"
services:
dsm:
container_name: dsm
@@ -40,212 +39,246 @@ services:
- 5000:5000
volumes:
- /var/dsm:/storage
restart: on-failure
stop_grace_period: 2m
```
Via `docker run`
Via Docker CLI:
```bash
docker run -it --rm -p 5000:5000 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 120 vdsm/virtual-dsm
```
## FAQ
Via Kubernetes:
* ### How do I use it?
```shell
kubectl apply -f kubernetes.yml
```
Very simple! These are the steps:
- Start the container and get some coffee.
## FAQ 💬
- Connect to [port 5000](http://localhost:5000) of the container in your web browser.
### How do I use it?
- Wait until DSM is ready, choose an username and password, and you will be taken to the desktop.
Very simple! These are the steps:
- Start the container and connect to [port 5000](http://localhost:5000) using your web browser.
- Enjoy your brand new machine, and don't forget to star this repo!
- Wait until DSM is ready, choose an username and password, and you will be taken to the desktop.
Enjoy your brand new machine, and don't forget to star this repo!
* ### How do I change the size of the disk?
### How do I change the storage location?
To expand the default size of 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
To change the storage location, include the following bind mount in your compose file:
```yaml
environment:
DISK_SIZE: "128G"
```
This can also be used to resize the existing disk to a larger capacity without any data loss.
```yaml
volumes:
- /var/dsm:/storage
```
* ### How do I change the storage location?
Replace the example path `/var/dsm` with the desired storage folder.
### How do I change the size of the disk?
To change the storage location, include the following bind mount in your compose file:
To expand the default size of 16 GB, locate the `DISK_SIZE` setting in your compose file and modify it to your preferred capacity:
```yaml
volumes:
- /var/dsm:/storage
```
```yaml
environment:
DISK_SIZE: "128G"
```
> [!TIP]
> This can also be used to resize the existing disk to a larger capacity without any data loss.
Replace the example path `/var/dsm` with the desired storage folder.
### How do I create a growable disk?
* ### How do I create a growable disk?
By default, the entire capacity of the disk is reserved in advance.
By default, the entire capacity of the disk is reserved in advance.
To create a growable disk that only allocates space that is actually used, add the following environment variable:
To create a growable disk that only allocates space that is actually used, add the following environment variable:
```yaml
environment:
DISK_FMT: "qcow2"
```
```yaml
environment:
DISK_FMT: "qcow2"
```
> [!NOTE]
> This may reduce the write performance of the disk.
Please note that this may reduce the write performance of the disk.
### How do I add multiple disks?
* ### How do I add multiple disks?
To create additional disks, modify your compose file like this:
```yaml
environment:
DISK2_SIZE: "32G"
DISK3_SIZE: "64G"
volumes:
- /home/example:/storage2
- /mnt/data/example:/storage3
```
To create additional disks, modify your compose file like this:
```yaml
environment:
DISK2_SIZE: "32G"
DISK3_SIZE: "64G"
volumes:
- /home/example:/storage2
- /mnt/data/example:/storage3
```
### How do I pass-through a disk?
* ### How do I pass-through a disk?
It is possible to pass-through a disk device directly, by adding it to your compose file in this way:
It is possible to pass-through disk devices directly by adding them to your compose file in this way:
```yaml
devices:
- /dev/disk/by-uuid/12345-12345-12345-12345-12345:/disk2
```
```yaml
environment:
DEVICE2: "/dev/sda"
DEVICE3: "/dev/sdb"
devices:
- /dev/sda
- /dev/sdb
```
Make sure to bind the disk via its UUID (obtainable via `lsblk -o name,uuid`) instead of its name (`/dev/sdc`), to prevent ever binding the wrong disk when the drive letters happen to change.
Please note that the device needs to be totally empty (without any partition table) otherwise DSM does not always format it into a volume.
> [!IMPORTANT]
> The device needs to be totally empty (without any partition table) otherwise DSM does not always format it into a volume.
Do NOT use this feature with the goal of sharing files from the host, they will all be lost without warning when DSM creates the volume.
> [!CAUTION]
> Do NOT use this feature with the goal of sharing files from the host, they will all be lost without warning when DSM creates the volume.
* ### How do I increase the amount of CPU or RAM?
### How do I change the amount of CPU or RAM?
By default, a single CPU core and 1 GB of RAM are allocated to the container.
By default, the container will be allowed to use a maximum of 1 CPU core and 1 GB of RAM.
To increase this, add the following environment variables:
If you want to adjust this, you can specify the desired amount using the following environment variables:
```yaml
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
```yaml
environment:
RAM_SIZE: "4G"
CPU_CORES: "4"
```
* ### How do I verify if my system supports KVM?
### How do I verify if my system supports KVM?
To verify if your system supports KVM, run the following commands:
To verify that your system supports KVM, run the following commands:
```bash
sudo apt install cpu-checker
sudo kvm-ok
```
```bash
sudo apt install cpu-checker
sudo kvm-ok
```
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS.
If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, please check whether:
* ### How do I assign an individual IP address to the container?
- the virtualization extensions (`Intel VT-x` or `AMD SVM`) are enabled in your BIOS.
By default, the container uses bridge networking, which shares the IP address with the host.
- you are running an operating system that supports them, like Linux or Windows 11 (macOS and Windows 10 do not unfortunately).
If you want to assign an individual IP address to the container, you can create a macvlan network as follows:
- you enabled "nested virtualization" if you are running the container inside a virtual machine.
```bash
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
- you are not using a cloud provider, as most of them do not allow nested virtualization for their VPS's.
Once you have created the network, change your compose file to look as follows:
If you didn't receive any error from `kvm-ok` at all, but the container still complains that `/dev/kvm` is missing, it might help to add `privileged: true` to your compose file (or `--privileged` to your `run` command), to rule out any permission issue.
```yaml
services:
dsm:
container_name: dsm
..<snip>..
networks:
vdsm:
ipv4_address: 192.168.0.100
### How do I assign an individual IP address to the container?
networks:
vdsm:
external: true
```
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
By default, the container uses bridge networking, which shares the IP address with the host.
Please note that this IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
If you want to assign an individual IP address to the container, you can create a macvlan network as follows:
* ### How can DSM acquire an IP address from my router?
```bash
docker network create -d macvlan \
--subnet=192.168.0.0/24 \
--gateway=192.168.0.1 \
--ip-range=192.168.0.100/28 \
-o parent=eth0 vdsm
```
Be sure to modify these values to match your local subnet.
After configuring the container for macvlan (see above), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
Once you have created the network, change your compose file to look as follows:
To enable this feature, add the following lines to your compose file:
```yaml
services:
dsm:
container_name: dsm
..<snip>..
networks:
vdsm:
ipv4_address: 192.168.0.100
```yaml
environment:
DHCP: "Y"
device_cgroup_rules:
- 'c *:* rwm'
```
networks:
vdsm:
external: true
```
An added benefit of this approach is that you won't have to perform any port mapping anymore, since all ports will be exposed by default.
Please note that even if you don't want DHCP, it's still recommended to enable this feature, as it prevents NAT issues and increases performance by using a `macvtap` interface. In that case, just set a static IP from the DSM control panel after you enabled this mode.
> [!IMPORTANT]
> This IP address won't be accessible from the Docker host due to the design of macvlan, which doesn't permit communication between the two. If this is a concern, you need to create a [second macvlan](https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/#host-access) as a workaround.
* ### How do I pass-through the GPU?
### How can DSM acquire an IP address from my router?
To pass-through your Intel GPU, add the following lines to your compose file:
After configuring the container for [macvlan](#how-do-i-assign-an-individual-ip-address-to-the-container), it is possible for DSM to become part of your home network by requesting an IP from your router, just like your other devices.
```yaml
environment:
GPU: "Y"
devices:
- /dev/dri
```
To enable this mode, add the following lines to your compose file:
This can be used to enable the facial recognition function in Synology Photos for example.
```yaml
environment:
DHCP: "Y"
devices:
- /dev/vhost-net
device_cgroup_rules:
- 'c *:* rwm'
```
* ### How do I install a specific version of vDSM?
> [!NOTE]
> In this mode, the container and DSM will each have their own separate IPs.
By default, version 7.2 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows:
### How do I pass-through the GPU?
```yaml
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
To pass-through your Intel GPU, add the following lines to your compose file:
With this method, it is even possible to switch between different versions while keeping all your file data intact.
```yaml
environment:
GPU: "Y"
devices:
- /dev/dri
```
* ### What are the differences compared to the standard DSM?
> [!TIP]
> This can be used to enable the facial recognition function in Synology Photos for example.
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
* ### Is this project legal?
### How do I install a specific version of vDSM?
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project would be considered legal.
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this project on an official Synology NAS, as any other use will be a violation of their terms and conditions.
By default, version 7.2 will be installed, but if you prefer an older version, you can add its download URL to your compose file as follows:
## Disclaimer
```yaml
environment:
URL: "https://global.synologydownload.com/download/DSM/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
```
Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc.
With this method, it is even possible to switch between different versions while keeping all your file data intact.
If you don't have internet access, it's also possible to skip the download by setting URL to:
```yaml
environment:
URL: "DSM_VirtualDSM_42218.pat"
```
after placing a file called `DSM_VirtualDSM_42218.pat` in your `/storage` folder.
### What are the differences compared to the standard DSM?
There are only two minor differences: the Virtual Machine Manager package is not available, and Surveillance Station will not include any free licenses.
### Is this project legal?
Yes, this project contains only open-source code and does not distribute any copyrighted material. Neither does it try to circumvent any copyright protection measures. So under all applicable laws, this project will be considered legal.
However, by installing Synology's Virtual DSM, you must accept their end-user license agreement, which does not permit installation on non-Synology hardware. So only run this container on an official Synology NAS, as any other use will be a violation of their terms and conditions.
## Stars 🌟
[![Stars](https://starchart.cc/vdsm/virtual-dsm.svg?variant=adaptive)](https://starchart.cc/vdsm/virtual-dsm)
## Disclaimer ⚖️
*Only run this container on Synology hardware, any other use is not permitted by their EULA. The product names, logos, brands, and other trademarks referred to within this project are the property of their respective trademark holders. This project is not affiliated, sponsored, or endorsed by Synology, Inc.*
[build_url]: https://github.com/vdsm/virtual-dsm/
[hub_url]: https://hub.docker.com/r/vdsm/virtual-dsm
[tag_url]: https://hub.docker.com/r/vdsm/virtual-dsm/tags
[pkg_url]: https://github.com/vdsm/virtual-dsm/pkgs/container/virtual-dsm
[Build]: https://github.com/vdsm/virtual-dsm/actions/workflows/build.yml/badge.svg
[Size]: https://img.shields.io/docker/image-size/vdsm/virtual-dsm/latest?color=066da5&label=size
[Pulls]: https://img.shields.io/docker/pulls/kroese/virtual-dsm.svg?style=flat&label=pulls&logo=docker
[Pulls]: https://img.shields.io/docker/pulls/vdsm/virtual-dsm.svg?style=flat&label=pulls&logo=docker
[Version]: https://img.shields.io/docker/v/vdsm/virtual-dsm/latest?arch=amd64&sort=semver&color=066da5
[Package]: https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fipitio.github.io%2Fbackage%2Fvdsm%2Fvirtual-dsm%2Fvirtual-dsm.json&query=%24.downloads&logo=github&style=flat&color=066da5&label=pulls

View File

@@ -1,13 +1,16 @@
#!/usr/bin/env bash
set -Eeuo pipefail
: "${NETWORK:="Y"}"
[ -f "/run/shm/qemu.end" ] && echo "QEMU is shutting down.." && exit 1
[ ! -f "/run/shm/qemu.pid" ] && echo "QEMU is not running yet.." && exit 0
[ ! -s "/run/shm/qemu.pid" ] && echo "QEMU is not running yet.." && exit 0
[[ "$NETWORK" == [Nn]* ]] && echo "Networking is disabled.." && exit 0
file="/run/shm/dsm.url"
address="/run/shm/qemu.ip"
[ ! -f "$file" ] && echo "DSM has not enabled networking yet.." && exit 1
[ ! -s "$file" ] && echo "DSM has not enabled networking yet.." && exit 1
location=$(<"$file")

View File

@@ -2,14 +2,36 @@
set -Eeuo pipefail
DEF_OPTS="-nodefaults -boot strict=on"
RAM_OPTS=$(echo "-m $RAM_SIZE" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
RAM_OPTS=$(echo "-m ${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
CPU_OPTS="-cpu $CPU_FLAGS -smp $CPU_CORES,sockets=1,dies=1,cores=$CPU_CORES,threads=1"
MAC_OPTS="-machine type=q35,usb=off,vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
MAC_OPTS="-machine type=q35,smm=off,usb=off,vmport=off,dump-guest-core=off,hpet=off${KVM_OPTS}"
DEV_OPTS="-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x4"
DEV_OPTS="$DEV_OPTS -object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS="$DEV_OPTS -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
DEV_OPTS+=" -object rng-random,id=objrng0,filename=/dev/urandom"
DEV_OPTS+=" -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pcie.0,addr=0x1c"
ARGS="$DEF_OPTS $CPU_OPTS $RAM_OPTS $MAC_OPTS $DISPLAY_OPTS $MON_OPTS $SERIAL_OPTS $NET_OPTS $DISK_OPTS $DEV_OPTS $ARGUMENTS"
ARGS=$(echo "$ARGS" | sed 's/\t/ /g' | tr -s ' ')
# Check available memory as the very last step
if [[ "$RAM_CHECK" != [Nn]* ]]; then
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
AVAIL_GB=$(( RAM_AVAIL/1073741824 ))
if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
error "Your configured RAM_SIZE of $WANTED_GB GB is too high for the $AVAIL_GB GB of memory available, please set a lower value."
exit 17
fi
if (( (RAM_WANTED + (RAM_SPARE * 3)) > RAM_AVAIL )); then
warn "your configured RAM_SIZE of $WANTED_GB GB is very close to the $AVAIL_GB GB of memory available, please consider a lower value."
fi
fi
if [[ "$DEBUG" == [Yy1]* ]]; then
printf "Arguments:\n\n%s" "${ARGS// -/$'\n-'}" && echo
fi
return 0

View File

@@ -5,6 +5,7 @@ set -Eeuo pipefail
: "${DISK_IO:="native"}" # I/O Mode, can be set to 'native', 'threads' or 'io_turing'
: "${DISK_FMT:="raw"}" # Disk file format, 'raw' by default for best performance
: "${DISK_TYPE:=""}" # Device type to be used, choose "ide", "usb", "blk" or "scsi"
: "${DISK_FLAGS:=""}" # Specifies the options for use with the qcow2 disk format
: "${DISK_CACHE:="none"}" # Caching mode, can be set to 'writeback' for better performance
: "${DISK_DISCARD:="on"}" # Controls whether unmap (TRIM) commands are passed to the host.
@@ -13,17 +14,8 @@ set -Eeuo pipefail
BOOT="$STORAGE/$BASE.boot.img"
SYSTEM="$STORAGE/$BASE.system.img"
[ ! -f "$BOOT" ] && error "Virtual DSM boot-image does not exist ($BOOT)" && exit 81
[ ! -f "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
DISK_OPTS="\
-object iothread,id=io2 \
-device virtio-scsi-pci,id=hw-synoboot,iothread=io2,bus=pcie.0,addr=0xa \
-drive file=$BOOT,if=none,id=drive-synoboot,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-synoboot.0,channel=0,scsi-id=0,lun=0,drive=drive-synoboot,id=synoboot0,rotation_rate=$DISK_ROTATION,bootindex=1 \
-device virtio-scsi-pci,id=hw-synosys,iothread=io2,bus=pcie.0,addr=0xb \
-drive file=$SYSTEM,if=none,id=drive-synosys,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-synosys.0,channel=0,scsi-id=0,lun=0,drive=drive-synosys,id=synosys0,rotation_rate=$DISK_ROTATION,bootindex=2"
[ ! -s "$BOOT" ] && error "Virtual DSM boot-image does not exist ($BOOT)" && exit 81
[ ! -s "$SYSTEM" ] && error "Virtual DSM system-image does not exist ($SYSTEM)" && exit 82
fmt2ext() {
local DISK_FMT=$1
@@ -80,14 +72,25 @@ getSize() {
isCow() {
local FS=$1
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
if [[ "${FS,,}" == "btrfs" ]]; then
return 0
fi
return 1
}
supportsDirect() {
local FS=$1
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
return 1
fi
return 0
}
createDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
@@ -113,9 +116,9 @@ createDisk() {
fi
html "Creating a $DISK_DESC image..."
info "Creating a $DISK_TYPE $DISK_DESC image in $DISK_FMT format with a size of $DISK_SPACE..."
info "Creating a $DISK_SPACE $DISK_STYLE $DISK_DESC image in $DISK_FMT format..."
local FAIL="Could not create a $DISK_TYPE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
local FAIL="Could not create a $DISK_STYLE $DISK_FMT $DISK_DESC image of $DISK_SPACE ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
@@ -150,8 +153,8 @@ createDisk() {
qcow2)
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
isCow "$FS" && DISK_PARAM+=",nocow=on"
[ -n "$DISK_FLAGS" ] && DISK_PARAM+=",$DISK_FLAGS"
if ! qemu-img create -f "$DISK_FMT" -o "$DISK_PARAM" -- "$DISK_FILE" "$DATA_SIZE" ; then
rm -f "$DISK_FILE"
@@ -171,6 +174,7 @@ createDisk() {
}
resizeDisk() {
local DISK_FILE=$1
local DISK_SPACE=$2
local DISK_DESC=$3
@@ -200,7 +204,7 @@ resizeDisk() {
MSG="Resizing $DISK_DESC from ${GB}G to $DISK_SPACE..."
info "$MSG" && html "$MSG"
local FAIL="Could not resize the $DISK_TYPE $DISK_FMT $DISK_DESC image from ${GB}G to $DISK_SPACE ($DISK_FILE)"
local FAIL="Could not resize the $DISK_STYLE $DISK_FMT $DISK_DESC image from ${GB}G to $DISK_SPACE ($DISK_FILE)"
case "${DISK_FMT,,}" in
raw)
@@ -236,6 +240,7 @@ resizeDisk() {
}
convertDisk() {
local SOURCE_FILE=$1
local SOURCE_FMT=$2
local DST_FILE=$3
@@ -266,34 +271,35 @@ convertDisk() {
fi
fi
html "Converting $DISK_DESC to $DST_FMT..."
info "Converting $DISK_DESC to $DST_FMT, please wait until completed..."
local msg="Converting $DISK_DESC to $DST_FMT"
html "$msg..."
info "$msg, please wait until completed..."
local CONV_FLAGS="-p"
local DISK_PARAM="$DISK_ALLOC"
isCow "$FS" && DISK_PARAM="$DISK_PARAM,nocow=on"
isCow "$FS" && DISK_PARAM+=",nocow=on"
if [[ "$DST_FMT" != "raw" ]]; then
if [[ "$ALLOCATE" == [Nn]* ]]; then
CONV_FLAGS="$CONV_FLAGS -c"
fi
[ -n "$DISK_FLAGS" ] && DISK_PARAM="$DISK_PARAM,$DISK_FLAGS"
if [[ "$ALLOCATE" == [Nn]* ]]; then
CONV_FLAGS+=" -c"
fi
[ -n "$DISK_FLAGS" ] && DISK_PARAM+=",$DISK_FLAGS"
fi
# shellcheck disable=SC2086
if ! qemu-img convert -f "$SOURCE_FMT" $CONV_FLAGS -o "$DISK_PARAM" -O "$DST_FMT" -- "$SOURCE_FILE" "$TMP_FILE"; then
rm -f "$TMP_FILE"
error "Failed to convert $DISK_TYPE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
error "Failed to convert $DISK_STYLE $DISK_DESC image to $DST_FMT format in $DIR, is there enough space available?" && exit 79
fi
if [[ "$DST_FMT" == "raw" ]]; then
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Work around qemu-img bug
CUR_SIZE=$(stat -c%s "$TMP_FILE")
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE"; then
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
fi
if [[ "$ALLOCATE" != [Nn]* ]]; then
# Work around qemu-img bug
CUR_SIZE=$(stat -c%s "$TMP_FILE")
if ! fallocate -l "$CUR_SIZE" "$TMP_FILE"; then
error "Failed to allocate $CUR_SIZE bytes for $DISK_DESC image $TMP_FILE"
fi
fi
fi
rm -f "$SOURCE_FILE"
@@ -306,13 +312,15 @@ convertDisk() {
fi
fi
html "Conversion of $DISK_DESC completed..."
info "Conversion of $DISK_DESC to $DST_FMT completed succesfully!"
msg="Conversion of $DISK_DESC"
html "$msg completed..."
info "$msg to $DST_FMT completed succesfully!"
return 0
}
checkFS () {
local FS=$1
local DISK_FILE=$2
local DISK_DESC=$3
@@ -329,6 +337,10 @@ checkFS () {
info "Warning: the filesystem of $DIR is FUSE, this extra layer will negatively affect performance!"
fi
if ! supportsDirect "$FS"; then
info "Warning: the filesystem of $DIR is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if isCow "$FS"; then
if [ -f "$DISK_FILE" ]; then
FA=$(lsattr "$DISK_FILE")
@@ -341,51 +353,108 @@ checkFS () {
return 0
}
createDevice () {
local DISK_FILE=$1
local DISK_TYPE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
local DISK_FMT=$5
local DISK_IO=$6
local DISK_CACHE=$7
local DISK_ID="data$DISK_INDEX"
local index=""
[ -n "$DISK_INDEX" ] && index=",bootindex=$DISK_INDEX"
local result=" -drive file=$DISK_FILE,id=$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on"
case "${DISK_TYPE,,}" in
"auto" )
echo "$result"
;;
"usb" )
result+=",if=none \
-device usb-storage,drive=${DISK_ID}${index}"
echo "$result"
;;
"ide" )
result+=",if=none \
-device ich9-ahci,id=ahci${DISK_INDEX},addr=$DISK_ADDRESS \
-device ide-hd,drive=${DISK_ID},bus=ahci$DISK_INDEX.0,rotation_rate=$DISK_ROTATION${index}"
echo "$result"
;;
"blk" | "virtio-blk" )
result+=",if=none \
-device virtio-blk-pci,drive=${DISK_ID},bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2${index}"
echo "$result"
;;
"scsi" | "virtio-scsi" )
result+=",if=none \
-device virtio-scsi-pci,id=${DISK_ID}b,bus=pcie.0,addr=$DISK_ADDRESS,iothread=io2 \
-device scsi-hd,drive=${DISK_ID},bus=${DISK_ID}b.0,channel=0,scsi-id=0,lun=0,rotation_rate=$DISK_ROTATION${index}"
echo "$result"
;;
esac
return 0
}
addDisk () {
local DISK_ID=$1
local DISK_BASE=$2
local DISK_EXT=$3
local DISK_DESC=$4
local DISK_SPACE=$5
local DISK_INDEX=$6
local DISK_ADDRESS=$7
local DISK_FMT=$8
local DISK_BASE=$1
local DISK_TYPE=$2
local DISK_DESC=$3
local DISK_SPACE=$4
local DISK_INDEX=$5
local DISK_ADDRESS=$6
local DISK_FMT=$7
local DISK_IO=$8
local DISK_CACHE=$9
local DISK_EXT DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE OPTS
DISK_EXT=$(fmt2ext "$DISK_FMT")
local DISK_FILE="$DISK_BASE.$DISK_EXT"
local DIR DATA_SIZE FS PREV_FMT PREV_EXT CUR_SIZE
DIR=$(dirname "$DISK_FILE")
[ ! -d "$DIR" ] && return 0
[ -z "$DISK_SPACE" ] && DISK_SPACE="16G"
DISK_SPACE=$(echo "${DISK_SPACE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
[[ -z "${DISK_SPACE//[0-9]}" ]] && DISK_SPACE="${DISK_SPACE}G"
DATA_SIZE=$(numfmt --from=iec "$DISK_SPACE")
if (( DATA_SIZE < 6442450944 )); then
if (( DATA_SIZE < 1 )); then
if (( DATA_SIZE < 1 )); then
error "Invalid value for ${DISK_DESC^^}_SIZE: $DISK_SPACE" && exit 73
else
fi
if (( DATA_SIZE < 6442450944 )); then
error "Please increase ${DISK_DESC^^}_SIZE to at least 6 GB." && exit 73
fi
fi
FS=$(stat -f -c %T "$DIR")
checkFS "$FS" "$DISK_FILE" "$DISK_DESC" || exit $?
if ! [ -f "$DISK_FILE" ] ; then
if ! supportsDirect "$FS"; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
if ! [ -s "$DISK_FILE" ] ; then
if [[ "${DISK_FMT,,}" != "raw" ]]; then
PREV_FMT="raw"
else
PREV_FMT="qcow2"
fi
PREV_EXT=$(fmt2ext "$PREV_FMT")
if [ -f "$DISK_BASE.$PREV_EXT" ] ; then
if [ -s "$DISK_BASE.$PREV_EXT" ] ; then
convertDisk "$DISK_BASE.$PREV_EXT" "$PREV_FMT" "$DISK_FILE" "$DISK_FMT" "$DISK_BASE" "$DISK_DESC" "$FS" || exit $?
fi
fi
if [ -f "$DISK_FILE" ]; then
if [ -s "$DISK_FILE" ]; then
CUR_SIZE=$(getSize "$DISK_FILE")
@@ -399,36 +468,36 @@ addDisk () {
fi
DISK_OPTS="$DISK_OPTS \
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
-drive file=$DISK_FILE,if=none,id=drive-$DISK_ID,format=$DISK_FMT,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
DISK_OPTS+=$(createDevice "$DISK_FILE" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE")
return 0
}
addDevice () {
local DISK_ID=$1
local DISK_DEV=$2
local DISK_DESC=$3
local DISK_INDEX=$4
local DISK_ADDRESS=$5
local DISK_DEV=$1
local DISK_TYPE=$2
local DISK_INDEX=$3
local DISK_ADDRESS=$4
[ -z "$DISK_DEV" ] && return 0
[ ! -b "$DISK_DEV" ] && error "Device $DISK_DEV cannot be found! Please add it to the 'devices' section of your compose file." && exit 55
DISK_OPTS="$DISK_OPTS \
-device virtio-scsi-pci,id=hw-$DISK_ID,iothread=io2,bus=pcie.0,addr=$DISK_ADDRESS \
-drive file=$DISK_DEV,if=none,id=drive-$DISK_ID,format=raw,cache=$DISK_CACHE,aio=$DISK_IO,discard=$DISK_DISCARD,detect-zeroes=on \
-device scsi-hd,bus=hw-$DISK_ID.0,channel=0,scsi-id=0,lun=0,drive=drive-$DISK_ID,id=$DISK_ID,rotation_rate=$DISK_ROTATION,bootindex=$DISK_INDEX"
DISK_OPTS+=$(createDevice "$DISK_DEV" "$DISK_TYPE" "$DISK_INDEX" "$DISK_ADDRESS" "raw" "$DISK_IO" "$DISK_CACHE")
return 0
}
html "Initializing disks..."
DISK_EXT=$(fmt2ext "$DISK_FMT")
[ -z "${DISK_OPTS:-}" ] && DISK_OPTS=""
[ -z "${DISK_TYPE:-}" ] && DISK_TYPE="scsi"
[ -z "${DISK_NAME:-}" ] && DISK_NAME="data"
case "${DISK_TYPE,,}" in
"ide" | "usb" | "scsi" | "blk" | "auto" ) ;;
* ) error "Invalid DISK_TYPE specified, value \"$DISK_TYPE\" is not recognized!" && exit 80 ;;
esac
if [ -z "$ALLOCATE" ]; then
if [[ "${DISK_FMT,,}" == "raw" ]]; then
@@ -439,20 +508,23 @@ if [ -z "$ALLOCATE" ]; then
fi
if [[ "$ALLOCATE" == [Nn]* ]]; then
DISK_TYPE="growable"
DISK_STYLE="growable"
DISK_ALLOC="preallocation=off"
else
DISK_TYPE="preallocated"
DISK_STYLE="preallocated"
DISK_ALLOC="preallocation=falloc"
fi
DISK1_FILE="$STORAGE/data"
DISK_OPTS+=$(createDevice "$BOOT" "$DISK_TYPE" "1" "0xa" "raw" "$DISK_IO" "$DISK_CACHE")
DISK_OPTS+=$(createDevice "$SYSTEM" "$DISK_TYPE" "2" "0xb" "raw" "$DISK_IO" "$DISK_CACHE")
DISK1_FILE="$STORAGE/${DISK_NAME}"
if [[ ! -f "$DISK1_FILE.img" ]] && [[ -f "$STORAGE/data${DISK_SIZE}.img" ]]; then
# Fallback for legacy installs
mv "$STORAGE/data${DISK_SIZE}.img" "$DISK1_FILE.img"
fi
DISK2_FILE="/storage2/data2"
DISK2_FILE="/storage2/${DISK_NAME}2"
if [ ! -f "$DISK2_FILE.img" ]; then
# Fallback for legacy installs
FALLBACK="/storage2/data.img"
@@ -465,7 +537,7 @@ if [ ! -f "$DISK2_FILE.img" ]; then
fi
fi
DISK3_FILE="/storage3/data3"
DISK3_FILE="/storage3/${DISK_NAME}3"
if [ ! -f "$DISK3_FILE.img" ]; then
# Fallback for legacy installs
FALLBACK="/storage3/data.img"
@@ -478,7 +550,7 @@ if [ ! -f "$DISK3_FILE.img" ]; then
fi
fi
DISK4_FILE="/storage4/data4"
DISK4_FILE="/storage4/${DISK_NAME}4"
: "${DISK2_SIZE:=""}"
: "${DISK3_SIZE:=""}"
@@ -489,29 +561,42 @@ DISK4_FILE="/storage4/data4"
: "${DEVICE3:=""}"
: "${DEVICE4:=""}"
[ -z "$DEVICE" ] && [ -b "/disk" ] && DEVICE="/disk"
[ -z "$DEVICE" ] && [ -b "/disk1" ] && DEVICE="/disk1"
[ -z "$DEVICE2" ] && [ -b "/disk2" ] && DEVICE2="/disk2"
[ -z "$DEVICE3" ] && [ -b "/disk3" ] && DEVICE3="/disk3"
[ -z "$DEVICE4" ] && [ -b "/disk4" ] && DEVICE4="/disk4"
[ -z "$DEVICE" ] && [ -b "/dev/disk1" ] && DEVICE="/dev/disk1"
[ -z "$DEVICE2" ] && [ -b "/dev/disk2" ] && DEVICE2="/dev/disk2"
[ -z "$DEVICE3" ] && [ -b "/dev/disk3" ] && DEVICE3="/dev/disk3"
[ -z "$DEVICE4" ] && [ -b "/dev/disk4" ] && DEVICE4="/dev/disk4"
if [ -n "$DEVICE" ]; then
addDevice "userdata" "$DEVICE" "device" "3" "0xc" || exit $?
addDevice "$DEVICE" "$DISK_TYPE" "3" "0xc" || exit $?
else
addDisk "userdata" "$DISK1_FILE" "$DISK_EXT" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" || exit $?
addDisk "$DISK1_FILE" "$DISK_TYPE" "disk" "$DISK_SIZE" "3" "0xc" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE2" ]; then
addDevice "userdata2" "$DEVICE2" "device2" "4" "0xd" || exit $?
addDevice "$DEVICE2" "$DISK_TYPE" "4" "0xd" || exit $?
else
addDisk "userdata2" "$DISK2_FILE" "$DISK_EXT" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" || exit $?
addDisk "$DISK2_FILE" "$DISK_TYPE" "disk2" "$DISK2_SIZE" "4" "0xd" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE3" ]; then
addDevice "userdata3" "$DEVICE3" "device3" "5" "0xe" || exit $?
addDevice "$DEVICE3" "$DISK_TYPE" "5" "0xe" || exit $?
else
addDisk "userdata3" "$DISK3_FILE" "$DISK_EXT" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" || exit $?
addDisk "$DISK3_FILE" "$DISK_TYPE" "disk3" "$DISK3_SIZE" "5" "0xe" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
if [ -n "$DEVICE4" ]; then
addDevice "userdata4" "$DEVICE4" "device4" "6" "0xf" || exit $?
addDevice "$DEVICE4" "$DISK_TYPE" "6" "0xf" || exit $?
else
addDisk "userdata4" "$DISK4_FILE" "$DISK_EXT" "disk4" "$DISK4_SIZE" "6" "0xf" "$DISK_FMT" || exit $?
addDisk "$DISK4_FILE" "$DISK_TYPE" "disk4" "$DISK4_SIZE" "6" "0xf" "$DISK_FMT" "$DISK_IO" "$DISK_CACHE" || exit $?
fi
DISK_OPTS+=" -object iothread,id=io2"
html "Initialized disks successfully..."
return 0

View File

@@ -6,6 +6,7 @@ set -Eeuo pipefail
: "${GPU:="N"}" # GPU passthrough
: "${VGA:="virtio"}" # VGA adaptor
: "${DISPLAY:="none"}" # Display type
: "${RENDERNODE:="/dev/dri/renderD128"}" # Render node
if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
@@ -15,19 +16,24 @@ if [[ "$GPU" != [Yy1]* ]] || [[ "$ARCH" != "amd64" ]]; then
fi
DISPLAY_OPTS="-display egl-headless,rendernode=/dev/dri/renderD128 -vga $VGA"
DISPLAY_OPTS="-display egl-headless,rendernode=$RENDERNODE"
DISPLAY_OPTS+=" -vga $VGA"
[ ! -d /dev/dri ] && mkdir -m 755 /dev/dri
if [ ! -c /dev/dri/card0 ]; then
if mknod /dev/dri/card0 c 226 0; then
chmod 666 /dev/dri/card0
# Extract the card number from the render node
CARD_NUMBER=$(echo "$RENDERNODE" | grep -oP '(?<=renderD)\d+')
CARD_DEVICE="/dev/dri/card$((CARD_NUMBER - 128))"
if [ ! -c "$CARD_DEVICE" ]; then
if mknod "$CARD_DEVICE" c 226 $((CARD_NUMBER - 128)); then
chmod 666 "$CARD_DEVICE"
fi
fi
if [ ! -c /dev/dri/renderD128 ]; then
if mknod /dev/dri/renderD128 c 226 128; then
chmod 666 /dev/dri/renderD128
if [ ! -c "$RENDERNODE" ]; then
if mknod "$RENDERNODE" c 226 "$CARD_NUMBER"; then
chmod 666 "$RENDERNODE"
fi
fi

View File

@@ -18,8 +18,8 @@ cd /run
trap - ERR
info "Booting $APP using $VERS..."
[[ "$DEBUG" == [Yy1]* ]] && echo "Arguments: $ARGS" && echo
version=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1 | awk '{ print $NF }')
info "Booting $APP using QEMU v$version..."
if [[ "$CONSOLE" == [Yy]* ]]; then
exec qemu-system-x86_64 ${ARGS:+ $ARGS}
@@ -32,4 +32,5 @@ terminal
tail -fn +0 "$QEMU_LOG" 2>/dev/null &
cat "$QEMU_TERM" 2>/dev/null & wait $! || :
sleep 1 && finish 0
sleep 1 & wait $!
[ ! -f "$QEMU_END" ] && finish 0

View File

@@ -5,6 +5,7 @@ set -Eeuo pipefail
if [ -f "$STORAGE/dsm.ver" ]; then
BASE=$(<"$STORAGE/dsm.ver")
[ -z "$BASE" ] && BASE="DSM_VirtualDSM_69057"
else
# Fallback for old installs
BASE="DSM_VirtualDSM_42962"
@@ -12,14 +13,21 @@ fi
if [ -n "$URL" ]; then
BASE=$(basename "$URL" .pat)
if [ ! -f "$STORAGE/$BASE.system.img" ]; then
if [ ! -s "$STORAGE/$BASE.system.img" ]; then
BASE=$(basename "${URL%%\?*}" .pat)
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}"
BASE=$(echo "$BASE" | sed -e 's/[^A-Za-z0-9._-]/_/g')
fi
if [[ "${URL,,}" != "http"* ]]; then
if [ -s "$STORAGE/$BASE.pat" ]; then
URL="file://$STORAGE/$BASE.pat"
else
error "File $STORAGE/$BASE.pat does not exist!" && exit 65
fi
fi
fi
if [[ -f "$STORAGE/$BASE.boot.img" ]] && [[ -f "$STORAGE/$BASE.system.img" ]]; then
if [[ -s "$STORAGE/$BASE.boot.img" ]] && [[ -s "$STORAGE/$BASE.system.img" ]]; then
return 0 # Previous installation found
fi
@@ -38,7 +46,7 @@ if [ -z "$DL" ]; then
[[ "${COUNTRY^^}" == "CN" ]] && DL="$DL_CHINA" || DL="$DL_GLOBAL"
fi
[ -z "$URL" ] && URL="$DL/release/7.2.1/69057-1/DSM_VirtualDSM_69057.pat"
[ -z "$URL" ] && URL="$DL/release/7.2.2/72806/DSM_VirtualDSM_72806.pat"
BASE=$(basename "${URL%%\?*}" .pat)
: "${BASE//+/ }"; printf -v BASE '%b' "${_//%/\\x}"
@@ -52,8 +60,6 @@ rm -f "$STORAGE/$BASE.agent"
rm -f "$STORAGE/$BASE.boot.img"
rm -f "$STORAGE/$BASE.system.img"
[[ "$DEBUG" == [Yy1]* ]] && set -x
# Check filesystem
FS=$(stat -f -c %T "$STORAGE")
@@ -65,7 +71,15 @@ if [[ "${FS,,}" == "fuse"* ]]; then
info "Warning: the filesystem of $STORAGE is FUSE, this extra layer will negatively affect performance!"
fi
if [[ "${FS,,}" != "fat"* && "${FS,,}" != "vfat"* && "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "msdos"* ]]; then
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
info "Warning: the filesystem of $STORAGE is $FS, which does not support O_DIRECT mode, adjusting settings..."
fi
if [[ "${FS,,}" == "fat"* || "${FS,,}" == "vfat"* || "${FS,,}" == "msdos"* ]]; then
error "Unable to install on $FS filesystems, please use a different filesystem for /storage." && exit 61
fi
if [[ "${FS,,}" != "exfat"* && "${FS,,}" != "ntfs"* && "${FS,,}" != "unknown"* ]]; then
TMP="$STORAGE/tmp"
else
TMP="/tmp/dsm"
@@ -85,10 +99,10 @@ SPACE=$(df --output=avail -B 1 / | tail -n 1)
SPACE_MB=$(( (SPACE + 1048575)/1048576 ))
(( ROOT_SPACE > SPACE )) && error "Not enough free space inside the container, have $SPACE_MB MB available but need at least 500 MB." && exit 96
MIN_SPACE=8589934592
MIN_SPACE=15032385536
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB GB available but need at least 8 GB." && exit 94
(( MIN_SPACE > SPACE )) && error "Not enough free space for installation in $STORAGE, have $SPACE_GB GB available but need at least 14 GB." && exit 94
# Check if output is to interactive TTY
if [ -t 1 ]; then
@@ -100,31 +114,71 @@ fi
# Download the required files from the Synology website
ROOT="Y"
RD="$TMP/rd.gz"
RDC="$STORAGE/dsm.rd"
if [ ! -f "$RDC" ]; then
if [ ! -s "$RDC" ] && [[ "$URL" == "file://"* ]] && [[ "${URL,,}" == *"_42218.pat" ]]; then
MSG="Downloading installer..."
info "Install: $MSG" && html "$MSG"
rm -f "$RD"
rm -f "$RDC"
RD="$TMP/rd.gz"
tar --extract --file="${URL:7}" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
cp "$RD" "$RDC"
fi
if [ ! -s "$RDC" ]; then
rm -f "$RD"
rm -f "$RDC"
MSG="Downloading installer"
info "Install: $MSG..." && html "$MSG..."
SIZE=5394188
POS="65627648-71021835"
VERIFY="b4215a4b213ff5154db0488f92c87864"
LOC="$DL/release/7.0.1/42218/DSM_VirtualDSM_42218.pat"
[[ "${URL,,}" == *"_42218.pat" ]] && LOC="$URL"
{ curl -r "$POS" -sfk -S -o "$RD" "$LOC"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
/run/progress.sh "$RD" "$SIZE" "$MSG ([P])..." &
{ curl -r "$POS" -sfk --connect-timeout 10 -S -o "$RD" "$LOC"; rc=$?; } || :
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
fKill "progress.sh"
ERR="Failed to download $LOC"
(( rc == 3 )) && error "$ERR , cannot write file (disk full?)" && exit 60
(( rc == 4 )) && error "$ERR , network failure!" && exit 60
(( rc == 8 )) && error "$ERR , server issued an error response!" && exit 60
if (( rc != 0 )); then
if (( rc != 22 )) && (( rc != 56 )); then
error "$ERR , reason: $rc" && exit 60
fi
SUM="skip"
else
SUM=$(md5sum "$RD" | cut -f 1 -d " ")
fi
if [ "$SUM" != "$VERIFY" ]; then
PAT="/install.pat"
rm "$RD"
SIZE=379637760
rm -f "$RD"
rm -f "$PAT"
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $LOC, reason: $rc" && exit 60
html "$MSG..."
/run/progress.sh "$PAT" "$SIZE" "$MSG ([P])..." &
{ wget "$LOC" -O "$PAT" -q --no-check-certificate --timeout=10 --show-progress "$PROGRESS"; rc=$?; } || :
fKill "progress.sh"
ERR="Failed to download $LOC"
(( rc == 3 )) && error "$ERR , cannot write file (disk full?)" && exit 60
(( rc == 4 )) && error "$ERR , network failure!" && exit 60
(( rc == 8 )) && error "$ERR , server issued an error response!" && exit 60
(( rc != 0 )) && error "$ERR , reason: $rc" && exit 60
tar --extract --file="$PAT" --directory="$(dirname "$RD")"/. "$(basename "$RD")"
rm "$PAT"
@@ -138,14 +192,14 @@ fi
if [ -f "$RDC" ]; then
{ xz -dc <"$RDC" >"$TMP/rd" 2>/dev/null; rc=$?; } || :
(( rc != 1 )) && error "Failed to unxz $RDC, reason $rc" && exit 91
(( rc != 1 )) && error "Failed to unxz $RDC on $FS, reason $rc" && exit 91
{ (cd "$TMP" && cpio -idm <"$TMP/rd" 2>/dev/null); rc=$?; } || :
if (( rc != 0 )); then
ROOT="N"
{ (cd "$TMP" && fakeroot cpio -idmu <"$TMP/rd" 2>/dev/null); rc=$?; } || :
(( rc != 0 )) && error "Failed to extract $RDC, reason $rc" && exit 92
(( rc != 0 )) && error "Failed to extract $RDC on $FS, reason $rc" && exit 92
fi
rm -rf /run/extract && mkdir -p /run/extract
@@ -175,7 +229,11 @@ fi
rm -rf "$TMP" && mkdir -p "$TMP"
info "Install: Downloading $BASE.pat..."
html "Install: Downloading DSM from Synology..."
MSG="Downloading DSM"
ERR="Failed to download $URL"
html "$MSG..."
PAT="/$BASE.pat"
rm -f "$PAT"
@@ -186,12 +244,25 @@ if [[ "$URL" == "file://"* ]]; then
else
{ wget "$URL" -O "$PAT" -q --no-check-certificate --show-progress "$PROGRESS"; rc=$?; } || :
(( rc != 0 )) && error "Failed to download $URL, reason: $rc" && exit 69
SIZE=0
[[ "${URL,,}" == *"_72806.pat" ]] && SIZE=361010261
[[ "${URL,,}" == *"_69057.pat" ]] && SIZE=363837333
[[ "${URL,,}" == *"_42218.pat" ]] && SIZE=379637760
/run/progress.sh "$PAT" "$SIZE" "$MSG ([P])..." &
{ wget "$URL" -O "$PAT" -q --no-check-certificate --timeout=10 --show-progress "$PROGRESS"; rc=$?; } || :
fKill "progress.sh"
(( rc == 3 )) && error "$ERR , cannot write file (disk full?)" && exit 69
(( rc == 4 )) && error "$ERR , network failure!" && exit 69
(( rc == 8 )) && error "$ERR , server issued an error response!" && exit 69
(( rc != 0 )) && error "$ERR , reason: $rc" && exit 69
fi
[ ! -f "$PAT" ] && error "Failed to download $URL" && exit 69
[ ! -s "$PAT" ] && error "$ERR" && exit 69
SIZE=$(stat -c%s "$PAT")
@@ -228,7 +299,7 @@ MSG="Preparing system partition..."
info "Install: $MSG" && html "$MSG"
BOOT=$(find "$TMP" -name "*.bin.zip")
[ ! -f "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
[ ! -s "$BOOT" ] && error "The PAT file contains no boot image." && exit 67
BOOT=$(echo "$BOOT" | head -c -5)
unzip -q -o "$BOOT".zip -d "$TMP"
@@ -237,23 +308,23 @@ SYSTEM="$STORAGE/$BASE.system.img"
rm -f "$SYSTEM"
# Check free diskspace
SYSTEM_SIZE=4954537983
SYSTEM_SIZE=10738466816
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_MB=$(( (SPACE + 1048575)/1048576 ))
if (( SYSTEM_SIZE > SPACE )); then
error "Not enough free space in $STORAGE to create a 5 GB system disk, have only $SPACE_MB MB available." && exit 97
error "Not enough free space in $STORAGE to create a 10 GB system disk, have only $SPACE_MB MB available." && exit 97
fi
if ! touch "$SYSTEM"; then
error "Could not create file $SYSTEM for the system disk." && exit 98
fi
if [[ "${FS,,}" == "xfs" || "${FS,,}" == "zfs" || "${FS,,}" == "btrfs" || "${FS,,}" == "bcachefs" ]]; then
if [[ "${FS,,}" == "btrfs" ]]; then
{ chattr +C "$SYSTEM"; } || :
FA=$(lsattr "$SYSTEM")
if [[ "$FA" != *"C"* ]]; then
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem (returned $FA)"
error "Failed to disable COW for system image $SYSTEM on ${FS^^} filesystem."
fi
fi
@@ -272,8 +343,8 @@ PART="$TMP/partition.fdisk"
echo "unit: sectors"
echo "sector-size: 512"
echo ""
echo "${SYSTEM}1 : start= 2048, size= 4980480, type=83"
echo "${SYSTEM}2 : start= 4982528, size= 4194304, type=82"
echo "${SYSTEM}1 : start= 2048, size= 16777216, type=83"
echo "${SYSTEM}2 : start= 16779264, size= 4194304, type=82"
} > "$PART"
sfdisk -q "$SYSTEM" < "$PART"
@@ -289,23 +360,23 @@ IDB="$TMP/indexdb"
PKG="$TMP/packages"
HDP="$TMP/synohdpack_img"
[ ! -f "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
[ ! -s "$HDA.tgz" ] && error "The PAT file contains no OS image." && exit 64
mv "$HDA.tgz" "$HDA.txz"
[ -d "$PKG" ] && mv "$PKG/" "$MOUNT/.SynoUpgradePackages/"
rm -f "$MOUNT/.SynoUpgradePackages/ActiveInsight-"*
[ -f "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/"
[ -s "$HDP.txz" ] && tar xpfJ "$HDP.txz" --absolute-names -C "$MOUNT/"
if [ -f "$IDB.txz" ]; then
if [ -s "$IDB.txz" ]; then
INDEX_DB="$MOUNT/usr/syno/synoman/indexdb/"
mkdir -p "$INDEX_DB"
tar xpfJ "$IDB.txz" --absolute-names -C "$INDEX_DB"
fi
LABEL="1.44.1-42218"
OFFSET="1048576" # 2048 * 512
NUMBLOCKS="622560" # (4980480 * 512) / 4096
OFFSET="1048576" # 2048 * 512
NUMBLOCKS="2097152" # (16777216 * 512) / 4096
MSG="Installing system partition..."
if [[ "$ROOT" != [Nn]* ]]; then
@@ -337,8 +408,7 @@ fi
mv -f "$BOOT" "$STORAGE/$BASE.boot.img"
rm -rf "$TMP"
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
html "Booting DSM instance..."
sleep 1.2
html "Installation finished successfully..."
return 0

View File

@@ -3,12 +3,16 @@ set -Eeuo pipefail
# Docker environment variables
: "${MAC:=""}"
: "${DHCP:="N"}"
: "${MAC:="02:11:32:AA:BB:CC"}"
: "${NETWORK:="Y"}"
: "${HOST_PORTS:=""}"
: "${USER_PORTS:=""}"
: "${VM_NET_DEV:=""}"
: "${VM_NET_TAP:="dsm"}"
: "${VM_NET_MAC:="$MAC"}"
: "${VM_NET_IP:="20.20.20.21"}"
: "${VM_NET_HOST:="VirtualDSM"}"
: "${DNSMASQ_OPTS:=""}"
@@ -23,17 +27,23 @@ ADD_ERR="Please add the following setting to your container:"
configureDHCP() {
# Create a macvtap network for the VM guest
# Create the necessary file structure for /dev/vhost-net
if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then
chmod 660 /dev/vhost-net
fi
fi
# Create a macvtap network for the VM guest
{ ip link add link "$VM_NET_DEV" name "$VM_NET_TAP" address "$VM_NET_MAC" type macvtap mode bridge ; rc=$?; } || :
if (( rc != 0 )); then
error "Cannot create macvtap interface. Please make sure the network type is 'macvlan' and not 'ipvlan',"
error "and that the NET_ADMIN capability has been added to the container: --cap-add NET_ADMIN" && exit 16
error "Cannot create macvtap interface. Please make sure that the network type is 'macvlan' and not 'ipvlan',"
error "that your kernel is recent (>4) and supports it, and that the container has the NET_ADMIN capability set." && return 1
fi
while ! ip link set "$VM_NET_TAP" up; do
info "Waiting for address to become available..."
info "Waiting for MAC address $VM_NET_MAC to become available..."
sleep 2
done
@@ -43,25 +53,25 @@ configureDHCP() {
# Create dev file (there is no udev in container: need to be done manually)
IFS=: read -r MAJOR MINOR < <(cat /sys/devices/virtual/net/"$VM_NET_TAP"/tap*/dev)
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && exit 18
(( MAJOR < 1)) && error "Cannot find: sys/devices/virtual/net/$VM_NET_TAP" && return 1
[[ ! -e "$TAP_PATH" ]] && [[ -e "/dev0/${TAP_PATH##*/}" ]] && ln -s "/dev0/${TAP_PATH##*/}" "$TAP_PATH"
if [[ ! -e "$TAP_PATH" ]]; then
{ mknod "$TAP_PATH" c "$MAJOR" "$MINOR" ; rc=$?; } || :
(( rc != 0 )) && error "Cannot mknod: $TAP_PATH ($rc)" && exit 20
(( rc != 0 )) && error "Cannot mknod: $TAP_PATH ($rc)" && return 1
fi
{ exec 30>>"$TAP_PATH"; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && exit 21
error "Cannot create TAP interface ($rc). $ADD_ERR --device-cgroup-rule='c *:* rwm'" && return 1
fi
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
if (( rc != 0 )); then
error "VHOST can not be found ($rc). $ADD_ERR --device=/dev/vhost-net" && exit 22
error "VHOST can not be found ($rc). $ADD_ERR --device=/dev/vhost-net" && return 1
fi
NET_OPTS="-netdev tap,id=hostnet0,vhost=on,vhostfd=40,fd=30"
@@ -72,20 +82,70 @@ configureDHCP() {
configureDNS() {
# dnsmasq configuration:
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-range=$VM_NET_IP,$VM_NET_IP --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite --dhcp-option=option:netmask,255.255.255.0"
DNSMASQ_OPTS+=" --dhcp-range=$VM_NET_IP,$VM_NET_IP --dhcp-host=$VM_NET_MAC,,$VM_NET_IP,$VM_NET_HOST,infinite --dhcp-option=option:netmask,255.255.255.0"
# Create lease file for faster resolve
echo "0 $VM_NET_MAC $VM_NET_IP $VM_NET_HOST 01:$VM_NET_MAC" > /var/lib/misc/dnsmasq.leases
chmod 644 /var/lib/misc/dnsmasq.leases
# Set DNS server and gateway
DNSMASQ_OPTS="$DNSMASQ_OPTS --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
DNSMASQ_OPTS+=" --dhcp-option=option:dns-server,${VM_NET_IP%.*}.1 --dhcp-option=option:router,${VM_NET_IP%.*}.1"
# Add DNS entry for container
DNSMASQ_OPTS+=" --address=/host.lan/${VM_NET_IP%.*}.1"
DNSMASQ_OPTS=$(echo "$DNSMASQ_OPTS" | sed 's/\t/ /g' | tr -s ' ' | sed 's/^ *//')
[[ "$DEBUG" == [Yy1]* ]] && set -x
$DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
if ! $DNSMASQ ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}; then
error "Failed to start dnsmasq, reason: $?" && return 1
fi
return 0
}
getUserPorts() {
local args=""
local list=$1
local ssh="22"
local dsm="5000"
[ -z "$list" ] && list="$ssh,$dsm" || list+=",$ssh,$dsm"
list="${list//,/ }"
list="${list## }"
list="${list%% }"
for port in $list; do
args+="hostfwd=tcp::$port-$VM_NET_IP:$port,"
done
echo "${args%?}"
return 0
}
getHostPorts() {
local list=$1
[ -z "$list" ] && echo "" && return 0
if [[ "$list" != *","* ]]; then
echo " ! --dport $list"
else
echo " -m multiport ! --dports $list"
fi
return 0
}
configureUser() {
NET_OPTS="-netdev user,id=hostnet0,host=${VM_NET_IP%.*}.1,net=${VM_NET_IP%.*}.0/24,dhcpstart=$VM_NET_IP,hostname=$VM_NET_HOST"
local forward
forward=$(getUserPorts "$USER_PORTS")
[ -n "$forward" ] && NET_OPTS+=",$forward"
return 0
}
@@ -101,89 +161,115 @@ configureNAT() {
fi
if [ ! -c /dev/net/tun ]; then
error "TUN device missing. $ADD_ERR --cap-add NET_ADMIN" && exit 25
error "TUN device missing. $ADD_ERR --device /dev/net/tun --cap-add NET_ADMIN" && return 1
fi
# Check port forwarding flag
if [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
{ sysctl -w net.ipv4.ip_forward=1 ; rc=$?; } || :
if (( rc != 0 )); then
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && exit 24
{ sysctl -w net.ipv4.ip_forward=1 > /dev/null; rc=$?; } || :
if (( rc != 0 )) || [[ $(< /proc/sys/net/ipv4/ip_forward) -eq 0 ]]; then
error "IP forwarding is disabled. $ADD_ERR --sysctl net.ipv4.ip_forward=1" && return 1
fi
fi
# Create a bridge with a static IP for the VM guest
local tables="The 'ip_tables' kernel module is not loaded. Try this command: sudo modprobe ip_tables iptable_nat"
local tuntap="The 'tun' kernel module is not available. Try this command: 'sudo modprobe tun' or run the container with 'privileged: true'."
VM_NET_IP='20.20.20.21'
[[ "$DEBUG" == [Yy1]* ]] && set -x
# Create a bridge with a static IP for the VM guest
{ ip link add dev dockerbridge type bridge ; rc=$?; } || :
if (( rc != 0 )); then
error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && exit 23
error "Failed to create bridge. $ADD_ERR --cap-add NET_ADMIN" && return 1
fi
ip address add ${VM_NET_IP%.*}.1/24 broadcast ${VM_NET_IP%.*}.255 dev dockerbridge
if ! ip address add "${VM_NET_IP%.*}.1/24" broadcast "${VM_NET_IP%.*}.255" dev dockerbridge; then
error "Failed to add IP address!" && return 1
fi
while ! ip link set dockerbridge up; do
info "Waiting for address to become available..."
info "Waiting for IP address to become available..."
sleep 2
done
# QEMU Works with taps, set tap to the bridge created
ip tuntap add dev "$VM_NET_TAP" mode tap
if ! ip tuntap add dev "$VM_NET_TAP" mode tap; then
error "$tuntap" && return 1
fi
while ! ip link set "$VM_NET_TAP" up promisc on; do
info "Waiting for tap to become available..."
info "Waiting for TAP to become available..."
sleep 2
done
ip link set dev "$VM_NET_TAP" master dockerbridge
if ! ip link set dev "$VM_NET_TAP" master dockerbridge; then
error "Failed to set IP link!" && return 1
fi
# Add internet connection to the VM
update-alternatives --set iptables /usr/sbin/iptables-legacy > /dev/null
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy > /dev/null
iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp -j DNAT --to "$VM_NET_IP"
iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"
exclude=$(getHostPorts "$HOST_PORTS")
if ! iptables -t nat -A POSTROUTING -o "$VM_NET_DEV" -j MASQUERADE; then
error "$tables" && return 1
fi
# shellcheck disable=SC2086
if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p tcp${exclude} -j DNAT --to "$VM_NET_IP"; then
error "Failed to configure IP tables!" && return 1
fi
if ! iptables -t nat -A PREROUTING -i "$VM_NET_DEV" -d "$IP" -p udp -j DNAT --to "$VM_NET_IP"; then
error "Failed to configure IP tables!" && return 1
fi
if (( KERNEL > 4 )); then
# Hack for guest VMs complaining about "bad udp checksums in 5 packets"
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill || true
iptables -A POSTROUTING -t mangle -p udp --dport bootpc -j CHECKSUM --checksum-fill > /dev/null 2>&1 || true
fi
{ set +x; } 2>/dev/null
[[ "$DEBUG" == [Yy1]* ]] && echo
NET_OPTS="-netdev tap,id=hostnet0,ifname=$VM_NET_TAP"
NET_OPTS="-netdev tap,ifname=$VM_NET_TAP,script=no,downscript=no,id=hostnet0"
if [ -c /dev/vhost-net ]; then
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
(( rc == 0 )) && NET_OPTS+=",vhost=on,vhostfd=40"
fi
{ exec 40>>/dev/vhost-net; rc=$?; } 2>/dev/null || :
(( rc == 0 )) && NET_OPTS="$NET_OPTS,vhost=on,vhostfd=40"
NET_OPTS+=",script=no,downscript=no"
configureDNS
! configureDNS && return 1
return 0
}
closeNetwork() {
exec 30<&- || true
exec 40<&- || true
if [[ "$DHCP" == [Yy1]* ]]; then
# Shutdown nginx
nginx -s stop 2> /dev/null
fWait "nginx"
fi
[[ "$NETWORK" == [Nn]* ]] && return 0
exec 30<&- || true
exec 40<&- || true
if [[ "$DHCP" == [Yy1]* ]]; then
ip link set "$VM_NET_TAP" down || true
ip link delete "$VM_NET_TAP" || true
else
local pid="/var/run/dnsmasq.pid"
[ -f "$pid" ] && pKill "$(<"$pid")"
[ -s "$pid" ] && pKill "$(<"$pid")"
[[ "${NETWORK,,}" == "user"* ]] && return 0
ip link set "$VM_NET_TAP" down promisc off || true
ip link delete "$VM_NET_TAP" || true
@@ -196,11 +282,32 @@ closeNetwork() {
return 0
}
checkOS() {
local name
local os=""
name=$(uname -a)
[[ "${name,,}" == *"darwin"* ]] && os="MacOS"
[[ "${name,,}" == *"microsoft"* ]] && os="Windows"
if [ -n "$os" ]; then
warn "you are using Docker Desktop for $os which does not support macvlan, please revert to bridge networking!"
fi
return 0
}
getInfo() {
if [ -z "$VM_NET_DEV" ]; then
# Give Kubernetes priority over the default interface
[ -d "/sys/class/net/net0" ] && VM_NET_DEV="net0"
[ -d "/sys/class/net/net1" ] && VM_NET_DEV="net1"
[ -d "/sys/class/net/net2" ] && VM_NET_DEV="net2"
[ -d "/sys/class/net/net3" ] && VM_NET_DEV="net3"
# Automaticly detect the default network interface
VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
[ -z "$VM_NET_DEV" ] && VM_NET_DEV=$(awk '$2 == 00000000 { print $1 }' /proc/net/route)
[ -z "$VM_NET_DEV" ] && VM_NET_DEV="eth0"
fi
@@ -209,17 +316,29 @@ getInfo() {
error "$ADD_ERR -e \"VM_NET_DEV=NAME\" to specify another interface name." && exit 27
fi
if [ -z "$VM_NET_MAC" ]; then
local file="$STORAGE/dsm.mac"
[ -s "$file" ] && VM_NET_MAC=$(<"$file")
if [ -z "$VM_NET_MAC" ]; then
# Generate MAC address based on Docker container ID in hostname
VM_NET_MAC=$(echo "$HOST" | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:11:32:\3:\4:\5/')
echo "${VM_NET_MAC^^}" > "$file"
fi
fi
VM_NET_MAC="${VM_NET_MAC^^}"
VM_NET_MAC="${VM_NET_MAC//-/:}"
if [[ ${#VM_NET_MAC} == 12 ]]; then
m="$VM_NET_MAC"
VM_NET_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi
if [[ ${#VM_NET_MAC} != 17 ]]; then
error "Invalid mac address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
error "Invalid MAC address: '$VM_NET_MAC', should be 12 or 17 digits long!" && exit 28
fi
GATEWAY=$(ip r | grep default | awk '{print $3}')
GATEWAY=$(ip route list dev "$VM_NET_DEV" | awk ' /^default/ {print $3}')
IP=$(ip address show dev "$VM_NET_DEV" | grep inet | awk '/inet / { print $2 }' | cut -f1 -d/)
echo "$IP" > /run/shm/qemu.ip
@@ -230,44 +349,75 @@ getInfo() {
# Configure Network
# ######################################
if [ ! -c /dev/vhost-net ]; then
if mknod /dev/vhost-net c 10 238; then
chmod 660 /dev/vhost-net
fi
if [[ "$NETWORK" == [Nn]* ]]; then
NET_OPTS=""
return 0
fi
getInfo
html "Initializing network..."
if [[ "$DEBUG" == [Yy1]* ]]; then
info "Container IP is $IP with gateway $GATEWAY on interface $VM_NET_DEV" && echo
info "Host: $HOST IP: $IP Gateway: $GATEWAY Interface: $VM_NET_DEV MAC: $VM_NET_MAC"
[ -f /etc/resolv.conf ] && grep '^nameserver*' /etc/resolv.conf
echo
fi
if [[ "$IP" == "172.17."* ]]; then
warn "your container IP starts with 172.17.* which will cause conflicts when you install the Container Manager package inside DSM!"
fi
if [[ "$DHCP" == [Yy1]* ]]; then
if [[ "$GATEWAY" == "172."* ]]; then
if [[ "$DEBUG" != [Yy1]* ]]; then
error "You can only enable DHCP while the container is on a macvlan network!" && exit 26
fi
checkOS
if [[ "$IP" == "172."* ]]; then
warn "container IP starts with 172.* which is often a sign that you are not on a macvlan network (required for DHCP)!"
fi
# Configuration for DHCP IP
configureDHCP
# Configure for macvtap interface
! configureDHCP && exit 20
MSG="Booting DSM instance..."
html "$MSG"
else
if [[ "$IP" != "172."* ]] && [[ "$IP" != "10.8"* ]] && [[ "$IP" != "10.9"* ]]; then
checkOS
fi
# Shutdown nginx
nginx -s stop 2> /dev/null
fWait "nginx"
# Configuration for static IP
configureNAT
if [[ "${NETWORK,,}" != "user"* ]]; then
# Configure for tap interface
if ! configureNAT; then
NETWORK="user"
warn "falling back to usermode networking! Performance will be bad and port forwarding will not work."
ip link set "$VM_NET_TAP" down promisc off &> null || true
ip link delete "$VM_NET_TAP" &> null || true
ip link set dockerbridge down &> null || true
ip link delete dockerbridge &> null || true
fi
fi
if [[ "${NETWORK,,}" == "user"* ]]; then
# Configure for usermode networking (slirp)
! configureUser && exit 24
fi
fi
NET_OPTS="$NET_OPTS -device virtio-net-pci,romfile=,netdev=hostnet0,mac=$VM_NET_MAC,id=net0"
NET_OPTS+=" -device virtio-net-pci,romfile=,netdev=hostnet0,mac=$VM_NET_MAC,id=net0"
return 0

View File

@@ -10,10 +10,11 @@ API_HOST="127.0.0.1:2210"
QEMU_TERM=""
QEMU_PORT=7100
QEMU_TIMEOUT=50
QEMU_PID="/run/shm/qemu.pid"
QEMU_LOG="/run/shm/qemu.log"
QEMU_OUT="/run/shm/qemu.out"
QEMU_END="/run/shm/qemu.end"
QEMU_DIR="/run/shm"
QEMU_PID="$QEMU_DIR/qemu.pid"
QEMU_LOG="$QEMU_DIR/qemu.log"
QEMU_OUT="$QEMU_DIR/qemu.out"
QEMU_END="$QEMU_DIR/qemu.end"
if [[ "$KVM" == [Nn]* ]]; then
API_TIMEOUT=$(( API_TIMEOUT*2 ))
@@ -34,7 +35,9 @@ finish() {
local pid
local reason=$1
if [ -f "$QEMU_PID" ]; then
touch "$QEMU_END"
if [ -s "$QEMU_PID" ]; then
pid=$(<"$QEMU_PID")
echo && error "Forcefully terminating QEMU process, reason: $reason..."
@@ -43,7 +46,7 @@ finish() {
while isAlive "$pid"; do
sleep 1
# Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break
[ ! -s "$QEMU_PID" ] && break
done
fi
@@ -62,7 +65,7 @@ terminal() {
local dev=""
if [ -f "$QEMU_OUT" ]; then
if [ -s "$QEMU_OUT" ]; then
local msg
msg=$(<"$QEMU_OUT")
@@ -111,7 +114,7 @@ _graceful_shutdown() {
touch "$QEMU_END"
echo && info "Received $1 signal, sending shutdown command..."
if [ ! -f "$QEMU_PID" ]; then
if [ ! -s "$QEMU_PID" ]; then
echo && error "QEMU PID file does not exist?"
finish "$code" && return "$code"
fi
@@ -155,7 +158,7 @@ _graceful_shutdown() {
[[ "$DEBUG" == [Yy1]* ]] && info "Shutting down, waiting... ($cnt/$QEMU_TIMEOUT)"
# Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break
[ ! -s "$QEMU_PID" ] && break
done
@@ -168,11 +171,12 @@ _graceful_shutdown() {
MON_OPTS="\
-pidfile $QEMU_PID \
-name $PROCESS,process=$PROCESS,debug-threads=on \
-monitor telnet:localhost:$QEMU_PORT,server,nowait,nodelay"
if [[ "$CONSOLE" != [Yy]* ]]; then
MON_OPTS="$MON_OPTS -daemonize -D $QEMU_LOG"
MON_OPTS+=" -daemonize -D $QEMU_LOG"
_trap _graceful_shutdown SIGTERM SIGHUP SIGINT SIGABRT SIGQUIT

View File

@@ -2,6 +2,9 @@
set -Eeuo pipefail
: "${DHCP:="N"}"
: "${NETWORK:="Y"}"
[[ "$NETWORK" == [Nn]* ]] && exit 0
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n" >&2; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; }
@@ -18,7 +21,7 @@ resp_err="Guest returned an invalid response:"
curl_err="Failed to connect to guest: curl error"
jq_err="Failed to parse response from guest: jq error"
while [ ! -f "$file" ]
while [ ! -s "$file" ]
do
# Check if not shutting down
@@ -27,7 +30,7 @@ do
sleep 3
[ -f "$shutdown" ] && exit 1
[ -f "$file" ] && break
[ -s "$file" ] && break
# Retrieve network info from guest VM
{ json=$(curl -m 20 -sk "$url"); rc=$?; } || :
@@ -101,3 +104,5 @@ info "-----------------------------------------------------------"
info " You can now login to DSM at $msg"
info "-----------------------------------------------------------"
echo "" >&2
exit 0

View File

@@ -6,9 +6,13 @@ set -Eeuo pipefail
: "${KVM:="Y"}"
: "${HOST_CPU:=""}"
: "${CPU_FLAGS:=""}"
: "${CPU_MODEL:="host"}"
: "${CPU_MODEL:=""}"
: "${DEF_MODEL:="qemu64"}"
[ "$ARCH" != "amd64" ] && KVM="N"
if [[ "${ARCH,,}" != "amd64" ]]; then
KVM="N"
warn "your CPU architecture is ${ARCH^^} and cannot provide KVM acceleration for x64 instructions, this will cause a major loss of performance."
fi
if [[ "$KVM" != [Nn]* ]]; then
@@ -20,7 +24,8 @@ if [[ "$KVM" != [Nn]* ]]; then
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(no write access)"
else
if ! grep -q -e vmx -e svm /proc/cpuinfo; then
flags=$(sed -ne '/^flags/s/^.*: //p' /proc/cpuinfo)
if ! grep -qw "vmx\|svm" <<< "$flags"; then
KVM_ERR="(vmx/svm disabled)"
fi
fi
@@ -28,48 +33,105 @@ if [[ "$KVM" != [Nn]* ]]; then
if [ -n "$KVM_ERR" ]; then
KVM="N"
error "KVM acceleration not detected $KVM_ERR, this will cause a major loss of performance."
error "See the FAQ on how to enable it, or continue without KVM by setting KVM=N (not recommended)."
[[ "$DEBUG" != [Yy1]* ]] && exit 88
if [[ "$OSTYPE" =~ ^darwin ]]; then
warn "you are using MacOS which has no KVM support, this will cause a major loss of performance."
else
if grep -qi Microsoft /proc/version; then
warn "you are using Windows 10 which has no KVM support, this will cause a major loss of performance."
else
error "KVM acceleration not available $KVM_ERR, this will cause a major loss of performance."
error "See the FAQ on how to diagnose the cause, or continue without KVM by setting KVM=N (not recommended)."
[[ "$DEBUG" != [Yy1]* ]] && exit 88
fi
fi
fi
fi
if [[ "$KVM" != [Nn]* ]]; then
CPU_FEATURES="kvm=on"
KVM_OPTS=",accel=kvm -enable-kvm"
CPU_FEATURES="kvm=on,l3-cache=on,+hypervisor"
CLOCK="/sys/devices/system/clocksource/clocksource0/current_clocksource"
KVM_OPTS=",accel=kvm -enable-kvm -global kvm-pit.lost_tick_policy=discard"
if ! grep -qw "sse4_2" <<< "$flags"; then
info "Your CPU does not have the SSE4 instruction set that Virtual DSM requires, it will be emulated..."
[ -z "$CPU_MODEL" ] && CPU_MODEL="$DEF_MODEL"
CPU_FEATURES+=",+ssse3,+sse4.1,+sse4.2"
fi
if [ -z "$CPU_MODEL" ]; then
CPU_MODEL="host"
CPU_FEATURES+=",migratable=no"
fi
if [ -f "$CLOCK" ]; then
CLOCK=$(<"$CLOCK")
if [[ "${CLOCK,,}" != "tsc" ]]; then
warn "unexpected clocksource: $CLOCK"
fi
else
warn "file \"$CLOCK\" cannot not found?"
fi
if grep -qw "svm" <<< "$flags"; then
# AMD processor
if grep -qw "tsc_scale" <<< "$flags"; then
CPU_FEATURES+=",+invtsc"
fi
else
# Intel processor
vmx=$(sed -ne '/^vmx flags/s/^.*: //p' /proc/cpuinfo)
if grep -qw "tsc_scaling" <<< "$vmx"; then
CPU_FEATURES+=",+invtsc"
fi
if ! grep -qE '^flags.* (sse4_2)' /proc/cpuinfo; then
error "Your host CPU does not have the SSE4.2 instruction set that Virtual DSM requires to boot."
error "Disable KVM by setting KVM=N to emulate a compatible CPU, at the cost of performance."
[[ "$DEBUG" != [Yy1]* ]] && exit 89
fi
else
KVM_OPTS=""
CPU_FEATURES="+ssse3,+sse4.1,+sse4.2"
CPU_FEATURES="l3-cache=on,+hypervisor"
if [[ "${CPU_MODEL,,}" == "host"* ]]; then
if [[ "$ARCH" == "amd64" ]]; then
KVM_OPTS=" -accel tcg,thread=multi"
fi
if [ -z "$CPU_MODEL" ]; then
if [[ "$ARCH" == "amd64" ]]; then
CPU_MODEL="max"
CPU_FEATURES+=",migratable=no"
else
CPU_MODEL="qemu64"
CPU_MODEL="$DEF_MODEL"
fi
fi
CPU_FEATURES+=",+ssse3,+sse4.1,+sse4.2"
fi
if [ -z "$CPU_FLAGS" ]; then
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES"
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES"
fi
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES,$CPU_FLAGS"
if [ -z "$CPU_FEATURES" ]; then
CPU_FLAGS="$CPU_MODEL,$CPU_FLAGS"
else
CPU_FLAGS="$CPU_MODEL,$CPU_FEATURES,$CPU_FLAGS"
fi
fi
if [ -z "$HOST_CPU" ]; then
HOST_CPU=$(lscpu | grep 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
HOST_CPU=$(lscpu | grep -m 1 'Model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
fi
if [ -n "$HOST_CPU" ]; then
@@ -77,9 +139,9 @@ if [ -n "$HOST_CPU" ]; then
else
HOST_CPU="QEMU, Virtual CPU,"
if [ "$ARCH" == "amd64" ]; then
HOST_CPU="$HOST_CPU X86_64"
HOST_CPU+=" X86_64"
else
HOST_CPU="$HOST_CPU $ARCH"
HOST_CPU+=" $ARCH"
fi
fi

38
src/progress.sh Normal file
View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -Eeuo pipefail
escape () {
local s
s=${1//&/\&amp;}
s=${s//</\&lt;}
s=${s//>/\&gt;}
s=${s//'"'/\&quot;}
printf -- %s "$s"
return 0
}
file="$1"
total="$2"
body=$(escape "$3")
info="/run/shm/msg.html"
if [[ "$body" == *"..." ]]; then
body="<p class=\"loading\">${body/.../}</p>"
fi
while true
do
if [ -s "$file" ]; then
bytes=$(du -sb "$file" | cut -f1)
if (( bytes > 1000 )); then
if [ -z "$total" ] || [[ "$total" == "0" ]]; then
size=$(numfmt --to=iec --suffix=B "$bytes" | sed -r 's/([A-Z])/ \1/')
else
size="$(echo "$bytes" "$total" | awk '{printf "%.1f", $1 * 100 / $2}')"
size="$size%"
fi
echo "${body//(\[P\])/($size)}"> "$info"
fi
fi
sleep 1 & wait $!
done

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash
set -Eeuo pipefail
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "$1" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: $1" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m " "Warning: $1" "\E[0m\n" >&2; }
info () { printf "%b%s%b" "\E[1;34m \E[1;36m" "${1:-}" "\E[0m\n"; }
error () { printf "%b%s%b" "\E[1;31m " "ERROR: ${1:-}" "\E[0m\n" >&2; }
warn () { printf "%b%s%b" "\E[1;31m " "Warning: ${1:-}" "\E[0m\n" >&2; }
trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
@@ -12,7 +12,6 @@ trap 'error "Status $? while: $BASH_COMMAND (line $LINENO/$BASH_LINENO)"' ERR
echo " Starting $APP for Docker v$(</run/version)..."
echo " For support visit $SUPPORT"
echo
# Docker environment variables
@@ -24,10 +23,14 @@ echo
: "${ARGUMENTS:=""}" # Extra QEMU parameters
: "${CPU_CORES:="1"}" # Amount of CPU cores
: "${RAM_SIZE:="1G"}" # Maximum RAM amount
: "${RAM_CHECK:="Y"}" # Check available RAM
: "${DISK_SIZE:="16G"}" # Initial data disk size
# Helper variables
PROCESS="${APP,,}"
PROCESS="${PROCESS// /-}"
STORAGE="/storage"
INFO="/run/shm/msg.html"
PAGE="/run/shm/index.html"
@@ -35,10 +38,26 @@ TEMPLATE="/var/www/index.html"
FOOTER1="$APP for Docker v$(</run/version)"
FOOTER2="<a href='$SUPPORT'>$SUPPORT</a>"
KERNEL=$(uname -r | cut -b 1)
MINOR=$(uname -r | cut -d '.' -f2)
CPI=$(lscpu)
SYS=$(uname -r)
HOST=$(hostname -s)
KERNEL=$(echo "$SYS" | cut -b 1)
MINOR=$(echo "$SYS" | cut -d '.' -f2)
ARCH=$(dpkg --print-architecture)
VERS=$(qemu-system-x86_64 --version | head -n 1 | cut -d '(' -f 1)
CORES=$(grep -c '^processor' /proc/cpuinfo)
if ! grep -qi "socket(s)" <<< "$CPI"; then
SOCKETS=1
else
SOCKETS=$(echo "$CPI" | grep -m 1 -i 'socket(s)' | awk '{print $(2)}')
fi
if ! grep -qi "model name" <<< "$CPI"; then
CPU="Unknown"
else
CPU=$(echo "$CPI" | grep -m 1 -i 'model name' | cut -f 2 -d ":" | awk '{$1=$1}1' | sed 's# @.*##g' | sed s/"(R)"//g | sed 's/[^[:alnum:] ]\+/ /g' | sed 's/ */ /g')
CPU="${CPU// with Radeon Graphics/}"
fi
# Check system
@@ -54,6 +73,42 @@ if [ ! -d "$STORAGE" ]; then
error "Storage folder ($STORAGE) not found!" && exit 13
fi
# Check filesystem
FS=$(stat -f -c %T "$STORAGE")
if [[ "${FS,,}" == "ecryptfs" ]] || [[ "${FS,,}" == "tmpfs" ]]; then
DISK_IO="threads"
DISK_CACHE="writeback"
fi
# Read memory
RAM_SPARE=500000000
RAM_AVAIL=$(free -b | grep -m 1 Mem: | awk '{print $7}')
RAM_TOTAL=$(free -b | grep -m 1 Mem: | awk '{print $2}')
RAM_SIZE=$(echo "${RAM_SIZE^^}" | sed 's/MB/M/g;s/GB/G/g;s/TB/T/g')
RAM_WANTED=$(numfmt --from=iec "$RAM_SIZE")
AVAIL_GB=$(( RAM_AVAIL/1073741824 ))
TOTAL_GB=$(( (RAM_TOTAL + 1073741823)/1073741824 ))
WANTED_GB=$(( (RAM_WANTED + 1073741823)/1073741824 ))
# Print system info
SYS="${SYS/-generic/}"
FS="${FS/ext2\/ext3/ext4}"
SPACE=$(df --output=avail -B 1 "$STORAGE" | tail -n 1)
SPACE_GB=$(( (SPACE + 1073741823)/1073741824 ))
echo " CPU: ${CPU} | RAM: $AVAIL_GB/$TOTAL_GB GB | DISK: $SPACE_GB GB (${FS}) | HOST: ${SYS}..."
echo
# Check memory
if [[ "$RAM_CHECK" != [Nn]* ]]; then
if (( (RAM_WANTED + RAM_SPARE) > RAM_AVAIL )); then
error "Your configured RAM_SIZE of $WANTED_GB GB is too high for the $AVAIL_GB GB of memory available, please set a lower value."
exit 17
fi
fi
# Cleanup files
rm -f /run/shm/qemu.*
rm -f /run/shm/dsm.url

View File

@@ -9,6 +9,21 @@ set -Eeuo pipefail
: "${HOST_MODEL:=""}"
: "${GUEST_SERIAL:=""}"
if [ -n "$HOST_MAC" ]; then
HOST_MAC="${HOST_MAC//-/:}"
if [[ ${#HOST_MAC} == 12 ]]; then
m="$HOST_MAC"
HOST_MAC="${m:0:2}:${m:2:2}:${m:4:2}:${m:6:2}:${m:8:2}:${m:10:2}"
fi
if [[ ${#HOST_MAC} != 17 ]]; then
error "Invalid HOST_MAC address: '$HOST_MAC', should be 12 or 17 digits long!" && exit 28
fi
fi
HOST_ARGS=()
HOST_ARGS+=("-cpu=$CPU_CORES")
HOST_ARGS+=("-cpu_arch=$HOST_CPU")
@@ -52,7 +67,7 @@ else
SERIAL_OPTS="-serial mon:stdio"
fi
SERIAL_OPTS="$SERIAL_OPTS \
SERIAL_OPTS+=" \
-device virtio-serial-pci,id=virtio-serial0,bus=pcie.0,addr=0x3 \
-chardev socket,id=charchannel0,host=127.0.0.1,port=12345,reconnect=10 \
-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=vchannel"

View File

@@ -1,7 +1,14 @@
body {
color: white;
background-color: #125bdb;
font-family: Verdana, Arial, sans-serif;
font-smoothing: antialiased;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: Verdana, Geneva, sans-serif;
}
#info {
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.25);
}
#content {
@@ -17,6 +24,7 @@ footer {
height: 40px;
text-align: center;
color: #0c8aeb;
text-shadow: 0 0 1px #0c8aeb;
}
#empty {
@@ -33,8 +41,13 @@ a:visited {
footer a:link,
footer a:visited,
footer a:active { color: #0c8aeb; }
footer a:hover { color: #73e6ff; }
footer a:active {
color: #0c8aeb;
}
footer a:hover {
color: #73e6ff;
}
.loading:after {
content: " .";

View File

@@ -1,8 +1,6 @@
server {
listen 80;
listen [::]:80;
listen 5000 default_server;
listen [::]:5000 default_server;
autoindex on;
tcp_nodelay on;