= [wiki:GENIExperimenter/Tutorials/GENIExperimentEngine Get to Know the GENI Experiment Engine] = {{{ #!html
Hello GENI index Hello GENI index Hello GENI index
}}} ---- = STEPS FOR EXECUTING EXERCISE = ---- '''Your goal in this tutorial is to fetch a parameterized URL on each node of your slicelet:''' '''!http://www.lively-web.org/nodejs/GEETutorial/helloWorld?slice=&name=&ip=&local=&lat=&lng=''' '''This page will log each of your queries, and you can check that all your nodes were successfully able to run the query.''' We will work up to this goal through hands-on learning with Ansible. ---- == 1. Experiment with Ansible == We will first get familiar with some basic Ansible tasks using the command-line interface. === (a) The ping module === The '''ping''' module simply tries to do a SSH login to a node and reports success or failure. Run the following command on your controller: {{{ $ ansible nodes -i ansible-hosts -m ping }}} If you don’t see success everywhere then there is something wrong with your setup. Ask one of the tutorial leaders for help. Note that you will be prompted to accept each node as you log into it; this happens only once per node, the first time you log in. === (b) The shell module === The '''shell''' module lets you run arbitrary SSH commands in parallel across a set of hosts. It’s useful for poking around, or if there is no Ansible module with the functionality you need. Try it out: {{{ $ ansible nodes -i ansible-hosts -m shell -a "hostname" }}} You can replace ''hostname'' above with any other Linux command. === (c) The setup module === The '''setup''' module gathers a bunch of information about each node and saves it in variables that you can reference in your Ansible playbooks. This will be really useful to do the tutorial! Try it out on a node to see what it collects (replace `` with your slicelet’s name): {{{ $ ansible .pcvm1-1.instageni.wisc.edu -i ansible-hosts -m setup }}} === (d) A simple playbook === Next, we will look at a simple Ansible playbook. An Ansible playbook is a YAML file containing a list of Ansible tasks. Copy the playbook below into a file called test.yaml: {{{ #!python --- - hosts: nodes remote_user: root tasks: - name: An example of a debug statement debug: var=ansible_hostname }}} Run the playbook as: {{{ $ ansible-playbook -i ansible-hosts test.yaml }}} The '''setup''' module is run automatically at the beginning of a playbook to populate variables for each node. The above playbook will dump the value of each node’s ''ansible_hostname'' variable. To run the playbook on a single node, replace ''nodes'' with the name of one of your slice nodes (e.g., slice338.pcvm3-7.instageni.nps.edu). ----- == 2. Create an Ansible playbook to download a parameterized URL from each node == Think about how you are going to solve the problems of this tutorial. You need to collect several pieces of information on each node: the container name, the IP of the host (i.e., the VM hosting the container), the IP of the container, and the latitude and longitude of the host. You then need to fetch a custom URL containing this information from each host. || [[Image(wiki:GENIExperimenter/Tutorials/Graphics:tip.png, nolink, 50px, bottom)]] || '''Pro Tip:''' Solve the problem on one node in your slice first, then deploy your solution to the remaining nodes. One thing at a time. || || [[Image(wiki:GENIExperimenter/Tutorials/Graphics:tip.png, nolink, 50px, bottom)]] || '''Pro Tip:''' Build your solution a piece at a time. Each step is, basically: (1) run a command, (2) possibly extract the information from the output and register it in an Ansible variable || === (a) Get the container's FQDN === Look at the variables collected by Ansible's setup module (step 1(c) above). Find one that holds the container's fully-qualified domain name (e.g., slice347.pcvm1-1.instageni.iu.edu) and dump it using a '''debug''' task. === (b) Get the container IP address === Look at the variables collected by Ansible's setup module (step 1(c) above). Find one that holds the container IP address and dump it using a '''debug''' task. === (c) Get the control host name === Look at the variables collected by Ansible's setup module (step 1(c) above). Find one that holds the control host's FQDN (HINT: it begins with ''pcvm'') and dump it using a '''debug''' task. You'll need this for the next step. === (d) Get the host's public IP address === The IP address visible inside the slicelet (as reported in the variable ''ansible_eth0.ipv4.address'') is a private address -- it is not the control address of the host. To discover the ''public'' IP address of the node, run '''dig +short '''. || [[Image(wiki:GENIExperimenter/Tutorials/Graphics:tip.png, nolink, 50px, bottom)]] || '''Pro Tip:''' The '''ansible''' command-line tool is a good way to try out Ansible tasks before putting them in your playbook. Look at the examples in part 1 above. || || [[Image(wiki:GENIExperimenter/Tutorials/Graphics:tip.png, nolink, 50px, bottom)]] || '''Pro Tip:''' Usually in an Ansible playbook you reference a variable by surrounding it in double curly brackets: ''{{ ansible_eth0.ipv4.address }}''. You can see examples of how variables are referenced in tasks in [https://github.com/ansible/ansible-examples/blob/master/language_features/get_url.yml this playbook]. || || [[Image(wiki:GENIExperimenter/Tutorials/Graphics:tip.png, nolink, 50px, bottom)]] || '''Pro Tip:''' When you run an Ansible command in a playbook, you can save the output into a new variable using '''register: varname''' Then you can retrieve the value later in the playbook using ''{{ varname }}'' or, for shell command output, ''{{ varname.stdout }}''. You can see an example of how to register a variable in [https://github.com/ansible/ansible-examples/blob/master/language_features/register_logic.yml this playbook]. || === (e) Get the latitude and longitude for each node === To map the host's control IP address obtained in the previous step to the latitude and longitude for each node, use the '''geoiplookup''' tool, provided by package '''geoip-bin'''. {{{ $ geoiplookup -f }}} where '''' is the database of IP addresses and locations. You can find a good one at: http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz, which you’ll have to download to each node and unzip. || [[Image(wiki:GENIExperimenter/Tutorials/Graphics:tip.png, nolink, 50px, bottom)]] || '''Pro Tip:''' The Ansible '''script''' module can be used to run arbitrary scripts in your slicelet. See: http://docs.ansible.com/script_module.html || || [[Image(wiki:GENIExperimenter/Tutorials/Graphics:tip.png, nolink, 50px, bottom)]] || '''Pro Tip:''' Not all the resources you may need are installed on the nodes! The '''apt''' Ansible module is useful for installing packages; see: http://docs.ansible.com/apt_module.html || === (f) Fetch the parameterized URL === At this point, you should have enough information to fetch the parameterized URL in the playbook. Here is an Ansible playbook skeleton to complete. Copy it to a file name ''gee-tutorial.yaml'' and fill in the bits marked `# INSERT ARGUMENTS HERE` based on the instructions in the following subsections. {{{ #!python --- - hosts: nodes remote_user: root tasks: - name: Update apt cache shell: apt-get update - name: Install python-apt (to work around an Ansible bug) shell: apt-get -y install python-apt ### 2(a): Get the container's FQDN ### - name: Dump container FQDN debug: # INSERT ARGUMENTS HERE ### 2(b): Get the container IP address ### - name: Dump container IP address debug: # INSERT ARGUMENTS HERE ### 2(c): Get the control host name ### - name: Dump control host name debug: # INSERT ARGUMENTS HERE ### 2(d): Get the host's public IP address ### - name: Install dnsutils (for dig) apt: # INSERT ARGUMENTS HERE - name: Get my public IP using 'dig +short' shell: # INSERT ARGUMENTS HERE register: public_ip - name: Dump public_ip variable debug: var=public_ip ### 2(e): Get the latitude and longitude for each node ### - name: Install geoip-bin (for geoiplookup) apt: # INSERT ARGUMENTS HERE - name: Download GeoLiteCity DB get_url: # INSERT ARGUMENTS HERE - name: Unzip GeoLiteCity.dat.gz shell: gunzip -f GeoLiteCity.dat.gz - name: Run geoiplookup to get latitude shell: # INSERT ARGUMENTS HERE register: latitude - name: Dump latitude variable debug: var=latitude - name: Run geoiplookup to get longitude shell: # INSERT ARGUMENTS HERE register: longitude - name: Dump longitude variable debug: var=longitude ### 2(f): Fetch the parameterized URL ### - name: Dump the full URL debug: msg="http://www.lively-web.org/nodejs/GEETutorial/helloWorld?slice=# INSERT ARGUMENTS HERE" - name: Fetch the full URL shell: curl "http://www.lively-web.org/nodejs/GEETutorial/helloWorld?slice=# INSERT ARGUMENTS HERE" }}} ---- == 3. Run the playbook == Once you have finished your playbook, run it against all the nodes! As a data point, our Ansible playbook contained six commands (not including debug commands) and used the '''apt''', '''shell''', and '''get_url''' modules. ---- == 4. Verify that your playbook worked as expected == Once you have completed the tutorial, you can check where you’ve said hello from at: ''!http://www.lively-web.org/nodejs/GEETutorial/show_hellos?slice='' You should see an entry for each node in your slicelet. ---- = [wiki:GENIExperimenter/Tutorials/GENIExperimentEngine/Finish Next: Teardown Experiment] =