Skip to content

Commit

Permalink
Merge pull request StackStorm-Exchange#97 from EncoreTechnologies/master
Browse files Browse the repository at this point in the history
feature/vm-bestfit-fixes
  • Loading branch information
bishopbm1 authored Nov 17, 2022
2 parents b6b800d + 03b2ef8 commit 5977631
Show file tree
Hide file tree
Showing 11 changed files with 45 additions and 14 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log

## v1.3.3

Updates:
* `vm_bestfit` - Added logic to account for scenario where there is more then one datacenter. (@bishopbm1)

## v1.3.2

Fixes:
Expand Down
2 changes: 1 addition & 1 deletion actions/guest_process_wait.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# limitations under the License.

from vmwarelib.guest import GuestAction
import eventlet
import eventlet # pylint: disable=import-error
import sys


Expand Down
14 changes: 11 additions & 3 deletions actions/vm_bestfit.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, config):
"""
super(BestFit, self).__init__(config)

def get_host(self, cluster_name):
def get_host(self, datacenter_name, cluster_name):
"""Return a host from the given cluster that's powered on and has the least number of VMs
:param cluster_name: Name of the cluster to retrieve a host from
:returns host_obj: Host object from the given cluster
Expand All @@ -39,9 +39,16 @@ def get_host(self, cluster_name):
least_vms = None

for host in hosts.view:
host_cluster = host.parent
# The first parent of a cluster is a folder
# and the parent of that is the Datacenter
host_dc = host_cluster.parent.parent
# Need to verify that the host is on, connected, and not in maintenance mode
# powerState can be 'poweredOff' 'poweredOn' 'standBy' 'unknown'
if (host.parent.name == cluster_name and
# Since there can be multiple hosts with the same name in different clusters
# and datacenters we need to verify we are getting the correct host.
if (host_dc.name == datacenter_name and
host_cluster.name == cluster_name and
host.runtime.powerState == 'poweredOn' and
host.runtime.inMaintenanceMode is False):
# Find the host that has the least number of VMs on it
Expand Down Expand Up @@ -137,6 +144,7 @@ def filter_datastores(self,
return default_return

def run(self,
datacenter_name,
cluster_name,
datastore_filter_strategy,
datastore_filter_regex_list,
Expand All @@ -159,7 +167,7 @@ def run(self,
self.establish_connection(vsphere)

# Return a host from the given cluster that's powered on and has the least amount of VMs
host = self.get_host(cluster_name)
host = self.get_host(datacenter_name, cluster_name)

# Return a datastore on the host that is either specified in the disks variable or
# has the most free space and a name that doesn't match any filters
Expand Down
4 changes: 4 additions & 0 deletions actions/vm_bestfit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ description: >
enabled: true
entry_point: vm_bestfit.py
parameters:
datacenter_name:
type: string
description: Name of the datacenter in vSphere
required: true
cluster_name:
type: string
description: Name of the cluster in vSphere
Expand Down
2 changes: 1 addition & 1 deletion actions/vm_check_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import eventlet
import eventlet # pylint: disable=import-error
import json

from pyVmomi import vim # pylint: disable-msg=E0611
Expand Down
2 changes: 1 addition & 1 deletion actions/vm_hw_power.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import eventlet
import eventlet # pylint: disable=import-error
from pyVmomi import vim # pylint: disable-msg=E0611

from vmwarelib import inventory
Expand Down
2 changes: 1 addition & 1 deletion actions/vm_snapshots_delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from vmwarelib import inventory
import re
import datetime
import pytz
import pytz # pylint: disable=import-error


class VMSnapshotsDelete(BaseAction):
Expand Down
2 changes: 1 addition & 1 deletion actions/vmwarelib/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import ssl
import atexit

import eventlet
import eventlet # pylint: disable=import-error
import requests
from pyVim import connect
from pyVmomi import vim # pylint: disable-msg=E0611
Expand Down
2 changes: 1 addition & 1 deletion actions/wait_for_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import eventlet
import eventlet # pylint: disable=import-error

from pyVmomi import vim # pylint: disable-msg=E0611

Expand Down
2 changes: 1 addition & 1 deletion pack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ref: vsphere
name: vsphere
description: VMware vSphere
stackstorm_version: ">=2.9.0"
version: 1.3.2
version: 1.3.3
author: Paul Mulvihill
email: [email protected]
contributors:
Expand Down
22 changes: 18 additions & 4 deletions tests/test_action_vm_bestfit.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,29 +124,40 @@ def test_get_host_none_available(self, mock_vim_type, mock_entities):
@mock.patch('vmwarelib.actions.BaseAction.get_vim_type')
def test_get_host(self, mock_vim_type, mock_entities):
test_cluster_name = "cls1"
test_datacetner_name = "dc1"
test_vim_type = "vimType"
mock_vim_type.return_value = test_vim_type

# Mock function results
mock_host1 = mock.MagicMock()
mock_host1.parent.name = "cls1"
mock_host1.parent.parent.parent.name = "dc1"
mock_host1.runtime.powerState = "poweredOn"
mock_host1.runtime.inMaintenanceMode = False
mock_host1.vm = ["vm1", "vm2"]

mock_host2 = mock.MagicMock()
mock_host2.parent.name = "cls1"
mock_host2.parent.parent.parent.name = "dc1"
mock_host2.runtime.powerState = "poweredOn"
mock_host2.runtime.inMaintenanceMode = False
# This host will be the expected result since it has the fewest VMs
mock_host2.vm = ["vm1"]

mock_host3 = mock.MagicMock()
mock_host3.parent.name = "cls1"
mock_host3.parent.parent.parent.name = "dc2"
mock_host3.runtime.powerState = "poweredOn"
mock_host3.runtime.inMaintenanceMode = False
# This host will be the expected result since it has the fewest VMs
mock_host3.vm = ["vm1"]

# Mock a list of 2 hosts that are unavailable
test_host_list = [mock_host1, mock_host2]
test_host_list = [mock_host1, mock_host2, mock_host3]
mock_host_list = mock.MagicMock(view=test_host_list)
mock_entities.return_value = mock_host_list

result = self._action.get_host(test_cluster_name)
result = self._action.get_host(test_datacetner_name, test_cluster_name)

self.assertEqual(result, mock_host2)
mock_entities.assert_called_with(self._action.si_content, test_vim_type)
Expand Down Expand Up @@ -301,6 +312,7 @@ def test_run(self, mock_get_host, mock_get_storage):
test_vsphere = "vsphere"

test_cluster_name = "test-cluster"
test_datacenter_name = "test-datacenter"
test_host_name = "test-host"
test_host_id = "host-123"
test_ds_name = "test-ds"
Expand All @@ -312,6 +324,7 @@ def test_run(self, mock_get_host, mock_get_storage):
mock_host = mock.MagicMock()
type(mock_host).name = mock.PropertyMock(return_value=test_host_name)
mock_host.parent.name = test_cluster_name
mock_host.parent.parent.parent.name = test_datacenter_name
mock_host._moId = test_host_id

mock_get_host.return_value = mock_host
Expand All @@ -328,15 +341,16 @@ def test_run(self, mock_get_host, mock_get_storage):
'datastoreName': test_ds_name,
'datastoreID': test_ds_id}

result = self._action.run(test_cluster_name,
result = self._action.run(test_datacenter_name,
test_cluster_name,
'exclude_matches',
test_ds_filter,
test_disks,
test_vsphere)

self.assertEqual(result, expected_result)
self._action.establish_connection.assert_called_with(test_vsphere)
mock_get_host.assert_called_with(test_cluster_name)
mock_get_host.assert_called_with(test_datacenter_name, test_cluster_name)
mock_get_storage.assert_called_with(mock_host,
'exclude_matches',
test_ds_filter,
Expand Down

0 comments on commit 5977631

Please sign in to comment.