Starting Openstack VMs in parallel

692 views
Skip to first unread message

Kurt Yoder

unread,
Jul 10, 2014, 6:17:48 PM7/10/14
to ansible...@googlegroups.com
Hello list,

I anticipate provisioning 10-20 VMs using Ansible, then assigning floating IPs to each, then waiting for SSH to become available for each VM. I would like to do this in parallel instead of serially. Specifically:

  • Start the VMs, but don't block
  • Assign the IPs, but don't block
  • Wait on SSH until all VMs respond

I saw the nova_compute "wait: 'no'" option, but when I use it I get a stack trace:

failed: [localhost] => (item=1) => {"failed": true, "item": 1, "parsed": false}
invalid output was: Traceback (most recent call last):
  File "/home/ubuntu/.ansible/tmp/ansible-tmp-1405028178.0-234314980043958/nova_compute", line 1490, in <module>
    main()
  File "/home/ubuntu/.ansible/tmp/ansible-tmp-1405028178.0-234314980043958/nova_compute", line 266, in main
    _create_server(module, nova)
  File "/home/ubuntu/.ansible/tmp/ansible-tmp-1405028178.0-234314980043958/nova_compute", line 194, in _create_server
    private = [ x['addr'] for x in getattr(server, 'addresses').itervalues().next() if x['OS-EXT-IPS:type'] == 'fixed']
StopIteration

Perhaps I'm using it incorrectly:

- name: Launch cluster VM on Openstack
  nova_compute:
    name: "{{ os_username }}_cluster1"
    state: present
    login_username: "{{ os_username }}"
    login_tenant_name: "{{ os_tenant }}"
    login_password: "{{ os_password }}"
    image_id: "{{ os_image_id }}"
    key_name: "{{ os_username }}_controller_key"
    wait: "no"
    flavor_id: "{{ os_flavor_id }}"
    auth_url: "{{ os_url }}"
    user_data: "#cloud-config\nmanage_etc_hosts: true"


So, two questions:

  1. Am I using "wait" correctly?
  2. Should I use "wait" to get to my desired parallel VM launch, as described above, or should I use something else, e.g. "async"?


Thanks,

-Kurt

Kurt Yoder

unread,
Jul 11, 2014, 5:20:34 PM7/11/14
to ansible...@googlegroups.com
Well, "async" is totally a bust. I got a message:

fatal: [localhost] => lookup plugins (with_*) cannot be used with async tasks

Kurt Yoder

unread,
Jul 11, 2014, 5:28:34 PM7/11/14
to ansible...@googlegroups.com
I guess that error is because I put a "with_items" in there.

How does everyone else do this? I don't understand how to loop asynchronously. See pseudo-code:

< start all 5 at once: >
   < start up openstack host >
   < assign it a floating ip >
   < capture the floating ip >
< end when all 5 have a floating ip >
< wait for all 5 floating IPs to have an open SSH port >

Michael DeHaan

unread,
Jul 11, 2014, 6:34:47 PM7/11/14
to ansible...@googlegroups.com
So some of the provisioning modules, like AWS in particular, support spinning up "N" modules at a time by passing "count" or "exact_count".

Rackspace I believe does this with manual looping (for now), but I could be wrong and that might have just been historical truth.

If the OpenStack API says we can launch 10 at once, it could be made to do similar things.




--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/32b58cdf-17cd-42c9-8ef6-dc90327e989a%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Kurt Yoder

unread,
Jul 11, 2014, 6:54:15 PM7/11/14
to ansible...@googlegroups.com
So should I make a custom module which loops over nova_compute asynchronously, and also assigns floating IPs?

Would such a module be useful to the wider community, or is it too specialized to contribute back?

Michael DeHaan

unread,
Jul 11, 2014, 9:50:10 PM7/11/14
to ansible...@googlegroups.com
"So should I make a custom module which loops over nova_compute asynchronously, and also assigns floating IPs?"

I'd first rather know where the openstack API allows simultaneous creation of N virtual machines of the same image type.

I expect the floating IP stuff is fast and a usual with_items loop isn't a problem there, once those guests exist.

(Using neutron, I assume?)


Kurt Yoder

unread,
Jul 14, 2014, 10:16:13 AM7/14/14
to ansible...@googlegroups.com
There's an undocumented min_count and max_count option in python-novaclient ServerManager.create() which looks like what you want [1].

Kurt Yoder

unread,
Jul 14, 2014, 1:07:59 PM7/14/14
to ansible...@googlegroups.com
To answer your other question about neutron: I use "quantum_floating_ip" to assign IPs on Openstack.

It would be very useful if these API calls could also be parallelized. I imagine a lot more time would be spent on 100 serial API calls than doing them in parallel.

-Kurt

Michael DeHaan

unread,
Jul 14, 2014, 3:09:21 PM7/14/14
to ansible...@googlegroups.com
Yep, I think we'd be open to that.




Kurt Yoder

unread,
Jul 14, 2014, 3:31:54 PM7/14/14
to ansible...@googlegroups.com
Is this a "pull requests welcome" situation? If so, I can try my best...

:D

Kurt Yoder

unread,
Jul 14, 2014, 3:37:17 PM7/14/14
to ansible...@googlegroups.com

Michael DeHaan

unread,
Jul 14, 2014, 3:57:25 PM7/14/14
to ansible...@googlegroups.com
Minor process note:

If you're going to submit the code to try, don't open the feature requests, just clutters up the queue.

If you aren't, opening an RFE usually doesn't mean the code fairies implement it anyway, since we're likely going to attend to existing bug reports/PRs and feature PRs first


Kurt Yoder

unread,
Jul 15, 2014, 1:27:29 PM7/15/14
to ansible...@googlegroups.com
I dug a bit further. The API does allow min_count and max_count, much the way boto does for AWS.

When you submit a request with min_count, your instances are named <ansible-provide name>-<instance UUID>. That's acceptable, though not ideal.

I'm taking a look at the Ansible ec2 module, and the code for boto instance-launching code looks very different than the nova_compute instance-launching code. I haven't run it yet; I need to dig around to find my ec2 creds so I can run a test.

The Ansible ec2 module also allows one to assign public IPs while launching multiple instances. The Ansible nova_compute module does not permit this ATM.

Michael DeHaan

unread,
Jul 16, 2014, 5:02:31 PM7/16/14
to ansible...@googlegroups.com
Additions of new params to add IP spawning behavior would be reasonable.

(assign_public_ip, True/False, etc)

What might you prefer on names?




Kurt Yoder

unread,
Jul 17, 2014, 10:04:14 AM7/17/14
to ansible...@googlegroups.com
I found a different approach to this problem. 


First create a cluster configuration file.
$ cat cluster.yml
---
cluster
:
 
- cluster1
 
- cluster2


Define the first task: setting up one connection to localhost for each API call. 
- include_vars: cluster.yml
 
- add_host:
    name
: "os_api_{{ item }}"
    ansible_ssh_host
: 127.0.0.1
    groups
: os_api
    ansible_connection
: local
    oshost
: "{{ item }}"
  with_items
: cluster

Define a follow-on task: tell Openstack to start up the VMs.
- name: Show host name
  debug:
    msg: "API connection: os_api_{{ oshost }}; Openstack host: {{ oshost }}"


- name: Launch cluster VM on Openstack
  nova_compute:
    name: "{{ os_username }}_{{ oshost }}"
    state: present
    login_username: "{{ os_username }}"
    login_tenant_name: "{{ os_tenant }}"
    login_password: "{{ os_password }}"
    image_id: "{{ os_image_id }}"
    key_name: "{{ os_username }}_controller_key"
    wait_for: 200
    flavor_id: "{{ os_flavor_id }}"
    auth_url: "{{ os_url }}"
        user_data: "#cloud-config\nmanage_etc_hosts: true"

- name: Assign IP address to cluster VM
  quantum_floating_ip:
    state: present
    login_username: "{{ os_username }}"
    login_password: "{{ os_password }}"
    login_tenant_name: "{{ os_tenant }}"
    network_name: "{{ os_network_name }}"
    instance_name: "{{ os_username }}_{{ oshost }}"
    internal_network_name: "{{ os_internal_network_name }}"
    auth_url: "{{ os_url }}"
  register: quantum_info

- name: Wait for cluster SSH to become available
  wait_for:
    port: 22
    host: "{{ quantum_info.public_ip }}"
    timeout: 180
    state: started



This method gives the following benefits:
  • I can define lots of flavors and images in my cluster.yml definition.
  • I can launch them all in parallel using Ansible's built-in, robust parallel execution. 
  • I have access to all of Ansible's primitives while doing so, so I can build in *any* custom logic.
  • No need to add options to nova_compute.

Overall, I'm extremely happy with this solution. To reiterate: *no code changes are required*!

Kurt Yoder

unread,
Jul 17, 2014, 10:19:40 AM7/17/14
to ansible...@googlegroups.com
I forgot to include a critical piece of this solution. Here's how you invoke the task to tell Openstack to start the VMs:
- name: Create cluster
  hosts
: os_api
  gather_facts
: no
  roles
: [instantiate] # "instantiate" is a role that includes the Openstack startup task


Perhaps this kind of example should be included in docs for parallel execution in Ansible. Let me know if you want me to help with that.

-Kurt

Tony Kinsley

unread,
Jul 18, 2014, 10:33:04 AM7/18/14
to ansible...@googlegroups.com
So I currently have an inventory script that creates me "fake" devices which I run the nova_compute task against. This allows me to provision all the vms in parallel using the native parallelization that ansible provides which is nice cause I can set it up to only provision 10 - 20 vms at a time using the serial flag. 

So this method provisions the VMs great, but since the "fake" devices do not have connection information I cannot use any other modules later in the playbook. I am trying to add these newly created VMs to a new group using the add_host module but I cannot get it to add more than one device to the running inventory.

- name: spawn vms
  local_action:
    module: nova_compute
    name: {{ vm_name }}
    ...
  register: nova

- name: add new hosts
  local_action:
    module: add_hosts
    name: {{ nova.private_ip }}



I saw the fake device approach on another thread and liked the ability to use ansible to throttle my provisioning as well as choose the names for the vms. I was wondering though if it would be possible to update host with the connection information ( specifically the ansible_ssh_host, ansible_ssh_private_key_file, and whatever variable specifies how to connect to the host ) rather than creating new hosts. 

I also am stuck trying to get add_hosts to get all of my hosts. I assumed that add_hosts would also run in parallel but after searching around all of the examples I have seen show it using a loop. If I need to use a loop is there a good way to get the registered output from nova into a list rather than per host? I could not figure out any way to use set_fact to append the per host values of the registered nova variable into a single variable.

I felt like this approach was pretty clean, but I am definitely open to other ideas. My goal is to be able to provision a scalability test environment so I am expecting to be provisioning 500 VMs in a private Openstack network. 

Tony

Michael DeHaan

unread,
Jul 18, 2014, 2:19:36 PM7/18/14
to ansible...@googlegroups.com
I'm not sure why you think add_host needs to run in parallel, it completes in almost zero time since it's just doing some internal inventory "math".

That all being said, what we really want is OpenStack's module having the equivalent of exact_count in AWS/Rax other (though the Rackspace implementation is a bit more low level).




Bob Tiernay

unread,
Jul 20, 2014, 8:03:05 PM7/20/14
to ansible...@googlegroups.com
Hey Kurt,

Do you happen to have a full example in a repo somewhere? I would be very interested to check it out.

Thanks in advance,

Bob

Bob Tiernay

unread,
Jul 20, 2014, 9:02:55 PM7/20/14
to ansible...@googlegroups.com
FYI - http://docs.openstack.org/api/openstack-compute/2/content/POST_multiple-create-v2_createServer__v2__tenant_id__servers_ext-os-multi-server-create.html

To get exact_count semantics, set min_count and max_count to the same value. This is part of the public OpenStack API.

Cheers,

Bob

Bob Tiernay

unread,
Jul 21, 2014, 7:51:45 AM7/21/14
to ansible...@googlegroups.com
Hi Tony,

Does this example do what you want? 


It basically starts with the add_hosts and then uses that as the basis for executing nova_compute, etc. It is set to be serial in this example, but I don't know the rationale there.

I'm just getting started with both OpenStack and Ansible and I'm finding there aren't many high quality examples in this space.  

Kurt Yoder

unread,
Jul 21, 2014, 9:50:00 AM7/21/14
to ansible...@googlegroups.com
At the moment my code is bound up in a playbook that I can't share. Sorry.
Reply all
Reply to author
Forward
0 new messages