-
Notifications
You must be signed in to change notification settings - Fork 39
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
Generate an init file that can be used with exported images #477
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ | |
create an alternative implementation of the provisioning details for the VM, | ||
for example, using a remote libvirt instance or similar. | ||
""" | ||
from copy import deepcopy | ||
import contextlib | ||
import functools | ||
import logging | ||
|
@@ -364,6 +365,10 @@ def metadata(self): | |
def disks(self): | ||
return self._spec['disks'][:] | ||
|
||
@property | ||
def spec(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes the new spec somewhat "read only", no? was that the intention? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
return deepcopy(self._spec) | ||
|
||
def name(self): | ||
return str(self._spec['name']) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -961,7 +961,8 @@ def _create_disks( | |
'dev': disk['dev'], | ||
'format': disk['format'], | ||
'metadata': metadata, | ||
'type': disk['type'] | ||
'type': disk['type'], | ||
'name': disk['name'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
}, | ||
) | ||
|
||
|
@@ -1009,9 +1010,14 @@ def virt_conf( | |
self.save() | ||
rollback.clear() | ||
|
||
def export_vms(self, vms_names, standalone, export_dir, compress): | ||
|
||
self.virt_env.export_vms(vms_names, standalone, export_dir, compress) | ||
def export_vms( | ||
self, vms_names, standalone, export_dir, compress, init_file_name, | ||
out_format | ||
): | ||
self.virt_env.export_vms( | ||
vms_names, standalone, export_dir, compress, init_file_name, | ||
out_format | ||
) | ||
|
||
def start(self, vm_names=None): | ||
""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
# | ||
# Refer to the README and COPYING files for full details of the license | ||
# | ||
from copy import deepcopy | ||
import functools | ||
import hashlib | ||
import json | ||
|
@@ -25,6 +26,7 @@ | |
import uuid | ||
import time | ||
import lxml.etree | ||
import yaml | ||
|
||
from . import ( | ||
brctl, | ||
|
@@ -191,7 +193,10 @@ def virt_path(self, *args): | |
def bootstrap(self): | ||
utils.invoke_in_parallel(lambda vm: vm.bootstrap(), self._vms.values()) | ||
|
||
def export_vms(self, vms_names, standalone, dst_dir, compress): | ||
def export_vms( | ||
self, vms_names, standalone, dst_dir, compress, init_file_name, | ||
out_format | ||
): | ||
if not vms_names: | ||
vms_names = self._vms.keys() | ||
|
||
|
@@ -219,6 +224,88 @@ def export_vms(self, vms_names, standalone, dst_dir, compress): | |
for _vm in vms: | ||
_vm.export_disks(standalone, dst_dir, compress) | ||
|
||
self.generate_init(os.path.join(dst_dir, init_file_name), out_format) | ||
|
||
def generate_init(self, dst, out_format, filters=None): | ||
""" | ||
Generate an init file which represents this env and can | ||
be used with the images created by self.export_vms | ||
|
||
Args: | ||
dst (str): path and name of the new init file | ||
out_format (plugins.output.OutFormatPlugin): | ||
formatter for the output (the default is yaml) | ||
filters (list): list of paths to keys that should be removed from | ||
the init file | ||
Returns: | ||
None | ||
""" | ||
with LogTask('Exporting init file to: {}'.format(dst)): | ||
# Set the default formatter to yaml. The default formatter | ||
# doesn't generate a valid init file, so it's not reasonable | ||
# to use it | ||
if isinstance(out_format, plugins.output.DefaultOutFormatPlugin): | ||
out_format = plugins.output.YAMLOutFormatPlugin() | ||
|
||
if not filters: | ||
filters = [ | ||
'domains/*/disks/*/metadata', | ||
'domains/*/metadata/deploy-scripts', 'domains/*/snapshots', | ||
'domains/*/name', 'nets/*/mapping' | ||
] | ||
spec = self.get_env_spec(filters) | ||
|
||
for _, domain in spec['domains'].viewitems(): | ||
for disk in domain['disks']: | ||
if disk['type'] == 'template': | ||
disk['template_type'] = 'qcow2' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if this is the right place for this logic. Should probably be a different method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is for generating an init file that can be used with the exported images 'out of the box'. |
||
elif disk['type'] == 'empty': | ||
disk['type'] = 'file' | ||
disk['make_a_copy'] = 'True' | ||
|
||
# Insert the relative path to the exported images | ||
disk['path'] = os.path.join( | ||
'$LAGO_INITFILE_PATH', os.path.basename(disk['path']) | ||
) | ||
|
||
with open(dst, 'wt') as f: | ||
if isinstance(out_format, plugins.output.YAMLOutFormatPlugin): | ||
# Dump the yaml file without type tags | ||
# TODO: Allow passing parameters to output plugins | ||
f.write(yaml.safe_dump(spec)) | ||
else: | ||
f.write(out_format.format(spec)) | ||
|
||
def get_env_spec(self, filters=None): | ||
""" | ||
Get the spec of the current env. | ||
The spec will hold the info about all the domains and | ||
networks associated with this env. | ||
|
||
Args: | ||
filters (list): list of paths to keys that should be removed from | ||
the init file | ||
Returns: | ||
dict: the spec of the current env | ||
""" | ||
spec = { | ||
'domains': | ||
{ | ||
vm_name: vm_object.spec | ||
for vm_name, vm_object in self._vms.viewitems() | ||
}, | ||
'nets': | ||
{ | ||
net_name: net_object.spec | ||
for net_name, net_object in self._nets.viewitems() | ||
} | ||
} | ||
|
||
if filters: | ||
utils.filter_spec(spec, filters) | ||
|
||
return spec | ||
|
||
def start(self, vm_names=None): | ||
if not vm_names: | ||
log_msg = 'Start Prefix' | ||
|
@@ -459,6 +546,10 @@ def save(self): | |
with open(self._env.virt_path('net-%s' % self.name()), 'w') as f: | ||
utils.json_dump(self._spec, f) | ||
|
||
@property | ||
def spec(self): | ||
return deepcopy(self._spec) | ||
|
||
|
||
class NATNetwork(Network): | ||
def _libvirt_xml(self): | ||
|
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.
We have our "specific" implementation of deepcopy in 'utils.py', I guess here its safe? (it was added to avoid the cross-references issue iirc)
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.
What do you mean by "cross-references" ?
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.
See the discussion here: #346 (review)
Not 100% if its relevant, just checking.