mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-23 13:20:23 -07:00
Relocating extras into lib/ansible/modules/ after merge
This commit is contained in:
parent
c65ba07d2c
commit
011ea55a8f
596 changed files with 0 additions and 266 deletions
249
lib/ansible/modules/cloud/vmware/vca_fw.py
Normal file
249
lib/ansible/modules/cloud/vmware/vca_fw.py
Normal file
|
@ -0,0 +1,249 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vca_fw
|
||||
short_description: add remove firewall rules in a gateway in a vca
|
||||
description:
|
||||
- Adds or removes firewall rules from a gateway in a vca environment
|
||||
version_added: "2.0"
|
||||
author: Peter Sprygada (@privateip)
|
||||
options:
|
||||
fw_rules:
|
||||
description:
|
||||
- A list of firewall rules to be added to the gateway, Please see examples on valid entries
|
||||
required: True
|
||||
default: false
|
||||
extends_documentation_fragment: vca.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
#Add a set of firewall rules
|
||||
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- vca_fw:
|
||||
instance_id: 'b15ff1e5-1024-4f55-889f-ea0209726282'
|
||||
vdc_name: 'benz_ansible'
|
||||
state: 'absent'
|
||||
fw_rules:
|
||||
- description: "ben testing"
|
||||
source_ip: "Any"
|
||||
dest_ip: 192.0.2.23
|
||||
- description: "ben testing 2"
|
||||
source_ip: 192.0.2.50
|
||||
source_port: "Any"
|
||||
dest_port: "22"
|
||||
dest_ip: 192.0.2.101
|
||||
is_enable: "true"
|
||||
enable_logging: "false"
|
||||
protocol: "Tcp"
|
||||
policy: "allow"
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyvcloud.schema.vcd.v1_5.schemas.vcloud.networkType import FirewallRuleType
|
||||
from pyvcloud.schema.vcd.v1_5.schemas.vcloud.networkType import ProtocolsType
|
||||
except ImportError:
|
||||
# normally set a flag here but it will be caught when testing for
|
||||
# the existence of pyvcloud (see module_utils/vca.py). This just
|
||||
# protects against generating an exception at runtime
|
||||
pass
|
||||
|
||||
VALID_PROTO = ['Tcp', 'Udp', 'Icmp', 'Other', 'Any']
|
||||
VALID_RULE_KEYS = ['policy', 'is_enable', 'enable_logging', 'description',
|
||||
'dest_ip', 'dest_port', 'source_ip', 'source_port',
|
||||
'protocol']
|
||||
|
||||
def protocol_to_tuple(protocol):
|
||||
return (protocol.get_Tcp(),
|
||||
protocol.get_Udp(),
|
||||
protocol.get_Icmp(),
|
||||
protocol.get_Other(),
|
||||
protocol.get_Any())
|
||||
|
||||
def protocol_to_string(protocol):
|
||||
protocol = protocol_to_tuple(protocol)
|
||||
if protocol[0] is True:
|
||||
return 'Tcp'
|
||||
elif protocol[1] is True:
|
||||
return 'Udp'
|
||||
elif protocol[2] is True:
|
||||
return 'Icmp'
|
||||
elif protocol[3] is True:
|
||||
return 'Other'
|
||||
elif protocol[4] is True:
|
||||
return 'Any'
|
||||
|
||||
def protocol_to_type(protocol):
|
||||
try:
|
||||
protocols = ProtocolsType()
|
||||
setattr(protocols, protocol, True)
|
||||
return protocols
|
||||
except AttributeError:
|
||||
raise VcaError("The value in protocol is not valid")
|
||||
|
||||
def validate_fw_rules(fw_rules):
|
||||
for rule in fw_rules:
|
||||
for k in rule.keys():
|
||||
if k not in VALID_RULE_KEYS:
|
||||
raise VcaError("%s is not a valid key in fw rules, please "
|
||||
"check above.." % k, valid_keys=VALID_RULE_KEYS)
|
||||
|
||||
rule['dest_port'] = str(rule.get('dest_port', 'Any')).lower()
|
||||
rule['dest_ip'] = rule.get('dest_ip', 'Any').lower()
|
||||
rule['source_port'] = str(rule.get('source_port', 'Any')).lower()
|
||||
rule['source_ip'] = rule.get('source_ip', 'Any').lower()
|
||||
rule['protocol'] = rule.get('protocol', 'Any').lower()
|
||||
rule['policy'] = rule.get('policy', 'allow').lower()
|
||||
rule['is_enable'] = rule.get('is_enable', True)
|
||||
rule['enable_logging'] = rule.get('enable_logging', False)
|
||||
rule['description'] = rule.get('description', 'rule added by Ansible')
|
||||
|
||||
return fw_rules
|
||||
|
||||
def fw_rules_to_dict(rules):
|
||||
fw_rules = list()
|
||||
for rule in rules:
|
||||
fw_rules.append(
|
||||
dict(
|
||||
dest_port=rule.get_DestinationPortRange().lower(),
|
||||
dest_ip=rule.get_DestinationIp().lower().lower(),
|
||||
source_port=rule.get_SourcePortRange().lower(),
|
||||
source_ip=rule.get_SourceIp().lower(),
|
||||
protocol=protocol_to_string(rule.get_Protocols()).lower(),
|
||||
policy=rule.get_Policy().lower(),
|
||||
is_enable=rule.get_IsEnabled(),
|
||||
enable_logging=rule.get_EnableLogging(),
|
||||
description=rule.get_Description()
|
||||
)
|
||||
)
|
||||
return fw_rules
|
||||
|
||||
def create_fw_rule(is_enable, description, policy, protocol, dest_port,
|
||||
dest_ip, source_port, source_ip, enable_logging):
|
||||
|
||||
return FirewallRuleType(IsEnabled=is_enable,
|
||||
Description=description,
|
||||
Policy=policy,
|
||||
Protocols=protocol_to_type(protocol),
|
||||
DestinationPortRange=dest_port,
|
||||
DestinationIp=dest_ip,
|
||||
SourcePortRange=source_port,
|
||||
SourceIp=source_ip,
|
||||
EnableLogging=enable_logging)
|
||||
|
||||
def main():
|
||||
argument_spec = vca_argument_spec()
|
||||
argument_spec.update(
|
||||
dict(
|
||||
fw_rules = dict(required=True, type='list'),
|
||||
gateway_name = dict(default='gateway'),
|
||||
state = dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
)
|
||||
|
||||
module = AnsibleModule(argument_spec, supports_check_mode=True)
|
||||
|
||||
fw_rules = module.params.get('fw_rules')
|
||||
gateway_name = module.params.get('gateway_name')
|
||||
vdc_name = module.params['vdc_name']
|
||||
|
||||
vca = vca_login(module)
|
||||
|
||||
gateway = vca.get_gateway(vdc_name, gateway_name)
|
||||
if not gateway:
|
||||
module.fail_json(msg="Not able to find the gateway %s, please check "
|
||||
"the gateway_name param" % gateway_name)
|
||||
|
||||
fwservice = gateway._getFirewallService()
|
||||
|
||||
rules = gateway.get_fw_rules()
|
||||
current_rules = fw_rules_to_dict(rules)
|
||||
|
||||
try:
|
||||
desired_rules = validate_fw_rules(fw_rules)
|
||||
except VcaError as e:
|
||||
module.fail_json(msg=e.message)
|
||||
|
||||
result = dict(changed=False)
|
||||
result['current_rules'] = current_rules
|
||||
result['desired_rules'] = desired_rules
|
||||
|
||||
updates = list()
|
||||
additions = list()
|
||||
deletions = list()
|
||||
|
||||
for (index, rule) in enumerate(desired_rules):
|
||||
try:
|
||||
if rule != current_rules[index]:
|
||||
updates.append((index, rule))
|
||||
except IndexError:
|
||||
additions.append(rule)
|
||||
|
||||
eol = len(current_rules) > len(desired_rules)
|
||||
if eol > 0:
|
||||
for rule in current_rules[eos:]:
|
||||
deletions.append(rule)
|
||||
|
||||
for rule in additions:
|
||||
if not module.check_mode:
|
||||
rule['protocol'] = rule['protocol'].capitalize()
|
||||
gateway.add_fw_rule(**rule)
|
||||
result['changed'] = True
|
||||
|
||||
for index, rule in updates:
|
||||
if not module.check_mode:
|
||||
rule = create_fw_rule(**rule)
|
||||
fwservice.replace_FirewallRule_at(index, rule)
|
||||
result['changed'] = True
|
||||
|
||||
keys = ['protocol', 'dest_port', 'dest_ip', 'source_port', 'source_ip']
|
||||
for rule in deletions:
|
||||
if not module.check_mode:
|
||||
kwargs = dict([(k, v) for k, v in rule.items() if k in keys])
|
||||
kwargs['protocol'] = protocol_to_string(kwargs['protocol'])
|
||||
gateway.delete_fw_rule(**kwargs)
|
||||
result['changed'] = True
|
||||
|
||||
if not module.check_mode and result['changed'] == True:
|
||||
task = gateway.save_services_configuration()
|
||||
if task:
|
||||
vca.block_until_completed(task)
|
||||
|
||||
result['rules_updated'] = count=len(updates)
|
||||
result['rules_added'] = count=len(additions)
|
||||
result['rules_deleted'] = count=len(deletions)
|
||||
|
||||
return module.exit_json(**result)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.vca import *
|
||||
if __name__ == '__main__':
|
||||
main()
|
219
lib/ansible/modules/cloud/vmware/vca_nat.py
Normal file
219
lib/ansible/modules/cloud/vmware/vca_nat.py
Normal file
|
@ -0,0 +1,219 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vca_nat
|
||||
short_description: add remove nat rules in a gateway in a vca
|
||||
description:
|
||||
- Adds or removes nat rules from a gateway in a vca environment
|
||||
version_added: "2.0"
|
||||
author: Peter Sprygada (@privateip)
|
||||
options:
|
||||
purge_rules:
|
||||
description:
|
||||
- If set to true, it will delete all rules in the gateway that are not given as paramter to this module.
|
||||
required: false
|
||||
default: false
|
||||
nat_rules:
|
||||
description:
|
||||
- A list of rules to be added to the gateway, Please see examples on valid entries
|
||||
required: True
|
||||
default: false
|
||||
extends_documentation_fragment: vca.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
#An example for a source nat
|
||||
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- vca_nat:
|
||||
instance_id: 'b15ff1e5-1024-4f55-889f-ea0209726282'
|
||||
vdc_name: 'benz_ansible'
|
||||
state: 'present'
|
||||
nat_rules:
|
||||
- rule_type: SNAT
|
||||
original_ip: 192.0.2.42
|
||||
translated_ip: 203.0.113.23
|
||||
|
||||
#example for a DNAT
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
tasks:
|
||||
- vca_nat:
|
||||
instance_id: 'b15ff1e5-1024-4f55-889f-ea0209726282'
|
||||
vdc_name: 'benz_ansible'
|
||||
state: 'present'
|
||||
nat_rules:
|
||||
- rule_type: DNAT
|
||||
original_ip: 203.0.113.23
|
||||
original_port: 22
|
||||
translated_ip: 192.0.2.42
|
||||
translated_port: 22
|
||||
|
||||
'''
|
||||
|
||||
import time
|
||||
import xmltodict
|
||||
|
||||
VALID_RULE_KEYS = ['rule_type', 'original_ip', 'original_port',
|
||||
'translated_ip', 'translated_port', 'protocol']
|
||||
|
||||
|
||||
def validate_nat_rules(nat_rules):
|
||||
for rule in nat_rules:
|
||||
if not isinstance(rule, dict):
|
||||
raise VcaError("nat rules must be a list of dictionaries, "
|
||||
"Please check", valid_keys=VALID_RULE_KEYS)
|
||||
|
||||
for k in rule.keys():
|
||||
if k not in VALID_RULE_KEYS:
|
||||
raise VcaError("%s is not a valid key in nat rules, please "
|
||||
"check above.." % k, valid_keys=VALID_RULE_KEYS)
|
||||
|
||||
rule['original_port'] = str(rule.get('original_port', 'any')).lower()
|
||||
rule['original_ip'] = rule.get('original_ip', 'any').lower()
|
||||
rule['translated_ip'] = rule.get('translated_ip', 'any').lower()
|
||||
rule['translated_port'] = str(rule.get('translated_port', 'any')).lower()
|
||||
rule['protocol'] = rule.get('protocol', 'any').lower()
|
||||
rule['rule_type'] = rule.get('rule_type', 'DNAT').lower()
|
||||
|
||||
return nat_rules
|
||||
|
||||
|
||||
def nat_rules_to_dict(nat_rules):
|
||||
result = []
|
||||
for rule in nat_rules:
|
||||
gw_rule = rule.get_GatewayNatRule()
|
||||
result.append(
|
||||
dict(
|
||||
rule_type=rule.get_RuleType().lower(),
|
||||
original_ip=gw_rule.get_OriginalIp().lower(),
|
||||
original_port=(gw_rule.get_OriginalPort().lower() or 'any'),
|
||||
translated_ip=gw_rule.get_TranslatedIp().lower(),
|
||||
translated_port=(gw_rule.get_TranslatedPort().lower() or 'any'),
|
||||
protocol=(gw_rule.get_Protocol().lower() or 'any')
|
||||
)
|
||||
)
|
||||
return result
|
||||
|
||||
def rule_to_string(rule):
|
||||
strings = list()
|
||||
for key, value in rule.items():
|
||||
strings.append('%s=%s' % (key, value))
|
||||
return ', '.join(string)
|
||||
|
||||
def main():
|
||||
argument_spec = vca_argument_spec()
|
||||
argument_spec.update(
|
||||
dict(
|
||||
nat_rules = dict(type='list', default=[]),
|
||||
gateway_name = dict(default='gateway'),
|
||||
purge_rules = dict(default=False, type='bool'),
|
||||
state = dict(default='present', choices=['present', 'absent'])
|
||||
)
|
||||
)
|
||||
|
||||
module = AnsibleModule(argument_spec, supports_check_mode=True)
|
||||
|
||||
vdc_name = module.params.get('vdc_name')
|
||||
state = module.params['state']
|
||||
nat_rules = module.params['nat_rules']
|
||||
gateway_name = module.params['gateway_name']
|
||||
purge_rules = module.params['purge_rules']
|
||||
|
||||
if not purge_rules and not nat_rules:
|
||||
module.fail_json(msg='Must define purge_rules or nat_rules')
|
||||
|
||||
vca = vca_login(module)
|
||||
|
||||
gateway = vca.get_gateway(vdc_name, gateway_name)
|
||||
if not gateway:
|
||||
module.fail_json(msg="Not able to find the gateway %s, please check "
|
||||
"the gateway_name param" % gateway_name)
|
||||
|
||||
try:
|
||||
desired_rules = validate_nat_rules(nat_rules)
|
||||
except VcaError as e:
|
||||
module.fail_json(msg=e.message)
|
||||
|
||||
rules = gateway.get_nat_rules()
|
||||
|
||||
result = dict(changed=False, rules_purged=0)
|
||||
|
||||
deletions = 0
|
||||
additions = 0
|
||||
|
||||
if purge_rules is True and len(rules) > 0:
|
||||
result['rules_purged'] = len(rules)
|
||||
deletions = result['rules_purged']
|
||||
rules = list()
|
||||
if not module.check_mode:
|
||||
gateway.del_all_nat_rules()
|
||||
task = gateway.save_services_configuration()
|
||||
vca.block_until_completed(task)
|
||||
rules = gateway.get_nat_rules()
|
||||
result['changed'] = True
|
||||
|
||||
current_rules = nat_rules_to_dict(rules)
|
||||
|
||||
result['current_rules'] = current_rules
|
||||
result['desired_rules'] = desired_rules
|
||||
|
||||
for rule in desired_rules:
|
||||
if rule not in current_rules:
|
||||
additions += 1
|
||||
if not module.check_mode:
|
||||
gateway.add_nat_rule(**rule)
|
||||
result['changed'] = True
|
||||
result['rules_added'] = additions
|
||||
|
||||
result['delete_rule'] = list()
|
||||
result['delete_rule_rc'] = list()
|
||||
for rule in current_rules:
|
||||
if rule not in desired_rules:
|
||||
deletions += 1
|
||||
if not module.check_mode:
|
||||
result['delete_rule'].append(rule)
|
||||
rc = gateway.del_nat_rule(**rule)
|
||||
result['delete_rule_rc'].append(rc)
|
||||
result['changed'] = True
|
||||
result['rules_deleted'] = deletions
|
||||
|
||||
if not module.check_mode and (additions > 0 or deletions > 0):
|
||||
task = gateway.save_services_configuration()
|
||||
vca.block_until_completed(task)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.vca import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
286
lib/ansible/modules/cloud/vmware/vca_vapp.py
Normal file
286
lib/ansible/modules/cloud/vmware/vca_vapp.py
Normal file
|
@ -0,0 +1,286 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright (c) 2015 Ansible, Inc.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vca_vapp
|
||||
short_description: Manages vCloud Air vApp instances.
|
||||
description:
|
||||
- This module will actively managed vCloud Air vApp instances. Instances
|
||||
can be created and deleted as well as both deployed and undeployed.
|
||||
version_added: "2.0"
|
||||
author: Peter Sprygada (@privateip)
|
||||
options:
|
||||
vapp_name:
|
||||
description:
|
||||
- The name of the vCloud Air vApp instance
|
||||
required: yes
|
||||
template_name:
|
||||
description:
|
||||
- The name of the vApp template to use to create the vApp instance. If
|
||||
the I(state) is not `absent` then the I(template_name) value must be
|
||||
provided. The I(template_name) must be previously uploaded to the
|
||||
catalog specified by I(catalog_name)
|
||||
required: no
|
||||
default: None
|
||||
network_name:
|
||||
description:
|
||||
- The name of the network that should be attached to the virtual machine
|
||||
in the vApp. The virtual network specified must already be created in
|
||||
the vCloud Air VDC. If the I(state) is not 'absent' then the
|
||||
I(network_name) argument must be provided.
|
||||
required: no
|
||||
default: None
|
||||
network_mode:
|
||||
description:
|
||||
- Configures the mode of the network connection.
|
||||
required: no
|
||||
default: pool
|
||||
choices: ['pool', 'dhcp', 'static']
|
||||
vm_name:
|
||||
description:
|
||||
- The name of the virtual machine instance in the vApp to manage.
|
||||
required: no
|
||||
default: None
|
||||
vm_cpus:
|
||||
description:
|
||||
- The number of vCPUs to configure for the VM in the vApp. If the
|
||||
I(vm_name) argument is provided, then this becomes a per VM setting
|
||||
otherwise it is applied to all VMs in the vApp.
|
||||
required: no
|
||||
default: None
|
||||
vm_memory:
|
||||
description:
|
||||
- The amount of memory in MB to allocate to VMs in the vApp. If the
|
||||
I(vm_name) argument is provided, then this becomes a per VM setting
|
||||
otherise it is applied to all VMs in the vApp.
|
||||
required: no
|
||||
default: None
|
||||
operation:
|
||||
description:
|
||||
- Specifies an operation to be performed on the vApp.
|
||||
required: no
|
||||
default: noop
|
||||
choices: ['noop', 'poweron', 'poweroff', 'suspend', 'shutdown', 'reboot', 'reset']
|
||||
state:
|
||||
description:
|
||||
- Configures the state of the vApp.
|
||||
required: no
|
||||
default: present
|
||||
choices: ['present', 'absent', 'deployed', 'undeployed']
|
||||
username:
|
||||
description:
|
||||
- The vCloud Air username to use during authentication
|
||||
required: false
|
||||
default: None
|
||||
password:
|
||||
description:
|
||||
- The vCloud Air password to use during authentication
|
||||
required: false
|
||||
default: None
|
||||
org:
|
||||
description:
|
||||
- The org to login to for creating vapp, mostly set when the service_type is vdc.
|
||||
required: false
|
||||
default: None
|
||||
instance_id:
|
||||
description:
|
||||
- The instance id in a vchs environment to be used for creating the vapp
|
||||
required: false
|
||||
default: None
|
||||
host:
|
||||
description:
|
||||
- The authentication host to be used when service type is vcd.
|
||||
required: false
|
||||
default: None
|
||||
api_version:
|
||||
description:
|
||||
- The api version to be used with the vca
|
||||
required: false
|
||||
default: "5.7"
|
||||
service_type:
|
||||
description:
|
||||
- The type of service we are authenticating against
|
||||
required: false
|
||||
default: vca
|
||||
choices: [ "vca", "vchs", "vcd" ]
|
||||
vdc_name:
|
||||
description:
|
||||
- The name of the virtual data center (VDC) where the vm should be created or contains the vAPP.
|
||||
required: false
|
||||
default: None
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
|
||||
- name: Creates a new vApp in a VCA instance
|
||||
vca_vapp:
|
||||
vapp_name: tower
|
||||
state=present
|
||||
template_name='Ubuntu Server 12.04 LTS (amd64 20150127)'
|
||||
vdc_name=VDC1
|
||||
instance_id=<your instance id here>
|
||||
username=<your username here>
|
||||
password=<your password here>
|
||||
|
||||
'''
|
||||
|
||||
DEFAULT_VAPP_OPERATION = 'noop'
|
||||
|
||||
VAPP_STATUS = {
|
||||
'Powered off': 'poweroff',
|
||||
'Powered on': 'poweron',
|
||||
'Suspended': 'suspend'
|
||||
}
|
||||
|
||||
VAPP_STATES = ['present', 'absent', 'deployed', 'undeployed']
|
||||
VAPP_OPERATIONS = ['poweron', 'poweroff', 'suspend', 'shutdown',
|
||||
'reboot', 'reset', 'noop']
|
||||
|
||||
|
||||
def get_instance(module):
|
||||
vapp_name = module.params['vapp_name']
|
||||
inst = dict(vapp_name=vapp_name, state='absent')
|
||||
try:
|
||||
vapp = module.get_vapp(vapp_name)
|
||||
if vapp:
|
||||
status = module.vca.get_status(vapp.me.get_status())
|
||||
inst['status'] = VAPP_STATUS.get(status, 'unknown')
|
||||
inst['state'] = 'deployed' if vapp.me.deployed else 'undeployed'
|
||||
return inst
|
||||
except VcaError:
|
||||
return inst
|
||||
|
||||
def create(module):
|
||||
vdc_name = module.params['vdc_name']
|
||||
vapp_name = module.params['vapp_name']
|
||||
template_name = module.params['template_name']
|
||||
catalog_name = module.params['catalog_name']
|
||||
network_name = module.params['network_name']
|
||||
network_mode = module.params['network_mode']
|
||||
vm_name = module.params['vm_name']
|
||||
vm_cpus = module.params['vm_cpus']
|
||||
vm_memory = module.params['vm_memory']
|
||||
deploy = module.params['state'] == 'deploy'
|
||||
poweron = module.params['operation'] == 'poweron'
|
||||
|
||||
task = module.vca.create_vapp(vdc_name, vapp_name, template_name,
|
||||
catalog_name, network_name, network_mode,
|
||||
vm_name, vm_cpus, vm_memory, deploy, poweron)
|
||||
|
||||
module.vca.block_until_completed(task)
|
||||
|
||||
def delete(module):
|
||||
vdc_name = module.params['vdc_name']
|
||||
vapp_name = module.params['vapp_name']
|
||||
module.vca.delete_vapp(vdc_name, vapp_name)
|
||||
|
||||
def do_operation(module):
|
||||
vapp_name = module.params['vapp_name']
|
||||
operation = module.params['operation']
|
||||
|
||||
vm_name = module.params.get('vm_name')
|
||||
vm = None
|
||||
if vm_name:
|
||||
vm = module.get_vm(vapp_name, vm_name)
|
||||
|
||||
if operation == 'poweron':
|
||||
operation = 'powerOn'
|
||||
elif operation == 'poweroff':
|
||||
operation = 'powerOff'
|
||||
|
||||
cmd = 'power:%s' % operation
|
||||
module.get_vapp(vapp_name).execute(cmd, 'post', targetVM=vm)
|
||||
|
||||
def set_state(module):
|
||||
state = module.params['state']
|
||||
vapp = module.get_vapp(module.params['vapp_name'])
|
||||
if state == 'deployed':
|
||||
action = module.params['operation'] == 'poweron'
|
||||
if not vapp.deploy(action):
|
||||
module.fail('unable to deploy vapp')
|
||||
elif state == 'undeployed':
|
||||
action = module.params['operation']
|
||||
if action == 'poweroff':
|
||||
action = 'powerOff'
|
||||
elif action != 'suspend':
|
||||
action = None
|
||||
if not vapp.undeploy(action):
|
||||
module.fail('unable to undeploy vapp')
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = dict(
|
||||
vapp_name=dict(required=True),
|
||||
vdc_name=dict(required=True),
|
||||
template_name=dict(),
|
||||
catalog_name=dict(default='Public Catalog'),
|
||||
network_name=dict(),
|
||||
network_mode=dict(default='pool', choices=['dhcp', 'static', 'pool']),
|
||||
vm_name=dict(),
|
||||
vm_cpus=dict(),
|
||||
vm_memory=dict(),
|
||||
operation=dict(default=DEFAULT_VAPP_OPERATION, choices=VAPP_OPERATIONS),
|
||||
state=dict(default='present', choices=VAPP_STATES)
|
||||
)
|
||||
|
||||
module = VcaAnsibleModule(argument_spec=argument_spec,
|
||||
supports_check_mode=True)
|
||||
|
||||
state = module.params['state']
|
||||
operation = module.params['operation']
|
||||
|
||||
instance = get_instance(module)
|
||||
|
||||
result = dict(changed=False)
|
||||
|
||||
if instance and state == 'absent':
|
||||
if not module.check_mode:
|
||||
delete(module)
|
||||
result['changed'] = True
|
||||
|
||||
elif state != 'absent':
|
||||
if instance['state'] == 'absent':
|
||||
if not module.check_mode:
|
||||
create(module)
|
||||
result['changed'] = True
|
||||
|
||||
elif instance['state'] != state and state != 'present':
|
||||
if not module.check_mode:
|
||||
set_state(module)
|
||||
result['changed'] = True
|
||||
|
||||
if operation != instance.get('status') and operation != 'noop':
|
||||
if not module.check_mode:
|
||||
do_operation(module)
|
||||
result['changed'] = True
|
||||
|
||||
return module.exit(**result)
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.vca import *
|
||||
if __name__ == '__main__':
|
||||
main()
|
255
lib/ansible/modules/cloud/vmware/vmware_cluster.py
Normal file
255
lib/ansible/modules/cloud/vmware/vmware_cluster.py
Normal file
|
@ -0,0 +1,255 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_cluster
|
||||
short_description: Create VMware vSphere Cluster
|
||||
description:
|
||||
- Create VMware vSphere Cluster
|
||||
version_added: 2.0
|
||||
author: Joseph Callen (@jcpowermac)
|
||||
notes:
|
||||
requirements:
|
||||
- Tested on ESXi 5.5
|
||||
- PyVmomi installed
|
||||
options:
|
||||
datacenter_name:
|
||||
description:
|
||||
- The name of the datacenter the cluster will be created in.
|
||||
required: True
|
||||
cluster_name:
|
||||
description:
|
||||
- The name of the cluster that will be created
|
||||
required: True
|
||||
enable_ha:
|
||||
description:
|
||||
- If set to True will enable HA when the cluster is created.
|
||||
required: False
|
||||
default: False
|
||||
enable_drs:
|
||||
description:
|
||||
- If set to True will enable DRS when the cluster is created.
|
||||
required: False
|
||||
default: False
|
||||
enable_vsan:
|
||||
description:
|
||||
- If set to True will enable vSAN when the cluster is created.
|
||||
required: False
|
||||
default: False
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example vmware_cluster command from Ansible Playbooks
|
||||
- name: Create Cluster
|
||||
local_action: >
|
||||
vmware_cluster
|
||||
hostname="{{ ansible_ssh_host }}" username=root password=vmware
|
||||
datacenter_name="datacenter"
|
||||
cluster_name="cluster"
|
||||
enable_ha=True
|
||||
enable_drs=True
|
||||
enable_vsan=True
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
class VMwareCluster(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.enable_ha = module.params['enable_ha']
|
||||
self.enable_drs = module.params['enable_drs']
|
||||
self.enable_vsan = module.params['enable_vsan']
|
||||
self.cluster_name = module.params['cluster_name']
|
||||
self.desired_state = module.params['state']
|
||||
self.datacenter = None
|
||||
self.cluster = None
|
||||
self.content = connect_to_api(module)
|
||||
self.datacenter_name = module.params['datacenter_name']
|
||||
|
||||
def process_state(self):
|
||||
cluster_states = {
|
||||
'absent': {
|
||||
'present': self.state_destroy_cluster,
|
||||
'absent': self.state_exit_unchanged,
|
||||
},
|
||||
'present': {
|
||||
'update': self.state_update_cluster,
|
||||
'present': self.state_exit_unchanged,
|
||||
'absent': self.state_create_cluster,
|
||||
}
|
||||
}
|
||||
current_state = self.check_cluster_configuration()
|
||||
# Based on the desired_state and the current_state call
|
||||
# the appropriate method from the dictionary
|
||||
cluster_states[self.desired_state][current_state]()
|
||||
|
||||
def configure_ha(self):
|
||||
das_config = vim.cluster.DasConfigInfo()
|
||||
das_config.enabled = self.enable_ha
|
||||
das_config.admissionControlPolicy = vim.cluster.FailoverLevelAdmissionControlPolicy()
|
||||
das_config.admissionControlPolicy.failoverLevel = 2
|
||||
return das_config
|
||||
|
||||
def configure_drs(self):
|
||||
drs_config = vim.cluster.DrsConfigInfo()
|
||||
drs_config.enabled = self.enable_drs
|
||||
# Set to partially automated
|
||||
drs_config.vmotionRate = 3
|
||||
return drs_config
|
||||
|
||||
def configure_vsan(self):
|
||||
vsan_config = vim.vsan.cluster.ConfigInfo()
|
||||
vsan_config.enabled = self.enable_vsan
|
||||
vsan_config.defaultConfig = vim.vsan.cluster.ConfigInfo.HostDefaultInfo()
|
||||
vsan_config.defaultConfig.autoClaimStorage = False
|
||||
return vsan_config
|
||||
|
||||
def state_create_cluster(self):
|
||||
try:
|
||||
cluster_config_spec = vim.cluster.ConfigSpecEx()
|
||||
cluster_config_spec.dasConfig = self.configure_ha()
|
||||
cluster_config_spec.drsConfig = self.configure_drs()
|
||||
if self.enable_vsan:
|
||||
cluster_config_spec.vsanConfig = self.configure_vsan()
|
||||
if not self.module.check_mode:
|
||||
self.datacenter.hostFolder.CreateClusterEx(self.cluster_name, cluster_config_spec)
|
||||
self.module.exit_json(changed=True)
|
||||
except vim.fault.DuplicateName:
|
||||
self.module.fail_json(msg="A cluster with the name %s already exists" % self.cluster_name)
|
||||
except vmodl.fault.InvalidArgument:
|
||||
self.module.fail_json(msg="Cluster configuration specification parameter is invalid")
|
||||
except vim.fault.InvalidName:
|
||||
self.module.fail_json(msg="%s is an invalid name for a cluster" % self.cluster_name)
|
||||
except vmodl.fault.NotSupported:
|
||||
# This should never happen
|
||||
self.module.fail_json(msg="Trying to create a cluster on an incorrect folder object")
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
# This should never happen either
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
|
||||
def state_destroy_cluster(self):
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
try:
|
||||
if not self.module.check_mode:
|
||||
task = self.cluster.Destroy_Task()
|
||||
changed, result = wait_for_task(task)
|
||||
self.module.exit_json(changed=changed, result=result)
|
||||
except vim.fault.VimFault as vim_fault:
|
||||
self.module.fail_json(msg=vim_fault.msg)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def state_update_cluster(self):
|
||||
cluster_config_spec = vim.cluster.ConfigSpecEx()
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if self.cluster.configurationEx.dasConfig.enabled != self.enable_ha:
|
||||
cluster_config_spec.dasConfig = self.configure_ha()
|
||||
if self.cluster.configurationEx.drsConfig.enabled != self.enable_drs:
|
||||
cluster_config_spec.drsConfig = self.configure_drs()
|
||||
if self.cluster.configurationEx.vsanConfigInfo.enabled != self.enable_vsan:
|
||||
cluster_config_spec.vsanConfig = self.configure_vsan()
|
||||
|
||||
try:
|
||||
if not self.module.check_mode:
|
||||
task = self.cluster.ReconfigureComputeResource_Task(cluster_config_spec, True)
|
||||
changed, result = wait_for_task(task)
|
||||
self.module.exit_json(changed=changed, result=result)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except TaskError as task_e:
|
||||
self.module.fail_json(msg=str(task_e))
|
||||
|
||||
def check_cluster_configuration(self):
|
||||
try:
|
||||
self.datacenter = find_datacenter_by_name(self.content, self.datacenter_name)
|
||||
if self.datacenter is None:
|
||||
self.module.fail_json(msg="Datacenter %s does not exist, "
|
||||
"please create first with Ansible Module vmware_datacenter or manually."
|
||||
% self.datacenter_name)
|
||||
self.cluster = find_cluster_by_name_datacenter(self.datacenter, self.cluster_name)
|
||||
|
||||
if self.cluster is None:
|
||||
return 'absent'
|
||||
else:
|
||||
desired_state = (self.enable_ha,
|
||||
self.enable_drs,
|
||||
self.enable_vsan)
|
||||
|
||||
current_state = (self.cluster.configurationEx.dasConfig.enabled,
|
||||
self.cluster.configurationEx.drsConfig.enabled,
|
||||
self.cluster.configurationEx.vsanConfigInfo.enabled)
|
||||
|
||||
if cmp(desired_state, current_state) != 0:
|
||||
return 'update'
|
||||
else:
|
||||
return 'present'
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(datacenter_name=dict(required=True, type='str'),
|
||||
cluster_name=dict(required=True, type='str'),
|
||||
enable_ha=dict(default=False, required=False, type='bool'),
|
||||
enable_drs=dict(default=False, required=False, type='bool'),
|
||||
enable_vsan=dict(default=False, required=False, type='bool'),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmware_cluster = VMwareCluster(module)
|
||||
vmware_cluster.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
164
lib/ansible/modules/cloud/vmware/vmware_datacenter.py
Normal file
164
lib/ansible/modules/cloud/vmware/vmware_datacenter.py
Normal file
|
@ -0,0 +1,164 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_datacenter
|
||||
short_description: Manage VMware vSphere Datacenters
|
||||
description:
|
||||
- Manage VMware vSphere Datacenters
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac), Kamil Szczygiel (@kamsz)"
|
||||
notes:
|
||||
- Tested on vSphere 6.0
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
hostname:
|
||||
description:
|
||||
- The hostname or IP address of the vSphere vCenter API server
|
||||
required: True
|
||||
username:
|
||||
description:
|
||||
- The username of the vSphere vCenter
|
||||
required: True
|
||||
aliases: ['user', 'admin']
|
||||
password:
|
||||
description:
|
||||
- The password of the vSphere vCenter
|
||||
required: True
|
||||
aliases: ['pass', 'pwd']
|
||||
datacenter_name:
|
||||
description:
|
||||
- The name of the datacenter the cluster will be created in.
|
||||
required: True
|
||||
state:
|
||||
description:
|
||||
- If the datacenter should be present or absent
|
||||
choices: ['present', 'absent']
|
||||
default: present
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example vmware_datacenter command from Ansible Playbooks
|
||||
- name: Create Datacenter
|
||||
local_action: >
|
||||
vmware_datacenter
|
||||
hostname="{{ ansible_ssh_host }}" username=root password=vmware
|
||||
datacenter_name="datacenter" state=present
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def get_datacenter(context, module):
|
||||
try:
|
||||
datacenter_name = module.params.get('datacenter_name')
|
||||
datacenter = find_datacenter_by_name(context, datacenter_name)
|
||||
return datacenter
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
|
||||
|
||||
def create_datacenter(context, module):
|
||||
datacenter_name = module.params.get('datacenter_name')
|
||||
folder = context.rootFolder
|
||||
|
||||
try:
|
||||
datacenter = get_datacenter(context, module)
|
||||
changed = False
|
||||
if not datacenter:
|
||||
changed = True
|
||||
if not module.check_mode:
|
||||
folder.CreateDatacenter(name=datacenter_name)
|
||||
module.exit_json(changed=changed)
|
||||
except vim.fault.DuplicateName:
|
||||
module.fail_json(msg="A datacenter with the name %s already exists" % datacenter_name)
|
||||
except vim.fault.InvalidName:
|
||||
module.fail_json(msg="%s is an invalid name for a cluster" % datacenter_name)
|
||||
except vmodl.fault.NotSupported:
|
||||
# This should never happen
|
||||
module.fail_json(msg="Trying to create a datacenter on an incorrect folder object")
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
|
||||
|
||||
def destroy_datacenter(context, module):
|
||||
result = None
|
||||
|
||||
try:
|
||||
datacenter = get_datacenter(context, module)
|
||||
changed = False
|
||||
if datacenter:
|
||||
changed = True
|
||||
if not module.check_mode:
|
||||
task = datacenter.Destroy_Task()
|
||||
changed, result = wait_for_task(task)
|
||||
module.exit_json(changed=changed, result=result)
|
||||
except vim.fault.VimFault as vim_fault:
|
||||
module.fail_json(msg=vim_fault.msg)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(
|
||||
dict(
|
||||
datacenter_name=dict(required=True, type='str'),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')
|
||||
)
|
||||
)
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
context = connect_to_api(module)
|
||||
state = module.params.get('state')
|
||||
|
||||
if state == 'present':
|
||||
create_datacenter(context, module)
|
||||
|
||||
if state == 'absent':
|
||||
destroy_datacenter(context, module)
|
||||
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.vmware import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
134
lib/ansible/modules/cloud/vmware/vmware_dns_config.py
Normal file
134
lib/ansible/modules/cloud/vmware/vmware_dns_config.py
Normal file
|
@ -0,0 +1,134 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_dns_config
|
||||
short_description: Manage VMware ESXi DNS Configuration
|
||||
description:
|
||||
- Manage VMware ESXi DNS Configuration
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
change_hostname_to:
|
||||
description:
|
||||
- The hostname that an ESXi host should be changed to.
|
||||
required: True
|
||||
domainname:
|
||||
description:
|
||||
- The domain the ESXi host should be apart of.
|
||||
required: True
|
||||
dns_servers:
|
||||
description:
|
||||
- The DNS servers that the host should be configured to use.
|
||||
required: True
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example vmware_dns_config command from Ansible Playbooks
|
||||
- name: Configure ESXi hostname and DNS servers
|
||||
local_action:
|
||||
module: vmware_dns_config
|
||||
hostname: esxi_hostname
|
||||
username: root
|
||||
password: your_password
|
||||
change_hostname_to: esx01
|
||||
domainname: foo.org
|
||||
dns_servers:
|
||||
- 8.8.8.8
|
||||
- 8.8.4.4
|
||||
'''
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def configure_dns(host_system, hostname, domainname, dns_servers):
|
||||
|
||||
changed = False
|
||||
host_config_manager = host_system.configManager
|
||||
host_network_system = host_config_manager.networkSystem
|
||||
config = host_network_system.dnsConfig
|
||||
|
||||
config.dhcp = False
|
||||
|
||||
if config.address != dns_servers:
|
||||
config.address = dns_servers
|
||||
changed = True
|
||||
if config.domainName != domainname:
|
||||
config.domainName = domainname
|
||||
changed = True
|
||||
if config.hostName != hostname:
|
||||
config.hostName = hostname
|
||||
changed = True
|
||||
if changed:
|
||||
host_network_system.UpdateDnsConfig(config)
|
||||
|
||||
return changed
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(change_hostname_to=dict(required=True, type='str'),
|
||||
domainname=dict(required=True, type='str'),
|
||||
dns_servers=dict(required=True, type='list')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
change_hostname_to = module.params['change_hostname_to']
|
||||
domainname = module.params['domainname']
|
||||
dns_servers = module.params['dns_servers']
|
||||
try:
|
||||
content = connect_to_api(module)
|
||||
host = get_all_objs(content, [vim.HostSystem])
|
||||
if not host:
|
||||
module.fail_json(msg="Unable to locate Physical Host.")
|
||||
host_system = host.keys()[0]
|
||||
changed = configure_dns(host_system, change_hostname_to, domainname, dns_servers)
|
||||
module.exit_json(changed=changed)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
253
lib/ansible/modules/cloud/vmware/vmware_dvs_host.py
Normal file
253
lib/ansible/modules/cloud/vmware/vmware_dvs_host.py
Normal file
|
@ -0,0 +1,253 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_dvs_host
|
||||
short_description: Add or remove a host from distributed virtual switch
|
||||
description:
|
||||
- Add or remove a host from distributed virtual switch
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
esxi_hostname:
|
||||
description:
|
||||
- The ESXi hostname
|
||||
required: True
|
||||
switch_name:
|
||||
description:
|
||||
- The name of the Distributed vSwitch
|
||||
required: True
|
||||
vmnics:
|
||||
description:
|
||||
- The ESXi hosts vmnics to use with the Distributed vSwitch
|
||||
required: True
|
||||
state:
|
||||
description:
|
||||
- If the host should be present or absent attached to the vSwitch
|
||||
choices: ['present', 'absent']
|
||||
required: True
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example vmware_dvs_host command from Ansible Playbooks
|
||||
- name: Add Host to dVS
|
||||
local_action:
|
||||
module: vmware_dvs_host
|
||||
hostname: vcenter_ip_or_hostname
|
||||
username: vcenter_username
|
||||
password: vcenter_password
|
||||
esxi_hostname: esxi_hostname_as_listed_in_vcenter
|
||||
switch_name: dvSwitch
|
||||
vmnics:
|
||||
- vmnic0
|
||||
- vmnic1
|
||||
state: present
|
||||
'''
|
||||
|
||||
try:
|
||||
import collections
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
class VMwareDvsHost(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.dv_switch = None
|
||||
self.uplink_portgroup = None
|
||||
self.host = None
|
||||
self.dv_switch = None
|
||||
self.nic = None
|
||||
self.content = connect_to_api(self.module)
|
||||
self.state = self.module.params['state']
|
||||
self.switch_name = self.module.params['switch_name']
|
||||
self.esxi_hostname = self.module.params['esxi_hostname']
|
||||
self.vmnics = self.module.params['vmnics']
|
||||
|
||||
def process_state(self):
|
||||
try:
|
||||
dvs_host_states = {
|
||||
'absent': {
|
||||
'present': self.state_destroy_dvs_host,
|
||||
'absent': self.state_exit_unchanged,
|
||||
},
|
||||
'present': {
|
||||
'update': self.state_update_dvs_host,
|
||||
'present': self.state_exit_unchanged,
|
||||
'absent': self.state_create_dvs_host,
|
||||
}
|
||||
}
|
||||
|
||||
dvs_host_states[self.state][self.check_dvs_host_state()]()
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=str(e))
|
||||
|
||||
def find_dvspg_by_name(self):
|
||||
portgroups = self.dv_switch.portgroup
|
||||
|
||||
for pg in portgroups:
|
||||
if pg.name == self.portgroup_name:
|
||||
return pg
|
||||
return None
|
||||
|
||||
def find_dvs_uplink_pg(self):
|
||||
# There should only always be a single uplink port group on
|
||||
# a distributed virtual switch
|
||||
|
||||
if len(self.dv_switch.config.uplinkPortgroup):
|
||||
return self.dv_switch.config.uplinkPortgroup[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
# operation should be edit, add and remove
|
||||
def modify_dvs_host(self, operation):
|
||||
spec = vim.DistributedVirtualSwitch.ConfigSpec()
|
||||
spec.configVersion = self.dv_switch.config.configVersion
|
||||
spec.host = [vim.dvs.HostMember.ConfigSpec()]
|
||||
spec.host[0].operation = operation
|
||||
spec.host[0].host = self.host
|
||||
|
||||
if operation in ("edit", "add"):
|
||||
spec.host[0].backing = vim.dvs.HostMember.PnicBacking()
|
||||
count = 0
|
||||
|
||||
for nic in self.vmnics:
|
||||
spec.host[0].backing.pnicSpec.append(vim.dvs.HostMember.PnicSpec())
|
||||
spec.host[0].backing.pnicSpec[count].pnicDevice = nic
|
||||
spec.host[0].backing.pnicSpec[count].uplinkPortgroupKey = self.uplink_portgroup.key
|
||||
count += 1
|
||||
|
||||
task = self.dv_switch.ReconfigureDvs_Task(spec)
|
||||
changed, result = wait_for_task(task)
|
||||
return changed, result
|
||||
|
||||
def state_destroy_dvs_host(self):
|
||||
operation = "remove"
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
changed, result = self.modify_dvs_host(operation)
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def state_update_dvs_host(self):
|
||||
operation = "edit"
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
changed, result = self.modify_dvs_host(operation)
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def state_create_dvs_host(self):
|
||||
operation = "add"
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
changed, result = self.modify_dvs_host(operation)
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def find_host_attached_dvs(self):
|
||||
for dvs_host_member in self.dv_switch.config.host:
|
||||
if dvs_host_member.config.host.name == self.esxi_hostname:
|
||||
return dvs_host_member.config.host
|
||||
|
||||
return None
|
||||
|
||||
def check_uplinks(self):
|
||||
pnic_device = []
|
||||
|
||||
for dvs_host_member in self.dv_switch.config.host:
|
||||
if dvs_host_member.config.host == self.host:
|
||||
for pnicSpec in dvs_host_member.config.backing.pnicSpec:
|
||||
pnic_device.append(pnicSpec.pnicDevice)
|
||||
|
||||
return collections.Counter(pnic_device) == collections.Counter(self.vmnics)
|
||||
|
||||
def check_dvs_host_state(self):
|
||||
self.dv_switch = find_dvs_by_name(self.content, self.switch_name)
|
||||
|
||||
if self.dv_switch is None:
|
||||
raise Exception("A distributed virtual switch %s does not exist" % self.switch_name)
|
||||
|
||||
self.uplink_portgroup = self.find_dvs_uplink_pg()
|
||||
|
||||
if self.uplink_portgroup is None:
|
||||
raise Exception("An uplink portgroup does not exist on the distributed virtual switch %s"
|
||||
% self.switch_name)
|
||||
|
||||
self.host = self.find_host_attached_dvs()
|
||||
|
||||
if self.host is None:
|
||||
# We still need the HostSystem object to add the host
|
||||
# to the distributed vswitch
|
||||
self.host = find_hostsystem_by_name(self.content, self.esxi_hostname)
|
||||
if self.host is None:
|
||||
self.module.fail_json(msg="The esxi_hostname %s does not exist in vCenter" % self.esxi_hostname)
|
||||
return 'absent'
|
||||
else:
|
||||
if self.check_uplinks():
|
||||
return 'present'
|
||||
else:
|
||||
return 'update'
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(esxi_hostname=dict(required=True, type='str'),
|
||||
switch_name=dict(required=True, type='str'),
|
||||
vmnics=dict(required=True, type='list'),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmware_dvs_host = VMwareDvsHost(module)
|
||||
vmware_dvs_host.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
202
lib/ansible/modules/cloud/vmware/vmware_dvs_portgroup.py
Normal file
202
lib/ansible/modules/cloud/vmware/vmware_dvs_portgroup.py
Normal file
|
@ -0,0 +1,202 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_dvs_portgroup
|
||||
short_description: Create or remove a Distributed vSwitch portgroup
|
||||
description:
|
||||
- Create or remove a Distributed vSwitch portgroup
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
portgroup_name:
|
||||
description:
|
||||
- The name of the portgroup that is to be created or deleted
|
||||
required: True
|
||||
switch_name:
|
||||
description:
|
||||
- The name of the distributed vSwitch the port group should be created on.
|
||||
required: True
|
||||
vlan_id:
|
||||
description:
|
||||
- The VLAN ID that should be configured with the portgroup
|
||||
required: True
|
||||
num_ports:
|
||||
description:
|
||||
- The number of ports the portgroup should contain
|
||||
required: True
|
||||
portgroup_type:
|
||||
description:
|
||||
- See VMware KB 1022312 regarding portgroup types
|
||||
required: True
|
||||
choices:
|
||||
- 'earlyBinding'
|
||||
- 'lateBinding'
|
||||
- 'ephemeral'
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Create Management portgroup
|
||||
local_action:
|
||||
module: vmware_dvs_portgroup
|
||||
hostname: vcenter_ip_or_hostname
|
||||
username: vcenter_username
|
||||
password: vcenter_password
|
||||
portgroup_name: Management
|
||||
switch_name: dvSwitch
|
||||
vlan_id: 123
|
||||
num_ports: 120
|
||||
portgroup_type: earlyBinding
|
||||
state: present
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
class VMwareDvsPortgroup(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.dvs_portgroup = None
|
||||
self.switch_name = self.module.params['switch_name']
|
||||
self.portgroup_name = self.module.params['portgroup_name']
|
||||
self.vlan_id = self.module.params['vlan_id']
|
||||
self.num_ports = self.module.params['num_ports']
|
||||
self.portgroup_type = self.module.params['portgroup_type']
|
||||
self.dv_switch = None
|
||||
self.state = self.module.params['state']
|
||||
self.content = connect_to_api(module)
|
||||
|
||||
def process_state(self):
|
||||
try:
|
||||
dvspg_states = {
|
||||
'absent': {
|
||||
'present': self.state_destroy_dvspg,
|
||||
'absent': self.state_exit_unchanged,
|
||||
},
|
||||
'present': {
|
||||
'update': self.state_update_dvspg,
|
||||
'present': self.state_exit_unchanged,
|
||||
'absent': self.state_create_dvspg,
|
||||
}
|
||||
}
|
||||
dvspg_states[self.state][self.check_dvspg_state()]()
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=str(e))
|
||||
|
||||
def create_port_group(self):
|
||||
config = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
|
||||
|
||||
config.name = self.portgroup_name
|
||||
config.numPorts = self.num_ports
|
||||
|
||||
# vim.VMwareDVSPortSetting() does not exist in the pyvmomi documentation
|
||||
# but this is the correct managed object type.
|
||||
|
||||
config.defaultPortConfig = vim.VMwareDVSPortSetting()
|
||||
|
||||
# vim.VmwareDistributedVirtualSwitchVlanIdSpec() does not exist in the
|
||||
# pyvmomi documentation but this is the correct managed object type
|
||||
config.defaultPortConfig.vlan = vim.VmwareDistributedVirtualSwitchVlanIdSpec()
|
||||
config.defaultPortConfig.vlan.inherited = False
|
||||
config.defaultPortConfig.vlan.vlanId = self.vlan_id
|
||||
config.type = self.portgroup_type
|
||||
|
||||
spec = [config]
|
||||
task = self.dv_switch.AddDVPortgroup_Task(spec)
|
||||
changed, result = wait_for_task(task)
|
||||
return changed, result
|
||||
|
||||
def state_destroy_dvspg(self):
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
task = self.dvs_portgroup.Destroy_Task()
|
||||
changed, result = wait_for_task(task)
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def state_update_dvspg(self):
|
||||
self.module.exit_json(changed=False, msg="Currently not implemented.")
|
||||
|
||||
def state_create_dvspg(self):
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
changed, result = self.create_port_group()
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def check_dvspg_state(self):
|
||||
self.dv_switch = find_dvs_by_name(self.content, self.switch_name)
|
||||
|
||||
if self.dv_switch is None:
|
||||
raise Exception("A distributed virtual switch with name %s does not exist" % self.switch_name)
|
||||
self.dvs_portgroup = find_dvspg_by_name(self.dv_switch, self.portgroup_name)
|
||||
|
||||
if self.dvs_portgroup is None:
|
||||
return 'absent'
|
||||
else:
|
||||
return 'present'
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(portgroup_name=dict(required=True, type='str'),
|
||||
switch_name=dict(required=True, type='str'),
|
||||
vlan_id=dict(required=True, type='int'),
|
||||
num_ports=dict(required=True, type='int'),
|
||||
portgroup_type=dict(required=True, choices=['earlyBinding', 'lateBinding', 'ephemeral'], type='str'),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmware_dvs_portgroup = VMwareDvsPortgroup(module)
|
||||
vmware_dvs_portgroup.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
213
lib/ansible/modules/cloud/vmware/vmware_dvswitch.py
Normal file
213
lib/ansible/modules/cloud/vmware/vmware_dvswitch.py
Normal file
|
@ -0,0 +1,213 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_dvswitch
|
||||
short_description: Create or remove a distributed vSwitch
|
||||
description:
|
||||
- Create or remove a distributed vSwitch
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
datacenter_name:
|
||||
description:
|
||||
- The name of the datacenter that will contain the dvSwitch
|
||||
required: True
|
||||
switch_name:
|
||||
description:
|
||||
- The name of the switch to create or remove
|
||||
required: True
|
||||
mtu:
|
||||
description:
|
||||
- The switch maximum transmission unit
|
||||
required: True
|
||||
uplink_quantity:
|
||||
description:
|
||||
- Quantity of uplink per ESXi host added to the switch
|
||||
required: True
|
||||
discovery_proto:
|
||||
description:
|
||||
- Link discovery protocol between Cisco and Link Layer discovery
|
||||
choices:
|
||||
- 'cdp'
|
||||
- 'lldp'
|
||||
required: True
|
||||
discovery_operation:
|
||||
description:
|
||||
- Select the discovery operation
|
||||
choices:
|
||||
- 'both'
|
||||
- 'none'
|
||||
- 'advertise'
|
||||
- 'listen'
|
||||
state:
|
||||
description:
|
||||
- Create or remove dvSwitch
|
||||
default: 'present'
|
||||
choices:
|
||||
- 'present'
|
||||
- 'absent'
|
||||
required: False
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
EXAMPLES = '''
|
||||
- name: Create dvswitch
|
||||
local_action:
|
||||
module: vmware_dvswitch
|
||||
hostname: vcenter_ip_or_hostname
|
||||
username: vcenter_username
|
||||
password: vcenter_password
|
||||
datacenter_name: datacenter
|
||||
switch_name: dvSwitch
|
||||
mtu: 9000
|
||||
uplink_quantity: 2
|
||||
discovery_proto: lldp
|
||||
discovery_operation: both
|
||||
state: present
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
class VMwareDVSwitch(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.dvs = None
|
||||
self.switch_name = self.module.params['switch_name']
|
||||
self.datacenter_name = self.module.params['datacenter_name']
|
||||
self.mtu = self.module.params['mtu']
|
||||
self.uplink_quantity = self.module.params['uplink_quantity']
|
||||
self.discovery_proto = self.module.params['discovery_proto']
|
||||
self.discovery_operation = self.module.params['discovery_operation']
|
||||
self.switch_name = self.module.params['switch_name']
|
||||
self.state = self.module.params['state']
|
||||
self.content = connect_to_api(module)
|
||||
|
||||
def process_state(self):
|
||||
try:
|
||||
dvs_states = {
|
||||
'absent': {
|
||||
'present': self.state_destroy_dvs,
|
||||
'absent': self.state_exit_unchanged,
|
||||
},
|
||||
'present': {
|
||||
'update': self.state_update_dvs,
|
||||
'present': self.state_exit_unchanged,
|
||||
'absent': self.state_create_dvs,
|
||||
}
|
||||
}
|
||||
dvs_states[self.state][self.check_dvs_configuration()]()
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
def create_dvswitch(self, network_folder):
|
||||
result = None
|
||||
changed = False
|
||||
|
||||
spec = vim.DistributedVirtualSwitch.CreateSpec()
|
||||
spec.configSpec = vim.dvs.VmwareDistributedVirtualSwitch.ConfigSpec()
|
||||
spec.configSpec.uplinkPortPolicy = vim.DistributedVirtualSwitch.NameArrayUplinkPortPolicy()
|
||||
spec.configSpec.linkDiscoveryProtocolConfig = vim.host.LinkDiscoveryProtocolConfig()
|
||||
|
||||
spec.configSpec.name = self.switch_name
|
||||
spec.configSpec.maxMtu = self.mtu
|
||||
spec.configSpec.linkDiscoveryProtocolConfig.protocol = self.discovery_proto
|
||||
spec.configSpec.linkDiscoveryProtocolConfig.operation = self.discovery_operation
|
||||
spec.productInfo = vim.dvs.ProductSpec()
|
||||
spec.productInfo.name = "DVS"
|
||||
spec.productInfo.vendor = "VMware"
|
||||
|
||||
for count in range(1, self.uplink_quantity+1):
|
||||
spec.configSpec.uplinkPortPolicy.uplinkPortName.append("uplink%d" % count)
|
||||
|
||||
task = network_folder.CreateDVS_Task(spec)
|
||||
changed, result = wait_for_task(task)
|
||||
return changed, result
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def state_destroy_dvs(self):
|
||||
task = self.dvs.Destroy_Task()
|
||||
changed, result = wait_for_task(task)
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def state_update_dvs(self):
|
||||
self.module.exit_json(changed=False, msg="Currently not implemented.")
|
||||
|
||||
def state_create_dvs(self):
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
dc = find_datacenter_by_name(self.content, self.datacenter_name)
|
||||
changed, result = self.create_dvswitch(dc.networkFolder)
|
||||
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def check_dvs_configuration(self):
|
||||
self.dvs = find_dvs_by_name(self.content, self.switch_name)
|
||||
if self.dvs is None:
|
||||
return 'absent'
|
||||
else:
|
||||
return 'present'
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(datacenter_name=dict(required=True, type='str'),
|
||||
switch_name=dict(required=True, type='str'),
|
||||
mtu=dict(required=True, type='int'),
|
||||
uplink_quantity=dict(required=True, type='int'),
|
||||
discovery_proto=dict(required=True, choices=['cdp', 'lldp'], type='str'),
|
||||
discovery_operation=dict(required=True, choices=['both', 'none', 'advertise', 'listen'], type='str'),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmware_dvswitch = VMwareDVSwitch(module)
|
||||
vmware_dvswitch.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
1349
lib/ansible/modules/cloud/vmware/vmware_guest.py
Normal file
1349
lib/ansible/modules/cloud/vmware/vmware_guest.py
Normal file
File diff suppressed because it is too large
Load diff
229
lib/ansible/modules/cloud/vmware/vmware_host.py
Normal file
229
lib/ansible/modules/cloud/vmware/vmware_host.py
Normal file
|
@ -0,0 +1,229 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_host
|
||||
short_description: Add/remove ESXi host to/from vCenter
|
||||
description:
|
||||
- This module can be used to add/remove an ESXi host to/from vCenter
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
datacenter_name:
|
||||
description:
|
||||
- Name of the datacenter to add the host
|
||||
required: True
|
||||
cluster_name:
|
||||
description:
|
||||
- Name of the cluster to add the host
|
||||
required: True
|
||||
esxi_hostname:
|
||||
description:
|
||||
- ESXi hostname to manage
|
||||
required: True
|
||||
esxi_username:
|
||||
description:
|
||||
- ESXi username
|
||||
required: True
|
||||
esxi_password:
|
||||
description:
|
||||
- ESXi password
|
||||
required: True
|
||||
state:
|
||||
description:
|
||||
- Add or remove the host
|
||||
default: 'present'
|
||||
choices:
|
||||
- 'present'
|
||||
- 'absent'
|
||||
required: False
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Example from Ansible playbook
|
||||
|
||||
- name: Add ESXi Host to VCSA
|
||||
local_action:
|
||||
module: vmware_host
|
||||
hostname: vcsa_host
|
||||
username: vcsa_user
|
||||
password: vcsa_pass
|
||||
datacenter_name: datacenter_name
|
||||
cluster_name: cluster_name
|
||||
esxi_hostname: esxi_hostname
|
||||
esxi_username: esxi_username
|
||||
esxi_password: esxi_password
|
||||
state: present
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
class VMwareHost(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.datacenter_name = module.params['datacenter_name']
|
||||
self.cluster_name = module.params['cluster_name']
|
||||
self.esxi_hostname = module.params['esxi_hostname']
|
||||
self.esxi_username = module.params['esxi_username']
|
||||
self.esxi_password = module.params['esxi_password']
|
||||
self.state = module.params['state']
|
||||
self.dc = None
|
||||
self.cluster = None
|
||||
self.host = None
|
||||
self.content = connect_to_api(module)
|
||||
|
||||
def process_state(self):
|
||||
try:
|
||||
# Currently state_update_dvs is not implemented.
|
||||
host_states = {
|
||||
'absent': {
|
||||
'present': self.state_remove_host,
|
||||
'absent': self.state_exit_unchanged,
|
||||
},
|
||||
'present': {
|
||||
'present': self.state_exit_unchanged,
|
||||
'absent': self.state_add_host,
|
||||
}
|
||||
}
|
||||
|
||||
host_states[self.state][self.check_host_state()]()
|
||||
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=str(e))
|
||||
|
||||
def find_host_by_cluster_datacenter(self):
|
||||
self.dc = find_datacenter_by_name(self.content, self.datacenter_name)
|
||||
self.cluster = find_cluster_by_name_datacenter(self.dc, self.cluster_name)
|
||||
|
||||
for host in self.cluster.host:
|
||||
if host.name == self.esxi_hostname:
|
||||
return host, self.cluster
|
||||
|
||||
return None, self.cluster
|
||||
|
||||
def add_host_to_vcenter(self):
|
||||
host_connect_spec = vim.host.ConnectSpec()
|
||||
host_connect_spec.hostName = self.esxi_hostname
|
||||
host_connect_spec.userName = self.esxi_username
|
||||
host_connect_spec.password = self.esxi_password
|
||||
host_connect_spec.force = True
|
||||
host_connect_spec.sslThumbprint = ""
|
||||
as_connected = True
|
||||
esxi_license = None
|
||||
resource_pool = None
|
||||
|
||||
try:
|
||||
task = self.cluster.AddHost_Task(host_connect_spec, as_connected, resource_pool, esxi_license)
|
||||
success, result = wait_for_task(task)
|
||||
return success, result
|
||||
except TaskError as add_task_error:
|
||||
# This is almost certain to fail the first time.
|
||||
# In order to get the sslThumbprint we first connect
|
||||
# get the vim.fault.SSLVerifyFault then grab the sslThumbprint
|
||||
# from that object.
|
||||
#
|
||||
# args is a tuple, selecting the first tuple
|
||||
ssl_verify_fault = add_task_error.args[0]
|
||||
host_connect_spec.sslThumbprint = ssl_verify_fault.thumbprint
|
||||
|
||||
task = self.cluster.AddHost_Task(host_connect_spec, as_connected, resource_pool, esxi_license)
|
||||
success, result = wait_for_task(task)
|
||||
return success, result
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def state_remove_host(self):
|
||||
changed = True
|
||||
result = None
|
||||
if not self.module.check_mode:
|
||||
if not self.host.runtime.inMaintenanceMode:
|
||||
maintenance_mode_task = self.host.EnterMaintenanceMode_Task(300, True, None)
|
||||
changed, result = wait_for_task(maintenance_mode_task)
|
||||
|
||||
if changed:
|
||||
task = self.host.Destroy_Task()
|
||||
changed, result = wait_for_task(task)
|
||||
else:
|
||||
raise Exception(result)
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def state_update_host(self):
|
||||
self.module.exit_json(changed=False, msg="Currently not implemented.")
|
||||
|
||||
def state_add_host(self):
|
||||
changed = True
|
||||
result = None
|
||||
|
||||
if not self.module.check_mode:
|
||||
changed, result = self.add_host_to_vcenter()
|
||||
self.module.exit_json(changed=changed, result=str(result))
|
||||
|
||||
def check_host_state(self):
|
||||
self.host, self.cluster = self.find_host_by_cluster_datacenter()
|
||||
|
||||
if self.host is None:
|
||||
return 'absent'
|
||||
else:
|
||||
return 'present'
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(datacenter_name=dict(required=True, type='str'),
|
||||
cluster_name=dict(required=True, type='str'),
|
||||
esxi_hostname=dict(required=True, type='str'),
|
||||
esxi_username=dict(required=True, type='str'),
|
||||
esxi_password=dict(required=True, type='str', no_log=True),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmware_host = VMwareHost(module)
|
||||
vmware_host.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
195
lib/ansible/modules/cloud/vmware/vmware_local_user_manager.py
Normal file
195
lib/ansible/modules/cloud/vmware/vmware_local_user_manager.py
Normal file
|
@ -0,0 +1,195 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright IBM Corp. 2016
|
||||
# Author(s): Andreas Nafpliotis <nafpliot@de.ibm.com>
|
||||
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_local_user_manager
|
||||
short_description: Manage local users on an ESXi host
|
||||
description:
|
||||
- Manage local users on an ESXi host
|
||||
version_added: "2.2"
|
||||
author: Andreas Nafpliotis
|
||||
notes:
|
||||
- Tested on ESXi 6.0
|
||||
- Be sure that the ESXi user used for login, has the appropriate rights to create / delete / edit users
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi installed
|
||||
options:
|
||||
local_user_name:
|
||||
description:
|
||||
- The local user name to be changed
|
||||
required: True
|
||||
local_user_password:
|
||||
description:
|
||||
- The password to be set
|
||||
required: False
|
||||
local_user_description:
|
||||
description:
|
||||
- Description for the user
|
||||
required: False
|
||||
state:
|
||||
description:
|
||||
- Indicate desired state of the user. If the user already exists when C(state=present), the user info is updated
|
||||
choices: ['present', 'absent']
|
||||
default: present
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example vmware_local_user_manager command from Ansible Playbooks
|
||||
- name: Add local user to ESXi
|
||||
local_action:
|
||||
module: vmware_local_user_manager
|
||||
hostname: esxi_hostname
|
||||
username: root
|
||||
password: vmware
|
||||
local_user_name: foo
|
||||
'''
|
||||
|
||||
RETURN = '''# '''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
class VMwareLocalUserManager(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.content = connect_to_api(self.module)
|
||||
self.local_user_name = self.module.params['local_user_name']
|
||||
self.local_user_password = self.module.params['local_user_password']
|
||||
self.local_user_description = self.module.params['local_user_description']
|
||||
self.state = self.module.params['state']
|
||||
|
||||
def process_state(self):
|
||||
try:
|
||||
local_account_manager_states = {
|
||||
'absent': {
|
||||
'present': self.state_remove_user,
|
||||
'absent': self.state_exit_unchanged,
|
||||
},
|
||||
'present': {
|
||||
'present': self.state_update_user,
|
||||
'absent': self.state_create_user,
|
||||
}
|
||||
}
|
||||
|
||||
local_account_manager_states[self.state][self.check_local_user_manager_state()]()
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
def check_local_user_manager_state(self):
|
||||
user_account = self.find_user_account()
|
||||
if not user_account:
|
||||
return 'absent'
|
||||
else:
|
||||
return 'present'
|
||||
|
||||
|
||||
def find_user_account(self):
|
||||
searchStr = self.local_user_name
|
||||
exactMatch = True
|
||||
findUsers = True
|
||||
findGroups = False
|
||||
user_account = self.content.userDirectory.RetrieveUserGroups(None, searchStr, None, None, exactMatch, findUsers, findGroups)
|
||||
return user_account
|
||||
|
||||
|
||||
def create_account_spec(self):
|
||||
account_spec = vim.host.LocalAccountManager.AccountSpecification()
|
||||
account_spec.id = self.local_user_name
|
||||
account_spec.password = self.local_user_password
|
||||
account_spec.description = self.local_user_description
|
||||
return account_spec
|
||||
|
||||
|
||||
def state_create_user(self):
|
||||
account_spec = self.create_account_spec()
|
||||
|
||||
try:
|
||||
task = self.content.accountManager.CreateUser(account_spec)
|
||||
self.module.exit_json(changed=True)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
|
||||
def state_update_user(self):
|
||||
account_spec = self.create_account_spec()
|
||||
|
||||
try:
|
||||
task = self.content.accountManager.UpdateUser(account_spec)
|
||||
self.module.exit_json(changed=True)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
|
||||
|
||||
def state_remove_user(self):
|
||||
try:
|
||||
task = self.content.accountManager.RemoveUser(self.local_user_name)
|
||||
self.module.exit_json(changed=True)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(local_user_name=dict(required=True, type='str'),
|
||||
local_user_password=dict(required=False, type='str', no_log=True),
|
||||
local_user_description=dict(required=False, type='str'),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmware_local_user_manager = VMwareLocalUserManager(module)
|
||||
vmware_local_user_manager.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
216
lib/ansible/modules/cloud/vmware/vmware_maintenancemode.py
Normal file
216
lib/ansible/modules/cloud/vmware/vmware_maintenancemode.py
Normal file
|
@ -0,0 +1,216 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, VMware, Inc.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_maintenancemode
|
||||
short_description: Place a host into maintenance mode
|
||||
description:
|
||||
- Place an ESXI host into maintenance mode
|
||||
- Support for VSAN compliant maintenance mode when selected
|
||||
author: "Jay Jahns <jjahns@vmware.com>"
|
||||
version_added: "2.1"
|
||||
notes:
|
||||
- Tested on vSphere 5.5 and 6.0
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
esxi_hostname:
|
||||
description:
|
||||
- Name of the host as defined in vCenter
|
||||
required: True
|
||||
vsan_mode:
|
||||
description:
|
||||
- Specify which VSAN compliant mode to enter
|
||||
choices:
|
||||
- 'ensureObjectAccessibility'
|
||||
- 'evacuateAllData'
|
||||
- 'noAction'
|
||||
required: False
|
||||
evacuate:
|
||||
description:
|
||||
- If True, evacuate all powered off VMs
|
||||
choices:
|
||||
- True
|
||||
- False
|
||||
default: False
|
||||
required: False
|
||||
timeout:
|
||||
description:
|
||||
- Specify a timeout for the operation
|
||||
required: False
|
||||
default: 0
|
||||
state:
|
||||
description:
|
||||
- Enter or exit maintenance mode
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
required: False
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Enter VSAN-Compliant Maintenance Mode
|
||||
local_action:
|
||||
module: vmware_maintenancemode
|
||||
hostname: vc_host
|
||||
username: vc_user
|
||||
password: vc_pass
|
||||
esxi_hostname: esxi.host.example
|
||||
vsan: ensureObjectAccessibility
|
||||
evacuate: yes
|
||||
timeout: 3600
|
||||
state: present
|
||||
'''
|
||||
RETURN = '''
|
||||
hostsystem:
|
||||
description: Name of vim reference
|
||||
returned: always
|
||||
type: string
|
||||
sample: "'vim.HostSystem:host-236'"
|
||||
hostname:
|
||||
description: Name of host in vCenter
|
||||
returned: always
|
||||
type: string
|
||||
sample: "esxi.local.domain"
|
||||
status:
|
||||
description: Action taken
|
||||
return: always
|
||||
type: string
|
||||
sample: "ENTER"
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim
|
||||
HAS_PYVMOMI = True
|
||||
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def EnterMaintenanceMode(module, host):
|
||||
|
||||
if host.runtime.inMaintenanceMode:
|
||||
module.exit_json(
|
||||
changed=False,
|
||||
hostsystem=str(host),
|
||||
hostname=module.params['esxi_hostname'],
|
||||
status='NO_ACTION',
|
||||
msg='Host already in maintenance mode')
|
||||
|
||||
spec = vim.host.MaintenanceSpec()
|
||||
|
||||
if module.params['vsan']:
|
||||
spec.vsanMode = vim.vsan.host.DecommissionMode()
|
||||
spec.vsanMode.objectAction = module.params['vsan']
|
||||
|
||||
try:
|
||||
task = host.EnterMaintenanceMode_Task(
|
||||
module.params['timeout'],
|
||||
module.params['evacuate'],
|
||||
spec)
|
||||
|
||||
success, result = wait_for_task(task)
|
||||
|
||||
return dict(changed=success,
|
||||
hostsystem=str(host),
|
||||
hostname=module.params['esxi_hostname'],
|
||||
status='ENTER',
|
||||
msg='Host entered maintenance mode')
|
||||
|
||||
except TaskError:
|
||||
module.fail_json(
|
||||
msg='Host failed to enter maintenance mode')
|
||||
|
||||
|
||||
def ExitMaintenanceMode(module, host):
|
||||
if not host.runtime.inMaintenanceMode:
|
||||
module.exit_json(
|
||||
changed=False,
|
||||
hostsystem=str(host),
|
||||
hostname=module.params['esxi_hostname'],
|
||||
status='NO_ACTION',
|
||||
msg='Host not in maintenance mode')
|
||||
|
||||
try:
|
||||
task = host.ExitMaintenanceMode_Task(
|
||||
module.params['timeout'])
|
||||
|
||||
success, result = wait_for_task(task)
|
||||
|
||||
return dict(changed=success,
|
||||
hostsystem=str(host),
|
||||
hostname=module.params['esxi_hostname'],
|
||||
status='EXIT',
|
||||
msg='Host exited maintenance mode')
|
||||
|
||||
except TaskError:
|
||||
module.fail_json(
|
||||
msg='Host failed to exit maintenance mode')
|
||||
|
||||
|
||||
def main():
|
||||
spec = vmware_argument_spec()
|
||||
spec.update(dict(
|
||||
esxi_hostname=dict(required=True),
|
||||
vsan=dict(required=False, choices=['ensureObjectAccessibility',
|
||||
'evacuateAllData',
|
||||
'noAction']),
|
||||
evacuate=dict(required=False, type='bool', default=False),
|
||||
timeout=dict(required=False, default=0, type='int'),
|
||||
state=dict(required=False,
|
||||
default='present',
|
||||
choices=['present', 'absent'])))
|
||||
|
||||
module = AnsibleModule(argument_spec=spec)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
content = connect_to_api(module)
|
||||
host = find_hostsystem_by_name(content, module.params['esxi_hostname'])
|
||||
|
||||
if not host:
|
||||
module.fail_json(
|
||||
msg='Host not found in vCenter')
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
result = EnterMaintenanceMode(module, host)
|
||||
|
||||
elif module.params['state'] == 'absent':
|
||||
result = ExitMaintenanceMode(module, host)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.vmware import *
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
200
lib/ansible/modules/cloud/vmware/vmware_migrate_vmk.py
Normal file
200
lib/ansible/modules/cloud/vmware/vmware_migrate_vmk.py
Normal file
|
@ -0,0 +1,200 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_migrate_vmk
|
||||
short_description: Migrate a VMK interface from VSS to VDS
|
||||
description:
|
||||
- Migrate a VMK interface from VSS to VDS
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
esxi_hostname:
|
||||
description:
|
||||
- ESXi hostname to be managed
|
||||
required: True
|
||||
device:
|
||||
description:
|
||||
- VMK interface name
|
||||
required: True
|
||||
current_switch_name:
|
||||
description:
|
||||
- Switch VMK interface is currently on
|
||||
required: True
|
||||
current_portgroup_name:
|
||||
description:
|
||||
- Portgroup name VMK interface is currently on
|
||||
required: True
|
||||
migrate_switch_name:
|
||||
description:
|
||||
- Switch name to migrate VMK interface to
|
||||
required: True
|
||||
migrate_portgroup_name:
|
||||
description:
|
||||
- Portgroup name to migrate VMK interface to
|
||||
required: True
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Example from Ansible playbook
|
||||
|
||||
- name: Migrate Management vmk
|
||||
local_action:
|
||||
module: vmware_migrate_vmk
|
||||
hostname: vcsa_host
|
||||
username: vcsa_user
|
||||
password: vcsa_pass
|
||||
esxi_hostname: esxi_hostname
|
||||
device: vmk1
|
||||
current_switch_name: temp_vswitch
|
||||
current_portgroup_name: esx-mgmt
|
||||
migrate_switch_name: dvSwitch
|
||||
migrate_portgroup_name: Management
|
||||
'''
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
class VMwareMigrateVmk(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.host_system = None
|
||||
self.migrate_switch_name = self.module.params['migrate_switch_name']
|
||||
self.migrate_portgroup_name = self.module.params['migrate_portgroup_name']
|
||||
self.device = self.module.params['device']
|
||||
self.esxi_hostname = self.module.params['esxi_hostname']
|
||||
self.current_portgroup_name = self.module.params['current_portgroup_name']
|
||||
self.current_switch_name = self.module.params['current_switch_name']
|
||||
self.content = connect_to_api(module)
|
||||
|
||||
def process_state(self):
|
||||
try:
|
||||
vmk_migration_states = {
|
||||
'migrate_vss_vds': self.state_migrate_vss_vds,
|
||||
'migrate_vds_vss': self.state_migrate_vds_vss,
|
||||
'migrated': self.state_exit_unchanged
|
||||
}
|
||||
|
||||
vmk_migration_states[self.check_vmk_current_state()]()
|
||||
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=str(e))
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def state_migrate_vds_vss(self):
|
||||
self.module.exit_json(changed=False, msg="Currently Not Implemented")
|
||||
|
||||
def create_host_vnic_config(self, dv_switch_uuid, portgroup_key):
|
||||
host_vnic_config = vim.host.VirtualNic.Config()
|
||||
host_vnic_config.spec = vim.host.VirtualNic.Specification()
|
||||
|
||||
host_vnic_config.changeOperation = "edit"
|
||||
host_vnic_config.device = self.device
|
||||
host_vnic_config.portgroup = ""
|
||||
host_vnic_config.spec.distributedVirtualPort = vim.dvs.PortConnection()
|
||||
host_vnic_config.spec.distributedVirtualPort.switchUuid = dv_switch_uuid
|
||||
host_vnic_config.spec.distributedVirtualPort.portgroupKey = portgroup_key
|
||||
|
||||
return host_vnic_config
|
||||
|
||||
def create_port_group_config(self):
|
||||
port_group_config = vim.host.PortGroup.Config()
|
||||
port_group_config.spec = vim.host.PortGroup.Specification()
|
||||
|
||||
port_group_config.changeOperation = "remove"
|
||||
port_group_config.spec.name = self.current_portgroup_name
|
||||
port_group_config.spec.vlanId = -1
|
||||
port_group_config.spec.vswitchName = self.current_switch_name
|
||||
port_group_config.spec.policy = vim.host.NetworkPolicy()
|
||||
|
||||
return port_group_config
|
||||
|
||||
def state_migrate_vss_vds(self):
|
||||
host_network_system = self.host_system.configManager.networkSystem
|
||||
|
||||
dv_switch = find_dvs_by_name(self.content, self.migrate_switch_name)
|
||||
pg = find_dvspg_by_name(dv_switch, self.migrate_portgroup_name)
|
||||
|
||||
config = vim.host.NetworkConfig()
|
||||
config.portgroup = [self.create_port_group_config()]
|
||||
config.vnic = [self.create_host_vnic_config(dv_switch.uuid, pg.key)]
|
||||
host_network_system.UpdateNetworkConfig(config, "modify")
|
||||
self.module.exit_json(changed=True)
|
||||
|
||||
def check_vmk_current_state(self):
|
||||
self.host_system = find_hostsystem_by_name(self.content, self.esxi_hostname)
|
||||
|
||||
for vnic in self.host_system.configManager.networkSystem.networkInfo.vnic:
|
||||
if vnic.device == self.device:
|
||||
#self.vnic = vnic
|
||||
if vnic.spec.distributedVirtualPort is None:
|
||||
if vnic.portgroup == self.current_portgroup_name:
|
||||
return "migrate_vss_vds"
|
||||
else:
|
||||
dvs = find_dvs_by_name(self.content, self.current_switch_name)
|
||||
if dvs is None:
|
||||
return "migrated"
|
||||
if vnic.spec.distributedVirtualPort.switchUuid == dvs.uuid:
|
||||
return "migrate_vds_vss"
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(esxi_hostname=dict(required=True, type='str'),
|
||||
device=dict(required=True, type='str'),
|
||||
current_switch_name=dict(required=True, type='str'),
|
||||
current_portgroup_name=dict(required=True, type='str'),
|
||||
migrate_switch_name=dict(required=True, type='str'),
|
||||
migrate_portgroup_name=dict(required=True, type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
self.module.fail_json(msg='pyvmomi required for this module')
|
||||
|
||||
vmware_migrate_vmk = VMwareMigrateVmk(module)
|
||||
vmware_migrate_vmk.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
167
lib/ansible/modules/cloud/vmware/vmware_portgroup.py
Normal file
167
lib/ansible/modules/cloud/vmware/vmware_portgroup.py
Normal file
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_portgroup
|
||||
short_description: Create a VMware portgroup
|
||||
description:
|
||||
- Create a VMware portgroup
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
switch_name:
|
||||
description:
|
||||
- vSwitch to modify
|
||||
required: True
|
||||
portgroup_name:
|
||||
description:
|
||||
- Portgroup name to add
|
||||
required: True
|
||||
vlan_id:
|
||||
description:
|
||||
- VLAN ID to assign to portgroup
|
||||
required: True
|
||||
network_policy:
|
||||
description:
|
||||
- Network policy specifies layer 2 security settings for a
|
||||
portgroup such as promiscuous mode, where guest adapter listens
|
||||
to all the packets, MAC address changes and forged transmits.
|
||||
Settings are promiscuous_mode, forged_transmits, mac_changes
|
||||
required: False
|
||||
version_added: "2.2"
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Example from Ansible playbook
|
||||
|
||||
- name: Add Management Network VM Portgroup
|
||||
local_action:
|
||||
module: vmware_portgroup
|
||||
hostname: esxi_hostname
|
||||
username: esxi_username
|
||||
password: esxi_password
|
||||
switch_name: vswitch_name
|
||||
portgroup_name: portgroup_name
|
||||
vlan_id: vlan_id
|
||||
|
||||
- name: Add Portgroup with Promiscuous Mode Enabled
|
||||
local_action:
|
||||
module: vmware_portgroup
|
||||
hostname: esxi_hostname
|
||||
username: esxi_username
|
||||
password: esxi_password
|
||||
switch_name: vswitch_name
|
||||
portgroup_name: portgroup_name
|
||||
network_policy:
|
||||
promiscuous_mode: True
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def create_network_policy(promiscuous_mode, forged_transmits, mac_changes):
|
||||
|
||||
security_policy = vim.host.NetworkPolicy.SecurityPolicy()
|
||||
if promiscuous_mode:
|
||||
security_policy.allowPromiscuous = promiscuous_mode
|
||||
if forged_transmits:
|
||||
security_policy.forgedTransmits = forged_transmits
|
||||
if mac_changes:
|
||||
security_policy.macChanges = mac_changes
|
||||
network_policy = vim.host.NetworkPolicy(security=security_policy)
|
||||
return network_policy
|
||||
|
||||
|
||||
def create_port_group(host_system, portgroup_name, vlan_id, vswitch_name, network_policy):
|
||||
|
||||
config = vim.host.NetworkConfig()
|
||||
config.portgroup = [vim.host.PortGroup.Config()]
|
||||
config.portgroup[0].changeOperation = "add"
|
||||
config.portgroup[0].spec = vim.host.PortGroup.Specification()
|
||||
config.portgroup[0].spec.name = portgroup_name
|
||||
config.portgroup[0].spec.vlanId = vlan_id
|
||||
config.portgroup[0].spec.vswitchName = vswitch_name
|
||||
config.portgroup[0].spec.policy = network_policy
|
||||
|
||||
host_network_config_result = host_system.configManager.networkSystem.UpdateNetworkConfig(config, "modify")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(portgroup_name=dict(required=True, type='str'),
|
||||
switch_name=dict(required=True, type='str'),
|
||||
vlan_id=dict(required=True, type='int'),
|
||||
network_policy=dict(required=False, type='dict', default={})))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
portgroup_name = module.params['portgroup_name']
|
||||
switch_name = module.params['switch_name']
|
||||
vlan_id = module.params['vlan_id']
|
||||
promiscuous_mode = module.params['network_policy'].get('promiscuous_mode', None)
|
||||
forged_transmits = module.params['network_policy'].get('forged_transmits', None)
|
||||
mac_changes = module.params['network_policy'].get('mac_changes', None)
|
||||
|
||||
try:
|
||||
content = connect_to_api(module)
|
||||
host = get_all_objs(content, [vim.HostSystem])
|
||||
if not host:
|
||||
raise SystemExit("Unable to locate Physical Host.")
|
||||
host_system = host.keys()[0]
|
||||
|
||||
if find_host_portgroup_by_name(host_system, portgroup_name):
|
||||
module.exit_json(changed=False)
|
||||
|
||||
network_policy = create_network_policy(promiscuous_mode, forged_transmits, mac_changes)
|
||||
changed = create_port_group(host_system, portgroup_name, vlan_id, switch_name, network_policy)
|
||||
|
||||
module.exit_json(changed=changed)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_target_canonical_facts
|
||||
short_description: Return canonical (NAA) from an ESXi host
|
||||
description:
|
||||
- Return canonical (NAA) from an ESXi host based on SCSI target ID
|
||||
version_added: "2.0"
|
||||
author: Joseph Callen
|
||||
notes:
|
||||
requirements:
|
||||
- Tested on vSphere 5.5
|
||||
- PyVmomi installed
|
||||
options:
|
||||
target_id:
|
||||
description:
|
||||
- The target id based on order of scsi device
|
||||
required: True
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example vmware_target_canonical_facts command from Ansible Playbooks
|
||||
- name: Get Canonical name
|
||||
local_action: >
|
||||
vmware_target_canonical_facts
|
||||
hostname="{{ ansible_ssh_host }}" username=root password=vmware
|
||||
target_id=7
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def find_hostsystem(content):
|
||||
host_system = get_all_objs(content, [vim.HostSystem])
|
||||
for host in host_system:
|
||||
return host
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(target_id=dict(required=True, type='int')))
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
content = connect_to_api(module)
|
||||
host = find_hostsystem(content)
|
||||
|
||||
target_lun_uuid = {}
|
||||
scsilun_canonical = {}
|
||||
|
||||
# Associate the scsiLun key with the canonicalName (NAA)
|
||||
for scsilun in host.config.storageDevice.scsiLun:
|
||||
scsilun_canonical[scsilun.key] = scsilun.canonicalName
|
||||
|
||||
# Associate target number with LUN uuid
|
||||
for target in host.config.storageDevice.scsiTopology.adapter[0].target:
|
||||
for lun in target.lun:
|
||||
target_lun_uuid[target.target] = lun.scsiLun
|
||||
|
||||
module.exit_json(changed=False, canonical=scsilun_canonical[target_lun_uuid[module.params['target_id']]])
|
||||
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.vmware import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
105
lib/ansible/modules/cloud/vmware/vmware_vm_facts.py
Normal file
105
lib/ansible/modules/cloud/vmware/vmware_vm_facts.py
Normal file
|
@ -0,0 +1,105 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vm_facts
|
||||
short_description: Return basic facts pertaining to a vSphere virtual machine guest
|
||||
description:
|
||||
- Return basic facts pertaining to a vSphere virtual machine guest
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Gather all registered virtual machines
|
||||
local_action:
|
||||
module: vmware_vm_facts
|
||||
hostname: esxi_or_vcenter_ip_or_hostname
|
||||
username: username
|
||||
password: password
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
# https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/getallvms.py
|
||||
def get_all_virtual_machines(content):
|
||||
virtual_machines = get_all_objs(content, [vim.VirtualMachine])
|
||||
_virtual_machines = {}
|
||||
|
||||
for vm in virtual_machines:
|
||||
_ip_address = ""
|
||||
summary = vm.summary
|
||||
if summary.guest is not None:
|
||||
_ip_address = summary.guest.ipAddress
|
||||
if _ip_address is None:
|
||||
_ip_address = ""
|
||||
|
||||
virtual_machine = {
|
||||
summary.config.name: {
|
||||
"guest_fullname": summary.config.guestFullName,
|
||||
"power_state": summary.runtime.powerState,
|
||||
"ip_address": _ip_address
|
||||
}
|
||||
}
|
||||
|
||||
_virtual_machines.update(virtual_machine)
|
||||
return _virtual_machines
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
try:
|
||||
content = connect_to_api(module)
|
||||
_virtual_machines = get_all_virtual_machines(content)
|
||||
module.exit_json(changed=False, virtual_machines=_virtual_machines)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
190
lib/ansible/modules/cloud/vmware/vmware_vm_shell.py
Normal file
190
lib/ansible/modules/cloud/vmware/vmware_vm_shell.py
Normal file
|
@ -0,0 +1,190 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, 2016 Ritesh Khadgaray <khadgaray () gmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vm_shell
|
||||
short_description: Execute a process in VM
|
||||
description:
|
||||
- Start a program in a VM without the need for network connection
|
||||
version_added: 2.1
|
||||
author: "Ritesh Khadgaray (@ritzk)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
- Only the first match against vm_id is used, even if there are multiple matches
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
datacenter:
|
||||
description:
|
||||
- The datacenter hosting the VM
|
||||
- Will help speed up search
|
||||
required: False
|
||||
default: None
|
||||
cluster:
|
||||
description:
|
||||
- The cluster hosting the VM
|
||||
- Will help speed up search
|
||||
required: False
|
||||
default: None
|
||||
vm_id:
|
||||
description:
|
||||
- The identification for the VM
|
||||
required: True
|
||||
vm_id_type:
|
||||
description:
|
||||
- The identification tag for the VM
|
||||
default: vm_name
|
||||
choices:
|
||||
- 'uuid'
|
||||
- 'dns_name'
|
||||
- 'inventory_path'
|
||||
- 'vm_name'
|
||||
required: False
|
||||
vm_username:
|
||||
description:
|
||||
- The user to connect to the VM.
|
||||
required: False
|
||||
default: None
|
||||
vm_password:
|
||||
description:
|
||||
- The password used to login to the VM.
|
||||
required: False
|
||||
default: None
|
||||
vm_shell:
|
||||
description:
|
||||
- The absolute path to the program to start. On Linux this is executed via bash.
|
||||
required: True
|
||||
vm_shell_args:
|
||||
description:
|
||||
- The argument to the program.
|
||||
required: False
|
||||
default: None
|
||||
vm_shell_env:
|
||||
description:
|
||||
- Comma seperated list of envirnoment variable, specified in the guest OS notation
|
||||
required: False
|
||||
default: None
|
||||
vm_shell_cwd:
|
||||
description:
|
||||
- The current working directory of the application from which it will be run
|
||||
required: False
|
||||
default: None
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: shell execution
|
||||
local_action:
|
||||
module: vmware_vm_shell
|
||||
hostname: myVSphere
|
||||
username: myUsername
|
||||
password: mySecret
|
||||
datacenter: myDatacenter
|
||||
vm_id: NameOfVM
|
||||
vm_username: root
|
||||
vm_password: superSecret
|
||||
vm_shell: /bin/echo
|
||||
vm_shell_args: " $var >> myFile "
|
||||
vm_shell_env:
|
||||
- "PATH=/bin"
|
||||
- "VAR=test"
|
||||
vm_shell_cwd: "/tmp"
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
# https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/execute_program_in_vm.py
|
||||
def execute_command(content, vm, vm_username, vm_password, program_path, args="", env=None, cwd=None):
|
||||
|
||||
creds = vim.vm.guest.NamePasswordAuthentication(username=vm_username, password=vm_password)
|
||||
cmdspec = vim.vm.guest.ProcessManager.ProgramSpec(arguments=args, envVariables=env, programPath=program_path, workingDirectory=cwd)
|
||||
cmdpid = content.guestOperationsManager.processManager.StartProgramInGuest(vm=vm, auth=creds, spec=cmdspec)
|
||||
|
||||
return cmdpid
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(datacenter=dict(default=None, type='str'),
|
||||
cluster=dict(default=None, type='str'),
|
||||
vm_id=dict(required=True, type='str'),
|
||||
vm_id_type=dict(default='vm_name', type='str', choices=['inventory_path', 'uuid', 'dns_name', 'vm_name']),
|
||||
vm_username=dict(required=False, type='str'),
|
||||
vm_password=dict(required=False, type='str', no_log=True),
|
||||
vm_shell=dict(required=True, type='str'),
|
||||
vm_shell_args=dict(default=" ", type='str'),
|
||||
vm_shell_env=dict(default=None, type='list'),
|
||||
vm_shell_cwd=dict(default=None, type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(changed=False, msg='pyvmomi is required for this module')
|
||||
|
||||
|
||||
try:
|
||||
p = module.params
|
||||
datacenter_name = p['datacenter']
|
||||
cluster_name = p['cluster']
|
||||
content = connect_to_api(module)
|
||||
|
||||
datacenter = None
|
||||
if datacenter_name:
|
||||
datacenter = find_datacenter_by_name(content, datacenter_name)
|
||||
if not datacenter:
|
||||
module.fail_json(changed=False, msg="datacenter not found")
|
||||
|
||||
cluster = None
|
||||
if cluster_name:
|
||||
cluster = find_cluster_by_name(content, cluster_name, datacenter)
|
||||
if not cluster:
|
||||
module.fail_json(changed=False, msg="cluster not found")
|
||||
|
||||
vm = find_vm_by_id(content, p['vm_id'], p['vm_id_type'], datacenter, cluster)
|
||||
if not vm:
|
||||
module.fail_json(msg='VM not found')
|
||||
|
||||
msg = execute_command(content, vm, p['vm_username'], p['vm_password'],
|
||||
p['vm_shell'], p['vm_shell_args'], p['vm_shell_env'], p['vm_shell_cwd'])
|
||||
|
||||
module.exit_json(changed=True, uuid=vm.summary.config.uuid, msg=msg)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(changed=False, msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(changed=False, msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
module.fail_json(changed=False, msg=str(e))
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
162
lib/ansible/modules/cloud/vmware/vmware_vm_vss_dvs_migrate.py
Normal file
162
lib/ansible/modules/cloud/vmware/vmware_vm_vss_dvs_migrate.py
Normal file
|
@ -0,0 +1,162 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vm_vss_dvs_migrate
|
||||
short_description: Migrates a virtual machine from a standard vswitch to distributed
|
||||
description:
|
||||
- Migrates a virtual machine from a standard vswitch to distributed
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
vm_name:
|
||||
description:
|
||||
- Name of the virtual machine to migrate to a dvSwitch
|
||||
required: True
|
||||
dvportgroup_name:
|
||||
description:
|
||||
- Name of the portgroup to migrate to the virtual machine to
|
||||
required: True
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Migrate VCSA to vDS
|
||||
local_action:
|
||||
module: vmware_vm_vss_dvs_migrate
|
||||
hostname: vcenter_ip_or_hostname
|
||||
username: vcenter_username
|
||||
password: vcenter_password
|
||||
vm_name: virtual_machine_name
|
||||
dvportgroup_name: distributed_portgroup_name
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
class VMwareVmVssDvsMigrate(object):
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.content = connect_to_api(module)
|
||||
self.vm = None
|
||||
self.vm_name = module.params['vm_name']
|
||||
self.dvportgroup_name = module.params['dvportgroup_name']
|
||||
|
||||
def process_state(self):
|
||||
vm_nic_states = {
|
||||
'absent': self.migrate_network_adapter_vds,
|
||||
'present': self.state_exit_unchanged,
|
||||
}
|
||||
|
||||
vm_nic_states[self.check_vm_network_state()]()
|
||||
|
||||
def find_dvspg_by_name(self):
|
||||
vmware_distributed_port_group = get_all_objs(self.content, [vim.dvs.DistributedVirtualPortgroup])
|
||||
for dvspg in vmware_distributed_port_group:
|
||||
if dvspg.name == self.dvportgroup_name:
|
||||
return dvspg
|
||||
return None
|
||||
|
||||
def find_vm_by_name(self):
|
||||
virtual_machines = get_all_objs(self.content, [vim.VirtualMachine])
|
||||
for vm in virtual_machines:
|
||||
if vm.name == self.vm_name:
|
||||
return vm
|
||||
return None
|
||||
|
||||
def migrate_network_adapter_vds(self):
|
||||
vm_configspec = vim.vm.ConfigSpec()
|
||||
nic = vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo()
|
||||
port = vim.dvs.PortConnection()
|
||||
devicespec = vim.vm.device.VirtualDeviceSpec()
|
||||
|
||||
pg = self.find_dvspg_by_name()
|
||||
|
||||
if pg is None:
|
||||
self.module.fail_json(msg="The standard portgroup was not found")
|
||||
|
||||
dvswitch = pg.config.distributedVirtualSwitch
|
||||
port.switchUuid = dvswitch.uuid
|
||||
port.portgroupKey = pg.key
|
||||
nic.port = port
|
||||
|
||||
for device in self.vm.config.hardware.device:
|
||||
if isinstance(device, vim.vm.device.VirtualEthernetCard):
|
||||
devicespec.device = device
|
||||
devicespec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
|
||||
devicespec.device.backing = nic
|
||||
vm_configspec.deviceChange.append(devicespec)
|
||||
|
||||
task = self.vm.ReconfigVM_Task(vm_configspec)
|
||||
changed, result = wait_for_task(task)
|
||||
self.module.exit_json(changed=changed, result=result)
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def check_vm_network_state(self):
|
||||
try:
|
||||
self.vm = self.find_vm_by_name()
|
||||
|
||||
if self.vm is None:
|
||||
self.module.fail_json(msg="A virtual machine with name %s does not exist" % self.vm_name)
|
||||
for device in self.vm.config.hardware.device:
|
||||
if isinstance(device, vim.vm.device.VirtualEthernetCard):
|
||||
if isinstance(device.backing, vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo):
|
||||
return 'present'
|
||||
return 'absent'
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(vm_name=dict(required=True, type='str'),
|
||||
dvportgroup_name=dict(required=True, type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmware_vmnic_migrate = VMwareVmVssDvsMigrate(module)
|
||||
vmware_vmnic_migrate.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
212
lib/ansible/modules/cloud/vmware/vmware_vmkernel.py
Normal file
212
lib/ansible/modules/cloud/vmware/vmware_vmkernel.py
Normal file
|
@ -0,0 +1,212 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vmkernel
|
||||
short_description: Create a VMware VMkernel Interface
|
||||
description:
|
||||
- Create a VMware VMkernel Interface
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
vswitch_name:
|
||||
description:
|
||||
- The name of the vswitch where to add the VMK interface
|
||||
required: True
|
||||
portgroup_name:
|
||||
description:
|
||||
- The name of the portgroup for the VMK interface
|
||||
required: True
|
||||
ip_address:
|
||||
description:
|
||||
- The IP Address for the VMK interface
|
||||
required: True
|
||||
subnet_mask:
|
||||
description:
|
||||
- The Subnet Mask for the VMK interface
|
||||
required: True
|
||||
vland_id:
|
||||
description:
|
||||
- The VLAN ID for the VMK interface
|
||||
required: True
|
||||
mtu:
|
||||
description:
|
||||
- The MTU for the VMK interface
|
||||
required: False
|
||||
enable_vsan:
|
||||
description:
|
||||
- Enable the VMK interface for VSAN traffic
|
||||
required: False
|
||||
enable_vmotion:
|
||||
description:
|
||||
- Enable the VMK interface for vMotion traffic
|
||||
required: False
|
||||
enable_mgmt:
|
||||
description:
|
||||
- Enable the VMK interface for Management traffic
|
||||
required: False
|
||||
enable_ft:
|
||||
description:
|
||||
- Enable the VMK interface for Fault Tolerance traffic
|
||||
required: False
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example command from Ansible Playbook
|
||||
|
||||
- name: Add Management vmkernel port (vmk1)
|
||||
local_action:
|
||||
module: vmware_vmkernel
|
||||
hostname: esxi_hostname
|
||||
username: esxi_username
|
||||
password: esxi_password
|
||||
vswitch_name: vswitch_name
|
||||
portgroup_name: portgroup_name
|
||||
vlan_id: vlan_id
|
||||
ip_address: ip_address
|
||||
subnet_mask: subnet_mask
|
||||
enable_mgmt: True
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def create_vmkernel_adapter(host_system, port_group_name,
|
||||
vlan_id, vswitch_name,
|
||||
ip_address, subnet_mask,
|
||||
mtu, enable_vsan, enable_vmotion, enable_mgmt, enable_ft):
|
||||
|
||||
host_config_manager = host_system.configManager
|
||||
host_network_system = host_config_manager.networkSystem
|
||||
host_virtual_vic_manager = host_config_manager.virtualNicManager
|
||||
config = vim.host.NetworkConfig()
|
||||
|
||||
config.portgroup = [vim.host.PortGroup.Config()]
|
||||
config.portgroup[0].changeOperation = "add"
|
||||
config.portgroup[0].spec = vim.host.PortGroup.Specification()
|
||||
config.portgroup[0].spec.name = port_group_name
|
||||
config.portgroup[0].spec.vlanId = vlan_id
|
||||
config.portgroup[0].spec.vswitchName = vswitch_name
|
||||
config.portgroup[0].spec.policy = vim.host.NetworkPolicy()
|
||||
|
||||
config.vnic = [vim.host.VirtualNic.Config()]
|
||||
config.vnic[0].changeOperation = "add"
|
||||
config.vnic[0].portgroup = port_group_name
|
||||
config.vnic[0].spec = vim.host.VirtualNic.Specification()
|
||||
config.vnic[0].spec.ip = vim.host.IpConfig()
|
||||
config.vnic[0].spec.ip.dhcp = False
|
||||
config.vnic[0].spec.ip.ipAddress = ip_address
|
||||
config.vnic[0].spec.ip.subnetMask = subnet_mask
|
||||
if mtu:
|
||||
config.vnic[0].spec.mtu = mtu
|
||||
|
||||
host_network_config_result = host_network_system.UpdateNetworkConfig(config, "modify")
|
||||
|
||||
for vnic_device in host_network_config_result.vnicDevice:
|
||||
if enable_vsan:
|
||||
vsan_system = host_config_manager.vsanSystem
|
||||
vsan_config = vim.vsan.host.ConfigInfo()
|
||||
vsan_config.networkInfo = vim.vsan.host.ConfigInfo.NetworkInfo()
|
||||
|
||||
vsan_config.networkInfo.port = [vim.vsan.host.ConfigInfo.NetworkInfo.PortConfig()]
|
||||
|
||||
vsan_config.networkInfo.port[0].device = vnic_device
|
||||
host_vsan_config_result = vsan_system.UpdateVsan_Task(vsan_config)
|
||||
|
||||
if enable_vmotion:
|
||||
host_virtual_vic_manager.SelectVnicForNicType("vmotion", vnic_device)
|
||||
|
||||
if enable_mgmt:
|
||||
host_virtual_vic_manager.SelectVnicForNicType("management", vnic_device)
|
||||
|
||||
if enable_ft:
|
||||
host_virtual_vic_manager.SelectVnicForNicType("faultToleranceLogging", vnic_device)
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(portgroup_name=dict(required=True, type='str'),
|
||||
ip_address=dict(required=True, type='str'),
|
||||
subnet_mask=dict(required=True, type='str'),
|
||||
mtu=dict(required=False, type='int'),
|
||||
enable_vsan=dict(required=False, type='bool'),
|
||||
enable_vmotion=dict(required=False, type='bool'),
|
||||
enable_mgmt=dict(required=False, type='bool'),
|
||||
enable_ft=dict(required=False, type='bool'),
|
||||
vswitch_name=dict(required=True, type='str'),
|
||||
vlan_id=dict(required=True, type='int')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
port_group_name = module.params['portgroup_name']
|
||||
ip_address = module.params['ip_address']
|
||||
subnet_mask = module.params['subnet_mask']
|
||||
mtu = module.params['mtu']
|
||||
enable_vsan = module.params['enable_vsan']
|
||||
enable_vmotion = module.params['enable_vmotion']
|
||||
enable_mgmt = module.params['enable_mgmt']
|
||||
enable_ft = module.params['enable_ft']
|
||||
vswitch_name = module.params['vswitch_name']
|
||||
vlan_id = module.params['vlan_id']
|
||||
|
||||
try:
|
||||
content = connect_to_api(module)
|
||||
host = get_all_objs(content, [vim.HostSystem])
|
||||
if not host:
|
||||
module.fail_json(msg="Unable to locate Physical Host.")
|
||||
host_system = host.keys()[0]
|
||||
changed = create_vmkernel_adapter(host_system, port_group_name,
|
||||
vlan_id, vswitch_name,
|
||||
ip_address, subnet_mask,
|
||||
mtu, enable_vsan, enable_vmotion, enable_mgmt, enable_ft)
|
||||
module.exit_json(changed=changed)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
127
lib/ansible/modules/cloud/vmware/vmware_vmkernel_ip_config.py
Normal file
127
lib/ansible/modules/cloud/vmware/vmware_vmkernel_ip_config.py
Normal file
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vmkernel_ip_config
|
||||
short_description: Configure the VMkernel IP Address
|
||||
description:
|
||||
- Configure the VMkernel IP Address
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
vmk_name:
|
||||
description:
|
||||
- VMkernel interface name
|
||||
required: True
|
||||
ip_address:
|
||||
description:
|
||||
- IP address to assign to VMkernel interface
|
||||
required: True
|
||||
subnet_mask:
|
||||
description:
|
||||
- Subnet Mask to assign to VMkernel interface
|
||||
required: True
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example command from Ansible Playbook
|
||||
|
||||
- name: Configure IP address on ESX host
|
||||
local_action:
|
||||
module: vmware_vmkernel_ip_config
|
||||
hostname: esxi_hostname
|
||||
username: esxi_username
|
||||
password: esxi_password
|
||||
vmk_name: vmk0
|
||||
ip_address: 10.0.0.10
|
||||
subnet_mask: 255.255.255.0
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def configure_vmkernel_ip_address(host_system, vmk_name, ip_address, subnet_mask):
|
||||
|
||||
host_config_manager = host_system.configManager
|
||||
host_network_system = host_config_manager.networkSystem
|
||||
|
||||
for vnic in host_network_system.networkConfig.vnic:
|
||||
if vnic.device == vmk_name:
|
||||
spec = vnic.spec
|
||||
if spec.ip.ipAddress != ip_address:
|
||||
spec.ip.dhcp = False
|
||||
spec.ip.ipAddress = ip_address
|
||||
spec.ip.subnetMask = subnet_mask
|
||||
host_network_system.UpdateVirtualNic(vmk_name, spec)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(vmk_name=dict(required=True, type='str'),
|
||||
ip_address=dict(required=True, type='str'),
|
||||
subnet_mask=dict(required=True, type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
vmk_name = module.params['vmk_name']
|
||||
ip_address = module.params['ip_address']
|
||||
subnet_mask = module.params['subnet_mask']
|
||||
|
||||
try:
|
||||
content = connect_to_api(module, False)
|
||||
host = get_all_objs(content, [vim.HostSystem])
|
||||
if not host:
|
||||
module.fail_json(msg="Unable to locate Physical Host.")
|
||||
host_system = host.keys()[0]
|
||||
changed = configure_vmkernel_ip_address(host_system, vmk_name, ip_address, subnet_mask)
|
||||
module.exit_json(changed=changed)
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
154
lib/ansible/modules/cloud/vmware/vmware_vmotion.py
Normal file
154
lib/ansible/modules/cloud/vmware/vmware_vmotion.py
Normal file
|
@ -0,0 +1,154 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Bede Carroll <bc+github () bedecarroll.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vmotion
|
||||
short_description: Move a virtual machine using vMotion
|
||||
description:
|
||||
- Using VMware vCenter, move a virtual machine using vMotion to a different
|
||||
host.
|
||||
version_added: 2.2
|
||||
author: "Bede Carroll (@bedecarroll)"
|
||||
notes:
|
||||
- Tested on vSphere 6.0
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- pyVmomi
|
||||
options:
|
||||
vm_name:
|
||||
description:
|
||||
- Name of the VM to perform a vMotion on
|
||||
required: True
|
||||
aliases: ['vm']
|
||||
destination_host:
|
||||
description:
|
||||
- Name of the end host the VM should be running on
|
||||
required: True
|
||||
aliases: ['destination']
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Example from Ansible playbook
|
||||
|
||||
- name: Perform vMotion of VM
|
||||
local_action:
|
||||
module: vmware_vmotion
|
||||
hostname: 'vcenter_hostname'
|
||||
username: 'vcenter_username'
|
||||
password: 'vcenter_password'
|
||||
validate_certs: False
|
||||
vm_name: 'vm_name_as_per_vcenter'
|
||||
destination_host: 'destination_host_as_per_vcenter'
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
running_host:
|
||||
description: List the host the virtual machine is registered to
|
||||
returned:
|
||||
- changed
|
||||
- success
|
||||
type: string
|
||||
sample: 'host1.example.com'
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def migrate_vm(vm_object, host_object):
|
||||
"""
|
||||
Migrate virtual machine and return the task.
|
||||
"""
|
||||
relocate_spec = vim.vm.RelocateSpec(host=host_object)
|
||||
task_object = vm_object.Relocate(relocate_spec)
|
||||
return task_object
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(
|
||||
dict(
|
||||
vm_name=dict(required=True, aliases=['vm'], type='str'),
|
||||
destination_host=dict(required=True, aliases=['destination'], type='str'),
|
||||
)
|
||||
)
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyVmomi is required for this module')
|
||||
|
||||
content = connect_to_api(module=module)
|
||||
|
||||
vm_object = find_vm_by_name(content=content, vm_name=module.params['vm_name'])
|
||||
host_object = find_hostsystem_by_name(content=content, hostname=module.params['destination_host'])
|
||||
|
||||
# Setup result
|
||||
result = {
|
||||
'changed': False
|
||||
}
|
||||
|
||||
# Check if we could find the VM or Host
|
||||
if not vm_object:
|
||||
module.fail_json(msg='Cannot find virtual machine')
|
||||
if not host_object:
|
||||
module.fail_json(msg='Cannot find host')
|
||||
|
||||
# Make sure VM isn't already at the destination
|
||||
if vm_object.runtime.host.name == module.params['destination_host']:
|
||||
module.exit_json(**result)
|
||||
|
||||
if not module.check_mode:
|
||||
# Migrate VM and get Task object back
|
||||
task_object = migrate_vm(vm_object=vm_object, host_object=host_object)
|
||||
|
||||
# Wait for task to complete
|
||||
wait_for_task(task_object)
|
||||
|
||||
# If task was a success the VM has moved, update running_host and complete module
|
||||
if task_object.info.state == vim.TaskInfo.State.success:
|
||||
vm_object = find_vm_by_name(content=content, vm_name=module.params['vm_name'])
|
||||
result['running_host'] = vm_object.runtime.host.name
|
||||
result['changed'] = True
|
||||
module.exit_json(**result)
|
||||
else:
|
||||
if task_object.info.error is None:
|
||||
module.fail_json(msg='Unable to migrate VM due to an error, please check vCenter')
|
||||
else:
|
||||
module.fail_json(msg='Unable to migrate VM due to an error: %s' % task_object.info.error)
|
||||
else:
|
||||
# If we are in check mode return a result as if move was performed
|
||||
result['running_host'] = module.params['destination_host']
|
||||
result['changed'] = True
|
||||
module.exit_json(**result)
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.vmware import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
134
lib/ansible/modules/cloud/vmware/vmware_vsan_cluster.py
Normal file
134
lib/ansible/modules/cloud/vmware/vmware_vsan_cluster.py
Normal file
|
@ -0,0 +1,134 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Russell Teague <rteague2 () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vsan_cluster
|
||||
short_description: Configure VSAN clustering on an ESXi host
|
||||
description:
|
||||
- This module can be used to configure VSAN clustering on an ESXi host
|
||||
version_added: 2.0
|
||||
author: "Russell Teague (@mtnbikenc)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
cluster_uuid:
|
||||
description:
|
||||
- Desired cluster UUID
|
||||
required: False
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Example command from Ansible Playbook
|
||||
|
||||
- name: Configure VMware VSAN Cluster
|
||||
hosts: deploy_node
|
||||
gather_facts: False
|
||||
tags:
|
||||
- vsan
|
||||
tasks:
|
||||
- name: Configure VSAN on first host
|
||||
vmware_vsan_cluster:
|
||||
hostname: "{{ groups['esxi'][0] }}"
|
||||
username: "{{ esxi_username }}"
|
||||
password: "{{ site_password }}"
|
||||
register: vsan_cluster
|
||||
|
||||
- name: Configure VSAN on remaining hosts
|
||||
vmware_vsan_cluster:
|
||||
hostname: "{{ item }}"
|
||||
username: "{{ esxi_username }}"
|
||||
password: "{{ site_password }}"
|
||||
cluster_uuid: "{{ vsan_cluster.cluster_uuid }}"
|
||||
with_items: "{{ groups['esxi'][1:] }}"
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def create_vsan_cluster(host_system, new_cluster_uuid):
|
||||
host_config_manager = host_system.configManager
|
||||
vsan_system = host_config_manager.vsanSystem
|
||||
|
||||
vsan_config = vim.vsan.host.ConfigInfo()
|
||||
vsan_config.enabled = True
|
||||
|
||||
if new_cluster_uuid is not None:
|
||||
vsan_config.clusterInfo = vim.vsan.host.ConfigInfo.ClusterInfo()
|
||||
vsan_config.clusterInfo.uuid = new_cluster_uuid
|
||||
|
||||
vsan_config.storageInfo = vim.vsan.host.ConfigInfo.StorageInfo()
|
||||
vsan_config.storageInfo.autoClaimStorage = True
|
||||
|
||||
task = vsan_system.UpdateVsan_Task(vsan_config)
|
||||
changed, result = wait_for_task(task)
|
||||
|
||||
host_status = vsan_system.QueryHostStatus()
|
||||
cluster_uuid = host_status.uuid
|
||||
|
||||
return changed, result, cluster_uuid
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(cluster_uuid=dict(required=False, type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
new_cluster_uuid = module.params['cluster_uuid']
|
||||
|
||||
try:
|
||||
content = connect_to_api(module, False)
|
||||
host = get_all_objs(content, [vim.HostSystem])
|
||||
if not host:
|
||||
module.fail_json(msg="Unable to locate Physical Host.")
|
||||
host_system = host.keys()[0]
|
||||
changed, result, cluster_uuid = create_vsan_cluster(host_system, new_cluster_uuid)
|
||||
module.exit_json(changed=changed, result=result, cluster_uuid=cluster_uuid)
|
||||
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
module.fail_json(msg=str(e))
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
203
lib/ansible/modules/cloud/vmware/vmware_vswitch.py
Normal file
203
lib/ansible/modules/cloud/vmware/vmware_vswitch.py
Normal file
|
@ -0,0 +1,203 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Joseph Callen <jcallen () csc.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vmware_vswitch
|
||||
short_description: Add a VMware Standard Switch to an ESXi host
|
||||
description:
|
||||
- Add a VMware Standard Switch to an ESXi host
|
||||
version_added: 2.0
|
||||
author: "Joseph Callen (@jcpowermac), Russell Teague (@mtnbikenc)"
|
||||
notes:
|
||||
- Tested on vSphere 5.5
|
||||
requirements:
|
||||
- "python >= 2.6"
|
||||
- PyVmomi
|
||||
options:
|
||||
switch_name:
|
||||
description:
|
||||
- vSwitch name to add
|
||||
required: True
|
||||
nic_name:
|
||||
description:
|
||||
- vmnic name to attach to vswitch
|
||||
required: True
|
||||
number_of_ports:
|
||||
description:
|
||||
- Number of port to configure on vswitch
|
||||
default: 128
|
||||
required: False
|
||||
mtu:
|
||||
description:
|
||||
- MTU to configure on vswitch
|
||||
required: False
|
||||
state:
|
||||
description:
|
||||
- Add or remove the switch
|
||||
default: 'present'
|
||||
choices:
|
||||
- 'present'
|
||||
- 'absent'
|
||||
required: False
|
||||
extends_documentation_fragment: vmware.documentation
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
Example from Ansible playbook
|
||||
|
||||
- name: Add a VMware vSwitch
|
||||
local_action:
|
||||
module: vmware_vswitch
|
||||
hostname: esxi_hostname
|
||||
username: esxi_username
|
||||
password: esxi_password
|
||||
switch_name: vswitch_name
|
||||
nic_name: vmnic_name
|
||||
mtu: 9000
|
||||
'''
|
||||
|
||||
try:
|
||||
from pyVmomi import vim, vmodl
|
||||
HAS_PYVMOMI = True
|
||||
except ImportError:
|
||||
HAS_PYVMOMI = False
|
||||
|
||||
|
||||
def find_vswitch_by_name(host, vswitch_name):
|
||||
for vss in host.config.network.vswitch:
|
||||
if vss.name == vswitch_name:
|
||||
return vss
|
||||
return None
|
||||
|
||||
|
||||
class VMwareHostVirtualSwitch(object):
|
||||
|
||||
def __init__(self, module):
|
||||
self.host_system = None
|
||||
self.content = None
|
||||
self.vss = None
|
||||
self.module = module
|
||||
self.switch_name = module.params['switch_name']
|
||||
self.number_of_ports = module.params['number_of_ports']
|
||||
self.nic_name = module.params['nic_name']
|
||||
self.mtu = module.params['mtu']
|
||||
self.state = module.params['state']
|
||||
self.content = connect_to_api(self.module)
|
||||
|
||||
def process_state(self):
|
||||
try:
|
||||
vswitch_states = {
|
||||
'absent': {
|
||||
'present': self.state_destroy_vswitch,
|
||||
'absent': self.state_exit_unchanged,
|
||||
},
|
||||
'present': {
|
||||
'update': self.state_update_vswitch,
|
||||
'present': self.state_exit_unchanged,
|
||||
'absent': self.state_create_vswitch,
|
||||
}
|
||||
}
|
||||
|
||||
vswitch_states[self.state][self.check_vswitch_configuration()]()
|
||||
|
||||
except vmodl.RuntimeFault as runtime_fault:
|
||||
self.module.fail_json(msg=runtime_fault.msg)
|
||||
except vmodl.MethodFault as method_fault:
|
||||
self.module.fail_json(msg=method_fault.msg)
|
||||
except Exception as e:
|
||||
self.module.fail_json(msg=str(e))
|
||||
|
||||
|
||||
# Source from
|
||||
# https://github.com/rreubenur/pyvmomi-community-samples/blob/patch-1/samples/create_vswitch.py
|
||||
|
||||
def state_create_vswitch(self):
|
||||
vss_spec = vim.host.VirtualSwitch.Specification()
|
||||
vss_spec.numPorts = self.number_of_ports
|
||||
vss_spec.mtu = self.mtu
|
||||
vss_spec.bridge = vim.host.VirtualSwitch.BondBridge(nicDevice=[self.nic_name])
|
||||
self.host_system.configManager.networkSystem.AddVirtualSwitch(vswitchName=self.switch_name, spec=vss_spec)
|
||||
self.module.exit_json(changed=True)
|
||||
|
||||
def state_exit_unchanged(self):
|
||||
self.module.exit_json(changed=False)
|
||||
|
||||
def state_destroy_vswitch(self):
|
||||
config = vim.host.NetworkConfig()
|
||||
|
||||
for portgroup in self.host_system.configManager.networkSystem.networkInfo.portgroup:
|
||||
if portgroup.spec.vswitchName == self.vss.name:
|
||||
portgroup_config = vim.host.PortGroup.Config()
|
||||
portgroup_config.changeOperation = "remove"
|
||||
portgroup_config.spec = vim.host.PortGroup.Specification()
|
||||
portgroup_config.spec.name = portgroup.spec.name
|
||||
portgroup_config.spec.name = portgroup.spec.name
|
||||
portgroup_config.spec.vlanId = portgroup.spec.vlanId
|
||||
portgroup_config.spec.vswitchName = portgroup.spec.vswitchName
|
||||
portgroup_config.spec.policy = vim.host.NetworkPolicy()
|
||||
config.portgroup.append(portgroup_config)
|
||||
|
||||
self.host_system.configManager.networkSystem.UpdateNetworkConfig(config, "modify")
|
||||
self.host_system.configManager.networkSystem.RemoveVirtualSwitch(self.vss.name)
|
||||
self.module.exit_json(changed=True)
|
||||
|
||||
def state_update_vswitch(self):
|
||||
self.module.exit_json(changed=False, msg="Currently not implemented.")
|
||||
|
||||
def check_vswitch_configuration(self):
|
||||
host = get_all_objs(self.content, [vim.HostSystem])
|
||||
if not host:
|
||||
self.module.fail_json(msg="Unable to find host")
|
||||
|
||||
self.host_system = host.keys()[0]
|
||||
self.vss = find_vswitch_by_name(self.host_system, self.switch_name)
|
||||
|
||||
if self.vss is None:
|
||||
return 'absent'
|
||||
else:
|
||||
return 'present'
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = vmware_argument_spec()
|
||||
argument_spec.update(dict(switch_name=dict(required=True, type='str'),
|
||||
nic_name=dict(required=True, type='str'),
|
||||
number_of_ports=dict(required=False, type='int', default=128),
|
||||
mtu=dict(required=False, type='int', default=1500),
|
||||
state=dict(default='present', choices=['present', 'absent'], type='str')))
|
||||
|
||||
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False)
|
||||
|
||||
if not HAS_PYVMOMI:
|
||||
module.fail_json(msg='pyvmomi is required for this module')
|
||||
|
||||
host_virtual_switch = VMwareHostVirtualSwitch(module)
|
||||
host_virtual_switch.process_state()
|
||||
|
||||
from ansible.module_utils.vmware import *
|
||||
from ansible.module_utils.basic import *
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
195
lib/ansible/modules/cloud/vmware/vsphere_copy.py
Normal file
195
lib/ansible/modules/cloud/vmware/vsphere_copy.py
Normal file
|
@ -0,0 +1,195 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 Dag Wieers <dag@wieers.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
ANSIBLE_METADATA = {'status': ['preview'],
|
||||
'supported_by': 'community',
|
||||
'version': '1.0'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vsphere_copy
|
||||
short_description: Copy a file to a vCenter datastore
|
||||
description:
|
||||
- Upload files to a vCenter datastore
|
||||
version_added: 2.0
|
||||
author: Dag Wieers (@dagwieers) <dag@wieers.com>
|
||||
options:
|
||||
host:
|
||||
description:
|
||||
- The vCenter server on which the datastore is available.
|
||||
required: true
|
||||
login:
|
||||
description:
|
||||
- The login name to authenticate on the vCenter server.
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- The password to authenticate on the vCenter server.
|
||||
required: true
|
||||
src:
|
||||
description:
|
||||
- The file to push to vCenter
|
||||
required: true
|
||||
datacenter:
|
||||
description:
|
||||
- The datacenter on the vCenter server that holds the datastore.
|
||||
required: true
|
||||
datastore:
|
||||
description:
|
||||
- The datastore on the vCenter server to push files to.
|
||||
required: true
|
||||
path:
|
||||
description:
|
||||
- The file to push to the datastore on the vCenter server.
|
||||
required: true
|
||||
validate_certs:
|
||||
description:
|
||||
- If C(no), SSL certificates will not be validated. This should only be
|
||||
set to C(no) when no other option exists.
|
||||
required: false
|
||||
default: 'yes'
|
||||
choices: ['yes', 'no']
|
||||
|
||||
notes:
|
||||
- "This module ought to be run from a system that can access vCenter directly and has the file to transfer.
|
||||
It can be the normal remote target or you can change it either by using C(transport: local) or using C(delegate_to)."
|
||||
- Tested on vSphere 5.5
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- vsphere_copy:
|
||||
host: vhost
|
||||
login: vuser
|
||||
password: vpass
|
||||
src: /some/local/file
|
||||
datacenter: DC1 Someplace
|
||||
datastore: datastore1
|
||||
path: some/remote/file
|
||||
transport: local
|
||||
- vsphere_copy:
|
||||
host: vhost
|
||||
login: vuser
|
||||
password: vpass
|
||||
src: /other/local/file
|
||||
datacenter: DC2 Someplace
|
||||
datastore: datastore2
|
||||
path: other/remote/file
|
||||
delegate_to: other_system
|
||||
'''
|
||||
|
||||
import atexit
|
||||
import urllib
|
||||
import mmap
|
||||
import errno
|
||||
import socket
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.pycompat24 import get_exception
|
||||
from ansible.module_utils.urls import open_url
|
||||
|
||||
def vmware_path(datastore, datacenter, path):
|
||||
''' Constructs a URL path that VSphere accepts reliably '''
|
||||
path = "/folder/%s" % path.lstrip("/")
|
||||
# Due to a software bug in vSphere, it fails to handle ampersand in datacenter names
|
||||
# The solution is to do what vSphere does (when browsing) and double-encode ampersands, maybe others ?
|
||||
datacenter = datacenter.replace('&', '%26')
|
||||
if not path.startswith("/"):
|
||||
path = "/" + path
|
||||
params = dict( dsName = datastore )
|
||||
if datacenter:
|
||||
params["dcPath"] = datacenter
|
||||
params = urllib.urlencode(params)
|
||||
return "%s?%s" % (path, params)
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
host = dict(required=True, aliases=[ 'hostname' ]),
|
||||
login = dict(required=True, aliases=[ 'username' ]),
|
||||
password = dict(required=True, no_log=True),
|
||||
src = dict(required=True, aliases=[ 'name' ]),
|
||||
datacenter = dict(required=True),
|
||||
datastore = dict(required=True),
|
||||
dest = dict(required=True, aliases=[ 'path' ]),
|
||||
validate_certs = dict(required=False, default=True, type='bool'),
|
||||
),
|
||||
# Implementing check-mode using HEAD is impossible, since size/date is not 100% reliable
|
||||
supports_check_mode = False,
|
||||
)
|
||||
|
||||
host = module.params.get('host')
|
||||
login = module.params.get('login')
|
||||
password = module.params.get('password')
|
||||
src = module.params.get('src')
|
||||
datacenter = module.params.get('datacenter')
|
||||
datastore = module.params.get('datastore')
|
||||
dest = module.params.get('dest')
|
||||
validate_certs = module.params.get('validate_certs')
|
||||
|
||||
fd = open(src, "rb")
|
||||
atexit.register(fd.close)
|
||||
|
||||
data = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ)
|
||||
atexit.register(data.close)
|
||||
|
||||
remote_path = vmware_path(datastore, datacenter, dest)
|
||||
url = 'https://%s%s' % (host, remote_path)
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Length": str(len(data)),
|
||||
}
|
||||
|
||||
try:
|
||||
r = open_url(url, data=data, headers=headers, method='PUT',
|
||||
url_username=login, url_password=password, validate_certs=validate_certs,
|
||||
force_basic_auth=True)
|
||||
except socket.error:
|
||||
e = get_exception()
|
||||
if isinstance(e.args, tuple) and e[0] == errno.ECONNRESET:
|
||||
# VSphere resets connection if the file is in use and cannot be replaced
|
||||
module.fail_json(msg='Failed to upload, image probably in use', status=None, errno=e[0], reason=str(e), url=url)
|
||||
else:
|
||||
module.fail_json(msg=str(e), status=None, errno=e[0], reason=str(e), url=url)
|
||||
except Exception:
|
||||
e = get_exception()
|
||||
error_code = -1
|
||||
try:
|
||||
if isinstance(e[0], int):
|
||||
error_code = e[0]
|
||||
except KeyError:
|
||||
pass
|
||||
module.fail_json(msg=str(e), status=None, errno=error_code, reason=str(e), url=url)
|
||||
|
||||
status = r.getcode()
|
||||
if 200 <= status < 300:
|
||||
module.exit_json(changed=True, status=status, reason=r.msg, url=url)
|
||||
else:
|
||||
length = r.headers.get('content-length', None)
|
||||
if r.headers.get('transfer-encoding', '').lower() == 'chunked':
|
||||
chunked = 1
|
||||
else:
|
||||
chunked = 0
|
||||
|
||||
module.fail_json(msg='Failed to upload', errno=None, status=status, reason=r.msg, length=length, headers=dict(r.headers), chunked=chunked, url=url)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue