Repository: ansible/ansible

Issue:
cs_sshkeypair.py return FAILED when renaming a key

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report


##### COMPONENT NAME
cs_sshkeypair

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.4.3.0
  config file = /Users/nbari/projects/ansible/ansible.cfg
  configured module search path = [u'/Users/nbari/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/nbari/Library/Python/2.7/lib/python/site-packages/ansible
  executable location = /Users/nbari/Library/Python/2.7/bin/ansible
  python version = 2.7.14 (default, Feb  6 2018, 20:04:00) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)]

```

##### CONFIGURATION
default

##### OS / ENVIRONMENT
N/A

##### SUMMARY
<!--- Explain the problem briefly -->

##### 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.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
---
- hosts: localhost
  connection: local
  tasks:
    - name: ensure my ssh public key
      cs_sshkeypair:
        name: my-key
        public_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
        api_region: my-region
```

Change name to: `my-key-2` or something different and run again the playbook:

    ansible-playbook name-of-the-pb.yml

It will only work for the 2nd time, but the first one will get an error.


<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
No error or message specifying changed=1

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: 'NoneType' object has no attribute '__getitem__'
fatal: [localhost]: FAILED! => {"changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/var/folders/75/8jzhscr56j13rv6tj6805ch40000gn/T/ansible_P78L9S/ansible_module_cs_sshkeypair.py\", line 276, in <module>\n    main()\n  File \"/var/folders/75/8jzhscr56j13rv6tj6805ch40000gn/T/ansible_P78L9S/ansible_module_cs_sshkeypair.py\", line 267, in main\n    ssh_key = acs_sshkey.register_ssh_key(public_key)\n  File \"/var/folders/75/8jzhscr56j13rv6tj6805ch40000gn/T/ansible_P78L9S/ansible_module_cs_sshkeypair.py\", line 172, in register_ssh_key\n    if ssh_key['fingerprint'] != fingerprint:\nTypeError: 'NoneType' object has no attribute '__getitem__'\n", "module_stdout": "", "msg": "MODULE FAILURE", "rc": 1}

```



Discussion:
Files identified in the description:
* [lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @resmo
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@nbari which cloudstack version?

needs_info
Hi @resmo, the version I am using is `2.1.3`
@nbari that is the cs library version, but to which cloudstack api endpoint? exoscale? or other cloud?

needs_info
@resno, I am testing with exoscale
you wrote:
> Change name to: my-key-2 or something different and run again the playbook:

does that mean you change the name of that key in the UI and after you run the playbook again?
All within the playbook, nothing within the UI.
ok, thanks for the info, trying to reproduce.

Resolving patch:
diff --git a/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py b/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py
--- a/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py
+++ b/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py
@@ -169,7 +169,7 @@ def register_ssh_key(self, public_key):
                     # We need to make another lookup if there is a key with identical name.
                     self.ssh_key = None
                     ssh_key = self.get_ssh_key()
-                    if ssh_key['fingerprint'] != fingerprint:
+                    if ssh_key and ssh_key['fingerprint'] != fingerprint:
                         args['name'] = name
                         self.query_api('deleteSSHKeyPair', **args)
 


Test patch:
diff --git a/test/integration/targets/cs_sshkeypair/tasks/main.yml b/test/integration/targets/cs_sshkeypair/tasks/main.yml
--- a/test/integration/targets/cs_sshkeypair/tasks/main.yml
+++ b/test/integration/targets/cs_sshkeypair/tasks/main.yml
@@ -1,9 +1,17 @@
 ---
 - name: setup cleanup
-  cs_sshkeypair: name=first-sshkey state=absent
-
-- name: setup cleanup
-  cs_sshkeypair: name=second-sshkey state=absent
+  cs_sshkeypair:
+    name: "{{ item }}"
+    state: absent
+  register: sshkey
+  with_items:
+    - first-sshkey
+    - first-sshkey-renamed
+    - second-sshkey
+- name: verify setup cleanup
+  assert:
+    that:
+    - sshkey is success
 
 - name: test fail on missing name
   action: cs_sshkeypair
@@ -17,7 +25,7 @@
 
 - name: test ssh key creation in check mode
   cs_sshkeypair:
-    name: "first-sshkey"
+    name: first-sshkey
   register: sshkey
   check_mode: true
 - name: verify results of ssh key creation in check mode
@@ -28,7 +36,7 @@
 
 - name: test ssh key creation
   cs_sshkeypair:
-    name: "first-sshkey"
+    name: first-sshkey
   register: sshkey
 - name: verify results of ssh key creation
   assert:
@@ -41,7 +49,7 @@
 
 - name: test ssh key creation idempotence
   cs_sshkeypair:
-    name: "first-sshkey"
+    name: first-sshkey
   register: sshkey2
 - name: verify results of ssh key creation idempotence
   assert:
@@ -54,7 +62,7 @@
 
 - name: test replace ssh public key in check mode
   cs_sshkeypair:
-    name: "first-sshkey"
+    name: first-sshkey
     public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
   register: sshkey2
   check_mode: true
@@ -69,13 +77,12 @@
 
 - name: test replace ssh public key
   cs_sshkeypair:
-    name: "first-sshkey"
+    name: first-sshkey
     public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
   register: sshkey3
 - name: verify results of replace ssh public key
   assert:
     that:
-    - sshkey3 is successful
     - sshkey3 is changed
     - sshkey3.fingerprint is defined and sshkey3.fingerprint != sshkey2.fingerprint
     - sshkey3.private_key is not defined
@@ -83,31 +90,69 @@
 
 - name: test replace ssh public key idempotence
   cs_sshkeypair:
-    name: "first-sshkey"
+    name: first-sshkey
     public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
   register: sshkey4
 - name: verify results of ssh public key idempotence
   assert:
     that:
-    - sshkey4 is successful
     - sshkey4 is not changed
     - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
     - sshkey4.private_key is not defined
     - sshkey4.name == "first-sshkey"
 
-- name: setup ssh key with name "second-sshke"
+- name: test rename ssh key in check mode
   cs_sshkeypair:
-    name: "second-sshkey"
+    name: first-sshkey-renamed
+    public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+  register: sshkey4
+  check_mode: true
+- name: verify test rename ssh key in check mode
+  assert:
+    that:
+    - sshkey4 is changed
+    - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
+    - sshkey4.private_key is not defined
+    - sshkey4.name == "first-sshkey"
+
+- name: test rename ssh key
+  cs_sshkeypair:
+    name: first-sshkey-renamed
+    public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+  register: sshkey4
+- name: verify test rename ssh key
+  assert:
+    that:
+    - sshkey4 is changed
+    - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
+    - sshkey4.private_key is not defined
+    - sshkey4.name == "first-sshkey-renamed"
+
+- name: test rename ssh key idempotence
+  cs_sshkeypair:
+    name: first-sshkey-renamed
+    public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
+  register: sshkey4
+- name: verify test rename ssh key idempotence
+  assert:
+    that:
+    - sshkey4 is not changed
+    - sshkey4.fingerprint is defined and sshkey4.fingerprint == sshkey3.fingerprint
+    - sshkey4.private_key is not defined
+    - sshkey4.name == "first-sshkey-renamed"
+
+- name: setup ssh key with name "second-sshkey"
+  cs_sshkeypair:
+    name: second-sshkey
 
 - name: test different but exisitng name but same ssh public key as first-sshkey
   cs_sshkeypair:
-    name: "second-sshkey"
+    name: second-sshkey
     public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsTI7KJZ8tz/CwQIrSol41c6s3vzkGYCMI8o7P9Et48UG9eRoGaMaGYaTvBTj/VQrD7cfurI6Bn0HTT3FLK3OHOweyelm9rIiQ2hjkSl+2lIKWHu992GO58E5Gcy9yYW4sHGgGLNZkPBKrrj0w7lhmiHjPtVnf+2+7Ix1WOO2/HXPcAHhsX/AlyItDewIL4mr/BT83vq0202sPCiM2cFQJl+5WGwS1wYYK8d167cspsmdyX7OyAFCUB0vueuqjE8MFqJvyIJR9y8Lj9Ny71pSV5/QWrXUgELxMYOKSby3gHkxcIXgYBMFLl4DipRTO74OWQlRRaOlqXlOOQbikcY4T rene.moser@swisstxt.ch"
   register: sshkey
 - name: verify test different but exisitng name but same ssh public key as first-sshkey
   assert:
     that:
-    - sshkey is successful
     - sshkey is changed
     - sshkey.fingerprint is defined and sshkey.fingerprint == sshkey4.fingerprint
     - sshkey.private_key is not defined
@@ -120,31 +165,32 @@
 - name: verify result of key absent in check mode
   assert:
     that:
-    - sshkey5 is successful
     - sshkey5 is changed
     - sshkey5.fingerprint is defined and sshkey5.fingerprint == sshkey3.fingerprint
     - sshkey5.private_key is not defined
     - sshkey5.name == "second-sshkey"
 
 - name: test ssh key absent
-  cs_sshkeypair: name=second-sshkey state=absent
+  cs_sshkeypair:
+    name: second-sshkey
+    state: absent
   register: sshkey5
 - name: verify result of key absent
   assert:
     that:
-    - sshkey5 is successful
     - sshkey5 is changed
     - sshkey5.fingerprint is defined and sshkey5.fingerprint == sshkey3.fingerprint
     - sshkey5.private_key is not defined
     - sshkey5.name == "second-sshkey"
 
 - name: test ssh key absent idempotence
-  cs_sshkeypair: name=second-sshkey state=absent
+  cs_sshkeypair:
+    name: second-sshkey
+    state: absent
   register: sshkey6
 - name: verify result of ssh key absent idempotence
   assert:
     that:
-    - sshkey6 is successful
     - sshkey6 is not changed
     - sshkey6.fingerprint is not defined
     - sshkey6.private_key is not defined