-
Notifications
You must be signed in to change notification settings - Fork 625
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
base: main
Are you sure you want to change the base?
Multipass clone #3264
Conversation
d8739fd
to
c9f71b0
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3264 +/- ##
==========================================
- Coverage 88.82% 88.48% -0.34%
==========================================
Files 253 255 +2
Lines 14121 14365 +244
==========================================
+ Hits 12543 12711 +168
- Misses 1578 1654 +76 ☔ View full report in Codecov by Sentry. |
0e5a833
to
5e2a139
Compare
77e02fb
to
69d81b9
Compare
5b2c7f7
to
2bb5b3a
Compare
eddafcc
to
fb663a5
Compare
794467a
to
dac94dd
Compare
563f9f3
to
f448929
Compare
c28404e
to
a662819
Compare
f96a5cf
to
a662819
Compare
6b0b4c7
to
963f599
Compare
560583e
to
8c70116
Compare
92819f9
to
f328b81
Compare
…re branch of cmd dispatch.
…rce and destination instance folders.
…sistent with the metadata sub-string replacement in JsonUtils::update_unique_identifiers_of_metadata.
… ci use relwithdebinfo mode and that does hit the assertion.
…instead of the QemuVirtualMachineFactory::create_virtual_machine public function.
…ction and replace copying the whole directory call with that.
5067f65
to
0f619d0
Compare
…rom_the_image function.
…e implementation and call it in the factory class.
40ab758
to
db63cc7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @georgeliao, thanks for all the work you've done with clone! Took a little while to go over everything, but I think I'm finally ready to submit my initial review.
Functionally it looks great! Just some comments/questions from my code review.
|
||
QString cmd::Clone::short_help() const | ||
{ | ||
return QStringLiteral("Clone an Ubuntu instance"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we typical refer to them simply as an instance. See snapshot.cpp
|
||
QString cmd::Clone::description() const | ||
{ | ||
return QStringLiteral("A clone is a complete independent copy of a whole virtual machine instance"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should describe an action since it is a description of multipass clone
; an action. Right now, it describes an object. How about something like:
Create a complete independent copy of an existing instance
WDYT
{ | ||
if (!mp::utils::valid_hostname(request.destination_name())) | ||
{ | ||
throw std::runtime_error("Invalid destination virtual machine instance name: " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a small nitpick, but I feel like you're repeating yourself by saying "virtual machine instance" since we use "virtual machine" and "instance" interchangeably. There is already a precedent for referring to them as "instances" so that is what I would expect.
config->vault->remove(destination_name); | ||
}); | ||
|
||
const auto& source_vm_ptr = operative_instances[source_name]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should already have a pointer to the vm from calling find_instance_and_react
earlier in the function.
throw std::runtime_error("Please stop instance " + source_name + " before you clone it."); | ||
} | ||
|
||
auto clone_spec = [this](const mp::VMSpecs& src_vm_spec, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the point in having all these lambdas functions in clone()
. It makes it harder to follow the execution sequence since there code in between different lambda functions. Each of the lambdas here are only called once, so I would say either just inline the code, or if you need to separate it for readability, put it in a helper function.
|
||
const fs::path filename = entry.path().filename(); | ||
// if the filename does not contains "snapshot" sub-string, then copy | ||
if (filename.string().find("snapshot") == std::string::npos) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really an important issue right now, but maybe it would be better if we explicitly define which files to copy so that this doesn't need to change if/when more files are created and associated with a vm. I guess we are only filtering because of the exception with cloning snapshots, so maybe it's not a big issue. 🤷
@@ -727,6 +727,29 @@ void mp::CloudInitFileOps::update_cloud_init_with_new_extra_interfaces_and_new_i | |||
iso_file.write_to(QString::fromStdString(cloud_init_path.string())); | |||
} | |||
|
|||
void mp::CloudInitFileOps::update_cloned_cloud_init_unique_identifiers( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for my own understanding; this is basically doing the same thing as in mp::JsonUtils::update_unique_identifiers_of_metadata()
, just a different format, right? Cloud-init iso instead of json. Seems like a bit of code smell that we have two functions that functionally do the same thing, but I guess it can't be avoided...
@@ -22,6 +22,7 @@ | |||
#include <multipass/file_ops.h> | |||
#include <multipass/format.h> | |||
#include <multipass/logging/log.h> | |||
#include <multipass/network_interface.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover development code?
|
||
QDir instance_directory() const; | ||
std::string get_vm_name() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vm_name
is a public member so you shouldn't need this accessor method, right?
namespace mpt = multipass::test; | ||
using namespace testing; | ||
|
||
struct TestDaemonClone : public mpt::DaemonTestFixture |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still some uncovered lines in daemon::clone()
that would be nice if they were covered.
Please read the spec first to get a sense of the context.
The code can be divided into several parts:
daemon::clone
method indaemon.cpp
,2.1. generate destination name, this step processes the name options of the input, use the given name or generate a new one if no name is provided. This step also needs the name list of instances to check if the name exist, it also requires the source spec
VMSpecs::clone_count
field to generate a new name.2.2. Once the new destination name is produced, we can clone the vmspec object, this step requires copying the vmspec instance and updating the
VMSpecs::default_mac_address
andVMSpecs::extra_interfaces
fields. Ideally, this method can be a data member method (calledclone
maybe) inVMSpecs
class. However, given the fact that the dependency code (generate_unused_mac_address
method andallocated_mac_addrs
data) still resides indaemon.cpp
, soclone_spec
is a local lambda method indaemon.cpp
for now.2.3. clone image record through the
VMImageVault::clone
method.2.4. calls
create_vm_and_clone_instance_dir_data
fromVirtualMachineFactory
.remove_all_snapshots_from_the_image
function is added toVirtualMachine
class, it gets called in the factory class and it removes the snapshots from the image file.qemu_virtual_machine_factory::create_vm_and_clone_instance_dir_data
, it copies the whole instance folder with the exclusion of snapshot files and updates the unique identifiers incloud-init-config.iso
file. Besides that, it creates the newVirtualMachine
instance and also removes the snapshots from the image file.multipass clone
command line.Functional testing should cover at least the following scenarios:
Small note:
The unit tests are not finished yet considering that they might change if the code structure is required to change according to the review. More unit tests will be added once the review is finished.
Some further thoughts on the code architecture (open for discussion):
VMSpecs::clone_count
to count cloned instances and theBaseVirtualMachine::snapshot_count
to count snapshots is cumbersome. We need a variable and a file or json item to track the value. Besides that, the current name-generation scheme also does not persist on trying. What I mean by that is if the next about-to-be-generated name already exists (if the user already created the snapshot/cloned instance by specifying that name), then the auto name-generation will fail. To fix these things, we can try a different name-generation scheme, that is always looping over the existing instances/snapshots to seek the next available name, this scheme will have to do a linear search but it no longer depends on the counter variable/file and will persist on name generation. The corresponding name-generation behavior will change when there is a gap in the integer sequence (when user deletes the snapshots/instances in between) , the new scheme will reuse that deleted name and the counter based scheme will not. I think this approach is better overall, but it requires some changes in already released behavior.multipassd-vm-instances.json
file, themetadata::arguments
contains the image and clou-init file absolute path, themultipassd-instance-image-records.json
file also has the path item points to the image file path. These paths in a way added more unnecessary instance name occurrences (the instance folder name in the path) which need to be updated during the clone and renaming process. Then maybe a better disk data layout and C++ code structure can remove these paths. For example, if we split these json files into one item per file and move that into the instance directory, and meanwhile we can moveVMSpecs
intoVirtualMachine
class. With this new data layout and code structure, theVMSpecs
can access the instance directory and further access the multipassd-vm-instances.json file (with his own item), besides that, the data sync between theVMSpecs
andVirtualMachine
class becomes much easier. On top of these, there are more benefits like the rollback mechanism and thread-safety can be much easier.Mac_address_generator
class that can be accessed from everywhere and refactor the corresponding code. If this can be done, then theclone_spec
does not have to be a local lambda indaemon.cpp
.