1# VMware vSphere Python SDK
2# Copyright (c) 2008-2015 VMware, Inc. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""
17This module is a converter from dynamic type to pyVmomi type
18"""
19__author__ = "VMware, Inc."
20
21from pyVmomi import VmomiSupport, vmodl
22from Cache import Cache
23
24## Dynamic type importer
25#
26class DynamicTypeImporter:
27   """ Dynamic type importer  """
28
29   ## Constructor
30   #
31   # @param  stub Server stub
32   def __init__(self, stub, hostSystem=None):
33      self.stub = stub
34      self.hostSystem = hostSystem
35
36   ## Get dynamic type manager
37   #
38   # @return moRef to dynamic type manager
39   @Cache
40   def GetTypeManager(self):
41      """ Get dynamic type manager """
42      dynTypeMgr = None
43      if self.hostSystem:
44         try:
45            dynTypeMgr = self.hostSystem.RetrieveDynamicTypeManager()
46         except vmodl.fault.MethodNotFound as err:
47            pass
48
49      if not dynTypeMgr:
50         # Older host not support RetrieveDynamicTypeManager
51         cmdlineTypesMoId = "ha-dynamic-type-manager"
52         dynTypeMgr = vmodl.reflect.DynamicTypeManager(cmdlineTypesMoId,
53                                                       self.stub)
54      return dynTypeMgr
55
56   ## Import dynamic types
57   #
58   # @param  prefix Only types with the specified prefix are imported
59   # @return dynamic types
60   @Cache
61   def ImportTypes(self, prefix=''):
62      """ Build dynamic types """
63      # Use QueryTypeInfo to get all types
64      dynTypeMgr = self.GetTypeManager()
65      filterSpec = None
66      if prefix != '':
67         filterSpec = vmodl.reflect.DynamicTypeManager.TypeFilterSpec(
68                                                              typeSubstr=prefix)
69      allTypes = dynTypeMgr.QueryTypeInfo(filterSpec)
70
71      ## Convert dynamic types to pyVmomi types
72      #
73      DynamicTypeConstructor().CreateTypes(allTypes)
74      return allTypes
75
76
77## Construct pyVmomi types from dynamic types definition
78#
79class DynamicTypeConstructor:
80   """ Dynamic type constructor  """
81
82   _mapFlags = { "optional": VmomiSupport.F_OPTIONAL,
83                 "linkable": VmomiSupport.F_LINKABLE,
84                 "link":     VmomiSupport.F_LINK,
85                 "secret":   VmomiSupport.F_SECRET }
86
87   ## Constructor
88   #
89   def __init__(self):
90      """ Constructor """
91      pass
92
93   ## Create pyVmomi types from vmodl.reflect.DynamicTypeManager.AllTypeInfo
94   #
95   # @param  allTypes vmodl.reflect.DynamicTypeManager.AllTypeInfo
96   def CreateTypes(self, allTypes):
97      """
98      Create pyVmomi types from vmodl.reflect.DynamicTypeManager.AllTypeInfo
99      """
100      enumTypes, dataTypes, managedTypes = self._ConvertAllTypes(allTypes)
101      self._CreateAllTypes(enumTypes, dataTypes, managedTypes)
102
103   ## Convert all dynamic types to pyVmomi type definitions
104   #
105   # @param  allTypes vmodl.reflect.DynamicTypeManager.AllTypeInfo
106   # @return a tuple of (enumTypes, dataTypes, managedTypes)
107   def _ConvertAllTypes(self, allTypes):
108      """ Convert all dynamic types to pyVmomi type definitions """
109      # Generate lists good for VmomiSupport.CreateXYZType
110      enumTypes = self._Filter(self._ConvertEnumType, allTypes.enumTypeInfo)
111      dataTypes = self._Filter(self._ConvertDataType, allTypes.dataTypeInfo)
112      managedTypes = self._Filter(self._ConvertManagedType,
113                                  allTypes.managedTypeInfo)
114      retAllTypes = (enumTypes, dataTypes, managedTypes)
115      return retAllTypes
116
117   ## Create pyVmomi types from pyVmomi type definitions
118   #
119   # @param  enumTypes pyVmomi enum type definitions
120   # @param  dataTypes pyVmomi data type definitions
121   # @param  managedTypes pyVmomi managed type definitions
122   def _CreateAllTypes(self, enumTypes, dataTypes, managedTypes):
123      """ Create pyVmomi types from pyVmomi type definitions """
124
125      # Create versions
126      for typeInfo in managedTypes:
127         name = typeInfo[0]
128         version = typeInfo[3]
129         VmomiSupport.AddVersion(version, '', '1.0', 0, name)
130         VmomiSupport.AddVersionParent(version, 'vmodl.version.version0')
131         VmomiSupport.AddVersionParent(version, 'vmodl.version.version1')
132         VmomiSupport.AddVersionParent(version, version)
133
134      # Create partial types
135      for fn, infos in (VmomiSupport.CreateEnumType, enumTypes), \
136                       (VmomiSupport.CreateDataType, dataTypes), \
137                       (VmomiSupport.CreateManagedType, managedTypes):
138         for typeInfo in infos:
139            try:
140               fn(*typeInfo)
141            except Exception as err:
142               #Ignore errors due to duplicate importing
143               pass
144
145   def _ConvertAnnotations(self, annotations):
146      """ Convert annotations to pyVmomi flags """
147      flags = 0
148      if annotations:
149         for annotation in annotations:
150            flags |= self._mapFlags.get(annotation.name, 0)
151      return flags
152
153   @staticmethod
154   def _Filter(fn, types):
155      """ Call fn for each non null element in types. Similiar to filter """
156      if types:
157         return [fn(prop) for prop in types if prop is not None]
158      else:
159         return []
160
161   def _ConvertParamType(self, paramType):
162      """
163      Convert vmodl.reflect.DynamicTypeManager.ParamTypeInfo to pyVmomi param
164      definition
165      """
166      if paramType:
167         name = paramType.name
168         version = paramType.version
169         aType = paramType.type
170         flags = self._ConvertAnnotations(paramType.annotation)
171         privId = paramType.privId
172         param = (name, aType, version, flags, privId)
173      else:
174         param = None
175      return param
176
177   def _ConvertMethodType(self, methodType):
178      """
179      Convert vmodl.reflect.DynamicTypeManager.MethodTypeInfo to pyVmomi method
180      definition
181      """
182      if methodType:
183         name = methodType.name
184         wsdlName = methodType.wsdlName
185         version = methodType.version
186         params = self._Filter(self._ConvertParamType, methodType.paramTypeInfo)
187         privId = methodType.privId
188         faults = methodType.fault
189
190         # Figure out reture info
191         if methodType.returnTypeInfo:
192            returnTypeInfo = methodType.returnTypeInfo
193            retFlags = self._ConvertAnnotations(returnTypeInfo.annotation)
194            methodRetType = returnTypeInfo.type
195         else:
196            retFlags = 0
197            methodRetType = "void"
198         if wsdlName.endswith("_Task"):
199            # TODO: Need a seperate task return type for task, instead of
200            #       hardcode vim.Task as return type
201            retType = "vim.Task"
202         else:
203            retType = methodRetType
204         retInfo = (retFlags, retType, methodRetType)
205
206         method = (name, wsdlName, version, params, retInfo, privId, faults)
207      else:
208         method = None
209      return method
210
211   def _ConvertManagedPropertyType(self, propType):
212      """
213      Convert vmodl.reflect.DynamicTypeManager.PropertyTypeInfo to pyVmomi
214      managed property definition
215      """
216      if propType:
217         name = propType.name
218         version = propType.version
219         aType = propType.type
220         flags = self._ConvertAnnotations(propType.annotation)
221         privId = propType.privId
222         prop = (name, aType, version, flags, privId)
223      else:
224         prop = None
225      return prop
226
227   def _ConvertManagedType(self, managedType):
228      """
229      Convert vmodl.reflect.DynamicTypeManager.ManagedTypeInfo to pyVmomi
230      managed type definition
231      """
232      if managedType:
233         vmodlName = managedType.name
234         wsdlName = managedType.wsdlName
235         version = managedType.version
236         parent = managedType.base[0]
237         props = self._Filter(self._ConvertManagedPropertyType, managedType.property)
238         methods = self._Filter(self._ConvertMethodType, managedType.method)
239         moType = (vmodlName, wsdlName, parent, version, props, methods)
240      else:
241         moType = None
242      return moType
243
244   def _ConvertDataPropertyType(self, propType):
245      """
246      Convert vmodl.reflect.DynamicTypeManager.PropertyTypeInfo to pyVmomi
247      data property definition
248      """
249      if propType:
250         name = propType.name
251         version = propType.version
252         aType = propType.type
253         flags = self._ConvertAnnotations(propType.annotation)
254         prop = (name, aType, version, flags)
255      else:
256         prop = None
257      return prop
258
259   def _ConvertDataType(self, dataType):
260      """
261      Convert vmodl.reflect.DynamicTypeManager.DataTypeInfo to pyVmomi data
262      type definition
263      """
264      if dataType:
265         vmodlName = dataType.name
266         wsdlName = dataType.wsdlName
267         version = dataType.version
268         parent = dataType.base[0]
269         props = self._Filter(self._ConvertDataPropertyType, dataType.property)
270         doType = (vmodlName, wsdlName, parent, version, props)
271      else:
272         doType = None
273      return doType
274
275   def _ConvertEnumType(self, enumType):
276      """
277      Convert vmodl.reflect.DynamicTypeManager.EnumTypeInfo to pyVmomi enum
278      type definition
279      """
280      if enumType:
281         vmodlName = enumType.name
282         wsdlName = enumType.wsdlName
283         version = enumType.version
284         values = enumType.value
285         enumType = (vmodlName, wsdlName, version, values)
286      else:
287         enumType = None
288      return enumType
289
290