Add force flag to bypass broken packages upon installation

This commit is contained in:
Muhammad Ibrahim
2025-10-04 13:37:05 +01:00
parent fa57b35270
commit 2659a930d6
4 changed files with 75 additions and 6 deletions

View File

@@ -33,6 +33,7 @@ HOST_PREFIX="${HOST_PREFIX:-}"
SKIP_STOPPED="${SKIP_STOPPED:-true}" SKIP_STOPPED="${SKIP_STOPPED:-true}"
PARALLEL_INSTALL="${PARALLEL_INSTALL:-false}" PARALLEL_INSTALL="${PARALLEL_INSTALL:-false}"
MAX_PARALLEL="${MAX_PARALLEL:-5}" MAX_PARALLEL="${MAX_PARALLEL:-5}"
FORCE_INSTALL="${FORCE_INSTALL:-false}"
# ===== COLOR OUTPUT ===== # ===== COLOR OUTPUT =====
RED='\033[0;31m' RED='\033[0;31m'
@@ -243,6 +244,13 @@ while IFS= read -r line; do
# Install PatchMon agent in container # Install PatchMon agent in container
info " Installing PatchMon agent..." info " Installing PatchMon agent..."
# Build install URL with force flag if enabled
install_url="$PATCHMON_URL/api/v1/hosts/install"
if [[ "$FORCE_INSTALL" == "true" ]]; then
install_url="$install_url?force=true"
info " Using force mode - will bypass broken packages"
fi
# Reset exit code for this container # Reset exit code for this container
install_exit_code=0 install_exit_code=0
@@ -253,7 +261,7 @@ while IFS= read -r line; do
-H \"X-API-ID: $api_id\" \ -H \"X-API-ID: $api_id\" \
-H \"X-API-KEY: $api_key\" \ -H \"X-API-KEY: $api_key\" \
-o patchmon-install.sh \ -o patchmon-install.sh \
'$PATCHMON_URL/api/v1/hosts/install' && \ '$install_url' && \
bash patchmon-install.sh && \ bash patchmon-install.sh && \
rm -f patchmon-install.sh rm -f patchmon-install.sh
" 2>&1 </dev/null) || install_exit_code=$? " 2>&1 </dev/null) || install_exit_code=$?

View File

@@ -480,13 +480,17 @@ router.get("/proxmox-lxc", async (req, res) => {
} }
} catch (_) {} } catch (_) {}
// Inject the token credentials, server URL, and curl flags into the script // Check for --force parameter
const force_install = req.query.force === "true" || req.query.force === "1";
// Inject the token credentials, server URL, curl flags, and force flag into the script
const env_vars = `#!/bin/bash const env_vars = `#!/bin/bash
# PatchMon Auto-Enrollment Configuration (Auto-generated) # PatchMon Auto-Enrollment Configuration (Auto-generated)
export PATCHMON_URL="${server_url}" export PATCHMON_URL="${server_url}"
export AUTO_ENROLLMENT_KEY="${token.token_key}" export AUTO_ENROLLMENT_KEY="${token.token_key}"
export AUTO_ENROLLMENT_SECRET="${token_secret}" export AUTO_ENROLLMENT_SECRET="${token_secret}"
export CURL_FLAGS="${curl_flags}" export CURL_FLAGS="${curl_flags}"
export FORCE_INSTALL="${force_install ? "true" : "false"}"
`; `;

View File

@@ -45,6 +45,7 @@ const HostDetail = () => {
const [showDeleteModal, setShowDeleteModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false);
const [showAllUpdates, setShowAllUpdates] = useState(false); const [showAllUpdates, setShowAllUpdates] = useState(false);
const [activeTab, setActiveTab] = useState("host"); const [activeTab, setActiveTab] = useState("host");
const [forceInstall, setForceInstall] = useState(false);
const { const {
data: host, data: host,
@@ -1083,6 +1084,7 @@ const HostDetail = () => {
const CredentialsModal = ({ host, isOpen, onClose }) => { const CredentialsModal = ({ host, isOpen, onClose }) => {
const [showApiKey, setShowApiKey] = useState(false); const [showApiKey, setShowApiKey] = useState(false);
const [activeTab, setActiveTab] = useState("quick-install"); const [activeTab, setActiveTab] = useState("quick-install");
const [forceInstall, setForceInstall] = useState(false);
const apiIdInputId = useId(); const apiIdInputId = useId();
const apiKeyInputId = useId(); const apiKeyInputId = useId();
@@ -1104,6 +1106,12 @@ const CredentialsModal = ({ host, isOpen, onClose }) => {
return settings?.ignore_ssl_self_signed ? "-sk" : "-s"; return settings?.ignore_ssl_self_signed ? "-sk" : "-s";
}; };
// Helper function to build installation URL with optional force flag
const getInstallUrl = () => {
const baseUrl = `${serverUrl}/api/v1/hosts/install`;
return forceInstall ? `${baseUrl}?force=true` : baseUrl;
};
const copyToClipboard = async (text) => { const copyToClipboard = async (text) => {
try { try {
// Try modern clipboard API first // Try modern clipboard API first
@@ -1197,10 +1205,30 @@ const CredentialsModal = ({ host, isOpen, onClose }) => {
Copy and run this command on the target host to securely install Copy and run this command on the target host to securely install
and configure the PatchMon agent: and configure the PatchMon agent:
</p> </p>
{/* Force Install Toggle */}
<div className="mb-3">
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={forceInstall}
onChange={(e) => setForceInstall(e.target.checked)}
className="rounded border-secondary-300 dark:border-secondary-600 text-primary-600 focus:ring-primary-500 dark:focus:ring-primary-400 dark:bg-secondary-700"
/>
<span className="text-primary-800 dark:text-primary-200">
Force install (bypass broken packages)
</span>
</label>
<p className="text-xs text-primary-600 dark:text-primary-400 mt-1">
Enable this if the target host has broken packages
(CloudPanel, WHM, etc.) that block apt-get operations
</p>
</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input <input
type="text" type="text"
value={`curl ${getCurlFlags()} ${serverUrl}/api/v1/hosts/install -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | bash`} value={`curl ${getCurlFlags()} ${getInstallUrl()} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | bash`}
readOnly readOnly
className="flex-1 px-3 py-2 border border-primary-300 dark:border-primary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white" className="flex-1 px-3 py-2 border border-primary-300 dark:border-primary-600 rounded-md bg-white dark:bg-secondary-800 text-sm font-mono text-secondary-900 dark:text-white"
/> />
@@ -1208,7 +1236,7 @@ const CredentialsModal = ({ host, isOpen, onClose }) => {
type="button" type="button"
onClick={() => onClick={() =>
copyToClipboard( copyToClipboard(
`curl ${getCurlFlags()} ${serverUrl}/api/v1/hosts/install -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | bash`, `curl ${getCurlFlags()} ${getInstallUrl()} -H "X-API-ID: ${host.api_id}" -H "X-API-KEY: ${host.api_key}" | bash`,
) )
} }
className="btn-primary flex items-center gap-1" className="btn-primary flex items-center gap-1"

View File

@@ -22,6 +22,7 @@ const Integrations = () => {
const [new_token, setNewToken] = useState(null); const [new_token, setNewToken] = useState(null);
const [show_secret, setShowSecret] = useState(false); const [show_secret, setShowSecret] = useState(false);
const [server_url, setServerUrl] = useState(""); const [server_url, setServerUrl] = useState("");
const [force_proxmox_install, setForceProxmoxInstall] = useState(false);
// Form state // Form state
const [form_data, setFormData] = useState({ const [form_data, setFormData] = useState({
@@ -34,6 +35,12 @@ const Integrations = () => {
const [copy_success, setCopySuccess] = useState({}); const [copy_success, setCopySuccess] = useState({});
// Helper function to build Proxmox enrollment URL with optional force flag
const getProxmoxUrl = () => {
const baseUrl = `${server_url}/api/v1/auto-enrollment/proxmox-lxc?token_key=${new_token.token_key}&token_secret=${new_token.token_secret}`;
return force_proxmox_install ? `${baseUrl}&force=true` : baseUrl;
};
const handleTabChange = (tabName) => { const handleTabChange = (tabName) => {
setActiveTab(tabName); setActiveTab(tabName);
}; };
@@ -664,10 +671,32 @@ const Integrations = () => {
Run this command on your Proxmox host to download and Run this command on your Proxmox host to download and
execute the enrollment script: execute the enrollment script:
</p> </p>
{/* Force Install Toggle */}
<div className="mb-3">
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={force_proxmox_install}
onChange={(e) =>
setForceProxmoxInstall(e.target.checked)
}
className="rounded border-secondary-300 dark:border-secondary-600 text-primary-600 focus:ring-primary-500 dark:focus:ring-primary-400 dark:bg-secondary-700"
/>
<span className="text-secondary-800 dark:text-secondary-200">
Force install (bypass broken packages in containers)
</span>
</label>
<p className="text-xs text-secondary-600 dark:text-secondary-400 mt-1">
Enable this if your LXC containers have broken packages
(CloudPanel, WHM, etc.) that block apt-get operations
</p>
</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input <input
type="text" type="text"
value={`curl -s "${server_url}/api/v1/auto-enrollment/proxmox-lxc?token_key=${new_token.token_key}&token_secret=${new_token.token_secret}" | bash`} value={`curl -s "${getProxmoxUrl()}" | bash`}
readOnly readOnly
className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-secondary-50 dark:bg-secondary-900 text-secondary-900 dark:text-white font-mono text-xs" className="flex-1 px-3 py-2 border border-secondary-300 dark:border-secondary-600 rounded-md bg-secondary-50 dark:bg-secondary-900 text-secondary-900 dark:text-white font-mono text-xs"
/> />
@@ -675,7 +704,7 @@ const Integrations = () => {
type="button" type="button"
onClick={() => onClick={() =>
copy_to_clipboard( copy_to_clipboard(
`curl -s "${server_url}/api/v1/auto-enrollment/proxmox-lxc?token_key=${new_token.token_key}&token_secret=${new_token.token_secret}" | bash`, `curl -s "${getProxmoxUrl()}" | bash`,
"curl-command", "curl-command",
) )
} }