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

Multipass clone #3264

Open
wants to merge 175 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
175 commits
Select commit Hold shift + click to select a range
e40376c
[grpc] Added multipass clone protobuf message place holder.
georgeliao Sep 28, 2023
4d8c1a1
[grpc] Added missing fields of clone message
georgeliao Oct 2, 2023
0fbed45
[cli] Added clone command line class and functions interfaces.
georgeliao Oct 2, 2023
fc6a33f
[cli] Added parse_args implementation and invocation.
georgeliao Oct 2, 2023
fd17fef
[cli] Added grpc code on the frond end.
georgeliao Oct 2, 2023
96b42ff
[grpc] Create the rpc framework for daemon::clone function.
georgeliao Oct 3, 2023
49b0056
Added rpc_request fill-in code on the front end.
georgeliao Oct 3, 2023
2d602c6
Added source_name validity check.
georgeliao Oct 4, 2023
370ca51
Added specified destination name check.
georgeliao Oct 4, 2023
cddeca1
Added generating destination name.
georgeliao Oct 4, 2023
47e28ee
Added the source instance state check.
georgeliao Oct 4, 2023
57478bf
Small renaming for the vm instance pointer variable
georgeliao Oct 12, 2023
cc99eb3
Formatted legacy code diff on this branch based on the new .clang-for…
georgeliao Oct 12, 2023
d6a6a72
[daemon] Added clone_spec_item_and_write_to_instance_db lambda functi…
georgeliao Oct 12, 2023
6b4abef
[daemon] Wrap the destination name related code into generate_destina…
georgeliao Oct 12, 2023
7b5c083
[imageVault] Added clone method for DefaultVMImageVault class
georgeliao Oct 13, 2023
b8ae251
[daemon] Added vault clone method interface and the caller of that.
georgeliao Oct 13, 2023
25a934e
[daemon] Added the code of virtual machine instance folder copy.
georgeliao Oct 16, 2023
c155026
[file_ops] Added copy file wrapper function.
georgeliao Oct 18, 2023
97fc1bd
[daemon] replace the std file copy function with the wrapper one.
georgeliao Oct 18, 2023
fd732fd
[daemon] added qemu_iso and the meta_data and network-config parts.
georgeliao Oct 19, 2023
ba99097
[daemon] Added mount directory creation.
georgeliao Oct 19, 2023
4704c20
[daemon] Added mount command for the iso file.
georgeliao Oct 19, 2023
a4a7b41
[daemon] add the loading the same parts of iso file and write to the …
georgeliao Oct 19, 2023
524c04b
[daemon] Added unmount command.
georgeliao Oct 19, 2023
fba93ca
[daemon] Added removing directory.
georgeliao Oct 19, 2023
447af7e
[daemon] added create_virtual_machine and init_mount code for destina…
georgeliao Oct 20, 2023
f75e054
[daemon] fix the compiler warning which caused the build failure.
georgeliao Oct 20, 2023
716eb5f
[daemon] small fix for rebase conflict.
georgeliao Nov 2, 2023
26d3b83
[daemon, cli] Added the reply message of clone and improved the clone…
georgeliao Nov 14, 2023
45e60a9
[snapshot] modified the find_parent function and added call to snapsh…
georgeliao Nov 16, 2023
1e3fda3
[snapshot] added qemu_snapshot constructor that is based on another s…
georgeliao Nov 16, 2023
95e6540
[snapshot] added clone function interface.
georgeliao Nov 20, 2023
8179527
[virtual_machine] added clone method of qemu virtual machine
georgeliao Nov 20, 2023
6cf74e0
[virtual machine] added clone_snapshots method place holder.
georgeliao Nov 20, 2023
d3a67fc
[virtual machine] small name improvement for the snapshot clone funct…
georgeliao Nov 20, 2023
a688d9b
[snapshot] fix the constness of snapshot classes
georgeliao Nov 20, 2023
c3e5702
[virtual machine] fix the constness of snapshot in clone_one_snapshot…
georgeliao Nov 21, 2023
cc5cab5
[snapshot] reverted the in RAM clone snapshot related code.
georgeliao Nov 21, 2023
8bda1a1
[snapshot] added new constructor for for constructing from file and r…
georgeliao Nov 21, 2023
06e1503
[snapshot] added qemu_snapshot constructor.
georgeliao Nov 21, 2023
a77db55
[virtual machine] added make_specific_snapshot function place holder
georgeliao Nov 21, 2023
3e6d45b
[virtual machine] added make_specific_snapshot qemu implementation.
georgeliao Nov 21, 2023
28065bc
[virtual machine] added public method load_snapshots_and_update_uniqu…
georgeliao Nov 22, 2023
23b17f3
[virtual machine] added load one file to snapshot function. PS: refac…
georgeliao Nov 22, 2023
fab405d
[daemon] added the loading and updating snapshots calls, now the whol…
georgeliao Nov 22, 2023
4d7f13a
[json] added update_unique_identifiers_of_metadata function and refac…
georgeliao Nov 27, 2023
4878dc8
[virtual machine] added load_snapshots_common to reduce the repeated …
georgeliao Nov 27, 2023
593196f
[virtual machine] added variadic templated function load_snapshot_and…
georgeliao Nov 27, 2023
eab612f
[virtual machine] changed load_snapshots_common function to variadic …
georgeliao Nov 27, 2023
13958eb
[virtual machine] added explanatory comment for load_snapshots_common…
georgeliao Nov 27, 2023
3dc81b2
[cli] replaced the destination name positional argument with option.
georgeliao Dec 11, 2023
ec189fe
[cli] fix the warning (compilation error) after upgrading to ubuntu 2…
georgeliao Jan 3, 2024
4cb037a
[cli] fixed and refined the destination name description.
georgeliao Jan 3, 2024
6e0f108
[daemon] added destination name validity check.
georgeliao Jan 3, 2024
643fe95
[virtual machine] improved the name generator based on the team discu…
georgeliao Jan 10, 2024
a36a3e0
[utils] move some yaml helpers functions into utils.cpp to set up the…
georgeliao Jan 11, 2024
9c7a9f6
[daemon] small refactoring, localize the lambda function further.
georgeliao Jan 11, 2024
566ece9
[vm factory] added create_vm_and_instance_disk_data function for clon…
georgeliao Jan 12, 2024
f076464
[vm factory] added create_vm_and_instance_disk_data interface and cal…
georgeliao Jan 12, 2024
e035496
[vm factory] using the new read_from function to read the cloud-init-…
georgeliao Feb 1, 2024
e1f2a69
[cloud init] added at operator, it is similar with std::unordered_map…
georgeliao Feb 7, 2024
b93250c
[vm factory] added load string and replace name functionality of mak…
georgeliao Feb 8, 2024
638e6c8
[cloud init] added contains function.
georgeliao Feb 8, 2024
23dd54f
[vm factory] refine the client code of make_cloud_init_network_config…
georgeliao Feb 8, 2024
77ed82c
[cloud init] clean up some CloudInitIso utility functions/
georgeliao Feb 8, 2024
4171139
[vm factory] added early back-end check for the clone operation.
georgeliao Feb 9, 2024
609b3c7
[json util] refined on the source name to destination name string re…
georgeliao Feb 13, 2024
7b81f5c
[daemon] added run_at_boot commands unique identifiers update for clo…
georgeliao Feb 13, 2024
54bccb3
[daemon] moved cloned_instance_count from virtual machine class to vm…
georgeliao Feb 14, 2024
1f91f74
[daemon] fix a small error from the previous commit.
georgeliao Feb 14, 2024
47cd576
[daemon] refined the clone_spec_item function.
georgeliao Feb 15, 2024
68be40c
[daemon] use find_instance_and_react to make the error report of clon…
georgeliao Feb 20, 2024
50c7822
[daemon] correct the extra interfaces update in clone.
georgeliao Feb 21, 2024
85fe30a
[daemon] removed update_extra_interfaces_mac_address_of_run_at_boot s…
georgeliao Feb 22, 2024
9b2c3d0
[vm factory] added scope_guard clean up function for the create_vm_an…
georgeliao Feb 23, 2024
4019ea2
[cloud init] rebase fix.
georgeliao Mar 4, 2024
b069450
[json utils] fix formatting.
georgeliao Mar 5, 2024
eb0a6c9
fixed the post-merge compilation.
georgeliao Apr 9, 2024
54e5d0c
[bash completion] added clone bash completion
georgeliao Apr 10, 2024
48de54a
[unit test] added clone cli tests.
georgeliao Apr 12, 2024
c1f648b
[unit test][daemon] added the daemon clone unit test frame work.
georgeliao Apr 15, 2024
3e4092c
[unit test][daemon] added unusual unit test case.
georgeliao Apr 15, 2024
8cbe7b2
[unit test][daemon] added failsOnCloneOnNonStoppedInstance test.
georgeliao Apr 15, 2024
e4e69e4
rebase fix.
georgeliao Apr 29, 2024
85065c9
[yaml utils] made the make_cloud_init_meta_config to update instance_…
georgeliao Apr 30, 2024
7dbeaaa
[json utils] added updating cloud init instance id in snapshot file c…
georgeliao Apr 30, 2024
2815630
[unit test][json utils] added unit tests for update_cloud_init_instan…
georgeliao Apr 30, 2024
2093e42
[json utils] changed update_unique_identifiers_of_metadata parameter …
georgeliao Apr 30, 2024
ea81690
[clone] small comment correction.
georgeliao Apr 30, 2024
4e15104
[clone] small cleanup for some comments.
georgeliao May 1, 2024
13b9e34
[daemon] refined the the roll back mechanism in clone.
georgeliao May 3, 2024
97ba9b4
[unit test] added more unit tests for client failed command line args…
georgeliao May 3, 2024
2845d38
[unit test] added clone invalid option unit test.
georgeliao May 3, 2024
efd0cd3
[cmd] added AnimatedSpinner to clone command.
georgeliao May 3, 2024
3e6f277
[client][unit test] added command fail error to cover action_on_failu…
georgeliao May 4, 2024
c364287
[vm factory] use in class data member instances_dir to derive the sou…
georgeliao May 6, 2024
1bee362
[vm image] improve one function parameter name.
georgeliao May 6, 2024
2032a3d
[clone] function name improvement.
georgeliao May 8, 2024
90a59e6
[clone] added update_cloned_cloud_init utility function.
georgeliao May 8, 2024
d36c380
[cloud init] [unit test] added unit test for update_cloned_cloud_init…
georgeliao May 8, 2024
718973e
[vm factory] use update_cloned_cloud_init function to prepare for uni…
georgeliao May 8, 2024
9ccfc5e
[unit test] added FileOps::copy unit test.
georgeliao May 8, 2024
e3a36fd
[image vault] added unit test for DefaultVMImageVault::clone.
georgeliao May 8, 2024
5c339c3
[image vault] [unit test] added imageCloneFailOnNonExistSrcImage case.
georgeliao May 9, 2024
7477df7
[image vault] [unit test] added imageCloneFailOnAlreadyExistDestImage…
georgeliao May 9, 2024
9274626
[lxd image vault][unit test] added lxdImageVaultCloneThrow unit test.
georgeliao May 9, 2024
6389e79
[unit test] added coverage for DaemonRpc::clone.
georgeliao May 24, 2024
c0d18a1
[daemon] small refactor on generate_next_clone_name function.
georgeliao May 27, 2024
621f499
[cloud init] small function name improvement and typo correction.
georgeliao May 27, 2024
3f81305
[vm image] improves the image_path sub-string replacement, get it con…
georgeliao May 27, 2024
255d6ce
[qemu][vm factory] fixed rollback instance directory removal did not …
georgeliao May 30, 2024
57b8fc8
[clone] added metadata non-empty check for the non-qemu backend cases.
georgeliao May 30, 2024
f452dd7
[unit test] removed assertion line coverage unit test because windows…
georgeliao Jun 11, 2024
2752fa6
[qemu][vm factory] using the QemuVirtualMachine constructor directly …
georgeliao Jun 11, 2024
8b8222d
[qemu][vm factory] added copy_instance_dir_without_snapshot_files fun…
georgeliao Jun 13, 2024
1ed3178
[qemu] remove all load_snapshots_and_update_unique_identifiers relate…
georgeliao Jun 13, 2024
61d5648
[virtual machine] added the placeholder of the remove_all_snapshots_f…
georgeliao Jun 14, 2024
139d271
[qemu][virtual machine] added qemu remove_all_snapshots_from_the_imag…
georgeliao Jun 14, 2024
6955469
[vm] removed get_vm_name because it is not needed.
georgeliao Jul 10, 2024
fb09fec
[cli] improve the command description based on review comments.
georgeliao Jul 11, 2024
0ea8eb8
[daemon] use release_resources function to simplify the roll back mec…
georgeliao Jul 11, 2024
08d66b1
[daemon] moving is_name_already_used from local lambda to private fun…
georgeliao Jul 11, 2024
4469a9b
[daemon] moving generate_destination_name and clone_spec to private f…
georgeliao Jul 11, 2024
dab1ad6
[json utils] refined the update_cloud_init_instance_id function.
georgeliao Jul 11, 2024
a99038d
[lxd][vm image] Using NotImplementedOnThisBackendException to be more…
georgeliao Jul 11, 2024
7491d6b
[qemu factory] simplified the copy_instance_dir_without_snapshot_file…
georgeliao Jul 11, 2024
884832d
[daemon] using instance_trail to get the source_vm_ptr pointer to sav…
georgeliao Jul 11, 2024
532dc9e
[daemon] added cloneInvalidNameException and set the corresponding gr…
georgeliao Jul 12, 2024
3636b01
[daemon][cli] small wording improvement.
georgeliao Jul 12, 2024
82b138a
[daemon] added preparing_instances for clone operation, followed the …
georgeliao Jul 12, 2024
92109f0
[lxd] fixed one unit test.
georgeliao Jul 12, 2024
b2a9f0c
[daemon] polishing some daemon::clone code
georgeliao Jul 12, 2024
386ce53
[daemon] added invalidDestVmName test.
georgeliao Jul 12, 2024
fa3af0c
[unit test] change the instance_name for better clarity.
georgeliao Jul 12, 2024
d7b6dc3
[unit test][daemon] added alreadyExistDestVmName unit test.
georgeliao Jul 12, 2024
8613150
[unit test] added unit test for qemu removeAllSnapshotsFromTheImage.
georgeliao Jul 12, 2024
42acc3e
[qemu][unit test] added createVmAndCloneInstanceDirData test.
georgeliao Jul 12, 2024
c647843
[unit test][daemon] added the extra interface so the daemon::clone su…
georgeliao Jul 15, 2024
cfba218
[qemu][unit test] added mocked snapshot_list output stream to cover s…
georgeliao Jul 15, 2024
5d40b1c
Update src/daemon/daemon.cpp
georgeliao Jul 16, 2024
1b0c647
[daemon] small format correction.
georgeliao Jul 16, 2024
89591be
[daemon] small wording improvement.
georgeliao Jul 16, 2024
85dd29b
[daemon] fix the format.
georgeliao Jul 16, 2024
06308e4
[daemon][unit test] added successfulCloneSpecifyDestNameOkStatus unit…
georgeliao Jul 17, 2024
9aa8840
Update src/client/cli/cmd/clone.cpp
georgeliao Jul 17, 2024
767249e
renaming the function name from remove_all_snapshots_from_the_image t…
georgeliao Jul 17, 2024
142fbf3
[unit test][daemon] removed the unused data member.
georgeliao Jul 17, 2024
24ad520
[unit test][qemu] improved unit test createVmAndCloneInstanceDirData …
georgeliao Jul 17, 2024
f672a75
[daemon][unit test] small header cleanup.
georgeliao Jul 17, 2024
c3b3da4
Update src/platform/backends/lxd/lxd_vm_image_vault.h
georgeliao Jul 17, 2024
e585b54
[daemon][qemu unit test] small format improvement.
georgeliao Jul 17, 2024
fcc4904
[daemon] added preparing_instances removal to the rollback_clean_up_a…
georgeliao Jul 17, 2024
71daf4a
[unit test] fix the unit test.
georgeliao Jul 17, 2024
bf3ed13
[qemu][unit test] improved the removeAllSnapshotsFromTheImage unit test.
georgeliao Jul 17, 2024
b3c2044
Use char* variable for cloud-init-config.iso string literal
georgeliao Jul 17, 2024
5a46eca
[unit test] small tuning of the string construction.
georgeliao Jul 18, 2024
c30f674
Update src/daemon/daemon.cpp
georgeliao Jul 18, 2024
4af1dcf
[daemon] changing throwing to early return.
georgeliao Jul 18, 2024
a644d2d
[daemon] move the srt vm state before the rollback and generating des…
georgeliao Jul 18, 2024
35695ee
[daemon] converted from regular try-catch to function try-catch
georgeliao Jul 18, 2024
84c5b64
[yaml utils] small header format improvement.
georgeliao Jul 19, 2024
0247452
[yaml utils] make default interface node always present in the case o…
georgeliao Jul 29, 2024
9bed6a3
[yaml utils] refactored the create_default_interface_node code into a…
georgeliao Jul 29, 2024
a224c69
[yaml utils] added dhcp-identifier: mac to all network interfaces.
georgeliao Jul 29, 2024
30ea5b4
[cloud init] fixed the update_cloned_cloud_init_unique_identifiers di…
georgeliao Jul 29, 2024
92363db
[qemu img utils] move snapshot -l into a function
georgeliao Jul 29, 2024
df8cd7d
[qemu img utils] move snapshot -d code into a function.
georgeliao Jul 29, 2024
dfe6e98
[qemu img utils] removed repeated qemu img utils function.
georgeliao Jul 29, 2024
96a7664
[yaml utils] added comments for the new make_cloud_init_network_confi…
georgeliao Jul 30, 2024
6ec5836
[qemu][unit test] corrected and improved the unit test removeAllSnaps…
georgeliao Aug 9, 2024
75b21c9
[test cloud_init] change std::string_view to char* to adhere to the s…
georgeliao Aug 12, 2024
4332fa1
[virtual machine] improve the exception message.
georgeliao Aug 12, 2024
cb40bca
[vm factory] created the instance folder copy utility function and us…
georgeliao Sep 11, 2024
54fcf58
[cmd] improved the clone help text based the documentation review.
georgeliao Sep 18, 2024
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
8 changes: 7 additions & 1 deletion completions/bash/multipass
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ _multipass_complete()
prev_opts=false
multipass_cmds="authenticate transfer delete exec find help info launch list mount networks \
purge recover restart restore shell snapshot start stop suspend umount version get set \
alias aliases unalias"
clone alias aliases unalias"

if [[ "${multipass_cmds}" =~ " ${cmd} " || "${multipass_cmds}" =~ ^${cmd} || "${multipass_cmds}" =~ \ ${cmd}$ ]];
then
Expand Down Expand Up @@ -283,6 +283,9 @@ _multipass_complete()
"restore")
_add_nonrepeating_args "--destructive"
;;
"clone")
_add_nonrepeating_args "--name"
;;
"get")
_add_nonrepeating_args "--raw --keys"
;;
Expand Down Expand Up @@ -369,6 +372,9 @@ _multipass_complete()
"snapshot")
_multipass_instances "Stopped"
;;
"clone")
_multipass_instances "Stopped"
;;
"restore")
_multipass_restorable_snapshots
;;
Expand Down
5 changes: 5 additions & 0 deletions include/multipass/cloud_init_iso.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ class CloudInitFileOps : public Singleton<CloudInitFileOps>
const std::vector<NetworkInterface>& extra_interfaces,
const std::string& new_instance_id,
const std::filesystem::path& cloud_init_path) const;

virtual void update_cloned_cloud_init_unique_identifiers(const std::string& default_mac_addr,
const std::vector<NetworkInterface>& extra_interfaces,
const std::string& new_hostname,
const std::filesystem::path& cloud_init_path) const;
virtual void add_extra_interface_to_cloud_init(const std::string& default_mac_addr,
const NetworkInterface& extra_interfaces,
const std::filesystem::path& cloud_init_path) const;
Expand Down
2 changes: 2 additions & 0 deletions include/multipass/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ constexpr auto mounts_key = "local.privileged-mounts"; // idem
constexpr auto winterm_key = "client.apps.windows-terminal.profiles"; // idem
constexpr auto mirror_key = "local.image.mirror"; // idem; this defines the mirror of simple streams

constexpr auto cloud_init_file_name = "cloud-init-config.iso";

[[maybe_unused]] // hands off clang-format
constexpr auto key_examples = {petenv_key, driver_key, mounts_key};

Expand Down
32 changes: 32 additions & 0 deletions include/multipass/exceptions/clone_exceptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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_CLONE_EXCEPTIONS_H
#define MULTIPASS_CLONE_EXCEPTIONS_H

#include <stdexcept>

namespace multipass
{
class CloneInvalidNameException : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't you create a string template that takes the vm name and clone name and formats them into an appropriate error string. Otherwise, there's no real point in having this class other than the class name...

Copy link
Contributor Author

@georgeliao georgeliao Jul 16, 2024

Choose a reason for hiding this comment

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

If we look at the function body of generate_destination_instance_name_for_clone, there are three error messages of invalid name and they all have different formats. First, I think it is informative to users to have these specific error messages. With this in place, it is hard to patternize the error message into an exception.

The only role of this exception is to let the daemon::clone catch so he can set grpc::StatusCode::INVALID_ARGUMENT uniformly for these three cases. If we do not use an exception here then generate_destination_instance_name_for_clone needs to return the error string, which will make the function signature more cumbersome.

std::expected from C++23 which is similar to Rust std::result will be a better choice here than an exception. With that, we can do an early return in the if(status.ok()) block of daemon::clone like return status_promise->set_value(grpc::Status{grpc::INVALID_ARGUMENT, <error msg>});, as a result, the branch catch (const mp::CloneInvalidNameException& e) can be removed. But std::expected is not available yet in Multipass code base.

Be free to share any other possible code design you might have.

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 think it is necessary to have generate_destination_instance_name_for_clone code as a function in terms of modulization, expressiveness and not cluttering the daemon::clone further.

With that said, throwing an exception is one way and returning the error message from the function is another way to propagate the error message. Returning the error message requires changing the return type from std::string to either a struct or std::pair.

The way I see it, the only purpose of this class is as a fancy JUMP statement. Otherwise, it provides no value...

That is right.

@ricab in case you have any better idea.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Otherwise, there's no real point in having this class other than the class name...

The exception name is crucial. It is what allows you to catch and handle specific errors in a different way. The idea of a separate function throwing a specific exception sounds right to me. However...

Why don't you create a string template that takes the vm name and clone name and formats them into an appropriate error string.

I wonder if a common error prefix would be more informative. Something like "Could not clone: {}"? I don't know, this also depends on how things are printed on the client side. I guess we should look into what we do in other cases (i.e. failure to start, to stop, to snapshot, etc.) and try to stick with that.

};
} // namespace multipass

#endif // MULTIPASS_CLONE_EXCEPTIONS_H
1 change: 1 addition & 0 deletions include/multipass/file_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class FileOps : public Singleton<FileOps>
std::ios_base::openmode mode = std::ios_base::out) const;
virtual std::unique_ptr<std::istream> open_read(const fs::path& path,
std::ios_base::openmode mode = std::ios_base::in) const;
virtual void copy(const fs::path& src, const fs::path& dist, fs::copy_options copy_options) const;
virtual bool exists(const fs::path& path, std::error_code& err) const;
virtual bool is_directory(const fs::path& path, std::error_code& err) const;
virtual bool create_directory(const fs::path& path, std::error_code& err) const;
Expand Down
9 changes: 9 additions & 0 deletions include/multipass/json_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,22 @@

namespace multipass
{
struct VMSpecs;
class JsonUtils : public Singleton<JsonUtils>
{
public:
explicit JsonUtils(const Singleton<JsonUtils>::PrivatePass&) noexcept;

virtual void write_json(const QJsonObject& root, QString file_name) const; // transactional; creates parent dirs
virtual std::string json_to_string(const QJsonObject& root) const;
virtual QJsonValue update_cloud_init_instance_id(const QJsonValue& cloud_init_instance_id_value,
const std::string& src_vm_name,
const std::string& dest_vm_name) const;
virtual QJsonValue update_unique_identifiers_of_metadata(const QJsonValue& metadata_value,
const multipass::VMSpecs& src_specs,
const multipass::VMSpecs& dest_specs,
const std::string& src_vm_name,
const std::string& dest_vm_name) const;
virtual QJsonArray extra_interfaces_to_json_array(const std::vector<NetworkInterface>& extra_interfaces) const;
virtual std::optional<std::vector<NetworkInterface>> read_extra_interfaces(const QJsonObject& record) const;
};
Expand Down
1 change: 1 addition & 0 deletions include/multipass/virtual_machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class VirtualMachine : private DisabledCopyMove
virtual void load_snapshots() = 0;
virtual std::vector<std::string> get_childrens_names(const Snapshot* parent) const = 0;
virtual int get_snapshot_count() const = 0;
virtual void remove_snapshots_from_image() const = 0;

QDir instance_directory() const;

Expand Down
8 changes: 8 additions & 0 deletions include/multipass/virtual_machine_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ class VirtualMachineFactory : private DisabledCopyMove
virtual VirtualMachine::UPtr create_virtual_machine(const VirtualMachineDescription& desc,
const SSHKeyProvider& key_provider,
VMStatusMonitor& monitor) = 0;
virtual VirtualMachine::UPtr create_vm_and_clone_instance_dir_data(const VMSpecs& src_vm_spec,
sharder996 marked this conversation as resolved.
Show resolved Hide resolved
const VMSpecs& dest_vm_spec,
const std::string& source_name,
const std::string& destination_name,
const VMImage& dest_vm_image,
const SSHKeyProvider& key_provider,
VMStatusMonitor& monitor) = 0;

/** Removes any resources associated with a VM of the given name.
*
Expand All @@ -73,6 +80,7 @@ class VirtualMachineFactory : private DisabledCopyMove
virtual std::vector<NetworkInterfaceInfo> networks() const = 0;
virtual void require_snapshots_support() const = 0;
virtual void require_suspend_support() const = 0;
virtual void require_clone_support() const = 0;

protected:
VirtualMachineFactory() = default;
Expand Down
1 change: 1 addition & 0 deletions include/multipass/vm_image_vault.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class VMImageVault : private DisabledCopyMove
virtual void update_images(const FetchType& fetch_type, const PrepareAction& prepare,
const ProgressMonitor& monitor) = 0;
virtual MemorySize minimum_image_size_for(const std::string& id) = 0;
virtual void clone(const std::string& source_instance_name, const std::string& destination_instance_name) = 0;
virtual VMImageHost* image_host_for(const std::string& remote_name) const = 0;
virtual std::vector<std::pair<std::string, VMImageInfo>> all_info_for(const Query& query) const = 0;

Expand Down
23 changes: 13 additions & 10 deletions include/multipass/vm_specs.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct VMSpecs
std::unordered_map<std::string, VMMount> mounts;
bool deleted;
QJsonObject metadata;
int clone_count = 0; // tracks the number of cloned vm from this source vm (regardless of deletes)
};

inline bool operator==(const VMSpecs& a, const VMSpecs& b)
Expand All @@ -57,16 +58,18 @@ inline bool operator==(const VMSpecs& a, const VMSpecs& b)
a.state,
a.mounts,
a.deleted,
a.metadata) == std::tie(b.num_cores,
b.mem_size,
b.disk_space,
b.default_mac_address,
b.extra_interfaces,
b.ssh_username,
b.state,
b.mounts,
b.deleted,
b.metadata);
a.metadata,
a.clone_count) == std::tie(b.num_cores,
b.mem_size,
b.disk_space,
b.default_mac_address,
b.extra_interfaces,
b.ssh_username,
b.state,
b.mounts,
b.deleted,
b.metadata,
a.clone_count);
}

inline bool operator!=(const VMSpecs& a, const VMSpecs& b) // TODO drop in C++20
Expand Down
4 changes: 4 additions & 0 deletions include/multipass/yaml_node_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ YAML::Node make_cloud_init_network_config(const std::string& default_mac_addr,
YAML::Node add_extra_interface_to_network_config(const std::string& default_mac_addr,
const NetworkInterface& extra_interface,
const std::string& network_config_file_content);
// the make_cloud_init_network_config and add_extra_interface_to_network_config functions are adapted to generate the
// new format network-config file (having default interface present and having dhcp-identifier: mac on every network
// interface). At the same time, it also needs to take care of the pre-existed file, meaning that the generated file
// from the old file should have the new format.
} // namespace utils
} // namespace multipass
#endif // MULTIPASS_YAML_NODE_UTILS_H
2 changes: 2 additions & 0 deletions src/client/cli/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "cmd/alias.h"
#include "cmd/aliases.h"
#include "cmd/authenticate.h"
#include "cmd/clone.h"
#include "cmd/delete.h"
#include "cmd/exec.h"
#include "cmd/find.h"
Expand Down Expand Up @@ -108,6 +109,7 @@ mp::Client::Client(ClientConfig& config)
add_command<cmd::Delete>(aliases);
add_command<cmd::Umount>();
add_command<cmd::Version>();
add_command<cmd::Clone>();

sort_commands();

Expand Down
1 change: 1 addition & 0 deletions src/client/cli/cmd/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_library(commands STATIC
aliases.cpp
animated_spinner.cpp
authenticate.cpp
clone.cpp
common_cli.cpp
create_alias.cpp
delete.cpp
Expand Down
109 changes: 109 additions & 0 deletions src/client/cli/cmd/clone.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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/>.
*
*/

#include "clone.h"

#include "animated_spinner.h"
#include "common_cli.h"

#include <multipass/cli/argparser.h>

namespace mp = multipass;
namespace cmd = multipass::cmd;

mp::ReturnCode cmd::Clone::run(ArgParser* parser)
{
const auto parscode = parse_args(parser);
if (parscode != ParseCode::Ok)
{
return parser->returnCodeFrom(parscode);
}

AnimatedSpinner spinner{cout};
auto action_on_success = [this, &spinner](CloneReply& reply) -> ReturnCode {
spinner.stop();
cout << reply.reply_message();

return ReturnCode::Ok;
};

auto action_on_failure = [this, &spinner](grpc::Status& status, CloneReply& reply) -> ReturnCode {
spinner.stop();
return standard_failure_handler_for(name(), cerr, status, reply.reply_message());
};

spinner.start("Cloning " + rpc_request.source_name());
return dispatch(&RpcMethod::clone, rpc_request, action_on_success, action_on_failure);
}

std::string cmd::Clone::name() const
{
return "clone";
}

QString cmd::Clone::short_help() const
{
return QStringLiteral("Clone an instance");
}

QString cmd::Clone::description() const
{
return QStringLiteral(
"Create an independent copy of an existing instance. The instance must be stopped before you proceed.");
}

mp::ParseCode cmd::Clone::parse_args(ArgParser* parser)
{
parser->addPositionalArgument("source_name", "The name of the source instance to be cloned", "<source_name>");

const QCommandLineOption destination_name_option{
{"n", "name"},
"Specify a custom name for the cloned instance. The name must follow the same validity rules as instance names "
"(see \"help launch\"). Default: \"<source_name>-cloneN\", where N is the Nth cloned instance.",
"destination-name"};

parser->addOption(destination_name_option);

const auto status = parser->commandParse(this);
if (status != ParseCode::Ok)
{
return status;
}

const auto number_of_positional_arguments = parser->positionalArguments().count();
if (number_of_positional_arguments < 1)
{
cerr << "Please provide the name of the source instance.\n";
return ParseCode::CommandLineError;
}

if (number_of_positional_arguments > 1)
{
cerr << "Too many arguments.\n";
return ParseCode::CommandLineError;
}

const auto source_name = parser->positionalArguments()[0];
rpc_request.set_source_name(source_name.toStdString());
rpc_request.set_verbosity_level(parser->verbosityLevel());
if (parser->isSet(destination_name_option))
{
rpc_request.set_destination_name(parser->value(destination_name_option).toStdString());
}

return ParseCode::Ok;
}
44 changes: 44 additions & 0 deletions src/client/cli/cmd/clone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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_CLONE_H
#define MULTIPASS_CLONE_H

#include <multipass/cli/command.h>

namespace multipass
{
namespace cmd
{
class Clone final : public Command
{
public:
using Command::Command;
ReturnCode run(ArgParser* parser) override;

std::string name() const override;
QString short_help() const override;
QString description() const override;

private:
ParseCode parse_args(ArgParser* parser);

CloneRequest rpc_request;
};
} // namespace cmd
} // namespace multipass
#endif // MULTIPASS_CLONE_H
Loading
Loading