コード例 #1
0
def build(args):
    global workdir

    ports = set()
    deps = set()

    parser = argparse.ArgumentParser(prog='platydock build',
                                     description='Build a Platypush image ' +
                                     'from a config.yaml')

    parser.add_argument('-c',
                        '--config',
                        type=str,
                        required=True,
                        help='Path to the platypush configuration file')

    opts, args = parser.parse_known_args(args)

    cfgfile = os.path.abspath(os.path.expanduser(opts.config))
    Config.init(cfgfile)
    register_backends()
    backend_config = Config.get_backends()

    if backend_config.get('http'):
        http_backend = get_backend('http')
        ports.add(http_backend.port)
        if http_backend.websocket_port:
            ports.add(http_backend.websocket_port)

    if backend_config.get('tcp'):
        ports.add(get_backend('tcp').port)

    if backend_config.get('websocket'):
        ports.add(get_backend('websocket').port)

    for name in Config.get_backends().keys():
        deps.update(_parse_deps(get_backend(name)))

    for name in Config.get_plugins().keys():
        try:
            deps.update(_parse_deps(get_plugin(name)))
        except:
            pass

    devdir = os.path.join(workdir, Config.get('device_id'))
    generate_dockerfile(deps=deps, ports=ports, cfgfile=cfgfile, devdir=devdir)

    subprocess.call([
        'docker', 'build', '-t',
        'platypush-{}'.format(Config.get('device_id')), devdir
    ])
コード例 #2
0
ファイル: manifest.py プロジェクト: BlackLight/platypush
def get_manifests_from_conf(
        conf_file: Optional[str] = None) -> Mapping[str, Manifest]:
    import platypush
    from platypush.config import Config

    conf_args = []
    if conf_file:
        conf_args.append(conf_file)

    Config.init(*conf_args)
    app_dir = os.path.dirname(inspect.getfile(platypush))
    manifest_files = set()

    for name in Config.get_backends().keys():
        manifest_files.add(
            os.path.join(app_dir, 'backend', *name.split('.'),
                         'manifest.yaml'))

    for name in Config.get_plugins().keys():
        manifest_files.add(
            os.path.join(app_dir, 'plugins', *name.split('.'),
                         'manifest.yaml'))

    return {
        manifest_file: Manifest.from_file(manifest_file)
        for manifest_file in manifest_files
    }
コード例 #3
0
def build(args):
    global workdir

    ports = set()
    parser = argparse.ArgumentParser(
        prog='platydock build',
        description='Build a Platypush image from a config.yaml')

    parser.add_argument('-c',
                        '--config',
                        type=str,
                        required=True,
                        help='Path to the platypush configuration file')
    parser.add_argument('-p',
                        '--python-version',
                        type=str,
                        default='3.9',
                        help='Python version to be used')

    opts, args = parser.parse_known_args(args)

    cfgfile = os.path.abspath(os.path.expanduser(opts.config))
    manifest._available_package_manager = 'apt'  # Force apt for Debian-based Docker images
    install_cmds = manifest.get_dependencies_from_conf(cfgfile)
    python_version = opts.python_version
    backend_config = Config.get_backends()

    # Container exposed ports
    if backend_config.get('http'):
        from platypush.backend.http import HttpBackend
        # noinspection PyProtectedMember
        ports.add(backend_config['http'].get('port',
                                             HttpBackend._DEFAULT_HTTP_PORT))
        # noinspection PyProtectedMember
        ports.add(backend_config['http'].get(
            'websocket_port', HttpBackend._DEFAULT_WEBSOCKET_PORT))

    if backend_config.get('tcp'):
        ports.add(backend_config['tcp']['port'])

    if backend_config.get('websocket'):
        from platypush.backend.websocket import WebsocketBackend
        # noinspection PyProtectedMember
        ports.add(backend_config['websocket'].get(
            'port', WebsocketBackend._default_websocket_port))

    dev_dir = os.path.join(workdir, Config.get('device_id'))
    generate_dockerfile(deps=dict(install_cmds),
                        ports=ports,
                        cfgfile=cfgfile,
                        device_dir=dev_dir,
                        python_version=python_version)

    subprocess.call([
        'docker', 'build', '-t',
        'platypush-{}'.format(Config.get('device_id')), dev_dir
    ])
コード例 #4
0
ファイル: __init__.py プロジェクト: jamesagada/platypush
    def notify_web_clients(self, event):
        backends = Config.get_backends()
        if 'http' not in backends: return

        backend = get_backend('http')
        if backend:
            backend.notify_web_clients(event)

        backend = get_backend('websocket')
        if backend:
            backend.notify_web_clients(event)
コード例 #5
0
def index():
    """ Route to the main web panel """
    configured_plugins = Config.get_plugins()
    enabled_templates = {}
    enabled_scripts = {}
    enabled_styles = {}

    js_folder = os.path.abspath(
        os.path.join(template_folder, '..', 'static', 'js'))
    style_folder = os.path.abspath(
        os.path.join(template_folder, '..', 'static', 'css', 'dist'))

    for plugin, conf in configured_plugins.items():
        template_file = os.path.join(template_folder, 'plugins', plugin,
                                     'index.html')

        script_file = os.path.join(js_folder, 'plugins', plugin, 'index.js')
        style_file = os.path.join(style_folder, 'webpanel', 'plugins',
                                  plugin + '.css')

        if os.path.isfile(template_file):
            conf['_template_file'] = '/' + '/'.join(
                template_file.split(os.sep)[-3:])
            enabled_templates[plugin] = conf

        if os.path.isfile(script_file):
            conf['_script_file'] = '/'.join(script_file.split(os.sep)[-4:])
            enabled_scripts[plugin] = conf

        if os.path.isfile(style_file):
            conf['_style_file'] = 'css/dist/' + style_file[len(style_folder) +
                                                           1:]
            enabled_styles[plugin] = conf

    http_conf = Config.get('backend.http')
    return render_template('index.html',
                           templates=enabled_templates,
                           scripts=enabled_scripts,
                           styles=enabled_styles,
                           utils=HttpUtils,
                           token=Config.get('token'),
                           websocket_port=get_websocket_port(),
                           template_folder=template_folder,
                           static_folder=static_folder,
                           plugins=Config.get_plugins(),
                           backends=Config.get_backends(),
                           has_ssl=http_conf.get('ssl_cert') is not None)
コード例 #6
0
 def setUp(self):
     logging.basicConfig(level=logging.INFO, stream=sys.stdout)
     backends = Config.get_backends()
     self.assertTrue('http' in backends)
コード例 #7
0
def generate_dockerfile(deps, ports, cfgfile, device_dir, python_version):
    device_id = Config.get('device_id')
    if not device_id:
        raise RuntimeError(
            ('You need to specify a device_id in {} - Docker ' +
             'containers cannot rely on hostname').format(cfgfile))

    os.makedirs(device_dir, exist_ok=True)
    content = textwrap.dedent('''
        FROM python:{python_version}-slim-bullseye

        RUN mkdir -p /app
        RUN mkdir -p /etc/platypush
        RUN mkdir -p /usr/local/share/platypush\n
        '''.format(python_version=python_version)).lstrip()

    srcdir = os.path.dirname(cfgfile)
    cfgfile_copy = os.path.join(device_dir, 'config.yaml')
    shutil.copy(cfgfile, cfgfile_copy, follow_symlinks=True)
    content += 'COPY config.yaml /etc/platypush/\n'
    backend_config = Config.get_backends()

    # Redis configuration for Docker
    if 'redis' not in backend_config:
        backend_config['redis'] = {
            'redis_args': {
                'host': 'redis',
                'port': 6379,
            }
        }

        with open(cfgfile_copy, 'a') as f:
            f.write('\n# Automatically added by platydock, do not remove\n' +
                    yaml.dump({
                        'backend.redis': backend_config['redis'],
                    }) + '\n')

    # Main database configuration
    has_main_db = False
    with open(cfgfile_copy, 'r') as f:
        for line in f.readlines():
            if re.match(r'^(main.)?db.*', line):
                has_main_db = True
                break

    if not has_main_db:
        with open(cfgfile_copy, 'a') as f:
            f.write(
                '\n# Automatically added by platydock, do not remove\n' +
                yaml.dump({'main.db': {
                    'engine': 'sqlite:////platypush.db',
                }}) + '\n')

    # Copy included files
    # noinspection PyProtectedMember
    for include in Config._included_files:
        incdir = os.path.relpath(os.path.dirname(include), srcdir)
        destdir = os.path.join(device_dir, incdir)
        pathlib.Path(destdir).mkdir(parents=True, exist_ok=True)
        shutil.copy(include, destdir, follow_symlinks=True)
        content += 'RUN mkdir -p /etc/platypush/' + incdir + '\n'
        content += 'COPY ' + os.path.relpath(include, srcdir) + \
                   ' /etc/platypush/' + incdir + '\n'

    # Copy script files
    scripts_dir = os.path.join(os.path.dirname(cfgfile), 'scripts')
    if os.path.isdir(scripts_dir):
        local_scripts_dir = os.path.join(device_dir, 'scripts')
        remote_scripts_dir = '/etc/platypush/scripts'
        shutil.copytree(scripts_dir,
                        local_scripts_dir,
                        symlinks=True,
                        dirs_exist_ok=True)
        content += f'RUN mkdir -p {remote_scripts_dir}\n'
        content += f'COPY scripts/ {remote_scripts_dir}\n'

    packages = deps.pop('packages', None)
    pip = deps.pop('pip', None)
    exec_cmds = deps.pop('exec', None)
    pkg_cmd = f'\n\t&& apt-get install --no-install-recommends -y {" ".join(packages)} \\' if packages else ''
    pip_cmd = f'\n\t&& pip install {" ".join(pip)} \\' if pip else ''
    content += f'''
RUN dpkg --configure -a \\
    && apt-get -f install \\
    && apt-get --fix-missing install \\
    && apt-get clean \\
    && apt-get update \\
    && apt-get -y upgrade \\
    && apt-get -y dist-upgrade \\
    && apt-get install --no-install-recommends -y apt-utils \\
    && apt-get install --no-install-recommends -y build-essential \\
    && apt-get install --no-install-recommends -y git \\
    && apt-get install --no-install-recommends -y sudo \\
    && apt-get install --no-install-recommends -y libffi-dev \\
    && apt-get install --no-install-recommends -y libcap-dev \\
    && apt-get install --no-install-recommends -y libjpeg-dev \\{pkg_cmd}{pip_cmd}'''

    for exec_cmd in exec_cmds:
        content += f'\n\t&& {exec_cmd} \\'
    content += '''
    && apt-get install --no-install-recommends -y zlib1g-dev

RUN git clone --recursive https://git.platypush.tech/platypush/platypush.git /app \\
    && cd /app \\
    && pip install -r requirements.txt

RUN apt-get remove -y git \\
    && apt-get remove -y build-essential \\
    && apt-get remove -y libffi-dev \\
    && apt-get remove -y libjpeg-dev \\
    && apt-get remove -y libcap-dev \\
    && apt-get remove -y zlib1g-dev \\
    && apt-get remove -y apt-utils \\
    && apt-get clean \\
    && apt-get autoremove -y \\
    && rm -rf /var/lib/apt/lists/*
'''

    for port in ports:
        content += 'EXPOSE {}\n'.format(port)

    content += textwrap.dedent('''

        ENV PYTHONPATH /app:$PYTHONPATH
        CMD ["python", "-m", "platypush"]
        ''')

    dockerfile = os.path.join(device_dir, 'Dockerfile')
    print('Generating Dockerfile {}'.format(dockerfile))

    with open(dockerfile, 'w') as f:
        f.write(content)
コード例 #8
0
ファイル: index.py プロジェクト: lopeben/platypush
def index():
    """ Route to the main web panel """
    configured_plugins = Config.get_plugins()
    enabled_templates = {}
    enabled_scripts = {}
    enabled_styles = {}

    enabled_plugins = set(request.args.get('enabled_plugins', '').split(','))
    for plugin in enabled_plugins:
        if plugin not in configured_plugins:
            configured_plugins[plugin] = {}

    configured_plugins['execute'] = {}
    disabled_plugins = set(request.args.get('disabled_plugins', '').split(','))

    js_folder = os.path.abspath(
        os.path.join(template_folder, '..', 'static', 'js'))
    style_folder = os.path.abspath(
        os.path.join(template_folder, '..', 'static', 'css', 'dist'))

    for plugin, conf in configured_plugins.copy().items():
        if plugin in disabled_plugins:
            if plugin == 'execute':
                configured_plugins.pop('execute')
            continue

        template_file = os.path.join(template_folder, 'plugins', plugin,
                                     'index.html')

        script_file = os.path.join(js_folder, 'plugins', plugin, 'index.js')
        style_file = os.path.join(style_folder, 'webpanel', 'plugins',
                                  plugin + '.css')

        if os.path.isfile(template_file):
            conf['_template_file'] = '/' + '/'.join(
                template_file.split(os.sep)[-3:])
            enabled_templates[plugin] = conf

        if os.path.isfile(script_file):
            conf['_script_file'] = '/'.join(script_file.split(os.sep)[-4:])
            enabled_scripts[plugin] = conf

        if os.path.isfile(style_file):
            conf['_style_file'] = 'css/dist/' + style_file[len(style_folder) +
                                                           1:]
            enabled_styles[plugin] = conf

    http_conf = Config.get('backend.http')
    return render_template('index.html',
                           templates=enabled_templates,
                           scripts=enabled_scripts,
                           styles=enabled_styles,
                           utils=HttpUtils,
                           token=Config.get('token'),
                           websocket_port=get_websocket_port(),
                           template_folder=template_folder,
                           static_folder=static_folder,
                           plugins=Config.get_plugins(),
                           backends=Config.get_backends(),
                           procedures=json.dumps(Config.get_procedures(),
                                                 cls=Message.Encoder),
                           has_ssl=http_conf.get('ssl_cert') is not None)