Ejemplo n.º 1
0
    def build_connection(self, peer=None, address=None, identity=None,
                         publickey=None, secretkey=None, serverkey=None,
                         capabilities=[], **kwargs):
        self.logit('Building connection to {}'.format(peer))
        self.allow_all_connections()

        if address is None:
            self.logit(
                'Default address was None so setting to current instances')
            address = self.vip_address
            serverkey = self.serverkey
        if serverkey is None:
            self.logit("serverkey wasn't set but the address was.")
            raise Exception("Invalid state.")

        if publickey is None or secretkey is None:
            self.logit('generating new public secret key pair')
            keyfile = tempfile.mktemp(".keys", "agent", self.volttron_home)
            keys = KeyStore(keyfile)
            keys.generate()
            publickey = keys.public
            secretkey = keys.secret
            entry = AuthEntry(capabilities=capabilities,
                              comments="Added by test",
                              credentials=keys.public)
            file = AuthFile(self.volttron_home + "/auth.json")
            file.add(entry)

        conn = Connection(address=address, peer=peer, publickey=publickey,
                          secretkey=secretkey, serverkey=serverkey,
                          volttron_home=self.volttron_home)

        return conn
Ejemplo n.º 2
0
def start_wrapper_platform(wrapper,
                           with_http=False,
                           with_tcp=True,
                           volttron_central_address=None,
                           volttron_central_serverkey=None,
                           add_local_vc_address=False):
    """ Customize easily customize the platform wrapper before starting it.
    """
    assert not wrapper.is_running()

    vc_http = get_rand_http_address() if with_http else None
    vc_tcp = get_rand_tcp_address() if with_tcp else None

    if add_local_vc_address:
        ks = KeyStore(os.path.join(wrapper.volttron_home, 'keystore'))
        ks.generate()
        volttron_central_address = vc_tcp
        volttron_central_serverkey = ks.public

    wrapper.startup_platform(
        vip_address=vc_tcp,
        bind_web_address=vc_http,
        volttron_central_address=volttron_central_address,
        volttron_central_serverkey=volttron_central_serverkey)
    if with_http:
        discovery = "{}/discovery/".format(vc_http)
        response = requests.get(discovery)
        assert response.ok

    assert wrapper.is_running()
Ejemplo n.º 3
0
def setup_control_connection(request, get_volttron_instances):
    """ Creates a single instance of VOLTTRON for testing purposes
    """
    global wrapper, control_connection

    wrapper = get_volttron_instances(1)

    request.addfinalizer(wrapper.shutdown_platform)

    assert wrapper
    assert wrapper.is_running()

    if get_volttron_instances.param == 'encrypted':
        if wrapper.encrypt:
            wrapper.allow_all_connections()
        # Connect using keys
        ks = KeyStore()
        ks.generate()

        control_connection = build_connection(identity="foo",
                                              address=wrapper.vip_address,
                                              peer=CONTROL,
                                              serverkey=wrapper.serverkey,
                                              publickey=ks.public,
                                              secretkey=ks.secret)
    else:
        control_connection = Connection(address=wrapper.local_vip_address,
                                        peer=CONTROL,
                                        developer_mode=True)
    # Sleep a couple seconds to wait for things to startup
    gevent.sleep(2)
    return wrapper, control_connection
Ejemplo n.º 4
0
def setup_control_connection(request, get_volttron_instances):
    """ Creates a single instance of VOLTTRON for testing purposes
    """
    global wrapper, control_connection

    wrapper = get_volttron_instances(1)

    request.addfinalizer(wrapper.shutdown_platform)

    assert wrapper
    assert wrapper.is_running()

    wrapper.allow_all_connections()

    # Connect using keys
    ks = KeyStore()
    ks.generate()

    control_connection = build_connection(identity="foo",
                                          address=wrapper.vip_address,
                                          peer=CONTROL,
                                          serverkey=wrapper.serverkey,
                                          publickey=ks.public,
                                          secretkey=ks.secret,
                                          instance_name=wrapper.instance_name,
                                          message_bus=wrapper.messagebus)

    # Sleep a couple seconds to wait for things to startup
    gevent.sleep(2)
    return wrapper, control_connection
Ejemplo n.º 5
0
    def build_connection(self, peer=None, address=None, identity=None,
                         publickey=None, secretkey=None, serverkey=None,
                         capabilities=[], **kwargs):
        self.logit('Building connection to {}'.format(peer))
        self.allow_all_connections()

        if address is None:
            self.logit(
                'Default address was None so setting to current instances')
            address = self.vip_address
            serverkey = self.serverkey
        if serverkey is None:
            self.logit("serverkey wasn't set but the address was.")
            raise Exception("Invalid state.")

        if publickey is None or secretkey is None:
            self.logit('generating new public secret key pair')
            keyfile = tempfile.mktemp(".keys", "agent", self.volttron_home)
            keys = KeyStore(keyfile)
            keys.generate()
            publickey = keys.public
            secretkey = keys.secret
            entry = AuthEntry(capabilities=capabilities,
                              comments="Added by test",
                              credentials=keys.public)
            file = AuthFile(self.volttron_home + "/auth.json")
            file.add(entry)

        conn = Connection(address=address, peer=peer, publickey=publickey,
                          secretkey=secretkey, serverkey=serverkey,
                          volttron_home=self.volttron_home)

        return conn
Ejemplo n.º 6
0
def start_wrapper_platform(wrapper, with_http=False, with_tcp=True,
                           volttron_central_address=None,
                           volttron_central_serverkey=None,
                           add_local_vc_address=False):
    """ Customize easily customize the platform wrapper before starting it.
    """
    assert not wrapper.is_running()

    vc_http = get_rand_http_address() if with_http else None
    vc_tcp = get_rand_tcp_address() if with_tcp else None

    if add_local_vc_address:
        ks = KeyStore(os.path.join(wrapper.volttron_home, 'keystore'))
        ks.generate()
        volttron_central_address = vc_tcp
        volttron_central_serverkey = ks.public

    wrapper.startup_platform(vip_address=vc_tcp,
                             bind_web_address=vc_http,
                             volttron_central_address=volttron_central_address,
                             volttron_central_serverkey=volttron_central_serverkey)
    if with_http:
        discovery = "{}/discovery/".format(vc_http)
        response = requests.get(discovery)
        assert response.ok

    assert wrapper.is_running()
Ejemplo n.º 7
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

    if volttron_instance1.encrypt:
        tf = tempfile.NamedTemporaryFile()
        ks = KeyStore(tf.name)
        # generate public private key pair for instance1
        ks.generate()

        # add public key of instance1 to instance2 auth file
        authfile = AuthFile(volttron_instance2.volttron_home + "/auth.json")
        entry = AuthEntry(credentials=ks.public)
        authfile.add(entry)

        # setup destination address to include keys
        forwarder_config["destination-vip"] =\
            "{}?serverkey={}&publickey={}&secretkey={}".format(
                volttron_instance2.vip_address,
                volttron_instance2.serverkey,
                ks.public, ks.secret)
    else:
        forwarder_config["destination-vip"] = volttron_instance2.vip_address
    # 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.º 8
0
    def build_agent(self, address=None, should_spawn=True, identity=None,
                    publickey=None, secretkey=None, serverkey=None,
                    generatekeys=False, **kwargs):
        """ Build an agent connnected to the passed bus.

        By default the current instance that this class wraps will be the
        vip address of the agent.

        :param address:
        :param should_spawn:
        :param identity:
        :param publickey:
        :param secretkey:
        :param serverkey:
        :return:
        """
        self.logit("Building generic agent.")

        use_ipc = kwargs.pop('use_ipc', False)
        if address is None:
            if use_ipc:
                self.logit('Using IPC vip-address')
                address = "ipc://@"+self.volttron_home+"/run/vip.socket"
            else:
                self.logit('Using vip-address '+self.vip_address)
                address = self.vip_address

        if generatekeys:
            self.logit('generating new public secret key pair')
            tf = tempfile.NamedTemporaryFile()
            ks = KeyStore(tf.name)
            ks.generate()
            publickey = ks.public()
            secretkey = ks.secret()

        if publickey and not serverkey:
            self.logit('using instance serverkey: {}'.format(self.publickey))
            serverkey = self.publickey

        agent = Agent(address=address, identity=identity, publickey=publickey,
                      secretkey=secretkey, serverkey=serverkey, **kwargs)
        self.logit('platformwrapper.build_agent.address: {}'.format(address))

        # Automatically add agent's credentials to auth.json file
        if publickey:
            self.logit('Adding publickey to auth.json')
            gevent.spawn(self._append_allow_curve_key, publickey)
            gevent.sleep(0.1)


        if should_spawn:
            self.logit('platformwrapper.build_agent spawning')
            event = gevent.event.Event()
            gevent.spawn(agent.core.run, event)#.join(0)
            event.wait(timeout=2)

            hello = agent.vip.hello().get(timeout=.3)
            self.logit('Got hello response {}'.format(hello))

        return agent
Ejemplo n.º 9
0
def setup_control_connection(request, get_volttron_instances):
    """ Creates a single instance of VOLTTRON for testing purposes
    """
    global wrapper, control_connection

    wrapper = get_volttron_instances(1)

    request.addfinalizer(wrapper.shutdown_platform)

    assert wrapper
    assert wrapper.is_running()

    if get_volttron_instances.param == 'encrypted':
        if wrapper.encrypt:
            wrapper.allow_all_connections()
        # Connect using keys
        ks = KeyStore()
        ks.generate()

        control_connection = build_connection(identity="foo",
                                              address=wrapper.vip_address,
                                              peer=CONTROL,
                                              serverkey=wrapper.serverkey,
                                              publickey=ks.public,
                                              secretkey=ks.secret)
    else:
        control_connection = Connection(address=wrapper.local_vip_address,
                                        peer=CONTROL, developer_mode=True)
    # Sleep a couple seconds to wait for things to startup
    gevent.sleep(2)
    return wrapper, control_connection
Ejemplo n.º 10
0
def tcp_to(instance):

    tmp = tempfile.NamedTemporaryFile()
    key = KeyStore(tmp.name)
    key.generate()

    return "{}?serverkey={}&publickey={}&secretkey={}".format(
        instance.vip_address, instance.serverkey, key.public, key.secret)
Ejemplo n.º 11
0
    def __init__(self):
        """ Initializes a new VOLTTRON instance

        Creates a temporary VOLTTRON_HOME directory with a packaged directory
        for agents that are built.
        """

        self.volttron_home = tempfile.mkdtemp()
        self.packaged_dir = os.path.join(self.volttron_home, "packaged")
        os.makedirs(self.packaged_dir)

        # in the context of this platform it is very important not to
        # use the main os.environ for anything.
        self.env = {
            'VOLTTRON_HOME': self.volttron_home,
            'PACKAGED_DIR': self.packaged_dir,
            'DEBUG_MODE': os.environ.get('DEBUG_MODE', ''),
            'DEBUG': os.environ.get('DEBUG', ''),
            'PATH': VOLTTRON_ROOT + ':' + os.environ['PATH']
        }

        # By default no web server should be started.
        self.bind_web_address = None
        self.discovery_address = None
        self.jsonrpc_endpoint = None
        self.volttron_central_address = None
        self.instance_name = None
        self.serverkey = None

        self.p_process = None
        self.t_process = None

        self.started_agent_pids = []
        self.local_vip_address = None
        self.vip_address = None
        self.encrypt = False
        self.logit('Creating platform wrapper')

        # This was used when we are testing the SMAP historian.
        self.use_twistd = False

        # Added restricted code properties
        self.certsobj = None

        # Control whether the instance directory is cleaned up when shutdown.
        # if the environment variable DEBUG is set to a True value then the
        # instance is not cleaned up.
        self.skip_cleanup = False

        # This is used as command line entry replacement.  Especially working
        # with older 2.0 agents.
        self.opts = None

        keystorefile = os.path.join(self.volttron_home, 'keystore')
        self.keystore = KeyStore(keystorefile)
        self.keystore.generate()
Ejemplo n.º 12
0
def tcp_to(instance):

    tmp = tempfile.NamedTemporaryFile()
    key = KeyStore(tmp.name)
    key.generate()

    return "{}?serverkey={}&publickey={}&secretkey={}".format(
        instance.vip_address,
        instance.serverkey,
        key.public,
        key.secret)
Ejemplo n.º 13
0
def get_configs(config_id, output_directory):


    keystore = KeyStore()
    agent = Agent(address=get_address(),
                  publickey=keystore.public, secretkey=keystore.secret,
                  enable_store=False)

    event = gevent.event.Event()
    gevent.spawn(agent.core.run, event)
    event.wait()

    config_list = agent.vip.rpc.call(CONFIGURATION_STORE,
                           'manage_list_configs',
                           config_id).get(timeout=10)

    if not config_list:
        print "Config store", config_id, "does not exist."
        return

    ensure_dir(output_directory)

    os.chdir(output_directory)

    for config in config_list:
        print "Retrieving configuration", config
        raw_config = agent.vip.rpc.call(CONFIGURATION_STORE,
                           'manage_get',
                           config_id,
                           config, raw=True).get(timeout=10)

        ensure_dir(os.path.dirname(config))

        with open(config, "w") as f:
            f.write(raw_config)
Ejemplo n.º 14
0
 def get_agent_keystore(self, agent_uuid, encoded_public=None,
                        encoded_secret=None):
     agent_path = os.path.join(self.install_dir, agent_uuid)
     agent_name = self.agent_name(agent_uuid)
     dist_info = os.path.join(agent_path, agent_name,
                              agent_name + '.dist-info')
     keystore_path = os.path.join(dist_info, 'keystore.json')
     return KeyStore(keystore_path, encoded_public, encoded_secret)
Ejemplo n.º 15
0
 def _get_keys_from_keystore(self):
     '''Returns agent's public and secret key from keystore'''
     if self.agent_uuid:
         # this is an installed agent
         keystore_dir = os.curdir
     elif self.identity:
         if not self.volttron_home:
             raise ValueError('VOLTTRON_HOME must be specified.')
         keystore_dir = os.path.join(self.volttron_home, 'keystores',
                                     self.identity)
         if not os.path.exists(keystore_dir):
             os.makedirs(keystore_dir)
     else:
         # the agent is not installed and its identity was not set
         return None, None
     keystore_path = os.path.join(keystore_dir, 'keystore.json')
     keystore = KeyStore(keystore_path)
     return keystore.public(), keystore.secret()
Ejemplo n.º 16
0
def test_discovery(scheme):
    vhome = create_volttron_home()
    # creates a vhome level key store
    keystore = KeyStore()
    serverkey = decode_key(keystore.public)

    # Depending upon scheme we enable/disable password jwt and certificate based jwt.
    if scheme == 'https':
        with certs_profile_1('/'.join([vhome, 'certs'])) as certs:
            config_params = dict(web_ssl_key=certs.server_certs[0].key_file,
                                 web_ssl_cert=certs.server_certs[0].cert_file)
    else:
        config_params = dict(web_secret_key=get_random_key())

    with get_test_volttron_home(messagebus='zmq', config_params=config_params):
        instance_name = "booballoon"
        host, port = get_hostname_and_random_port()

        # this is the vip address
        address = f"tcp://{host}:{port}"

        def _construct_query_mock(core):
            """
            Internal function that creates a concrete response for the data.
            when query('instance-name').get() is called the passed instance name
            is returned
            """
            nonlocal instance_name, address

            kv = {"instance-name": instance_name, "addresses": [address]}
            return MockQuery(**kv)

        with mock.patch('volttron.platform.vip.agent.subsystems.query.Query',
                        _construct_query_mock):
            host, port = get_hostname_and_random_port()
            bind_web_address = f"{scheme}://{host}:{port}"
            serverkey = decode_key(keystore.public)

            mws = MasterWebService(serverkey=serverkey,
                                   identity=MASTER_WEB,
                                   address=address,
                                   bind_web_address=bind_web_address,
                                   **config_params)
            mws.startupagent(sender='testweb')

            env = get_test_web_env("/discovery/")
            mock_start_response = mock.Mock()
            # A closingiterator is returned from the response object so we use the next
            # on the returned response.  Then we can do json responses.
            response = mws.app_routing(env, mock_start_response).__next__()
            # load json into a dict for testing responses.
            response = jsonapi.loads(response.decode('utf-8'))

            assert response.get('instance-name') is not None
            assert instance_name == response.get('instance-name')
            assert keystore.public == response.get('serverkey')
            assert address == response.get('vip-address')
Ejemplo n.º 17
0
def main():
    # parse the command line arguments
    arg_parser = argparse.ArgumentParser(description=__doc__)

    arg_parser.add_argument(
        "--address", help="Target only device(s) at <address> for request")

    arg_parser.add_argument(
        "--range",
        type=int,
        nargs=2,
        metavar=('LOW', 'HIGH'),
        help="Lower and upper limit on device ID in results")

    arg_parser.add_argument(
        "--timeout",
        type=int,
        metavar=('SECONDS'),
        help="Time, in seconds, to wait for responses. Default: %(default)s",
        default=5)

    arg_parser.add_argument("--proxy-id",
                            help="VIP IDENTITY of the BACnet proxy agent.",
                            default="platform.bacnet_proxy")

    args = arg_parser.parse_args()

    _log.debug("initialization")
    _log.debug("    - args: %r", args)

    keystore = KeyStore()
    agent = BACnetInteraction(args.proxy_id,
                              address=get_address(),
                              volttron_home=get_home(),
                              publickey=keystore.public,
                              secretkey=keystore.secret,
                              enable_store=False)

    event = gevent.event.Event()
    gevent.spawn(agent.core.run, event)
    event.wait()

    kwargs = {'address': args.address}

    if args.range is not None:
        kwargs['low_device_id'] = int(args.range[0])
        kwargs['high_device_id'] = int(args.range[1])

    try:
        agent.send_iam(**kwargs)
    except errors.Unreachable:
        _log.error(
            "There is no BACnet proxy Agent running on the platform with the VIP IDENTITY {}"
            .format(args.proxy_id))
    else:
        gevent.sleep(args.timeout)
Ejemplo n.º 18
0
def build_agent_with_key(platform: PlatformWrapper, identity=None):
    """Create an agent instance that has a generated public and private key.

    The passed platform will be the vip-address of the agent and the
     identity will be set.  If the identity is set to None then a random
     identity will be created.
    """
    os.environ['VOLTTRON_HOME'] = platform.volttron_home
    keys = KeyStore(os.path.join(platform.volttron_home, identity + '.keys'))
    keys.generate()
    agent = platform.build_agent(identity=identity,
                                 serverkey=platform.publickey,
                                 publickey=keys.public,
                                 secretkey=keys.secret)
    # Make publickey easily accessible for these tests
    agent.publickey = keys.public
    gevent.sleep(0.1)  # switch context for a bit
    os.environ.pop('VOLTTRON_HOME')
    return agent
Ejemplo n.º 19
0
 def _get_keys_from_keystore(self):
     '''Returns agent's public and secret key from keystore'''
     if self.agent_uuid:
         # this is an installed agent
         keystore_dir = os.curdir
     elif self.identity:
         if not os.environ.get('VOLTTRON_HOME'):
             raise ValueError('VOLTTRON_HOME must be specified.')
         keystore_dir = os.path.join(
                 os.environ.get('VOLTTRON_HOME'), 'keystores',
                 self.identity)
         if not os.path.exists(keystore_dir):
             os.makedirs(keystore_dir)
     else:
         # the agent is not installed and its identity was not set
         return None, None
     keystore_path = os.path.join(keystore_dir, 'keystore.json')
     keystore = KeyStore(keystore_path)
     return keystore.public(), keystore.secret()
Ejemplo n.º 20
0
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:{}"
            .format(e))

    return ks.public, ks.secret
Ejemplo n.º 21
0
    def build_connection(self,
                         peer=None,
                         address=None,
                         identity=None,
                         publickey=None,
                         secretkey=None,
                         serverkey=None,
                         **kwargs):

        if self.encrypt:
            self.allow_all_connections()

        if address is None:
            address = self.vip_address
            serverkey = self.serverkey

        if publickey is None or secretkey is None:
            self.logit('generating new public secret key pair')
            keyfile = tempfile.mktemp(".keys", "agent", self.volttron_home)
            keys = KeyStore(keyfile)
            keys.generate()
            publickey = keys.public()
            secretkey = keys.secret()
        if self.encrypt:
            conn = Connection(address=address,
                              peer=peer,
                              publickey=publickey,
                              secretkey=secretkey,
                              serverkey=serverkey,
                              volttron_home=self.volttron_home)
        else:
            conn = Connection(address=self.local_vip_address,
                              peer=peer,
                              volttron_home=self.volttron_home)
        return conn
Ejemplo n.º 22
0
def update_curve_key(curve_key_path, no_warn=False):
    try:
        with open(curve_key_path, 'r') as curve_file:
            public, secret = read_curve_key(curve_file)
    except IOError as e:
        print e
        return

    keystore_path = os.path.join(os.path.dirname(curve_key_path), 'keystore')
    
    if os.path.exists(keystore_path) and not no_warn:
        response = raw_input("{} already exists. "
                "Overwrite? [y/N]: ".format(keystore_path))
        if not response.lower().startswith('y'):
            print "Key update aborted."
            return

    keystore = KeyStore(keystore_path)
    keystore.public = public
    keystore.secret = secret
    print "Keys from {} have been transfered to {}".format(curve_key_path, 
            keystore.filename)
Ejemplo n.º 23
0
def update_curve_key(curve_key_path, no_warn=False):
    try:
        with open(curve_key_path, 'r') as curve_file:
            public, secret = read_curve_key(curve_file)
    except IOError as e:
        print e
        return

    keystore_path = os.path.join(os.path.dirname(curve_key_path), 'keystore')
    
    if os.path.exists(keystore_path) and not no_warn:
        response = raw_input("{} already exists. "
                "Overwrite? [y/N]: ".format(keystore_path))
        if not response.lower().startswith('y'):
            print "Key update aborted."
            return

    keystore = KeyStore(keystore_path)
    keystore.public = public
    keystore.secret = secret
    print "Keys from {} have been transfered to {}".format(curve_key_path, 
            keystore.filename)
Ejemplo n.º 24
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}
def install_configs(input_directory, keep=False):
    try:
        os.chdir(input_directory)
    except FileNotFoundError:
        print(f"'input_directory' could not be found: {input_directory}")
        return

    ks = KeyStore()
    agent = build_agent(identity=PLATFORM,
                        publickey=ks.public,
                        secretkey=ks.secret,
                        enable_store=True,
                        timeout=30)

    if not keep:
        print("Deleting old Platform Driver store")
        agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_store',
                           PLATFORM_DRIVER).get(timeout=10)

    with open("config") as f:
        print("Storing main configuration")
        agent.vip.rpc.call(CONFIGURATION_STORE,
                           'manage_store',
                           PLATFORM_DRIVER,
                           'config',
                           f.read(),
                           config_type="json").get(timeout=10)

    for name in glob.iglob("registry_configs/*"):
        with open(name) as f:
            print("Storing configuration:", name)
            agent.vip.rpc.call(CONFIGURATION_STORE,
                               'manage_store',
                               PLATFORM_DRIVER,
                               name,
                               f.read(),
                               config_type="csv").get(timeout=10)

    for dir_path, _, files in os.walk("devices"):
        for file_name in files:
            name = os.path.join(dir_path, file_name)
            with open(name) as f:
                print("Storing configuration:", name)
                agent.vip.rpc.call(CONFIGURATION_STORE,
                                   'manage_store',
                                   PLATFORM_DRIVER,
                                   name,
                                   f.read(),
                                   config_type="json").get(timeout=10)
Ejemplo n.º 26
0
def install_configs(input_directory, keep=False):
    os.chdir(input_directory)

    keystore = KeyStore()
    agent = Agent(address=get_address(),
                  identity="master_driver_update_agent",
                  publickey=keystore.public,
                  secretkey=keystore.secret,
                  enable_store=False)

    event = gevent.event.Event()
    gevent.spawn(agent.core.run, event)
    event.wait()

    if not keep:
        print("Deleting old Master Driver store")
        agent.vip.rpc.call(CONFIGURATION_STORE, 'manage_delete_store',
                           PLATFORM_DRIVER).get(timeout=10)

    with open("config") as f:
        print("Storing main configuration")
        agent.vip.rpc.call(CONFIGURATION_STORE,
                           'manage_store',
                           PLATFORM_DRIVER,
                           'config',
                           f.read(),
                           config_type="json").get(timeout=10)

    for name in glob.iglob("registry_configs/*"):
        with open(name) as f:
            print("Storing configuration:", name)
            agent.vip.rpc.call(CONFIGURATION_STORE,
                               'manage_store',
                               PLATFORM_DRIVER,
                               name,
                               f.read(),
                               config_type="csv").get(timeout=10)

    for dir_path, _, files in os.walk("devices"):
        for file_name in files:
            name = os.path.join(dir_path, file_name)
            with open(name) as f:
                print("Storing configuration:", name)
                agent.vip.rpc.call(CONFIGURATION_STORE,
                                   'manage_store',
                                   PLATFORM_DRIVER,
                                   name,
                                   f.read(),
                                   config_type="json").get(timeout=10)
Ejemplo n.º 27
0
    def _get_keys_from_keystore(self):
        '''Returns agent's public and secret key from keystore'''
        if self.agent_uuid:
            # this is an installed agent, put keystore in its dist-info
            current_directory = os.path.abspath(os.curdir)
            keystore_dir = os.path.join(
                current_directory,
                "{}.dist-info".format(os.path.basename(current_directory)))
        elif self.identity is None:
            raise ValueError("Agent's VIP identity is not set")
        else:
            if not self.volttron_home:
                raise ValueError('VOLTTRON_HOME must be specified.')
            keystore_dir = os.path.join(self.volttron_home, 'keystores',
                                        self.identity)

        keystore_path = os.path.join(keystore_dir, 'keystore.json')
        keystore = KeyStore(keystore_path)
        return keystore.public, keystore.secret
Ejemplo n.º 28
0
def upgrade_old_agents(aip):
    """
    Moves any keystore.json from agent-data to dist-info.
    Only applies to agents in auth file.
    """

    vhome = Path(aip.env.volttron_home)
    agent_map = aip.get_agent_identity_to_uuid_mapping()

    auth_file = AuthFile()
    install_dir = vhome.joinpath("agents")
    for agent in agent_map:
        agent_path = install_dir.joinpath(agent_map[agent])
        try:
            agent_data = get_agent_path(agent_path, 'agent-data')
        # Skip if no agent-data exists
        except KeyError as err:
            print(f"agent-data not found for {err}")
            continue

        keystore_path = agent_data.joinpath('keystore.json')
        try:
            dist_info = get_agent_path(agent_path, 'dist-info')
        # Skip if no dist-info exists
        except KeyError as err:
            print(f"dist-info not found for {err}")
            continue
        keystore_dest_path = dist_info.joinpath('keystore.json')

        if keystore_path.exists():
            agent_keystore = KeyStore(keystore_path)
            for entry in auth_file.read()[0]:
                # Only move if agent exists in auth file
                if entry.credentials == agent_keystore.public:
                    shutil.move(str(keystore_path), str(keystore_dest_path))
                    break
    return
Ejemplo n.º 29
0
def build_agent_with_key(platform, identity=None):
    """Create an agent instance that has a generated public and private key.

    The passed platform will be the vip-address of the agent and the
     identity will be set.  If the identity is set to None then a random
     identity will be created.
    """

    keys = KeyStore(os.path.join(platform.volttron_home,
                                          identity + '.keys'))
    keys.generate()
    agent = platform.build_agent(identity=identity,
                                  serverkey=platform.publickey,
                                  publickey=keys.public(),
                                  secretkey=keys.secret())
    # Make publickey easily accessible for these tests
    agent.publickey = keys.public()
    gevent.sleep(0.1) # switch context for a bit

    return agent
Ejemplo n.º 30
0
def main():
    global agent
    global config_writer
    # parse the command line arguments
    arg_parser = argparse.ArgumentParser(description=__doc__)

    arg_parser.add_argument("device_id",
                            type=int,
                            help="Device ID of the target device")

    arg_parser.add_argument(
        "--address",
        help=
        "Address of target device, may be needed to help route initial request to device."
    )

    arg_parser.add_argument("--registry-out-file",
                            type=argparse.FileType('w'),
                            help="Output registry to CSV file",
                            default=sys.stdout)

    arg_parser.add_argument("--driver-out-file",
                            type=argparse.FileType('w'),
                            help="Output driver configuration to JSON file.",
                            default=sys.stdout)

    arg_parser.add_argument(
        "--max-range-report",
        nargs='?',
        type=float,
        help=
        'Affects how very large numbers are reported in the "Unit Details" column of the '
        'output. Does not affect driver behavior.',
        default=1.0e+20)

    arg_parser.add_argument("--proxy-id",
                            help="VIP IDENTITY of the BACnet proxy agent.",
                            default="platform.bacnet_proxy")

    args = arg_parser.parse_args()

    _log.debug("initialization")
    _log.debug("    - args: %r", args)

    key_store = KeyStore()
    config_writer = DictWriter(
        args.registry_out_file,
        ('Reference Point Name', 'Volttron Point Name', 'Units',
         'Unit Details', 'BACnet Object Type', 'Property', 'Writable', 'Index',
         'Write Priority', 'Notes'))

    config_writer.writeheader()

    agent = build_agent(address=get_address(),
                        volttron_home=get_home(),
                        publickey=key_store.public,
                        secretkey=key_store.secret,
                        enable_store=False)

    bn = BACnetReader(agent.vip, args.proxy_id, bacnet_response)

    async_result = AsyncResult()

    try:
        bn.get_iam(args.device_id, async_result.set, args.address)
    except errors.Unreachable as ure:
        _log.error(ure)
        _log.error(
            "No BACnet proxy Agent running on the platform with the VIP IDENTITY {}"
            .format(args.proxy_id))
        sys.exit(1)

    try:
        results = async_result.get(timeout=5.0)
    except gevent.Timeout:
        _log.error("No response from device id {}".format(args.device_id))
        sys.exit(1)

    if args.address and args.address != results["address"]:
        msg = "Inconsistent results from passed address ({}) and device address ({}) using results.".format(
            args.address, results["address"])
        _log.warning(msg)
        args.address = results["address"]
    elif results["address"]:
        args.address = results["address"]

    bn.read_device_properties(target_address=args.address,
                              device_id=args.device_id)

    agent.core.stop()
Ejemplo n.º 31
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.º 32
0
def test_forwarding(volttron_instance1_encrypt, volttron_instance2_encrypt):
    global FORWARDER_CONFIG
    tf = tempfile.NamedTemporaryFile()
    tf2 = tempfile.NamedTemporaryFile()
    tf3 = tempfile.NamedTemporaryFile()
    ks = KeyStore(tf.name)
    ks.generate()
    ks2 = KeyStore(tf2.name)
    ks2.generate()
    ks3 = KeyStore(tf2.name)
    ks3.generate()

    wrap1 = volttron_instance1_encrypt
    wrap2 = volttron_instance2_encrypt

    authfile1 = AuthFile(wrap1.volttron_home+"/auth.json")
    entry1 = AuthEntry(
        credentials="CURVE:{}".format(ks3.public())
    )
    authfile1.add(entry1)

    authfile = AuthFile(wrap2.volttron_home+"/auth.json")
    entry = AuthEntry(
        credentials="CURVE:{}".format(ks.public()))
    authfile.add(entry)
    entry = AuthEntry(
        credentials="CURVE:{}".format(ks2.public()))
    authfile.add(entry)

    forward_to_vip = "{}?serverkey={}&publickey={}&secretkey={}".format(
        wrap2.vip_address, wrap2.publickey, ks.public(), ks.secret()
    )

    FORWARDER_CONFIG["destination-vip"] = forward_to_vip
    forwarder_config = FORWARDER_CONFIG
    print("THE CONFIG = {}".format(forwarder_config))

    wrap1.install_agent(
        agent_dir="services/core/ForwardHistorian",
        config_file=forwarder_config
    )

    connect_to_wrap2 = "{}?serverkey={}&publickey={}&secretkey={}".format(
        wrap2.vip_address, wrap2.publickey, ks2.public(), ks2.secret()
    )

    connect_to_wrap1 = "{}?serverkey={}&publickey={}&secretkey={}".format(
        wrap1.vip_address, wrap1.publickey, ks3.public(), ks3.secret()
    )

    agent_connected1 = wrap1.build_agent(address=connect_to_wrap1)
    agent_connected2 = wrap2.build_agent(address=connect_to_wrap2)

    message = ''
    agent_connected2.vip.pubsub.subscribe('pubsub', '', callback=onmessage)
    gevent.sleep(0.2)

    do_publish(agent1=agent_connected1)
    gevent.sleep(1)
    assert allforwardedmessage
import os
import sys

import gevent

from volttron.platform import get_address
from volttron.platform.agent.known_identities import VOLTTRON_CENTRAL_PLATFORM
from volttron.platform.keystore import KeyStore
from volttron.platform.messaging import topics
from volttron.platform.vip.agent import Agent


keystore = KeyStore()
agent = Agent(address=get_address(), identity="blahagent",
              publickey=keystore.public(), secretkey=keystore.secret(),
              enable_store=False)

event = gevent.event.Event()
config_store_task = gevent.spawn(agent.core.run, event)
event.wait()
del event

if VOLTTRON_CENTRAL_PLATFORM not in agent.vip.peerlist().get():
    agent.core.stop()
    print('no vcp availablel')
    sys.exit()


def receive_platform_data(peer, sender, bus, topic, headers, message):
    #assert 'message' in kwargs
Ejemplo n.º 34
0
    def build_agent(self, address=None, should_spawn=True, identity=None,
                    publickey=None, secretkey=None, serverkey=None,
                    agent_class=Agent, **kwargs):
        """ Build an agent connnected to the passed bus.

        By default the current instance that this class wraps will be the
        vip address of the agent.

        :param address:
        :param should_spawn:
        :param identity:
        :param publickey:
        :param secretkey:
        :param serverkey:
        :param agent_class: Agent class to build
        :return:
        """
        self.logit("Building generic agent.")

        use_ipc = kwargs.pop('use_ipc', False)

        if serverkey is None:
            serverkey = self.serverkey
        if publickey is None:
            self.logit('generating new public secret key pair')
            keyfile = tempfile.mktemp(".keys", "agent", self.volttron_home)
            keys = KeyStore(keyfile)
            keys.generate()
            publickey = keys.public
            secretkey = keys.secret

        if address is None:
            self.logit('Using vip-address ' + self.vip_address)
            address = self.vip_address

        if publickey and not serverkey:
            self.logit('using instance serverkey: {}'.format(self.publickey))
            serverkey = self.publickey

        agent = agent_class(address=address, identity=identity,
                            publickey=publickey, secretkey=secretkey,
                            serverkey=serverkey,
                            volttron_home=self.volttron_home,
                            **kwargs)
        self.logit('platformwrapper.build_agent.address: {}'.format(address))

        # Automatically add agent's credentials to auth.json file
        if publickey:
            self.logit('Adding publickey to auth.json')
            gevent.spawn(self._append_allow_curve_key, publickey)
            gevent.sleep(0.1)

        if should_spawn:
            self.logit('platformwrapper.build_agent spawning')
            event = gevent.event.Event()
            gevent.spawn(agent.core.run, event)  # .join(0)
            event.wait(timeout=2)

            hello = agent.vip.hello().get(timeout=.3)
            self.logit('Got hello response {}'.format(hello))
        agent.publickey = publickey
        return agent
Ejemplo n.º 35
0
def get_new_keypair():
    tf = tempfile.NamedTemporaryFile()
    ks = KeyStore(tf.name)
    ks.generate()
    return ks.public, ks.secret
Ejemplo n.º 36
0
    def __init__(self):
        """ Initializes a new VOLTTRON instance

        Creates a temporary VOLTTRON_HOME directory with a packaged directory
        for agents that are built.
        """

        # This is hopefully going to keep us from attempting to shutdown
        # multiple times.  For example if a fixture calls shutdown and a
        # lower level fixture calls shutdown, this won't hang.
        self._instance_shutdown = False

        self.volttron_home = tempfile.mkdtemp()
        self.packaged_dir = os.path.join(self.volttron_home, "packaged")
        os.makedirs(self.packaged_dir)

        # in the context of this platform it is very important not to
        # use the main os.environ for anything.
        self.env = {
            'VOLTTRON_HOME': self.volttron_home,
            'PACKAGED_DIR': self.packaged_dir,
            'DEBUG_MODE': os.environ.get('DEBUG_MODE', ''),
            'DEBUG': os.environ.get('DEBUG', ''),
            'PATH': VOLTTRON_ROOT + ':' + os.environ['PATH']
        }
        self.volttron_root = VOLTTRON_ROOT

        volttron_exe = subprocess.check_output(['which', 'volttron']).strip()

        assert os.path.exists(volttron_exe)
        self.python = os.path.join(os.path.dirname(volttron_exe), 'python')
        assert os.path.exists(self.python)

        # By default no web server should be started.
        self.bind_web_address = None
        self.discovery_address = None
        self.jsonrpc_endpoint = None
        self.volttron_central_address = None
        self.instance_name = None
        self.serverkey = None

        self.p_process = None
        self.t_process = None

        self.started_agent_pids = []
        self.local_vip_address = None
        self.vip_address = None
        self.logit('Creating platform wrapper')

        # This was used when we are testing the SMAP historian.
        self.use_twistd = False

        # Added restricted code properties
        self.certsobj = None

        # Control whether the instance directory is cleaned up when shutdown.
        # if the environment variable DEBUG is set to a True value then the
        # instance is not cleaned up.
        self.skip_cleanup = False

        # This is used as command line entry replacement.  Especially working
        # with older 2.0 agents.
        self.opts = None

        keystorefile = os.path.join(self.volttron_home, 'keystore')
        self.keystore = KeyStore(keystorefile)
        self.keystore.generate()
Ejemplo n.º 37
0
class PlatformWrapper:
    def __init__(self):
        """ Initializes a new VOLTTRON instance

        Creates a temporary VOLTTRON_HOME directory with a packaged directory
        for agents that are built.
        """

        # This is hopefully going to keep us from attempting to shutdown
        # multiple times.  For example if a fixture calls shutdown and a
        # lower level fixture calls shutdown, this won't hang.
        self._instance_shutdown = False

        self.volttron_home = tempfile.mkdtemp()
        self.packaged_dir = os.path.join(self.volttron_home, "packaged")
        os.makedirs(self.packaged_dir)

        # in the context of this platform it is very important not to
        # use the main os.environ for anything.
        self.env = {
            'VOLTTRON_HOME': self.volttron_home,
            'PACKAGED_DIR': self.packaged_dir,
            'DEBUG_MODE': os.environ.get('DEBUG_MODE', ''),
            'DEBUG': os.environ.get('DEBUG', ''),
            'PATH': VOLTTRON_ROOT + ':' + os.environ['PATH']
        }
        self.volttron_root = VOLTTRON_ROOT

        volttron_exe = subprocess.check_output(['which', 'volttron']).strip()

        assert os.path.exists(volttron_exe)
        self.python = os.path.join(os.path.dirname(volttron_exe), 'python')
        assert os.path.exists(self.python)

        # By default no web server should be started.
        self.bind_web_address = None
        self.discovery_address = None
        self.jsonrpc_endpoint = None
        self.volttron_central_address = None
        self.instance_name = None
        self.serverkey = None

        self.p_process = None
        self.t_process = None

        self.started_agent_pids = []
        self.local_vip_address = None
        self.vip_address = None
        self.logit('Creating platform wrapper')

        # This was used when we are testing the SMAP historian.
        self.use_twistd = False

        # Added restricted code properties
        self.certsobj = None

        # Control whether the instance directory is cleaned up when shutdown.
        # if the environment variable DEBUG is set to a True value then the
        # instance is not cleaned up.
        self.skip_cleanup = False

        # This is used as command line entry replacement.  Especially working
        # with older 2.0 agents.
        self.opts = None

        keystorefile = os.path.join(self.volttron_home, 'keystore')
        self.keystore = KeyStore(keystorefile)
        self.keystore.generate()

    def logit(self, message):
        print('{}: {}'.format(self.volttron_home, message))

    def allow_all_connections(self):
        """ Add a /.*/ entry to the auth.json file.
        """
        entry = AuthEntry(credentials="/.*/")
        authfile = AuthFile(self.volttron_home + "/auth.json")
        try:
            authfile.add(entry)
        except AuthFileEntryAlreadyExists:
            pass

    def build_connection(self, peer=None, address=None, identity=None,
                         publickey=None, secretkey=None, serverkey=None,
                         capabilities=[], **kwargs):
        self.logit('Building connection to {}'.format(peer))
        self.allow_all_connections()

        if address is None:
            self.logit(
                'Default address was None so setting to current instances')
            address = self.vip_address
            serverkey = self.serverkey
        if serverkey is None:
            self.logit("serverkey wasn't set but the address was.")
            raise Exception("Invalid state.")

        if publickey is None or secretkey is None:
            self.logit('generating new public secret key pair')
            keyfile = tempfile.mktemp(".keys", "agent", self.volttron_home)
            keys = KeyStore(keyfile)
            keys.generate()
            publickey = keys.public
            secretkey = keys.secret
            entry = AuthEntry(capabilities=capabilities,
                              comments="Added by test",
                              credentials=keys.public)
            file = AuthFile(self.volttron_home + "/auth.json")
            file.add(entry)

        conn = Connection(address=address, peer=peer, publickey=publickey,
                          secretkey=secretkey, serverkey=serverkey,
                          volttron_home=self.volttron_home)

        return conn

    def build_agent(self, address=None, should_spawn=True, identity=None,
                    publickey=None, secretkey=None, serverkey=None,
                    agent_class=Agent, **kwargs):
        """ Build an agent connnected to the passed bus.

        By default the current instance that this class wraps will be the
        vip address of the agent.

        :param address:
        :param should_spawn:
        :param identity:
        :param publickey:
        :param secretkey:
        :param serverkey:
        :param agent_class: Agent class to build
        :return:
        """
        self.logit("Building generic agent.")

        use_ipc = kwargs.pop('use_ipc', False)

        if serverkey is None:
            serverkey = self.serverkey
        if publickey is None:
            self.logit('generating new public secret key pair')
            keyfile = tempfile.mktemp(".keys", "agent", self.volttron_home)
            keys = KeyStore(keyfile)
            keys.generate()
            publickey = keys.public
            secretkey = keys.secret

        if address is None:
            self.logit('Using vip-address ' + self.vip_address)
            address = self.vip_address

        if publickey and not serverkey:
            self.logit('using instance serverkey: {}'.format(self.publickey))
            serverkey = self.publickey

        agent = agent_class(address=address, identity=identity,
                            publickey=publickey, secretkey=secretkey,
                            serverkey=serverkey,
                            volttron_home=self.volttron_home,
                            **kwargs)
        self.logit('platformwrapper.build_agent.address: {}'.format(address))

        # Automatically add agent's credentials to auth.json file
        if publickey:
            self.logit('Adding publickey to auth.json')
            gevent.spawn(self._append_allow_curve_key, publickey)
            gevent.sleep(0.1)

        if should_spawn:
            self.logit('platformwrapper.build_agent spawning')
            event = gevent.event.Event()
            gevent.spawn(agent.core.run, event)  # .join(0)
            event.wait(timeout=2)

            hello = agent.vip.hello().get(timeout=.3)
            self.logit('Got hello response {}'.format(hello))
        agent.publickey = publickey
        return agent

    def _read_auth_file(self):
        auth_path = os.path.join(self.volttron_home, 'auth.json')
        try:
            with open(auth_path, 'r') as fd:
                data = strip_comments(FileObject(fd, close=False).read())
                if data:
                    auth = jsonapi.loads(data)
                else:
                    auth = {}
        except IOError:
            auth = {}
        if 'allow' not in auth:
            auth['allow'] = []
        return auth, auth_path

    def _append_allow_curve_key(self, publickey):
        entry = AuthEntry(credentials=publickey)
        authfile = AuthFile(self.volttron_home + "/auth.json")
        try:
            authfile.add(entry)
        except AuthFileEntryAlreadyExists:
            pass

    def add_vc(self):
        return add_vc_to_instance(self)

    def add_capabilities(self, publickey, capabilities):
        if isinstance(capabilities, basestring):
            capabilities = [capabilities]
        auth, auth_path = self._read_auth_file()
        cred = publickey
        allow = auth['allow']
        entry = next((item for item in allow if item['credentials'] == cred),
                     {})
        caps = entry.get('capabilities', [])
        entry['capabilities'] = list(set(caps + capabilities))

        with open(auth_path, 'w+') as fd:
            json.dump(auth, fd)

    def set_auth_dict(self, auth_dict):
        if auth_dict:
            with open(os.path.join(self.volttron_home, 'auth.json'), 'w') as fd:
                fd.write(json.dumps(auth_dict))

    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)

    def is_running(self):
        self.logit("PROCESS IS RUNNING: {}".format(self.p_process))
        return self.p_process is not None and self.p_process.poll() is None

    def twistd_is_running(self):
        return self.t_process is not None

    def direct_sign_agentpackage_creator(self, package):
        assert (RESTRICTED), "Auth not available"
        print ("wrapper.certsobj", self.certsobj.cert_dir)
        assert (
            auth.sign_as_creator(package, 'creator',
                                 certsobj=self.certsobj)), "Signing as {} failed.".format(
            'creator')

    def direct_sign_agentpackage_admin(self, package):
        assert (RESTRICTED), "Auth not available"
        assert (auth.sign_as_admin(package, 'admin',
                                   certsobj=self.certsobj)), "Signing as {} failed.".format(
            'admin')

    def direct_sign_agentpackage_initiator(self, package, config_file,
                                           contract):
        assert (RESTRICTED), "Auth not available"
        files = {"config_file": config_file, "contract": contract}
        assert (auth.sign_as_initiator(package, 'initiator', files=files,
                                       certsobj=self.certsobj)), "Signing as {} failed.".format(
            'initiator')

    def _aip(self):
        opts = type('Options', (), self.opts)
        aip = AIPplatform(opts)
        aip.setup()
        return aip

    def _install_agent(self, wheel_file, start, vip_identity):
        self.logit('Creating channel for sending the agent.')
        gevent.sleep(0.3)
        self.logit('calling control install agent.')
        self.logit("VOLTTRON_HOME SETTING: {}".format(
            self.env['VOLTTRON_HOME']))
        env = self.env.copy()
        cmd = ['volttron-ctl', '-vv', 'install', wheel_file]
        if vip_identity:
            cmd.extend(['--vip-identity', vip_identity])
        self.logit("cmd: {}".format(cmd))
        res = subprocess.check_output(cmd, env=env)
        assert res, "failed to install wheel:{}".format(wheel_file)
        agent_uuid = res.split(' ')[-2]
        self.logit(agent_uuid)

        if start:
            self.start_agent(agent_uuid)

        return agent_uuid

    def install_multiple_agents(self, agent_configs):
        """
        Installs mutltiple agents on the platform.

        :param agent_configs:list
            A list of 3-tuple that allows the configuration of a platform
            in a single go.  The tuple order is
            1. path to the agent directory.
            2. configuration data (either file or json data)
            3. Whether the agent should be started or not.

        :return:list:
            A list of uuid's associated with the agents that were installed.


        :Note:
            In order for this method to be called the platform must be
            currently running.
        """
        if not self.is_running():
            raise PlatformWrapperError("Instance isn't running!")
        results = []

        for path, config, start in agent_configs:
            results = self.install_agent(agent_dir=path, config_file=config,
                                         start=start)

        return results

    def install_agent(self, agent_wheel=None, agent_dir=None, config_file=None,
                      start=True, vip_identity=None):
        """
        Install and optionally start an agent on the instance.

        This function allows installation from an agent wheel or an
        agent directory (NOT BOTH).  If an agent_wheel is specified then
        it is assumed to be ready for installation (has a config file).
        If an agent_dir is specified then a config_file file must be
        specified or if it is not specified then it is assumed that the
        file agent_dir/config is to be used as the configuration file.  If
        none of these exist then an assertion error will be thrown.

        This function will return with a uuid of the installed agent.

        :param agent_wheel:
        :param agent_dir:
        :param config_file:
        :param start:
        :param vip_identity:
        :return:
        """

        assert self.is_running(), "Instance must be running to install agent."
        assert agent_wheel or agent_dir, "Invalid agent_wheel or agent_dir."

        if agent_wheel:
            assert not agent_dir
            assert not config_file
            assert os.path.exists(agent_wheel)
            wheel_file = agent_wheel
            agent_uuid = self._install_agent(wheel_file, start, vip_identity)

        # Now if the agent_dir is specified.
        if agent_dir:
            assert not agent_wheel
            if isinstance(config_file, dict):
                from os.path import join, basename
                temp_config = join(self.volttron_home,
                                   basename(agent_dir) + "_config_file")
                with open(temp_config, "w") as fp:
                    fp.write(json.dumps(config_file))
                config_file = temp_config
            elif not config_file:
                if os.path.exists(os.path.join(agent_dir, "config")):
                    config_file = os.path.join(agent_dir, "config")
                else:
                    from os.path import join, basename
                    temp_config = join(self.volttron_home,
                                       basename(agent_dir) + "_config_file")
                    with open(temp_config, "w") as fp:
                        fp.write(json.dumps({}))
                    config_file = temp_config
            elif os.path.exists(config_file):
                pass  # config_file already set!
            else:
                raise ValueError("Can't determine correct config file.")

            script = os.path.join(self.volttron_root,
                                  "scripts/install-agent.py")
            cmd = [self.python, script,
                   "--volttron-home", self.volttron_home,
                   "--volttron-root", self.volttron_root,
                   "--agent-source", agent_dir,
                   "--config", config_file,
                   "--json"]

            if vip_identity:
                cmd.extend(["--vip-identity", vip_identity])
            if start:
                cmd.extend(["--start"])

            results = subprocess.check_output(cmd)

            # Because we are no longer silencing output from the install, the
            # the results object is now much more verbose.  Our assumption is
            # the line before the output we care about has WHEEL at the end
            # of it.
            new_results = ""
            found_wheel = False
            for line in results.split("\n"):
                if line.endswith("WHEEL"):
                    found_wheel = True
                elif found_wheel:
                    new_results += line
            results = new_results

            #
            # Response from results is expected as follows depending on
            # parameters, note this is a json string so parse to get dictionary.
            # {
            #     "started": true,
            #     "agent_pid": 26241,
            #     "starting": true,
            #     "agent_uuid": "ec1fd94e-922a-491f-9878-c392b24dbe50"
            # }
            assert results

            resultobj = jsonapi.loads(str(results))

            if start:
                assert resultobj['started']
            agent_uuid = resultobj['agent_uuid']

        assert agent_uuid is not None

        if start:
            assert self.is_agent_running(agent_uuid)

        return agent_uuid

    def start_agent(self, agent_uuid):
        self.logit('Starting agent {}'.format(agent_uuid))
        self.logit("VOLTTRON_HOME SETTING: {}".format(
            self.env['VOLTTRON_HOME']))
        cmd = ['volttron-ctl']
        cmd.extend(['start', agent_uuid])
        p = Popen(cmd, env=self.env,
                  stdout=sys.stdout, stderr=sys.stderr)
        p.wait()

        # Confirm agent running
        cmd = ['volttron-ctl']
        cmd.extend(['status', agent_uuid])
        res = subprocess.check_output(cmd, env=self.env)
        # 776 TODO: Timing issue where check fails
        time.sleep(.1)
        self.logit("Subprocess res is {}".format(res))
        assert 'running' in res
        pidpos = res.index('[') + 1
        pidend = res.index(']')
        pid = int(res[pidpos: pidend])

        assert psutil.pid_exists(pid), \
            "The pid associated with agent {} does not exist".format(pid)

        self.started_agent_pids.append(pid)
        return pid

    def stop_agent(self, agent_uuid):
        # Confirm agent running
        _log.debug("STOPPING AGENT: {}".format(agent_uuid))
        try:
            cmd = ['volttron-ctl']
            cmd.extend(['stop', agent_uuid])
            res = subprocess.check_output(cmd, env=self.env)
        except CalledProcessError as ex:
            _log.error("Exception: {}".format(ex))
        return self.agent_pid(agent_uuid)

    def list_agents(self):
        agent = self.build_agent()
        print('PEER LIST: {}'.format(agent.vip.peerlist().get(timeout=10)))
        agent_list = agent.vip.rpc('control', 'list_agents').get(timeout=10)
        agent.core.stop(timeout=3)
        return agent_list

    def remove_agent(self, agent_uuid):
        """Remove the agent specified by agent_uuid"""
        _log.debug("REMOVING AGENT: {}".format(agent_uuid))
        try:
            cmd = ['volttron-ctl']
            cmd.extend(['remove', agent_uuid])
            res = subprocess.check_output(cmd, env=self.env)
        except CalledProcessError as ex:
            _log.error("Exception: {}".format(ex))
        return self.agent_pid(agent_uuid)

    def is_agent_running(self, agent_uuid):
        return self.agent_pid(agent_uuid) is not None

    def agent_pid(self, agent_uuid):
        """
        Returns the pid of a running agent or None

        :param agent_uuid:
        :return:
        """
        # Confirm agent running
        cmd = ['volttron-ctl']
        cmd.extend(['status', agent_uuid])
        pid = None
        try:
            res = subprocess.check_output(cmd, env=self.env)
            try:
                pidpos = res.index('[') + 1
                pidend = res.index(']')
                pid = int(res[pidpos: pidend])
            except:
                pid = None
        except CalledProcessError as ex:
            _log.error("Exception: {}".format(ex))

        # Handle the following exception that seems to happen when getting a
        # pid of an agent during the platform shutdown phase.
        #
        # Logged from file platformwrapper.py, line 797
        #   AGENT             IDENTITY          TAG STATUS
        # Traceback (most recent call last):
        #   File "/usr/lib/python2.7/logging/__init__.py", line 882, in emit
        #     stream.write(fs % msg)
        #   File "/home/volttron/git/volttron/env/local/lib/python2.7/site-packages/_pytest/capture.py", line 244, in write
        #     self.buffer.write(obj)
        # ValueError: I/O operation on closed file
        except ValueError:
            pass
        # _log.debug("AGENT_PID: {}".format(pid))
        return pid

    def build_agentpackage(self, agent_dir, config_file={}):
        if isinstance(config_file, dict):
            cfg_path = os.path.join(agent_dir, "config_temp")
            with open(cfg_path, "w") as tmp_cfg:
                tmp_cfg.write(jsonapi.dumps(config_file))
            config_file = cfg_path

        # Handle relative paths from the volttron git directory.
        if not os.path.isabs(agent_dir):
            agent_dir = os.path.join(self.volttron_root, agent_dir)

        assert os.path.exists(config_file)
        assert os.path.exists(agent_dir)

        wheel_path = packaging.create_package(agent_dir,
                                              self.packaged_dir)
        packaging.add_files_to_package(wheel_path, {
            'config_file': os.path.join('./', config_file)
        })

        return wheel_path

    def confirm_agent_running(self, agent_name, max_retries=5,
                              timeout_seconds=2):
        running = False
        retries = 0
        while not running and retries < max_retries:
            status = self.test_aip.status_agents()
            print ("Status", status)
            if len(status) > 0:
                status_name = status[0][1]
                assert status_name == agent_name

                assert len(status[0][2]) == 2, 'Unexpected agent status message'
                status_agent_status = status[0][2][1]
                running = not isinstance(status_agent_status, int)
            retries += 1
            time.sleep(timeout_seconds)
        return running

    # def direct_stop_agent(self, agent_uuid):
    #     result = self.conn.call.stop_agent(agent_uuid)
    #     print result

    def shutdown_platform(self):
        """
        Stop platform here.  First grab a list of all of the agents that are
        running on the platform, then shutdown, then if any of the listed agent
        pids are still running then kill them.
        """

        # Handle cascading calls from multiple levels of fixtures.
        if self._instance_shutdown:
            return

        running_pids = []

        for agnt in self.list_agents():
            pid = self.agent_pid(agnt['uuid'])
            if pid is not None and int(pid) > 0:
                running_pids.append(int(pid))

        # First try and nicely shutdown the platform, which should clean all
        # of the agents up automatically.
        cmd = ['volttron-ctl']
        cmd.extend(['shutdown', '--platform'])
        try:
            res = subprocess.check_output(cmd, env=self.env)
        except CalledProcessError:
            if self.p_process is not None:
                try:
                    gevent.sleep(0.2)
                    self.p_process.terminate()
                    gevent.sleep(0.2)
                except OSError:
                    self.logit('Platform process was terminated.')
            else:
                self.logit("platform process was null")

        for pid in running_pids:
            if psutil.pid_exists(pid):
                self.logit("TERMINATING: {}".format(pid))
                proc = psutil.Process(pid)
                proc.terminate()

        if self.use_twistd and self.t_process is not None:
            self.t_process.kill()
            self.t_process.wait()
        elif self.use_twistd:
            self.logit("twistd process was null")

        if os.environ.get('PRINT_LOG'):
            logpath = os.path.join(self.volttron_home, 'volttron.log')
            if os.path.exists(logpath):
                print("************************* Begin {}".format(logpath))
                with open(logpath) as f:
                    for l in f.readlines():
                        print(l)
                print("************************* End {}".format(logpath))
            else:
                print("######################### No Log Exists: {}".format(
                    logpath
                ))
        if not self.skip_cleanup:
            self.logit('Removing {}'.format(self.volttron_home))
            shutil.rmtree(self.volttron_home, ignore_errors=True)
        self._instance_shutdown = True

    def __repr__(self):
        return str(self)

    def __str__(self):
        data = []
        data.append('volttron_home: {}'.format(self.volttron_home))
        return '\n'.join(data)
Ejemplo n.º 38
0
def main():
    global agent
    # parse the command line arguments
    arg_parser = argparse.ArgumentParser(description=__doc__)

    arg_parser.add_argument("device_id",
                            type=int,
                            help="Device ID of the target device")

    arg_parser.add_argument(
        "--address",
        help=
        "Address of target device, may be needed to help route initial request to device."
    )

    arg_parser.add_argument("--registry-out-file",
                            type=argparse.FileType('wb'),
                            help="Output registry to CSV file",
                            default=sys.stdout)

    arg_parser.add_argument("--driver-out-file",
                            type=argparse.FileType('wb'),
                            help="Output driver configuration to JSON file.",
                            default=sys.stdout)

    arg_parser.add_argument(
        "--max-range-report",
        nargs='?',
        type=float,
        help=
        'Affects how very large numbers are reported in the "Unit Details" column of the output. '
        'Does not affect driver behavior.',
        default=1.0e+20)

    arg_parser.add_argument("--proxy-id",
                            help="VIP IDENTITY of the BACnet proxy agent.",
                            default="platform.bacnet_proxy")

    args = arg_parser.parse_args()

    _log.debug("initialization")
    _log.debug("    - args: %r", args)

    key_store = KeyStore()
    agent = BACnetInteraction(args.proxy_id,
                              address=get_address(),
                              volttron_home=get_home(),
                              publickey=key_store.public,
                              secretkey=key_store.secret,
                              enable_store=False)

    event = gevent.event.Event()
    gevent.spawn(agent.core.run, event)
    event.wait()

    async_result = AsyncResult()

    try:
        agent.get_iam(args.device_id, async_result.set, args.address)
    except errors.Unreachable:
        _log.error(
            "There is no BACnet proxy Agent running on the platform with the VIP IDENTITY {}"
            .format(args.proxy_id))
        sys.exit(1)

    try:
        results = async_result.get(timeout=5.0)
    except gevent.Timeout:
        _log.error("No response from device id {}".format(args.device_id))
        sys.exit(1)

    target_address = results["address"]
    device_id = results["device_id"]

    config_file_name = basename(args.registry_out_file.name)

    config = {
        "driver_config": {
            "device_address": str(target_address),
            "device_id": device_id
        },
        "driver_type": "bacnet",
        "registry_config":
        "config://registry_configs/{}".format(config_file_name)
    }

    json.dump(config, args.driver_out_file, indent=4)

    _log.debug('pduSource = ' + target_address)
    _log.debug('iAmDeviceIdentifier = ' + str(device_id))
    _log.debug('maxAPDULengthAccepted = ' + str(results["max_apdu_length"]))
    _log.debug('segmentationSupported = ' + results["segmentation_supported"])
    _log.debug('vendorID = ' + str(results["vendor_id"]))

    try:
        device_name = read_prop(target_address, "device", device_id,
                                "objectName")
        _log.debug('device_name = ' + str(device_name))
    except TypeError:
        _log.debug('device missing objectName')

    try:
        device_description = read_prop(target_address, "device", device_id,
                                       "description")
        _log.debug('description = ' + str(device_description))
    except TypeError:
        _log.debug('device missing description')

    config_writer = DictWriter(
        args.registry_out_file,
        ('Reference Point Name', 'Volttron Point Name', 'Units',
         'Unit Details', 'BACnet Object Type', 'Property', 'Writable', 'Index',
         'Write Priority', 'Notes'))

    config_writer.writeheader()

    try:
        object_count = read_prop(target_address,
                                 "device",
                                 device_id,
                                 "objectList",
                                 index=0)
        list_property = "objectList"
    except TypeError:
        object_count = read_prop(target_address,
                                 "device",
                                 device_id,
                                 "structuredObjectList",
                                 index=0)
        list_property = "structuredObjectList"

    _log.debug('object_count = ' + str(object_count))

    for object_index in xrange(1, object_count + 1):
        _log.debug('object_device_index = ' + repr(object_index))

        bac_object = read_prop(target_address,
                               "device",
                               device_id,
                               list_property,
                               index=object_index)

        obj_type, index = bac_object

        process_object(target_address, obj_type, index, args.max_range_report,
                       config_writer)
Ejemplo n.º 39
0
def get_new_keypair():
    tf = tempfile.NamedTemporaryFile()
    ks = KeyStore(tf.name)
    ks.generate()
    return ks.public, ks.secret
Ejemplo n.º 40
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
from volttron.platform.vip.agent import Agent
from volttron.platform.vip.agent.connection import Connection

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

ks = KeyStore()


def build_connection(identity,
                     peer='',
                     address=get_address(),
                     publickey=ks.public,
                     secretkey=ks.secret,
                     **kwargs):
    cn = Connection(address=address,
                    identity=identity,
                    peer=peer,
                    publickey=publickey,
                    secretkey=secretkey,
                    **kwargs)
    return cn
Ejemplo n.º 41
0
    def __init__(self):
        """ Initializes a new VOLTTRON instance

        Creates a temporary VOLTTRON_HOME directory with a packaged directory
        for agents that are built.
        """

        # This is hopefully going to keep us from attempting to shutdown
        # multiple times.  For example if a fixture calls shutdown and a
        # lower level fixture calls shutdown, this won't hang.
        self._instance_shutdown = False

        self.volttron_home = tempfile.mkdtemp()
        self.packaged_dir = os.path.join(self.volttron_home, "packaged")
        os.makedirs(self.packaged_dir)

        # in the context of this platform it is very important not to
        # use the main os.environ for anything.
        self.env = {
            'VOLTTRON_HOME': self.volttron_home,
            'PACKAGED_DIR': self.packaged_dir,
            'DEBUG_MODE': os.environ.get('DEBUG_MODE', ''),
            'DEBUG': os.environ.get('DEBUG', ''),
            'PATH': VOLTTRON_ROOT + ':' + os.environ['PATH']
        }
        self.volttron_root = VOLTTRON_ROOT

        volttron_exe = subprocess.check_output(['which', 'volttron']).strip()

        assert os.path.exists(volttron_exe)
        self.python = os.path.join(os.path.dirname(volttron_exe), 'python')
        assert os.path.exists(self.python)

        # By default no web server should be started.
        self.bind_web_address = None
        self.discovery_address = None
        self.jsonrpc_endpoint = None
        self.volttron_central_address = None
        self.instance_name = None
        self.serverkey = None

        self.p_process = None
        self.t_process = None

        self.started_agent_pids = []
        self.local_vip_address = None
        self.vip_address = None
        self.logit('Creating platform wrapper')

        # This was used when we are testing the SMAP historian.
        self.use_twistd = False

        # Added restricted code properties
        self.certsobj = None

        # Control whether the instance directory is cleaned up when shutdown.
        # if the environment variable DEBUG is set to a True value then the
        # instance is not cleaned up.
        self.skip_cleanup = False

        # This is used as command line entry replacement.  Especially working
        # with older 2.0 agents.
        self.opts = None

        keystorefile = os.path.join(self.volttron_home, 'keystore')
        self.keystore = KeyStore(keystorefile)
        self.keystore.generate()
Ejemplo n.º 42
0
def main():
    # parse the command line arguments
    arg_parser = argparse.ArgumentParser(description=__doc__)

    arg_parser.add_argument(
        "--address", help="Target only device(s) at <address> for request")

    arg_parser.add_argument(
        "--range",
        type=int,
        nargs=2,
        metavar=('LOW', 'HIGH'),
        help="Lower and upper limit on device ID in results")

    arg_parser.add_argument(
        "--timeout",
        type=int,
        metavar=('SECONDS'),
        help="Time, in seconds, to wait for responses. Default: %(default)s",
        default=5)

    arg_parser.add_argument("--proxy-id",
                            help="VIP IDENTITY of the BACnet proxy agent.",
                            default="platform.bacnet_proxy")

    arg_parser.add_argument("--csv-out",
                            dest="csv_out",
                            help="Write results to the CSV file specified.")

    arg_parser.add_argument("--debug",
                            action="store_true",
                            help="Set the logger in debug mode")

    args = arg_parser.parse_args()

    core_logger = logging.getLogger("volttron.platform.vip.agent.core")
    core_logger.setLevel(logging.WARN)
    _log.setLevel(logging.WARN)

    if args.debug:
        _log.setLevel(logging.DEBUG)
        core_logger.setLevel(logging.DEBUG)

    _log.debug("initialization")
    _log.debug("    - args: %r", args)

    csv_writer = None

    if args.csv_out is not None:
        f = open(args.csv_out, "wb")
        field_names = [
            "address", "device_id", "max_apdu_length",
            "segmentation_supported", "vendor_id"
        ]
        csv_writer = csv.DictWriter(f, field_names)
        csv_writer.writeheader()

    keystore = KeyStore()
    agent = BACnetInteraction(args.proxy_id,
                              csv_writer=csv_writer,
                              address=get_address(),
                              volttron_home=get_home(),
                              publickey=keystore.public,
                              secretkey=keystore.secret,
                              enable_store=False)

    event = gevent.event.Event()
    gevent.spawn(agent.core.run, event)
    event.wait()

    kwargs = {'address': args.address}

    if args.range is not None:
        kwargs['low_device_id'] = int(args.range[0])
        kwargs['high_device_id'] = int(args.range[1])

    try:
        agent.send_iam(**kwargs)
    except errors.Unreachable:
        _log.error(
            "There is no BACnet proxy Agent running on the platform with the VIP IDENTITY {}"
            .format(args.proxy_id))
    else:
        gevent.sleep(args.timeout)
Ejemplo n.º 43
0
    def build_agent(self,
                    address=None,
                    should_spawn=True,
                    identity=None,
                    publickey=None,
                    secretkey=None,
                    serverkey=None,
                    agent_class=Agent,
                    **kwargs):
        """ Build an agent connnected to the passed bus.

        By default the current instance that this class wraps will be the
        vip address of the agent.

        :param address:
        :param should_spawn:
        :param identity:
        :param publickey:
        :param secretkey:
        :param serverkey:
        :param agent_class: Agent class to build
        :return:
        """
        self.logit("Building generic agent.")

        use_ipc = kwargs.pop('use_ipc', False)

        if serverkey is None:
            serverkey = self.serverkey
        if publickey is None:
            self.logit('generating new public secret key pair')
            keyfile = tempfile.mktemp(".keys", "agent", self.volttron_home)
            keys = KeyStore(keyfile)
            keys.generate()
            publickey = keys.public
            secretkey = keys.secret

        if address is None:
            self.logit('Using vip-address ' + self.vip_address)
            address = self.vip_address

        if publickey and not serverkey:
            self.logit('using instance serverkey: {}'.format(self.publickey))
            serverkey = self.publickey

        agent = agent_class(address=address,
                            identity=identity,
                            publickey=publickey,
                            secretkey=secretkey,
                            serverkey=serverkey,
                            volttron_home=self.volttron_home,
                            **kwargs)
        self.logit('platformwrapper.build_agent.address: {}'.format(address))

        # Automatically add agent's credentials to auth.json file
        if publickey:
            self.logit('Adding publickey to auth.json')
            gevent.spawn(self._append_allow_curve_key, publickey)
            gevent.sleep(0.1)

        if should_spawn:
            self.logit('platformwrapper.build_agent spawning')
            event = gevent.event.Event()
            gevent.spawn(agent.core.run, event)  # .join(0)
            event.wait(timeout=2)

            hello = agent.vip.hello().get(timeout=.3)
            self.logit('Got hello response {}'.format(hello))
        agent.publickey = publickey
        return agent