Ejemplo n.º 1
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    services_topic_list = config.get('services_topic_list', [
        topics.DRIVER_TOPIC_BASE, topics.LOGGER_BASE, topics.ACTUATOR,
        topics.ANALYSIS_TOPIC_BASE
    ])
    custom_topic_list = config.get('custom_topic_list', [])
    topic_replace_list = config.get('topic_replace_list', [])
    destination_vip = config.get('destination-vip')
    destination_historian_identity = config.get(
        'destination-historian-identity', 'platform.historian')
    backup_storage_limit_gb = config.get('backup_storage_limit_gb', None)

    gather_timing_data = config.get('gather_timing_data', False)

    hosts = KnownHostsStore()
    destination_serverkey = hosts.serverkey(destination_vip)
    if destination_serverkey is None:
        _log.info(
            "Destination serverkey not found in known hosts file, using config"
        )
        destination_serverkey = config['destination-serverkey']

    return DataMover(services_topic_list,
                     custom_topic_list,
                     topic_replace_list,
                     destination_vip,
                     destination_serverkey,
                     destination_historian_identity,
                     gather_timing_data,
                     backup_storage_limit_gb=backup_storage_limit_gb,
                     **kwargs)
Ejemplo n.º 2
0
def forwarder(request, volttron_instances):
    #print "Fixture forwarder"
    global volttron_instance1, volttron_instance2

    global forwarder_uuid, forwarder_config
    # 1. Update destination address in forwarder configuration

    volttron_instance1.allow_all_connections()
    volttron_instance2.allow_all_connections()

    # setup destination address to include keys
    known_hosts_file = os.path.join(volttron_instance1.volttron_home, 'known_hosts')
    known_hosts = KnownHostsStore(known_hosts_file)
    known_hosts.add(volttron_instance2.vip_address, volttron_instance2.serverkey)

    forwarder_config["destination-vip"] = volttron_instance2.vip_address
    forwarder_config["destination-serverkey"] = volttron_instance2.serverkey

    # 1: Install historian agent
    # Install and start sqlhistorian agent in instance2
    forwarder_uuid = volttron_instance1.install_agent(
        agent_dir=get_services_core("ForwardHistorian"),
        config_file=forwarder_config,
        start=True)
    print("forwarder agent id: ", forwarder_uuid)
Ejemplo n.º 3
0
def forwarder(request, volttron_instances):
    global volttron_instance1, volttron_instance2
    global datamover_uuid, datamover_config
    # 1. Update destination address in forwarder configuration

    volttron_instance1.allow_all_connections()
    volttron_instance2.allow_all_connections()

    datamover_config["destination-vip"] = volttron_instance2.vip_address

    known_hosts_file = os.path.join(volttron_instance1.volttron_home,
                                    'known_hosts')
    known_hosts = KnownHostsStore(known_hosts_file)
    known_hosts.add(volttron_instance2.vip_address,
                    volttron_instance2.serverkey)

    # setup destination address to include keys
    datamover_config["destination-serverkey"] = volttron_instance2.serverkey

    # 1: Install historian agent
    # Install and start sqlhistorian agent in instance2
    datamover_uuid = volttron_instance1.install_agent(
        agent_dir=get_services_core("DataMover"),
        config_file=datamover_config,
        start=True)
    print("forwarder agent id: ", datamover_uuid)
Ejemplo n.º 4
0
def forwarder(request, volttron_instances):
    #print "Fixture forwarder"
    global volttron_instance1, volttron_instance2

    global forwarder_uuid, forwarder_config
    # 1. Update destination address in forwarder configuration

    volttron_instance1.allow_all_connections()
    volttron_instance2.allow_all_connections()

    # setup destination address to include keys
    known_hosts_file = os.path.join(volttron_instance1.volttron_home,
                                    'known_hosts')
    known_hosts = KnownHostsStore(known_hosts_file)
    known_hosts.add(volttron_instance2.vip_address,
                    volttron_instance2.serverkey)

    forwarder_config["destination-vip"] = volttron_instance2.vip_address
    forwarder_config["destination-serverkey"] = volttron_instance2.serverkey

    # 1: Install historian agent
    # Install and start sqlhistorian agent in instance2
    forwarder_uuid = volttron_instance1.install_agent(
        agent_dir="services/core/ForwardHistorian",
        config_file=forwarder_config,
        start=True)
    print("forwarder agent id: ", forwarder_uuid)
Ejemplo n.º 5
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    services_topic_list = config.get('services_topic_list', [
        topics.DRIVER_TOPIC_BASE,
        topics.LOGGER_BASE,
        topics.ACTUATOR,
        topics.ANALYSIS_TOPIC_BASE
    ])
    custom_topic_list = config.get('custom_topic_list', [])
    topic_replace_list = config.get('topic_replace_list', [])
    destination_vip = config.get('destination-vip')
    destination_historian_identity = config.get('destination-historian-identity',
                                                'platform.historian')
    backup_storage_limit_gb = config.get('backup_storage_limit_gb', None)

    gather_timing_data = config.get('gather_timing_data', False)

    hosts = KnownHostsStore()
    destination_serverkey = hosts.serverkey(destination_vip)
    if destination_serverkey is None:
        _log.info("Destination serverkey not found in known hosts file, using config")
        destination_serverkey = config['destination-serverkey']

    return DataMover(services_topic_list,
                     custom_topic_list,
                     topic_replace_list,
                     destination_vip,
                     destination_serverkey,
                     destination_historian_identity,
                     gather_timing_data,
                     backup_storage_limit_gb=backup_storage_limit_gb,
                     **kwargs)
Ejemplo n.º 6
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    custom_topic_list = config.pop('custom_topic_list', [])
    topic_replace_list = config.pop('topic_replace_list', [])
    destination_vip = config.pop('destination-vip', None)
    service_topic_list = config.pop('service_topic_list', None)
    destination_serverkey = None
    try:
        destination_address = config.pop('destination-address')
    except KeyError:
        destination_address = None
    if service_topic_list is not None:
        w = "Deprecated service_topic_list.  Use capture_device_data " \
            "capture_log_data, capture_analysis_data or capture_record_data " \
            "instead!"
        _log.warning(w)

        # Populate the new values for the kwargs based upon the old data.
        kwargs['capture_device_data'] = True if (
            "device" in service_topic_list
            or "all" in service_topic_list) else False
        kwargs['capture_log_data'] = True if (
            "datalogger" in service_topic_list
            or "all" in service_topic_list) else False
        kwargs['capture_record_data'] = True if (
            "record" in service_topic_list
            or "all" in service_topic_list) else False
        kwargs['capture_analysis_data'] = True if (
            "analysis" in service_topic_list
            or "all" in service_topic_list) else False

    if destination_vip:
        hosts = KnownHostsStore()
        destination_serverkey = hosts.serverkey(destination_vip)
        if destination_serverkey is None:
            _log.info(
                "Destination serverkey not found in known hosts file, using config"
            )
            destination_serverkey = config.pop('destination-serverkey')
        else:
            config.pop('destination-serverkey', None)

        destination_messagebus = 'zmq'

    required_target_agents = config.pop('required_target_agents', [])
    cache_only = config.pop('cache_only', False)

    utils.update_kwargs_with_config(kwargs, config)

    return ForwardHistorian(destination_vip,
                            destination_serverkey,
                            custom_topic_list=custom_topic_list,
                            topic_replace_list=topic_replace_list,
                            required_target_agents=required_target_agents,
                            cache_only=cache_only,
                            destination_address=destination_address,
                            **kwargs)
Ejemplo n.º 7
0
def get_keys():
    """Gets keys from keystore and known-hosts store

    :returns: Keys for connecting to the platform
    :rtype: dict
    """
    hosts = KnownHostsStore()
    serverkey = hosts.serverkey(get_address())
    key_store = KeyStore()
    publickey = key_store.public
    secretkey = key_store.secret
    return {'publickey': publickey,
            'secretkey': secretkey,
            'serverkey': serverkey}
Ejemplo n.º 8
0
def get_keys():
    """Gets keys from keystore and known-hosts store

    :returns: Keys for connecting to the platform
    :rtype: dict
    """
    hosts = KnownHostsStore()
    serverkey = hosts.serverkey(get_address())
    key_store = KeyStore()
    publickey = key_store.public
    secretkey = key_store.secret
    return {'publickey': publickey,
            'secretkey': secretkey,
            'serverkey': serverkey}
Ejemplo n.º 9
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    destination_vip = config.get('destination-vip', None)
    assert destination_vip is not None

    hosts = KnownHostsStore()
    destination_serverkey = hosts.serverkey(destination_vip)
    if destination_serverkey is not None:
        config['destination-serverkey'] = destination_serverkey
    else:
        assert config.get('destination-serverkey') is not None
        _log.info("Destination serverkey not found in known hosts file, using config")

    utils.update_kwargs_with_config(kwargs, config)
    return DataMover(**kwargs)
Ejemplo n.º 10
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    destination_vip = config.get('destination-vip', None)
    assert destination_vip is not None

    hosts = KnownHostsStore()
    serverkey = hosts.serverkey(destination_vip)
    if serverkey is not None:
        config['destination-serverkey'] = serverkey
    else:
        assert config.get('destination-serverkey') is not None
        _log.info("Destination serverkey not found in known hosts file, "
                  "using config")

    utils.update_kwargs_with_config(kwargs, config)
    return DataMover(**kwargs)
Ejemplo n.º 11
0
    def __init__(self, config_path, **kwargs):
        super(FailoverAgent, self).__init__(**kwargs)
        config = utils.load_config(config_path)

        # Get agent and remote ids
        agent_id = config["agent_id"]
        if agent_id == "primary":
            self.agent_id = "primary"
            self.remote_id = "secondary"
        elif agent_id == "secondary":
            self.agent_id = "secondary"
            self.remote_id = "primary"
        else:
            _log.error("agent_id must be either 'primary' or 'secondary'")

        # Modify ids if we're using the simple option
        # Defaults to true pending vc coordination
        use_simple = config.get("simple_behavior", True)
        if use_simple:
            self.agent_id = "simple_" + self.agent_id
            self.remote_id = "simple_" + self.remote_id

        self.remote_vip = config["remote_vip"]

        hosts = KnownHostsStore()
        self.remote_serverkey = hosts.serverkey(self.remote_vip)
        if self.remote_serverkey is None:
            self.remote_serverkey = config["remote_serverkey"]

        self.agent_vip_identity = config["agent_vip_identity"]
        self.heartbeat_period = config["heartbeat_period"]
        self.timeout = config["timeout"]

        self.vc_timeout = self.timeout
        self.remote_timeout = self.timeout
        self.agent_uuid = None
        self.heartbeat = None
        self.last_connected = None

        self._state = True, True
        self._state_machine = getattr(self, self.agent_id + '_state_machine')
Ejemplo n.º 12
0
    def __init__(self, config_path, **kwargs):
        super(FailoverAgent, self).__init__(**kwargs)
        config = utils.load_config(config_path)

        # Get agent and remote ids
        agent_id = config["agent_id"]
        if agent_id == "primary":
            self.agent_id = "primary"
            self.remote_id = "secondary"
        elif agent_id == "secondary":
            self.agent_id = "secondary"
            self.remote_id = "primary"
        else:
            _log.error("agent_id must be either 'primary' or 'secondary'")

        # Modify ids if we're using the simple option
        # Defaults to true pending vc coordination
        use_simple = config.get("simple_behavior", True)
        if use_simple:
            self.agent_id = "simple_" + self.agent_id
            self.remote_id = "simple_" + self.remote_id

        self.remote_vip = config["remote_vip"]

        hosts = KnownHostsStore()
        self.remote_serverkey = hosts.serverkey(self.remote_vip)
        if self.remote_serverkey is None:
            self.remote_serverkey = config["remote_serverkey"]

        self.agent_vip_identity = config["agent_vip_identity"]
        self.heartbeat_period = config["heartbeat_period"]
        self.timeout = config["timeout"]

        self.vc_timeout = self.timeout
        self.remote_timeout = self.timeout
        self.agent_uuid = None
        self.heartbeat = None
        self.last_connected = None

        self._state = True, True
        self._state_machine = getattr(self, self.agent_id + '_state_machine')
Ejemplo n.º 13
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    custom_topic_list = config.pop('custom_topic_list', [])
    topic_replace_list = config.pop('topic_replace_list', [])
    destination_vip = config.pop('destination-vip', None)

    service_topic_list = config.pop('service_topic_list', None)
    if service_topic_list is not None:
        w = "Deprecated service_topic_list.  Use capture_device_data " \
            "capture_log_data, capture_analysis_data or capture_record_data " \
            "instead!"
        _log.warning(w)

        # Populate the new values for the kwargs based upon the old data.
        kwargs['capture_device_data'] = True if ("device" in service_topic_list or "all" in service_topic_list) else False
        kwargs['capture_log_data'] = True if ("datalogger" in service_topic_list or "all" in service_topic_list) else False
        kwargs['capture_record_data'] = True if ("record" in service_topic_list or "all" in service_topic_list) else False
        kwargs['capture_analysis_data'] = True if ("analysis" in service_topic_list or "all" in service_topic_list) else False

    hosts = KnownHostsStore()
    destination_serverkey = hosts.serverkey(destination_vip)
    if destination_serverkey is None:
        _log.info("Destination serverkey not found in known hosts file, using config")
        destination_serverkey = config.pop('destination-serverkey')
    else:
        config.pop('destination-serverkey', None)

    required_target_agents = config.pop('required_target_agents', [])
    cache_only = config.pop('cache_only', False)

    utils.update_kwargs_with_config(kwargs, config)

    return ForwardHistorian(destination_vip, destination_serverkey,
                            custom_topic_list=custom_topic_list,
                            topic_replace_list=topic_replace_list,
                            required_target_agents=required_target_agents,
                            cache_only=cache_only,
                            **kwargs)
Ejemplo n.º 14
0
    def connect_remote_platform(
            self,
            address,
            serverkey=None,
            agent_class=None
    ):
        """
        Agent attempts to connect to a remote platform to exchange data.

        address must start with http, https, tcp, ampq, or ampqs or a
        ValueError will be
        raised

        If this function is successful it will return an instance of the
        `agent_class`
        parameter if not then this function will return None.

        If the address parameter begins with http or https
        TODO: use the known host functionality here
        the agent will attempt to use Discovery to find the values
        associated with it.

        Discovery should return either an rmq-address or a vip-address or
        both.  In
        that situation the connection will be made using zmq.  In the event
        that
        fails then rmq will be tried.  If both fail then None is returned
        from this
        function.

        """
        from volttron.platform.vip.agent.utils import build_agent
        from volttron.platform.vip.agent import Agent

        if agent_class is None:
            agent_class = Agent

        parsed_address = urlparse(address)
        _log.debug("Begining auth.connect_remote_platform: {}".format(address))

        value = None
        if parsed_address.scheme == "tcp":
            # ZMQ connection
            hosts = KnownHostsStore()
            temp_serverkey = hosts.serverkey(address)
            if not temp_serverkey:
                _log.info(
                    "Destination serverkey not found in known hosts file, "
                    "using config"
                )
                destination_serverkey = serverkey
            elif not serverkey:
                destination_serverkey = temp_serverkey
            else:
                if temp_serverkey != serverkey:
                    raise ValueError(
                        "server_key passed and known hosts serverkey do not "
                        ""
                        "match!"
                    )
                destination_serverkey = serverkey

            publickey, secretkey = (
                self._core().publickey,
                self._core().secretkey,
            )
            _log.debug(
                "Connecting using: %s", get_fq_identity(self._core().identity)
            )

            value = build_agent(
                agent_class=agent_class,
                identity=get_fq_identity(self._core().identity),
                serverkey=destination_serverkey,
                publickey=publickey,
                secretkey=secretkey,
                message_bus="zmq",
                address=address,
            )
        elif parsed_address.scheme in ("https", "http"):
            from volttron.platform.web import DiscoveryInfo
            from volttron.platform.web import DiscoveryError

            try:
                # TODO: Use known host instead of looking up for discovery
                #  info if possible.

                # We need to discover which type of bus is at the other end.
                info = DiscoveryInfo.request_discovery_info(address)
                remote_identity = "{}.{}.{}".format(
                    info.instance_name,
                    get_platform_instance_name(),
                    self._core().identity,
                )
                # if the current message bus is zmq then we need
                # to connect a zmq on the remote, whether that be the
                # rmq router or proxy.  Also note that we are using the
                # fully qualified
                # version of the identity because there will be conflicts if
                # volttron central has more than one platform.agent connecting
                if get_messagebus() == "zmq":
                    if not info.vip_address or not info.serverkey:
                        err = (
                            "Discovery from {} did not return serverkey "
                            "and/or vip_address".format(address)
                        )
                        raise ValueError(err)

                    _log.debug(
                        "Connecting using: %s",
                        get_fq_identity(self._core().identity),
                    )

                    # use fully qualified identity
                    value = build_agent(
                        identity=get_fq_identity(self._core().identity),
                        address=info.vip_address,
                        serverkey=info.serverkey,
                        secretkey=self._core().secretkey,
                        publickey=self._core().publickey,
                        agent_class=agent_class,
                    )

                else:  # we are on rmq messagebus

                    # This is if both remote and local are rmq message buses.
                    if info.messagebus_type == "rmq":
                        _log.debug("Both remote and local are rmq messagebus.")
                        fqid_local = get_fq_identity(self._core().identity)

                        # Check if we already have the cert, if so use it
                        # instead of requesting cert again
                        remote_certs_dir = self.get_remote_certs_dir()
                        remote_cert_name = "{}.{}".format(
                            info.instance_name, fqid_local
                        )
                        certfile = os.path.join(
                            remote_certs_dir, remote_cert_name + ".crt"
                        )
                        if os.path.exists(certfile):
                            response = certfile
                        else:
                            response = self.request_cert(
                                address, fqid_local, info
                            )

                        if response is None:
                            _log.error("there was no response from the server")
                            value = None
                        elif isinstance(response, tuple):
                            if response[0] == "PENDING":
                                _log.info(
                                    "Waiting for administrator to accept a "
                                    "CSR request."
                                )
                            value = None
                        # elif isinstance(response, dict):
                        #     response
                        elif os.path.exists(response):
                            # info = DiscoveryInfo.request_discovery_info(
                            # address)
                            # From the remote platforms perspective the
                            # remote user name is
                            #   remoteinstance.localinstance.identity,
                            #   this is what we must
                            #   pass to the build_remote_connection_params
                            #   for a successful

                            remote_rmq_user = get_fq_identity(
                                fqid_local, info.instance_name
                            )
                            _log.debug(
                                "REMOTE RMQ USER IS: %s", remote_rmq_user
                            )
                            remote_rmq_address = self._core().rmq_mgmt.build_remote_connection_param(
                                remote_rmq_user,
                                info.rmq_address,
                                ssl_auth=True,
                                cert_dir=self.get_remote_certs_dir(),
                            )

                            value = build_agent(
                                identity=fqid_local,
                                address=remote_rmq_address,
                                instance_name=info.instance_name,
                                publickey=self._core().publickey,
                                secretkey=self._core().secretkey,
                                message_bus="rmq",
                                enable_store=False,
                                agent_class=agent_class,
                            )
                        else:
                            raise ValueError(
                                "Unknown path through discovery process!"
                            )

                    else:
                        # TODO: cache the connection so we don't always have
                        #  to ping the server to connect.

                        # This branch happens when the message bus is not
                        # the same note
                        # this writes to the agent-data directory of this
                        # agent if the agent
                        # is installed.
                        if get_messagebus() == "rmq":
                            if not os.path.exists("keystore.json"):
                                with open("keystore.json", "w") as file_pointer:
                                    file_pointer.write(
                                        jsonapi.dumps(
                                            KeyStore.generate_keypair_dict()
                                        )
                                    )

                            with open("keystore.json") as file_pointer:
                                keypair = jsonapi.loads(file_pointer.read())

                        value = build_agent(
                            agent_class=agent_class,
                            identity=remote_identity,
                            serverkey=info.serverkey,
                            publickey=keypair.get("publickey"),
                            secretkey=keypair.get("secretekey"),
                            message_bus="zmq",
                            address=info.vip_address,
                        )
            except DiscoveryError:
                _log.error(
                    "Couldn't connect to %s or incorrect response returned "
                    "response was %s",
                    address,
                    value,
                )

        else:
            raise ValueError(
                "Invalid configuration found the address: {} has an invalid "
                "scheme".format(address)
            )

        return value
Ejemplo n.º 15
0
import logging
import os

import gevent

from volttron.platform import get_address
from volttron.platform.agent import utils
from volttron.platform.keystore import KeyStore, KnownHostsStore
from volttron.platform.vip.agent import Agent
from volttron.platform.vip.agent.connection import Connection

utils.setup_logging()
_log = logging.getLogger(__name__)

host_store = KnownHostsStore()


def get_known_host_serverkey(vip_address):
    return host_store.serverkey(vip_address)


def get_server_keys():
    try:
        # attempt to read server's keys. Should be used only by multiplatform connection and tests
        # If agents such as forwarder attempt this in secure mode this will throw access violation exception
        ks = KeyStore()
    except IOError as e:
        raise RuntimeError(
            "Exception accessing server keystore. Agents must use agent's public and private key"
            "to build dynamic agents when running in secure mode. Exception:{}"
Ejemplo n.º 16
0
    def startup_platform(self, vip_address, auth_dict=None, use_twistd=False,
                         mode=UNRESTRICTED, bind_web_address=None,
                         volttron_central_address=None,
                         volttron_central_serverkey=None):

        # if not isinstance(vip_address, list):
        #     self.vip_address = [vip_address]
        # else:
        #     self.vip_address = vip_address

        self.vip_address = vip_address
        self.mode = mode
        self.bind_web_address = bind_web_address
        if self.bind_web_address:
            self.discovery_address = "{}/discovery/".format(
                self.bind_web_address)

            # Only available if vc is installed!
            self.jsonrpc_endpoint = "{}/jsonrpc".format(
                self.bind_web_address)

        enable_logging = self.env.get('ENABLE_LOGGING', False)
        debug_mode = self.env.get('DEBUG_MODE', False)
        if not debug_mode:
            debug_mode = self.env.get('DEBUG', False)
        self.skip_cleanup = self.env.get('SKIP_CLEANUP', False)
        if debug_mode:
            self.skip_cleanup = True
            enable_logging = True
        self.logit(
            "In start up platform enable_logging is {} ".format(enable_logging))
        assert self.mode in MODES, 'Invalid platform mode set: ' + str(mode)
        opts = None

        # see main.py for how we handle pub sub addresses.
        ipc = 'ipc://{}{}/run/'.format(
            '@' if sys.platform.startswith('linux') else '',
            self.volttron_home)
        self.local_vip_address = ipc + 'vip.socket'
        self.set_auth_dict(auth_dict)

        self.opts = {'verify_agents': False,
                     'volttron_home': self.volttron_home,
                     'vip_address': vip_address,
                     'vip_local_address': ipc + 'vip.socket',
                     'publish_address': ipc + 'publish',
                     'subscribe_address': ipc + 'subscribe',
                     'bind_web_address': bind_web_address,
                     'volttron_central_address': volttron_central_address,
                     'volttron_central_serverkey': volttron_central_serverkey,
                     'platform_name': None,
                     'log': os.path.join(self.volttron_home, 'volttron.log'),
                     'log_config': None,
                     'monitor': True,
                     'autostart': True,
                     'log_level': logging.DEBUG,
                     'verboseness': logging.DEBUG}

        pconfig = os.path.join(self.volttron_home, 'config')
        config = {}

        # Add platform's public key to known hosts file
        publickey = self.keystore.public
        known_hosts_file = os.path.join(self.volttron_home, 'known_hosts')
        known_hosts = KnownHostsStore(known_hosts_file)
        known_hosts.add(self.opts['vip_local_address'], publickey)
        known_hosts.add(self.opts['vip_address'], publickey)

        # Set up the configuration file based upon the passed parameters.
        parser = configparser.ConfigParser()
        parser.add_section('volttron')
        parser.set('volttron', 'vip-address', vip_address)
        if bind_web_address:
            parser.set('volttron', 'bind-web-address', bind_web_address)
        if volttron_central_address:
            parser.set('volttron', 'volttron-central-address',
                       volttron_central_address)
        if volttron_central_serverkey:
            parser.set('volttron', 'volttron-central-serverkey',
                       volttron_central_serverkey)
        if self.mode == UNRESTRICTED:
            # TODO Restricted code should set with volttron as contianer
            # if RESTRICTED_AVAILABLE:
            #     config['mobility'] = False
            #     config['resource-monitor'] = False
            #     config['verify'] = False
            with closing(open(pconfig, 'wb')) as cfg:
                cfg.write(PLATFORM_CONFIG_UNRESTRICTED.format(**config))
                parser.write(cfg)

        elif self.mode == RESTRICTED:
            if not RESTRICTED_AVAILABLE:
                raise ValueError("restricted is not available.")

            certsdir = os.path.join(self.volttron_home, 'certificates')

            print ("certsdir", certsdir)
            self.certsobj = certs.Certs(certsdir)

            with closing(open(pconfig, 'wb')) as cfg:
                cfg.write(PLATFORM_CONFIG_RESTRICTED.format(**config))
        else:
            raise PlatformWrapperError(
                "Invalid platform mode specified: {}".format(mode))

        log = os.path.join(self.volttron_home, 'volttron.log')
        if enable_logging:
            cmd = ['volttron', '-vv', '-l{}'.format(log)]
        else:
            cmd = ['volttron', '-l{}'.format(log)]

        print('process environment: {}'.format(self.env))
        print('popen params: {}'.format(cmd))
        self.p_process = Popen(cmd, env=self.env, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)

        assert self.p_process is not None
        # A None value means that the process is still running.
        # A negative means that the process exited with an error.
        assert self.p_process.poll() is None

        self.serverkey = self.keystore.public
        assert self.serverkey
        agent = self.build_agent()

        has_control = False
        times = 0
        while not has_control and times < 10:
            times += 1
            try:
                has_control = agent.vip.peerlist().get(timeout=.2)
            except gevent.Timeout:
                pass

        if not has_control:
            self.shutdown_platform()
            raise "Couldn't connect to core platform!"

        if bind_web_address:
            times = 0
            has_discovery = False
            while times < 10:
                times += 1
                try:
                    resp = requests.get(self.discovery_address)
                    if resp.ok:
                        has_discovery = True
                        break
                except Exception as e:
                    gevent.sleep(0.1)
                    self.logit("Connection error found {}".format(e))
            if not has_discovery:
                raise "Couldn't connect to discovery platform."

        self.use_twistd = use_twistd

        # TODO: Revise this to start twistd with platform.
        if self.use_twistd:
            tconfig = os.path.join(self.volttron_home, TMP_SMAP_CONFIG_FILENAME)

            with closing(open(tconfig, 'w')) as cfg:
                cfg.write(TWISTED_CONFIG.format(**config))

            tparams = [TWISTED_START, "-n", "smap", tconfig]
            self.t_process = subprocess.Popen(tparams, env=self.env)
            time.sleep(5)
Ejemplo n.º 17
0
 def _get_serverkey_from_known_hosts(self):
     known_hosts_file = os.path.join(self.volttron_home, 'known_hosts')
     known_hosts = KnownHostsStore(known_hosts_file)
     return known_hosts.serverkey(self.address)
Ejemplo n.º 18
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    services_topic_list = config.get('services_topic_list', ['all'])
    custom_topic_list = config.get('custom_topic_list', [])
    topic_replace_list = config.get('topic_replace_list', [])
    destination_vip = config.get('destination-vip')

    gather_timing_data = config.get('gather_timing_data', False)

    hosts = KnownHostsStore()
    destination_serverkey = hosts.serverkey(destination_vip)
    if destination_serverkey is None:
        _log.info("Destination serverkey not found in known hosts file, using config")
        destination_serverkey = config['destination-serverkey']

    required_target_agents = config.get('required_target_agents', [])
    backup_storage_limit_gb = config.get('backup_storage_limit_gb', None)
    if 'all' in services_topic_list:
        services_topic_list = [topics.DRIVER_TOPIC_BASE, topics.LOGGER_BASE,
                               topics.ACTUATOR, topics.ANALYSIS_TOPIC_BASE]

    class ForwardHistorian(BaseHistorian):
        """
        This historian forwards data to another platform.
        """

        def __init__(self, **kwargs):
            # will be available in both threads.
            self._topic_replace_map = {}
            self._num_failures = 0
            self._last_timeout = 0
            self._target_platform = None
            super(ForwardHistorian, self).__init__(**kwargs)

        @Core.receiver("onstart")
        def starting_base(self, sender, **kwargs):
            """
            Subscribes to the platform message bus on the actuator, record,
            datalogger, and device topics to capture data.
            """

            def subscriber(subscription, callback_method):
                _log.debug("subscribing to {}".format(subscription))
                self.vip.pubsub.subscribe(peer='pubsub',
                                          prefix=subscription,
                                          callback=callback_method)

            _log.debug("Starting Forward historian")
            for topic_subscriptions in services_topic_list:
                subscriber(topic_subscriptions, self.capture_data)

            for custom_topic in custom_topic_list:
                subscriber(custom_topic, self.capture_data)

            self._started = True

        def timestamp(self):
            return time.mktime(datetime.datetime.now().timetuple())

        def capture_data(self, peer, sender, bus, topic, headers, message):

            # Grab the timestamp string from the message (we use this as the
            # value in our readings at the end of this method)
            _log.debug("In capture data")
            timestamp_string = headers.get(headers_mod.DATE, None)

            data = message
            try:
                # 2.0 agents compatability layer makes sender = pubsub.compat
                # so we can do the proper thing when it is here
                _log.debug("message in capture_data {}".format(message))
                if sender == 'pubsub.compat':
                    # data = jsonapi.loads(message[0])
                    data = compat.unpack_legacy_message(headers, message)
                    _log.debug("data in capture_data {}".format(data))
                if isinstance(data, dict):
                    data = data
                elif isinstance(data, int) or \
                        isinstance(data, float) or \
                        isinstance(data, long):
                    data = data
                    # else:
                    #     data = data[0]
            except ValueError as e:
                log_message = "message for {topic} bad message string:" \
                              "{message_string}"
                _log.error(log_message.format(topic=topic,
                                              message_string=message[0]))
                raise

            if topic_replace_list:
                if topic in self._topic_replace_map.keys():
                    topic = self._topic_replace_map[topic]
                else:
                    self._topic_replace_map[topic] = topic
                    temptopics = {}
                    for x in topic_replace_list:
                        if x['from'] in topic:
                            new_topic = temptopics.get(topic, topic)
                            temptopics[topic] = new_topic.replace(
                                x['from'], x['to'])

                    for k, v in temptopics.items():
                        self._topic_replace_map[k] = v
                    topic = self._topic_replace_map[topic]

            if gather_timing_data:
                add_timing_data_to_header(headers, self.core.agent_uuid or self.core.identity, "collected")

            payload = {'headers': headers, 'message': data}

            self._event_queue.put({'source': "forwarded",
                                   'topic': topic,
                                   'readings': [(timestamp_string, payload)]})

        @doc_inherit
        def publish_to_historian(self, to_publish_list):
            handled_records = []

            _log.debug("publish_to_historian number of items: {}"
                       .format(len(to_publish_list)))
            parsed = urlparse(self.core.address)
            next_dest = urlparse(destination_vip)
            current_time = self.timestamp()
            last_time = self._last_timeout
            _log.debug('Lasttime: {} currenttime: {}'.format(last_time,
                                                             current_time))
            timeout_occurred = False
            if self._last_timeout:
                # if we failed we need to wait 60 seconds before we go on.
                if self.timestamp() < self._last_timeout + 60:
                    _log.debug('Not allowing send < 60 seconds from failure')
                    return
            if not self._target_platform:
                self.historian_setup()
            if not self._target_platform:
                _log.debug('Could not connect to target')
                return

            for vip_id in required_target_agents:
                try:
                    self._target_platform.vip.ping(vip_id).get()
                except Unreachable:
                    skip = "Skipping publish: Target platform not running " \
                           "required agent {}".format(vip_id)
                    _log.warn(skip)
                    self.vip.health.set_status(
                        STATUS_BAD, skip)
                    return
                except Exception as e:
                    err = "Unhandled error publishing to target platform."
                    _log.error(err)
                    _log.error(traceback.format_exc())
                    self.vip.health.set_status(
                        STATUS_BAD, err)
                    return

            for x in to_publish_list:
                topic = x['topic']
                value = x['value']
                # payload = jsonapi.loads(value)
                payload = value
                headers = payload['headers']
                headers['X-Forwarded'] = True
                try:
                    del headers['Origin']
                except KeyError:
                    pass
                try:
                    del headers['Destination']
                except KeyError:
                    pass

                if gather_timing_data:
                    add_timing_data_to_header(headers, self.core.agent_uuid or self.core.identity,"forwarded")

                if timeout_occurred:
                    _log.error(
                        'A timeout has occurred so breaking out of publishing')
                    break
                with gevent.Timeout(30):
                    try:
                        _log.debug('debugger: {} {} {}'.format(topic,
                                                               headers,
                                                               payload))

                        self._target_platform.vip.pubsub.publish(
                            peer='pubsub',
                            topic=topic,
                            headers=headers,
                            message=payload['message']).get()
                    except gevent.Timeout:
                        _log.debug("Timeout occurred email should send!")
                        timeout_occurred = True
                        self._last_timeout = self.timestamp()
                        self._num_failures += 1
                        # Stop the current platform from attempting to
                        # connect
                        self._target_platform.core.stop()
                        self._target_platform = None
                        self.vip.health.set_status(
                            STATUS_BAD, "Timeout occured")
                    except Unreachable:
                        _log.error("Target not reachable. Wait till it's ready!")
                    except ZMQError as exc:
                        if exc.errno == ENOTSOCK:
                            # Stop the current platform from attempting to
                            # connect
                            _log.error("Target disconnected. Stopping target platform agent")
                            self._target_platform = None
                            self.vip.health.set_status(
                                STATUS_BAD, "Target platform disconnected")
                    except Exception as e:
                        err = "Unhandled error publishing to target platfom."
                        _log.error(err)
                        _log.error(traceback.format_exc())
                        self.vip.health.set_status(
                            STATUS_BAD, err)
                        # Before returning lets mark any that weren't errors
                        # as sent.
                        self.report_handled(handled_records)
                        return
                    else:
                        handled_records.append(x)

            _log.debug("handled: {} number of items".format(
                len(to_publish_list)))
            self.report_handled(handled_records)

            if timeout_occurred:
                _log.debug('Sending alert from the ForwardHistorian')
                status = Status.from_json(self.vip.health.get_status())
                self.vip.health.send_alert(FORWARD_TIMEOUT_KEY,
                                           status)
            else:
                self.vip.health.set_status(
                    STATUS_GOOD,"published {} items".format(
                        len(to_publish_list)))

        @doc_inherit
        def historian_setup(self):
            _log.debug("Setting up to forward to {}".format(destination_vip))
            try:
                agent = build_agent(address=destination_vip,
                                    serverkey=destination_serverkey,
                                    publickey=self.core.publickey,
                                    secretkey=self.core.secretkey,
                                    enable_store=False)

            except gevent.Timeout:
                self.vip.health.set_status(
                    STATUS_BAD, "Timeout in setup of agent")
                status = Status.from_json(self.vip.health.get_status_json())
                self.vip.health.send_alert(FORWARD_TIMEOUT_KEY,
                                           status)
            else:
                self._target_platform = agent


    return ForwardHistorian(backup_storage_limit_gb=backup_storage_limit_gb,
                            **kwargs)
Ejemplo n.º 19
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    services_topic_list = config.get('services_topic_list', ['all'])
    custom_topic_list = config.get('custom_topic_list', [])
    topic_replace_list = config.get('topic_replace_list', [])
    destination_vip = config.get('destination-vip')

    gather_timing_data = config.get('gather_timing_data', False)

    hosts = KnownHostsStore()
    destination_serverkey = hosts.serverkey(destination_vip)
    if destination_serverkey is None:
        _log.info(
            "Destination serverkey not found in known hosts file, using config"
        )
        destination_serverkey = config['destination-serverkey']

    required_target_agents = config.get('required_target_agents', [])
    backup_storage_limit_gb = config.get('backup_storage_limit_gb', None)
    if 'all' in services_topic_list:
        services_topic_list = [
            topics.DRIVER_TOPIC_BASE, topics.LOGGER_BASE, topics.ACTUATOR,
            topics.ANALYSIS_TOPIC_BASE
        ]

    class ForwardHistorian(BaseHistorian):
        """
        This historian forwards data to another platform.
        """
        def __init__(self, **kwargs):
            # will be available in both threads.
            self._topic_replace_map = {}
            self._num_failures = 0
            self._last_timeout = 0
            self._target_platform = None
            super(ForwardHistorian, self).__init__(**kwargs)

        @Core.receiver("onstart")
        def starting_base(self, sender, **kwargs):
            """
            Subscribes to the platform message bus on the actuator, record,
            datalogger, and device topics to capture data.
            """
            def subscriber(subscription, callback_method):
                _log.debug("subscribing to {}".format(subscription))
                self.vip.pubsub.subscribe(peer='pubsub',
                                          prefix=subscription,
                                          callback=callback_method)

            _log.debug("Starting Forward historian")
            for topic_subscriptions in services_topic_list:
                subscriber(topic_subscriptions, self.capture_data)

            for custom_topic in custom_topic_list:
                subscriber(custom_topic, self.capture_data)

            self._started = True

        def timestamp(self):
            return time.mktime(datetime.datetime.now().timetuple())

        def capture_data(self, peer, sender, bus, topic, headers, message):

            # Grab the timestamp string from the message (we use this as the
            # value in our readings at the end of this method)
            _log.debug("In capture data")
            timestamp_string = headers.get(headers_mod.DATE, None)

            data = message
            try:
                # 2.0 agents compatability layer makes sender = pubsub.compat
                # so we can do the proper thing when it is here
                _log.debug("message in capture_data {}".format(message))
                if sender == 'pubsub.compat':
                    # data = jsonapi.loads(message[0])
                    data = compat.unpack_legacy_message(headers, message)
                    _log.debug("data in capture_data {}".format(data))
                if isinstance(data, dict):
                    data = data
                elif isinstance(data, int) or \
                        isinstance(data, float) or \
                        isinstance(data, long):
                    data = data
                    # else:
                    #     data = data[0]
            except ValueError as e:
                log_message = "message for {topic} bad message string:" \
                              "{message_string}"
                _log.error(
                    log_message.format(topic=topic, message_string=message[0]))
                raise

            if topic_replace_list:
                if topic in self._topic_replace_map.keys():
                    topic = self._topic_replace_map[topic]
                else:
                    self._topic_replace_map[topic] = topic
                    temptopics = {}
                    for x in topic_replace_list:
                        if x['from'] in topic:
                            new_topic = temptopics.get(topic, topic)
                            temptopics[topic] = new_topic.replace(
                                x['from'], x['to'])

                    for k, v in temptopics.items():
                        self._topic_replace_map[k] = v
                    topic = self._topic_replace_map[topic]

            if gather_timing_data:
                add_timing_data_to_header(
                    headers, self.core.agent_uuid or self.core.identity,
                    "collected")

            payload = {'headers': headers, 'message': data}

            self._event_queue.put({
                'source': "forwarded",
                'topic': topic,
                'readings': [(timestamp_string, payload)]
            })

        @doc_inherit
        def publish_to_historian(self, to_publish_list):
            handled_records = []

            _log.debug("publish_to_historian number of items: {}".format(
                len(to_publish_list)))
            parsed = urlparse(self.core.address)
            next_dest = urlparse(destination_vip)
            current_time = self.timestamp()
            last_time = self._last_timeout
            _log.debug('Lasttime: {} currenttime: {}'.format(
                last_time, current_time))
            timeout_occurred = False
            if self._last_timeout:
                # if we failed we need to wait 60 seconds before we go on.
                if self.timestamp() < self._last_timeout + 60:
                    _log.debug('Not allowing send < 60 seconds from failure')
                    return
            if not self._target_platform:
                self.historian_setup()
            if not self._target_platform:
                _log.debug('Could not connect to target')
                return

            for vip_id in required_target_agents:
                try:
                    self._target_platform.vip.ping(vip_id).get()
                except Unreachable:
                    skip = "Skipping publish: Target platform not running " \
                           "required agent {}".format(vip_id)
                    _log.warn(skip)
                    self.vip.health.set_status(STATUS_BAD, skip)
                    return
                except Exception as e:
                    err = "Unhandled error publishing to target platform."
                    _log.error(err)
                    _log.error(traceback.format_exc())
                    self.vip.health.set_status(STATUS_BAD, err)
                    return

            for x in to_publish_list:
                topic = x['topic']
                value = x['value']
                # payload = jsonapi.loads(value)
                payload = value
                headers = payload['headers']
                headers['X-Forwarded'] = True
                try:
                    del headers['Origin']
                except KeyError:
                    pass
                try:
                    del headers['Destination']
                except KeyError:
                    pass

                if gather_timing_data:
                    add_timing_data_to_header(
                        headers, self.core.agent_uuid or self.core.identity,
                        "forwarded")

                if timeout_occurred:
                    _log.error(
                        'A timeout has occurred so breaking out of publishing')
                    break
                with gevent.Timeout(30):
                    try:
                        _log.debug('debugger: {} {} {}'.format(
                            topic, headers, payload))

                        self._target_platform.vip.pubsub.publish(
                            peer='pubsub',
                            topic=topic,
                            headers=headers,
                            message=payload['message']).get()
                    except gevent.Timeout:
                        _log.debug("Timeout occurred email should send!")
                        timeout_occurred = True
                        self._last_timeout = self.timestamp()
                        self._num_failures += 1
                        # Stop the current platform from attempting to
                        # connect
                        self._target_platform.core.stop()
                        self._target_platform = None
                        self.vip.health.set_status(STATUS_BAD,
                                                   "Timeout occured")
                    except Unreachable:
                        _log.error(
                            "Target not reachable. Wait till it's ready!")
                    except ZMQError as exc:
                        if exc.errno == ENOTSOCK:
                            # Stop the current platform from attempting to
                            # connect
                            _log.error(
                                "Target disconnected. Stopping target platform agent"
                            )
                            self._target_platform = None
                            self.vip.health.set_status(
                                STATUS_BAD, "Target platform disconnected")
                    except Exception as e:
                        err = "Unhandled error publishing to target platfom."
                        _log.error(err)
                        _log.error(traceback.format_exc())
                        self.vip.health.set_status(STATUS_BAD, err)
                        # Before returning lets mark any that weren't errors
                        # as sent.
                        self.report_handled(handled_records)
                        return
                    else:
                        handled_records.append(x)

            _log.debug("handled: {} number of items".format(
                len(to_publish_list)))
            self.report_handled(handled_records)

            if timeout_occurred:
                _log.debug('Sending alert from the ForwardHistorian')
                status = Status.from_json(self.vip.health.get_status())
                self.vip.health.send_alert(FORWARD_TIMEOUT_KEY, status)
            else:
                self.vip.health.set_status(
                    STATUS_GOOD,
                    "published {} items".format(len(to_publish_list)))

        @doc_inherit
        def historian_setup(self):
            _log.debug("Setting up to forward to {}".format(destination_vip))
            try:
                agent = build_agent(address=destination_vip,
                                    serverkey=destination_serverkey,
                                    publickey=self.core.publickey,
                                    secretkey=self.core.secretkey,
                                    enable_store=False)

            except gevent.Timeout:
                self.vip.health.set_status(STATUS_BAD,
                                           "Timeout in setup of agent")
                status = Status.from_json(self.vip.health.get_status_json())
                self.vip.health.send_alert(FORWARD_TIMEOUT_KEY, status)
            else:
                self._target_platform = agent

    return ForwardHistorian(backup_storage_limit_gb=backup_storage_limit_gb,
                            **kwargs)
Ejemplo n.º 20
0
 def _get_serverkey_from_known_hosts(self):
     known_hosts_file = os.path.join(self.volttron_home, 'known_hosts')
     known_hosts = KnownHostsStore(known_hosts_file)
     return known_hosts.serverkey(self.address)
Ejemplo n.º 21
0
    def startup_platform(self,
                         vip_address,
                         auth_dict=None,
                         use_twistd=False,
                         mode=UNRESTRICTED,
                         bind_web_address=None,
                         volttron_central_address=None,
                         volttron_central_serverkey=None):

        # if not isinstance(vip_address, list):
        #     self.vip_address = [vip_address]
        # else:
        #     self.vip_address = vip_address

        self.vip_address = vip_address
        self.mode = mode
        self.bind_web_address = bind_web_address
        if self.bind_web_address:
            self.discovery_address = "{}/discovery/".format(
                self.bind_web_address)

            # Only available if vc is installed!
            self.jsonrpc_endpoint = "{}/jsonrpc".format(self.bind_web_address)

        enable_logging = self.env.get('ENABLE_LOGGING', False)
        debug_mode = self.env.get('DEBUG_MODE', False)
        if not debug_mode:
            debug_mode = self.env.get('DEBUG', False)
        self.skip_cleanup = self.env.get('SKIP_CLEANUP', False)
        if debug_mode:
            self.skip_cleanup = True
            enable_logging = True
        self.logit("In start up platform enable_logging is {} ".format(
            enable_logging))
        assert self.mode in MODES, 'Invalid platform mode set: ' + str(mode)
        opts = None

        # see main.py for how we handle pub sub addresses.
        ipc = 'ipc://{}{}/run/'.format(
            '@' if sys.platform.startswith('linux') else '',
            self.volttron_home)
        self.local_vip_address = ipc + 'vip.socket'
        self.set_auth_dict(auth_dict)

        self.opts = {
            'verify_agents': False,
            'volttron_home': self.volttron_home,
            'vip_address': vip_address,
            'vip_local_address': ipc + 'vip.socket',
            'publish_address': ipc + 'publish',
            'subscribe_address': ipc + 'subscribe',
            'bind_web_address': bind_web_address,
            'volttron_central_address': volttron_central_address,
            'volttron_central_serverkey': volttron_central_serverkey,
            'platform_name': None,
            'log': os.path.join(self.volttron_home, 'volttron.log'),
            'log_config': None,
            'monitor': True,
            'autostart': True,
            'log_level': logging.DEBUG,
            'verboseness': logging.DEBUG
        }

        pconfig = os.path.join(self.volttron_home, 'config')
        config = {}

        # Add platform's public key to known hosts file
        publickey = self.keystore.public
        known_hosts_file = os.path.join(self.volttron_home, 'known_hosts')
        known_hosts = KnownHostsStore(known_hosts_file)
        known_hosts.add(self.opts['vip_local_address'], publickey)
        known_hosts.add(self.opts['vip_address'], publickey)

        # Set up the configuration file based upon the passed parameters.
        parser = configparser.ConfigParser()
        parser.add_section('volttron')
        parser.set('volttron', 'vip-address', vip_address)
        if bind_web_address:
            parser.set('volttron', 'bind-web-address', bind_web_address)
        if volttron_central_address:
            parser.set('volttron', 'volttron-central-address',
                       volttron_central_address)
        if volttron_central_serverkey:
            parser.set('volttron', 'volttron-central-serverkey',
                       volttron_central_serverkey)
        if self.mode == UNRESTRICTED:
            # TODO Restricted code should set with volttron as contianer
            # if RESTRICTED_AVAILABLE:
            #     config['mobility'] = False
            #     config['resource-monitor'] = False
            #     config['verify'] = False
            with closing(open(pconfig, 'wb')) as cfg:
                cfg.write(PLATFORM_CONFIG_UNRESTRICTED.format(**config))
                parser.write(cfg)

        elif self.mode == RESTRICTED:
            if not RESTRICTED_AVAILABLE:
                raise ValueError("restricted is not available.")

            certsdir = os.path.join(self.volttron_home, 'certificates')

            print("certsdir", certsdir)
            self.certsobj = certs.Certs(certsdir)

            with closing(open(pconfig, 'wb')) as cfg:
                cfg.write(PLATFORM_CONFIG_RESTRICTED.format(**config))
        else:
            raise PlatformWrapperError(
                "Invalid platform mode specified: {}".format(mode))

        log = os.path.join(self.volttron_home, 'volttron.log')
        if enable_logging:
            cmd = ['volttron', '-vv', '-l{}'.format(log)]
        else:
            cmd = ['volttron', '-l{}'.format(log)]

        print('process environment: {}'.format(self.env))
        print('popen params: {}'.format(cmd))
        self.p_process = Popen(cmd,
                               env=self.env,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)

        assert self.p_process is not None
        # A None value means that the process is still running.
        # A negative means that the process exited with an error.
        assert self.p_process.poll() is None

        self.serverkey = self.keystore.public
        assert self.serverkey
        agent = self.build_agent()

        has_control = False
        times = 0
        while not has_control and times < 10:
            times += 1
            try:
                has_control = agent.vip.peerlist().get(timeout=.2)
            except gevent.Timeout:
                pass

        if not has_control:
            self.shutdown_platform()
            raise "Couldn't connect to core platform!"

        if bind_web_address:
            times = 0
            has_discovery = False
            while times < 10:
                times += 1
                try:
                    resp = requests.get(self.discovery_address)
                    if resp.ok:
                        has_discovery = True
                        break
                except Exception as e:
                    gevent.sleep(0.1)
                    self.logit("Connection error found {}".format(e))
            if not has_discovery:
                raise "Couldn't connect to discovery platform."

        self.use_twistd = use_twistd

        # TODO: Revise this to start twistd with platform.
        if self.use_twistd:
            tconfig = os.path.join(self.volttron_home,
                                   TMP_SMAP_CONFIG_FILENAME)

            with closing(open(tconfig, 'w')) as cfg:
                cfg.write(TWISTED_CONFIG.format(**config))

            tparams = [TWISTED_START, "-n", "smap", tconfig]
            self.t_process = subprocess.Popen(tparams, env=self.env)
            time.sleep(5)
Ejemplo n.º 22
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    services_topic_list = config.get('services_topic_list', ['all'])
    custom_topic_list = config.get('custom_topic_list', [])
    topic_replace_list = config.get('topic_replace_list', [])
    source_vip = config.get('source-vip')
    hosts = KnownHostsStore()
    source_serverkey = hosts.serverkey(source_vip)
    if source_serverkey is None:
        _log.info(
            "Source serverkey not found in known hosts file, using config")
        source_serverkey = config['source-serverkey']
    identity = config.get('identity', kwargs.pop('identity', None))
    include_destination_in_header = config.get('include_destination_in_header',
                                               False)

    origin = config.get('origin', None)
    overwrite_origin = config.get('overwrite_origin', False)
    include_origin_in_header = config.get('include_origin_in_header', False)
    if 'all' in services_topic_list:
        services_topic_list = [
            topics.DRIVER_TOPIC_BASE, topics.LOGGER_BASE, topics.ACTUATOR,
            topics.ANALYSIS_TOPIC_BASE
        ]

    class DataPuller(Agent):
        '''This historian pulls data from another platform.
        '''
        def __init__(self, **kwargs):
            # will be available in both threads.
            self._topic_replace_map = {}
            self._num_failures = 0
            self._last_timeout = 0
            self._target_platform = None
            super(DataPuller, self).__init__(**kwargs)

        @Core.receiver("onstart")
        def starting_base(self, sender, **kwargs):
            self.puller_setup()
            '''
            Subscribes to the platform message bus on the actuator, record,
            datalogger, and device topics to capture data.
            '''
            def subscriber(subscription, callback_method):
                _log.debug("subscribing to {}".format(subscription))
                self._target_platform.vip.pubsub.subscribe(
                    peer='pubsub',
                    prefix=subscription,
                    callback=callback_method)

            _log.debug("Starting DataPuller")
            for topic_subscriptions in services_topic_list:
                subscriber(topic_subscriptions, self.on_message)

            for custom_topic in custom_topic_list:
                subscriber(custom_topic, self.on_message)

            self._started = True

        def timestamp(self):
            return time.mktime(datetime.datetime.now().timetuple())

        def on_message(self, peer, sender, bus, topic, headers, message):

            # Grab the timestamp string from the message (we use this as the
            # value in our readings at the end of this method)
            _log.debug("In capture data")
            timestamp_string = headers.get(headers_mod.DATE, None)

            data = message
            try:
                # 2.0 agents compatability layer makes sender = pubsub.compat
                # so we can do the proper thing when it is here
                _log.debug("message in capture_data {}".format(message))
                if sender == 'pubsub.compat':
                    # data = jsonapi.loads(message[0])
                    data = compat.unpack_legacy_message(headers, message)
                    _log.debug("data in capture_data {}".format(data))
                if isinstance(data, dict):
                    data = data
                elif isinstance(data, int) or \
                        isinstance(data, float) or \
                        isinstance(data, long):
                    data = data
                    # else:
                    #     data = data[0]
            except ValueError as e:
                log_message = "message for {topic} bad message string:" \
                              "{message_string}"
                _log.error(
                    log_message.format(topic=topic, message_string=message[0]))
                raise

            if topic_replace_list:
                if topic in self._topic_replace_map.keys():
                    topic = self._topic_replace_map[topic]
                else:
                    self._topic_replace_map[topic] = topic
                    temptopics = {}
                    for x in topic_replace_list:
                        if x['from'] in topic:
                            new_topic = temptopics.get(topic, topic)
                            temptopics[topic] = new_topic.replace(
                                x['from'], x['to'])

                    for k, v in temptopics.items():
                        self._topic_replace_map[k] = v
                    topic = self._topic_replace_map[topic]

            payload = {'headers': headers, 'topic': topic, 'message': data}
            self.publish_to_self(topic, payload)

        #             self._event_queue.put({'source': "forwarded",
        #                                    'topic': topic,
        #                                    'readings': [(timestamp_string, payload)]})

        def publish_to_self(self, topic, payload):
            handled_records = []

            parsed = urlparse(self.core.address)
            next_dest = urlparse(source_vip)
            current_time = self.timestamp()
            last_time = self._last_timeout
            _log.debug('Lasttime: {} currenttime: {}'.format(
                last_time, current_time))
            timeout_occurred = False
            if self._last_timeout:
                # if we failed we need to wait 60 seconds before we go on.
                if self.timestamp() < self._last_timeout + 60:
                    _log.debug('Not allowing send < 60 seconds from failure')
                    return
            if not self._target_platform:
                self.puller_setup()
            if not self._target_platform:
                _log.debug('Could not connect to target')
                return

            headers = payload['headers']
            headers['X-Forwarded'] = True
            try:
                del headers['Origin']
            except KeyError:
                pass
            try:
                del headers['Destination']
            except KeyError:
                pass

            print("should publish", topic, payload)

            self.vip.pubsub.publish(peer='pubsub',
                                    topic=topic,
                                    headers=headers,
                                    message=payload['message']).get(30)

        def puller_setup(self):
            _log.debug("Setting up to forward to {}".format(source_vip))
            try:
                agent = build_agent(address=source_vip,
                                    serverkey=source_serverkey,
                                    publickey=self.core.publickey,
                                    secretkey=self.core.secretkey,
                                    enable_store=False)
            except gevent.Timeout:
                self.vip.health.set_status(STATUS_BAD,
                                           "Timeout in setup of agent")
                status = Status.from_json(self.vip.health.get_status_json())
                self.vip.health.send_alert(FORWARD_TIMEOUT_KEY, status)
            else:
                self._target_platform = agent

    DataPuller.__name__ = 'DataPuller'
    return DataPuller(identity=identity, **kwargs)
Ejemplo n.º 23
0
def historian(config_path, **kwargs):
    config = utils.load_config(config_path)
    services_topic_list = config.get('services_topic_list', ['all'])
    custom_topic_list = config.get('custom_topic_list', [])
    topic_replace_list = config.get('topic_replace_list', [])
    source_vip = config.get('source-vip')
    hosts = KnownHostsStore()
    source_serverkey = hosts.serverkey(source_vip)
    if source_serverkey is None:
        _log.info("Source serverkey not found in known hosts file, using config")
        source_serverkey = config['source-serverkey']
    identity = config.get('identity', kwargs.pop('identity', None))
    include_destination_in_header = config.get('include_destination_in_header',
                                               False)

    origin = config.get('origin', None)
    overwrite_origin = config.get('overwrite_origin', False)
    include_origin_in_header = config.get('include_origin_in_header', False)
    if 'all' in services_topic_list:
        services_topic_list = [topics.DRIVER_TOPIC_BASE, topics.LOGGER_BASE,
                               topics.ACTUATOR, topics.ANALYSIS_TOPIC_BASE]

    class DataPuller(Agent):
        '''This historian pulls data from another platform.
        '''

        def __init__(self, **kwargs):
            # will be available in both threads.
            self._topic_replace_map = {}
            self._num_failures = 0
            self._last_timeout = 0
            self._target_platform = None
            super(DataPuller, self).__init__(**kwargs)

        @Core.receiver("onstart")
        def starting_base(self, sender, **kwargs):
            self.puller_setup()
            '''
            Subscribes to the platform message bus on the actuator, record,
            datalogger, and device topics to capture data.
            '''

            def subscriber(subscription, callback_method):
                _log.debug("subscribing to {}".format(subscription))
                self._target_platform.vip.pubsub.subscribe(peer='pubsub',
                                                           prefix=subscription,
                                                           callback=callback_method)

            _log.debug("Starting DataPuller")
            for topic_subscriptions in services_topic_list:
                subscriber(topic_subscriptions, self.on_message)

            for custom_topic in custom_topic_list:
                subscriber(custom_topic, self.on_message)

            self._started = True

        def timestamp(self):
            return time.mktime(datetime.datetime.now().timetuple())

        def on_message(self, peer, sender, bus, topic, headers, message):

            # Grab the timestamp string from the message (we use this as the
            # value in our readings at the end of this method)
            _log.debug("In capture data")
            timestamp_string = headers.get(headers_mod.DATE, None)

            data = message
            try:
                # 2.0 agents compatability layer makes sender = pubsub.compat
                # so we can do the proper thing when it is here
                _log.debug("message in capture_data {}".format(message))
                if sender == 'pubsub.compat':
                    # data = jsonapi.loads(message[0])
                    data = compat.unpack_legacy_message(headers, message)
                    _log.debug("data in capture_data {}".format(data))
                if isinstance(data, dict):
                    data = data
                elif isinstance(data, int) or \
                        isinstance(data, float) or \
                        isinstance(data, long):
                    data = data
                    # else:
                    #     data = data[0]
            except ValueError as e:
                log_message = "message for {topic} bad message string:" \
                              "{message_string}"
                _log.error(log_message.format(topic=topic,
                                              message_string=message[0]))
                raise

            if topic_replace_list:
                if topic in self._topic_replace_map.keys():
                    topic = self._topic_replace_map[topic]
                else:
                    self._topic_replace_map[topic] = topic
                    temptopics = {}
                    for x in topic_replace_list:
                        if x['from'] in topic:
                            new_topic = temptopics.get(topic, topic)
                            temptopics[topic] = new_topic.replace(
                                x['from'], x['to'])

                    for k, v in temptopics.items():
                        self._topic_replace_map[k] = v
                    topic = self._topic_replace_map[topic]

            payload = {'headers': headers, 'topic': topic, 'message': data}
            self.publish_to_self(topic, payload)

        #             self._event_queue.put({'source': "forwarded",
        #                                    'topic': topic,
        #                                    'readings': [(timestamp_string, payload)]})


        def publish_to_self(self, topic, payload):
            handled_records = []

            parsed = urlparse(self.core.address)
            next_dest = urlparse(source_vip)
            current_time = self.timestamp()
            last_time = self._last_timeout
            _log.debug('Lasttime: {} currenttime: {}'.format(last_time, current_time))
            timeout_occurred = False
            if self._last_timeout:
                # if we failed we need to wait 60 seconds before we go on.
                if self.timestamp() < self._last_timeout + 60:
                    _log.debug('Not allowing send < 60 seconds from failure')
                    return
            if not self._target_platform:
                self.puller_setup()
            if not self._target_platform:
                _log.debug('Could not connect to target')
                return

            headers = payload['headers']
            headers['X-Forwarded'] = True
            try:
                del headers['Origin']
            except KeyError:
                pass
            try:
                del headers['Destination']
            except KeyError:
                pass

            print("should publish", topic, payload)

            self.vip.pubsub.publish(
                peer='pubsub',
                topic=topic,
                headers=headers,
                message=payload['message']).get(30)

        def puller_setup(self):
            _log.debug("Setting up to forward to {}".format(source_vip))
            try:
                agent = build_agent(address=source_vip,
                                    serverkey=source_serverkey,
                                    publickey=self.core.publickey,
                                    secretkey=self.core.secretkey,
                                    enable_store=False)
            except gevent.Timeout:
                self.vip.health.set_status(
                    STATUS_BAD, "Timeout in setup of agent")
                status = Status.from_json(self.vip.health.get_status_json())
                self.vip.health.send_alert(FORWARD_TIMEOUT_KEY,
                                           status)
            else:
                self._target_platform = agent

    DataPuller.__name__ = 'DataPuller'
    return DataPuller(identity=identity,
                      **kwargs)