{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Ansible\n", "\n", "Ansible is a configuration management software.\n", "\n", "Connects via ssh or docker to a list of inventory machines and executes a series of tasks eventually grouped in playbooks.\n", "\n", "At first, create an inventory file with all your hosts." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/notebooks/notebooks/ansible\n" ] } ], "source": [ "cd ansible\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#\r\n", "# This inventory file contains a list of server to \r\n", "# play with - divided in groups.\r\n", "#\r\n", "[course]\r\n", "# this is the local machine where you run jupyter\r\n", "# the tutorial just works with this one.\r\n", "pythonforsysadmin_course_1 ansible_connection=local\r\n", "\r\n", "\r\n", "# Another group of servers\r\n", "# where we can pass optional arguments\r\n", "# Homework: you can play with this group of host\r\n", "# once you exchange ssh-keys between the pythonforsysadmin_course_1\r\n", "# container and the pythonforsysadmin_ansible_* ones._\r\n", "[ansible]\r\n", "172.17.0.[5:7] \r\n", "\r\n" ] } ], "source": [ "cat inventory" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now check if you can ping the local host." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[0;32mpythonforsysadmin_course_1 | SUCCESS => {\r\n", " \"ansible_facts\": {\r\n", " \"ansible_all_ipv4_addresses\": [\r\n", " \"172.17.0.3\"\r\n", " ], \r\n", " \"ansible_all_ipv6_addresses\": [\r\n", " \"fe80::42:acff:fe11:3\"\r\n", " ], \r\n", " \"ansible_architecture\": \"x86_64\", \r\n", " \"ansible_bios_date\": \"06/30/2014\", \r\n", " \"ansible_bios_version\": \"A00\", \r\n", " \"ansible_cmdline\": {\r\n", " \"BOOT_IMAGE\": \"/vmlinuz-4.9.17-100.fc24.x86_64\", \r\n", " \"LANG\": \"it_IT.UTF-8\", \r\n", " \"i8042.nopnp\": true, \r\n", " \"rd.lvm.lv\": \"vg0/root00\", \r\n", " \"ro\": true, \r\n", " \"root\": \"/dev/mapper/vg0-root00\"\r\n", " }, \r\n", " \"ansible_date_time\": {\r\n", " \"date\": \"2017-04-05\", \r\n", " \"day\": \"05\", \r\n", " \"epoch\": \"1491399416\", \r\n", " \"hour\": \"13\", \r\n", " \"iso8601\": \"2017-04-05T13:36:56Z\", \r\n", " \"iso8601_basic\": \"20170405T133656277588\", \r\n", " \"iso8601_basic_short\": \"20170405T133656\", \r\n", " \"iso8601_micro\": \"2017-04-05T13:36:56.277679Z\", \r\n", " \"minute\": \"36\", \r\n", " \"month\": \"04\", \r\n", " \"second\": \"56\", \r\n", " \"time\": \"13:36:56\", \r\n", " \"tz\": \"UTC\", \r\n", " \"tz_offset\": \"+0000\", \r\n", " \"weekday\": \"Wednesday\", \r\n", " \"weekday_number\": \"3\", \r\n", " \"weeknumber\": \"14\", \r\n", " \"year\": \"2017\"\r\n", " }, \r\n", " \"ansible_default_ipv4\": {\r\n", " \"address\": \"172.17.0.3\", \r\n", " \"alias\": \"eth0\", \r\n", " \"broadcast\": \"global\", \r\n", " \"gateway\": \"172.17.0.1\", \r\n", " \"interface\": \"eth0\", \r\n", " \"macaddress\": \"02:42:ac:11:00:03\", \r\n", " \"mtu\": 1500, \r\n", " \"netmask\": \"255.255.0.0\", \r\n", " \"network\": \"172.17.0.0\", \r\n", " \"type\": \"ether\"\r\n", " }, \r\n", " \"ansible_default_ipv6\": {}, \r\n", " \"ansible_devices\": {\r\n", " \"sda\": {\r\n", " \"holders\": [], \r\n", " \"host\": \"\", \r\n", " \"model\": \"ST500LM000-1EJ16\", \r\n", " \"partitions\": {\r\n", " \"sda1\": {\r\n", " \"sectors\": \"1024000\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"500.00 MB\", \r\n", " \"start\": \"2048\"\r\n", " }, \r\n", " \"sda2\": {\r\n", " \"sectors\": \"81920\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"40.00 MB\", \r\n", " \"start\": \"1026048\"\r\n", " }, \r\n", " \"sda3\": {\r\n", " \"sectors\": \"262144\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"128.00 MB\", \r\n", " \"start\": \"1107968\"\r\n", " }, \r\n", " \"sda4\": {\r\n", " \"sectors\": \"1536000\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"750.00 MB\", \r\n", " \"start\": \"1370112\"\r\n", " }, \r\n", " \"sda5\": {\r\n", " \"sectors\": \"819200\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"400.00 MB\", \r\n", " \"start\": \"2906112\"\r\n", " }, \r\n", " \"sda6\": {\r\n", " \"sectors\": \"14827568\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"7.07 GB\", \r\n", " \"start\": \"961943552\"\r\n", " }, \r\n", " \"sda7\": {\r\n", " \"sectors\": \"1048576\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"512.00 MB\", \r\n", " \"start\": \"3725312\"\r\n", " }, \r\n", " \"sda8\": {\r\n", " \"sectors\": \"897589248\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"428.00 GB\", \r\n", " \"start\": \"4773888\"\r\n", " }, \r\n", " \"sda9\": {\r\n", " \"sectors\": \"8388608\", \r\n", " \"sectorsize\": 512, \r\n", " \"size\": \"4.00 GB\", \r\n", " \"start\": \"902363136\"\r\n", " }\r\n", " }, \r\n", " \"removable\": \"0\", \r\n", " \"rotational\": \"1\", \r\n", " \"sas_address\": null, \r\n", " \"sas_device_handle\": null, \r\n", " \"scheduler_mode\": \"cfq\", \r\n", " \"sectors\": \"976773168\", \r\n", " \"sectorsize\": \"512\", \r\n", " \"size\": \"465.76 GB\", \r\n", " \"support_discard\": \"0\", \r\n", " \"vendor\": \"ATA\"\r\n", " }\r\n", " }, \r\n", " \"ansible_distribution\": \"Debian\", \r\n", " \"ansible_distribution_major_version\": \"8\", \r\n", " \"ansible_distribution_release\": \"jessie\", \r\n", " \"ansible_distribution_version\": \"8.5\", \r\n", " \"ansible_dns\": {\r\n", " \"nameservers\": [\r\n", " \"10.0.11.254\", \r\n", " \"#\", \r\n", " \"removeme-babel-dns\", \r\n", " \"10.0.11.254\", \r\n", " \"#\", \r\n", " \"removeme-babel-dns\", \r\n", " \"10.0.11.254\", \r\n", " \"#\", \r\n", " \"removeme-babel-dns\", \r\n", " \"10.0.11.254\", \r\n", " \"10.0.252.5\"\r\n", " ], \r\n", " \"search\": [\r\n", " \"babel.it\"\r\n", " ]\r\n", " }, \r\n", " \"ansible_domain\": \"\", \r\n", " \"ansible_env\": {\r\n", " \"CLICOLOR\": \"1\", \r\n", " \"GIT_PAGER\": \"cat\", \r\n", " \"GPG_KEY\": \"C01E1CAD5EA2C4F0B8E3571504C367C218ADD4FF\", \r\n", " \"HOME\": \"/root\", \r\n", " \"HOSTNAME\": \"7ddd5bc0dd90\", \r\n", " \"JPY_PARENT_PID\": \"6\", \r\n", " \"LANG\": \"C.UTF-8\", \r\n", " \"LC_ALL\": \"C.UTF-8\", \r\n", " \"LC_MESSAGES\": \"C.UTF-8\", \r\n", " \"PAGER\": \"cat\", \r\n", " \"PATH\": \"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\", \r\n", " \"PWD\": \"/notebooks/notebooks/ansible\", \r\n", " \"PYTHONPATH\": \"\", \r\n", " \"PYTHON_PIP_VERSION\": \"8.1.2\", \r\n", " \"PYTHON_VERSION\": \"2.7.12\", \r\n", " \"TERM\": \"xterm-color\"\r\n", " }, \r\n", " \"ansible_eth0\": {\r\n", " \"active\": true, \r\n", " \"device\": \"eth0\", \r\n", " \"ipv4\": {\r\n", " \"address\": \"172.17.0.3\", \r\n", " \"broadcast\": \"global\", \r\n", " \"netmask\": \"255.255.0.0\", \r\n", " \"network\": \"172.17.0.0\"\r\n", " }, \r\n", " \"ipv6\": [\r\n", " {\r\n", " \"address\": \"fe80::42:acff:fe11:3\", \r\n", " \"prefix\": \"64\", \r\n", " \"scope\": \"link\"\r\n", " }\r\n", " ], \r\n", " \"macaddress\": \"02:42:ac:11:00:03\", \r\n", " \"mtu\": 1500, \r\n", " \"promisc\": false, \r\n", " \"type\": \"ether\"\r\n", " }, \r\n", " \"ansible_fips\": false, \r\n", " \"ansible_form_factor\": \"Portable\", \r\n", " \"ansible_fqdn\": \"7ddd5bc0dd90\", \r\n", " \"ansible_gather_subset\": [\r\n", " \"hardware\", \r\n", " \"network\", \r\n", " \"virtual\"\r\n", " ], \r\n", " \"ansible_hostname\": \"7ddd5bc0dd90\", \r\n", " \"ansible_interfaces\": [\r\n", " \"lo\", \r\n", " \"eth0\"\r\n", " ], \r\n", " \"ansible_kernel\": \"4.9.17-100.fc24.x86_64\", \r\n", " \"ansible_lo\": {\r\n", " \"active\": true, \r\n", " \"device\": \"lo\", \r\n", " \"ipv4\": {\r\n", " \"address\": \"127.0.0.1\", \r\n", " \"broadcast\": \"host\", \r\n", " \"netmask\": \"255.0.0.0\", \r\n", " \"network\": \"127.0.0.0\"\r\n", " }, \r\n", " \"ipv6\": [\r\n", " {\r\n", " \"address\": \"::1\", \r\n", " \"prefix\": \"128\", \r\n", " \"scope\": \"host\"\r\n", " }\r\n", " ], \r\n", " \"mtu\": 65536, \r\n", " \"promisc\": false, \r\n", " \"type\": \"loopback\"\r\n", " }, \r\n", " \"ansible_machine\": \"x86_64\", \r\n", " \"ansible_machine_id\": \"748cfc5d0ac0444e85d1cccb08411403\", \r\n", " \"ansible_memfree_mb\": 706, \r\n", " \"ansible_memory_mb\": {\r\n", " \"nocache\": {\r\n", " \"free\": 3707, \r\n", " \"used\": 4200\r\n", " }, \r\n", " \"real\": {\r\n", " \"free\": 706, \r\n", " \"total\": 7907, \r\n", " \"used\": 7201\r\n", " }, \r\n", " \"swap\": {\r\n", " \"cached\": 0, \r\n", " \"free\": 4095, \r\n", " \"total\": 4095, \r\n", " \"used\": 0\r\n", " }\r\n", " }, \r\n", " \"ansible_memtotal_mb\": 7907, \r\n", " \"ansible_mounts\": [\r\n", " {\r\n", " \"device\": \"/dev/mapper/docker-253:2-537280731-c85cb1165b8c710d56b97bfa1bbd902f1dc2eed671a883f570d48a8ab23dc822\", \r\n", " \"fstype\": \"xfs\", \r\n", " \"mount\": \"/\", \r\n", " \"options\": \"rw,context=\\\"system_u:object_r:svirt_sandbox_file_t:s0:c567,c688\\\",relatime,nouuid,attr2,inode64,logbsize=64k,sunit=128,swidth=128,noquota\", \r\n", " \"size_available\": 105882546176, \r\n", " \"size_total\": 107320705024, \r\n", " \"uuid\": \"NA\"\r\n", " }, \r\n", " {\r\n", " \"device\": \"/dev/mapper/vg0-home\", \r\n", " \"fstype\": \"xfs\", \r\n", " \"mount\": \"/notebooks\", \r\n", " \"options\": \"rw,seclabel,relatime,attr2,inode64,noquota\", \r\n", " \"size_available\": 21948248064, \r\n", " \"size_total\": 214643507200, \r\n", " \"uuid\": \"NA\"\r\n", " }, \r\n", " {\r\n", " \"device\": \"/dev/mapper/vg0-data\", \r\n", " \"fstype\": \"xfs\", \r\n", " \"mount\": \"/etc/resolv.conf\", \r\n", " \"options\": \"rw,seclabel,relatime,attr2,inode64,noquota\", \r\n", " \"size_available\": 4040863744, \r\n", " \"size_total\": 214643507200, \r\n", " \"uuid\": \"NA\"\r\n", " }, \r\n", " {\r\n", " \"device\": \"/dev/mapper/vg0-data\", \r\n", " \"fstype\": \"xfs\", \r\n", " \"mount\": \"/etc/hostname\", \r\n", " \"options\": \"rw,seclabel,relatime,attr2,inode64,noquota\", \r\n", " \"size_available\": 4040863744, \r\n", " \"size_total\": 214643507200, \r\n", " \"uuid\": \"NA\"\r\n", " }, \r\n", " {\r\n", " \"device\": \"/dev/mapper/vg0-data\", \r\n", " \"fstype\": \"xfs\", \r\n", " \"mount\": \"/etc/hosts\", \r\n", " \"options\": \"rw,seclabel,relatime,attr2,inode64,noquota\", \r\n", " \"size_available\": 4040863744, \r\n", " \"size_total\": 214643507200, \r\n", " \"uuid\": \"NA\"\r\n", " }\r\n", " ], \r\n", " \"ansible_nodename\": \"7ddd5bc0dd90\", \r\n", " \"ansible_os_family\": \"Debian\", \r\n", " \"ansible_pkg_mgr\": \"apt\", \r\n", " \"ansible_processor\": [\r\n", " \"GenuineIntel\", \r\n", " \"Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz\", \r\n", " \"GenuineIntel\", \r\n", " \"Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz\", \r\n", " \"GenuineIntel\", \r\n", " \"Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz\", \r\n", " \"GenuineIntel\", \r\n", " \"Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz\"\r\n", " ], \r\n", " \"ansible_processor_cores\": 2, \r\n", " \"ansible_processor_count\": 1, \r\n", " \"ansible_processor_threads_per_core\": 2, \r\n", " \"ansible_processor_vcpus\": 4, \r\n", " \"ansible_product_name\": \"Inspiron 7347\", \r\n", " \"ansible_product_serial\": \"54CK432\", \r\n", " \"ansible_product_uuid\": \"4C4C4544-0034-4310-804B-B5C04F343332\", \r\n", " \"ansible_product_version\": \"00h\", \r\n", " \"ansible_python\": {\r\n", " \"executable\": \"/usr/bin/python\", \r\n", " \"has_sslcontext\": true, \r\n", " \"type\": \"CPython\", \r\n", " \"version\": {\r\n", " \"major\": 2, \r\n", " \"micro\": 9, \r\n", " \"minor\": 7, \r\n", " \"releaselevel\": \"final\", \r\n", " \"serial\": 0\r\n", " }, \r\n", " \"version_info\": [\r\n", " 2, \r\n", " 7, \r\n", " 9, \r\n", " \"final\", \r\n", " 0\r\n", " ]\r\n", " }, \r\n", " \"ansible_python_version\": \"2.7.9\", \r\n", " \"ansible_selinux\": false, \r\n", " \"ansible_service_mgr\": \"upstart\", \r\n", " \"ansible_swapfree_mb\": 4095, \r\n", " \"ansible_swaptotal_mb\": 4095, \r\n", " \"ansible_system\": \"Linux\", \r\n", " \"ansible_system_capabilities\": [\r\n", " \"cap_chown\", \r\n", " \"cap_dac_override\", \r\n", " \"cap_fowner\", \r\n", " \"cap_fsetid\", \r\n", " \"cap_kill\", \r\n", " \"cap_setgid\", \r\n", " \"cap_setuid\", \r\n", " \"cap_setpcap\", \r\n", " \"cap_net_bind_service\", \r\n", " \"cap_net_raw\", \r\n", " \"cap_sys_chroot\", \r\n", " \"cap_mknod\", \r\n", " \"cap_audit_write\", \r\n", " \"cap_setfcap+eip\"\r\n", " ], \r\n", " \"ansible_system_capabilities_enforced\": \"True\", \r\n", " \"ansible_system_vendor\": \"Dell Inc.\", \r\n", " \"ansible_uptime_seconds\": 12220, \r\n", " \"ansible_user_dir\": \"/root\", \r\n", " \"ansible_user_gecos\": \"root\", \r\n", " \"ansible_user_gid\": 0, \r\n", " \"ansible_user_id\": \"root\", \r\n", " \"ansible_user_shell\": \"/bin/bash\", \r\n", " \"ansible_user_uid\": 0, \r\n", " \"ansible_userspace_architecture\": \"x86_64\", \r\n", " \"ansible_userspace_bits\": \"64\", \r\n", " \"ansible_virtualization_role\": \"guest\", \r\n", " \"ansible_virtualization_type\": \"docker\", \r\n", " \"module_setup\": true\r\n", " }, \r\n", " \"changed\": false\r\n", "}\u001b[0m\r\n" ] } ], "source": [ "# Check connections versus the local host in the \"course\" group\n", "\n", "!ansible -i inventory course -msetup" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[0;32mpythonforsysadmin_course_1 | SUCCESS => {\n", " \"changed\": false, \n", " \"ping\": \"pong\"\n", "}\u001b[0m\n", "\u001b[1;31m172.17.0.5 | UNREACHABLE! => {\n", " \"changed\": false, \n", " \"msg\": \"Failed to connect to the host via ssh.\", \n", " \"unreachable\": true\n", "}\u001b[0m\n", "\u001b[1;31m172.17.0.6 | UNREACHABLE! => {\n", " \"changed\": false, \n", " \"msg\": \"Failed to connect to the host via ssh.\", \n", " \"unreachable\": true\n", "}\u001b[0m\n", "\u001b[1;31m172.17.0.7 | UNREACHABLE! => {\n", " \"changed\": false, \n", " \"msg\": \"Failed to connect to the host via ssh.\", \n", " \"unreachable\": true\n", "}\u001b[0m\n" ] } ], "source": [ "# Pinging all hosts gives some errors too, due to missing hosts or no ssh-key exchange\n", "!ansible -i inventory -m ping all" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Further on inventories" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " You can split your servers in many inventory files, like\n", "\n", " - staging\n", " \n", "```\n", "# staging inventory file\n", "# run with\n", "# ansible -i staging ...\n", " [ws]\n", " staging-ws-[0:3]\n", " \n", " [jboss]\n", " staging-boss-[0:6]\n", "```\n", " \n", " - production\n", " \n", "```\n", "# production inventory file\n", "# run with\n", "# ansible -i production ...\n", " [ws]\n", " ws-[0:3]\n", " \n", " [jboss]\n", " boss-[0:6]\n", "```\n", " \n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Playbooks\n", "\n", "To run a group of tasks with ansible, just:\n", "\n", " - create a playbook.yml\n", " - run ansible-playbook -i inventory playbook.yml\n", " \n", "\n", "A playbook is a list of tasks in yml format, something like\n", "\n", "```\n", "#\n", "# playbook.yml\n", "#\n", "- name: All public traffic is redirected via https\n", " uri:\n", " url: http://{{server_host}}/\n", " validate_certs: false\n", " follow_redirects: none\n", " status_code: 301\n", " \n", "- name: This webapp is served\n", " uri:\n", " url: https://{{server_host}}/webapp-1\n", " validate_certs: false\n", " status_code: 200\n", " HEADER_testflag: test\n", "\n", "- name: The WS is serverd and requires authentication\n", " uri:\n", " url: https://{{server_host}}/rest/v1/method\n", " validate_certs: false\n", " status_code: 401\n", "\n", "```\n", "\n", "In this case, instead of making actual installation|setup tasks, we just created a testsuite validating our deployment. Now we must write another playbook which takes care of deployng the actual machine.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Testing our course environment\n", "\n", "We can write a playbook to test our course environment." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# Run this with\r\n", "#\r\n", "# #ansible-playbook -i inventory python-course-test.yml\r\n", "#\r\n", "- hosts: course\r\n", " tasks:\r\n", " - name: The /notebooks directory should exist\r\n", " file: path=\"/notebooks\" state=directory\r\n", "\r\n", " - name: jupyter is responding on 8888\r\n", " uri:\r\n", " url: http://0.0.0.0:8888/notebooks\r\n", " validate_certs: false\r\n", " status_code: 200 # modify this line to simulate an error and see the outcome!\r\n", "\r\n", " - name: The template.conf is in place\r\n", " file: path=\"/tmp/template.conf\" state=file\r\n" ] } ], "source": [ "!cat python-course-test.yml" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "PLAY [course] ******************************************************************\n", "\n", "TASK [setup] *******************************************************************\n", "\u001b[0;32mok: [pythonforsysadmin_course_1]\u001b[0m\n", "\n", "TASK [The /notebooks directory should exist] ***********************************\n", "\u001b[0;32mok: [pythonforsysadmin_course_1]\u001b[0m\n", "\n", "TASK [jupyter is responding on 8888] *******************************************\n", "\u001b[0;32mok: [pythonforsysadmin_course_1]\u001b[0m\n", "\n", "TASK [The template.conf is in place] *******************************************\n", "\u001b[0;32mok: [pythonforsysadmin_course_1]\u001b[0m\n", "\n", "PLAY RECAP *********************************************************************\n", "\u001b[0;32mpythonforsysadmin_course_1\u001b[0m : \u001b[0;32mok\u001b[0m\u001b[0;32m=\u001b[0m\u001b[0;32m4\u001b[0m changed=0 unreachable=0 failed=0 \n", "\n" ] } ], "source": [ "!ansible-playbook -i inventory python-course-test.yml " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see something is missing: this playbook is not going to modify our machine but only test that everything is in place. \n", "\n", "See ```ansible-playbook --check ``` and ``` --diff ``` for further infos.\n", "\n", "We can run a setup playbook, conventionally named site.yml.\n" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# Run this with\r\n", "#\r\n", "# #ansible-playbook -i inventory site.yml\r\n", "#\r\n", "- hosts: course\r\n", " tasks:\r\n", " \r\n", " - name: Create a file from a template\r\n", " template: src=mytemplate.j2 dest=/tmp/template.conf\r\n", "\r\n", " - name: Ensure needed packages are present and eventually install them\r\n", " apt: name={{item}} state=present\r\n", " with_items:\r\n", " - python\r\n", " - python-dev\r\n", "# ignore_errors: yes # ignore errors during the course (eg. connectivity)\r\n", "\r\n", "\r\n" ] } ], "source": [ "!cat site.yml" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "PLAY [course] ******************************************************************\n", "\n", "TASK [setup] *******************************************************************\n", "\u001b[0;32mok: [pythonforsysadmin_course_1]\u001b[0m\n", "\n", "TASK [Create a file from a template] *******************************************\n", "\u001b[0;32mok: [pythonforsysadmin_course_1]\u001b[0m\n", "\n", "TASK [Ensure needed packages are present and eventually install them] **********\n", "\u001b[0;32mok: [pythonforsysadmin_course_1] => (item=[u'python', u'python-dev'])\u001b[0m\n", "\n", "PLAY RECAP *********************************************************************\n", "\u001b[0;32mpythonforsysadmin_course_1\u001b[0m : \u001b[0;32mok\u001b[0m\u001b[0;32m=\u001b[0m\u001b[0;32m3\u001b[0m changed=0 unreachable=0 failed=0 \n", "\n" ] } ], "source": [ "!ansible-playbook -i inventory site.yml --diff --limit=course # in this case the --limit does not change anything ;)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#\r\n", "# A simple templated file for ansible.\r\n", "# See the documentation to use this flexible\r\n", "# jinja template.\r\n", "\r\n", "GW=10.0.0.254\t\t\t# a static line\r\n", "HOSTNAME={{ansible_hostname}} # a dynamic one\r\n", "\r\n", "\r\n" ] } ], "source": [ "!cat mytemplate.j2\n", "\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.12" } }, "nbformat": 4, "nbformat_minor": 0 }