-
Notifications
You must be signed in to change notification settings - Fork 23.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
VMware: Add new module: vmware_host_service_manager (#34862)
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
- Loading branch information
Showing
3 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
222 changes: 222 additions & 0 deletions
222
lib/ansible/modules/cloud/vmware/vmware_host_service_manager.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com> | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
__metaclass__ = type | ||
|
||
|
||
ANSIBLE_METADATA = { | ||
'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'community' | ||
} | ||
|
||
DOCUMENTATION = r''' | ||
--- | ||
module: vmware_host_service_manager | ||
short_description: Manage services on a given ESXi host | ||
description: | ||
- This module can be used to manage (start, stop, restart) services on a given ESXi host. | ||
- If cluster_name is provided, specified service will be managed on all ESXi host belonging to that cluster. | ||
- If specific esxi_hostname is provided, then specified service will be managed on given ESXi host only. | ||
version_added: '2.5' | ||
author: | ||
- Abhijeet Kasurde (@akasurde) | ||
notes: | ||
- Tested on vSphere 6.5 | ||
requirements: | ||
- python >= 2.6 | ||
- PyVmomi | ||
options: | ||
cluster_name: | ||
description: | ||
- Name of the cluster. | ||
- Service settings are applied to every ESXi host system/s in given cluster. | ||
- If C(esxi_hostname) is not given, this parameter is required. | ||
esxi_hostname: | ||
description: | ||
- ESXi hostname. | ||
- Service settings are applied to this ESXi host system. | ||
- If C(cluster_name) is not given, this parameter is required. | ||
state: | ||
description: | ||
- Desired state of service. | ||
- "State value 'start' and 'present' has same effect." | ||
- "State value 'stop' and 'absent' has same effect." | ||
choices: [ absent, present, restart, start, stop ] | ||
service_policy: | ||
description: | ||
- Set of valid service policy strings. | ||
- If set C(on), then service should be started when the host starts up. | ||
- If set C(automatic), then service should run if and only if it has open firewall ports. | ||
- If set C(off), then Service should not be started when the host starts up. | ||
service_name: | ||
description: | ||
- Name of Service to be managed. This is brief identifier for the service, for example, ntpd, vxsyslogd etc. | ||
- This value should be a valid ESXi service name. | ||
required: True | ||
extends_documentation_fragment: vmware.documentation | ||
''' | ||
|
||
EXAMPLES = r''' | ||
- name: Start ntpd service setting for all ESXi Host in given Cluster | ||
vmware_host_service_manager: | ||
hostname: '{{ vcenter_hostname }}' | ||
username: '{{ vcenter_username }}' | ||
password: '{{ vcenter_password }}' | ||
cluster_name: cluster_name | ||
service_name: ntpd | ||
state: present | ||
- name: Start ntpd setting for an ESXi Host | ||
vmware_host_service_manager: | ||
hostname: '{{ vcenter_hostname }}' | ||
username: '{{ vcenter_username }}' | ||
password: '{{ vcenter_password }}' | ||
esxi_hostname: '{{ esxi_hostname }}' | ||
service_name: ntpd | ||
state: present | ||
- name: Start ntpd setting for an ESXi Host with Service policy | ||
vmware_host_service_manager: | ||
hostname: '{{ vcenter_hostname }}' | ||
username: '{{ vcenter_username }}' | ||
password: '{{ vcenter_password }}' | ||
esxi_hostname: '{{ esxi_hostname }}' | ||
service_name: ntpd | ||
service_policy: on | ||
state: present | ||
- name: Stop ntpd setting for an ESXi Host | ||
vmware_host_service_manager: | ||
hostname: '{{ vcenter_hostname }}' | ||
username: '{{ vcenter_username }}' | ||
password: '{{ vcenter_password }}' | ||
esxi_hostname: '{{ esxi_hostname }}' | ||
service_name: ntpd | ||
state: absent | ||
''' | ||
|
||
RETURN = r'''# | ||
''' | ||
|
||
try: | ||
from pyVmomi import vim, vmodl | ||
except ImportError: | ||
pass | ||
|
||
from ansible.module_utils.basic import AnsibleModule | ||
from ansible.module_utils.vmware import vmware_argument_spec, PyVmomi | ||
from ansible.module_utils._text import to_native | ||
|
||
|
||
class VmwareServiceManager(PyVmomi): | ||
def __init__(self, module): | ||
super(VmwareServiceManager, self).__init__(module) | ||
cluster_name = self.params.get('cluster_name', None) | ||
esxi_host_name = self.params.get('esxi_hostname', None) | ||
self.options = self.params.get('options', dict()) | ||
self.hosts = [] | ||
if cluster_name: | ||
cluster_obj = self.find_cluster_by_name(cluster_name=cluster_name) | ||
if cluster_obj: | ||
self.hosts = [host for host in cluster_obj.host] | ||
else: | ||
module.fail_json(changed=False, msg="Cluster '%s' not found" % cluster_name) | ||
elif esxi_host_name: | ||
esxi_host_obj = self.find_hostsystem_by_name(host_name=esxi_host_name) | ||
if esxi_host_obj: | ||
self.hosts = [esxi_host_obj] | ||
else: | ||
module.fail_json(changed=False, msg="ESXi '%s' not found" % esxi_host_name) | ||
self.desired_state = self.params.get('state') | ||
self.desired_policy = self.params.get('service_policy', None) | ||
self.service_name = self.params.get('service_name') | ||
self.results = {} | ||
|
||
def service_ctrl(self): | ||
changed = False | ||
host_service_state = [] | ||
for host in self.hosts: | ||
actual_service_state, actual_service_policy = self.check_service_state(host=host, service_name=self.service_name) | ||
host_service_system = host.configManager.serviceSystem | ||
if host_service_system: | ||
changed_state = False | ||
self.results[host.name] = dict(service_name=self.service_name, | ||
actual_service_state='running' if actual_service_state else 'stopped', | ||
actual_service_policy=actual_service_policy, | ||
desired_service_policy=self.desired_policy, | ||
desired_service_state=self.desired_state, | ||
error='', | ||
) | ||
try: | ||
if self.desired_state in ['start', 'present']: | ||
if not actual_service_state: | ||
host_service_system.StartService(id=self.service_name) | ||
changed_state = True | ||
elif self.desired_state in ['stop', 'absent']: | ||
if actual_service_state: | ||
host_service_system.StopService(id=self.service_name) | ||
changed_state = True | ||
elif self.desired_state == 'restart': | ||
host_service_system.RestartService(id=self.service_name) | ||
changed_state = True | ||
|
||
if self.desired_policy: | ||
if actual_service_policy != self.desired_policy: | ||
host_service_system.UpdateServicePolicy(id=self.service_name, | ||
policy=self.desired_policy) | ||
changed_state = True | ||
|
||
host_service_state.append(changed_state) | ||
self.results[host.name].update(changed=changed_state) | ||
except (vim.fault.InvalidState, vim.fault.NotFound, | ||
vim.fault.HostConfigFault, vmodl.fault.InvalidArgument) as e: | ||
self.results[host.name].update(changed=False, | ||
error=to_native(e.msg)) | ||
|
||
if any(host_service_state): | ||
changed = True | ||
self.module.exit_json(changed=changed, results=self.results) | ||
|
||
def check_service_state(self, host, service_name): | ||
host_service_system = host.configManager.serviceSystem | ||
if host_service_system: | ||
services = host_service_system.serviceInfo.service | ||
for service in services: | ||
if service.key == service_name: | ||
return service.running, service.policy | ||
|
||
msg = "Failed to find '%s' service on host system '%s'" % (service_name, host.name) | ||
cluster_name = self.params.get('cluster_name', None) | ||
if cluster_name: | ||
msg += " located on cluster '%s'" % cluster_name | ||
msg += ", please check if you have specified a valid ESXi service name." | ||
self.module.fail_json(msg=msg) | ||
|
||
|
||
def main(): | ||
argument_spec = vmware_argument_spec() | ||
argument_spec.update( | ||
cluster_name=dict(type='str', required=False), | ||
esxi_hostname=dict(type='str', required=False), | ||
state=dict(type='str', default='start', choices=['absent', 'present', 'restart', 'start', 'stop']), | ||
service_name=dict(type='str', required=True), | ||
service_policy=dict(type='str', choices=['automatic', 'off', 'on']), | ||
) | ||
|
||
module = AnsibleModule( | ||
argument_spec=argument_spec, | ||
required_one_of=[ | ||
['cluster_name', 'esxi_hostname'], | ||
] | ||
) | ||
|
||
vmware_host_service = VmwareServiceManager(module) | ||
vmware_host_service.service_ctrl() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
posix/ci/cloud/group4/vcenter | ||
cloud/vcenter | ||
destructive |
94 changes: 94 additions & 0 deletions
94
test/integration/targets/vmware_host_service_manager/tasks/main.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# Test code for the vmware_host_service_manager module. | ||
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com> | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
# TODO: vcsim does not support service management | ||
# commenting this testcase till the time. | ||
#- name: make sure pyvmomi is installed | ||
# pip: | ||
# name: pyvmomi | ||
# state: latest | ||
# when: "{{ ansible_user_id == 'root' }}" | ||
|
||
#- name: store the vcenter container ip | ||
# set_fact: | ||
# vcsim: "{{ lookup('env', 'vcenter_host') }}" | ||
|
||
#- debug: var=vcsim | ||
|
||
#- name: Wait for Flask controller to come up online | ||
# wait_for: | ||
# host: "{{ vcsim }}" | ||
# port: 5000 | ||
# state: started | ||
|
||
#- name: kill vcsim | ||
# uri: | ||
# url: http://{{ vcsim }}:5000/killall | ||
|
||
#- name: start vcsim | ||
# uri: | ||
# url: http://{{ vcsim }}:5000/spawn?cluster=2 | ||
# register: vcsim_instance | ||
|
||
#- debug: | ||
# var: vcsim_instance | ||
|
||
#- name: Wait for vcsim server to come up online | ||
# wait_for: | ||
# host: "{{ vcsim }}" | ||
# port: 443 | ||
# state: started | ||
|
||
#- name: get a list of Cluster from vcsim | ||
# uri: | ||
# url: http://{{ vcsim }}:5000/govc_find?filter=CCR | ||
# register: clusters | ||
|
||
#- name: get a cluster | ||
# set_fact: | ||
# ccr1: "{{ clusters.json[0] | basename }}" | ||
|
||
#- name: get a list of hosts from vcsim | ||
# uri: | ||
# url: http://{{ vcsim }}:5000/govc_find?filter=H | ||
# register: hosts | ||
|
||
#- name: get a cluster | ||
# set_fact: | ||
# host1: "{{ hosts.json[0] | basename }}" | ||
|
||
#- debug: var=ccr1 | ||
#- debug: var=host1 | ||
|
||
#- name: Start ntpd service on all hosts in given cluster | ||
# vmware_host_service_manager: | ||
# hostname: "{{ vcsim }}" | ||
# username: "{{ vcsim_instance.json.username }}" | ||
# password: "{{ vcsim_instance.json.password }}" | ||
# validate_certs: no | ||
# cluster_name: "{{ ccr1 }}" | ||
# service_name: ntpd | ||
# state: present | ||
# register: all_hosts_result | ||
|
||
#- name: ensure facts are gathered for all hosts | ||
# assert: | ||
# that: | ||
# - all_hosts_result.changed | ||
|
||
#- name: Stop ntpd service on a given host | ||
# vmware_host_service_manager: | ||
# hostname: "{{ vcsim }}" | ||
# username: "{{ vcsim_instance.json.username }}" | ||
# password: "{{ vcsim_instance.json.password }}" | ||
# validate_certs: no | ||
# esxi_hostname: "{{ host1 }}" | ||
# service_name: ntpd | ||
# state: absent | ||
# register: single_hosts_result | ||
|
||
#- name: ensure facts are gathered for all hosts | ||
# assert: | ||
# that: | ||
# - single_hosts_result.changed == False |