Skip to content

Commit aa9d568

Browse files
joechainzJoey Gibson
andauthored
Relocate vm (#194)
* relocate virtual machine * pre commit Co-authored-by: Joey Gibson <jgibson@saltstack.com>
1 parent 64ce630 commit aa9d568

6 files changed

Lines changed: 208 additions & 28 deletions

File tree

src/saltext/vmware/modules/vm.py

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,31 +69,6 @@ def path(vm_name, service_instance=None):
6969
return utils_common.get_path(vm_ref, service_instance)
7070

7171

72-
def _deployment_resources(host_name, service_instance):
73-
"""
74-
Returns the dict representation of deployment resources from given host name.
75-
76-
host_name
77-
The name of the esxi host to obtain esxi reference.
78-
79-
"""
80-
destination_host_ref = utils_common.get_mor_by_property(
81-
service_instance,
82-
vim.HostSystem,
83-
host_name,
84-
)
85-
datacenter_ref = utils_common.get_parent_type(destination_host_ref, vim.Datacenter)
86-
cluster_ref = utils_common.get_parent_type(destination_host_ref, vim.ClusterComputeResource)
87-
resource_pool = cluster_ref.resourcePool
88-
89-
return {
90-
"destination_host": destination_host_ref,
91-
"datacenter": datacenter_ref,
92-
"cluster": cluster_ref,
93-
"resource_pool": resource_pool,
94-
}
95-
96-
9772
def _deploy_ovf(name, host_name, ovf, service_instance=None):
9873
"""
9974
Helper fuctions that takes in a OVF file to create a virtual machine.
@@ -123,7 +98,7 @@ def _deploy_ovf(name, host_name, ovf, service_instance=None):
12398
manager = content.ovfManager
12499
spec_params = vim.OvfManager.CreateImportSpecParams(entityName=name)
125100

126-
resources = _deployment_resources(host_name, service_instance)
101+
resources = utils_common.deployment_resources(host_name, service_instance)
127102

128103
import_spec = manager.CreateImportSpec(
129104
ovf, resources["resource_pool"], resources["destination_host"].datastore[0], spec_params
@@ -212,7 +187,7 @@ def deploy_template(vm_name, template_name, host_name, service_instance=None):
212187
raise salt.exceptions.CommandExecutionError("Template does not exist.")
213188

214189
template = utils_common.get_mor_by_property(service_instance, vim.VirtualMachine, template_name)
215-
resources = _deployment_resources(host_name, service_instance)
190+
resources = utils_common.deployment_resources(host_name, service_instance)
216191

217192
relospec = vim.vm.RelocateSpec()
218193
relospec.pool = resources["resource_pool"]
@@ -512,3 +487,34 @@ def snapshot(vm_name, datacenter_name=None, service_instance=None):
512487
snapshots = utils_vm.get_snapshots(vm_ref)
513488

514489
return {"snapshots": snapshots}
490+
491+
492+
def relocate(vm_name, new_host_name, datastore_name, service_instance=None):
493+
"""
494+
Relocates a virtual machine to the location specified.
495+
496+
vm_name
497+
The name of the virtual machine to relocate.
498+
499+
new_host_name
500+
The name of the host you want to move the virtual machine to.
501+
502+
datastore_name
503+
The name of the datastore you want to move the virtual machine to.
504+
505+
service_instance
506+
(optional) The Service Instance from which to obtain managed object references.
507+
"""
508+
if service_instance is None:
509+
service_instance = connect.get_service_instance(opts=__opts__, pillar=__pillar__)
510+
vm_ref = utils_common.get_mor_by_property(service_instance, vim.VirtualMachine, vm_name)
511+
resources = utils_common.deployment_resources(new_host_name, service_instance)
512+
datastore_ref = utils_common.get_datastore(
513+
datastore_name, resources["datacenter"], service_instance
514+
)
515+
ret = utils_vm.relocate(
516+
vm_ref, resources["destination_host"], datastore_ref, resources["resource_pool"]
517+
)
518+
if ret == "success":
519+
return {"virtual_machine": "moved"}
520+
return {"virtual_machine": "failed to move"}

src/saltext/vmware/states/vm.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,50 @@ def snapshot_absent(
214214
ret["changes"]["result"] = False
215215
ret["comment"] = str(e)
216216
return ret
217+
218+
219+
def relocate(name, new_host_name, datastore_name, service_instance=None):
220+
"""
221+
Relocates a virtual machine to the location specified.
222+
223+
name
224+
The name of the virtual machine to relocate.
225+
226+
new_host_name
227+
The name of the host you want to move the virtual machine to.
228+
229+
datastore_name
230+
The name of the datastore you want to move the virtual machine to.
231+
232+
service_instance
233+
(optional) The Service Instance from which to obtain managed object references.
234+
"""
235+
if service_instance is None:
236+
service_instance = connect.get_service_instance(opts=__opts__, pillar=__pillar__)
237+
ret = {"name": name, "changes": {}, "result": True, "comment": ""}
238+
vm_ref = utils_common.get_mor_by_property(service_instance, vim.VirtualMachine, name)
239+
datastore_match = False
240+
for ds in vm_ref.datastore:
241+
if ds.name == datastore_name:
242+
datastore_match = True
243+
if datastore_match and vm_ref.runtime.host.name == new_host_name:
244+
ret["comment"] = f"{name} virtual machine is already on host {new_host_name}"
245+
return ret
246+
resources = utils_common.deployment_resources(new_host_name, service_instance)
247+
datastore_ref = utils_common.get_datastore(
248+
datastore_name, resources["datacenter"], service_instance
249+
)
250+
if __opts__["test"]:
251+
ret["changes"]["new"] = f"{name} virtual machine will be moved to host {new_host_name}"
252+
ret["comment"] = "These options are set to change."
253+
return ret
254+
relo = utils_vm.relocate(
255+
vm_ref, resources["destination_host"], datastore_ref, resources["resource_pool"]
256+
)
257+
if relo == "success":
258+
ret["changes"]["new"] = f"{name} virtual machine was moved to host {new_host_name}"
259+
ret["comment"] = "moved"
260+
return ret
261+
ret["changes"]["result"] = False
262+
ret["comment"] = "failed to move"
263+
return ret

src/saltext/vmware/utils/common.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,3 +872,28 @@ def list_license_mgrs(service_instance):
872872
"""
873873
log.debug("start list of License Managers")
874874
return list_objects(service_instance, vim.LicenseAssignmentManager)
875+
876+
877+
def deployment_resources(host_name, service_instance):
878+
"""
879+
Returns the dict representation of deployment resources from given host name.
880+
881+
host_name
882+
The name of the esxi host to obtain esxi reference.
883+
884+
"""
885+
destination_host_ref = get_mor_by_property(
886+
service_instance,
887+
vim.HostSystem,
888+
host_name,
889+
)
890+
datacenter_ref = get_parent_type(destination_host_ref, vim.Datacenter)
891+
cluster_ref = get_parent_type(destination_host_ref, vim.ClusterComputeResource)
892+
resource_pool = cluster_ref.resourcePool
893+
894+
return {
895+
"destination_host": destination_host_ref,
896+
"datacenter": datacenter_ref,
897+
"cluster": cluster_ref,
898+
"resource_pool": resource_pool,
899+
}

src/saltext/vmware/utils/vm.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,3 +911,25 @@ def destroy_snapshot(snapshot, remove_children):
911911
task = snapshot.RemoveSnapshot_Task(remove_children)
912912
ret = utils_common.wait_for_task(task, vm_name, "remove snapshot")
913913
return ret
914+
915+
916+
def relocate(vm, host, datastore, pool):
917+
"""
918+
Relocates a virtual machine to the location specified.
919+
920+
vm
921+
Reference to virtual machine.
922+
923+
host
924+
Reference to new host.
925+
926+
datastore
927+
Reference to datastore
928+
929+
Pool
930+
Reference to resource pool.
931+
"""
932+
relocate_spec = vim.vm.RelocateSpec(host=host, datastore=datastore, pool=pool)
933+
task = vm.RelocateVM_Task(relocate_spec)
934+
utils_common.wait_for_task(task, vm.name, "move vm")
935+
return task.info.state

tests/integration/modules/test_vm.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@
44
import tarfile
55

66
import pytest
7-
import salt.exceptions
7+
import saltext.vmware.modules.esxi as esxi
88
import saltext.vmware.modules.vm as virtual_machine
9+
import saltext.vmware.utils.common as utils_common
10+
11+
try:
12+
from pyVmomi import vim
13+
14+
HAS_PYVMOMI = True
15+
except ImportError:
16+
HAS_PYVMOMI = False
917

1018

1119
@pytest.mark.parametrize(
@@ -172,3 +180,25 @@ def test_destroy_snapshot(integration_test_config, patch_salt_globals_vm):
172180
assert res["snapshot"] == "destroyed"
173181
else:
174182
pytest.skip("test requires at least one virtual machine")
183+
184+
185+
def test_relocate(patch_salt_globals_vm, service_instance):
186+
"""
187+
Test relocate virtual machine.
188+
"""
189+
hosts = esxi.list_hosts(service_instance=service_instance)
190+
if len(hosts) >= 2:
191+
temp = virtual_machine.list_templates()
192+
if temp:
193+
virtual_machine.deploy_template(
194+
vm_name="test_move_vm",
195+
template_name=temp[0],
196+
host_name=hosts[0],
197+
)
198+
host = utils_common.get_mor_by_property(service_instance, vim.HostSystem, hosts[1])
199+
res = virtual_machine.relocate("test_move_vm", host.name, host.datastore[0].name)
200+
assert res["virtual_machine"] == "moved"
201+
else:
202+
pytest.skip("test requires at least one template")
203+
else:
204+
pytest.skip("test requires at least two hosts")

tests/integration/states/test_vm.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
# Copyright 2021 VMware, Inc.
22
# SPDX-License-Identifier: Apache-2.0
33
import pytest
4+
import saltext.vmware.modules.esxi as esxi
5+
import saltext.vmware.modules.vm as vmm
46
import saltext.vmware.states.vm as virtual_machine
7+
import saltext.vmware.utils.common as utils_common
8+
9+
try:
10+
from pyVmomi import vim
11+
12+
HAS_PYVMOMI = True
13+
except ImportError:
14+
HAS_PYVMOMI = False
515

616

717
def test_set_boot_manager_dry(integration_test_config, patch_salt_globals_vm_state_test):
@@ -69,3 +79,43 @@ def test_snapshot_absent(integration_test_config, patch_salt_globals_vm_state):
6979
assert ret["comment"] == "destroyed"
7080
else:
7181
pytest.skip("test requires at least one virtual machine")
82+
83+
84+
def test_relocate_with_test(patch_salt_globals_vm_state_test, service_instance):
85+
"""
86+
test relocate virtual machine functionality with test equals true
87+
"""
88+
hosts = esxi.list_hosts(service_instance=service_instance)
89+
if len(hosts) >= 2:
90+
temp = vmm.list_templates(service_instance=service_instance)
91+
if temp:
92+
vmm.deploy_template(
93+
vm_name="test_move_vm_state",
94+
template_name=temp[0],
95+
host_name=hosts[0],
96+
service_instance=service_instance,
97+
)
98+
host = utils_common.get_mor_by_property(service_instance, vim.HostSystem, hosts[1])
99+
res = virtual_machine.relocate("test_move_vm_state", host.name, host.datastore[0].name)
100+
assert res["comment"] == "These options are set to change."
101+
else:
102+
pytest.skip("test requires at least one template")
103+
else:
104+
pytest.skip("test requires at least two hosts")
105+
106+
107+
def test_relocate(patch_salt_globals_vm_state, service_instance):
108+
"""
109+
test relocate virtual machine functionality
110+
"""
111+
hosts = esxi.list_hosts(service_instance=service_instance)
112+
if len(hosts) >= 2:
113+
temp = vmm.list_templates(service_instance=service_instance)
114+
if temp:
115+
host = utils_common.get_mor_by_property(service_instance, vim.HostSystem, hosts[1])
116+
res = virtual_machine.relocate("test_move_vm_state", host.name, host.datastore[0].name)
117+
assert res["comment"] == "moved"
118+
else:
119+
pytest.skip("test requires at least one template")
120+
else:
121+
pytest.skip("test requires at least two hosts")

0 commit comments

Comments
 (0)