mirror of
https://github.com/gryf/boxpy.git
synced 2025-12-19 05:30:18 +01:00
Changing approach with detecting if cloud init finished.
Till now, boxpy was based on the fact, that there was power_state section, and there was a check if VM is down already. That approach have their own issues. Now, there will be no more power-off, there is a check by using `cloud-init status` command through ssh. Cleanup/destroy parts has needed some modification, so that there will be no leftovers from cloud init ISO image. And finally, there was some tweaks for user-data cloud-init part (mainly for ssh handling), so that `cloud-init status` will not report phony errors.
This commit is contained in:
25
README.rst
25
README.rst
@@ -116,15 +116,10 @@ Default user-script looks as follows:
|
||||
gecos: ubuntu
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
groups: users, admin
|
||||
power_state:
|
||||
mode: poweroff
|
||||
timeout: 10
|
||||
condition: True
|
||||
|
||||
It is really simple, and use ``string.Template`` for exchanging token
|
||||
``$ssh_key`` with default, or provided public key, so that you will be able to
|
||||
log in into the VM using that key. Section ``power_state`` is used internally
|
||||
for making sure the cloud-init finish up and the VM will be started again.
|
||||
log in into the VM using that key.
|
||||
|
||||
Note, that you need to be extra careful regarding ``$`` sign. As explained
|
||||
above ``$ssh_key`` will be used as a "variable" for the template to substitute
|
||||
@@ -145,10 +140,10 @@ pass filenames to the custom config, instead of filling up
|
||||
filename: /path/to/local/file.txt
|
||||
|
||||
during processing this file, boxpy will look for ``filename`` key in the yaml
|
||||
file for the ``write_files`` sections, and it will remove that key read the
|
||||
file for the ``write_files`` sections, and it will remove that key, read the
|
||||
file and put its contents under ``content`` key. What is more important, that
|
||||
will be done after template processing, so that there will be no interference
|
||||
for possible ``$`` characters.
|
||||
will be done after template processing, so there will be no interference for
|
||||
possible ``$`` characters.
|
||||
|
||||
What is more interesting is the fact, that you could use whatever cloud-init
|
||||
accepts, and a special section, for keeping configuration, so that you don't
|
||||
@@ -185,6 +180,18 @@ initialized, just to make you an idea, what could be done with it.
|
||||
You can find some real world examples of the yaml cloud-init files that I use
|
||||
in examples directory.
|
||||
|
||||
There is special section ``boxpy_data``, where you can place all the
|
||||
configuration for the VM. Keys are the same as in ``create`` command options.
|
||||
There is one additional key ``advanced`` which for now can be used for
|
||||
configuration additional NIC for virtual machine, i.e:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
…
|
||||
boxpy_data:
|
||||
advanced:
|
||||
nic2: intnet
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
56
box.py
56
box.py
@@ -34,10 +34,9 @@ users:
|
||||
gecos: ${realname}
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
groups: users, admin
|
||||
power_state:
|
||||
mode: poweroff
|
||||
timeout: 10
|
||||
condition: True
|
||||
no_ssh_fingerprints: true
|
||||
ssh:
|
||||
emit_keys_to_console: false
|
||||
boxpy_data:
|
||||
cpus: 1
|
||||
disk_size: 10240
|
||||
@@ -579,12 +578,22 @@ class VBoxManage:
|
||||
return Run(['vboxmanage', 'list', 'runningvms']).stdout
|
||||
|
||||
def destroy(self):
|
||||
self.get_vm_info()
|
||||
if not self.vm_info:
|
||||
LOG.fatal("Cannot remove VM \"%s\" - it doesn't exist.",
|
||||
self.name_or_uuid)
|
||||
return 4
|
||||
|
||||
LOG.info('Removing VM %s.', self.name_or_uuid)
|
||||
self.poweroff(silent=True)
|
||||
time.sleep(1) # wait a bit, for VM shutdown to complete
|
||||
# detach cloud image.
|
||||
self.storageattach('IDE', 1, 'dvddrive', 'none')
|
||||
self.closemedium('dvd', self.vm_info['iso_path'])
|
||||
if Run(['vboxmanage', 'unregistervm', self.name_or_uuid,
|
||||
'--delete']).returncode != 0:
|
||||
LOG.fatal('Removing VM "%s" failed', self.name_or_uuid)
|
||||
raise BoxVBoxFailure()
|
||||
return 7
|
||||
|
||||
def create(self, cpus, memory, port=None):
|
||||
LOG.info('Creating VM %s.', self.name_or_uuid)
|
||||
@@ -972,6 +981,7 @@ def vmcreate(args, conf=None):
|
||||
|
||||
iso = IsoImage(conf)
|
||||
path_to_iso = iso.get_generated_image()
|
||||
vbox.setextradata('iso_path', path_to_iso)
|
||||
vbox.storageattach('SATA', 0, 'hdd', path_to_disk)
|
||||
vbox.storageattach('IDE', 1, 'dvddrive', path_to_iso)
|
||||
|
||||
@@ -986,34 +996,42 @@ def vmcreate(args, conf=None):
|
||||
# give VBox some time to actually change the state of the VM before query
|
||||
time.sleep(3)
|
||||
|
||||
def _cleanup(vbox, iso, image, path_to_iso):
|
||||
time.sleep(1) # wait a bit, for VM shutdown to complete
|
||||
vbox.storageattach('IDE', 1, 'dvddrive', 'none')
|
||||
vbox.closemedium('dvd', path_to_iso)
|
||||
iso.cleanup()
|
||||
image.cleanup()
|
||||
|
||||
# than, let's try to see if boostraping process has finished
|
||||
LOG.info('Waiting for cloud init to finish ', end='')
|
||||
cmd = ['ssh', '-o', 'StrictHostKeyChecking=no',
|
||||
'-o', 'UserKnownHostsFile=/dev/null',
|
||||
'-o', 'ConnectTimeout=2',
|
||||
'-i', conf.ssh_key_path[:-4],
|
||||
f'ssh://{DISTROS[conf.distro]["username"]}'
|
||||
f'@localhost:{vbox.vm_info["port"]}', 'cloud-init status']
|
||||
try:
|
||||
while True:
|
||||
if vbox.vm_info['uuid'] in vbox.get_running_vms():
|
||||
out = Run(cmd).stdout
|
||||
LOG.debug2('Out: %s', out)
|
||||
|
||||
if (not out) or ('status' in out and 'running' in out):
|
||||
LOG.info('.', end='')
|
||||
sys.stdout.flush()
|
||||
time.sleep(3)
|
||||
else:
|
||||
continue
|
||||
|
||||
LOG.info(' done.')
|
||||
break
|
||||
out = out.split(':')[1].strip()
|
||||
if out != 'done':
|
||||
LOG.warning('Cloud init finished with "%s" status. You can log '
|
||||
'in and investigate.', out)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
LOG.warning('\nIterrupted, cleaning up.')
|
||||
vbox.poweroff(silent=True)
|
||||
_cleanup(vbox, iso, image, path_to_iso)
|
||||
iso.cleanup()
|
||||
image.cleanup()
|
||||
vbox.destroy()
|
||||
return 1
|
||||
|
||||
# dettach ISO image
|
||||
_cleanup(vbox, iso, image, path_to_iso)
|
||||
vbox.poweron()
|
||||
# cleanup
|
||||
iso.cleanup()
|
||||
image.cleanup()
|
||||
|
||||
# reread config to update fields
|
||||
conf = Config(args, vbox)
|
||||
|
||||
Reference in New Issue
Block a user