Example #1
0
class SaveReportServerAction(AbstractServerAction):
    name = 'save-report'
    before_send = Signal('SaveReportServerAction.before_send')
    after_send = Signal('SaveReportServerAction.after_send')
    before_receive = Signal('SaveReportServerAction.before_receive')
    after_receive = Signal('SaveReportServerAction.after_receive')
    after_confirm = Signal('SaveReportServerAction.after_confirm')

    def execute(self, connection):
        with create_session() as session:
            client = session.query(Client).filter(
                Client.id == connection.client_id).first()
            report = Report(client=client)
            before_report_create.emit(session=session, report=report)
            session.add(report)
            session.flush()
            after_report_create.emit(session=session, report=report)

            values = self.payload['report']
            for name in reports_registry:
                value = values.get(name, None)
                before_report_value_create.emit(session=session,
                                                report_value=value)
                session.add(ReportValue(report=report, name=name, value=value))
                session.flush()
                after_report_value_create.emit(session=session,
                                               report_value=value)
Example #2
0
class SetCommand(AbstractCommand):
    name = 'set'
    help = 'Set config settings'
    before_run = Signal('SetCommand.before_run')
    after_run = Signal('SetCommand.after_run')

    @staticmethod
    def arguments(parser):
        group = parser.add_argument_group('settings')
        for name in sorted(settings_registry):
            setting = settings_registry[name]
            flag = '--{}'.format(name)
            metavar = name.rsplit('.', 1)[-1].upper()
            params = setting.add_argument_params()
            group.add_argument(flag,
                               metavar=metavar,
                               help=setting.help,
                               **params)

    def run(self, args):
        affected = []
        for name in settings_registry:
            value = getattr(args, name)
            if value is not None:
                affected.append(name)
                config.set(name, value)
        config.save()
        for name in affected:
            value = config.get(name)
            print('{}: {}'.format(name, value))
Example #3
0
class InstallCommand(AbstractCommand):
    name = 'install'
    help = 'Install Skywall frontend npm dependencies'
    before_run = Signal('InstallCommand.before_run')
    after_run = Signal('InstallCommand.after_run')

    def run(self, args):
        install_frontend()
Example #4
0
class BuildCommand(AbstractCommand):
    name = 'build'
    help = 'Build Skywall frontend'
    before_run = Signal('BuildCommand.before_run')
    after_run = Signal('BuildCommand.after_run')

    def run(self, args):
        build_frontend()
Example #5
0
class ClientCommand(AbstractCommand):
    name = 'client'
    help = 'Run skywall client'
    before_run = Signal('ClientCommand.before_run')
    after_run = Signal('ClientCommand.after_run')

    def run(self, args):
        config.validate(CLIENT_MODE)
        run_client()
Example #6
0
class PingClientAction(AbstractClientAction):
    name = 'example-ping'
    before_send = Signal('PingClientAction.before_send')
    after_send = Signal('PingClientAction.after_send')
    before_receive = Signal('PingClientAction.before_receive')
    after_receive = Signal('PingClientAction.after_receive')
    after_confirm = Signal('PingClientAction.after_confirm')

    def execute(self, client):
        print('PingClientAction', self.payload)
Example #7
0
class PongServerAction(AbstractServerAction):
    name = 'example-pong'
    before_send = Signal('PongServerAction.before_send')
    after_send = Signal('PongServerAction.after_send')
    before_receive = Signal('PongServerAction.before_receive')
    after_receive = Signal('PongServerAction.after_receive')
    after_confirm = Signal('PongServerAction.after_confirm')

    def execute(self, connection):
        print('PongServerAction', self.payload)
Example #8
0
class ServerCommand(AbstractCommand):
    name = 'server'
    help = 'Run skywall server'
    before_run = Signal('ServerCommand.before_run')
    after_run = Signal('ServerCommand.after_run')

    def run(self, args):
        config.validate(SERVER_MODE)
        connect_database()
        run_server()
Example #9
0
class SetIdClientAction(AbstractClientAction):
    name = 'set-id'
    before_send = Signal('SetIdClientAction.before_send')
    after_send = Signal('SetIdClientAction.after_send')
    before_receive = Signal('SetIdClientAction.before_receive')
    after_receive = Signal('SetIdClientAction.after_receive')
    after_confirm = Signal('SetIdClientAction.after_confirm')

    def execute(self, client):
        config.set('client.id', self.payload['client_id'])
        config.set('client.token', self.payload['client_token'])
        config.save()
Example #10
0
class SetLabelClientAction(AbstractClientAction):
    name = 'set-label'
    before_send = Signal('SetLabelClientAction.before_send')
    after_send = Signal('SetLabelClientAction.after_send')
    before_receive = Signal('SetLabelClientAction.before_receive')
    after_receive = Signal('SetLabelClientAction.after_receive')
    after_confirm = Signal('SetLabelClientAction.after_confirm')

    def execute(self, client):
        label = self.payload['label']
        config.set('client.label', label)
        config.save()
Example #11
0
class ExampleCommand(AbstractCommand):
    name = 'example-echo'
    help = 'Example Skywall module command'
    before_run = Signal('ExampleCommand.before_run')
    after_run = Signal('ExampleCommand.after_run')

    @staticmethod
    def arguments(parser):
        parser.add_argument('names',
                            metavar='names',
                            nargs='+',
                            help='Names to print')

    def run(self, args):
        print('This is example Skywall module command')
        example_signal.emit(value=args)
Example #12
0
class SaveLabelServerAction(AbstractServerAction):
    name = 'save-label'
    before_send = Signal('SaveLabelServerAction.before_send')
    after_send = Signal('SaveLabelServerAction.after_send')
    before_receive = Signal('SaveLabelServerAction.before_receive')
    after_receive = Signal('SaveLabelServerAction.after_receive')
    after_confirm = Signal('SaveLabelServerAction.after_confirm')

    def execute(self, connection):
        with create_session() as session:
            client = session.query(Client).filter(
                Client.id == connection.client_id).first()
            client.label = self.payload['label'] or ''
            before_client_update.emit(session=session, client=client)
            session.flush()
            after_client_update.emit(session=session, client=client)
Example #13
0
class GetCommand(AbstractCommand):
    name = 'get'
    help = 'Get config settings'
    before_run = Signal('GetCommand.before_run')
    after_run = Signal('GetCommand.after_run')

    @staticmethod
    def arguments(parser):
        parser.add_argument('names',
                            metavar='name',
                            nargs='*',
                            help='Name or prefix of names of settings to show')

    def run(self, args):
        for name in sorted(settings_registry):
            if _setting_matches_args(name, args.names):
                value = config.get(name)
                print('{}: {}'.format(name, value))
Example #14
0
from contextlib import contextmanager
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from skywall.core.config import config
from skywall.core.signals import Signal

Model = declarative_base()
_session = None

before_database_connect = Signal('before_database_connect')
after_database_connect = Signal('after_database_connect')


def connect_database():
    # pylint: disable=global-statement
    global _session
    before_database_connect.emit()
    database = config.get('server.database')
    engine = create_engine(database, echo=True)
    _session = sessionmaker(bind=engine)
    Model.metadata.create_all(engine)
    after_database_connect.emit()


@contextmanager
def create_session():
    session = _session()
    try:
        yield session
        session.commit()
Example #15
0
from skywall.core.config import config
from skywall.core.signals import Signal
from skywall.core.api import api_registry
from skywall.core.database import create_session
from skywall.core.actions import parse_server_action
from skywall.core.constants import CLIENT_ID_HEADER, CLIENT_TOKEN_HEADER, API_ROUTE, BUILD_ROUTE
from skywall.core.frontend import get_frontend, run_webpack
from skywall.core.utils import randomstring
from skywall.models.clients import Client, before_client_create, after_client_create
from skywall.models.connections import (Connection, before_connection_create,
                                        after_connection_create,
                                        before_connection_update,
                                        after_connection_update)
from skywall.actions.clientid import SetIdClientAction

before_server_start = Signal('before_server_start')
after_server_start = Signal('after_server_start')
before_server_stop = Signal('before_server_stop')
after_server_stop = Signal('after_server_stop')

before_server_connection_open = Signal('before_server_connection_open')
after_server_connection_open = Signal('after_server_connection_open')
before_server_connection_close = Signal('before_server_connection_close')
after_server_connection_close = Signal('after_server_connection_close')
after_server_connection_ended = Signal('after_server_connection_ended')

before_client_action_send = Signal('before_client_action_send')
after_client_action_send = Signal('after_client_action_send')
after_client_action_confirm = Signal('after_client_action_confirm')

before_server_action_receive = Signal('before_server_action_receive')
Example #16
0
import os
import re
from ruamel import yaml
from skywall.core.settings import settings_registry
from skywall.core.signals import Signal

before_config_load = Signal('before_config_load')
after_config_load = Signal('after_config_load')
before_config_save = Signal('before_config_save')
after_config_save = Signal('after_config_save')


class Config:
    data = None

    def load(self):
        before_config_load.emit(config=self)
        try:
            with open('config.yaml', 'r') as f:
                self.data = yaml.round_trip_load(f)
        except FileNotFoundError:
            self.data = None
        after_config_load.emit(config=self)

    def save(self):
        before_config_save.emit(config=self)
        with open('config.yaml', 'w') as f:
            yaml.round_trip_dump(self.data, f)
        after_config_save.emit(config=self)

    def validate(self, mode):
Example #17
0
import re
from aiohttp.web import json_response, HTTPBadRequest
from sqlalchemy.exc import IntegrityError
from skywall.core.signals import Signal
from skywall.core.api import register_api, parse_json_body, assert_request_param_is_string
from skywall.core.database import create_session
from skywall.models.groups import Group, before_group_create, after_group_create

before_add_group = Signal('before_add_group')
after_add_group = Signal('after_add_group')


@register_api('POST', '/groups', before_add_group, after_add_group)
async def add_group(request):
    """
    ---
    tags:
      - Skywall Core
    summary: Add group
    description: Creates a new group
    produces:
      - application/json
    parameters:
      - name: body
        in: body
        description: Group properties to be saved
        required: true
        schema:
          type: object
          title: PostGroupBody
          required:
Example #18
0
from functools import wraps
from collections import namedtuple
from aiohttp.web import HTTPBadRequest, HTTPNotFound
from skywall.core.signals import Signal


Api = namedtuple('Api', ['method', 'path', 'handler'])
api_registry = []

before_api_call = Signal('before_api_call')
after_api_call = Signal('after_api_call')


def register_api(method, path, before_call, after_call):
    def decorator(handler):
        @wraps(handler)
        async def signaled_handler(request):
            before_api_call.emit(api=api, request=request)
            before_call.emit(api=api, request=request)
            try:
                response = await handler(request)
                after_call.emit(api=api, request=request, response=response, exception=None)
                after_api_call.emit(api=api, request=request, response=response, exception=None)
                return response
            except Exception as e:
                after_call.emit(api=api, request=request, response=None, exception=e)
                after_api_call.emit(api=api, request=request, response=None, exception=e)
                raise
        api = Api(method, path, signaled_handler)
        api_registry.append(api)
        return signaled_handler
Example #19
0
from sqlalchemy import Column, Integer, String, TIMESTAMP, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql.functions import current_timestamp
from skywall.core.database import Model
from skywall.core.signals import Signal

before_client_create = Signal('before_client_create')
after_client_create = Signal('after_client_create')
before_client_update = Signal('before_client_update')
after_client_update = Signal('after_client_update')


class Client(Model):
    __tablename__ = 'client'

    id = Column(Integer, primary_key=True)
    created = Column(TIMESTAMP(timezone=True),
                     nullable=False,
                     server_default=current_timestamp())
    token = Column(String, nullable=False)
    label = Column(String, nullable=False, server_default='')
    group_id = Column(Integer, ForeignKey('group.id'), nullable=True)

    group = relationship('Group', back_populates='clients')
    reports = relationship('Report', back_populates='client')
    connections = relationship('Connection', back_populates='client')

    def __repr__(self):
        return '<Client id={0.id} label={0.label}>'.format(self)
Example #20
0
from sqlalchemy import Column, Integer, TIMESTAMP, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql.functions import current_timestamp
from skywall.core.database import Model
from skywall.core.signals import Signal

before_connection_create = Signal('before_connection_create')
after_connection_create = Signal('after_connection_create')
before_connection_update = Signal('before_connection_update')
after_connection_update = Signal('after_connection_update')


class Connection(Model):
    __tablename__ = 'connection'

    id = Column(Integer, primary_key=True)
    created = Column(TIMESTAMP(timezone=True),
                     nullable=False,
                     server_default=current_timestamp())
    client_id = Column(Integer, ForeignKey('client.id'), nullable=False)
    last_activity = Column(TIMESTAMP(timezone=True),
                           nullable=False,
                           server_default=current_timestamp())
    closed = Column(TIMESTAMP(timezone=True), nullable=True)

    client = relationship('Client', back_populates='connections')

    def __repr__(self):
        return '<Report id={0.id} client_id={0.client_id}>'.format(self)
Example #21
0
from aiohttp.web import json_response, HTTPServiceUnavailable
from skywall.core.signals import Signal
from skywall.core.api import (
    register_api,
    parse_json_body,
    parse_obj_path_param,
    assert_request_param_is_string,
    assert_request_param_is_entity,
)
from skywall.core.database import create_session
from skywall.core.server import get_server
from skywall.models.groups import Group
from skywall.models.clients import Client, before_client_update, after_client_update
from skywall.actions.labels import SetLabelClientAction

before_update_client = Signal('before_update_client')
after_update_client = Signal('after_update_client')


async def _send_label_to_client(client_id, label):
    connection = get_server().get_connection(client_id)
    if not connection:
        reason = 'Changing label failed. Client {} is not connected right now.'.format(
            client_id)
        raise HTTPServiceUnavailable(reason=reason)
    try:
        await connection.check_send_action(SetLabelClientAction(label=label))
    except asyncio.TimeoutError:
        reason = 'Changing label failed. Client {} is not responding right now.'.format(
            client_id)
        raise HTTPServiceUnavailable(reason=reason)
Example #22
0
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import relationship
from skywall.core.database import Model
from skywall.core.signals import Signal
from skywall.models.clients import Client

before_group_create = Signal('before_group_create')
after_group_create = Signal('after_group_create')
before_group_update = Signal('before_group_update')
after_group_update = Signal('after_group_update')
before_group_delete = Signal('before_group_delete')
after_group_delete = Signal('after_group_delete')


class Group(Model):
    __tablename__ = 'group'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)
    description = Column(String, nullable=False, server_default='')

    clients = relationship('Client', back_populates='group')

    def __repr__(self):
        return '<Group id={0.id} name={0.name}>'.format(self)


def get_group_clients(session, group):
    """
    We can't use directly `group.clients` for the DEFAULT group because it is represented by `None`. Unless we are
    sure the group is not DEFAULT, we must use `get_group_clients(session, group)` instead.
Example #23
0
from skywall.core.signals import Signal


example_signal = Signal('example_signal')


@example_signal.connect
def example_signal_listener(value):
    print('Received example signal: {}'.format(value))
Example #24
0
import asyncio
from aiohttp import ClientSession, WSCloseCode, WSMsgType, ClientConnectionError, WSServerHandshakeError
from skywall.core.constants import ACTION_CONFIRM_TIMEOUT, CLIENT_RECONECT_INTERVAL
from skywall.core.config import config
from skywall.core.signals import Signal
from skywall.core.actions import parse_client_action
from skywall.core.reports import collect_report
from skywall.core.constants import CLIENT_ID_HEADER, CLIENT_TOKEN_HEADER
from skywall.actions.reports import SaveReportServerAction
from skywall.actions.labels import SaveLabelServerAction


before_client_start = Signal('before_client_start')
after_client_start = Signal('after_client_start')
before_client_stop = Signal('before_client_stop')
after_client_stop = Signal('after_client_stop')

before_client_action_receive = Signal('before_client_action_receive')
after_client_action_receive = Signal('after_client_action_receive')

before_server_action_send = Signal('before_server_action_send')
after_server_action_send = Signal('after_server_action_send')
after_server_action_confirm = Signal('after_server_action_confirm')


class WebsocketClient:

    def __init__(self, loop):
        self.url = config.get('server.publicUrl')
        self.client_id = config.get('client.id')
        self.client_token = config.get('client.token')
Example #25
0
from aiohttp.web import json_response
from skywall.core.signals import Signal
from skywall.core.api import register_api, parse_obj_path_param
from skywall.core.database import create_session
from skywall.models.groups import Group, before_group_delete, after_group_delete


before_delete_group = Signal('before_delete_group')
after_delete_group = Signal('after_delete_group')


@register_api('DELETE', '/groups/{groupId}', before_delete_group, after_delete_group)
async def delete_group(request):
    """
    ---
    tags:
      - Skywall Core
    summary: Delete group
    description: Deletes an existing group
    produces:
      - application/json
    parameters:
      - name: groupId
        in: path
        description: ID of group to delete
        required: true
        type: integer
    responses:
      200:
        description: Group deleted
        schema:
Example #26
0
import os
import argparse
from skywall.core.config import config
from skywall.core.modules import import_enabled_modules
from skywall.core.commands import commands_registry
from skywall.core.signals import Signal

before_command_run = Signal('before_command_run')
after_command_run = Signal('after_command_run')


def assert_virtualenv():
    if not os.environ.get('VIRTUAL_ENV'):
        raise NotImplementedError(
            'Running Skywall outside a virtualenv is not supported')


def change_to_workdir():
    workdir = os.path.dirname(os.environ.get('VIRTUAL_ENV'))
    os.chdir(workdir)


def parse_args():
    desc = 'Client-Server based manager for connecting systems together and running tasks.'
    parser = argparse.ArgumentParser(description=desc)
    subparsers = parser.add_subparsers(dest='command', metavar='command')
    subparsers.required = True
    for command_name in sorted(commands_registry):
        command = commands_registry[command_name]
        subparser = subparsers.add_parser(command.name, help=command.help)
        command.arguments(subparser)
Example #27
0
from sqlalchemy import Column, Integer, String, TIMESTAMP, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql.functions import current_timestamp
from sqlalchemy.dialects.postgresql import JSONB
from skywall.core.database import Model
from skywall.core.signals import Signal

before_report_create = Signal('before_report_create')
after_report_create = Signal('after_report_create')

before_report_value_create = Signal('before_report_value_create')
after_report_value_create = Signal('after_report_value_create')


class Report(Model):
    __tablename__ = 'report'

    id = Column(Integer, primary_key=True)
    created = Column(TIMESTAMP(timezone=True),
                     nullable=False,
                     server_default=current_timestamp())
    client_id = Column(Integer, ForeignKey('client.id'), nullable=False)

    client = relationship('Client', back_populates='reports')
    values = relationship('ReportValue', back_populates='report')

    def __repr__(self):
        return '<Report id={0.id} client_id={0.client_id}>'.format(self)


class ReportValue(Model):
Example #28
0
from aiohttp.web import json_response
from skywall.core.database import create_session
from skywall.core.signals import Signal
from skywall.core.api import register_api
from skywall_example.models.example import Example, before_example_create, after_example_create

before_get_example = Signal('before_get_example')
after_get_example = Signal('before_get_example')


@register_api('GET', '/example', before_get_example, after_get_example)
async def get_example(request):
    """
    ---
    tags:
      - Example module
    summary: Example API
    description: Example Skywall module API endpoint
    produces:
      - application/json
    responses:
      200:
        description: Example response
        schema:
          type: object
          title: GetExample
          required:
            - message
          properties:
            message:
              type: string
Example #29
0
from aiohttp.web import json_response
from sqlalchemy import desc
from skywall.core.api import register_api
from skywall.core.signals import Signal
from skywall.core.database import create_session
from skywall.core.reports import reports_registry
from skywall.core.server import get_server
from skywall.models.clients import Client
from skywall.models.groups import Group
from skywall.models.connections import Connection
from skywall.models.reports import Report, ReportValue


before_get_clients = Signal('before_get_clients')
after_get_clients = Signal('after_get_clients')


def _client_response(client):
    return {
            'id': client.id,
            'created': client.created.timestamp(),
            'label': client.label,
            'groupId': client.group_id,
            'connected': get_server().get_connection(client.id) is not None,
            }

def _clients_response(clients):
    return [_client_response(client) for client in clients]

def _group_response(group):
    return {
Example #30
0
import re
from aiohttp.web import json_response, HTTPBadRequest
from sqlalchemy.exc import IntegrityError
from skywall.core.signals import Signal
from skywall.core.api import register_api, parse_json_body, parse_obj_path_param, assert_request_param_is_string
from skywall.core.database import create_session
from skywall.models.groups import Group, before_group_update, after_group_update

before_update_group = Signal('before_update_group')
after_update_group = Signal('after_update_group')


@register_api('PUT', '/groups/{groupId}', before_update_group,
              after_update_group)
async def update_group(request):
    """
    ---
    tags:
      - Skywall Core
    summary: Update group
    description: Updates an existing group
    produces:
      - application/json
    parameters:
      - name: groupId
        in: path
        description: ID of group to update
        required: true
        type: integer
      - name: body
        in: body