Install simulated fabric and test client on the compute node

Change-Id: I8bd88561064f1309f1779e4666ba655bcad56bfa
diff --git a/cord-compute-playbook.yml b/cord-compute-playbook.yml
index df42336..72b0e04 100644
--- a/cord-compute-playbook.yml
+++ b/cord-compute-playbook.yml
@@ -1,5 +1,5 @@
 ---
-# Installs  new compute nodes in cord-pod XOS configuration using Juju
+# Installs new compute nodes in cord-pod XOS configuration using Juju
 
 - name: Include vars
   hosts: all
@@ -34,10 +34,11 @@
   become: yes
   roles:
     - compute-prep
+    - { role: maas-simulate-fabric, when: cord_in_a_box }
+    - { role: maas-test-client-install, when: cord_in_a_box }
 
 - name: Deploy compute nodes
   hosts: head
   roles:
     - juju-compute-setup
     - xos-compute-setup
-
diff --git a/roles/automation-integration/tasks/main.yml b/roles/automation-integration/tasks/main.yml
index 9f81631..c76dadd 100644
--- a/roles/automation-integration/tasks/main.yml
+++ b/roles/automation-integration/tasks/main.yml
@@ -57,6 +57,8 @@
     - head-prep
     - juju-compute-setup
     - xos-compute-setup
+    - maas-simulate-fabric
+    - maas-test-client-install
 
 - name: Copy Required Ansible Variables
   become: yes
@@ -71,6 +73,11 @@
     - cord.yml
     - example_keystone.yml
 
+- name: Store cord_in_a_box value for compute node provisioning
+  become: yes
+  lineinfile: "dest=/etc/maas/ansible/vars/cord.yml state=present regexp='^cord_in_a_box' line='cord_in_a_box: True'"
+  when: cord_in_a_box
+
 - name: Ensure JuJu and XOS Compute Node Provisioning
   become: yes
   lineinfile:
diff --git a/roles/compute-prep/tasks/main.yml b/roles/compute-prep/tasks/main.yml
index 975f2ec..ddda2c3 100644
--- a/roles/compute-prep/tasks/main.yml
+++ b/roles/compute-prep/tasks/main.yml
@@ -38,3 +38,8 @@
   file:
     path=/var/lib/nova
     state=directory
+
+- name: Remove superfluous requests package
+  pip:
+    name=requests
+    state=absent
diff --git a/roles/head-prep/tasks/main.yml b/roles/head-prep/tasks/main.yml
index 0fd1a7b..290d94c 100644
--- a/roles/head-prep/tasks/main.yml
+++ b/roles/head-prep/tasks/main.yml
@@ -29,6 +29,7 @@
     - git
     - bzr
     - juju-core
+    - python-pip
     - python-novaclient
     - python-neutronclient
     - python-keystoneclient
@@ -36,6 +37,16 @@
     - python-lxml
     - virt-top
 
+- name: Install Python packages
+  pip:
+    name={{ item}}
+    state=present
+  with_items:
+    - urllib3
+    - pyopenssl
+    - ndg-httpsclient
+    - pyasn1
+
 - name: Prep user account by adding to libvirtd group and generating SSH key
   user:
     name={{ ansible_user_id }}
diff --git a/roles/maas-simulate-fabric/defaults/main.yml b/roles/maas-simulate-fabric/defaults/main.yml
new file mode 100755
index 0000000..c86c5ee
--- /dev/null
+++ b/roles/maas-simulate-fabric/defaults/main.yml
@@ -0,0 +1,36 @@
+---
+# maas-simulate-fabric/defaults/main.yml
+
+simfabric_bridges:
+  - name: databr
+    addresses:
+      - "10.168.0.1/24"
+      - "10.168.1.1/24"
+    interfaces:
+      - veth0
+
+simfabric_links:
+  - type: veth
+    dev: veth0
+    peer: fabric
+    mac: "02:42:0a:a8:00:01"
+
+# see note in playbook, won't apply until ansible gets module support
+simfabric_iptables:
+  - table: nat
+    chain: POSTROUTING
+    source: "10.168.0.0/16"
+    dest: "! 10.168.0.0/16"
+    jump: MASQUERADE
+
+simfabric_sysctl:
+  - name: net.ipv4.ip_forward
+    value: 1
+  - name: net.ipv4.conf.all.send_redirects
+    value: 0
+  - name: net.ipv4.conf.default.send_redirects
+    value: 0
+  - name: net.ipv4.conf.eth0.send_redirects
+    value: 0
+  - name: net.ipv4.conf.databr.send_redirects
+    value: 0
diff --git a/roles/maas-simulate-fabric/tasks/main.yml b/roles/maas-simulate-fabric/tasks/main.yml
new file mode 100755
index 0000000..08cbafe
--- /dev/null
+++ b/roles/maas-simulate-fabric/tasks/main.yml
@@ -0,0 +1,83 @@
+---
+- name: Install prerequisites
+  apt:
+    name={{ item }}
+    update_cache=yes
+    cache_valid_time=3600
+  become: yes
+  register: result
+  until: result | success
+  retries: 15
+  delay: 60
+  with_items:
+   - bridge-utils
+
+- name: Create bridges
+  when: "ansible_{{ item.name }} is not defined"
+  command: brctl addbr "{{ item.name }}"
+  with_items: "{{ simfabric_bridges }}"
+
+# note, not idempotent if failed between prior step and this step
+- name: Set IP addresses to bridges
+  when: "ansible_{{ item.0.name }} is not defined"
+  command: "ip addr add {{ item.1 }} dev {{ item.0.name }}"
+  with_subelements:
+   - "{{ simfabric_bridges }}"
+   - addresses
+
+- name: Run setup again to obtain bridge info
+  setup:
+
+- name: Start bridges
+  when: "not ansible_{{ item.name }}.active"
+  command: "ip link set dev {{ item.name }} up"
+  with_items: "{{ simfabric_bridges }}"
+
+- name: Create ip links
+  when: "ansible_{{ item.dev }} is not defined"
+  command: "ip link add dev {{ item.dev }} address {{ item.mac }} type {{ item.type }} peer name {{ item.peer }}"
+  with_items: "{{ simfabric_links }}"
+
+- name: Run setup again to obtain link info
+  setup:
+
+- name: Start interfaces
+  when: "not ansible_{{ item }}.active"
+  command: "ip link set dev {{ item }} up"
+  with_items:
+  - "{{ simfabric_links | map(attribute='dev') | list }}"
+  - "{{ simfabric_links | map(attribute='peer') | list }}"
+
+- name: Add interfaces to bridges
+  when: "not item.1 in ansible_{{ item.0.name }}.interfaces"
+  command: "brctl addif {{ item.0.name }} {{ item.1 }}"
+  with_subelements:
+   - "{{ simfabric_bridges }}"
+   - interfaces
+
+- name: Check for iptables rule
+  command: "iptables -t nat -C POSTROUTING -s 10.168.0.0/16 ! -d 10.168.0.0/16 -j MASQUERADE"
+  register: iptables_check
+  failed_when: "iptables_check|failed and 'No chain/target/match by that name' not in iptables_check.stderr"
+  tags:
+    - skip_ansible_lint # FIXME: should use iptables module when it supports inversion of ranges
+
+- name: Create iptables rule
+  when: "iptables_check.rc != 0"
+  command: "iptables -t nat -A POSTROUTING -s 10.168.0.0/16 ! -d 10.168.0.0/16 -j MASQUERADE"
+
+# the below will likely work when this pull makes it into ansible:
+# https://github.com/ansible/ansible-modules-extras/pull/1685
+#   - name: Configure iptables
+#     iptables: "table={{ item.table }} chain={{ item.chain }} source={{ item.source }} destination={{ item.dest }} jump={{ item.jump }}"
+#     with_items: "{{ simfabric_iptables }}"
+
+- name: Set kernel sysctl values
+  sysctl:
+    name="{{ item.name }}"
+    value="{{ item.value }}"
+    sysctl_set=yes
+    state=present
+    reload=yes
+  with_items: "{{ simfabric_sysctl }}"
+
diff --git a/roles/maas-test-client-install/tasks/main.yml b/roles/maas-test-client-install/tasks/main.yml
new file mode 100644
index 0000000..8e90c9e
--- /dev/null
+++ b/roles/maas-test-client-install/tasks/main.yml
@@ -0,0 +1,43 @@
+---
+- name: Install software
+  apt:
+    name={{ item }}
+    update_cache=yes
+    cache_valid_time=3600
+  become: yes
+  register: result
+  until: result | success
+  retries: 15
+  delay: 60
+  with_items:
+   - lxc
+
+- name: set lxc bridge interface to be databr
+  become: yes
+  lineinfile:
+    dest: /etc/lxc/default.conf
+    regexp: "^lxc.network.link ="
+    line: "lxc.network.link = databr"
+
+- name: Create testclient
+  become: yes
+  shell: lxc-ls | grep testclient || lxc-create -t ubuntu -n testclient
+  tags:
+    - skip_ansible_lint # FIXME: should used lxc_container module
+
+- name: Start testclient
+  become: yes
+  shell: lxc-info -n testclient -s | grep RUNNING || lxc-start -d -n testclient
+  tags:
+    - skip_ansible_lint # FIXME: should used lxc_container module
+
+- name: Set up networking inside the testclient for testing sample CORD subscriber
+  become: yes
+  shell: "{{ item }}"
+  with_items:
+  - "lxc-attach -n testclient -- bash -c 'ip link show eth0.222 || ip link add link eth0 name eth0.222 type vlan id 222'"
+  - "lxc-attach -n testclient -- bash -c 'ip link show eth0.222.111 || ip link add link eth0.222 name eth0.222.111 type vlan id 111'"
+  - "lxc-attach -n testclient -- ifconfig eth0.222 up"
+  - "lxc-attach -n testclient -- ifconfig eth0.222.111 up"
+  tags:
+    - skip_ansible_lint # non-trivial use case
diff --git a/roles/test-exampleservice/tasks/main.yml b/roles/test-exampleservice/tasks/main.yml
index 92bf70b..279a9d0 100644
--- a/roles/test-exampleservice/tasks/main.yml
+++ b/roles/test-exampleservice/tasks/main.yml
@@ -45,8 +45,14 @@
   tags:
     - skip_ansible_lint # running a sub job
 
+- name: Get name of compute node
+  shell: bash -c "source ~/admin-openrc.sh; nova service-list|grep nova-compute|cut -d '|' -f 3"
+  register: node_name
+  tags:
+    - skip_ansible_lint # running a sub job
+
 - name: Wait for Apache to come up inside VM
-  shell: ssh -o ProxyCommand="ssh -W %h:%p ubuntu@nova-compute-1" ubuntu@{{ mgmt_ip.stdout }} "ls /var/run/apache2/apache2.pid" > /dev/null
+  shell: ssh -o ProxyCommand="ssh -W %h:%p -l ubuntu {{ node_name.stdout }}" ubuntu@{{ mgmt_ip.stdout }} "ls /var/run/apache2/apache2.pid" > /dev/null
   register: result
   until: result | success
   retries: 20
@@ -55,14 +61,12 @@
     - skip_ansible_lint # running a sub job
 
 - name: Install curl in testclient
-  command: ansible nova-compute-1 -u ubuntu -m shell \
-    -s -a "lxc-attach -n testclient -- apt-get -y install curl"
+  command: ssh -l ubuntu {{ node_name.stdout }} "sudo lxc-attach -n testclient -- apt-get -y install curl"
   tags:
     - skip_ansible_lint # running a sub job
 
 - name: Test connectivity to ExampleService from test client
-  command: ansible nova-compute-1 -u ubuntu -m shell \
-    -s -a "lxc-attach -n testclient -- curl -s http://{{ public_ip.stdout }}"
+  command: ssh -l ubuntu {{ node_name.stdout }} "sudo lxc-attach -n testclient -- curl -s http://{{ public_ip.stdout }}"
   register: curltest
   tags:
     - skip_ansible_lint # running a sub job
diff --git a/roles/test-vsg/tasks/main.yml b/roles/test-vsg/tasks/main.yml
index eaad0a5..9eb08a9 100644
--- a/roles/test-vsg/tasks/main.yml
+++ b/roles/test-vsg/tasks/main.yml
@@ -39,8 +39,14 @@
   tags:
     - skip_ansible_lint # running a sub job
 
+- name: Get name of compute node
+  shell: bash -c "source ~/admin-openrc.sh; nova service-list|grep nova-compute|cut -d '|' -f 3"
+  register: node_name
+  tags:
+    - skip_ansible_lint # running a sub job
+
 - name: Wait for Docker container inside VM to come up
-  shell: ssh -o ProxyCommand="ssh -W %h:%p ubuntu@nova-compute-1" ubuntu@{{ mgmt_ip.stdout }} "sudo docker ps|grep vcpe" > /dev/null
+  shell: ssh -o ProxyCommand="ssh -W %h:%p -l ubuntu {{ node_name.stdout }}" ubuntu@{{ mgmt_ip.stdout }} "sudo docker ps|grep vcpe" > /dev/null
   register: result
   until: result | success
   retries: 20
@@ -49,14 +55,12 @@
     - skip_ansible_lint # running a sub job
 
 - name: Run dhclient inside testclient to get IP address from vSG
-  command: ansible nova-compute-1 -u ubuntu -m shell \
-    -s -a "lxc-attach -n testclient -- dhclient eth0.222.111"
+  command: ssh -l ubuntu {{ node_name.stdout }} "sudo lxc-attach -n testclient -- dhclient eth0.222.111"
   tags:
     - skip_ansible_lint # running a sub job
 
 - name: Test external connectivity in test client
-  command: ansible nova-compute-1 -u ubuntu -m shell \
-    -s -a "lxc-attach -n testclient -- ping -c 3 8.8.8.8"
+  command: ssh -l ubuntu {{ node_name.stdout }} "sudo lxc-attach -n testclient -- ping -c 3 8.8.8.8"
   register: pingtest
   tags:
     - skip_ansible_lint # running a sub job
diff --git a/roles/xos-compute-setup/tasks/main.yml b/roles/xos-compute-setup/tasks/main.yml
index a7b8414..1df8204 100644
--- a/roles/xos-compute-setup/tasks/main.yml
+++ b/roles/xos-compute-setup/tasks/main.yml
@@ -7,3 +7,11 @@
   command: ssh ubuntu@xos "cd {{ service_profile_repo_dest }}/{{ xos_configuration }}/; make new-nodes"
   tags:
     - skip_ansible_lint # running a sub-job
+
+- name: Pause 5 seconds
+  pause: seconds=5
+
+- name: ssh to XOS VM and run 'make vtn'
+  command: ssh ubuntu@xos "cd {{ service_profile_repo_dest }}/{{ xos_configuration }}/; rm -f vtn-external.yaml; make vtn"
+  tags:
+    - skip_ansible_lint # running a sub-job
diff --git a/vars/cord.yml b/vars/cord.yml
index c04f7a0..faa243d 100644
--- a/vars/cord.yml
+++ b/vars/cord.yml
@@ -44,7 +44,8 @@
 #    image_url: "http://www.vicci.org/cord/ceilometer-trusty-server-multi-nic.compressed.qcow2"
 #    checksum: "sha256:afde3f0448483902693be4d52ae76bb683fd74b1c7728019094bf81b37d86105"
 
-# turn this on, or override when running playbook with --extra-vars="on_cloudlab=True"
+# turn this on, or override it when running the playbook with --extra-vars="on_cloudlab=True"
 on_cloudlab: False
 
-
+# turn this on, or override it when running the playbook with --extra-vars="cord_in_a_box=True"
+cord_in_a_box: False