Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions exordos_core/compute/builders/pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,21 @@ def _actualize_machine_derivatives_on_create_update(
# Don't swith boot mode for the core set as the update procedure
# is performed by guest machine driver.
if not self._is_core_machine(machine):
_, guest_actual = machine_guest_pair
guest_target, guest_actual = machine_guest_pair
# A machine that is still being installed has asked for a
# network boot and has not reported back yet. Any update
# that reaches it meanwhile (an element re-rendering its
# node, say) must not take it out of that boot mode: it
# would be rebuilt off a disk Seed OS never wrote.
if (
guest_actual is None
and guest_target.boot == nc.BootAlternative.network
):
boot = nc.BootAlternative.network.value
port = models.Port.from_boot_network()
# The image is changed, so the machine should be booted in the
# `network` boot mode and flashed with a new image.
if guest_actual and guest_actual.image != resolved_image:
elif guest_actual and guest_actual.image != resolved_image:
boot = nc.BootAlternative.network.value
# Any port for the boot network is fine. The port will be replaced
# after the machine is flashed and switched to the main network.
Expand Down
102 changes: 102 additions & 0 deletions exordos_core/tests/unit/compute/test_pool_builder_boot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Copyright 2026 Genesis Corporation.
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""Which boot mode an update leaves a machine in (compute/builders/pool)."""

from unittest import mock
import uuid as sys_uuid

import pytest

from exordos_core.compute import constants as nc
from exordos_core.compute.builders import pool as pool_builder

IMAGE = "http://repo/exordos-base.raw.zst"


@pytest.fixture
def builder():
return pool_builder.PoolBuilderService.__new__(pool_builder.PoolBuilderService)


def _machine(name="worker-a"):
machine = mock.MagicMock()
machine.uuid = sys_uuid.uuid4()
machine.name = name
machine.node.uuid = sys_uuid.uuid4()
return machine


def _guest(boot, image=IMAGE):
guest = mock.MagicMock()
guest.boot = boot
guest.image = image
return guest


def _derivatives(builder, machine, guest_pair):
port, volume = mock.MagicMock(), mock.MagicMock()
volume.image = IMAGE
with (
mock.patch.object(
builder, "_get_or_fetch_machine_ctx", return_value=(port, volume)
),
mock.patch.object(pool_builder.ua_models, "UniversalAgent") as agent,
mock.patch.object(pool_builder.models.Port, "from_boot_network"),
mock.patch.object(
pool_builder.pool_models.PoolMachine, "from_machine_and_port"
),
mock.patch.object(pool_builder.pool_models, "GuestMachine"),
mock.patch.object(builder, "_agent_by_pool", return_value=sys_uuid.uuid4()),
):
agent.objects.get_one_or_none.return_value = mock.MagicMock()
builder._actualize_machine_derivatives_on_create_update(
machine, machine_guest_pair=guest_pair
)
return machine.boot


def test_an_update_keeps_a_machine_that_is_still_installing_on_the_network(builder):
"""Seed OS has not reported back yet: taking the machine off the network
boot would rebuild it from a disk nothing has written."""
machine = _machine()
boot = _derivatives(
builder, machine, guest_pair=(_guest(nc.BootAlternative.network), None)
)
assert boot == nc.BootAlternative.network.value


def test_an_update_leaves_an_installed_machine_on_its_disk(builder):
machine = _machine()
boot = _derivatives(
builder,
machine,
guest_pair=(_guest(nc.BootAlternative.hd0), _guest(nc.BootAlternative.hd0)),
)
assert boot == nc.BootAlternative.hd0.value


def test_a_changed_image_sends_the_machine_back_to_the_network(builder):
machine = _machine()
boot = _derivatives(
builder,
machine,
guest_pair=(
_guest(nc.BootAlternative.hd0),
_guest(nc.BootAlternative.hd0, image="http://repo/other.raw.zst"),
),
)
assert boot == nc.BootAlternative.network.value