Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
975a694
add daemon gRPC boilerplate for AZs
andrei-toterman Dec 18, 2024
aae0bba
[az] add abstract classes for az and az manager
andrei-toterman Jan 23, 2025
4187601
[az] add az exceptions
andrei-toterman Feb 6, 2025
369473e
[az] make vms and vm factories aware of zones
andrei-toterman Jan 23, 2025
41b3d14
[az] add az implementation
andrei-toterman Jan 23, 2025
443e1f1
[az] add az manager implementation
andrei-toterman Jan 23, 2025
15ea82b
[daemon] integrate zones in daemon
andrei-toterman Jan 23, 2025
e3eedac
[tests] make stub az classes and put them where they are needed
andrei-toterman Jan 23, 2025
7d960d6
[az] add default zone names to constants
andrei-toterman Apr 1, 2025
449bdee
[az] inject az manager into vm factory constructors
andrei-toterman Apr 1, 2025
23231ae
[az] move az from vm to base vm
andrei-toterman Apr 1, 2025
7d437b6
[az] handle az not found in daemon
andrei-toterman Apr 1, 2025
bd8dc44
[tests] make tests compile with azs
andrei-toterman Apr 1, 2025
8b12e22
[utils] introduce util to read json object from file
andrei-toterman Apr 2, 2025
8e7531a
[az] refactor base az implementation
andrei-toterman Apr 2, 2025
ddeeb95
[az] refactor base az manager implementation
andrei-toterman Apr 2, 2025
aff8dee
[az] Address review comments
Sploder12 Apr 17, 2025
627ab3f
[az] add test coverage for base az and manager files
levkropp Apr 8, 2025
5da1bfe
apply code review suggestions
levkropp Apr 11, 2025
44a1fb4
[az] Fix mock naming
Sploder12 Apr 21, 2025
3f9a1e0
[az] Address some review comments
Sploder12 Apr 24, 2025
96fafde
[az] Address more review comments
Sploder12 May 8, 2025
e1534ee
[az] Integrate Windows
Sploder12 May 9, 2025
a2ed07a
[az] Integrate macOS
Sploder12 May 12, 2025
afeb5d6
[cli] add retrieval of zones
andrei-toterman Jan 23, 2025
af0c618
[tests] fix tests to accommodate AZs
andrei-toterman Feb 7, 2025
f2fdbb7
[tests] add zones command tests for CLI
levkropp Apr 14, 2025
e98bc54
[test] add tests for zones formatting
levkropp Jul 10, 2025
11654bd
Add enable-zones and disable-zones commands
levkropp May 12, 2025
6b5a0ad
Add tests for enable-zones and disable-zones commands
levkropp May 14, 2025
ae976ae
Implement --all option for enabling zones in CLI
levkropp Jun 2, 2025
27979a1
Implement --all option for disabling zones in CLI
levkropp Jun 2, 2025
934a134
ReturnCode::CommandFail if no zones exist
levkropp Jun 2, 2025
d723884
Clarify message for disable-zones --force
levkropp Jun 2, 2025
5d9bf6f
Enhance description for disable-zones command
levkropp Jun 2, 2025
104d926
Enhance description for enable-zones command
levkropp Jun 2, 2025
bc2fd84
Refine descriptions in disable_zones
levkropp Jul 10, 2025
3a5842f
Refine description for enable_zones
levkropp Jul 10, 2025
04b5e9f
disable_zones accepts an empty answer to mean Yes
levkropp Jul 10, 2025
d46ae41
remove redundant no arguments check
levkropp Jul 11, 2025
0edd57c
empty ZonesStateRequest = all zones
levkropp Jul 11, 2025
642517c
add tests for DisableZones::confirm() & on_failure
levkropp Jul 11, 2025
4de24de
add tests for launch.cpp
levkropp Jul 14, 2025
8615f2d
cover enable zones on_failure
levkropp Jul 14, 2025
f2fac15
cover !is_live() in disable_zones
levkropp Jul 15, 2025
f5f6400
add daemon coverage (requires mocked az headers)
levkropp Jul 15, 2025
07f7a04
cover DisableZones::confirm() with multiple zones
levkropp Jul 15, 2025
d83a1ab
use az_manager var for both if branches in daemon
levkropp Jul 31, 2025
a21309d
make DisableZones::confirm() const
levkropp Jul 31, 2025
99bc5f2
add missing space to DisableZones::description string
levkropp Jul 31, 2025
d0fdc5b
Implement availability zones support in GUI
levkropp Apr 9, 2025
d07f2c3
apply code review suggestions
levkropp Apr 10, 2025
7fe8163
always show vm table and buttons on instances page
levkropp Apr 14, 2025
8321da1
zone dropdown and launch form behavior updates
levkropp Apr 14, 2025
6ca3504
add enable zone button and notification in launch form
levkropp Apr 14, 2025
891bfe9
add option to enable all zones when none are available in launch form
levkropp Apr 16, 2025
38bc7c1
make 'launch and configure next' button outlined
levkropp Apr 24, 2025
b85f977
add chevron icon to zones dropdown button
levkropp Apr 24, 2025
639597c
[ci] trigger workflow rerun
levkropp Jul 4, 2025
5c19f33
[az] psuedo zones -> zones
levkropp Jul 10, 2025
f0c717e
add click cursor to zones dropdown switch
levkropp Jul 11, 2025
5ccc6d6
make zone name line height 24px
levkropp Jul 11, 2025
bc2c37c
increase font size and line height for running instance count text
levkropp Jul 11, 2025
c8ed7ff
pad zones dropdown edges at 24px
levkropp Jul 11, 2025
7a0ed4a
padding 24px and format
levkropp Jul 11, 2025
c57e945
increase popup width
levkropp Jul 11, 2025
0b3baf2
button, text, padding, border tweaks
levkropp Jul 11, 2025
1e2c81f
shrink top and bottom padding by 8px
levkropp Jul 11, 2025
7ab05b0
change zones dropdown padding & text
levkropp Jul 14, 2025
82b6068
add zone(s) unavailable warning text
levkropp Jul 14, 2025
b7da816
button height of 32px
levkropp Jul 14, 2025
5941f9f
[az] Fixup rebase
Sploder12 Aug 18, 2025
d36b27c
[az] Add daemon zones tests
Sploder12 Aug 22, 2025
cfa1e14
[az] Add daemon zones state tests
Sploder12 Aug 22, 2025
a74429b
[az] Add json read obj from file tests
Sploder12 Aug 22, 2025
d1fa856
[az] Fix disable-zones tests
Sploder12 Aug 25, 2025
1987a15
[az] Add zone CSV format test
Sploder12 Aug 25, 2025
74adc17
[az] Add daemon rpc test
Sploder12 Aug 25, 2025
78d1ec8
[az] Remove round robin from az manager
levkropp Aug 26, 2025
0a69a2a
[az] Use first available zone in GUI
levkropp Aug 26, 2025
1db1539
[az] Fix default az selection in launch form
levkropp Aug 28, 2025
85a2385
[az] Use find_if to find next available az
levkropp Aug 28, 2025
e1cf4bc
[az] Add qemu subnet support
Sploder12 May 1, 2025
bd3bfc2
[az] Fix some tests
Sploder12 May 2, 2025
405258b
[az] Use alias for subnet container
Sploder12 Aug 7, 2025
1f16559
[az] Add missing dnsmasq test coverage
Sploder12 Aug 7, 2025
348c482
[az] Update formatting
Sploder12 Aug 27, 2025
00a6cd9
[az] Use DisabledCopyMove explicitly
Sploder12 Aug 27, 2025
52a860f
[az] Account for rebase
Sploder12 Oct 21, 2025
acba722
[az] Address C++20 comments
Sploder12 Oct 21, 2025
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
45 changes: 45 additions & 0 deletions include/multipass/availability_zone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef MULTIPASS_AVAILABILITY_ZONE_H
#define MULTIPASS_AVAILABILITY_ZONE_H

#include "disabled_copy_move.h"
#include "virtual_machine.h"

#include <memory>

namespace multipass
{
class AvailabilityZone : private DisabledCopyMove
{
public:
using UPtr = std::unique_ptr<AvailabilityZone>;
using ShPtr = std::shared_ptr<AvailabilityZone>;

virtual ~AvailabilityZone() = default;

[[nodiscard]] virtual const std::string& get_name() const = 0;
[[nodiscard]] virtual const std::string& get_subnet() const = 0;
[[nodiscard]] virtual bool is_available() const = 0;
virtual void set_available(bool new_available) = 0;
virtual void add_vm(VirtualMachine& vm) = 0;
virtual void remove_vm(VirtualMachine& vm) = 0;
};
} // namespace multipass

#endif // MULTIPASS_AVAILABILITY_ZONE_H
49 changes: 49 additions & 0 deletions include/multipass/availability_zone_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef MULTIPASS_AVAILABILITY_ZONE_MANAGER_H
#define MULTIPASS_AVAILABILITY_ZONE_MANAGER_H

#include "availability_zone.h"

#include <functional>
#include <memory>
#include <string>
#include <vector>

namespace multipass
{
class AvailabilityZoneManager : private DisabledCopyMove
{
public:
using UPtr = std::unique_ptr<AvailabilityZoneManager>;
using ShPtr = std::shared_ptr<AvailabilityZoneManager>;

virtual ~AvailabilityZoneManager() = default;

virtual AvailabilityZone& get_zone(const std::string& name) = 0;
virtual std::vector<std::reference_wrapper<const AvailabilityZone>> get_zones() = 0;
// this returns a computed zone name, using an algorithm e.g. round-robin
// not to be confused with [get_default_zone_name]
virtual std::string get_automatic_zone_name() = 0;
// this always returns the same zone name, to be given to VMs that were not assigned to a zone
// in the past not to be confused with [get_automatic_zone]
virtual std::string get_default_zone_name() const = 0;
};
} // namespace multipass

#endif // MULTIPASS_AVAILABILITY_ZONE_MANAGER_H
63 changes: 63 additions & 0 deletions include/multipass/base_availability_zone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef MULTIPASS_BASE_AVAILABILITY_ZONE_H
#define MULTIPASS_BASE_AVAILABILITY_ZONE_H

#include "availability_zone.h"

#include <filesystem>
#include <mutex>
#include <string>
#include <vector>

namespace multipass
{
class BaseAvailabilityZone : public AvailabilityZone
{
public:
BaseAvailabilityZone(const std::string& name, const std::filesystem::path& az_directory);

const std::string& get_name() const override;
const std::string& get_subnet() const override;
bool is_available() const override;
void set_available(bool new_available) override;
void add_vm(VirtualMachine& vm) override;
void remove_vm(VirtualMachine& vm) override;

private:
void serialize() const;

// we store all the data in one struct so that it can be created from one function call in the
// initializer list
struct data
{
const std::string name{};
const std::filesystem::path file_path{};
const std::string subnet{};
bool available{};
std::vector<std::reference_wrapper<VirtualMachine>> vms{};
// we don't have designated initializers, so mutex remains last so it doesn't need to be
// manually initialized
mutable std::recursive_mutex mutex{};
} m;

static data read_from_file(const std::string& name, const std::filesystem::path& file_path);
};
} // namespace multipass

#endif // MULTIPASS_BASE_AVAILABILITY_ZONE_H
81 changes: 81 additions & 0 deletions include/multipass/base_availability_zone_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef MULTIPASS_BASE_AVAILABILITY_ZONE_MANAGER_H
#define MULTIPASS_BASE_AVAILABILITY_ZONE_MANAGER_H

#include "availability_zone_manager.h"

#include <multipass/constants.h>

#include <array>
#include <filesystem>
#include <mutex>
#include <shared_mutex>

namespace multipass
{
class BaseAvailabilityZoneManager final : public AvailabilityZoneManager
{
public:
explicit BaseAvailabilityZoneManager(const std::filesystem::path& data_dir);

AvailabilityZone& get_zone(const std::string& name) override;
std::vector<std::reference_wrapper<const AvailabilityZone>> get_zones() override;
std::string get_automatic_zone_name() override;
std::string get_default_zone_name() const override;

private:
void serialize() const;

class ZoneCollection
{
public:
static constexpr size_t size = default_zone_names.size();
using ZoneArray = std::array<AvailabilityZone::UPtr, size>;
static_assert(size > 0);

const ZoneArray zones{};

ZoneCollection(ZoneArray&& zones, std::string last_used);
[[nodiscard]] std::string next_available();
[[nodiscard]] std::string last_used() const;

private:
ZoneArray::const_iterator automatic_zone;
mutable std::shared_mutex mutex{};
};

// we store all the data in one struct so that it can be created from one function call in the
// initializer list
struct data
{
const std::filesystem::path file_path{};
ZoneCollection zone_collection;
// we don't have designated initializers, so mutex remains last so it doesn't need to be
// manually initialized
mutable std::recursive_mutex mutex{};
} m;

[[nodiscard]] const ZoneCollection::ZoneArray& zones() const;

static data read_from_file(const std::filesystem::path& file_path,
const std::filesystem::path& zones_directory);
};
} // namespace multipass

#endif // MULTIPASS_BASE_AVAILABILITY_ZONE_MANAGER_H
14 changes: 9 additions & 5 deletions include/multipass/cli/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class Command : private DisabledCopyMove

using Arg0Type =
typename multipass::callable_traits<SuccessCallable>::template arg<0>::type;
using ReplyType = typename std::remove_reference<Arg0Type>::type;
using ReplyType = std::decay_t<Arg0Type>;
ReplyType reply;
auto handle_failure = adapt_failure_handler(on_failure, reply);

Expand Down Expand Up @@ -146,7 +146,7 @@ class Command : private DisabledCopyMove
{
using Arg0Type =
typename multipass::callable_traits<SuccessCallable>::template arg<0>::type;
using ReplyType = typename std::remove_reference<Arg0Type>::type;
using ReplyType = std::decay_t<Arg0Type>;
return dispatch(rpc_func,
request,
on_success,
Expand Down Expand Up @@ -176,8 +176,12 @@ class Command : private DisabledCopyMove
using FailureCallableArg0Type =
std::remove_reference_t<typename FailureCallableTraits::template arg<0>::type>;

static_assert(std::is_same<typename SuccessCallableTraits::return_type, ReturnCode>::value);
static_assert(std::is_same<typename FailureCallableTraits::return_type, ReturnCode>::value);
static_assert(
std::is_same_v<std::remove_const_t<typename SuccessCallableTraits::return_type>,
ReturnCode>);
static_assert(
std::is_same_v<std::remove_const_t<typename FailureCallableTraits::return_type>,
ReturnCode>);

static_assert(SuccessCallableTraits::num_args == 1);
static_assert(std::is_base_of_v<google::protobuf::Message, SuccessCallableArg0Type>,
Expand All @@ -192,7 +196,7 @@ class Command : private DisabledCopyMove
static_assert(std::is_same_v<SuccessCallableArg0Type, FailureCallableArg1Type>,
"`on_success` and `on_failure` should handle the same reply types");
}
static_assert(std::is_same<FailureCallableArg0Type, grpc::Status>::value);
static_assert(std::is_same_v<std::remove_const_t<FailureCallableArg0Type>, grpc::Status>);
}

template <typename FailureCallable, typename Reply>
Expand Down
1 change: 1 addition & 0 deletions include/multipass/cli/csv_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ class CSVFormatter final : public Formatter
std::string format(const FindReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
};
} // namespace multipass
1 change: 1 addition & 0 deletions include/multipass/cli/formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Formatter : private DisabledCopyMove
virtual std::string format(const VersionReply& reply,
const std::string& client_version) const = 0;
virtual std::string format(const AliasDict& aliases) const = 0;
virtual std::string format(const ZonesReply& reply) const = 0;

protected:
Formatter() = default;
Expand Down
1 change: 1 addition & 0 deletions include/multipass/cli/json_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ class JsonFormatter final : public Formatter
std::string format(const FindReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
};
} // namespace multipass
1 change: 1 addition & 0 deletions include/multipass/cli/table_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ class TableFormatter final : public Formatter
std::string format(const FindReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
};
} // namespace multipass
1 change: 1 addition & 0 deletions include/multipass/cli/yaml_formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ class YamlFormatter final : public Formatter
std::string format(const FindReply& list) const override;
std::string format(const VersionReply& list, const std::string& client_version) const override;
std::string format(const AliasDict& aliases) const override;
std::string format(const ZonesReply& reply) const override;
};
} // namespace multipass
1 change: 1 addition & 0 deletions include/multipass/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ constexpr auto petenv_default = "primary";
constexpr auto timeout_exit_code = 5;
constexpr auto authenticated_certs_dir = "authenticated-certs";
constexpr auto home_in_instance = "/home/ubuntu";
constexpr auto default_zone_names = {"zone1", "zone2", "zone3"};
} // namespace multipass
41 changes: 41 additions & 0 deletions include/multipass/exceptions/availability_zone_exceptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef MULTIPASS_AVAILABILITY_ZONE_EXCEPTIONS_H
#define MULTIPASS_AVAILABILITY_ZONE_EXCEPTIONS_H

#include "formatted_exception_base.h"

namespace multipass
{
struct AvailabilityZoneNotFound final : FormattedExceptionBase<>
{
explicit AvailabilityZoneNotFound(const std::string& name)
: FormattedExceptionBase{"no AZ with name {:?} found", name}
{
}
};

struct NoAvailabilityZoneAvailable final : std::runtime_error
{
NoAvailabilityZoneAvailable() : std::runtime_error{"no AZ is available"}
{
}
};
} // namespace multipass

#endif // MULTIPASS_AVAILABILITY_ZONE_EXCEPTIONS_H
2 changes: 2 additions & 0 deletions include/multipass/json_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <QJsonObject>
#include <QString>

#include <filesystem>
#include <optional>
#include <string>
#include <vector>
Expand All @@ -41,6 +42,7 @@ class JsonUtils : public Singleton<JsonUtils>

virtual void write_json(const QJsonObject& root,
QString file_name) const; // transactional; creates parent dirs
virtual QJsonObject read_object_from_file(const std::filesystem::path& file_path) const;
virtual std::string json_to_string(const QJsonObject& root) const;
virtual QJsonValue update_cloud_init_instance_id(const QJsonValue& id,
const std::string& src_vm_name,
Expand Down
Loading
Loading