import hashlib
import os
import socket
import sys
import base64
import time
import json
#import threading
import subprocess
import random
import tempfile
#from sshtunnel import SSHTunnelForwarder
from django.db.models import F, Q
from xos.config import Config
from synchronizers.base.syncstep import SyncStep
from synchronizers.base.ansible_helper import run_template
from synchronizers.base.ansible_helper import run_template_ssh
from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
from core.models import Service, Slice
from services.monitoring.models import CeilometerService, OpenStackServiceMonitoringPublisher
from xos.logger import Logger, logging

parentdir = os.path.join(os.path.dirname(__file__),"..")
sys.path.insert(0,parentdir)

logger = Logger(level=logging.INFO)

class SyncOpenStackMonitoringPublisher(SyncInstanceUsingAnsible):
    provides=[OpenStackServiceMonitoringPublisher]
    observes=OpenStackServiceMonitoringPublisher
    requested_interval=0
    template_name = "sync_openstackmonitoringpublisher.yaml"

    def __init__(self, *args, **kwargs):
        super(SyncOpenStackMonitoringPublisher, self).__init__(*args, **kwargs)

    def fetch_pending(self, deleted):
        if (not deleted):
            objs = OpenStackServiceMonitoringPublisher.get_tenant_objects().filter(Q(enacted__lt=F('updated')) | Q(enacted=None),Q(lazy_blocked=False))
        else:
            objs = OpenStackServiceMonitoringPublisher.get_deleted_tenant_objects()

        return objs

    def sync_record(self, o):
        logger.info("sync'ing object %s" % str(o),extra=o.tologdict())

        self.prepare_record(o)

        ceilometer_services = CeilometerService.get_service_objects().filter(id=o.provider_service.id)
        if not ceilometer_services:
            raise "No associated Ceilometer service"
        ceilometer_service = ceilometer_services[0]
        service_instance = ceilometer_service.get_instance()
        # sync only when the corresponding service instance is fully synced
        if not service_instance:
            self.defer_sync(o, "waiting on associated service instance")
            return
        if not service_instance.instance_name:
            self.defer_sync(o, "waiting on associated service instance.instance_name")
            return

        # Step1: Orchestrate UDP proxy agent on the compute node where monitoring service VM is spawned

        fields = { "hostname": ceilometer_service.ceilometer_rabbit_compute_node,
                   "baremetal_ssh": True,
                   "instance_name": "rootcontext",
                   "username": "root",
                   "container_name": None,
                   "rabbit_host": ceilometer_service.ceilometer_rabbit_host,
                   "rabbit_user": ceilometer_service.ceilometer_rabbit_user,
                   "rabbit_password": ceilometer_service.ceilometer_rabbit_password,
		   "listen_ip_addr": socket.gethostbyname(ceilometer_service.ceilometer_rabbit_compute_node)
	}

        # If 'o' defines a 'sync_attributes' list, then we'll copy those
        # attributes into the Ansible recipe's field list automatically.
        if hasattr(o, "sync_attributes"):
            for attribute_name in o.sync_attributes:
                fields[attribute_name] = getattr(o, attribute_name)

        key_name = self.get_node_key(service_instance.node)
        if not os.path.exists(key_name):
            raise Exception("Node key %s does not exist" % key_name)
        key = file(key_name).read()
        fields["private_key"] = key

        template_name = "sync_openstackmonitoringpublisher.yaml"
        fields["ansible_tag"] =  o.__class__.__name__ + "_" + str(o.id) + "_step1"

        self.run_playbook(o, fields, template_name)

        # Step2: Orchestrate OpenStack publish agent
        target_uri = "udp://" + ceilometer_service.ceilometer_rabbit_compute_node + ":4455"
        fields = {}
        agent_info = []
        if o.monitoring_agents:
           for agent in o.monitoring_agents.all():
              body = {'target': target_uri}
              if agent.start_url_json_data:
                 start_url_dict = json.loads(agent.start_url_json_data)
                 body.update(start_url_dict)
              a = {'url': agent.start_url, 'body': json.dumps(body)}
              agent_info.append(a)

        fields["agents"] = agent_info 
        #fields["private_key"] = ""

        template_name = "enable_monitoring_service.yaml"
        fields["ansible_tag"] =  o.__class__.__name__ + "_" + str(o.id) + "_step2"

        run_template(template_name, fields)

    def map_delete_inputs(self, o):
        fields = {"unique_id": o.id,
                  "delete": True}
        return fields

    def delete_record(self, o):
        pass

