1""" 2Library for VMware Storage Policy management (via the pbm endpoint) 3 4This library is used to manage the various policies available in VMware 5 6:codeauthor: Alexandru Bleotu <alexandru.bleotu@morganstaley.com> 7 8Dependencies 9~~~~~~~~~~~~ 10 11- pyVmomi Python Module 12 13pyVmomi 14------- 15 16PyVmomi can be installed via pip: 17 18.. code-block:: bash 19 20 pip install pyVmomi 21 22.. note:: 23 24 versions of Python. If using version 6.0 of pyVmomi, Python 2.6, 25 Python 2.7.9, or newer must be present. This is due to an upstream dependency 26 in pyVmomi 6.0 that is not supported in Python versions 2.7 to 2.7.8. If the 27 version of Python is not in the supported range, you will need to install an 28 earlier version of pyVmomi. See `Issue #29537`_ for more information. 29 30.. _Issue #29537: https://github.com/saltstack/salt/issues/29537 31 32Based on the note above, to install an earlier version of pyVmomi than the 33version currently listed in PyPi, run the following: 34 35.. code-block:: bash 36 37 pip install pyVmomi==5.5.0.2014.1.1 38""" 39 40 41import logging 42 43import salt.utils.vmware 44from salt.exceptions import ( 45 VMwareApiError, 46 VMwareObjectRetrievalError, 47 VMwareRuntimeError, 48) 49 50try: 51 from pyVmomi import pbm, vim, vmodl # pylint: disable=no-name-in-module 52 53 HAS_PYVMOMI = True 54except ImportError: 55 HAS_PYVMOMI = False 56 57 58# Get Logging Started 59log = logging.getLogger(__name__) 60 61 62def __virtual__(): 63 """ 64 Only load if PyVmomi is installed. 65 """ 66 if HAS_PYVMOMI: 67 return True 68 else: 69 return ( 70 False, 71 "Missing dependency: The salt.utils.pbm module " 72 "requires the pyvmomi library", 73 ) 74 75 76def get_profile_manager(service_instance): 77 """ 78 Returns a profile manager 79 80 service_instance 81 Service instance to the host or vCenter 82 """ 83 stub = salt.utils.vmware.get_new_service_instance_stub( 84 service_instance, ns="pbm/2.0", path="/pbm/sdk" 85 ) 86 pbm_si = pbm.ServiceInstance("ServiceInstance", stub) 87 try: 88 profile_manager = pbm_si.RetrieveContent().profileManager 89 except vim.fault.NoPermission as exc: 90 log.exception(exc) 91 raise VMwareApiError( 92 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 93 ) 94 except vim.fault.VimFault as exc: 95 log.exception(exc) 96 raise VMwareApiError(exc.msg) 97 except vmodl.RuntimeFault as exc: 98 log.exception(exc) 99 raise VMwareRuntimeError(exc.msg) 100 return profile_manager 101 102 103def get_placement_solver(service_instance): 104 """ 105 Returns a placement solver 106 107 service_instance 108 Service instance to the host or vCenter 109 """ 110 stub = salt.utils.vmware.get_new_service_instance_stub( 111 service_instance, ns="pbm/2.0", path="/pbm/sdk" 112 ) 113 pbm_si = pbm.ServiceInstance("ServiceInstance", stub) 114 try: 115 profile_manager = pbm_si.RetrieveContent().placementSolver 116 except vim.fault.NoPermission as exc: 117 log.exception(exc) 118 raise VMwareApiError( 119 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 120 ) 121 except vim.fault.VimFault as exc: 122 log.exception(exc) 123 raise VMwareApiError(exc.msg) 124 except vmodl.RuntimeFault as exc: 125 log.exception(exc) 126 raise VMwareRuntimeError(exc.msg) 127 return profile_manager 128 129 130def get_capability_definitions(profile_manager): 131 """ 132 Returns a list of all capability definitions. 133 134 profile_manager 135 Reference to the profile manager. 136 """ 137 res_type = pbm.profile.ResourceType( 138 resourceType=pbm.profile.ResourceTypeEnum.STORAGE 139 ) 140 try: 141 cap_categories = profile_manager.FetchCapabilityMetadata(res_type) 142 except vim.fault.NoPermission as exc: 143 log.exception(exc) 144 raise VMwareApiError( 145 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 146 ) 147 except vim.fault.VimFault as exc: 148 log.exception(exc) 149 raise VMwareApiError(exc.msg) 150 except vmodl.RuntimeFault as exc: 151 log.exception(exc) 152 raise VMwareRuntimeError(exc.msg) 153 cap_definitions = [] 154 for cat in cap_categories: 155 cap_definitions.extend(cat.capabilityMetadata) 156 return cap_definitions 157 158 159def get_policies_by_id(profile_manager, policy_ids): 160 """ 161 Returns a list of policies with the specified ids. 162 163 profile_manager 164 Reference to the profile manager. 165 166 policy_ids 167 List of policy ids to retrieve. 168 """ 169 try: 170 return profile_manager.RetrieveContent(policy_ids) 171 except vim.fault.NoPermission as exc: 172 log.exception(exc) 173 raise VMwareApiError( 174 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 175 ) 176 except vim.fault.VimFault as exc: 177 log.exception(exc) 178 raise VMwareApiError(exc.msg) 179 except vmodl.RuntimeFault as exc: 180 log.exception(exc) 181 raise VMwareRuntimeError(exc.msg) 182 183 184def get_storage_policies(profile_manager, policy_names=None, get_all_policies=False): 185 """ 186 Returns a list of the storage policies, filtered by name. 187 188 profile_manager 189 Reference to the profile manager. 190 191 policy_names 192 List of policy names to filter by. 193 Default is None. 194 195 get_all_policies 196 Flag specifying to return all policies, regardless of the specified 197 filter. 198 """ 199 res_type = pbm.profile.ResourceType( 200 resourceType=pbm.profile.ResourceTypeEnum.STORAGE 201 ) 202 try: 203 policy_ids = profile_manager.QueryProfile(res_type) 204 except vim.fault.NoPermission as exc: 205 log.exception(exc) 206 raise VMwareApiError( 207 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 208 ) 209 except vim.fault.VimFault as exc: 210 log.exception(exc) 211 raise VMwareApiError(exc.msg) 212 except vmodl.RuntimeFault as exc: 213 log.exception(exc) 214 raise VMwareRuntimeError(exc.msg) 215 log.trace("policy_ids = %s", policy_ids) 216 # More policies are returned so we need to filter again 217 policies = [ 218 p 219 for p in get_policies_by_id(profile_manager, policy_ids) 220 if p.resourceType.resourceType == pbm.profile.ResourceTypeEnum.STORAGE 221 ] 222 if get_all_policies: 223 return policies 224 if not policy_names: 225 policy_names = [] 226 return [p for p in policies if p.name in policy_names] 227 228 229def create_storage_policy(profile_manager, policy_spec): 230 """ 231 Creates a storage policy. 232 233 profile_manager 234 Reference to the profile manager. 235 236 policy_spec 237 Policy update spec. 238 """ 239 try: 240 profile_manager.Create(policy_spec) 241 except vim.fault.NoPermission as exc: 242 log.exception(exc) 243 raise VMwareApiError( 244 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 245 ) 246 except vim.fault.VimFault as exc: 247 log.exception(exc) 248 raise VMwareApiError(exc.msg) 249 except vmodl.RuntimeFault as exc: 250 log.exception(exc) 251 raise VMwareRuntimeError(exc.msg) 252 253 254def update_storage_policy(profile_manager, policy, policy_spec): 255 """ 256 Updates a storage policy. 257 258 profile_manager 259 Reference to the profile manager. 260 261 policy 262 Reference to the policy to be updated. 263 264 policy_spec 265 Policy update spec. 266 """ 267 try: 268 profile_manager.Update(policy.profileId, policy_spec) 269 except vim.fault.NoPermission as exc: 270 log.exception(exc) 271 raise VMwareApiError( 272 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 273 ) 274 except vim.fault.VimFault as exc: 275 log.exception(exc) 276 raise VMwareApiError(exc.msg) 277 except vmodl.RuntimeFault as exc: 278 log.exception(exc) 279 raise VMwareRuntimeError(exc.msg) 280 281 282def get_default_storage_policy_of_datastore(profile_manager, datastore): 283 """ 284 Returns the default storage policy reference assigned to a datastore. 285 286 profile_manager 287 Reference to the profile manager. 288 289 datastore 290 Reference to the datastore. 291 """ 292 # Retrieve all datastores visible 293 hub = pbm.placement.PlacementHub(hubId=datastore._moId, hubType="Datastore") 294 log.trace("placement_hub = %s", hub) 295 try: 296 policy_id = profile_manager.QueryDefaultRequirementProfile(hub) 297 except vim.fault.NoPermission as exc: 298 log.exception(exc) 299 raise VMwareApiError( 300 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 301 ) 302 except vim.fault.VimFault as exc: 303 log.exception(exc) 304 raise VMwareApiError(exc.msg) 305 except vmodl.RuntimeFault as exc: 306 log.exception(exc) 307 raise VMwareRuntimeError(exc.msg) 308 policy_refs = get_policies_by_id(profile_manager, [policy_id]) 309 if not policy_refs: 310 raise VMwareObjectRetrievalError( 311 "Storage policy with id '{}' was not found".format(policy_id) 312 ) 313 return policy_refs[0] 314 315 316def assign_default_storage_policy_to_datastore(profile_manager, policy, datastore): 317 """ 318 Assigns a storage policy as the default policy to a datastore. 319 320 profile_manager 321 Reference to the profile manager. 322 323 policy 324 Reference to the policy to assigned. 325 326 datastore 327 Reference to the datastore. 328 """ 329 placement_hub = pbm.placement.PlacementHub( 330 hubId=datastore._moId, hubType="Datastore" 331 ) 332 log.trace("placement_hub = %s", placement_hub) 333 try: 334 profile_manager.AssignDefaultRequirementProfile( 335 policy.profileId, [placement_hub] 336 ) 337 except vim.fault.NoPermission as exc: 338 log.exception(exc) 339 raise VMwareApiError( 340 "Not enough permissions. Required privilege: {}".format(exc.privilegeId) 341 ) 342 except vim.fault.VimFault as exc: 343 log.exception(exc) 344 raise VMwareApiError(exc.msg) 345 except vmodl.RuntimeFault as exc: 346 log.exception(exc) 347 raise VMwareRuntimeError(exc.msg) 348