Repository: ansible/ansible

Issue:
cs_host doesn't handle IP address based names properly
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
cs_host
##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.4.0
  config file = /home/john/.ansible.cfg
  configured module search path = [u'/home/john/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible-2.4.0-py2.7.egg/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.13 (default, May 10 2017, 20:04:28) [GCC 6.3.1 20161221 (Red Hat 6.3.1-1)]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->
N/A
##### SUMMARY
<!--- Explain the problem briefly -->
Using the Cloudstack API it is valid to provide an IP address as the name of the host to add. The cs_host module accepts this, and the host is successfully added to CloudStack.

The problem is that Cloudstack replaces the IP address with the hostname that it learns from the host that was added. CloudStack does record the IP address, but writes it to the ipaddress field, not the name field.

On subsequent runs of the ansible playbook cs_host does not recognise the host as being the same at that added previously.

I have a patch that solves this problem. I'll open a pull request shortly with the fix.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
Use the cs_host module passing an IP address instead of a hostname. On subsequent runs the added host will not be matched to the IP address.
<!--- Paste example playbooks or commands between quotes below -->
```yaml
  - name: Add compute hosts
    local_action:
      module: cs_host
      name: 192.168.1.10
      api_timeout: 120
      username: root
      password: "{{ compute_root_password }}"
      cluster: Xeon
      pod: Telehouse
      zone: London
      hypervisor: KVM
      allocation_state: enabled
      state: present
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Subsequent run of the playbook should recognise the host as already having been added.
##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
The host added in the first pass is not matched, and the hosted is added repeatedly.
<!--- Paste verbatim command output between quotes below -->
```
N/A
```



Discussion:
cc @resmo
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/cloud/cloudstack/cs_host.py b/lib/ansible/modules/cloud/cloudstack/cs_host.py
--- a/lib/ansible/modules/cloud/cloudstack/cs_host.py
+++ b/lib/ansible/modules/cloud/cloudstack/cs_host.py
@@ -36,7 +36,7 @@
     description:
       - Name of the host.
     required: true
-    aliases: [ 'url' ]
+    aliases: [ 'url', 'ip_address' ]
   username:
     description:
       - Username for the host.
@@ -428,13 +428,15 @@ def get_allocation_state(self):
 
     def get_host(self):
         host = None
+        name = self.module.params.get('name')
         args = {
             'zoneid': self.get_zone(key='id'),
-            'name': self.module.params.get('name'),
         }
-        hosts = self.cs.listHosts(**args)
-        if hosts:
-            host = hosts['host'][0]
+        res = self.cs.listHosts(**args)
+        if res:
+            for h in res['host']:
+                if name in [h['ipaddress'], h['name']]:
+                    host = h
         return host
 
     def present_host(self):
@@ -506,7 +508,7 @@ def absent_host(self):
 def main():
     argument_spec = cs_argument_spec()
     argument_spec.update(dict(
-        name=dict(required=True, aliases=['url']),
+        name=dict(required=True, aliases=['url', 'ip_address']),
         password=dict(default=None, no_log=True),
         username=dict(default=None),
         hypervisor=dict(choices=CS_HYPERVISORS, default=None),


Test patch: