Skip to content

Commit

Permalink
Merge pull request #6 from sandwichcloud/betterimaging
Browse files Browse the repository at this point in the history
clone vms instead of just marking as a template
  • Loading branch information
rmb938 authored Dec 8, 2017
2 parents 8d95381 + 60a9bb0 commit 2a383fc
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
5 changes: 4 additions & 1 deletion ingredients_tasks/tasks/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from celery.utils.log import get_task_logger

from ingredients_db.models.images import ImageState
from ingredients_db.models.instance import Instance, InstanceState
from ingredients_db.models.region import Region
from ingredients_tasks.tasks.tasks import ImageTask
from ingredients_tasks.vmware import VMWareClient
Expand Down Expand Up @@ -48,6 +49,7 @@ def delete_image(self, **kwargs):
@celery.shared_task(base=ImageTask, bind=True, max_retires=2, default_retry_delay=5)
def convert_vm(self, **kwargs):
image = self.request.image
instance = self.request.session.query(Instance).filter(Instance.id == kwargs['instance_id']).one()
region: Region = self.request.session.query(Region).filter(Region.id == image.region_id).one()
with VMWareClient.client_session() as vmware:
datacenter = vmware.get_datacenter(region.datacenter)
Expand All @@ -69,6 +71,7 @@ def convert_vm(self, **kwargs):
if folder is None:
raise LookupError("Could not find VMWare VM & Templates folder for region %s" % str(region.id))

vmware.template_vm(vmware_vm, datastore, folder)
image.file_name = vmware.clone_and_template_vm(vmware_vm, datastore, folder)

instance.state = InstanceState.STOPPED # If this errors the instance will be stuck in the IMAGING state
image.state = ImageState.CREATED
32 changes: 28 additions & 4 deletions ingredients_tasks/vmware.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time
import uuid
from contextlib import contextmanager

from pyVim import connect
Expand Down Expand Up @@ -157,7 +158,7 @@ def power_off_vm(self, vm, hard=False, timeout=60):
try:
vm.ShutdownGuest()
except vim.fault.ToolsUnavailable:
# Guest tools was not running to hard power off instead
# Guest tools was not running so hard power off instead
return self.power_off_vm(vm, hard=True)
# Poll every 5 seconds until powered off or timeout
while vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
Expand All @@ -180,7 +181,7 @@ def delete_image(self, image):
task = image.Destroy_Task()
self.wait_for_tasks([task])

def template_vm(self, vm, datastore, folder):
def clone_and_template_vm(self, vm, datastore, folder):
reloSpec = vim.vm.RelocateSpec()
reloSpec.datastore = datastore
# the vm template stays on the host
Expand All @@ -189,9 +190,32 @@ def template_vm(self, vm, datastore, folder):
if folder is not None:
reloSpec.folder = folder

task = vm.RelocateVM_Task(reloSpec)
# Configure the new vm to be super small because why not
# We may want to remove it from the vswitch as well
vmconf = vim.vm.ConfigSpec()
vmconf.numCPUs = 1
vmconf.memoryMB = 128

# The vm may have additional device customization (i.e more disks)
# How do we remove those devices and only keep the first disk?

# If the vm starts with a large disk there is no way to shrink it.
# Hopefully it is thin provisioned...
# We should be smart when we create instances that will be converted to images
# they should have as small a disk as possible
# storage is cheap but cloning is expensive

clonespec = vim.vm.CloneSpec()
clonespec.location = reloSpec
clonespec.config = vmconf
clonespec.powerOn = False
clonespec.template = True

file_name = str(uuid.uuid4())

task = vm.Clone(folder=folder, name=file_name, spec=clonespec)
self.wait_for_tasks([task])
vm.MarkAsTemplate() # This doesn't return a task?
return file_name

def get_obj(self, vimtype, name, folder=None):
"""
Expand Down

0 comments on commit 2a383fc

Please sign in to comment.