mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-06-16 20:41:19 +02:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c0896f80f | |||
| 4d4e1d7654 | |||
| 6b25e35ecf | |||
| 6c23883d94 | |||
| e08719ac3f | |||
| 0683d4942c | |||
| b0896dbdeb | |||
| f1ee2a2b91 | |||
| 691ce33090 | |||
| 5f5881c757 | |||
| af7e83300f | |||
| 29c25a0ab8 | |||
| e60c1f31c2 | |||
| f13782704e | |||
| 7ee47be436 | |||
| 868b256603 | |||
| 16bd4f473b | |||
| 77eb109927 | |||
| 55703ab0ec |
+1
@@ -28,6 +28,7 @@ jobs:
|
|||||||
const allowedBots = [
|
const allowedBots = [
|
||||||
"push-app-to-main[bot]",
|
"push-app-to-main[bot]",
|
||||||
"push-app-to-main",
|
"push-app-to-main",
|
||||||
|
"community-scripts-pr-app"
|
||||||
];
|
];
|
||||||
|
|
||||||
if (allowedBots.includes(author)) {
|
if (allowedBots.includes(author)) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ jobs:
|
|||||||
BEFORE="${{ github.event.before }}"
|
BEFORE="${{ github.event.before }}"
|
||||||
AFTER="${{ github.event.after }}"
|
AFTER="${{ github.event.after }}"
|
||||||
slugs=""
|
slugs=""
|
||||||
|
ct_slugs=""
|
||||||
|
|
||||||
# Deleted JSON files: get slug from previous commit
|
# Deleted JSON files: get slug from previous commit
|
||||||
deleted_json=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- json/ | grep '\.json$' || true)
|
deleted_json=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- json/ | grep '\.json$' || true)
|
||||||
@@ -37,6 +38,14 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Deleted script files: derive slug from path
|
# Deleted script files: derive slug from path
|
||||||
|
deleted_ct=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- ct/ | grep '\.sh$' || true)
|
||||||
|
for f in $deleted_ct; do
|
||||||
|
[[ -z "$f" ]] && continue
|
||||||
|
base="${f##*/}"
|
||||||
|
base="${base%.sh}"
|
||||||
|
[[ -n "$base" ]] && ct_slugs="$ct_slugs $base"
|
||||||
|
done
|
||||||
|
|
||||||
deleted_sh=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- ct/ install/ tools/ turnkey/ vm/ | grep '\.sh$' || true)
|
deleted_sh=$(git diff --name-only --diff-filter=D "$BEFORE" "$AFTER" -- ct/ install/ tools/ turnkey/ vm/ | grep '\.sh$' || true)
|
||||||
for f in $deleted_sh; do
|
for f in $deleted_sh; do
|
||||||
[[ -z "$f" ]] && continue
|
[[ -z "$f" ]] && continue
|
||||||
@@ -51,14 +60,17 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
slugs=$(echo $slugs | xargs -n1 | sort -u | tr '\n' ' ')
|
slugs=$(echo $slugs | xargs -n1 | sort -u | tr '\n' ' ')
|
||||||
|
ct_slugs=$(echo $ct_slugs | xargs -n1 2>/dev/null | sort -u | tr '\n' ' ')
|
||||||
if [[ -z "$slugs" ]]; then
|
if [[ -z "$slugs" ]]; then
|
||||||
echo "No deleted JSON or script files to mark as deleted in PocketBase."
|
echo "No deleted JSON or script files to mark as deleted in PocketBase."
|
||||||
echo "count=0" >> "$GITHUB_OUTPUT"
|
echo "count=0" >> "$GITHUB_OUTPUT"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
echo "$slugs" > slugs_to_delete.txt
|
echo "$slugs" > slugs_to_delete.txt
|
||||||
|
echo "$ct_slugs" > ct_slugs_to_stub.txt
|
||||||
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
|
||||||
echo "Slugs to mark as deleted: $slugs"
|
echo "Slugs to mark as deleted: $slugs"
|
||||||
|
[[ -n "$ct_slugs" ]] && echo "CT stubs to generate: $ct_slugs"
|
||||||
|
|
||||||
- name: Mark as deleted in PocketBase
|
- name: Mark as deleted in PocketBase
|
||||||
if: steps.slugs.outputs.count != '0'
|
if: steps.slugs.outputs.count != '0'
|
||||||
@@ -159,3 +171,134 @@ jobs:
|
|||||||
})().catch(e => { console.error(e); process.exit(1); });
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
ENDSCRIPT
|
ENDSCRIPT
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
- name: Generate CT stubs for deleted scripts
|
||||||
|
if: steps.slugs.outputs.count != '0'
|
||||||
|
env:
|
||||||
|
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
|
||||||
|
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
|
||||||
|
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
|
||||||
|
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
if [[ ! -s ct_slugs_to_stub.txt ]]; then
|
||||||
|
echo "No deleted ct/*.sh files; skipping stub generation."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
node << 'ENDSCRIPT'
|
||||||
|
(async function() {
|
||||||
|
const fs = require('fs');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
const path = require('path');
|
||||||
|
const url = require('url');
|
||||||
|
|
||||||
|
function request(fullUrl, opts, redirectCount) {
|
||||||
|
redirectCount = redirectCount || 0;
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
const u = url.parse(fullUrl);
|
||||||
|
const isHttps = u.protocol === 'https:';
|
||||||
|
const body = opts.body;
|
||||||
|
const options = {
|
||||||
|
hostname: u.hostname,
|
||||||
|
port: u.port || (isHttps ? 443 : 80),
|
||||||
|
path: u.path,
|
||||||
|
method: opts.method || 'GET',
|
||||||
|
headers: opts.headers || {}
|
||||||
|
};
|
||||||
|
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
|
||||||
|
const lib = isHttps ? https : http;
|
||||||
|
const req = lib.request(options, function(res) {
|
||||||
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||||
|
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
|
||||||
|
const redirectUrl = url.resolve(fullUrl, res.headers.location);
|
||||||
|
res.resume();
|
||||||
|
resolve(request(redirectUrl, opts, redirectCount + 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let data = '';
|
||||||
|
res.on('data', function(chunk) { data += chunk; });
|
||||||
|
res.on('end', function() {
|
||||||
|
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
req.on('error', reject);
|
||||||
|
if (body) req.write(body);
|
||||||
|
req.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
|
||||||
|
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
|
||||||
|
const coll = process.env.POCKETBASE_COLLECTION;
|
||||||
|
const ctSlugs = fs.readFileSync('ct_slugs_to_stub.txt', 'utf8').trim().split(/\s+/).filter(Boolean);
|
||||||
|
if (!ctSlugs.length) {
|
||||||
|
console.log('No ct slugs to process.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authRes = await request(apiBase + '/collections/users/auth-with-password', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
identity: process.env.POCKETBASE_ADMIN_EMAIL,
|
||||||
|
password: process.env.POCKETBASE_ADMIN_PASSWORD
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (!authRes.ok) throw new Error('Auth failed: ' + authRes.body);
|
||||||
|
const token = JSON.parse(authRes.body).token;
|
||||||
|
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
|
||||||
|
|
||||||
|
for (const slug of ctSlugs) {
|
||||||
|
const filter = "(slug='" + slug + "')";
|
||||||
|
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1&fields=slug,name,deleted_message', {
|
||||||
|
headers: { 'Authorization': token }
|
||||||
|
});
|
||||||
|
if (!listRes.ok) {
|
||||||
|
console.warn('Failed to fetch record for slug "' + slug + '"');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const list = JSON.parse(listRes.body);
|
||||||
|
const rec = list.items && list.items[0];
|
||||||
|
const appName = (rec && rec.name) ? rec.name : slug;
|
||||||
|
const deletedMessage = (rec && rec.deleted_message && rec.deleted_message.trim())
|
||||||
|
? rec.deleted_message.trim()
|
||||||
|
: 'This script was removed and cannot be installed or updated.';
|
||||||
|
|
||||||
|
const stubPath = path.join('ct', slug + '.sh');
|
||||||
|
const content =
|
||||||
|
`#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
|
||||||
|
APP="${appName.replace(/"/g, '\\"')}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
|
||||||
|
msg_error "This script is no longer available in community-scripts."
|
||||||
|
msg_error "${deletedMessage.replace(/"/g, '\\"')}"
|
||||||
|
msg_warn "More info: https://community-scripts.org/scripts/${slug}"
|
||||||
|
exit 1
|
||||||
|
`;
|
||||||
|
fs.writeFileSync(stubPath, content);
|
||||||
|
console.log('Generated stub: ' + stubPath);
|
||||||
|
}
|
||||||
|
})().catch(e => { console.error(e); process.exit(1); });
|
||||||
|
ENDSCRIPT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Commit generated stubs
|
||||||
|
if: steps.slugs.outputs.count != '0'
|
||||||
|
run: |
|
||||||
|
if git diff --quiet -- ct; then
|
||||||
|
echo "No generated ct stubs to commit."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add ct/*.sh
|
||||||
|
git commit -m "chore: add deleted script stubs"
|
||||||
|
git push
|
||||||
|
shell: bash
|
||||||
|
|||||||
@@ -483,14 +483,35 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## 2026-06-16
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Feishin ([#15130](https://github.com/community-scripts/ProxmoxVE/pull/15130))
|
||||||
|
- Kiwix ([#15131](https://github.com/community-scripts/ProxmoxVE/pull/15131))
|
||||||
|
- Add runtime status guard and deleted script stubs [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15125](https://github.com/community-scripts/ProxmoxVE/pull/15125))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix storyteller install failure with yarn 4 corepack [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15140](https://github.com/community-scripts/ProxmoxVE/pull/15140))
|
||||||
|
- Fix InvoiceShelf install/update Yarn package manager mismatch [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15141](https://github.com/community-scripts/ProxmoxVE/pull/15141))
|
||||||
|
- fix: generate policy-compliant OpenObserve root password [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#15137](https://github.com/community-scripts/ProxmoxVE/pull/15137))
|
||||||
|
|
||||||
## 2026-06-15
|
## 2026-06-15
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Watcharr: Clean install on update [@tremor021](https://github.com/tremor021) ([#15119](https://github.com/community-scripts/ProxmoxVE/pull/15119))
|
||||||
- Vaultwarden: extend version check for VaultWarden update [@MickLesk](https://github.com/MickLesk) ([#15105](https://github.com/community-scripts/ProxmoxVE/pull/15105))
|
- Vaultwarden: extend version check for VaultWarden update [@MickLesk](https://github.com/MickLesk) ([#15105](https://github.com/community-scripts/ProxmoxVE/pull/15105))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- degoog: add curl-impersonate to script [@MickLesk](https://github.com/MickLesk) ([#15117](https://github.com/community-scripts/ProxmoxVE/pull/15117))
|
||||||
|
|
||||||
### 💾 Core
|
### 💾 Core
|
||||||
|
|
||||||
- #### ✨ New Features
|
- #### ✨ New Features
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
|
||||||
|
APP="BookLore"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
|
||||||
|
msg_error "This script is no longer available in community-scripts."
|
||||||
|
msg_error "The Booklore or the Grimmory Fork will for now not return to community-scripts. Due to the unstable nature of these projects we decided to remove them and will decide at later point if they come back, which will most likley not happen. Plese do not create Issues for this."
|
||||||
|
msg_warn "More info: https://community-scripts.org/scripts/booklore"
|
||||||
|
exit 1
|
||||||
@@ -52,6 +52,7 @@ function update_script() {
|
|||||||
msg_ok "Updated Valkey"
|
msg_ok "Updated Valkey"
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "curl-impersonate" "lexiforest/curl-impersonate" "prebuild" "latest" "/usr/local/bin" "curl-impersonate-v*.$(uname -m)-linux-gnu.tar.gz"
|
||||||
|
|
||||||
restore_backup
|
restore_backup
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: MickLesk (CanbiZ)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/jeffvli/feishin
|
||||||
|
|
||||||
|
APP="Feishin"
|
||||||
|
var_tags="${var_tags:-music;player;streaming}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-4096}"
|
||||||
|
var_disk="${var_disk:-8}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_arm64="${var_arm64:-no}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -d /opt/feishin ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "feishin" "jeffvli/feishin"; then
|
||||||
|
create_backup /opt/feishin/.env
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "feishin" "jeffvli/feishin" "tarball"
|
||||||
|
|
||||||
|
msg_info "Rebuilding Feishin Web"
|
||||||
|
cd /opt/feishin
|
||||||
|
#PNPM_VERSION=$(jq -r '.packageManager | ltrimstr("pnpm@")' /opt/feishin/package.json)
|
||||||
|
$STD corepack enable
|
||||||
|
$STD corepack prepare "pnpm@10" --activate
|
||||||
|
$STD pnpm install
|
||||||
|
$STD pnpm run build:web
|
||||||
|
msg_ok "Rebuilt Feishin Web"
|
||||||
|
|
||||||
|
restore_backup
|
||||||
|
|
||||||
|
msg_info "Publishing Web Assets"
|
||||||
|
rm -rf /usr/share/nginx/html
|
||||||
|
mkdir -p /usr/share/nginx/html
|
||||||
|
cp -r /opt/feishin/out/web/. /usr/share/nginx/html/
|
||||||
|
|
||||||
|
set -a
|
||||||
|
source /opt/feishin/.env
|
||||||
|
set +a
|
||||||
|
|
||||||
|
envsubst </opt/feishin/settings.js.template >/etc/nginx/conf.d/settings.js
|
||||||
|
envsubst '${PUBLIC_PATH}' </opt/feishin/ng.conf.template >/etc/nginx/sites-available/feishin
|
||||||
|
ln -sf /etc/nginx/sites-available/feishin /etc/nginx/sites-enabled/feishin
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
systemctl restart nginx
|
||||||
|
msg_ok "Published Web Assets"
|
||||||
|
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
fi
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed Successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:9180${CL}"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
____ __ __
|
||||||
|
/ __ )____ ____ / /__/ / ____ ________
|
||||||
|
/ __ / __ \/ __ \/ //_/ / / __ \/ ___/ _ \
|
||||||
|
/ /_/ / /_/ / /_/ / ,< / /___/ /_/ / / / __/
|
||||||
|
/_____/\____/\____/_/|_/_____/\____/_/ \___/
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
______ _ __ _
|
||||||
|
/ ____/__ (_)____/ /_ (_)___
|
||||||
|
/ /_ / _ \/ / ___/ __ \/ / __ \
|
||||||
|
/ __/ / __/ (__ ) / / / / / / /
|
||||||
|
/_/ \___/_/____/_/ /_/_/_/ /_/
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
__ __ _ _
|
||||||
|
/ //_/(_) __(_) __
|
||||||
|
/ ,< / / | /| / / / |/_/
|
||||||
|
/ /| |/ /| |/ |/ / /> <
|
||||||
|
/_/ |_/_/ |__/|__/_/_/|_|
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
__ _ __ __ __ __ ___
|
||||||
|
/ / (_) /____ / / / / / |/ /
|
||||||
|
/ / / / __/ _ \/ / / / / /|_/ /
|
||||||
|
/ /___/ / /_/ __/ /___/ /___/ / / /
|
||||||
|
/_____/_/\__/\___/_____/_____/_/ /_/
|
||||||
|
|
||||||
@@ -52,8 +52,14 @@ function update_script() {
|
|||||||
msg_info "Updating Application"
|
msg_info "Updating Application"
|
||||||
cd /opt/invoiceshelf
|
cd /opt/invoiceshelf
|
||||||
$STD composer install --no-dev --optimize-autoloader
|
$STD composer install --no-dev --optimize-autoloader
|
||||||
|
if command -v corepack >/dev/null 2>&1; then
|
||||||
|
$STD corepack enable
|
||||||
|
$STD corepack yarn install
|
||||||
|
$STD corepack yarn build
|
||||||
|
else
|
||||||
$STD yarn install
|
$STD yarn install
|
||||||
$STD yarn build
|
$STD yarn build
|
||||||
|
fi
|
||||||
$STD php artisan migrate --force
|
$STD php artisan migrate --force
|
||||||
$STD php artisan optimize:clear
|
$STD php artisan optimize:clear
|
||||||
chown -R www-data:www-data /opt/invoiceshelf
|
chown -R www-data:www-data /opt/invoiceshelf
|
||||||
|
|||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: MickLesk
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/kiwix/kiwix-tools
|
||||||
|
|
||||||
|
APP="Kiwix"
|
||||||
|
var_tags="${var_tags:-documentation;offline}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-512}"
|
||||||
|
var_disk="${var_disk:-4}"
|
||||||
|
var_os="${var_os:-ubuntu}"
|
||||||
|
var_version="${var_version:-24.04}"
|
||||||
|
var_arm64="${var_arm64:-no}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if ! dpkg -s kiwix-tools &>/dev/null; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
CURRENT=$(dpkg-query -W -f='${Version}' kiwix-tools 2>/dev/null)
|
||||||
|
|
||||||
|
msg_info "Updating Package Index"
|
||||||
|
$STD apt update
|
||||||
|
msg_ok "Updated Package Index"
|
||||||
|
|
||||||
|
CANDIDATE=$(apt-cache policy kiwix-tools | awk '/Candidate:/{print $2}')
|
||||||
|
if [[ -z "$CANDIDATE" || "$CANDIDATE" == "(none)" ]]; then
|
||||||
|
msg_error "No Candidate Version Found for kiwix-tools"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$CURRENT" == "$CANDIDATE" ]]; then
|
||||||
|
echo "${CURRENT}" >/root/.kiwix
|
||||||
|
msg_ok "Already on latest version: ${CURRENT}"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop kiwix-serve
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Updating Kiwix-Tools"
|
||||||
|
$STD apt install -y --only-upgrade kiwix-tools
|
||||||
|
RELEASE=$(dpkg-query -W -f='${Version}' kiwix-tools 2>/dev/null)
|
||||||
|
echo "${RELEASE}" >/root/.kiwix
|
||||||
|
msg_ok "Updated Kiwix-Tools"
|
||||||
|
msg_ok "Updated successfully from ${CURRENT} to ${RELEASE}!"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start kiwix-serve
|
||||||
|
msg_ok "Started Service"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8080${CL}"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
|
||||||
|
APP="LiteLLM"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
|
||||||
|
msg_error "This script is no longer available in community-scripts."
|
||||||
|
msg_error "This script was removed and cannot be installed or updated."
|
||||||
|
msg_warn "More info: https://community-scripts.org/scripts/litellm"
|
||||||
|
exit 1
|
||||||
+4
-69
@@ -1,80 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: MickLesk (CanbiZ)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: https://github.com/minio/minio
|
|
||||||
|
|
||||||
APP="MinIO"
|
APP="MinIO"
|
||||||
var_tags="${var_tags:-object-storage}"
|
|
||||||
var_cpu="${var_cpu:-1}"
|
|
||||||
var_ram="${var_ram:-1024}"
|
|
||||||
var_disk="${var_disk:-5}"
|
|
||||||
var_os="${var_os:-debian}"
|
|
||||||
var_version="${var_version:-13}"
|
|
||||||
var_arm64="${var_arm64:-no}"
|
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
|
||||||
|
|
||||||
header_info "$APP"
|
header_info "$APP"
|
||||||
variables
|
variables
|
||||||
color
|
color
|
||||||
catch_errors
|
|
||||||
|
|
||||||
function update_script() {
|
msg_error "This script is no longer available in community-scripts."
|
||||||
header_info
|
msg_error "Repository is archived. Minio is gone"
|
||||||
check_container_storage
|
msg_warn "More info: https://community-scripts.org/scripts/minio"
|
||||||
check_container_resources
|
exit 1
|
||||||
if [[ ! -f /usr/local/bin/minio ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
FEATURE_RICH_VERSION="2025-04-22T22-12-26Z"
|
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/minio/minio/releases/latest | grep '"tag_name"' | awk -F '"' '{print $4}')
|
|
||||||
CURRENT_VERSION=""
|
|
||||||
[[ -f /opt/${APP}_version.txt ]] && CURRENT_VERSION=$(cat /opt/${APP}_version.txt)
|
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/minio/minio/releases/latest | grep '"tag_name"' | awk -F '"' '{print $4}')
|
|
||||||
|
|
||||||
if [[ "${CURRENT_VERSION}" == "${FEATURE_RICH_VERSION}" && "${RELEASE}" != "${FEATURE_RICH_VERSION}" ]]; then
|
|
||||||
echo
|
|
||||||
echo "You are currently running the last feature-rich community version: ${FEATURE_RICH_VERSION}"
|
|
||||||
echo "WARNING: Updating to the latest version will REMOVE most management features from the Console UI."
|
|
||||||
echo "Do you still want to upgrade to the latest version? [y/N]: "
|
|
||||||
read -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
msg_ok "No update performed. Staying on the feature-rich version."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "${CURRENT_VERSION}" != "${RELEASE}" ]]; then
|
|
||||||
msg_info "Stopping Service"
|
|
||||||
systemctl stop minio
|
|
||||||
msg_ok "Stopped Service"
|
|
||||||
|
|
||||||
msg_info "Updating ${APP} to ${RELEASE}"
|
|
||||||
mv /usr/local/bin/minio /usr/local/bin/minio_bak
|
|
||||||
curl -fsSL "https://dl.min.io/server/minio/release/linux-amd64/minio" -o /usr/local/bin/minio
|
|
||||||
chmod +x /usr/local/bin/minio
|
|
||||||
rm -f /usr/local/bin/minio_bak
|
|
||||||
echo "${RELEASE}" >/opt/${APP}_version.txt
|
|
||||||
msg_ok "Updated ${APP}"
|
|
||||||
|
|
||||||
msg_info "Starting Service"
|
|
||||||
systemctl start minio
|
|
||||||
msg_ok "Started Service"
|
|
||||||
msg_ok "Updated successfully!"
|
|
||||||
else
|
|
||||||
msg_ok "No update required. ${APP} is already at ${RELEASE}"
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
start
|
|
||||||
build_container
|
|
||||||
description
|
|
||||||
|
|
||||||
msg_ok "Completed successfully!\n"
|
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
|
||||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
|
||||||
echo -e "${GATEWAY}${BGN}http://${IP}:9000${CL}"
|
|
||||||
|
|||||||
+3
-2
@@ -48,13 +48,14 @@ function update_script() {
|
|||||||
msg_info "Rebuilding Storyteller"
|
msg_info "Rebuilding Storyteller"
|
||||||
cd /opt/storyteller
|
cd /opt/storyteller
|
||||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||||
$STD yarn install --network-timeout 600000
|
$STD corepack enable
|
||||||
|
$STD corepack yarn install --network-timeout 600000
|
||||||
$STD gcc -g -fPIC -rdynamic -shared web/sqlite/uuid.c -o web/sqlite/uuid.c.so
|
$STD gcc -g -fPIC -rdynamic -shared web/sqlite/uuid.c -o web/sqlite/uuid.c.so
|
||||||
export CI=1
|
export CI=1
|
||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
export NEXT_TELEMETRY_DISABLED=1
|
export NEXT_TELEMETRY_DISABLED=1
|
||||||
export SQLITE_NATIVE_BINDING=/opt/storyteller/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
export SQLITE_NATIVE_BINDING=/opt/storyteller/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||||
$STD yarn workspaces foreach -Rpt --from @storyteller-platform/web --exclude @storyteller-platform/eslint run build
|
$STD corepack yarn workspaces foreach -Rpt --from @storyteller-platform/web --exclude @storyteller-platform/eslint run build
|
||||||
mkdir -p /opt/storyteller/web/.next/standalone/web/.next/static
|
mkdir -p /opt/storyteller/web/.next/standalone/web/.next/static
|
||||||
cp -rT /opt/storyteller/web/.next/static /opt/storyteller/web/.next/standalone/web/.next/static
|
cp -rT /opt/storyteller/web/.next/static /opt/storyteller/web/.next/standalone/web/.next/static
|
||||||
if [[ -d /opt/storyteller/web/public ]]; then
|
if [[ -d /opt/storyteller/web/public ]]; then
|
||||||
|
|||||||
+3
-3
@@ -34,9 +34,9 @@ function update_script() {
|
|||||||
systemctl stop watcharr
|
systemctl stop watcharr
|
||||||
msg_ok "Stopped Service"
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
rm -f /opt/watcharr/server/watcharr
|
create_backup /opt/watcharr/server/data
|
||||||
rm -rf /opt/watcharr/server/ui
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "watcharr" "sbondCo/Watcharr" "tarball"
|
||||||
fetch_and_deploy_gh_release "watcharr" "sbondCo/Watcharr" "tarball"
|
restore_backup
|
||||||
|
|
||||||
msg_info "Updating Watcharr"
|
msg_info "Updating Watcharr"
|
||||||
cd /opt/watcharr
|
cd /opt/watcharr
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ ln -sf /root/.bun/bin/bun /usr/local/bin/bun
|
|||||||
ln -sf /root/.bun/bin/bunx /usr/local/bin/bunx
|
ln -sf /root/.bun/bin/bunx /usr/local/bin/bunx
|
||||||
msg_ok "Installed Bun"
|
msg_ok "Installed Bun"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "curl-impersonate" "lexiforest/curl-impersonate" "prebuild" "latest" "/usr/local/bin" "curl-impersonate-v*.$(uname -m)-linux-gnu.tar.gz"
|
||||||
fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
|
fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
|
||||||
|
|
||||||
msg_info "Setting up degoog"
|
msg_info "Setting up degoog"
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: MickLesk (CanbiZ)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/jeffvli/feishin
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
$STD apt install -y \
|
||||||
|
nginx \
|
||||||
|
gettext-base
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "feishin" "jeffvli/feishin" "tarball"
|
||||||
|
|
||||||
|
msg_info "Building Feishin Web"
|
||||||
|
cd /opt/feishin
|
||||||
|
#PNPM_VERSION=$(jq -r '.packageManager | ltrimstr("pnpm@")' /opt/feishin/package.json)
|
||||||
|
$STD corepack enable
|
||||||
|
$STD corepack prepare "pnpm@10" --activate
|
||||||
|
$STD pnpm install
|
||||||
|
$STD pnpm run build:web
|
||||||
|
msg_ok "Built Feishin Web"
|
||||||
|
|
||||||
|
msg_info "Configuring Environment"
|
||||||
|
cat <<EOF >/opt/feishin/.env
|
||||||
|
SERVER_NAME=jellyfin
|
||||||
|
SERVER_LOCK=false
|
||||||
|
SERVER_TYPE=jellyfin
|
||||||
|
SERVER_URL=http://localhost:8096
|
||||||
|
REMOTE_URL=
|
||||||
|
LEGACY_AUTHENTICATION=false
|
||||||
|
ANALYTICS_DISABLED=false
|
||||||
|
PUBLIC_PATH=/
|
||||||
|
EOF
|
||||||
|
msg_ok "Configured Environment"
|
||||||
|
|
||||||
|
msg_info "Publishing Web Assets"
|
||||||
|
rm -rf /usr/share/nginx/html
|
||||||
|
mkdir -p /usr/share/nginx/html
|
||||||
|
cp -r /opt/feishin/out/web/. /usr/share/nginx/html/
|
||||||
|
|
||||||
|
set -a
|
||||||
|
source /opt/feishin/.env
|
||||||
|
set +a
|
||||||
|
|
||||||
|
envsubst </opt/feishin/settings.js.template >/etc/nginx/conf.d/settings.js
|
||||||
|
envsubst '${PUBLIC_PATH}' </opt/feishin/ng.conf.template >/etc/nginx/sites-available/feishin
|
||||||
|
|
||||||
|
ln -sf /etc/nginx/sites-available/feishin /etc/nginx/sites-enabled/feishin
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
systemctl enable -q --now nginx
|
||||||
|
systemctl reload nginx
|
||||||
|
msg_ok "Published Web Assets"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@@ -39,8 +39,14 @@ sed -i "s|^DB_USERNAME=.*|DB_USERNAME=${PG_DB_USER}|" .env
|
|||||||
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=${PG_DB_PASS}|" .env
|
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=${PG_DB_PASS}|" .env
|
||||||
COMPOSER_ALLOW_SUPERUSER=1 $STD composer install --no-dev --optimize-autoloader --no-interaction
|
COMPOSER_ALLOW_SUPERUSER=1 $STD composer install --no-dev --optimize-autoloader --no-interaction
|
||||||
$STD php artisan key:generate
|
$STD php artisan key:generate
|
||||||
$STD yarn install
|
if command -v corepack >/dev/null 2>&1; then
|
||||||
$STD yarn build
|
$STD corepack enable
|
||||||
|
$STD corepack yarn install
|
||||||
|
$STD corepack yarn build
|
||||||
|
else
|
||||||
|
$STD yarn install
|
||||||
|
$STD yarn build
|
||||||
|
fi
|
||||||
mkdir -p storage/framework/{cache,sessions,views} storage/logs bootstrap/cache
|
mkdir -p storage/framework/{cache,sessions,views} storage/logs bootstrap/cache
|
||||||
chown -R www-data:www-data /opt/invoiceshelf
|
chown -R www-data:www-data /opt/invoiceshelf
|
||||||
chmod -R 775 storage bootstrap/cache
|
chmod -R 775 storage bootstrap/cache
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: MickLesk (CanbiZ) | tewalds
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/kiwix/kiwix-tools
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
$STD apt install -y software-properties-common
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
msg_info "Adding Kiwix PPA"
|
||||||
|
add-apt-repository -y ppa:kiwixteam/release >>"$(get_active_logfile)" 2>&1
|
||||||
|
$STD apt update
|
||||||
|
msg_ok "Added Kiwix PPA"
|
||||||
|
|
||||||
|
msg_info "Installing Kiwix-Tools"
|
||||||
|
$STD apt install -y kiwix-tools
|
||||||
|
RELEASE=$(dpkg -s kiwix-tools 2>/dev/null | awk '/^Version:/{print $2}')
|
||||||
|
mkdir -p /data
|
||||||
|
echo "${RELEASE}" >/root/.kiwix
|
||||||
|
msg_ok "Installed Kiwix-Tools"
|
||||||
|
|
||||||
|
msg_info "Downloading Kiwix Test Archive"
|
||||||
|
ZIM_BASE_URL="https://download.kiwix.org/zim/wikipedia"
|
||||||
|
ZIM_FILE="$(CURL_TIMEOUT=60 CURL_CONNECT_TO=15 curl_with_retry "${ZIM_BASE_URL}/" "-" |
|
||||||
|
grep -oE 'href="speedtest_en_blob_[0-9]{4}-[0-9]{2}\.zim"' |
|
||||||
|
sed -E 's/^href="|"$//g' |
|
||||||
|
sort -V |
|
||||||
|
tail -n 1)" || true
|
||||||
|
|
||||||
|
if [[ -z "${ZIM_FILE}" ]]; then
|
||||||
|
msg_warn "No Kiwix speedtest ZIM archive found - skipping optional download"
|
||||||
|
else
|
||||||
|
ZIM_URL="${ZIM_BASE_URL}/${ZIM_FILE}"
|
||||||
|
ZIM_TEMP="/data/.${ZIM_FILE}.tmp"
|
||||||
|
ZIM_TARGET="/data/${ZIM_FILE}"
|
||||||
|
if ! CURL_TIMEOUT=120 CURL_CONNECT_TO=15 curl_with_retry "${ZIM_URL}" "${ZIM_TEMP}"; then
|
||||||
|
rm -f "${ZIM_TEMP}"
|
||||||
|
msg_warn "Failed to download Kiwix ZIM archive - skipping optional download"
|
||||||
|
ZIM_FILE=""
|
||||||
|
elif [[ ! -s "${ZIM_TEMP}" ]]; then
|
||||||
|
rm -f "${ZIM_TEMP}"
|
||||||
|
msg_warn "Downloaded Kiwix ZIM archive is empty - skipping optional download"
|
||||||
|
ZIM_FILE=""
|
||||||
|
else
|
||||||
|
mv "${ZIM_TEMP}" "${ZIM_TARGET}"
|
||||||
|
msg_ok "Downloaded Kiwix Test Archive (${ZIM_FILE})"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<'EOF' >/etc/systemd/system/kiwix-serve.service
|
||||||
|
[Unit]
|
||||||
|
Description=Kiwix ZIM Server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/bin/sh -c 'exec /usr/bin/kiwix-serve --port 8080 /data/*.zim'
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now kiwix-serve
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
|
||||||
# Author: MickLesk (CanbiZ)
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: https://github.com/minio/minio
|
|
||||||
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
|
||||||
color
|
|
||||||
verb_ip6
|
|
||||||
catch_errors
|
|
||||||
setting_up_container
|
|
||||||
network_check
|
|
||||||
update_os
|
|
||||||
|
|
||||||
FEATURE_RICH_VERSION="2025-04-22T22-12-26Z"
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "MinIO recently removed many management features from the Console UI."
|
|
||||||
echo "The last feature-complete version is: $FEATURE_RICH_VERSION"
|
|
||||||
echo "Latest versions require the paid edition for full UI functionality."
|
|
||||||
echo
|
|
||||||
echo "Choose which version to install:"
|
|
||||||
echo " [N] Feature-rich community version ($FEATURE_RICH_VERSION) [Recommended]"
|
|
||||||
echo " [Y] Latest version (may lack UI features)"
|
|
||||||
echo
|
|
||||||
read -p "Install latest MinIO version? [y/N]: " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
USE_LATEST=true
|
|
||||||
else
|
|
||||||
USE_LATEST=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "Setting up MinIO"
|
|
||||||
if [[ "$USE_LATEST" == "true" ]]; then
|
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/minio/minio/releases/latest | grep '"tag_name"' | awk -F '"' '{print $4}')
|
|
||||||
DOWNLOAD_URL="https://dl.min.io/server/minio/release/linux-amd64/minio"
|
|
||||||
else
|
|
||||||
RELEASE="$FEATURE_RICH_VERSION"
|
|
||||||
DOWNLOAD_URL="https://dl.min.io/server/minio/release/linux-amd64/archive/minio.RELEASE.${FEATURE_RICH_VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
curl -fsSL "$DOWNLOAD_URL" -o /usr/local/bin/minio
|
|
||||||
chmod +x /usr/local/bin/minio
|
|
||||||
useradd -r minio-user -s /sbin/nologin
|
|
||||||
mkdir -p /home/minio-user
|
|
||||||
chown minio-user:minio-user /home/minio-user
|
|
||||||
mkdir -p /data
|
|
||||||
chown minio-user:minio-user /data
|
|
||||||
|
|
||||||
MINIO_ADMIN_USER="minioadmin"
|
|
||||||
MINIO_ADMIN_PASSWORD="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)"
|
|
||||||
|
|
||||||
cat <<EOF >/etc/default/minio
|
|
||||||
MINIO_ROOT_USER=${MINIO_ADMIN_USER}
|
|
||||||
MINIO_ROOT_PASSWORD=${MINIO_ADMIN_PASSWORD}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
{
|
|
||||||
echo ""
|
|
||||||
echo "MinIO Credentials"
|
|
||||||
echo "MinIO Admin User: $MINIO_ADMIN_USER"
|
|
||||||
echo "MinIO Admin Password: $MINIO_ADMIN_PASSWORD"
|
|
||||||
} >>~/minio.creds
|
|
||||||
echo "${RELEASE}" >/opt/${APPLICATION,,}_version.txt
|
|
||||||
msg_ok "Setup MinIO"
|
|
||||||
|
|
||||||
msg_info "Creating service"
|
|
||||||
cat <<EOF >/etc/systemd/system/minio.service
|
|
||||||
[Unit]
|
|
||||||
Description=MinIO
|
|
||||||
Documentation=https://docs.min.io
|
|
||||||
Wants=network-online.target
|
|
||||||
After=network-online.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
User=minio-user
|
|
||||||
Group=minio-user
|
|
||||||
EnvironmentFile=-/etc/default/minio
|
|
||||||
ExecStart=/usr/local/bin/minio server --console-address ":9001" /data
|
|
||||||
Restart=always
|
|
||||||
RestartSec=5
|
|
||||||
LimitNOFILE=65536
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
systemctl enable -q --now minio
|
|
||||||
msg_ok "Service created"
|
|
||||||
|
|
||||||
motd_ssh
|
|
||||||
customize
|
|
||||||
cleanup_lxc
|
|
||||||
@@ -17,7 +17,7 @@ msg_info "Installing OpenObserve"
|
|||||||
mkdir -p /opt/openobserve/data
|
mkdir -p /opt/openobserve/data
|
||||||
RELEASE=$(get_latest_github_release "openobserve/openobserve")
|
RELEASE=$(get_latest_github_release "openobserve/openobserve")
|
||||||
tar zxf <(curl -fsSL https://downloads.openobserve.ai/releases/openobserve/v$RELEASE/openobserve-v$RELEASE-linux-amd64.tar.gz) -C /opt/openobserve
|
tar zxf <(curl -fsSL https://downloads.openobserve.ai/releases/openobserve/v$RELEASE/openobserve-v$RELEASE-linux-amd64.tar.gz) -C /opt/openobserve
|
||||||
ROOT_PASS=$(openssl rand -base64 18 | cut -c1-13)
|
ROOT_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c9)Aa1!"
|
||||||
|
|
||||||
cat <<EOF >/opt/openobserve/data/.env
|
cat <<EOF >/opt/openobserve/data/.env
|
||||||
ZO_ROOT_USER_EMAIL = "admin@example.com"
|
ZO_ROOT_USER_EMAIL = "admin@example.com"
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ fetch_and_deploy_gl_release "storyteller" "storyteller-platform/storyteller" "ta
|
|||||||
|
|
||||||
msg_info "Setting up Storyteller"
|
msg_info "Setting up Storyteller"
|
||||||
cd /opt/storyteller
|
cd /opt/storyteller
|
||||||
$STD yarn install --network-timeout 600000
|
$STD corepack enable
|
||||||
|
$STD corepack yarn install --network-timeout 600000
|
||||||
$STD gcc -g -fPIC -rdynamic -shared web/sqlite/uuid.c -o web/sqlite/uuid.c.so
|
$STD gcc -g -fPIC -rdynamic -shared web/sqlite/uuid.c -o web/sqlite/uuid.c.so
|
||||||
STORYTELLER_SECRET_KEY=$(openssl rand -base64 32)
|
STORYTELLER_SECRET_KEY=$(openssl rand -base64 32)
|
||||||
cat <<EOF >/opt/storyteller/.env
|
cat <<EOF >/opt/storyteller/.env
|
||||||
@@ -58,7 +59,7 @@ export CI=1
|
|||||||
export NODE_ENV=production
|
export NODE_ENV=production
|
||||||
export NEXT_TELEMETRY_DISABLED=1
|
export NEXT_TELEMETRY_DISABLED=1
|
||||||
export SQLITE_NATIVE_BINDING=/opt/storyteller/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
export SQLITE_NATIVE_BINDING=/opt/storyteller/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||||
$STD yarn workspaces foreach -Rpt --from @storyteller-platform/web --exclude @storyteller-platform/eslint run build
|
$STD corepack yarn workspaces foreach -Rpt --from @storyteller-platform/web --exclude @storyteller-platform/eslint run build
|
||||||
mkdir -p /opt/storyteller/web/.next/standalone/web/.next/static
|
mkdir -p /opt/storyteller/web/.next/standalone/web/.next/static
|
||||||
cp -rT /opt/storyteller/web/.next/static /opt/storyteller/web/.next/standalone/web/.next/static
|
cp -rT /opt/storyteller/web/.next/static /opt/storyteller/web/.next/standalone/web/.next/static
|
||||||
if [[ -d /opt/storyteller/web/public ]]; then
|
if [[ -d /opt/storyteller/web/public ]]; then
|
||||||
|
|||||||
@@ -3645,6 +3645,53 @@ run_addon_updates() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
runtime_script_status_guard() {
|
||||||
|
local script_slug="${SCRIPT_SLUG:-${NSAPP:-}}"
|
||||||
|
script_slug="$(echo "$script_slug" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
|
||||||
|
[[ -z "$script_slug" ]] && return 0
|
||||||
|
|
||||||
|
local api_url="https://db.community-scripts.org/api/collections/script_scripts/records?filter=(slug='${script_slug}')&perPage=1&fields=slug,is_disabled,is_deleted,disable_message,deleted_message"
|
||||||
|
local response
|
||||||
|
if ! response=$(curl -fsSL --connect-timeout 2 --max-time 3 "$api_url" 2>/dev/null); then
|
||||||
|
msg_warn "Script status check is unavailable. Continuing without status verification."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq >/dev/null 2>&1; then
|
||||||
|
msg_warn "Missing jq for script status check. Continuing without status verification."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local has_record is_deleted is_disabled deleted_message disable_message info_url
|
||||||
|
has_record=$(printf '%s' "$response" | jq -r '.items | length')
|
||||||
|
[[ "$has_record" == "0" ]] && return 0
|
||||||
|
|
||||||
|
is_deleted=$(printf '%s' "$response" | jq -r '.items[0].is_deleted // false')
|
||||||
|
is_disabled=$(printf '%s' "$response" | jq -r '.items[0].is_disabled // false')
|
||||||
|
deleted_message=$(printf '%s' "$response" | jq -r '.items[0].deleted_message // ""')
|
||||||
|
disable_message=$(printf '%s' "$response" | jq -r '.items[0].disable_message // ""')
|
||||||
|
info_url="https://community-scripts.org/scripts/${script_slug}"
|
||||||
|
|
||||||
|
if [[ "$is_deleted" == "true" ]]; then
|
||||||
|
msg_error "This script is no longer available in community-scripts."
|
||||||
|
[[ -n "$deleted_message" ]] && msg_error "$deleted_message"
|
||||||
|
[[ -z "$deleted_message" ]] && msg_error "This script was removed and cannot be installed or updated."
|
||||||
|
msg_warn "More info: ${info_url}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$is_disabled" == "true" ]]; then
|
||||||
|
msg_error "This script is currently disabled in community-scripts."
|
||||||
|
[[ -n "$disable_message" ]] && msg_error "$disable_message"
|
||||||
|
[[ -z "$disable_message" ]] && msg_error "Updates and installs are temporarily disabled for this script."
|
||||||
|
msg_warn "More info: ${info_url}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# start()
|
# start()
|
||||||
#
|
#
|
||||||
@@ -3653,9 +3700,11 @@ run_addon_updates() {
|
|||||||
# - In silent mode: runs update_script with automatic cleanup
|
# - In silent mode: runs update_script with automatic cleanup
|
||||||
# - Otherwise: shows update/setting menu and runs update_script with cleanup
|
# - Otherwise: shows update/setting menu and runs update_script with cleanup
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
|
||||||
if command -v pveversion >/dev/null 2>&1; then
|
if command -v pveversion >/dev/null 2>&1; then
|
||||||
|
runtime_script_status_guard || return 0
|
||||||
install_script || return 0
|
install_script || return 0
|
||||||
return 0
|
return 0
|
||||||
elif [ ! -z ${PHS_SILENT+x} ] && [[ "${PHS_SILENT}" == "1" ]]; then
|
elif [ ! -z ${PHS_SILENT+x} ] && [[ "${PHS_SILENT}" == "1" ]]; then
|
||||||
@@ -3663,6 +3712,7 @@ start() {
|
|||||||
set_std_mode
|
set_std_mode
|
||||||
ensure_profile_loaded
|
ensure_profile_loaded
|
||||||
get_lxc_ip
|
get_lxc_ip
|
||||||
|
runtime_script_status_guard || return 0
|
||||||
update_script
|
update_script
|
||||||
run_addon_updates
|
run_addon_updates
|
||||||
update_motd_ip
|
update_motd_ip
|
||||||
@@ -3673,6 +3723,7 @@ start() {
|
|||||||
set_std_mode
|
set_std_mode
|
||||||
ensure_profile_loaded
|
ensure_profile_loaded
|
||||||
get_lxc_ip
|
get_lxc_ip
|
||||||
|
runtime_script_status_guard || return 0
|
||||||
update_script
|
update_script
|
||||||
run_addon_updates
|
run_addon_updates
|
||||||
update_motd_ip
|
update_motd_ip
|
||||||
@@ -3702,6 +3753,7 @@ start() {
|
|||||||
esac
|
esac
|
||||||
ensure_profile_loaded
|
ensure_profile_loaded
|
||||||
get_lxc_ip
|
get_lxc_ip
|
||||||
|
runtime_script_status_guard || return 0
|
||||||
update_script
|
update_script
|
||||||
run_addon_updates
|
run_addon_updates
|
||||||
update_motd_ip
|
update_motd_ip
|
||||||
|
|||||||
+44
-548
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/LICENSE
|
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/LICENSE
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
SPINNER_PID=""
|
SPINNER_PID=""
|
||||||
@@ -14,18 +14,9 @@ declare -A MSG_INFO_SHOWN
|
|||||||
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
|
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
|
||||||
_CORE_FUNC_LOADED=1
|
_CORE_FUNC_LOADED=1
|
||||||
|
|
||||||
COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main}"
|
|
||||||
|
|
||||||
load_api_functions() {
|
|
||||||
if ! declare -f post_to_api_vm >/dev/null 2>&1; then
|
|
||||||
source /dev/stdin <<<$(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/api.func")
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
load_functions() {
|
load_functions() {
|
||||||
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
|
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
|
||||||
__FUNCTIONS_LOADED=1
|
__FUNCTIONS_LOADED=1
|
||||||
load_api_functions
|
|
||||||
color
|
color
|
||||||
formatting
|
formatting
|
||||||
icons
|
icons
|
||||||
@@ -40,24 +31,18 @@ load_functions() {
|
|||||||
arch_check
|
arch_check
|
||||||
}
|
}
|
||||||
|
|
||||||
load_cloud_init_functions() {
|
|
||||||
if ! declare -f setup_cloud_init >/dev/null 2>&1; then
|
|
||||||
source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/cloud-init.func") 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to download & save header files
|
# Function to download & save header files
|
||||||
get_header() {
|
get_header() {
|
||||||
local app_name=$(echo "${APP,,}" | tr ' ' '-')
|
local app_name=$(echo "${APP,,}" | tr ' ' '-')
|
||||||
local app_type=${APP_TYPE:-vm}
|
local app_type=${APP_TYPE:-vm}
|
||||||
local header_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/${app_type}/headers/${app_name}"
|
local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/${app_type}/headers/${app_name}"
|
||||||
local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}"
|
local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}"
|
||||||
|
|
||||||
mkdir -p "$(dirname "$local_header_path")"
|
mkdir -p "$(dirname "$local_header_path")"
|
||||||
|
|
||||||
if [ ! -s "$local_header_path" ]; then
|
if [ ! -s "$local_header_path" ]; then
|
||||||
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
|
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
|
||||||
return 1
|
return 250
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -113,7 +98,6 @@ icons() {
|
|||||||
DNSOK="✔️ "
|
DNSOK="✔️ "
|
||||||
DNSFAIL="${TAB}✖️${TAB}"
|
DNSFAIL="${TAB}✖️${TAB}"
|
||||||
INFO="${TAB}💡${TAB}${CL}"
|
INFO="${TAB}💡${TAB}${CL}"
|
||||||
CLOUD="${TAB}☁️${TAB}${CL}"
|
|
||||||
OS="${TAB}🖥️${TAB}${CL}"
|
OS="${TAB}🖥️${TAB}${CL}"
|
||||||
OSVERSION="${TAB}🌟${TAB}${CL}"
|
OSVERSION="${TAB}🌟${TAB}${CL}"
|
||||||
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
|
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
|
||||||
@@ -204,32 +188,18 @@ silent() {
|
|||||||
trap 'error_handler' ERR
|
trap 'error_handler' ERR
|
||||||
|
|
||||||
if [[ $rc -ne 0 ]]; then
|
if [[ $rc -ne 0 ]]; then
|
||||||
# Source explain_exit_code if needed
|
# Return instead of exit so that callers can use `$STD cmd || true`
|
||||||
if ! declare -f explain_exit_code >/dev/null 2>&1; then
|
# When no || is used, set -e + ERR trap catches it via error_handler()
|
||||||
source <(curl -fsSL "$COMMUNITY_SCRIPTS_URL/misc/error_handler.func") 2>/dev/null || true
|
export _SILENT_FAILED_RC="$rc"
|
||||||
|
export _SILENT_FAILED_CMD="$cmd"
|
||||||
|
export _SILENT_FAILED_LINE="$caller_line"
|
||||||
|
export _SILENT_FAILED_LOG="$logfile"
|
||||||
|
|
||||||
|
return "$rc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local explanation=""
|
# Clear stale flags on success
|
||||||
if declare -f explain_exit_code >/dev/null 2>&1; then
|
unset _SILENT_FAILED_RC _SILENT_FAILED_CMD _SILENT_FAILED_LINE _SILENT_FAILED_LOG 2>/dev/null || true
|
||||||
explanation="$(explain_exit_code "$rc")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf "\e[?25h"
|
|
||||||
if [[ -n "$explanation" ]]; then
|
|
||||||
msg_error "in line ${caller_line}: exit code ${rc} (${explanation})"
|
|
||||||
else
|
|
||||||
msg_error "in line ${caller_line}: exit code ${rc}"
|
|
||||||
fi
|
|
||||||
msg_custom "→" "${YWB}" "${cmd}"
|
|
||||||
|
|
||||||
if [[ -s "$logfile" ]]; then
|
|
||||||
echo -e "\n${TAB}--- Last 20 lines of log ---"
|
|
||||||
tail -n 20 "$logfile"
|
|
||||||
echo -e "${TAB}----------------------------\n"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit "$rc"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -260,7 +230,7 @@ curl_handler() {
|
|||||||
|
|
||||||
if [[ -z "$url" ]]; then
|
if [[ -z "$url" ]]; then
|
||||||
msg_error "no valid url or option entered for curl_handler"
|
msg_error "no valid url or option entered for curl_handler"
|
||||||
exit 1
|
exit 64
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$STD msg_info "Fetching: $url"
|
$STD msg_info "Fetching: $url"
|
||||||
@@ -289,7 +259,7 @@ curl_handler() {
|
|||||||
rm -f /tmp/curl_error.log
|
rm -f /tmp/curl_error.log
|
||||||
fi
|
fi
|
||||||
__curl_err_handler "$exit_code" "$url" "$curl_stderr"
|
__curl_err_handler "$exit_code" "$url" "$curl_stderr"
|
||||||
exit 1 # hard exit if exit_code is not 0
|
exit "$exit_code"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2
|
$STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2
|
||||||
@@ -332,7 +302,7 @@ __curl_err_handler() {
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
[[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2
|
[[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2
|
||||||
exit 1
|
exit "$exit_code"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -347,7 +317,7 @@ shell_check() {
|
|||||||
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
|
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
|
||||||
echo -e "\nExiting..."
|
echo -e "\nExiting..."
|
||||||
sleep 2
|
sleep 2
|
||||||
exit
|
exit 103
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,11 +338,11 @@ clear_line() {
|
|||||||
#
|
#
|
||||||
# - Determines if script should run in verbose mode
|
# - Determines if script should run in verbose mode
|
||||||
# - Checks VERBOSE and var_verbose variables
|
# - Checks VERBOSE and var_verbose variables
|
||||||
# - Also returns true if not running in TTY (pipe/redirect scenario)
|
# - Note: Non-TTY (pipe) scenarios are handled separately in msg_info()
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
is_verbose_mode() {
|
is_verbose_mode() {
|
||||||
local verbose="${VERBOSE:-${var_verbose:-no}}"
|
local verbose="${VERBOSE:-${var_verbose:-no}}"
|
||||||
[[ "$verbose" != "no" || ! -t 2 ]]
|
[[ "$verbose" != "no" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
### dev spinner ###
|
### dev spinner ###
|
||||||
@@ -511,20 +481,6 @@ msg_debug() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
error_handler() {
|
|
||||||
local exit_code="$?"
|
|
||||||
local line_number="${1:-unknown}"
|
|
||||||
local command="${2:-unknown}"
|
|
||||||
|
|
||||||
if declare -f post_update_to_api >/dev/null 2>&1; then
|
|
||||||
post_update_to_api "failed" "$exit_code"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
|
|
||||||
echo -e "\n$error_message\n"
|
|
||||||
cleanup_vmid
|
|
||||||
}
|
|
||||||
|
|
||||||
# Displays error message and immediately terminates script
|
# Displays error message and immediately terminates script
|
||||||
fatal() {
|
fatal() {
|
||||||
msg_error "$1"
|
msg_error "$1"
|
||||||
@@ -560,13 +516,9 @@ cleanup_vmid() {
|
|||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
local exit_code=$?
|
local exit_code=$?
|
||||||
stop_spinner
|
|
||||||
if [[ "$(dirs -p | wc -l)" -gt 1 ]]; then
|
if [[ "$(dirs -p | wc -l)" -gt 1 ]]; then
|
||||||
popd >/dev/null || true
|
popd >/dev/null || true
|
||||||
fi
|
fi
|
||||||
if [[ -n "${TEMP_DIR:-}" && -d "$TEMP_DIR" ]]; then
|
|
||||||
rm -rf "$TEMP_DIR"
|
|
||||||
fi
|
|
||||||
# Report final telemetry status if post_to_api_vm was called but no update was sent
|
# Report final telemetry status if post_to_api_vm was called but no update was sent
|
||||||
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
|
if [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
|
||||||
if declare -f post_update_to_api >/dev/null 2>&1; then
|
if declare -f post_update_to_api >/dev/null 2>&1; then
|
||||||
@@ -586,37 +538,18 @@ check_root() {
|
|||||||
msg_error "Please run this script as root."
|
msg_error "Please run this script as root."
|
||||||
echo -e "\nExiting..."
|
echo -e "\nExiting..."
|
||||||
sleep 2
|
sleep 2
|
||||||
exit
|
exit 104
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
pve_check() {
|
pve_check() {
|
||||||
local pve_ver
|
if ! pveversion | grep -Eq "pve-manager/(8\.[1-4]|9\.[0-2])(\.[0-9]+)*"; then
|
||||||
pve_ver="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
msg_error "This version of Proxmox Virtual Environment is not supported"
|
||||||
|
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.2."
|
||||||
if [[ "$pve_ver" =~ ^8\.([0-9]+) ]]; then
|
echo -e "Exiting..."
|
||||||
local minor="${BASH_REMATCH[1]}"
|
sleep 2
|
||||||
if ((minor < 0 || minor > 9)); then
|
|
||||||
msg_error "This version of Proxmox VE is not supported."
|
|
||||||
msg_error "Supported: Proxmox VE version 8.0 – 8.9"
|
|
||||||
exit 105
|
exit 105
|
||||||
fi
|
fi
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$pve_ver" =~ ^9\.([0-9]+) ]]; then
|
|
||||||
local minor="${BASH_REMATCH[1]}"
|
|
||||||
if ((minor < 0 || minor > 2)); then
|
|
||||||
msg_error "This version of Proxmox VE is not supported."
|
|
||||||
msg_error "Supported: Proxmox VE version 9.0 – 9.2"
|
|
||||||
exit 105
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_error "This version of Proxmox VE is not supported."
|
|
||||||
msg_error "Supported versions: Proxmox VE 8.0 – 8.9 or 9.0 – 9.2"
|
|
||||||
exit 105
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arch_check() {
|
arch_check() {
|
||||||
@@ -625,487 +558,50 @@ arch_check() {
|
|||||||
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
|
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
|
||||||
echo -e "Exiting..."
|
echo -e "Exiting..."
|
||||||
sleep 2
|
sleep 2
|
||||||
exit
|
exit 106
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
ssh_check() {
|
|
||||||
if command -v pveversion >/dev/null 2>&1 && [ -n "${SSH_CLIENT:-}" ]; then
|
|
||||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
|
|
||||||
:
|
|
||||||
else
|
|
||||||
clear
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
exit_script() {
|
exit_script() {
|
||||||
clear
|
clear
|
||||||
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
|
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
|
||||||
exit
|
exit 0
|
||||||
}
|
|
||||||
|
|
||||||
sanitize_vm_hostname() {
|
|
||||||
local hostname="${1,,}"
|
|
||||||
hostname=$(echo "$hostname" | tr -cs 'a-z0-9-' '-' | sed 's/^-//;s/-$//')
|
|
||||||
echo "${hostname:0:63}"
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_confirm_new_vm() {
|
|
||||||
local title="$1"
|
|
||||||
local message="$2"
|
|
||||||
local height="${3:-10}"
|
|
||||||
local width="${4:-58}"
|
|
||||||
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "$title" --yesno "$message" "$height" "$width"
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_choose_settings_mode() {
|
|
||||||
local message="${1:-Use Default Settings?}"
|
|
||||||
local height="${2:-10}"
|
|
||||||
local width="${3:-58}"
|
|
||||||
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "$message" --no-button Advanced "$height" "$width"
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_confirm_advanced_settings() {
|
|
||||||
local message="$1"
|
|
||||||
local height="${2:-10}"
|
|
||||||
local width="${3:-58}"
|
|
||||||
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "$message" --no-button Do-Over "$height" "$width"
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_vmid() {
|
|
||||||
local default_vmid="${1:-$(get_valid_nextid)}"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 "$default_vmid" --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$VMID" ]; then
|
|
||||||
VMID=$(get_valid_nextid)
|
|
||||||
fi
|
|
||||||
if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
|
|
||||||
echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
|
|
||||||
sleep 2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
|
|
||||||
break
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_apply_machine_type() {
|
|
||||||
local machine_type="${1:-i440fx}"
|
|
||||||
|
|
||||||
if [ "$machine_type" = "q35" ]; then
|
|
||||||
MACHINE_TYPE="q35"
|
|
||||||
FORMAT=""
|
|
||||||
MACHINE=" -machine q35"
|
|
||||||
else
|
|
||||||
MACHINE_TYPE="i440fx"
|
|
||||||
FORMAT=",efitype=4m"
|
|
||||||
MACHINE=""
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_machine_type_label() {
|
|
||||||
case "${1:-i440fx}" in
|
|
||||||
q35)
|
|
||||||
echo "Q35 (Modern)"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "i440fx"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_machine_type() {
|
|
||||||
local default_machine="${1:-i440fx}"
|
|
||||||
local i440fx_default="ON"
|
|
||||||
local q35_default="OFF"
|
|
||||||
local machine_choice
|
|
||||||
|
|
||||||
if [ "$default_machine" = "q35" ]; then
|
|
||||||
i440fx_default="OFF"
|
|
||||||
q35_default="ON"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if machine_choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
|
|
||||||
"i440fx" "Machine i440fx" "$i440fx_default" \
|
|
||||||
"q35" "Machine q35" "$q35_default" \
|
|
||||||
3>&1 1>&2 2>&3); then
|
|
||||||
vm_apply_machine_type "$machine_choice"
|
|
||||||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$(vm_machine_type_label "$MACHINE_TYPE")${CL}"
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_cloud_init() {
|
|
||||||
local default_user="${1:-root}"
|
|
||||||
|
|
||||||
USE_CLOUD_INIT="no"
|
|
||||||
load_cloud_init_functions
|
|
||||||
|
|
||||||
if ! declare -f configure_cloud_init_interactive >/dev/null 2>&1; then
|
|
||||||
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}unavailable${CL}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
configure_cloud_init_interactive "$default_user" || true
|
|
||||||
USE_CLOUD_INIT="${CLOUDINIT_ENABLE:-no}"
|
|
||||||
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}${USE_CLOUD_INIT}${CL}"
|
|
||||||
|
|
||||||
if [ "$USE_CLOUD_INIT" = "yes" ] && declare -f configure_cloudinit_ssh_keys >/dev/null 2>&1; then
|
|
||||||
configure_cloudinit_ssh_keys || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_disk_size() {
|
|
||||||
local default_size="${1:-8G}"
|
|
||||||
local prompt_message="${2:-Set Disk Size in GiB (e.g., 10, 20)}"
|
|
||||||
|
|
||||||
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "$prompt_message" 8 58 "$default_size" --title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
DISK_SIZE=$(echo "$DISK_SIZE" | tr -d ' ')
|
|
||||||
if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
|
|
||||||
DISK_SIZE="${DISK_SIZE}G"
|
|
||||||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
|
|
||||||
elif [[ "$DISK_SIZE" =~ ^[0-9]+G$ ]]; then
|
|
||||||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
|
|
||||||
else
|
|
||||||
echo -e "${DISKSIZE}${BOLD}${RD}Invalid Disk Size. Please use a number (e.g., 10 or 10G).${CL}"
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_disk_cache() {
|
|
||||||
local default_cache="${1:-none}"
|
|
||||||
local none_default="ON"
|
|
||||||
local write_default="OFF"
|
|
||||||
local cache_choice
|
|
||||||
|
|
||||||
if [ "$default_cache" = "writethrough" ]; then
|
|
||||||
none_default="OFF"
|
|
||||||
write_default="ON"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if cache_choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
|
||||||
"0" "None (Default)" "$none_default" \
|
|
||||||
"1" "Write Through" "$write_default" \
|
|
||||||
3>&1 1>&2 2>&3); then
|
|
||||||
if [ "$cache_choice" = "1" ]; then
|
|
||||||
DISK_CACHE="cache=writethrough,"
|
|
||||||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
|
|
||||||
else
|
|
||||||
DISK_CACHE=""
|
|
||||||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_hostname() {
|
|
||||||
local default_hostname="${1:-vm}"
|
|
||||||
local adjusted_hostname
|
|
||||||
local input_hostname
|
|
||||||
|
|
||||||
if input_hostname=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$default_hostname" --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$input_hostname" ]; then
|
|
||||||
HN="$default_hostname"
|
|
||||||
else
|
|
||||||
adjusted_hostname=$(sanitize_vm_hostname "$input_hostname")
|
|
||||||
HN="${adjusted_hostname:-$default_hostname}"
|
|
||||||
if [ "$HN" != "${input_hostname,,}" ]; then
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "HOSTNAME ADJUSTED" --msgbox "Invalid characters detected. Hostname has been adjusted to:\n\n $HN" 10 58
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_cpu_model() {
|
|
||||||
local default_model="${1:-kvm64}"
|
|
||||||
local kvm_default="ON"
|
|
||||||
local host_default="OFF"
|
|
||||||
local cpu_choice
|
|
||||||
|
|
||||||
if [ "$default_model" = "host" ]; then
|
|
||||||
kvm_default="OFF"
|
|
||||||
host_default="ON"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if cpu_choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
|
||||||
"0" "KVM64 (Default)" "$kvm_default" \
|
|
||||||
"1" "Host" "$host_default" \
|
|
||||||
3>&1 1>&2 2>&3); then
|
|
||||||
if [ "$cpu_choice" = "1" ]; then
|
|
||||||
CPU_TYPE=" -cpu host"
|
|
||||||
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
|
|
||||||
else
|
|
||||||
CPU_TYPE=""
|
|
||||||
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_cpu_cores() {
|
|
||||||
local default_cores="${1:-2}"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$default_cores" --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$CORE_COUNT" ]; then
|
|
||||||
CORE_COUNT="$default_cores"
|
|
||||||
fi
|
|
||||||
if [[ "$CORE_COUNT" =~ ^[1-9][0-9]*$ ]]; then
|
|
||||||
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "CPU Cores must be a positive integer (e.g., 2)." 8 58
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_ram() {
|
|
||||||
local default_ram="${1:-2048}"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$default_ram" --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$RAM_SIZE" ]; then
|
|
||||||
RAM_SIZE="$default_ram"
|
|
||||||
fi
|
|
||||||
if [[ "$RAM_SIZE" =~ ^[1-9][0-9]*$ ]]; then
|
|
||||||
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "RAM Size must be a positive integer in MiB (e.g., 2048)." 8 58
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_bridge() {
|
|
||||||
local default_bridge="${1:-vmbr0}"
|
|
||||||
|
|
||||||
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 "$default_bridge" --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$BRG" ]; then
|
|
||||||
BRG="$default_bridge"
|
|
||||||
fi
|
|
||||||
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_mac() {
|
|
||||||
local default_mac="${1:-$GEN_MAC}"
|
|
||||||
local input_mac
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
if input_mac=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 "$default_mac" --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$input_mac" ]; then
|
|
||||||
MAC="$default_mac"
|
|
||||||
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if [[ "$input_mac" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
|
|
||||||
MAC="$input_mac"
|
|
||||||
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "Invalid MAC address format. Use XX:XX:XX:XX:XX:XX (e.g., AA:BB:CC:DD:EE:FF)." 8 58
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_vlan() {
|
|
||||||
local default_vlan="${1:-}"
|
|
||||||
local input_vlan
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
if input_vlan=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan (leave blank for default)" 8 58 "$default_vlan" --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$input_vlan" ]; then
|
|
||||||
VLAN=""
|
|
||||||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if [[ "$input_vlan" =~ ^[0-9]+$ ]] && [ "$input_vlan" -ge 1 ] && [ "$input_vlan" -le 4094 ]; then
|
|
||||||
VLAN=",tag=$input_vlan"
|
|
||||||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$input_vlan${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "VLAN must be a number between 1 and 4094, or leave blank for default." 8 58
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_mtu() {
|
|
||||||
local default_mtu="${1:-}"
|
|
||||||
local input_mtu
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
if input_mtu=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 "$default_mtu" --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
|
||||||
if [ -z "$input_mtu" ]; then
|
|
||||||
MTU=""
|
|
||||||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if [[ "$input_mtu" =~ ^[0-9]+$ ]] && [ "$input_mtu" -ge 576 ] && [ "$input_mtu" -le 65520 ]; then
|
|
||||||
MTU=",mtu=$input_mtu"
|
|
||||||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$input_mtu${CL}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "MTU Size must be a number between 576 and 65520, or leave blank for default." 8 58
|
|
||||||
else
|
|
||||||
exit_script
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_prompt_start_vm() {
|
|
||||||
local default_start="${1:-yes}"
|
|
||||||
local default_flag=()
|
|
||||||
|
|
||||||
if [ "$default_start" = "no" ]; then
|
|
||||||
default_flag=(--defaultno)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if whiptail --backtitle "Proxmox VE Helper Scripts" "${default_flag[@]}" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58; then
|
|
||||||
START_VM="yes"
|
|
||||||
else
|
|
||||||
START_VM="no"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}${START_VM}${CL}"
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_apply_storage_layout() {
|
|
||||||
local storage_type="$1"
|
|
||||||
|
|
||||||
case $storage_type in
|
|
||||||
nfs | dir | cifs)
|
|
||||||
DISK_EXT=".qcow2"
|
|
||||||
DISK_REF="$VMID/"
|
|
||||||
DISK_IMPORT_FORMAT="qcow2"
|
|
||||||
THIN=""
|
|
||||||
;;
|
|
||||||
btrfs)
|
|
||||||
DISK_EXT=".raw"
|
|
||||||
DISK_REF="$VMID/"
|
|
||||||
DISK_IMPORT_FORMAT="raw"
|
|
||||||
FORMAT=",efitype=4m"
|
|
||||||
THIN=""
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
DISK_EXT=""
|
|
||||||
DISK_REF=""
|
|
||||||
DISK_IMPORT_FORMAT="raw"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_select_storage() {
|
|
||||||
local hostname="${1:-${HN:-vm}}"
|
|
||||||
local storage_menu=()
|
|
||||||
local msg_max_length=0
|
|
||||||
local line tag type free item
|
|
||||||
local offset=2
|
|
||||||
local valid_storage
|
|
||||||
|
|
||||||
msg_info "Validating Storage"
|
|
||||||
|
|
||||||
while read -r line; do
|
|
||||||
tag=$(echo "$line" | awk '{print $1}')
|
|
||||||
type=$(echo "$line" | awk '{printf "%-10s", $2}')
|
|
||||||
free=$(echo "$line" | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
|
|
||||||
item=" Type: $type Free: $free "
|
|
||||||
if [[ $((${#item} + offset)) -gt $msg_max_length ]]; then
|
|
||||||
msg_max_length=$((${#item} + offset))
|
|
||||||
fi
|
|
||||||
storage_menu+=("$tag" "$item" "OFF")
|
|
||||||
done < <(pvesm status -content images | awk 'NR>1')
|
|
||||||
|
|
||||||
valid_storage=$(pvesm status -content images | awk 'NR>1')
|
|
||||||
if [ -z "$valid_storage" ]; then
|
|
||||||
msg_error "Unable to detect a valid storage location."
|
|
||||||
exit
|
|
||||||
elif [ $((${#storage_menu[@]} / 3)) -eq 1 ]; then
|
|
||||||
STORAGE=${storage_menu[0]}
|
|
||||||
else
|
|
||||||
if [ -n "${SPINNER_PID:-}" ] && ps -p "$SPINNER_PID" >/dev/null 2>&1; then
|
|
||||||
kill "$SPINNER_PID" >/dev/null 2>&1 || true
|
|
||||||
SPINNER_ACTIVE=0
|
|
||||||
printf "\r\e[2K" >&2
|
|
||||||
fi
|
|
||||||
while [ -z "${STORAGE:+x}" ]; do
|
|
||||||
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
|
|
||||||
"Which storage pool would you like to use for ${hostname}?\nTo make a selection, use the Spacebar.\n" \
|
|
||||||
16 $(($msg_max_length + 23)) 6 \
|
|
||||||
"${storage_menu[@]}" 3>&1 1>&2 2>&3)
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
|
|
||||||
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
|
|
||||||
|
|
||||||
STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')
|
|
||||||
vm_apply_storage_layout "$STORAGE_TYPE"
|
|
||||||
}
|
|
||||||
|
|
||||||
vm_define_disk_references() {
|
|
||||||
local disk_count="${1:-2}"
|
|
||||||
local i disk_name
|
|
||||||
|
|
||||||
for ((i = 0; i < disk_count; i++)); do
|
|
||||||
disk_name="vm-${VMID}-disk-${i}${DISK_EXT:-}"
|
|
||||||
printf -v "DISK${i}" '%s' "$disk_name"
|
|
||||||
printf -v "DISK${i}_REF" '%s' "${STORAGE}:${DISK_REF:-}${disk_name}"
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_hostname_conflict() {
|
check_hostname_conflict() {
|
||||||
local hostname="$1"
|
local hostname="$1"
|
||||||
if qm list | awk '{print $2}' | grep -qx "$hostname"; then
|
if qm list | awk '{print $2}' | grep -qx "$hostname"; then
|
||||||
msg_error "Hostname $hostname already in use by another VM."
|
msg_error "Hostname $hostname already in use by another VM."
|
||||||
exit 1
|
exit 206
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
set_description() {
|
set_description() {
|
||||||
local description_title="${APP:-${NSAPP} VM}"
|
local app_name script_slug script_url donate_url
|
||||||
|
app_name=$(echo "${APP,,}" | tr ' ' '-')
|
||||||
|
script_slug="${SCRIPT_SLUG:-${app_name}}"
|
||||||
|
script_slug="$(echo "$script_slug" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')"
|
||||||
|
script_url="https://community-scripts.org/scripts/${script_slug}"
|
||||||
|
donate_url="https://community-scripts.org/donate"
|
||||||
|
|
||||||
DESCRIPTION=$(
|
DESCRIPTION=$(
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
<div align='center'>
|
<div align='center'>
|
||||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
|
||||||
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
|
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h2 style='font-size: 24px; margin: 20px 0;'>${description_title}</h2>
|
<h2 style='font-size: 24px; margin: 20px 0;'>${NSAPP} VM</h2>
|
||||||
|
|
||||||
<p style='margin: 16px 0;'>
|
<p style='margin: 16px 0;'>
|
||||||
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
|
<a href='${donate_url}' target='_blank' rel='noopener noreferrer'>
|
||||||
<img src='https://img.shields.io/badge/☕-Buy us a coffee-blue' alt='spend Coffee' />
|
<img src='https://img.shields.io/badge/❤️-Sponsoring%20%26%20Donations-FF5E5B' alt='Sponsoring and donations' />
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p style='margin: 12px 0;'>
|
||||||
|
<a href='${script_url}' target='_blank' rel='noopener noreferrer'>
|
||||||
|
<img src='https://img.shields.io/badge/📦-Open%20Script%20Page-00617f' alt='Open script page' />
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user