예제 #1
0
    def FindByName(cls, name):
        """Find an installed VirtualTile by name.

        This function searches for installed virtual tiles
        using the pkg_resources entry_point `iotile.virtual_tile`.

        If name is a path ending in .py, it is assumed to point to
        a module on disk and loaded directly rather than using
        pkg_resources.

        Args:
            name (str): The name of the tile to search
                for.

        Returns:
            VirtualTile class: A virtual tile subclass that can be
                instantiated to create a virtual tile.
        """

        if name.endswith('.py'):
            return cls.LoadFromFile(name)

        reg = ComponentRegistry()
        for _name, tile in reg.load_extensions('iotile.virtual_tile',
                                               name_filter=name,
                                               class_filter=BaseVirtualTile):
            return tile

        raise ArgumentError("VirtualTile could not be found by name",
                            name=name)
예제 #2
0
def require(builder_name):
    """Find an advertised autobuilder and return it

    This function searches through all installed distributions to find
    if any advertise an entry point with group 'iotile.autobuild' and
    name equal to builder_name.  The first one that is found is returned.

    This function raises a BuildError if it cannot find the required
    autobuild function

    Args:
        builder_name (string): The name of the builder to find

    Returns:
        callable: the autobuilder function found in the search
    """

    reg = ComponentRegistry()
    for _name, autobuild_func in reg.load_extensions('iotile.autobuild',
                                                     name_filter=builder_name):
        return autobuild_func

    raise BuildError(
        'Cannot find required autobuilder, make sure the distribution providing it is installed',
        name=builder_name)
예제 #3
0
    def FindByName(cls, name):
        """Find a specific installed auth provider by name."""

        reg = ComponentRegistry()
        for _, entry in reg.load_extensions('iotile.auth_provider',
                                            name_filter=name):
            return entry
예제 #4
0
    def LoadPlugins(cls):
        """Load all registered iotile.update_record plugins."""

        if cls.PLUGINS_LOADED:
            return

        reg = ComponentRegistry()
        for _, record in reg.load_extensions('iotile.update_record'):
            cls.RegisterRecordType(record)

        cls.PLUGINS_LOADED = True
예제 #5
0
    def _load_device(self, name, config):
        """Load a device either from a script or from an installed module"""

        if config is None:
            config_dict = {}
        elif isinstance(config, dict):
            config_dict = config
        elif config[0] == '#':
            # Allow passing base64 encoded json directly in the port string to ease testing.
            import base64
            config_str = str(base64.b64decode(config[1:]), 'utf-8')
            config_dict = json.loads(config_str)
        else:
            try:
                with open(config, "r") as conf:
                    data = json.load(conf)
            except IOError as exc:
                raise ArgumentError("Could not open config file",
                                    error=str(exc),
                                    path=config)

            if 'device' not in data:
                raise ArgumentError(
                    "Invalid configuration file passed to VirtualDeviceAdapter",
                    device_name=name,
                    config_path=config,
                    missing_key='device')

            config_dict = data['device']

        reg = ComponentRegistry()

        if name.endswith('.py'):
            _name, device_factory = reg.load_extension(
                name, class_filter=BaseVirtualDevice, unique=True)
            return _instantiate_virtual_device(device_factory, config_dict,
                                               self._loop)

        seen_names = []
        for device_name, device_factory in reg.load_extensions(
                'iotile.virtual_device',
                class_filter=BaseVirtualDevice,
                product_name="virtual_device"):
            if device_name == name:
                return _instantiate_virtual_device(device_factory, config_dict,
                                                   self._loop)

            seen_names.append(device_name)

        raise ArgumentError("Could not find virtual_device by name",
                            name=name,
                            known_names=seen_names)
예제 #6
0
    def __init__(self):

        self._recipe_actions = {}
        self._recipe_resources = {}
        self._recipes = {}

        reg = ComponentRegistry()
        for name, action in reg.load_extensions('iotile.recipe_action',
                                                product_name='build_step'):
            self._recipe_actions[name] = action

        for name, resource in reg.load_extensions('iotile.recipe_resource'):
            self._recipe_resources[name] = resource
예제 #7
0
def register_apps():
    reg = ComponentRegistry()
    reg.clear_extensions('iotile.app')
    reg.register_extension('iotile.app', 'app', FakeApp)

    yield

    reg.clear_extensions('iotile.app')
예제 #8
0
    def _build_type_map(cls):
        """Build a map of all of the known report format processors"""

        return {
            report_format.ReportType: report_format
            for _, report_format in ComponentRegistry().load_extensions(
                'iotile.report_format')
        }
예제 #9
0
    def __init__(self, args=None):
        super(ChainedAuthProvider, self).__init__(args)

        # FIXME: Allow overwriting default providers via args
        self._load_installed_providers()

        reg = ComponentRegistry()

        sub_providers = []
        for _, (priority, provider, provider_args
                ) in reg.load_extensions('iotile.default_auth_providers'):
            if provider not in self._auth_factories:
                raise ExternalError(
                    "Default authentication provider list references unknown auth provider",
                    provider_name=provider,
                    known_providers=self._auth_factories.keys())
            configured = self._auth_factories[provider](provider_args)
            sub_providers.append((priority, configured))

        sub_providers.sort(key=lambda x: x[0])
        self.providers = sub_providers
예제 #10
0
def instantiate_interface(virtual_iface, config):
    """Find a virtual interface by name and instantiate it

    Args:
        virtual_iface (string): The name of the pkg_resources entry point corresponding to
            the interface.  It should be in group iotile.virtual_interface
        config (dict): A dictionary with a 'interface' key with the config info for configuring
            this virtual interface.  This is optional.

    Returns:
        VirtualInterface: The instantiated subclass of VirtualInterface
    """

    # Allow the null virtual interface for testing
    if virtual_iface == 'null':
        return VirtualIOTileInterface()

    conf = {}
    if 'interface' in config:
        conf = config['interface']

    try:
        reg = ComponentRegistry()
        if virtual_iface.endswith('.py'):
            _name, iface = reg.load_extension(
                virtual_iface,
                class_filter=VirtualIOTileInterface,
                unique=True)
        else:
            _name, iface = reg.load_extensions(
                'iotile.virtual_interface',
                name_filter=virtual_iface,
                class_filter=VirtualIOTileInterface,
                unique=True)

        return iface(conf)
    except ArgumentError as err:
        print("ERROR: Could not load virtual interface (%s): %s" %
              (virtual_iface, err.msg))
        sys.exit(1)
예제 #11
0
def instantiate_device(virtual_dev, config, loop):
    """Find a virtual device by name and instantiate it

    Args:
        virtual_dev (string): The name of the pkg_resources entry point corresponding to
            the device.  It should be in group iotile.virtual_device.  If virtual_dev ends
            in .py, it is interpreted as a python script and loaded directly from the script.
        config (dict): A dictionary with a 'device' key with the config info for configuring
            this virtual device.  This is optional.

    Returns:
        BaseVirtualDevice: The instantiated subclass of BaseVirtualDevice
    """
    conf = {}
    if 'device' in config:
        conf = config['device']

    # If we're given a path to a script, try to load and use that rather than search for an installed module
    try:
        reg = ComponentRegistry()

        if virtual_dev.endswith('.py'):
            _name, dev = reg.load_extension(virtual_dev,
                                            class_filter=BaseVirtualDevice,
                                            unique=True)
        else:
            _name, dev = reg.load_extensions('iotile.virtual_device',
                                             name_filter=virtual_dev,
                                             class_filter=BaseVirtualDevice,
                                             product_name="virtual_device",
                                             unique=True)

        return dev(conf)
    except ArgumentError as err:
        print("ERROR: Could not load virtual device (%s): %s" %
              (virtual_dev, err.msg))
        sys.exit(1)
예제 #12
0
    def __init__(self, settings_file=None):
        self.rules = []

        logger = logging.getLogger('iotile.build.warnings')
        logger.addHandler(logging.NullHandler)

        #FIXME: Load settings_file

        #Find all registered default builders and load them in priority order
        #Each default resolver should be a 4-tuple with (priority, matching_regex, factory, default args)
        reg = ComponentRegistry()

        for name, resolver_entry in reg.load_extensions(
                'iotile.build.default_depresolver'):
            try:
                priority, regex, factory, settings = resolver_entry
            except TypeError:
                logger.warn(
                    'Invalid default resolver entry %s that was not a 4-tuple: %s',
                    name, str(resolver_entry))
                continue

            self.rules.append((priority, (regex, factory, settings)))

        self.rules.sort(key=lambda x: x[0])

        self._known_resolvers = {}
        for _, factory in reg.load_extensions('iotile.build.depresolver'):
            name = factory.__name__

            if name in self._known_resolvers:
                raise ExternalError(
                    "The same dependency resolver class name is provided by more than one entry point",
                    name=name)

            self._known_resolvers[name] = factory
예제 #13
0
def tile_based():
    conf_file = os.path.join(os.path.dirname(__file__), 'tile_config.json')

    if '@' in conf_file or ',' in conf_file or ';' in conf_file:
        pytest.skip('Cannot pass device config because path has [@,;] in it')

    reg = ComponentRegistry()
    reg.register_extension('iotile.proxy', 'virtual_tile',
                           'test/test_hw/virtual_tile.py')
    reg.register_extension('iotile.proxy', 'simple_virtual_tile',
                           'test/test_hw/simple_virtual_tile.py')

    hw = HardwareManager('virtual:tile_based@%s' % conf_file)
    yield hw

    reg.clear_extensions()
    hw.disconnect()
    hw.close()
예제 #14
0
def proxy_variants_2():
    conf_file = os.path.join(os.path.dirname(__file__),
                             'proxy_match_tile_config.json')

    if '@' in conf_file or ',' in conf_file or ';' in conf_file:
        pytest.skip('Cannot pass device config because path has [@,;] in it')

    reg = ComponentRegistry()
    # None, =1.0.0, ^1.0.0
    reg.register_extension('iotile.proxy', 'proxy_match_tile', ProxyMatchTest1)
    reg.register_extension('iotile.proxy', 'proxy_match_tile', ProxyMatchTest3)
    reg.register_extension('iotile.proxy', 'proxy_match_tile', ProxyMatchTest4)

    hw = HardwareManager('virtual:tile_based@%s' % conf_file)
    yield hw

    reg.clear_extensions()
    hw.close()
def linked_tile(rpc_agent, tmpdir):
    """Create a connected HardwareManager instance with a proxy pointed at an RPCDispatcher."""

    visor, _client1, _client2 = rpc_agent

    # Create a config file that we can use to initialize a virtual device that will point at our
    # BasicRPCDispatch via a running IOTileSupervisor.  Currently, HardwareManager can only
    # load configurations for virtual devices from actual files, so we need to save this to a
    # temp file.
    config = {
        "device": {
            "iotile_id":
            1,
            "tiles": [{
                "name": "service_delegate",
                "address": 11,
                "args": {
                    "url": "ws://127.0.0.1:%d/services" % visor.
                    port,  # This has to match the port of the supervisor instance that we want to connect to
                    "service":
                    "service_1",  # This has to match the service name that the RPCDispatcher is registered as an agent for
                    "name":
                    "bsctst"  # This is the 6 character string that must match the ModuleName() of the proxy and is used to find the right proxy
                }
            }]
        }
    }

    # This is a special py.path.local object from pytest
    # https://docs.pytest.org/en/latest/tmpdir.html
    config_path_obj = tmpdir.join('config.json')
    config_path_obj.write(json.dumps(config))

    config_path = str(config_path_obj)

    reg = ComponentRegistry()
    reg.register_extension('iotile.proxy', 'test_proxy',
                           BasicRPCDispatcherProxy)

    # This will create a HardwareManager pointed at a virtual tile based device
    # where the tiles that are added to the virtual device are found using the config
    # file specified after the @ symbol.
    hw = HardwareManager(port="virtual:tile_based@%s" % config_path)  # pylint:disable=invalid-name; We use hw throughout CoreTools to denote a HardwareManager instance

    # We specified that the virtual device should be at uuid 1 (using iotile_id above)
    # so we know how to connect to it.  We also know that we specified a single tile
    # at address 11 inside that virtual device so we will be able to get its proxy
    # object by calling hw.get(11) once we are connected.
    hw.connect(1)
    yield hw

    hw.disconnect()
    reg.clear_extensions('iotile.proxy')
예제 #16
0
def test_recording_rpcs(tmpdir):
    """Make sure we can record RPCs."""

    record_path = tmpdir.join('recording.csv')
    conf_file = os.path.join(os.path.dirname(__file__), 'tile_config.json')

    if '@' in conf_file or ',' in conf_file or ';' in conf_file:
        pytest.skip('Cannot pass device config because path has [@,;] in it')

    reg = ComponentRegistry()
    reg.register_extension('iotile.proxy', 'virtual_tile',
                           'test/test_hw/virtual_tile.py')

    try:
        with HardwareManager('virtual:tile_based@%s' % conf_file,
                             record=str(record_path)) as hw:
            hw.connect(1)

            con = hw.get(9)
            tile1 = hw.get(11)

            con.count()
            tile1.add(3, 5)
            tile1.count()
    finally:
        reg.clear_extensions()

    assert record_path.exists()

    rpcs = record_path.readlines(cr=False)
    assert len(rpcs) == 12
    assert rpcs[:3] == ['# IOTile RPC Recording', '# Format: 1.0', '']

    # Patch out the timestamps and run times for better comparison
    rpc_lines = [x.split(',') for x in rpcs[4:-1]]

    for rpc in rpc_lines:
        assert len(rpc) == 9
        rpc[1] = ""
        rpc[5] = ""

    rpc_lines = [",".join(x) for x in rpc_lines]

    print(rpc_lines[4])
    assert rpc_lines == [
        '1,, 9,0x0004,0xc0,,                                        ,ffff74657374303101000003                ,',
        '1,, 9,0x0004,0xc0,,                                        ,ffff74657374303101000003                ,',
        '1,,11,0x0004,0xc0,,                                        ,ffff74657374303101000003                ,',
        '1,,11,0x0004,0xc0,,                                        ,ffff74657374303101000003                ,',
        '1,, 9,0x8001,0xc0,,                                        ,00000000                                ,',
        '1,,11,0x8000,0xc0,,0300000005000000                        ,08000000                                ,',
        '1,,11,0x8001,0xc0,,                                        ,00000000                                ,'
    ]
예제 #17
0
    def LoadFromFile(cls, script_path):
        """Import a virtual tile from a file rather than an installed module

        script_path must point to a python file ending in .py that contains exactly one
        VirtualTile class definition.  That class is loaded and executed as if it
        were installed.

        To facilitate development, if there is a proxy object defined in the same
        file, it is also added to the HardwareManager proxy registry so that it
        can be found and used with the device.

        Args:
            script_path (string): The path to the script to load

        Returns:
            VirtualTile: A subclass of VirtualTile that was loaded from script_path
        """

        _name, dev = ComponentRegistry().load_extension(script_path, class_filter=VirtualTile, unique=True)
        return dev
예제 #18
0
    def _load_installed_providers(self):
        self._auth_factories = {}
        reg = ComponentRegistry()

        for name, entry in reg.load_extensions('iotile.auth_provider'):
            self._auth_factories[name] = entry
예제 #19
0
def _find_release_providers():
    reg = ComponentRegistry()
    return {
        name: entry
        for name, entry in reg.load_extensions('iotile.build.release_provider')
    }
예제 #20
0
def test_build_command():
    """Make sure iotile.build has been properly registered as a plugin."""

    reg = ComponentRegistry()
    plugs = reg.list_plugins()
    assert 'build' in plugs
예제 #21
0
def main(argv=None, loop=SharedLoop):
    """Serve access to a virtual IOTile device using a virtual iotile interface."""

    if argv is None:
        argv = sys.argv[1:]

    list_parser = argparse.ArgumentParser(add_help=False)
    list_parser.add_argument(
        '-l',
        '--list',
        action='store_true',
        help="List all known installed interfaces and devices and then exit")
    list_parser.add_argument(
        '-v',
        '--verbose',
        action="count",
        default=0,
        help="Increase logging level (goes error, warn, info, debug)")

    parser = argparse.ArgumentParser(
        description=
        "Serve acess to a virtual IOTile device using a virtual IOTile interface"
    )

    parser.add_argument('interface',
                        help="The name of the virtual device interface to use")
    parser.add_argument('device',
                        help="The name of the virtual device to create")
    parser.add_argument(
        '-c',
        '--config',
        help=
        "An optional JSON config file with arguments for the interface and device"
    )
    parser.add_argument(
        '-l',
        '--list',
        action='store_true',
        help="List all known installed interfaces and devices and then exit")
    parser.add_argument('-n',
                        '--scenario',
                        help="Load a test scenario from the given file")
    parser.add_argument(
        '-s',
        '--state',
        help=
        "Load a given state into the device before starting to serve it.  Only works with emulated devices."
    )
    parser.add_argument(
        '-d',
        '--dump',
        help=
        "Dump the device's state when we exit the program.  Only works with emulated devices."
    )
    parser.add_argument(
        '-t',
        '--track',
        help=
        "Track all changes to the device's state.  Only works with emulated devices."
    )
    parser.add_argument(
        '-v',
        '--verbose',
        action="count",
        default=0,
        help="Increase logging level (goes error, warn, info, debug)")

    args, _rest = list_parser.parse_known_args(argv)

    if args.list:
        configure_logging(args.verbose)

        reg = ComponentRegistry()
        print("Installed Device Servers:")
        for name, _iface in reg.load_extensions(
                'iotile.device_server', class_filter=AbstractDeviceServer):
            print('- {}'.format(name))

        print("\nInstalled Virtual Devices:")
        for name, dev in reg.load_extensions('iotile.virtual_device',
                                             class_filter=BaseVirtualDevice,
                                             product_name="virtual_device"):
            print('- {}: {}'.format(name, one_line_desc(dev)))

        return 0

    args = parser.parse_args(argv)

    configure_logging(args.verbose)

    config = {}
    if args.config is not None:
        with open(args.config, "r") as conf_file:
            config = json.load(conf_file)

    started = False
    device = None
    stop_immediately = args.interface == 'null'
    try:
        server = instantiate_interface(args.interface, config, loop)
        device = instantiate_device(args.device, config, loop)

        if args.state is not None:
            print("Loading device state from file %s" % args.state)
            device.load_state(args.state)

        if args.scenario is not None:
            print("Loading scenario from file %s" % args.scenario)

            with open(args.scenario, "r") as infile:
                scenario = json.load(infile)

            # load_metascenario expects a list of scenarios even when there is only one
            if isinstance(scenario, dict):
                scenario = [scenario]

            device.load_metascenario(scenario)

        if args.track is not None:
            print("Tracking all state changes to device")
            device.state_history.enable()

        adapter = VirtualDeviceAdapter(devices=[device], loop=loop)
        server.adapter = adapter

        loop.run_coroutine(adapter.start())

        try:
            loop.run_coroutine(server.start())
        except:
            loop.run_coroutine(adapter.stop())
            adapter = None
            raise

        started = True

        print("Starting to serve virtual IOTile device")

        if stop_immediately:
            return 0

        # We need to periodically process events that are queued up in the interface
        while True:
            time.sleep(0.5)

    except KeyboardInterrupt:
        print("Break received, cleanly exiting...")
    finally:
        if args.dump is not None and device is not None:
            print("Dumping final device state to %s" % args.dump)
            device.save_state(args.dump)

        if started:
            loop.run_coroutine(server.stop())
            loop.run_coroutine(adapter.stop())

        if args.track is not None and device is not None:
            print("Saving state history to file %s" % args.track)
            device.state_history.dump(args.track)

    return 0