Skip to content

Commit

Permalink
Merge pull request #45 from czee/tabulate_output
Browse files Browse the repository at this point in the history
- added snapshot operations
- snapshot output is now tabulated with left text alignment
  • Loading branch information
snobear committed Aug 5, 2015
2 parents 0dafdaa + 3136627 commit fe600da
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 10 deletions.
8 changes: 8 additions & 0 deletions ezmomi/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ def cli():
ez.clone()
elif kwargs['mode'] == 'destroy':
ez.destroy()
elif kwargs['mode'] == 'listSnapshots':
ez.listSnapshots()
elif kwargs['mode'] == 'createSnapshot':
ez.createSnapshot()
elif kwargs['mode'] == 'removeSnapshot':
ez.removeSnapshot()
elif kwargs['mode'] == 'revertSnapshot':
ez.revertSnapshot()
elif kwargs['mode'] == 'status':
ez.status()
elif kwargs['mode'] == 'shutdown':
Expand Down
126 changes: 116 additions & 10 deletions ezmomi/ezmomi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ def __init__(self, **kwargs):
# load up our configs and connect to the vSphere server
self.config = self.get_configs(kwargs)
self.connect()
self._columns_two = "{0:<20} {1:<20}"
self._columns_three = "{0:<20} {1:<20} {2:<20}"
self._column_spacing = 4

def get_configs(self, kwargs):
default_cfg_dir = "%s/.config/ezmomi" % os.path.expanduser("~")
Expand Down Expand Up @@ -75,7 +74,7 @@ def get_configs(self, kwargs):
# command line arguments
notset = list()
for key, value in kwargs.items():
if value:
if value is not None:
config[key] = value
elif (value is None) and (key not in config):
# compile list of parameters that were not set
Expand Down Expand Up @@ -126,16 +125,15 @@ def list_objects(self):

# print header line
print "%s list" % vimtype
if vimtype == "VirtualMachine":
print self._columns_three.format('MOID', 'Name', 'Status')
else:
print self._columns_two.format('MOID', 'Name')

rows = [['MOID', 'Name', 'Status']] if vimtype == "VirtualMachine" else [['MOID', 'Name']]
for c in container.view:
if vimtype == "VirtualMachine":
print self._columns_three.format(c._moId, c.name, c.runtime.powerState)
rows.append([c._moId, c.name, c.runtime.powerState])
else:
print self._columns_two.format(c._moId, c.name)
rows.append([c._moId, c.name])

self.tabulate(rows)

def clone(self):
self.config['hostname'] = self.config['hostname'].lower()
Expand Down Expand Up @@ -321,7 +319,7 @@ def destroy(self):
''' Check power status '''
def status(self):
vm = self.get_vm_failfast(self.config['name'])
print self._columns_two.format(vm.name, vm.runtime.powerState)
self.tabulate([[vm.name, vm.runtime.powerState]])

''' shutdown guest, with fallback to power off if guest tools aren't installed '''
def shutdown(self):
Expand All @@ -345,6 +343,90 @@ def shutdown(self):
print "GuestTools not running or not installed: will powerOff"
self.powerOff()

def createSnapshot(self):
tasks = []

vm = self.get_vm_failfast(self.config['vm'])
tasks.append(vm.CreateSnapshot(self.config['name'],
memory=self.config['memory'],
quiesce=self.config['quiesce']))
result = self.WaitForTasks(tasks)
print "Created snapshot for %s" % vm.name

def get_all_snapshots(self, vm_name):
vm = self.get_vm_failfast(vm_name)

try:
vm_snapshot_info = vm.snapshot
except IndexError:
return

return vm_snapshot_info.rootSnapshotList

def get_snapshot_by_name(self, vm, name):
return next(snapshot.snapshot for snapshot in
self.get_all_snapshots(vm) if
snapshot.name == name)

def tabulate(self, data):
column_widths = []

for row in data:
for column in range(0, len(row)):
column_len = len(row[column])
try:
column_widths[column] = max(column_len,
column_widths[column])
except IndexError:
column_widths.append(column_len)

for column in range(0, len(column_widths)):
column_widths[column] += self._column_spacing - 1

format = "{0:<%d}" % column_widths[0]
for width in range(1, len(column_widths)):
format += " {%d:<%d}" % (width, column_widths[width])

for row in data:
print format.format(*row)

def listSnapshots(self):
root_snapshot_list = self.get_all_snapshots(self.config['vm'])

if root_snapshot_list:
snapshots = []
for snapshot in root_snapshot_list:
snapshots.append([str(snapshot.vm), snapshot.name,
str(snapshot.createTime)])

data = [['VM', 'Snapshot', 'Create Time']] + snapshots
self.tabulate(data)
else:
print "No snapshots for %s" % self.config['vm']

def removeSnapshot(self):
tasks = []

snapshot = self.get_snapshot_by_name(self.config['vm'],
self.config['name'])
tasks.append(snapshot.Remove(self.config['remove_children'],
self.config['consolidate']))
result = self.WaitForTasks(tasks)
print("Removed snapshot %s for virtual machine %s" %
(self.config['name'], self.config['vm']))

def revertSnapshot(self):
tasks = []

snapshot = self.get_snapshot_by_name(self.config['vm'],
self.config['name'])
host_system = self.get_host_system_failfast(self.config['host'])
tasks.append(snapshot.Revert(host=host_system,
suppressPowerOn=self.config['suppress_power_on']))
result = self.WaitForTasks(tasks)
print("Reverted snapshot %s for virtual machine %s" %
(self.config['name'], self.config['vm']))

def powerOff(self):
vm = self.get_vm_failfast(self.config['name'])

Expand Down Expand Up @@ -414,6 +496,30 @@ def get_obj(self, vimtype, name):
break
return obj

'''
Get a HostSystem object
'''
def get_host_system(self, name):
return self.get_obj([vim.HostSystem], name)

'''
Get a HostSystem object and fail fast if the object isn't a valid reference
'''
def get_host_system_failfast(self, name, verbose=False, host_system_term='HS'):
if True == verbose:
print "Finding HostSystem named %s..." % name

hs = self.get_host_system(name)

if None == hs:
print "Error: %s '%s' does not exist" % (host_system_term, name)
sys.exit(1)

if True == verbose:
print("Found HostSystem: {0} Name: {1}", hs, hs.name)

return hs

'''
Get a VirtualMachine object
'''
Expand Down
102 changes: 102 additions & 0 deletions ezmomi/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,108 @@ def add_params(subparsers):
help='Object type, e.g. Network, VirtualMachine.'
)

list_snapshot_parser = subparsers.add_parser(
'listSnapshots',
help='List snapshots for a VM'
)
list_snapshot_parser.add_argument(
'--vm',
required=True,
help='VM name (case-sensitive)'
)

create_snapshot_parser = subparsers.add_parser(
'createSnapshot',
help='Create snapshot for a VM'
)
create_snapshot_parser.add_argument(
'--vm',
required=True,
help='VM name (case-sensitive)'
)
create_snapshot_parser.add_argument(
'--name',
required=True,
help='Snapshot name (case-sensitive)'
)
create_snapshot_parser.add_argument(
'--memory',
required=False,
action='store_true',
default=False,
help=("When set, a dump of the internal state of the virtual "
"machine (basically a memory dump) is included in the "
"snapshot. When unset, the power state of the snapshot "
"is set to powered off.")
)
create_snapshot_parser.add_argument(
'--quiesce',
required=False,
action='store_true',
default=True,
help=("When set and the virtual machine is powered on when the "
"snapshot is taken, VMware Tools is used to quiesce "
"the file system in the virtual machine.")
)

remove_snapshot_parser = subparsers.add_parser(
'removeSnapshot',
help='Remove snapshot for a VM'
)
remove_snapshot_parser.add_argument(
'--vm',
required=True,
help='VM name (case-sensitive)'
)
remove_snapshot_parser.add_argument(
'--name',
required=True,
help='Snapshot name (case-sensitive)'
)
remove_snapshot_parser.add_argument(
'--remove-children',
required=False,
action='store_true',
default=False,
help='Flag to specify removal of the entire snapshot subtree'
)
remove_snapshot_parser.add_argument(
'--consolidate',
required=False,
action='store_true',
default=True,
help='If true, the virtual disk associated with this snapshot will be merged with other disk if possible'
)

revert_snapshot_parser = subparsers.add_parser(
'revertSnapshot',
help='Revert snapshot for a VM'
)
revert_snapshot_parser.add_argument(
'--vm',
required=True,
help='VM name (case-sensitive)'
)
revert_snapshot_parser.add_argument(
'--name',
required=True,
help='Snapshot name (case-sensitive)'
)
revert_snapshot_parser.add_argument(
'--host',
required=False,
type=str,
help='Choice of host for the virtual machine, in case this operation causes the virtual machine to power on.'
)
revert_snapshot_parser.add_argument(
'--suppress-power-on',
required=False,
action='store_true',
default=False,
help=("When set, the virtual machine will not be powered on regardless"
"of the power state when the snapshot was created")
)

# clone
clone_parser = subparsers.add_parser(
'clone',
Expand Down

0 comments on commit fe600da

Please sign in to comment.