1Rackspace Cloud Guide 2===================== 3 4.. _rax_introduction: 5 6Introduction 7```````````` 8 9.. note:: This section of the documentation is under construction. We are in the process of adding more examples about the Rackspace modules and how they work together. Once complete, there will also be examples for Rackspace Cloud in `ansible-examples <https://github.com/ansible/ansible-examples/>`_. 10 11Ansible contains a number of core modules for interacting with Rackspace Cloud. 12 13The purpose of this section is to explain how to put Ansible modules together 14(and use inventory scripts) to use Ansible in a Rackspace Cloud context. 15 16Prerequisites for using the rax modules are minimal. In addition to ansible itself, 17all of the modules require and are tested against pyrax 1.5 or higher. 18You'll need this Python module installed on the execution host. 19 20``pyrax`` is not currently available in many operating system 21package repositories, so you will likely need to install it via pip: 22 23.. code-block:: bash 24 25 $ pip install pyrax 26 27Ansible creates an implicit localhost that executes in the same context as the ``ansible-playbook`` and the other CLI tools. 28If for any reason you need or want to have it in your inventory you should do something like the following: 29 30.. code-block:: ini 31 32 [localhost] 33 localhost ansible_connection=local ansible_python_interpreter=/usr/local/bin/python2 34 35For more information see :ref:`Implicit Localhost <implicit_localhost>` 36 37In playbook steps, we'll typically be using the following pattern: 38 39.. code-block:: yaml 40 41 - hosts: localhost 42 gather_facts: False 43 tasks: 44 45.. _credentials_file: 46 47Credentials File 48```````````````` 49 50The `rax.py` inventory script and all `rax` modules support a standard `pyrax` credentials file that looks like: 51 52.. code-block:: ini 53 54 [rackspace_cloud] 55 username = myraxusername 56 api_key = d41d8cd98f00b204e9800998ecf8427e 57 58Setting the environment parameter ``RAX_CREDS_FILE`` to the path of this file will help Ansible find how to load 59this information. 60 61More information about this credentials file can be found at 62https://github.com/pycontribs/pyrax/blob/master/docs/getting_started.md#authenticating 63 64 65.. _virtual_environment: 66 67Running from a Python Virtual Environment (Optional) 68++++++++++++++++++++++++++++++++++++++++++++++++++++ 69 70Most users will not be using virtualenv, but some users, particularly Python developers sometimes like to. 71 72There are special considerations when Ansible is installed to a Python virtualenv, rather than the default of installing at a global scope. Ansible assumes, unless otherwise instructed, that the python binary will live at /usr/bin/python. This is done via the interpreter line in modules, however when instructed by setting the inventory variable 'ansible_python_interpreter', Ansible will use this specified path instead to find Python. This can be a cause of confusion as one may assume that modules running on 'localhost', or perhaps running via 'local_action', are using the virtualenv Python interpreter. By setting this line in the inventory, the modules will execute in the virtualenv interpreter and have available the virtualenv packages, specifically pyrax. If using virtualenv, you may wish to modify your localhost inventory definition to find this location as follows: 73 74.. code-block:: ini 75 76 [localhost] 77 localhost ansible_connection=local ansible_python_interpreter=/path/to/ansible_venv/bin/python 78 79.. note:: 80 81 pyrax may be installed in the global Python package scope or in a virtual environment. There are no special considerations to keep in mind when installing pyrax. 82 83.. _provisioning: 84 85Provisioning 86```````````` 87 88Now for the fun parts. 89 90The 'rax' module provides the ability to provision instances within Rackspace Cloud. Typically the provisioning task will be performed from your Ansible control server (in our example, localhost) against the Rackspace cloud API. This is done for several reasons: 91 92 - Avoiding installing the pyrax library on remote nodes 93 - No need to encrypt and distribute credentials to remote nodes 94 - Speed and simplicity 95 96.. note:: 97 98 Authentication with the Rackspace-related modules is handled by either 99 specifying your username and API key as environment variables or passing 100 them as module arguments, or by specifying the location of a credentials 101 file. 102 103Here is a basic example of provisioning an instance in ad-hoc mode: 104 105.. code-block:: bash 106 107 $ ansible localhost -m rax -a "name=awx flavor=4 image=ubuntu-1204-lts-precise-pangolin wait=yes" 108 109Here's what it would look like in a playbook, assuming the parameters were defined in variables: 110 111.. code-block:: yaml 112 113 tasks: 114 - name: Provision a set of instances 115 rax: 116 name: "{{ rax_name }}" 117 flavor: "{{ rax_flavor }}" 118 image: "{{ rax_image }}" 119 count: "{{ rax_count }}" 120 group: "{{ group }}" 121 wait: yes 122 register: rax 123 delegate_to: localhost 124 125The rax module returns data about the nodes it creates, like IP addresses, hostnames, and login passwords. By registering the return value of the step, it is possible used this data to dynamically add the resulting hosts to inventory (temporarily, in memory). This facilitates performing configuration actions on the hosts in a follow-on task. In the following example, the servers that were successfully created using the above task are dynamically added to a group called "raxhosts", with each nodes hostname, IP address, and root password being added to the inventory. 126 127.. code-block:: yaml 128 129 - name: Add the instances we created (by public IP) to the group 'raxhosts' 130 add_host: 131 hostname: "{{ item.name }}" 132 ansible_host: "{{ item.rax_accessipv4 }}" 133 ansible_password: "{{ item.rax_adminpass }}" 134 groups: raxhosts 135 loop: "{{ rax.success }}" 136 when: rax.action == 'create' 137 138With the host group now created, the next play in this playbook could now configure servers belonging to the raxhosts group. 139 140.. code-block:: yaml 141 142 - name: Configuration play 143 hosts: raxhosts 144 user: root 145 roles: 146 - ntp 147 - webserver 148 149The method above ties the configuration of a host with the provisioning step. This isn't always what you want, and leads us 150to the next section. 151 152.. _host_inventory: 153 154Host Inventory 155`````````````` 156 157Once your nodes are spun up, you'll probably want to talk to them again. The best way to handle this is to use the "rax" inventory plugin, which dynamically queries Rackspace Cloud and tells Ansible what nodes you have to manage. You might want to use this even if you are spinning up cloud instances via other tools, including the Rackspace Cloud user interface. The inventory plugin can be used to group resources by metadata, region, OS, and so on. Utilizing metadata is highly recommended in "rax" and can provide an easy way to sort between host groups and roles. If you don't want to use the ``rax.py`` dynamic inventory script, you could also still choose to manually manage your INI inventory file, though this is less recommended. 158 159In Ansible it is quite possible to use multiple dynamic inventory plugins along with INI file data. Just put them in a common directory and be sure the scripts are chmod +x, and the INI-based ones are not. 160 161.. _raxpy: 162 163rax.py 164++++++ 165 166To use the Rackspace dynamic inventory script, copy ``rax.py`` into your inventory directory and make it executable. You can specify a credentials file for ``rax.py`` utilizing the ``RAX_CREDS_FILE`` environment variable. 167 168.. note:: Dynamic inventory scripts (like ``rax.py``) are saved in ``/usr/local/share/py38-ansible/inventory`` if Ansible has been installed globally. If installed to a virtualenv, the inventory scripts are installed to ``$VIRTUALENV/share/inventory``. 169 170.. note:: Users of :ref:`ansible_tower` will note that dynamic inventory is natively supported by Tower, and all you have to do is associate a group with your Rackspace Cloud credentials, and it will easily synchronize without going through these steps:: 171 172 $ RAX_CREDS_FILE=~/.raxpub ansible all -i rax.py -m setup 173 174``rax.py`` also accepts a ``RAX_REGION`` environment variable, which can contain an individual region, or a comma separated list of regions. 175 176When using ``rax.py``, you will not have a 'localhost' defined in the inventory. 177 178As mentioned previously, you will often be running most of these modules outside of the host loop, and will need 'localhost' defined. The recommended way to do this, would be to create an ``inventory`` directory, and place both the ``rax.py`` script and a file containing ``localhost`` in it. 179 180Executing ``ansible`` or ``ansible-playbook`` and specifying the ``inventory`` directory instead 181of an individual file, will cause ansible to evaluate each file in that directory for inventory. 182 183Let's test our inventory script to see if it can talk to Rackspace Cloud. 184 185.. code-block:: bash 186 187 $ RAX_CREDS_FILE=~/.raxpub ansible all -i inventory/ -m setup 188 189Assuming things are properly configured, the ``rax.py`` inventory script will output information similar to the 190following information, which will be utilized for inventory and variables. 191 192.. code-block:: json 193 194 { 195 "ORD": [ 196 "test" 197 ], 198 "_meta": { 199 "hostvars": { 200 "test": { 201 "ansible_host": "198.51.100.1", 202 "rax_accessipv4": "198.51.100.1", 203 "rax_accessipv6": "2001:DB8::2342", 204 "rax_addresses": { 205 "private": [ 206 { 207 "addr": "192.0.2.2", 208 "version": 4 209 } 210 ], 211 "public": [ 212 { 213 "addr": "198.51.100.1", 214 "version": 4 215 }, 216 { 217 "addr": "2001:DB8::2342", 218 "version": 6 219 } 220 ] 221 }, 222 "rax_config_drive": "", 223 "rax_created": "2013-11-14T20:48:22Z", 224 "rax_flavor": { 225 "id": "performance1-1", 226 "links": [ 227 { 228 "href": "https://ord.servers.api.rackspacecloud.com/111111/flavors/performance1-1", 229 "rel": "bookmark" 230 } 231 ] 232 }, 233 "rax_hostid": "e7b6961a9bd943ee82b13816426f1563bfda6846aad84d52af45a4904660cde0", 234 "rax_human_id": "test", 235 "rax_id": "099a447b-a644-471f-87b9-a7f580eb0c2a", 236 "rax_image": { 237 "id": "b211c7bf-b5b4-4ede-a8de-a4368750c653", 238 "links": [ 239 { 240 "href": "https://ord.servers.api.rackspacecloud.com/111111/images/b211c7bf-b5b4-4ede-a8de-a4368750c653", 241 "rel": "bookmark" 242 } 243 ] 244 }, 245 "rax_key_name": null, 246 "rax_links": [ 247 { 248 "href": "https://ord.servers.api.rackspacecloud.com/v2/111111/servers/099a447b-a644-471f-87b9-a7f580eb0c2a", 249 "rel": "self" 250 }, 251 { 252 "href": "https://ord.servers.api.rackspacecloud.com/111111/servers/099a447b-a644-471f-87b9-a7f580eb0c2a", 253 "rel": "bookmark" 254 } 255 ], 256 "rax_metadata": { 257 "foo": "bar" 258 }, 259 "rax_name": "test", 260 "rax_name_attr": "name", 261 "rax_networks": { 262 "private": [ 263 "192.0.2.2" 264 ], 265 "public": [ 266 "198.51.100.1", 267 "2001:DB8::2342" 268 ] 269 }, 270 "rax_os-dcf_diskconfig": "AUTO", 271 "rax_os-ext-sts_power_state": 1, 272 "rax_os-ext-sts_task_state": null, 273 "rax_os-ext-sts_vm_state": "active", 274 "rax_progress": 100, 275 "rax_status": "ACTIVE", 276 "rax_tenant_id": "111111", 277 "rax_updated": "2013-11-14T20:49:27Z", 278 "rax_user_id": "22222" 279 } 280 } 281 } 282 } 283 284.. _standard_inventory: 285 286Standard Inventory 287++++++++++++++++++ 288 289When utilizing a standard ini formatted inventory file (as opposed to the inventory plugin), it may still be advantageous to retrieve discoverable hostvar information from the Rackspace API. 290 291This can be achieved with the ``rax_facts`` module and an inventory file similar to the following: 292 293.. code-block:: ini 294 295 [test_servers] 296 hostname1 rax_region=ORD 297 hostname2 rax_region=ORD 298 299.. code-block:: yaml 300 301 - name: Gather info about servers 302 hosts: test_servers 303 gather_facts: False 304 tasks: 305 - name: Get facts about servers 306 rax_facts: 307 credentials: ~/.raxpub 308 name: "{{ inventory_hostname }}" 309 region: "{{ rax_region }}" 310 delegate_to: localhost 311 - name: Map some facts 312 set_fact: 313 ansible_host: "{{ rax_accessipv4 }}" 314 315While you don't need to know how it works, it may be interesting to know what kind of variables are returned. 316 317The ``rax_facts`` module provides facts as followings, which match the ``rax.py`` inventory script: 318 319.. code-block:: json 320 321 { 322 "ansible_facts": { 323 "rax_accessipv4": "198.51.100.1", 324 "rax_accessipv6": "2001:DB8::2342", 325 "rax_addresses": { 326 "private": [ 327 { 328 "addr": "192.0.2.2", 329 "version": 4 330 } 331 ], 332 "public": [ 333 { 334 "addr": "198.51.100.1", 335 "version": 4 336 }, 337 { 338 "addr": "2001:DB8::2342", 339 "version": 6 340 } 341 ] 342 }, 343 "rax_config_drive": "", 344 "rax_created": "2013-11-14T20:48:22Z", 345 "rax_flavor": { 346 "id": "performance1-1", 347 "links": [ 348 { 349 "href": "https://ord.servers.api.rackspacecloud.com/111111/flavors/performance1-1", 350 "rel": "bookmark" 351 } 352 ] 353 }, 354 "rax_hostid": "e7b6961a9bd943ee82b13816426f1563bfda6846aad84d52af45a4904660cde0", 355 "rax_human_id": "test", 356 "rax_id": "099a447b-a644-471f-87b9-a7f580eb0c2a", 357 "rax_image": { 358 "id": "b211c7bf-b5b4-4ede-a8de-a4368750c653", 359 "links": [ 360 { 361 "href": "https://ord.servers.api.rackspacecloud.com/111111/images/b211c7bf-b5b4-4ede-a8de-a4368750c653", 362 "rel": "bookmark" 363 } 364 ] 365 }, 366 "rax_key_name": null, 367 "rax_links": [ 368 { 369 "href": "https://ord.servers.api.rackspacecloud.com/v2/111111/servers/099a447b-a644-471f-87b9-a7f580eb0c2a", 370 "rel": "self" 371 }, 372 { 373 "href": "https://ord.servers.api.rackspacecloud.com/111111/servers/099a447b-a644-471f-87b9-a7f580eb0c2a", 374 "rel": "bookmark" 375 } 376 ], 377 "rax_metadata": { 378 "foo": "bar" 379 }, 380 "rax_name": "test", 381 "rax_name_attr": "name", 382 "rax_networks": { 383 "private": [ 384 "192.0.2.2" 385 ], 386 "public": [ 387 "198.51.100.1", 388 "2001:DB8::2342" 389 ] 390 }, 391 "rax_os-dcf_diskconfig": "AUTO", 392 "rax_os-ext-sts_power_state": 1, 393 "rax_os-ext-sts_task_state": null, 394 "rax_os-ext-sts_vm_state": "active", 395 "rax_progress": 100, 396 "rax_status": "ACTIVE", 397 "rax_tenant_id": "111111", 398 "rax_updated": "2013-11-14T20:49:27Z", 399 "rax_user_id": "22222" 400 }, 401 "changed": false 402 } 403 404 405Use Cases 406````````` 407 408This section covers some additional usage examples built around a specific use case. 409 410.. _network_and_server: 411 412Network and Server 413++++++++++++++++++ 414 415Create an isolated cloud network and build a server 416 417.. code-block:: yaml 418 419 - name: Build Servers on an Isolated Network 420 hosts: localhost 421 gather_facts: False 422 tasks: 423 - name: Network create request 424 rax_network: 425 credentials: ~/.raxpub 426 label: my-net 427 cidr: 192.168.3.0/24 428 region: IAD 429 state: present 430 delegate_to: localhost 431 432 - name: Server create request 433 rax: 434 credentials: ~/.raxpub 435 name: web%04d.example.org 436 flavor: 2 437 image: ubuntu-1204-lts-precise-pangolin 438 disk_config: manual 439 networks: 440 - public 441 - my-net 442 region: IAD 443 state: present 444 count: 5 445 exact_count: yes 446 group: web 447 wait: yes 448 wait_timeout: 360 449 register: rax 450 delegate_to: localhost 451 452.. _complete_environment: 453 454Complete Environment 455++++++++++++++++++++ 456 457Build a complete webserver environment with servers, custom networks and load balancers, install nginx and create a custom index.html 458 459.. code-block:: yaml 460 461 --- 462 - name: Build environment 463 hosts: localhost 464 gather_facts: False 465 tasks: 466 - name: Load Balancer create request 467 rax_clb: 468 credentials: ~/.raxpub 469 name: my-lb 470 port: 80 471 protocol: HTTP 472 algorithm: ROUND_ROBIN 473 type: PUBLIC 474 timeout: 30 475 region: IAD 476 wait: yes 477 state: present 478 meta: 479 app: my-cool-app 480 register: clb 481 482 - name: Network create request 483 rax_network: 484 credentials: ~/.raxpub 485 label: my-net 486 cidr: 192.168.3.0/24 487 state: present 488 region: IAD 489 register: network 490 491 - name: Server create request 492 rax: 493 credentials: ~/.raxpub 494 name: web%04d.example.org 495 flavor: performance1-1 496 image: ubuntu-1204-lts-precise-pangolin 497 disk_config: manual 498 networks: 499 - public 500 - private 501 - my-net 502 region: IAD 503 state: present 504 count: 5 505 exact_count: yes 506 group: web 507 wait: yes 508 register: rax 509 510 - name: Add servers to web host group 511 add_host: 512 hostname: "{{ item.name }}" 513 ansible_host: "{{ item.rax_accessipv4 }}" 514 ansible_password: "{{ item.rax_adminpass }}" 515 ansible_user: root 516 groups: web 517 loop: "{{ rax.success }}" 518 when: rax.action == 'create' 519 520 - name: Add servers to Load balancer 521 rax_clb_nodes: 522 credentials: ~/.raxpub 523 load_balancer_id: "{{ clb.balancer.id }}" 524 address: "{{ item.rax_networks.private|first }}" 525 port: 80 526 condition: enabled 527 type: primary 528 wait: yes 529 region: IAD 530 loop: "{{ rax.success }}" 531 when: rax.action == 'create' 532 533 - name: Configure servers 534 hosts: web 535 handlers: 536 - name: restart nginx 537 service: name=nginx state=restarted 538 539 tasks: 540 - name: Install nginx 541 apt: pkg=nginx state=latest update_cache=yes cache_valid_time=86400 542 notify: 543 - restart nginx 544 545 - name: Ensure nginx starts on boot 546 service: name=nginx state=started enabled=yes 547 548 - name: Create custom index.html 549 copy: content="{{ inventory_hostname }}" dest=/usr/share/nginx/www/index.html 550 owner=root group=root mode=0644 551 552.. _rackconnect_and_manged_cloud: 553 554RackConnect and Managed Cloud 555+++++++++++++++++++++++++++++ 556 557When using RackConnect version 2 or Rackspace Managed Cloud there are Rackspace automation tasks that are executed on the servers you create after they are successfully built. If your automation executes before the RackConnect or Managed Cloud automation, you can cause failures and unusable servers. 558 559These examples show creating servers, and ensuring that the Rackspace automation has completed before Ansible continues onwards. 560 561For simplicity, these examples are joined, however both are only needed when using RackConnect. When only using Managed Cloud, the RackConnect portion can be ignored. 562 563The RackConnect portions only apply to RackConnect version 2. 564 565.. _using_a_control_machine: 566 567Using a Control Machine 568*********************** 569 570.. code-block:: yaml 571 572 - name: Create an exact count of servers 573 hosts: localhost 574 gather_facts: False 575 tasks: 576 - name: Server build requests 577 rax: 578 credentials: ~/.raxpub 579 name: web%03d.example.org 580 flavor: performance1-1 581 image: ubuntu-1204-lts-precise-pangolin 582 disk_config: manual 583 region: DFW 584 state: present 585 count: 1 586 exact_count: yes 587 group: web 588 wait: yes 589 register: rax 590 591 - name: Add servers to in memory groups 592 add_host: 593 hostname: "{{ item.name }}" 594 ansible_host: "{{ item.rax_accessipv4 }}" 595 ansible_password: "{{ item.rax_adminpass }}" 596 ansible_user: root 597 rax_id: "{{ item.rax_id }}" 598 groups: web,new_web 599 loop: "{{ rax.success }}" 600 when: rax.action == 'create' 601 602 - name: Wait for rackconnect and managed cloud automation to complete 603 hosts: new_web 604 gather_facts: false 605 tasks: 606 - name: ensure we run all tasks from localhost 607 delegate_to: localhost 608 block: 609 - name: Wait for rackconnnect automation to complete 610 rax_facts: 611 credentials: ~/.raxpub 612 id: "{{ rax_id }}" 613 region: DFW 614 register: rax_facts 615 until: rax_facts.ansible_facts['rax_metadata']['rackconnect_automation_status']|default('') == 'DEPLOYED' 616 retries: 30 617 delay: 10 618 619 - name: Wait for managed cloud automation to complete 620 rax_facts: 621 credentials: ~/.raxpub 622 id: "{{ rax_id }}" 623 region: DFW 624 register: rax_facts 625 until: rax_facts.ansible_facts['rax_metadata']['rax_service_level_automation']|default('') == 'Complete' 626 retries: 30 627 delay: 10 628 629 - name: Update new_web hosts with IP that RackConnect assigns 630 hosts: new_web 631 gather_facts: false 632 tasks: 633 - name: Get facts about servers 634 rax_facts: 635 name: "{{ inventory_hostname }}" 636 region: DFW 637 delegate_to: localhost 638 - name: Map some facts 639 set_fact: 640 ansible_host: "{{ rax_accessipv4 }}" 641 642 - name: Base Configure Servers 643 hosts: web 644 roles: 645 - role: users 646 647 - role: openssh 648 opensshd_PermitRootLogin: "no" 649 650 - role: ntp 651 652.. _using_ansible_pull: 653 654Using Ansible Pull 655****************** 656 657.. code-block:: yaml 658 659 --- 660 - name: Ensure Rackconnect and Managed Cloud Automation is complete 661 hosts: all 662 tasks: 663 - name: ensure we run all tasks from localhost 664 delegate_to: localhost 665 block: 666 - name: Check for completed bootstrap 667 stat: 668 path: /etc/bootstrap_complete 669 register: bootstrap 670 671 - name: Get region 672 command: xenstore-read vm-data/provider_data/region 673 register: rax_region 674 when: bootstrap.stat.exists != True 675 676 - name: Wait for rackconnect automation to complete 677 uri: 678 url: "https://{{ rax_region.stdout|trim }}.api.rackconnect.rackspace.com/v1/automation_status?format=json" 679 return_content: yes 680 register: automation_status 681 when: bootstrap.stat.exists != True 682 until: automation_status['automation_status']|default('') == 'DEPLOYED' 683 retries: 30 684 delay: 10 685 686 - name: Wait for managed cloud automation to complete 687 wait_for: 688 path: /tmp/rs_managed_cloud_automation_complete 689 delay: 10 690 when: bootstrap.stat.exists != True 691 692 - name: Set bootstrap completed 693 file: 694 path: /etc/bootstrap_complete 695 state: touch 696 owner: root 697 group: root 698 mode: 0400 699 700 - name: Base Configure Servers 701 hosts: all 702 roles: 703 - role: users 704 705 - role: openssh 706 opensshd_PermitRootLogin: "no" 707 708 - role: ntp 709 710.. _using_ansible_pull_with_xenstore: 711 712Using Ansible Pull with XenStore 713******************************** 714 715.. code-block:: yaml 716 717 --- 718 - name: Ensure Rackconnect and Managed Cloud Automation is complete 719 hosts: all 720 tasks: 721 - name: Check for completed bootstrap 722 stat: 723 path: /etc/bootstrap_complete 724 register: bootstrap 725 726 - name: Wait for rackconnect_automation_status xenstore key to exist 727 command: xenstore-exists vm-data/user-metadata/rackconnect_automation_status 728 register: rcas_exists 729 when: bootstrap.stat.exists != True 730 failed_when: rcas_exists.rc|int > 1 731 until: rcas_exists.rc|int == 0 732 retries: 30 733 delay: 10 734 735 - name: Wait for rackconnect automation to complete 736 command: xenstore-read vm-data/user-metadata/rackconnect_automation_status 737 register: rcas 738 when: bootstrap.stat.exists != True 739 until: rcas.stdout|replace('"', '') == 'DEPLOYED' 740 retries: 30 741 delay: 10 742 743 - name: Wait for rax_service_level_automation xenstore key to exist 744 command: xenstore-exists vm-data/user-metadata/rax_service_level_automation 745 register: rsla_exists 746 when: bootstrap.stat.exists != True 747 failed_when: rsla_exists.rc|int > 1 748 until: rsla_exists.rc|int == 0 749 retries: 30 750 delay: 10 751 752 - name: Wait for managed cloud automation to complete 753 command: xenstore-read vm-data/user-metadata/rackconnect_automation_status 754 register: rsla 755 when: bootstrap.stat.exists != True 756 until: rsla.stdout|replace('"', '') == 'DEPLOYED' 757 retries: 30 758 delay: 10 759 760 - name: Set bootstrap completed 761 file: 762 path: /etc/bootstrap_complete 763 state: touch 764 owner: root 765 group: root 766 mode: 0400 767 768 - name: Base Configure Servers 769 hosts: all 770 roles: 771 - role: users 772 773 - role: openssh 774 opensshd_PermitRootLogin: "no" 775 776 - role: ntp 777 778.. _advanced_usage: 779 780Advanced Usage 781`````````````` 782 783.. _awx_autoscale: 784 785Autoscaling with Tower 786++++++++++++++++++++++ 787 788:ref:`ansible_tower` also contains a very nice feature for auto-scaling use cases. 789In this mode, a simple curl script can call a defined URL and the server will "dial out" to the requester 790and configure an instance that is spinning up. This can be a great way to reconfigure ephemeral nodes. 791See the Tower documentation for more details. 792 793A benefit of using the callback in Tower over pull mode is that job results are still centrally recorded 794and less information has to be shared with remote hosts. 795 796.. _pending_information: 797 798Orchestration in the Rackspace Cloud 799++++++++++++++++++++++++++++++++++++ 800 801Ansible is a powerful orchestration tool, and rax modules allow you the opportunity to orchestrate complex tasks, deployments, and configurations. The key here is to automate provisioning of infrastructure, like any other piece of software in an environment. Complex deployments might have previously required manual manipulation of load balancers, or manual provisioning of servers. Utilizing the rax modules included with Ansible, one can make the deployment of additional nodes contingent on the current number of running nodes, or the configuration of a clustered application dependent on the number of nodes with common metadata. One could automate the following scenarios, for example: 802 803* Servers that are removed from a Cloud Load Balancer one-by-one, updated, verified, and returned to the load balancer pool 804* Expansion of an already-online environment, where nodes are provisioned, bootstrapped, configured, and software installed 805* A procedure where app log files are uploaded to a central location, like Cloud Files, before a node is decommissioned 806* Servers and load balancers that have DNS records created and destroyed on creation and decommissioning, respectively 807 808 809 810 811