Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add local.instance.bridged setting. #3193

Merged
merged 4 commits into from
Sep 25, 2023
Merged

Conversation

luis4a0
Copy link
Contributor

@luis4a0 luis4a0 commented Aug 16, 2023

This PR implements the set interface to add a bridged network to an existing instance.

@luis4a0 luis4a0 marked this pull request as draft August 16, 2023 18:30
@codecov
Copy link

codecov bot commented Aug 16, 2023

Codecov Report

Merging #3193 (1a28788) into add-network-bridges (57c464f) will decrease coverage by 0.04%.
The diff coverage is 77.77%.

@@                   Coverage Diff                   @@
##           add-network-bridges    #3193      +/-   ##
=======================================================
- Coverage                88.56%   88.53%   -0.04%     
=======================================================
  Files                      239      239              
  Lines                    12123    12143      +20     
=======================================================
+ Hits                     10737    10751      +14     
- Misses                    1386     1392       +6     
Files Changed Coverage Δ
src/daemon/daemon.cpp 73.31% <45.45%> (-0.26%) ⬇️
src/daemon/instance_settings_handler.cpp 100.00% <100.00%> (ø)

@luis4a0 luis4a0 marked this pull request as ready for review August 18, 2023 12:55
@luis4a0 luis4a0 force-pushed the add-bridged-setting branch 2 times, most recently from 48ac4cd to 42bf8ec Compare September 12, 2023 16:42
Copy link
Collaborator

@ricab ricab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @luis4a0, I was curious and I just had a quick look. The code looks good, I like that you're splitting things into small self contained units 👍 I spotted only a couple of wrinkles in this very superficial pass.

@@ -153,6 +154,48 @@ void update_disk(const QString& key, const QString& val, mp::VirtualMachine& ins
}
}

bool to_bool(const QString& key, const QString& val)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is implemented in BoolSettingSpec. Instead of copy+pasting from there, why don't you instantiate a helper object and use that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ricab, thanks for your quick review!

I thought in avoid copy+pasting, but I opted for not a QString and comparing against it. Just true or false. Do you still think it's OK to reuse the existing implementation?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean: you want to return a bool and compare against that in the code, right? But you can still achieve that with an extra step. For example, just something like this to replace the contents of to_bool: return BoolSettingSpec{key, "false"}.interpret(val) == "true";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to avoid that string comparison, and throw directly instead of returning a value before throwing. But well, it is true that the code looks much better the way you propose. Since time is not critical here, I changed it. Thanks!

auto size = get_memory_size(key, val);
if (property == mem_suffix)
update_mem(key, val, instance, spec, size);
if (property == bridged_suffix)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else if? To avoid one extra nesting level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, changed. I was hesitating whether to mix an inline else if with a structured else { stmt; if ... }. But right, we save four columns the way you mention.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not for saving spaces, it's that it makes it easier to understand that they are alternatives at the same level, with no further shared logic (unlike the following 2 properties, which do share the conversion of the memory size).

inline static constexpr auto properties = std::array{"cpus", "disk", "memory"};
inline static constexpr auto numeric_properties = std::array{"cpus", "disk", "memory"};
inline static constexpr auto boolean_properties = std::array{"bridged"};
inline static constexpr auto properties = std::array{"cpus", "disk", "memory", "bridged"};
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it stems from the original code, but maybe change the copy initialization to direct initialization to make the code cleaner.

    inline static constexpr std::array numeric_properties{"cpus", "disk", "memory"};
    inline static constexpr std::array boolean_properties{"bridged"};
    inline static constexpr std::array properties{"cpus", "disk", "memory", "bridged"};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, looks better that way. Changed.

return true;
}

return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std algorithm based code can be another alternative, the code is shorter, the readability probably is the same

    return std::any_of(spec.extra_interfaces.cbegin(), spec.extra_interfaces.cend(),
                       [](const auto& network) -> bool { return network.auto_mode; });

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks nice, thanks! Changed.

auto bridged = mp::BoolSettingSpec{key, "false"}.interpret(val) == "true";

if (!bridged && is_bridged(spec))
{
Copy link
Contributor

@georgeliao georgeliao Sep 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to elaborate the roles of bridged boolean (it looks like is checking user's input) and is_bridged(spec) (looks like checking if the spec is bridged)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry if it wasn't clear. The bridged boolean is the value given by the user. The is_bridged() function returns a boolean stating if the VM has a bridged interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks.

// An extra interface in auto mode will result in bridging.
specs[target_instance_name].extra_interfaces = {{"id", "52:54:00:12:34:56", bridged}};

auto got = make_handler().get(make_key(target_instance_name, "bridged"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const auto got is better

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, better. Changed.

@georgeliao
Copy link
Contributor

HI @luis4a0 , it looks good overall. I just left a handful minor comments.

@luis4a0
Copy link
Contributor Author

luis4a0 commented Sep 20, 2023

Hey @georgeliao, thanks for the review! I addressed your concerns, let me know if everything looks better now.

bool is_bridged(const mp::VMSpecs& spec)
{
return std::any_of(spec.extra_interfaces.cbegin(), spec.extra_interfaces.cend(),
[](const auto& network) -> bool { return network.auto_mode; });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @luis4a0, I think for our purposes we'd better consider the instance bridged if and only if it has an extra_interface corresponding to the network that is currently set for local.bridged-network. That would make it symmetric to launch --bridged and allow adding multiple interfaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ricab, thanks for your comment. You're right, I didn't think on that. I changed the code to reflect this behavior.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!


if (bridged_id == "")
{
throw std::runtime_error(fmt::format("You have to `multipass set {}=<name>` to use the `--bridged` shortcut.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--bridged is not applicable in the case of settings, so the message needs to be generalized. Perhaps just:

Suggested change
throw std::runtime_error(fmt::format("You have to `multipass set {}=<name>` to use the `--bridged` shortcut.",
throw std::runtime_error(fmt::format("You have to `multipass set {}=<name>` to use the "bridged" shortcut.",

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, changed.

preparing_instances, [this] { persist_instances(); })}
instance_mod_handler{register_instance_mod(
vm_instance_specs, operative_instances, deleted_instances, preparing_instances,
[this] { persist_instances(); }, [] { return get_bridged_interface_name(); })}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need the lambda here? Unlike to persist instances, there is no closure for the bridge, so you should be able to pass the function directly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, nice catch. [this] { persist_instances(); }, get_bridged_interface_name)} will do it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, changed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

It must return true if and only if there exists in the instance an
interface bridged to the current interface set in
local.bridged-interface.
@luis4a0
Copy link
Contributor Author

luis4a0 commented Sep 22, 2023

Hey @ricab @georgeliao, thanks for the review! Let me note that all the uncovered code corresponds to the get_bridged_interface() function in daemon.cpp. It will be tested in the next PR, for doing it here would add lots of unnecessary complexity.

@luis4a0 luis4a0 merged commit 5c86860 into add-network-bridges Sep 25, 2023
13 of 15 checks passed
@bors bors bot deleted the add-bridged-setting branch September 25, 2023 17:40
luis4a0 added a commit that referenced this pull request Sep 26, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Oct 6, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Oct 16, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Oct 18, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Oct 28, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Nov 7, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Nov 7, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Nov 7, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Nov 8, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Nov 10, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Nov 27, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Dec 4, 2023
Add `local.instance.bridged` setting.
luis4a0 added a commit that referenced this pull request Jan 4, 2024
Add `local.instance.bridged` setting.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants