Minimize size plugin can now shrink vmdk images

It requires vmware workstation to be installed (and zerofree optionally, but highly recommended)
This commit is contained in:
Anders Ingemann 2014-01-22 01:03:30 +01:00
parent 8902e5d93f
commit d85ad7f598
4 changed files with 119 additions and 1 deletions

View file

@ -1,10 +1,27 @@
import tasks import tasks
def validate_manifest(data, validator, error):
import os.path
schema_path = os.path.join(os.path.dirname(__file__), 'manifest-schema.json')
validator(data, schema_path)
if 'zerofree' in data['plugins']['minimize_size']:
zerofree_schema_path = os.path.join(os.path.dirname(__file__), 'manifest-schema-zerofree.json')
validator(data, zerofree_schema_path)
if data['plugins']['minimize_size'].get('shrink', False) and data['volume']['backing'] != 'vmdk':
error('Can only shrink vmdk images', ['plugins', 'minimize_size', 'shrink'])
def resolve_tasks(taskset, manifest): def resolve_tasks(taskset, manifest):
taskset.update([tasks.AddFolderMounts, taskset.update([tasks.AddFolderMounts,
tasks.RemoveFolderMounts, tasks.RemoveFolderMounts,
]) ])
if 'zerofree' in manifest.plugins['minimize_size']:
taskset.add(tasks.CheckZerofreePath)
taskset.add(tasks.Zerofree)
if manifest.plugins['minimize_size'].get('shrink', False):
taskset.add(tasks.CheckVMWareDMCommand)
taskset.add(tasks.ShrinkVolume)
def resolve_rollback_tasks(taskset, manifest, counter_task): def resolve_rollback_tasks(taskset, manifest, counter_task):

View file

@ -0,0 +1,18 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Minimize size plugin manifest",
"type": "object",
"properties": {
"volume": {
"type": "object",
"properties": {
"partitions": {
"type": "object",
"properties": {
"type": { "enum": ["none"] }
}
}
}
}
}
}

View file

@ -0,0 +1,25 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Minimize size plugin manifest",
"type": "object",
"properties": {
"plugins": {
"type": "object",
"properties": {
"minimize_size": {
"type": "object",
"properties": {
"shrink": { "type": "boolean" },
"zerofree": { "$ref": "#/definitions/absolute_path" }
}
}
}
}
},
"definitions": {
"absolute_path": {
"type": "string",
"pattern": "^/[^\\0]+$"
}
}
}

View file

@ -1,7 +1,10 @@
from base import Task from base import Task
from common import phases from common import phases
from common.tasks import bootstrap
from common.tasks import apt from common.tasks import apt
from common.tasks import bootstrap
from common.tasks import filesystem
from common.tasks import partitioning
from common.tasks import volume
import os import os
folders = ['tmp', 'var/lib/apt/lists'] folders = ['tmp', 'var/lib/apt/lists']
@ -41,3 +44,58 @@ class RemoveFolderMounts(Task):
os.rmdir(info.minimize_size_folder) os.rmdir(info.minimize_size_folder)
del info.minimize_size_folder del info.minimize_size_folder
class CheckZerofreePath(Task):
description = 'Checking path to zerofree tool'
phase = phases.preparation
@classmethod
def run(cls, info):
from common.exceptions import TaskError
import os
zerofree = info.manifest.plugins['minimize_size']['zerofree']
if not os.path.isfile(zerofree):
raise TaskError('The path `{path}\' does not exist or is not a file'.format(path=zerofree))
if not os.access(zerofree, os.X_OK):
raise TaskError('The path `{path}\' is not executable'.format(path=zerofree))
# Get zerofree here: http://intgat.tigress.co.uk/rmy/uml/index.html
class Zerofree(Task):
description = 'Zeroing unused blocks on the volume'
phase = phases.volume_unmounting
predecessors = [filesystem.UnmountRoot, partitioning.UnmapPartitions]
successors = [volume.Detach]
@classmethod
def run(cls, info):
from common.tools import log_check_call
zerofree = info.manifest.plugins['minimize_size']['zerofree']
log_check_call([zerofree, info.volume.device_path])
class CheckVMWareDMCommand(Task):
description = 'Checking path to vmware-vdiskmanager tool'
phase = phases.preparation
@classmethod
def run(cls, info):
from common.exceptions import TaskError
import os
vdiskmngr = '/usr/bin/vmware-vdiskmanager'
if not os.path.isfile(vdiskmngr):
raise TaskError('Unable to find vmware-vdiskmanager at `{path}\''.format(path=vdiskmngr))
if not os.access(vdiskmngr, os.X_OK):
raise TaskError('vmware-vdiskmanager at `{path}\' is not executable'.format(path=vdiskmngr))
class ShrinkVolume(Task):
description = 'Shrinking the volume'
phase = phases.volume_unmounting
predecessors = [volume.Detach]
@classmethod
def run(cls, info):
from common.tools import log_check_call
log_check_call(['/usr/bin/vmware-vdiskmanager', '-k', info.volume.image_path])