ActiveTest Service Creation.

Onboarding is done by running 'make activetest'. fusion.img, qt600.img, vta.img, and vpma.img
should be in the corresponding service_profile's image/ folder in order for images to be
uploaded in glance.

The measurement agents can be created through the different agents tenants. For example, to
create a VPMA tenant, run 'make vpma 1' where '1' can be any numberical identifier for the
tenant to be created.

Measurement agents will automatically register with the fusion controller through the use of
the synchronizer. Furthermore, tests can be orchestrated through XOS by modifying the models
for the vpma agents.

Change-Id: I69bab4b5f771c87126781799217bb36fda478fd3
diff --git a/xos/synchronizer/steps/activetesttenant_playbook.yaml b/xos/synchronizer/steps/activetesttenant_playbook.yaml
new file mode 100644
index 0000000..0a7eaba
--- /dev/null
+++ b/xos/synchronizer/steps/activetesttenant_playbook.yaml
@@ -0,0 +1,13 @@
+---
+# activetesttenant_playbook - sets up the controller
+
+- hosts: "{{ instance_name }}"
+  connection: ssh
+  user: root
+  sudo: no
+  gather_facts: no
+  vars:
+    - public_ip: "{{ public_ip }}"
+
+  roles:
+    - setup_controller
diff --git a/xos/synchronizer/steps/qt600tenant_playbook.yaml b/xos/synchronizer/steps/qt600tenant_playbook.yaml
new file mode 100644
index 0000000..8218a36
--- /dev/null
+++ b/xos/synchronizer/steps/qt600tenant_playbook.yaml
@@ -0,0 +1,20 @@
+---
+# activetesttenant_playbook - sets up the controller
+
+- hosts: "{{ instance_name }}"
+  connection: ssh
+  user: root
+  sudo: no
+  gather_facts: no
+  vars:
+    - private_ip: "{{ private_ip }}"
+    - public_ip: "{{ public_ip }}"
+    - controller_ip: "{{ controller_ip }}"
+    - reflector_ip: "{{ reflector_ip }}"
+    - reflector_public_ip: "{{ reflector_public_ip }}"
+    - is_initiator: {{ is_initiator }}
+    - is_reflector: {{ is_reflector }}
+
+  roles:
+    - setup_ma
+    - setup_qt600
diff --git a/xos/synchronizer/steps/roles/setup_controller/tasks/main.yml b/xos/synchronizer/steps/roles/setup_controller/tasks/main.yml
new file mode 100644
index 0000000..86d1c96
--- /dev/null
+++ b/xos/synchronizer/steps/roles/setup_controller/tasks/main.yml
@@ -0,0 +1,29 @@
+---
+
+- name: check if need to set up controller
+  command: grep "localhost.fusion-controller" /etc/hosts
+  register: result
+  ignore_errors: True
+
+- name: setup /etc/hosts - delete default entry
+  shell: sed -i "/localhost.fusion-controller/d" /etc/hosts
+  when: result.rc == 0
+
+- name: setup /etc/hostname - set hostname
+  shell: sed -i "/localhost.fusion-controller/d" /etc/hostname
+  when: result.rc == 0
+
+- name: setup /etc/hosts - delete default entry
+  shell: echo "{{ public_ip }} $(hostname)" >> /etc/hosts
+  when: result.rc == 0
+
+- name: set controller ip in ui config
+  shell: |
+    python -c "import json as j;f='/ada/NTCtestui/config.json';d=j.load(open(f));d['fusion-controller']['hostname']='{{ public_ip }}';d['fusion-collector']['hostname']='{{ public_ip }}';j.dump(d,open(f,'w'))"
+  when: result.rc == 0
+
+- name: start fusion services
+  shell: /etc/init.d/npiu_adatdce restart
+  when: result.rc == 0
+
+   
diff --git a/xos/synchronizer/steps/roles/setup_ma/files/fusion_controller.py b/xos/synchronizer/steps/roles/setup_ma/files/fusion_controller.py
new file mode 100644
index 0000000..d1a8531
--- /dev/null
+++ b/xos/synchronizer/steps/roles/setup_ma/files/fusion_controller.py
@@ -0,0 +1,103 @@
+#!/usr/bin/python
+import requests, copy, json, datetime, os
+
+REFLECTOR_ID_FILE="/root/reflector_id"
+INITIATOR_ID_FILE="/root/initiator_id"
+
+##############################################################################################################################################################3
+
+start_reflector_template={u'agent': {u'primary': {u'config': u'primaryConfig',
+                                                  u'id': u'vpma1',
+                                                  u'type': u'inventory'}},
+                          u'config': [{u'primaryConfig': {u'ietf-lmap-control:lmap': {u'schedules': {u'schedule': [{u'action': [{u'name': u'TWAMP-REFLECTOR-PM-PROBE0-action',
+                                                                                                                                 u'option': [{u'id': u'source-ip',
+                                                                                                                                              u'value': u'10.0.0.0'},
+                                                                                                                                             {u'id': u'subnet',
+                                                                                                                                              u'value': u'255.255.255.0'},
+                                                                                                                                             {u'id': u'gateway',
+                                                                                                                                              u'value': u'0.0.0.0'},
+                                                                                                                                             {u'id': u'twamp',
+                                                                                                                                              u'value': u'{"ietf-twamp:twamp":{"twamp-server":{"server-admin-state":true,"server-tcp-port":"862","dscp":0,"mode":"bits.unauthenticated"}}}'}],
+                                                                                                                                 u'task': u'twamp-reflector'}],
+                                                                                                                    u'name': u'TWAMP-REFLECTOR-PM-PROBE0',
+                                                                                                                    u'start': u'immediate'}]}}}}],
+                          u'test': {}}
+
+##############################################################################################################################################################3
+
+start_initiator_template=u'{"agent":{"primary":{"type":"inventory","id":"%(initiator_name)s","config":"primaryConfig"}},"test":{"extended-config":{"test":{"nameOnProbe":"twamp-initiator","selected":true,"testType":"twamp","testTypeLabel":"TWAMP Initiator"},"testPoints":[{"ip":"%(initiator_ip)s","model":"vPMA","name":"%(initiator_name)s","port":"80","selected":true,"tag":"Test Point A","type":"inventory","vendor":"viavi","version":"1.0"},{"model":"vPMA","name":"Test Point B","selected":false,"tag":"Test Point B","type":"inventory","vendor":"viavi","version":"1.0"}],"pluginConfig":{"setup":{"version":"2","schedMode":"immediate","periodicDuration":"00:05:00","periodicInterval":"00:15:00","pmInterval":"1","enableRandomStart":"false","randomOffset":"00:10:00","enableRt":"true","rtInterval":"%(interval)s","srcIPAddress":"%(initiator_src_ip)s","srcNetmask":"255.255.255.0","gatewayIPAddress":"192.168.2.1","srcStartingPort":"50000","configToServicesMap":{},"serviceParamToConfigMap":{}},"connections":{"version":"2","connections":[{"version":"2","name":"My Session","enabled":"true","source":null,"destination":{"version":"2","ipv4DestMgmtAddr":"%(reflector_src_ip)s","dstMgmtPort":"862"},"network":null,"numFlows":1,"flows":[{"version":"1","flowName":"Flow 1","flowInUse":"true","flowIpv4DiffServVal":"0","flowPad":"483","flowUdpPort":"50000","flowTxInterval":"10","flowReflWaitTimeout":"2"}]}]}},"testInfo":{"comments":"","name":"Lorna-%(test_name)s"}},"test-list-data":{"customer":{}}},"config":[{"primaryConfig":{"ietf-lmap-control:lmap":{"schedules":{"schedule":[{"name":"Lorna-%(test_name)s","start":"immediate","action":[{"name":"Lorna-%(test_name)s-action","task":"twamp-initiator","option":[{"id":"subnet","value":"255.255.255.0"},{"id":"gateway","value":"0.0.0.0"},{"id":"twamp","value":"{\\"ietf-twamp:twamp\\":{\\"twamp-client\\":{\\"client-admin-state\\":true,\\"mode-preference-chain\\":[{\\"priority\\":1,\\"mode\\":\\"bits.unauthenticated\\"}],\\"twamp-client-ctrl-connection\\":[{\\"ctrl-connection-name\\":\\"My Session\\",\\"client-ip\\":\\"%(initiator_src_ip)s\\",\\"server-ip\\":\\"%(reflector_src_ip)s\\",\\"server-tcp-port\\":862,\\"dscp\\":0,\\"twamp-session-request\\":[{\\"test-session-name\\":\\"Flow 1\\",\\"sender-ip\\":\\"%(initiator_src_ip)s\\",\\"sender-udp-port\\":\\"50000\\",\\"reflector-ip\\":\\"%(reflector_src_ip)s\\",\\"reflector-udp-port\\":\\"50000\\",\\"timeout\\":\\"2\\",\\"padding-length\\":\\"483\\",\\"dscp\\":\\"0\\"}]}],\\"twamp-session-sender\\":{\\"session-sender-admin-state\\":true,\\"twamp-sender-test-session\\":[{\\"test-session-name\\":\\"Flow 1\\",\\"fill-mode\\":\\"fill-mode.zero\\",\\"periodic-interval\\":\\"10\\",\\"periodic-interval-units\\":\\"milliseconds\\"}]}}}}"}],"destination":["Lorna-%(test_name)s-results-periodic-pm","Lorna-%(test_name)s-results-periodic-rt"]}]},{"name":"Lorna-%(test_name)s-results-periodic-pm","start":"Lorna-%(test_name)s-results-periodic-pm-event","action":[{"name":"Lorna-%(test_name)s-results-periodic-pm-action","task":"results","option":[{"id":"result-type","value":"pm"},{"id":"channel","value":"http://%(controller_ip)s:26088/restconf/operations/ietf-lmap-report:report"}]}]},{"name":"Lorna-%(test_name)s-results-periodic-rt","start":"Lorna-%(test_name)s-results-periodic-rt-event","action":[{"name":"Lorna-%(test_name)s-results-periodic-rt-action","task":"results","option":[{"id":"result-type","value":"rt"},{"id":"channel","value":"http://%(controller_ip)s:26088/restconf/operations/ietf-lmap-report:report"}]}]}]},"events":{"event":[{"name":"Lorna-%(test_name)s-results-periodic-pm-event","periodic":{"interval":60}},{"name":"Lorna-%(test_name)s-results-periodic-rt-event","periodic":{"interval":5}}]}}}}]}'
+
+class FusionController:
+    def __init__(self,inventory_ip):
+        self.ip = inventory_ip
+        self.i_url="http://%s:30100"%self.ip # inventory url
+        self.c_url="http://%s:8080"%self.ip  # controller url
+        self.h = {"Content-Type":"application/json"}
+    def get_ma(self,ma_ip):
+        inventory = requests.post("%s/vibe/inventory/v2/queryDevices"%self.i_url, headers=self.h).json()
+        return [ma for ma in inventory if ma_ip in ma['connections'][0]['uri']][0]
+        
+    def start_reflector(self, reflector_ip, reflector_source_ip):
+        ma = self.get_ma(reflector_ip)
+        data = copy.deepcopy(start_reflector_template)
+        data['agent']['primary']['id']=ma['name']
+        config_options=data['config'][0]['primaryConfig']['ietf-lmap-control:lmap']['schedules']['schedule'][0]['action'][0]['option']
+        config_options[0]['value']=reflector_source_ip
+        r=requests.post("%s/sbi/restconf/data/ietf-lmap-control:lmap"%self.c_url,headers=self.h,data=json.dumps(data))
+        open(REFLECTOR_ID_FILE,"w").write(r.json()["id"])
+
+    def start_initiator(self, initiator_ip, initiator_source_ip, reflector_ip, reflector_source_ip, interval="1"):
+        reflector = self.get_ma(reflector_ip)
+        initiator = self.get_ma(initiator_ip)
+        
+	now = datetime.datetime.now()
+	timestamp = '{}-{}-{}-{}:{}'.format(now.year, now.month, now.day, now.hour, now.minute)
+        config_options={"initiator_name":initiator["name"],"initiator_ip":initiator_ip,"initiator_src_ip":initiator_source_ip,
+                        "reflector_name":reflector["name"],"reflector_ip":reflector_ip,"reflector_src_ip":reflector_source_ip,
+                        "interval":interval,"test_name":timestamp,"controller_ip":self.ip}
+        r=requests.post("%s/sbi/restconf/data/ietf-lmap-control:lmap"%self.c_url,headers=self.h,data=start_initiator_template%config_options)
+        open(INITIATOR_ID_FILE,"w").write(r.json()["id"])
+
+    def stop_test(self, id):
+       print("%s/sbi/restconf/operations/action/lmap?scheduleid=%s"%(self.c_url,id))
+       requests.post("%s/sbi/restconf/operations/action/lmap?scheduleid=%s"%(self.c_url,id),headers=self.h,data=json.dumps({'action':'cancel'}))
+
+
+def start_reflector(options):
+    f = FusionController(options.controller_ip)
+    f.start_reflector(options.reflector_ip,options.reflector_src_ip)
+
+def start_initiator(options):
+    f = FusionController(options.controller_ip)
+    f.start_initiator(options.initiator_ip,options.initiator_src_ip,options.reflector_ip,options.reflector_src_ip,options.results_interval)
+
+def stop_test(options,id_file):
+    if os.path.exists(id_file):
+        f = FusionController(options.controller_ip)
+        f.stop_test(open(id_file).read())
+        os.remove(id_file)
+
+if __name__=="__main__":
+    import argparse
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--controller-ip', help='IP of the Server', default='172.27.0.3')
+    parser.add_argument('--results-interval', help='Results Interval', default='5')
+    parser.add_argument('--reflector-ip', help='IP of the Agent to use as Reflector', default='10.0.6.4')
+    parser.add_argument('--reflector-src-ip', help='Source IP of the reflector', default='10.0.7.3')
+    parser.add_argument('--initiator-ip', help='IP of the Agent to use as initiator', default='10.0.6.5')
+    parser.add_argument('--initiator-src-ip', help='Source IP of the reflector', default='10.0.7.4')
+    parser.add_argument("--start-reflector", help="start reflector", action="store_true")
+    parser.add_argument("--start-initiator", help="start initiator", action="store_true")
+    parser.add_argument("--stop-reflector", help="stop reflector", action="store_true")
+    parser.add_argument("--stop-initiator", help="stop initiator", action="store_true")
+
+    options = parser.parse_args()
+    if options.start_reflector:
+        start_reflector(options)
+    if options.start_initiator:
+        start_initiator(options)
+    if options.stop_reflector:
+        stop_test(options,REFLECTOR_ID_FILE)
+    if options.stop_initiator:
+        stop_test(options,INITIATOR_ID_FILE)
+    
diff --git a/xos/synchronizer/steps/roles/setup_ma/tasks/main.yml b/xos/synchronizer/steps/roles/setup_ma/tasks/main.yml
new file mode 100644
index 0000000..abd98ee
--- /dev/null
+++ b/xos/synchronizer/steps/roles/setup_ma/tasks/main.yml
@@ -0,0 +1,4 @@
+---
+
+- name: copy test controller script
+  copy: src=fusion_controller.py dest=/root/fusion_controller.py mode=0755
diff --git a/xos/synchronizer/steps/roles/setup_qt600/tasks/main.yml b/xos/synchronizer/steps/roles/setup_qt600/tasks/main.yml
new file mode 100644
index 0000000..a8ef516
--- /dev/null
+++ b/xos/synchronizer/steps/roles/setup_qt600/tasks/main.yml
@@ -0,0 +1,59 @@
+---
+
+- name: check if work should be done
+  stat: path=/tmp/init_completed
+  register: result
+
+- name: get interface of private_ip
+  register: private_interface
+  shell: |
+    ip addr | awk '/^[0-9]+:/ {   sub(/:/,"",$2); iface=$2 } /^[[:space:]]*inet / {   split($2, a, "/");  print iface" : "a[1] }' | grep "{{ private_ip }}" | cut -d " " -f 1
+  when: result.stat.exists == False
+
+- name: run vnf-setup 
+  shell: vnf-setup --controller-address {{controller_ip}} --controller-port 30500 --test-interface {{ private_interface.stdout }} --enable-single-test-mode
+  when: result.stat.exists == False
+
+- name: rm dhcp cache
+  shell: rm /var/lib/dhcp/dhclient.leases
+  when: result.stat.exists == False
+
+- name: rm test interface from /etc/network/interfaces
+  shell: |
+    sed -i '/{{ private_interface.stdout }}/d' /etc/network/interfaces
+  when: result.stat.exists == False
+
+- name: reset test interface ip
+  shell: ifconfig {{ private_interface.stdout }} 0.0.0.0
+  when: result.stat.exists == False
+
+- name: stop qt services
+  shell: /etc/init.d/vqt_startup stop
+  when: result.stat.exists == False
+
+- name: start apache service
+  shell: /etc/init.d/apache2 start
+  when: result.stat.exists == False
+
+- name: start qt services
+  shell: /etc/init.d/vqt_startup start
+  when: result.stat.exists == False
+
+- name: record task completed
+  shell: echo "done" > /tmp/init_completed
+#
+# - name: run reflector
+#   command: python /root/fusion_controller.py --start-reflector --controller-ip "{{ controller_ip }}" --reflector-ip "{{ public_ip }}"  --reflector-src-ip "{{ private_ip }}"
+#   when: is_reflector
+# 
+# - name: run initiator
+#   command: python /root/fusion_controller.py --start-initiator  --controller-ip "{{ controller_ip }}" --initiator-ip "{{ public_ip }}"  --initiator-src-ip "{{ private_ip }}" --reflector-ip "{{ reflector_public_ip }}"  --reflector-src-ip "{{ reflector_ip }}" 
+#   when: is_initiator
+# 
+# - name: stop reflector
+#   command: python /root/fusion_controller.py --stop-reflector --controller-ip "{{ controller_ip }}"
+#   when: is_reflector == False
+# 
+# - name: stop initiator
+#   command: python /root/fusion_controller.py --stop-initiator  --controller-ip "{{ controller_ip }}"
+#   when: is_initiator == False
diff --git a/xos/synchronizer/steps/roles/setup_vpma/tasks/main.yml b/xos/synchronizer/steps/roles/setup_vpma/tasks/main.yml
new file mode 100644
index 0000000..f26f827
--- /dev/null
+++ b/xos/synchronizer/steps/roles/setup_vpma/tasks/main.yml
@@ -0,0 +1,51 @@
+---
+
+- name: check if work should be done
+  stat: path=/tmp/init_completed
+  register: result
+
+- name: get interface of private_ip
+  register: private_interface
+  shell: |
+    ip addr | awk '/^[0-9]+:/ {   sub(/:/,"",$2); iface=$2 } /^[[:space:]]*inet / {   split($2, a, "/");  print iface" : "a[1] }' | grep "{{ private_ip }}" | cut -d " " -f 1
+  when: result.stat.exists == False
+
+- name: run vnf-setup 
+  shell: vnf-setup --controller-address {{controller_ip}} --controller-port 30500 --test-interface {{ private_interface.stdout }} --enable-single-test-mode
+  when: result.stat.exists == False
+
+- name: rm dhcp cache
+  shell: rm /var/lib/dhcp/dhclient.leases
+  when: result.stat.exists == False
+
+- name: rm test interface from /etc/network/interfaces
+  shell: |
+    sed -i '/{{ private_interface.stdout }}/d' /etc/network/interfaces
+  when: result.stat.exists == False
+
+- name: reset test interface ip
+  shell: ifconfig {{ private_interface.stdout }} 0.0.0.0
+  when: result.stat.exists == False
+
+- name: restart qt services
+  shell: /etc/init.d/vqt_startup restart
+  when: result.stat.exists == False
+
+- name: record task completed
+  shell: echo "done" > /tmp/init_completed
+
+- name: run reflector
+  command: python /root/fusion_controller.py --start-reflector --controller-ip "{{ controller_ip }}" --reflector-ip "{{ public_ip }}"  --reflector-src-ip "{{ private_ip }}"
+  when: is_reflector
+
+- name: run initiator
+  command: python /root/fusion_controller.py --start-initiator  --controller-ip "{{ controller_ip }}" --initiator-ip "{{ public_ip }}"  --initiator-src-ip "{{ private_ip }}" --reflector-ip "{{ reflector_public_ip }}"  --reflector-src-ip "{{ reflector_ip }}" 
+  when: is_initiator
+
+- name: stop reflector
+  command: python /root/fusion_controller.py --stop-reflector --controller-ip "{{ controller_ip }}"
+  when: is_reflector == False
+
+- name: stop initiator
+  command: python /root/fusion_controller.py --stop-initiator  --controller-ip "{{ controller_ip }}"
+  when: is_initiator == False
\ No newline at end of file
diff --git a/xos/synchronizer/steps/roles/setup_vta/tasks/main.yml b/xos/synchronizer/steps/roles/setup_vta/tasks/main.yml
new file mode 100644
index 0000000..8a00676
--- /dev/null
+++ b/xos/synchronizer/steps/roles/setup_vta/tasks/main.yml
@@ -0,0 +1,36 @@
+---
+
+- name: check if work should be done
+  stat: path=/tmp/init_completed
+  register: result
+
+- name: get interface of private_ip
+  register: private_interface
+  shell: |
+    ip addr | awk '/^[0-9]+:/ {   sub(/:/,"",$2); iface=$2 } /^[[:space:]]*inet / {   split($2, a, "/");  print iface" : "a[1] }' | grep "{{ private_ip }}" | cut -d " " -f 1
+  when: result.stat.exists == False
+
+- name: get interface of public_ip
+  register: public_interface
+  shell: |
+    ip addr | awk '/^[0-9]+:/ {   sub(/:/,"",$2); iface=$2 } /^[[:space:]]*inet / {   split($2, a, "/");  print iface" : "a[1] }' | grep "{{ public_ip }}" | cut -d " " -f 1
+  when: result.stat.exists == False
+
+- name: get gateway of private_ip
+  register: private_gateway
+  shell: |
+    echo {{ private_ip }} | cut -d '.' -f 1,2,3 | sed '/.*/ s/$/.1/'
+  when: result.stat.exists == False
+
+- name: setup vta
+  shell: |
+    vnf-setup --test-network {{private_interface.stdout}},{{private_ip}},255.255.255.0,{{private_gateway.stdout}} --management-interface {{public_interface.stdout}} --io-virtualization VIRTIO --test-speed 1G --tagging UNTAGGED --mtu-size 1450 --controller-address {{ controller_ip }}
+  when: result.stat.exists == False
+
+- name: record task completed
+  shell: echo "done" > /tmp/init_completed
+
+- name: restart vta
+  shell: reboot
+  when: result.stat.exists == False
+
diff --git a/xos/synchronizer/steps/sync_activetesttenant.py b/xos/synchronizer/steps/sync_activetesttenant.py
new file mode 100644
index 0000000..e97fbda
--- /dev/null
+++ b/xos/synchronizer/steps/sync_activetesttenant.py
@@ -0,0 +1,52 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.activetest.models import ActiveTestService, ActiveTestTenant
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncActiveTestTenant(SyncInstanceUsingAnsible):
+
+    provides = [ActiveTestTenant]
+
+    observes = ActiveTestTenant
+
+    requested_interval = 0
+
+    template_name = "activetesttenant_playbook.yaml"
+
+    service_key_name = "/opt/xos/synchronizers/activetest/activetest_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncActiveTestTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = ActiveTestTenant.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+            # If this is a deletion we get all of the deleted tenants..
+            objs = ActiveTestTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    def get_activetestservice(self, o):
+        if not o.provider_service:
+            return None
+
+        activetestservice = ActiveTestService.get_service_objects().filter(id=o.provider_service.id)
+
+        if not activetestservice:
+            return None
+
+        return activetestservice[0]
+
+    # Gets the attributes that are used by the Ansible template but are not
+    # part of the set of default attributes.
+    def get_extra_attributes(self, o):
+        return { "public_ip": o.public_ip }
+
+
diff --git a/xos/synchronizer/steps/sync_qt600tenant.py b/xos/synchronizer/steps/sync_qt600tenant.py
new file mode 100644
index 0000000..216cb13
--- /dev/null
+++ b/xos/synchronizer/steps/sync_qt600tenant.py
@@ -0,0 +1,48 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.activetest.models import Qt600Tenant
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncQt600Tenant(SyncInstanceUsingAnsible):
+
+    provides = [Qt600Tenant]
+
+    observes = Qt600Tenant
+
+    requested_interval = 0
+
+    template_name = "qt600tenant_playbook.yaml"
+
+    service_key_name = "/opt/xos/synchronizers/activetest/activetest_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncQt600Tenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = Qt600Tenant.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+            # If this is a deletion we get all of the deleted tenants..
+            objs = Qt600Tenant.get_deleted_tenant_objects()
+
+        return objs
+
+    # Gets the attributes that are used by the Ansible template but are not
+    # part of the set of default attributes.
+    def get_extra_attributes(self, o):
+        return { "private_ip":o.private_ip,
+                 "public_ip":o.public_ip,
+                 "controller_ip":o.controller_ip,
+                 "reflector_ip":o.reflector_ip,
+                 "reflector_public_ip":o.reflector_public_ip,
+                 "is_reflector":o.is_reflector,
+                 "is_initiator":o.is_initiator
+             }
+
+
diff --git a/xos/synchronizer/steps/sync_vpmatenant.py b/xos/synchronizer/steps/sync_vpmatenant.py
new file mode 100644
index 0000000..52b5e32
--- /dev/null
+++ b/xos/synchronizer/steps/sync_vpmatenant.py
@@ -0,0 +1,48 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.activetest.models import VpmaTenant
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVpmaTenant(SyncInstanceUsingAnsible):
+
+    provides = [VpmaTenant]
+
+    observes = VpmaTenant
+
+    requested_interval = 0
+
+    template_name = "vpmatenant_playbook.yaml"
+
+    service_key_name = "/opt/xos/synchronizers/activetest/activetest_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVpmaTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = VpmaTenant.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+            # If this is a deletion we get all of the deleted tenants..
+            objs = VpmaTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    # Gets the attributes that are used by the Ansible template but are not
+    # part of the set of default attributes.
+    def get_extra_attributes(self, o):
+        return { "private_ip":o.private_ip,
+                 "public_ip":o.public_ip,
+                 "controller_ip":o.controller_ip,
+                 "reflector_ip":o.reflector_ip,
+                 "reflector_public_ip":o.reflector_public_ip,
+                 "is_reflector":o.is_reflector,
+                 "is_initiator":o.is_initiator
+             }
+
+
diff --git a/xos/synchronizer/steps/sync_vtatenant.py b/xos/synchronizer/steps/sync_vtatenant.py
new file mode 100644
index 0000000..1406e4b
--- /dev/null
+++ b/xos/synchronizer/steps/sync_vtatenant.py
@@ -0,0 +1,44 @@
+import os
+import sys
+from django.db.models import Q, F
+from services.activetest.models import VtaTenant
+from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
+
+parentdir = os.path.join(os.path.dirname(__file__), "..")
+sys.path.insert(0, parentdir)
+
+class SyncVtaTenant(SyncInstanceUsingAnsible):
+
+    provides = [VtaTenant]
+
+    observes = VtaTenant
+
+    requested_interval = 0
+
+    template_name = "vtatenant_playbook.yaml"
+
+    service_key_name = "/opt/xos/synchronizers/activetest/activetest_private_key"
+
+    def __init__(self, *args, **kwargs):
+        super(SyncVtaTenant, self).__init__(*args, **kwargs)
+
+    def fetch_pending(self, deleted):
+
+        if (not deleted):
+            objs = VtaTenant.get_tenant_objects().filter(
+                Q(enacted__lt=F('updated')) | Q(enacted=None), Q(lazy_blocked=False))
+        else:
+            # If this is a deletion we get all of the deleted tenants..
+            objs = VtaTenant.get_deleted_tenant_objects()
+
+        return objs
+
+    # Gets the attributes that are used by the Ansible template but are not
+    # part of the set of default attributes.
+    def get_extra_attributes(self, o):
+        return { "private_ip":o.private_ip,
+                 "public_ip":o.public_ip,
+                 "controller_ip":o.controller_ip
+             }
+
+
diff --git a/xos/synchronizer/steps/vpmatenant_playbook.yaml b/xos/synchronizer/steps/vpmatenant_playbook.yaml
new file mode 100644
index 0000000..26a12a1
--- /dev/null
+++ b/xos/synchronizer/steps/vpmatenant_playbook.yaml
@@ -0,0 +1,20 @@
+---
+# activetesttenant_playbook - sets up the controller
+
+- hosts: "{{ instance_name }}"
+  connection: ssh
+  user: root
+  sudo: no
+  gather_facts: no
+  vars:
+    - private_ip: "{{ private_ip }}"
+    - public_ip: "{{ public_ip }}"
+    - controller_ip: "{{ controller_ip }}"
+    - reflector_ip: "{{ reflector_ip }}"
+    - reflector_public_ip: "{{ reflector_public_ip }}"
+    - is_initiator: {{ is_initiator }}
+    - is_reflector: {{ is_reflector }}
+
+  roles:
+    - setup_ma
+    - setup_vpma
diff --git a/xos/synchronizer/steps/vtatenant_playbook.yaml b/xos/synchronizer/steps/vtatenant_playbook.yaml
new file mode 100644
index 0000000..fa036fb
--- /dev/null
+++ b/xos/synchronizer/steps/vtatenant_playbook.yaml
@@ -0,0 +1,16 @@
+---
+# activetesttenant_playbook - sets up the controller
+
+- hosts: "{{ instance_name }}"
+  connection: ssh
+  user: root
+  sudo: no
+  gather_facts: no
+  vars:
+    - private_ip: "{{ private_ip }}"
+    - public_ip: "{{ public_ip }}"
+    - controller_ip: "{{ controller_ip }}"
+
+  roles:
+    - setup_ma
+    - setup_vta