Skip to content

Commit

Permalink
get_properties: property collector action
Browse files Browse the repository at this point in the history
  • Loading branch information
jeking3 committed Oct 11, 2018
1 parent 3163bd2 commit 22f8537
Show file tree
Hide file tree
Showing 4 changed files with 318 additions and 3 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ PYVMOMI 6.0 requires alternative connection coding and Python 2.7.9 minimum due
## Actions

* `vsphere.get_moid` - Returns the MOID of vSphere managed entity corresponding to the specified parameters
* `vsphere.get_properties` - Retrieves some or all properties of some or all objects through the PropertyCollector.
* `vsphere.get_vmconsole_urls` - Retrieves urls of the virtual machines' consoles
* `vsphere.get_vms` - Retrieves the virtual machines on a vCenter Server system. It computes the union of Virtual Machine sets based on each parameter.
* `vsphere.guest_dir_create` - Create a directory inside the guest.
Expand All @@ -224,8 +225,8 @@ PYVMOMI 6.0 requires alternative connection coding and Python 2.7.9 minimum due
* `vsphere.set_vm` - Changes configuration of a Virtual Machine.
* `vsphere.vm_check_tools` - Wait for a Task to complete and returns its result.
* `vsphere.vm_create_from_template` - Create a new VM from existing template.
* `vsphere.vm_env_items_get` - Retrieve list of Objects from VSphere
* `vsphere.vm_guest_info_get` - Retrieve Guest details of a VM object
* `vsphere.vm_env_items_get` - Retrieve list of Objects from VSphere (alternatively, use get_properties type=<type> property=name)
* `vsphere.vm_guest_info_get` - Retrieve Guest details of a VM object (deprecated: use get_properties type=VirtualMachine property=guest)
* `vsphere.vm_hw_barebones_create` - Create BareBones VM (CPU, Ram, Graphics Only)
* `vsphere.vm_hw_basic_build` - Minstral Flow to Build Basic Server and power it on.
* `vsphere.vm_hw_cpu_mem_edit` - Adjust the CPU and RAM values assigned to a Virtual Machine
Expand All @@ -239,7 +240,7 @@ PYVMOMI 6.0 requires alternative connection coding and Python 2.7.9 minimum due
* `vsphere.vm_hw_remove` - Removes the Virtual Machine.
* `vsphere.vm_hw_scsi_controller_add` - Add SCSI HDD Controller device to VM
* `vsphere.vm_hw_uuid_get` - Retrieve VM UUID
* `vsphere.vm_runtime_info_get` - Retrieves the Runtime information for a VM.
* `vsphere.vm_runtime_info_get` - Retrieves the Runtime information for a VM (deprecated: use get_properties type=VirtualMachine property=runtime)
* `vsphere.wait_task` - Wait for a Task to complete and returns its result.

## Known Bugs
Expand Down
129 changes: 129 additions & 0 deletions actions/get_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from pyVmomi import vim, vmodl # pylint: disable-msg=E0611
from vmwarelib.actions import BaseAction

import datetime
import json
import pyVmomi


class GetProperties(BaseAction):

def run(self, type, property, id, raw, vsphere=None):
"""
Leverage the Property Collector to retrieve properties from any
Managed Object.
Args:
- type: vimType
- properties: optional array of properties to get (default: all)
- ids: optional array of MOIDs to limit results (default: all)
- vsphere: pre-configured connection information
Returns:
- dict: key = moid, value = dict of properties
"""

self.establish_connection(vsphere)
return self.collect(self.si_content, type, property, id, raw)

def collect(self, content, type, properties, ids, raw):
"""
Leverage the Property Collector to retrieve properties from any
Managed Object.
Args:
- content: service instance content
- type: object type
- properties: optional array of properties to get (default: all)
- ids: optional array of MOIDs to limit results (default: all)
Returns:
- dict: key = moid, value = dict of properties
"""

vimtype = getattr(vim, type)

rootFolder = content.rootFolder
viewMgr = content.viewManager
if not ids:
view = viewMgr.CreateContainerView(container=rootFolder,
type=[vimtype],
recursive=True)
else:
view = viewMgr.CreateListView()
for id in ids:
view.ModifyListView(add=[
pyVmomi.VmomiSupport.GetWsdlType('urn:vim25', type)(id)])

traversal_spec = vmodl.query.PropertyCollector.TraversalSpec()
traversal_spec.name = 'traverseEntities'
traversal_spec.path = 'view'
traversal_spec.skip = False
traversal_spec.type = view.__class__

obj_spec = vmodl.query.PropertyCollector.ObjectSpec()
obj_spec.obj = view
obj_spec.skip = True
obj_spec.selectSet = [traversal_spec]

property_spec = vmodl.query.PropertyCollector.PropertySpec()
property_spec.type = vimtype
if not properties:
property_spec.all = True
else:
property_spec.pathSet = properties

filter_spec = vmodl.query.PropertyCollector.FilterSpec()
filter_spec.objectSet = [obj_spec]
filter_spec.propSet = [property_spec]

rawdata = content.propertyCollector.RetrieveContents([filter_spec])
return self.transform(ids, rawdata) if not raw else rawdata

def jsonify_vsphere_obj(self, obj):
"""JSONify a vSphere Managed/Data object."""
class PyVmomiObjectJSONEncoder(json.JSONEncoder):
"""Custom JSON encoder to encode vSphere object."""
def __init__(self, *args, **kwargs):
super(PyVmomiObjectJSONEncoder, self).__init__(*args, **kwargs)

def default(self, obj): # pylint: disable=method-hidden
if isinstance(obj, datetime.datetime):
return pyVmomi.Iso8601.ISO8601Format(obj)
elif isinstance(obj, pyVmomi.VmomiSupport.DataObject):
return obj.__dict__
elif isinstance(obj, pyVmomi.VmomiSupport.ManagedObject):
return unquote(obj).split(':')[-1]
elif isinstance(obj, type):
return str(obj)
return json.JSONEncoder.default(self, obj)
return json.loads(PyVmomiObjectJSONEncoder().encode(obj))

def transform(self, ids, rawdata):
result = {}
for obj in rawdata:
objid = unquote(obj.obj).split(':')[-1]
ps = {}
for prop in obj.propSet:
ps[unquote(prop.name)] = self.jsonify_vsphere_obj(prop.val)
result[objid] = ps
return (not ids or sorted(result.keys()) == sorted(ids), result)


def unquote(item):
return str(item).strip("'")
44 changes: 44 additions & 0 deletions actions/get_properties.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: get_properties
runner_type: python-script
description: Get properties of managed objects through the PropertyCollector.
enabled: true
entry_point: get_properties.py
parameters:
type:
type: string
description: The type of object to get. This type must be compatible with CreateContainerView.
required: true
position: 0
enum:
- ComputeResource
- Datacenter
- Datastore
- Folder
- HostSystem
- ManagedEntity
- Network
- ResourcePool
- VirtualMachine
id:
type: array
description: MOIDs to restrict the results to. Omit to retrieve all objects.
required: false
position: 1
property:
type: array
description: Fully qualified property within the type (dot separated), such as 'config.hardware.memoryMB' for a VirtualMachine. Omit to retrieve all properties.
required: false
position: 2
raw:
type: boolean
description: If True, return the raw result of the PropertyCollector.RetrieveContents call.
required: false
default: false
position: 3
vsphere:
type: string
description: Pre-Configured vsphere connection details
required: false
position: 4
default: ~
141 changes: 141 additions & 0 deletions tests/test_action_get_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and

import datetime
import mock
import pyVmomi

from get_properties import GetProperties
from pyVmomi import vim # pylint: disable-msg=E0611
from vsphere_base_action_test_case import VsphereBaseActionTestCase

__all__ = [
'GetPropertiesTestCase'
]


class GetPropertiesTestCase(VsphereBaseActionTestCase):
__test__ = True
action_cls = GetProperties

transformed = {
"vm-22": {
"config.hardware.memoryMB": 10240,
"dataobj": {
"arguments": "arguments",
'dynamicType': None,
'dynamicProperty': [],
"envVariables": ["A=B", "C=D"],
"programPath": "cmd.exe",
"workingDirectory": "/tmp"
},
"guest.ipAddress": "10.99.0.4",
"name": "VCSA",
"network": ["network-15"],
"time": "1992-01-12T01:01:22Z"
},
"vm-46": {
"config.hardware.memoryMB": 2048,
"guest.ipAddress": "fe80::250:56ff:feb4:cfb9",
"name": "testvm",
"network": [],
"time": "1992-01-17T01:01:46Z"
}
}

def setUp(self):
def mockDynamicProperty(name, val):
result = mock.Mock()
result.name = name
result.val = val
return result
super(GetPropertiesTestCase, self).setUp()
self._action = self.get_action_instance(self.new_config)
self._action.establish_connection = mock.Mock()
self._action.si_content = mock.Mock()
self._action.si_content.rootFolder = mock.Mock()
self._action.si_content.viewManager = mock.Mock()
self._action.si_content.viewManager.CreateContainerView = mock.Mock()
self._action.si_content.viewManager.CreateListView = mock.Mock()
self._action.si_content.propertyCollector = mock.Mock()
cmdspec = vim.vm.guest.ProcessManager.ProgramSpec(
arguments="arguments",
envVariables=["A=B", "C=D"],
programPath="cmd.exe",
workingDirectory='/tmp')
# mock up the raw objects used to test transform
vm22 = mock.Mock()
vm22.obj = 'vim.VirtualMachine:vm-22'
vm22.propSet = [mockDynamicProperty("config.hardware.memoryMB", 10240),
mockDynamicProperty("dataobj", cmdspec),
mockDynamicProperty("guest.ipAddress", "10.99.0.4"),
mockDynamicProperty("name", "VCSA"),
mockDynamicProperty("network", [
pyVmomi.VmomiSupport.GetWsdlType(
'urn:vim25', 'Network')(
'network-15')]),
mockDynamicProperty("time",
datetime.datetime(
1992, 1, 12, 1, 1, 22))]
vm46 = mock.Mock()
vm46.obj = 'vim.VirtualMachine:vm-46'
vm46.propSet = [mockDynamicProperty("config.hardware.memoryMB", 2048),
mockDynamicProperty("guest.ipAddress",
"fe80::250:56ff:feb4:cfb9"),
mockDynamicProperty("name", "testvm"),
mockDynamicProperty("network", []),
mockDynamicProperty("time",
datetime.datetime(
1992, 1, 17, 1, 1, 46))]
self.raw = [vm22, vm46]

@mock.patch('pyVmomi.vmodl.query.PropertyCollector')
def test_simple_property_by_id(self, pc):
with mock.patch.object(
self._action.si_content.propertyCollector, 'RetrieveContents',
return_value=self.raw):
result = self._action.run(type='VirtualMachine',
id=['vm-22', 'vm-46'],
property=['does.not.exist'], raw=False)
assert self._action.si_content.viewManager.CreateListView.called
# status True because every object was found
self.assertEqual(result, (True, self.transformed))
with mock.patch.object(
self._action.si_content.propertyCollector, 'RetrieveContents',
return_value=self.raw):
result = self._action.run(type='VirtualMachine',
id=['vm-22', 'vm-46', 'vm-47'],
property=None, raw=False)
# status False because not every object was found
self.assertEqual(result, (False, self.transformed))

@mock.patch('pyVmomi.vmodl.query.PropertyCollector')
def test_simple_by_type(self, pc):
with mock.patch.object(
self._action.si_content.propertyCollector, 'RetrieveContents',
return_value=self.raw):
result = self._action.run(type='VirtualMachine', id=None,
property=None, raw=False)
assert\
self._action.si_content.viewManager.CreateContainerView.called
self.assertEqual(result, (True, self.transformed))

@mock.patch('pyVmomi.vmodl.query.PropertyCollector')
def test_raw_output(self, pc):
with mock.patch.object(
self._action.si_content.propertyCollector, 'RetrieveContents',
return_value=self.raw):
result = self._action.run(type='VirtualMachine', id=None,
property=None, raw=True)
self.assertNotEqual(result, self.transformed)

0 comments on commit 22f8537

Please sign in to comment.