Repository: ansible/ansible

Issue:
os_server fails against Rackspace on subsequent runs
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
os_server

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
devel
```

##### 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.
-->

Python 3.6.1
shade 1.20.0
python-novaclient 8.0.0 / 7.1.0

##### SUMMARY
After creating a server with `os_server` on Rackspace, subsequent calls to "ensure" the server is there, fails with:

```
  File "/tmp/ansible___iglsfb/ansible_module_os_server.py", line 758, in <module>
    main()
  File "/tmp/ansible___iglsfb/ansible_module_os_server.py", line 746, in main
    _get_server_state(module, cloud)
  File "/tmp/ansible___iglsfb/ansible_module_os_server.py", line 663, in _get_server_state
    (sg_changed, server) = _check_security_groups(module, cloud, server)
  File "/tmp/ansible___iglsfb/ansible_module_os_server.py", line 634, in _check_security_groups
    server_security_groups = set(sg.name for sg in server.security_groups)
TypeError: 'NoneType' object is not iterable
```

The following change resolves the issue for me:

```diff
diff --git a/lib/ansible/modules/cloud/openstack/os_server.py b/lib/ansible/modules/cloud/openstack/os_server.py
index e6298fa..2746820 100644
--- a/lib/ansible/modules/cloud/openstack/os_server.py
+++ b/lib/ansible/modules/cloud/openstack/os_server.py
@@ -631,7 +631,10 @@ def _check_security_groups(module, cloud, server):
         return changed, server
 
     module_security_groups = set(module.params['security_groups'])
-    server_security_groups = set(sg.name for sg in server.security_groups)
+    try:
+        server_security_groups = set(sg.name for sg in server.security_groups)
+    except TypeError:
+        return changed, server
 
     add_sgs = module_security_groups - server_security_groups
     remove_sgs = server_security_groups - module_security_groups
```

##### STEPS TO REPRODUCE

Task:

```
    - os_server:
        state: present
        cloud: sivel
        name: os_test
        flavor: general1-1
        image: e6baca58-c5f4-48d3-901a-abdeb0cfe907
        region_name: IAD
        wait: yes
        timeout: 300
        key_name: noc
        auto_ip: false
```

Run once to create the server, run again to "ensure" its existence.


##### EXPECTED RESULTS

No Exception

##### ACTUAL RESULTS

Exception


Discussion:
cc @emonty 
cc @shrews @juliakreger @j2sol @rcarrillocruz @thingee
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
This workaround in the code here is valid, and one we can apply to the os_server module at the moment ... but the bug is ultimately in shade. https://review.openstack.org/465672 is a patch that should make sure security_groups is always a list - which is what shade's data model contract says it should be.

Resolving patch:
diff --git a/lib/ansible/modules/cloud/openstack/os_server.py b/lib/ansible/modules/cloud/openstack/os_server.py
--- a/lib/ansible/modules/cloud/openstack/os_server.py
+++ b/lib/ansible/modules/cloud/openstack/os_server.py
@@ -631,7 +631,11 @@ def _check_security_groups(module, cloud, server):
         return changed, server
 
     module_security_groups = set(module.params['security_groups'])
-    server_security_groups = set(sg.name for sg in server.security_groups)
+    # Workaround a bug in shade <= 1.20.0
+    if server.security_groups is not None:
+        server_security_groups = set(sg.name for sg in server.security_groups)
+    else:
+        server_security_groups = set()
 
     add_sgs = module_security_groups - server_security_groups
     remove_sgs = server_security_groups - module_security_groups


Test patch: