<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[VM Boot Order via XO?]]></title><description><![CDATA[<p dir="auto">Hello ~</p>
<p dir="auto">I found this <a href="https://xcp-ng.org/forum/topic/7906/is-it-possible-to-prioritize-the-booting-of-certain-vms-over-another-when-xcp-ng-starts">article</a> within the forums. Is it only possible to prioritize the boot order of VM's via the CLI? Or is there a facility with XO to do so? Thanks in advance for your help.</p>
<h4>USE CASE</h4>
<ul>
<li>Multiple DB types and clusters of DB's</li>
<li>K3S cluster</li>
<li>K8S cluster</li>
<li>Swarm cluster</li>
<li>DB's are required to be up prior to apps clusters (as listed) and in some cases there are interdependencies between various apps across K3S, K8S, and Swarm</li>
</ul>
<p dir="auto">All I am looking to do at the moment is ensure the DB VM's are up and operational prior to initializing my clusters. I can create <code>yml</code> configs to ensure the interdependencies are met within my app infra at a later date. With ESXi this was super easy, even Proxmox to a degree.</p>
<p dir="auto">Still very much new to XCP-ng and need some assistance finding this within the XO GUI.</p>
]]></description><link>https://xcp-ng.org/forum/topic/11222/vm-boot-order-via-xo</link><generator>RSS for Node</generator><lastBuildDate>Wed, 17 Jun 2026 03:29:57 GMT</lastBuildDate><atom:link href="https://xcp-ng.org/forum/topic/11222.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 27 Aug 2025 20:05:33 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to VM Boot Order via XO? on Tue, 02 Sep 2025 13:35:52 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/greg_e" aria-label="Profile: Greg_E">@<bdi>Greg_E</bdi></a> thanks for the clarification.</p>
]]></description><link>https://xcp-ng.org/forum/post/96996</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96996</guid><dc:creator><![CDATA[cichy]]></dc:creator><pubDate>Tue, 02 Sep 2025 13:35:52 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Tue, 02 Sep 2025 13:35:38 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/sid" aria-label="Profile: sid">@<bdi>sid</bdi></a> thanks for this! Not what I was looking for, as you stated, but useful nonetheless.</p>
]]></description><link>https://xcp-ng.org/forum/post/96995</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96995</guid><dc:creator><![CDATA[cichy]]></dc:creator><pubDate>Tue, 02 Sep 2025 13:35:38 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Tue, 02 Sep 2025 01:13:35 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/cichy" aria-label="Profile: cichy">@<bdi>cichy</bdi></a></p>
<p dir="auto">I mentioned waiting for the management agent because that's already a function of checking your backups, so they have part of that puzzle in place.</p>
]]></description><link>https://xcp-ng.org/forum/post/96966</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96966</guid><dc:creator><![CDATA[Greg_E]]></dc:creator><pubDate>Tue, 02 Sep 2025 01:13:35 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Fri, 29 Aug 2025 17:52:21 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/cichy" aria-label="Profile: cichy">@<bdi>cichy</bdi></a> I know this isn't as easy as what you're asking for, but I wrote some terrible python code.</p>
<p dir="auto">It relies on health checks being defined as VM tags, or at least the management agent being detected. For example in my terraform code I have these tags on a test postgres instance and test nginx instances respectively:</p>
<pre><code class="language-hcl"># postgres
  tags = [
    "bootOrder/agent-detect-timeout=45",
    "bootOrder/ip=${jsonencode("auto")}",
    "bootOrder/healtcheck/tcp=${jsonencode({
      "port" : 5432,
    })}",
  ]

# nginx
  tags = [
    "bootOrder/agent-detect-timeout=45",
    "bootOrder/ip=${jsonencode("auto")}",
    "bootOrder/healtcheck/http=${jsonencode({
      "port" : 80,
      "scheme" : "http",
      "path" : "/"
    })}",
  ]
</code></pre>
<p dir="auto">Then the actual python:</p>
<pre><code class="language-python">#!/usr/bin/env python3
import urllib3
import json
import os
import sys
import socket
import time
import logging

logging.basicConfig(level=logging.INFO)

BOOT_ORDER = [
    # Postgres
    ["55e88cb4-0c50-8384-2149-cf73e40b8c8e"],
    # nginx
    ["ba620f01-69d1-ddd8-b1d4-c256abe07e05", "bbe333bd-380a-1f94-4052-881c763b6177"],
]

DEFAULT_AGENT_DETECT_TIMEOUT_SECONDS = 60

class HealthCheck:
    def __init__(self, target: str, config: dict) -&gt; None:
        self.type = "base"
        self.target = target
        self.config = config
        self.timeout = 3
        self.retry_max_count = 5
        self.retry_cur_count = 0
        self.retry_sleep = 10

    def _retry(self):
        if self.retry_cur_count == 0:
            logging.info("Starting %s healtcheck against %s", self.type, self.target)
            self.retry_cur_count += 1
            return True
        if self.retry_cur_count == self.retry_max_count:
            logging.warning('Failed Healtcheck of type %s for %s', self.type, self.target) 
            return False
        time.sleep(self.retry_sleep)
        self.retry_cur_count += 1
        return True


class TCPHealthCheck(HealthCheck):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.type = "TCP"

    def run(self):
        port = self.config.get("port")
        while self._retry():
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
                sock.settimeout(self.timeout)
                success = sock.connect_ex((self.target, port)) == 0
                if success:
                    return True
        return False


class HttpHealthCheck(HealthCheck):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.type = "HTTP"

    def run(self):
        while self._retry():
            assert_hostname = self.config.get("tls_verification", True)
            http = urllib3.PoolManager(
                cert_reqs="CERT_REQUIRED" if assert_hostname else "CERT_NONE",
            )
            scheme = self.config.get("scheme", "http")
            port = self.config.get("port", 80)
            path = self.config.get("path", "").lstrip("/")
            url = f"{scheme}://{self.target}:{port}/{path}"
            response = http.request('GET', url, timeout=self.timeout)
            if response.status &gt;= 200 and response.status &lt; 300:
                return True
        return False

class XoaClient:
    def __init__(self, base_url: str, token: str) -&gt; None:
        self.base_url = base_url.rstrip("/")
        self.tags_prefix = "bootOrder/"
        self.token = token
        self.http = urllib3.PoolManager()
        self.headers = {
            "Content-Type": "application/json",
            "Cookie": f"token={self.token}",
        }
        self._vm_cache = {}

    def vm_ip(self, uuid):
        vm_tags = self._extract_vm_tags(uuid)
        ip = vm_tags.get("ip", "auto")
        if ip != "auto":
            return ip
        return self._get_vm(uuid).get("mainIpAddress")

    def vm_healthcheck(self, uuid):
        vm_tags = self._extract_vm_tags(uuid)
        tcp = vm_tags.get("healtcheck/tcp")
        http = vm_tags.get("healtcheck/http")
        return tcp, http


    def _get_vm(self, uuid: str):
        url = f"{self.base_url}/rest/v0/vms/{uuid}"
        # if url in self._vm_cache:
        #     return self._vm_cache[url]
        response = self.http.request("GET", url, headers=self.headers)
        result = self._handle_json_response(response)

        self._vm_cache[url] = result
        return result

    def _extract_vm_tags(self, uuid: str) -&gt; dict:
        dict_tags = {}
        tags = self._get_vm(uuid).get("tags")
        for tag in tags:
            if tag.startswith(self.tags_prefix):
                k,v = tag.split("=", 1)
                k = k[len(self.tags_prefix):]
                dict_tags[k] = json.loads(v)
        return dict_tags

    def start_vm(self, uuid: str):
        if self._get_vm(uuid).get("power_state") == "Running":
            return
        url = f"{self.base_url}/rest/v0/vms/{uuid}/actions/start?sync=true"
        response = self.http.request("POST", url, headers=self.headers)
        if response.status != 204:
            raise Exception(f"HTTP {response.status}: {response.data.decode('utf-8')}")
        return

    def management_agent_detected(self, uuid: str) -&gt; bool:
        return self._get_vm(uuid).get("managementAgentDetected")

    def vm_agent_detection_timeout(self, uuid: str, default_seconds: int = 60) -&gt; bool:
        tags = self._extract_vm_tags(uuid)
        return tags.get("agent-detect-timeout", default_seconds)

    def _handle_json_response(self, response):
        if response.status &gt;= 200 and response.status &lt; 300:
            return json.loads(response.data.decode("utf-8"))
        else:
            raise Exception(f"HTTP {response.status}: {response.data.decode('utf-8')}")



if __name__ == "__main__":
    xoa_url = os.getenv("XOA_URL")
    xoa_token = os.getenv("XOA_TOKEN")
    if not xoa_url:
        logging.fatal("Missing XOA_URL environment variable")
        sys.exit(1)
    if not xoa_token:
        logging.fatal("Missing XOA_TOKEN environment variable")
        sys.exit(1)
    client = XoaClient(xoa_url, xoa_token)

    group_number = 1
    for boot_group in BOOT_ORDER:
        logging.info("Starting to boot group %s, length %s", group_number, len(boot_group))
        # These should be booted in parallel, but aren't
        for uuid in boot_group:
            client.start_vm(uuid)
            timeout = client.vm_agent_detection_timeout(
                uuid=uuid,
                default_seconds=DEFAULT_AGENT_DETECT_TIMEOUT_SECONDS,
            )
            mad = False
            for n in range(timeout):
                mad = client.management_agent_detected(uuid)
                if mad:
                    break
                time.sleep(1)
            if not mad:
                raise Exception(f"No management agent detected in host {uuid}")
            target = client.vm_ip(uuid)
            tcp, http = client.vm_healthcheck(uuid)
            if tcp:
                hc = TCPHealthCheck(target=target, config=tcp)
                hc.run()
            if http:
                hc = HttpHealthCheck(target=target, config=http)
                hc.run()
            logging.info("All healthchecks passed for %s", target)
        group_number += 1
</code></pre>
<p dir="auto">It'll boot each VM in order and wait for its agent to be detected, then wait for all its health checks to pass before moving on to the next VM.</p>
<p dir="auto">This is by no means production ready code, but it might be a decent solution.</p>
<p dir="auto">Finally a systemd timer would be set up on the XOA instance to auto-run this script on boot.</p>
]]></description><link>https://xcp-ng.org/forum/post/96874</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96874</guid><dc:creator><![CDATA[sid]]></dc:creator><pubDate>Fri, 29 Aug 2025 17:52:21 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Fri, 29 Aug 2025 14:40:27 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/greg_e" aria-label="Profile: Greg_E">@<bdi>Greg_E</bdi></a> exactly! I'm thinking of my junior/int sys-admins who are very comfortable with VMWare process (vCenter). It's dead simple, yet, even vCenter doesn't have a facility that can scan for app/service feedback as a health check. So, this would be a first.</p>
]]></description><link>https://xcp-ng.org/forum/post/96854</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96854</guid><dc:creator><![CDATA[cichy]]></dc:creator><pubDate>Fri, 29 Aug 2025 14:40:27 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Fri, 29 Aug 2025 14:31:41 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/cichy" aria-label="Profile: cichy">@<bdi>cichy</bdi></a></p>
<p dir="auto">Best way to implement this from XO would be to wait until the management agent comes up and then move on to the next VMs in the boot order.</p>
<p dir="auto">I'll have to check out the cli method and see what's involved, there are a few VMs I want to boot in order if the power goes out, things like get the AD VMs up and running so DHCP and DNS are working before other stuff gets booted.</p>
<p dir="auto">My system is small so I don't have things like the "traditional" LAMP stack with separate application, DB, other VMs so I've never looked into this aspect. But it's right on the surface for VMware and a lot of people are going to be looking for this functionality in one way or another. The VMware drag and drop makes it easy for a Junior level admin to configure a vApp to handle this type of requirement.</p>
]]></description><link>https://xcp-ng.org/forum/post/96852</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96852</guid><dc:creator><![CDATA[Greg_E]]></dc:creator><pubDate>Fri, 29 Aug 2025 14:31:41 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Fri, 29 Aug 2025 02:06:26 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/sid" aria-label="Profile: sid">@<bdi>sid</bdi></a> this is how my K8S/K3S and Stack yml configs work. They leverage interdependencies and health checks across clusters (ping via IP and listen for reply etc) work. API or potentially webhooks could work. Though, what I’m asking/looking for is a way that XO could facilitate. Even if the “script” were added via XO-UI and I could expose apps/services/vm’s dynamically via said UI. Proxmox has something similar to this, it’s buried with VM config options within the UI.</p>
]]></description><link>https://xcp-ng.org/forum/post/96812</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96812</guid><dc:creator><![CDATA[cichy]]></dc:creator><pubDate>Fri, 29 Aug 2025 02:06:26 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Fri, 29 Aug 2025 01:53:47 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/cichy" aria-label="Profile: cichy">@<bdi>cichy</bdi></a> I think there's more to it; namely that after a VM has booted, it might still be a while until its services are available. For example a ceph cluster, or an Elasticsearch cluster can take a while to come up, or what if there's an issue where something which should be quick to start fails to start?</p>
<p dir="auto">So I think not only do you want to boot VMs in a certain order, but you also want a health check to pass before proceeding to the next VM.</p>
<p dir="auto">If that is the case, then this might be out of scope of the hypervisor, and instead this could be a script that runs on a VM which is set to auto-start, and doesn't itself depend on other VMs, where it uses the API to start VMs and perform health checks before continuing to the next.</p>
]]></description><link>https://xcp-ng.org/forum/post/96811</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96811</guid><dc:creator><![CDATA[sid]]></dc:creator><pubDate>Fri, 29 Aug 2025 01:53:47 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Fri, 29 Aug 2025 01:25:16 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/thasianxi" aria-label="Profile: ThasianXi">@<bdi>ThasianXi</bdi></a> this is <em>a</em> solution, not the one I was hoping for. I was explicitly hoping for an XO guy-led solution. Something similar to the way VMWare allows one to drag vm's in boot pref. <a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/olivierlambert" aria-label="Profile: olivierlambert">@<bdi>olivierlambert</bdi></a> if this is not a feature request already, how do I make it one?</p>
]]></description><link>https://xcp-ng.org/forum/post/96810</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96810</guid><dc:creator><![CDATA[cichy]]></dc:creator><pubDate>Fri, 29 Aug 2025 01:25:16 GMT</pubDate></item><item><title><![CDATA[Reply to VM Boot Order via XO? on Thu, 28 Aug 2025 04:08:23 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/forum/user/cichy" aria-label="Profile: cichy">@<bdi>cichy</bdi></a> This can be accomplished using vApps via the CLI.<br />
Check out this forum post in which a member shared the process: <a href="https://xcp-ng.org/forum/post/70216">XCP-ng Pool Boot Order</a></p>
]]></description><link>https://xcp-ng.org/forum/post/96773</link><guid isPermaLink="true">https://xcp-ng.org/forum/post/96773</guid><dc:creator><![CDATA[ThasianXi]]></dc:creator><pubDate>Thu, 28 Aug 2025 04:08:23 GMT</pubDate></item></channel></rss>