Пример #1
0
def generate_cf_dynamo_schema(target):
    dynamo_connection = DynamoDBConnection()

    class FakeClient(object):
        def create_table(self, *args, **kwargs):
            write_schema_to_yaml(target, **kwargs)
            return {}

    client = FakeClient()
    dynamo_connection.client = client

    class FakeDynamo(object):
        def list_tables(self):
            return []

        def create_table(self, *args):
            result = dynamo_connection.create_table(*args)

        def describe_table(self, *args):
            StatusStruct = namedtuple('Status', 'status')
            return StatusStruct(status='ACTIVE')

    dynamo = FakeDynamo()
    engine = Engine()
    engine.dynamo = dynamo

    sys.path = ['{}/app/models'.format(target)] + sys.path
    modelModules = glob.glob('{}/app/models'.format(target) + '/*.py')
    models = [basename(f)[:-3] for f in modelModules if isfile(f)]
    for modelName in models:
        if modelName != '__init__':
            engine.register(getattr(importlib.__import__(modelName),
                                    modelName))

    engine.create_schema()
Пример #2
0
def rundb(target):
    """
    Start running a local DynamoDB instance.

    :param target:
    :return:
    """
    load_env(target)
    os.environ['AWS_REGION'] = 'us-west-2'
    shared_db = './dynamo_db/shared-local-instance.db'
    if os.path.exists(shared_db):
        os.remove(shared_db)
    dynamo_command = [
        'java',
        '-Djava.library.path={}/dynamo_db/DynamoDBLocal_lib'.format(CWD),
        '-jar', '{}/dynamo_db/DynamoDBLocal.jar'.format(CWD), '-sharedDb',
        '-dbPath', './dynamo_db'
    ]
    try:
        dynamo_process = subprocess.Popen(dynamo_command,
                                          stdin=subprocess.PIPE,
                                          stderr=subprocess.STDOUT)
    except Exception as e:
        pass
    try:
        '''
        Connect to DynamoDB and register and create tables for application models.
        '''
        engine = Engine()
        engine.connect(os.environ['AWS_REGION'],
                       host='localhost',
                       port=8000,
                       access_key='anything',
                       secret_key='anything',
                       is_secure=False)
        # load models
        sys.path = ['./app/models'] + sys.path
        modelModules = glob.glob('./app/models' + "/*.py")
        models = [basename(f)[:-3] for f in modelModules if isfile(f)]
        for modelName in models:
            if modelName != '__init__':
                engine.register(getattr(__import__(modelName), modelName))
        engine.create_schema()
        tables = [table for table in engine.dynamo.list_tables()]
        print("This engine has the following tables " + str(tables))
        for table in tables:
            engine.dynamo.describe_table(table)
    except Exception as e:
        # IF anything goes wrong, then we self-destruct.
        dynamo_process.kill()
        raise e
    # Wait for process to finish.
    dynamo_process.wait()
Пример #3
0
def write_data(namepsace: str, val3_base: str, port: int) -> None:
    db = Engine(namespace=namepsace)
    db.connect(
        'local',
        access_key='AK',
        secret_key='SK',
        host='localhost',
        port=port,
        is_secure=False,
    )

    db.register(Data)
    db.create_schema()

    started = datetime.utcnow()
    db.save(items=[
        Data(id=str(i), val1=str(i), val2=i, val3=f'{val3_base}-{i}') for i in range(100)
    ])
    elapsed = datetime.utcnow() - started
    print(f'{namepsace} elapsed time: {elapsed}')
Пример #4
0
def setup_dynamodb(models,
                   region=DB_REGION,
                   access_key=DB_KEY,
                   secret_key=DB_SECRET,
                   host=DB_HOST,
                   port=DB_PORT,
                   is_secure=DB_SECURE):
    """
    Setups DynamoDB Local and registers flywheel models.

    Parameters:
        models : list
            List of flywheel models to register
        region : str, optional
        access_key : str, optional
        secret_key : str, optional
        host : str, optional
        port : int, optional
        is_secure : bool, optional
    """
    # Create an engine and connect to DynamoDB Local
    engine = Engine()
    engine.connect(region,
                   access_key=access_key,
                   secret_key=secret_key,
                   host=host,
                   port=port,
                   is_secure=is_secure)

    # Register models with the engine so it can create Dynamo tables
    engine.register(*models)

    # Drop any existing schema in the database, so we can sync it up with
    # current schema. This is only for development.
    engine.delete_schema()

    # Create the dynamo table for our registered models
    engine.create_schema()
    return engine
Пример #5
0
def setup_dynamodb(models, region=DB_REGION, access_key=DB_KEY,
                   secret_key=DB_SECRET, host=DB_HOST, port=DB_PORT,
                   is_secure=DB_SECURE):
    """
    Setups DynamoDB Local and registers flywheel models.

    Parameters:
        models : list
            List of flywheel models to register
        region : str, optional
        access_key : str, optional
        secret_key : str, optional
        host : str, optional
        port : int, optional
        is_secure : bool, optional
    """
    # Create an engine and connect to DynamoDB Local
    engine = Engine()
    engine.connect(
        region,
        access_key=access_key,
        secret_key=secret_key,
        host=host,
        port=port,
        is_secure=is_secure
    )

    # Register models with the engine so it can create Dynamo tables
    engine.register(*models)

    # Drop any existing schema in the database, so we can sync it up with
    # current schema. This is only for development.
    engine.delete_schema()

    # Create the dynamo table for our registered models
    engine.create_schema()
    return engine
Пример #6
0
# -*- coding: utf-8 -*-
from flywheel import Engine

from werewolf.domain.user import *
from werewolf.domain.game import *
from werewolf.domain.game.repository import *


engine = Engine()
engine.connect_to_host(host='localhost', port=8000, is_secure=False)

engine.register(User)
engine.register(UserCredential)
engine.register(ClientSession)
engine.register(AccessToken)
engine.register(RefreshToken)
engine.register(VillageModel)
engine.register(ResidentModel)
engine.register(BehaviorModel)
engine.register(EventModel)

engine.create_schema()

repo_village = VillageRepository(engine)

repo_village.add(u'PyConJP 村')
repo_village.add(u'ペンギン村')
Пример #7
0
# -*- coding: utf-8 -*-
from flywheel import Engine

from werewolf.domain.user import *
from werewolf.domain.game import *
from werewolf.domain.game.repository import *

engine = Engine()
engine.connect_to_host(host='localhost', port=8000, is_secure=False)

engine.register(User)
engine.register(UserCredential)
engine.register(ClientSession)
engine.register(AccessToken)
engine.register(RefreshToken)
engine.register(VillageModel)
engine.register(ResidentModel)
engine.register(BehaviorModel)
engine.register(EventModel)

engine.create_schema()

repo_village = VillageRepository(engine)

repo_village.add(u'PyConJP 村')
repo_village.add(u'ペンギン村')
Пример #8
0
class CLI():
    def __init__(self, args):
        self.engine = Engine()
        self.engine.connect_to_region('eu-west-1')

        # Register our model with the engine so it can create the Dynamo table
        self.engine.register(Approval)

        # Create the dynamo table for our registered model
        self.engine.create_schema()
        self.args = args
        # Setup logging
        if args.verbose:
            loglevel = logging.DEBUG
        else:
            loglevel = logging.INFO
        logging.basicConfig(format="%(levelname)s: %(message)s",
                            level=loglevel)

    def main(self):
        if self.args.action == 'list':
            self.list()
        elif self.args.action == 'approve':
            self.approve()
        elif self.args.action == 'reject':
            self.reject()
        else:
            logging.error('Please use a correct argument')
            exit(1)

    def approve(self):
        if 'id' not in self.args:
            logging.error('Please give an id')
            exit(1)
        approval_lock = self.engine.scan(Approval).filter(
            id=self.args.id).all()
        if not approval_lock:
            logging.info('No lock with the id %s has been found' %
                         self.args.id)
            exit(1)
        approval_lock = approval_lock[0]
        approval_lock.approved = True
        approval_lock.timestamp = datetime.utcnow()
        self.engine.save(approval_lock, overwrite=True)
        logging.info('The lock %s has been approved' % self.args.id)

    def reject(self):
        if 'id' not in self.args:
            logging.error('Please give an id')
            exit(1)
        approval_lock = self.engine.scan(Approval).filter(
            id=self.args.id).all()
        if not approval_lock:
            logging.info('No lock with the id %s has been found' %
                         self.args.id)
            exit(1)
        approval_lock = approval_lock[0]
        approval_lock.approved = False
        approval_lock.timestamp = datetime.utcnow()
        self.engine.save(approval_lock, overwrite=True)
        logging.info('The lock %s has been rejected' % self.args.id)

    def list(self):
        approval_locks = self.engine.scan(Approval).filter(claimed=True).all()
        table = []

        if approval_locks:
            headers = sorted(approval_locks[0].keys_())
        else:
            headers = None
        if approval_locks:
            for item in approval_locks:
                row = []
                for key in sorted(item.keys_()):
                    row.append(getattr(item, key))
                table.append(row)

            print(tabulate(table, headers))
        else:
            print('There is no waiting approval')
Пример #9
0
class ApprovalResource:
    """
        Approval resource implementation.
        This python script is the target of symbolic links and is used for check, in and out.
        These three commands are defined as methods on this class and common parameters live in the constructor.
        To enable the debug output, the resource source configuration must have the debug parameter.

    """

    def __init__(self, command_name, json_data, command_argument):
        self.command_name = command_name
        self.command_argument = command_argument
        # Namespace the approval lock
        self.data = json.loads(json_data)
        self.wait_lock = 10
        self.pool = ''
        self.engine = Engine()

        # allow debug logging to console for tests
        if os.getenv('RESOURCE_DEBUG', False) or self.data.get('source', {}).get('debug', False):
            log.basicConfig(level=log.DEBUG)
        else:
            logfile = tempfile.NamedTemporaryFile(delete=False, prefix='log')
            log.basicConfig(level=log.DEBUG, filename=logfile.name)
        stderr = log.StreamHandler()
        stderr.setLevel(log.INFO)
        log.getLogger().addHandler(stderr)

        log.debug('command: %s', command_name)
        log.debug('input: %s', self.data)
        log.debug('args: %s', command_argument)
        log.debug('environment: %s', os.environ)

    def check_cmd(self, source, version):
        """
        Check for new version(s)
        This function will look on Dynamodb if there's a lock within the pool
        and will return the last timestamps associated.
        :param source: is an arbitrary JSON object which specifies the location of the resource,
        including any credentials. This is passed verbatim from the pipeline configuration.
        :param version: is a JSON object with string fields, used to uniquely identify an instance of the resource.
        :return: a dict with the version fetched
        """

        log.debug('version: %s', version)

        if not version:
            version = {"timestamp": '0'}
        log.debug('source: %s', source)
        log.debug('version: %s', version)
        approval_locks = self.engine.query(Approval)\
            .filter(
                Approval.timestamp >= datetime.fromtimestamp(Decimal(version.get('timestamp'))),
                pool=self.pool) \
            .all()
        versions_list = []
        for lock in approval_locks:
            versions_list.append({"timestamp": "{timestamp}".format(timestamp=Decimal(lock.timestamp.timestamp()))})
        if not approval_locks:
            versions_list.append(version)
        log.debug(versions_list)
        return versions_list

    def in_cmd(self, target_dir, source, version, params):
        """
        This function will fetch a lock in dynamodb an write it in the target directory.
        If parameters lock_name and need_approval are passed, then the function will wait for a change
        on the dynamodb lock item.
        :param target_dir: a temporary directory which will be exposed as an output
        :param source: is the same value as passed to check
        :param version: is the same type of value passed to check, and specifies the version to fetch.
        :param params: is an arbitrary JSON object passed along verbatim from params on a get.
        :return: a dict with the version fetched and the metadata of the lock
        """
        log.debug('source: %s', source)
        log.debug('version: %s', version)

        if not version:
            version = {"timestamp": 0}

        # Does the get should wait for an approval or not ?
        if 'lock_name' in params and 'need_approval' in params:
            log.debug('Looking for the lock %s in the pool %s' % (params.get('lock_name'), self.pool))
            approval_lock = self.query_lock(params.get('lock_name'))
            if approval_lock:
                # We want to wait until the approve is done
                while approval_lock.approved is None and approval_lock.need_approval:
                    # Query the lock item in the loop
                    refresh_approval = self.query_lock(lock_name=params['lock_name'])

                    # If the lock has timed out, then we override the refresh_approval to simulate a reject
                    if 'timeout' in params:
                        if approval_lock.timestamp + timedelta(minutes=params['timeout']) <= datetime.now():
                            refresh_approval.approved = False
                        countdown = (approval_lock.timestamp.replace(microsecond=0) +
                                     timedelta(minutes=params['timeout'])) - datetime.now().replace(microsecond=0)
                        timedelta(minutes=params['timeout']).total_seconds() / self.wait_lock
                        if countdown.days >= 0:
                            log.info("The lock %s is waiting for an approval. There is %s left" %
                                     (params['lock_name'], str(countdown)))
                    else:
                        log.info("The lock %s is waiting for an approval" % params['lock_name'])
                    # If hasn't been approved or rejected, waiting a bit more
                    if refresh_approval.approved is None:
                        time.sleep(self.wait_lock)
                        continue

                    # Is it approved ?
                    if refresh_approval.approved:
                        approval_lock.approved = True
                    else:
                        approval_lock.approved = False
                # If the lock has been rejected we should fail the job and release the lock
                if not approval_lock.approved and approval_lock.need_approval:
                    log.info("The lock hasn't been approved, exiting")
                    approval_lock.claimed = False
                    approval_lock.approved = None
                    self.engine.save(approval_lock, overwrite=True)
                    exit(1)
        elif 'lock_name' in params:
            approval_lock = self.query_lock(params.get('lock_name'))
        else:
            # There is no approval, we have just a normal lock. Let's fetch the lock
            approval_lock = self.engine.query(Approval)\
                .filter(
                    Approval.timestamp >= datetime.fromtimestamp(Decimal(version.get('timestamp'))),
                    pool=self.pool)\
                .all()
            if approval_lock:
                approval_lock = approval_lock[0]

        metadata = []

        if not approval_lock:
            log.info("No lock have been found")
            exit(0)
        for key in approval_lock.keys_():
            value = getattr(approval_lock, key)
            if type(value) is datetime:
                value = str(Decimal(value.timestamp()))
            elif type(value) is bool:
                value = str(value)
            metadata.append(
                {
                    'name': key,
                    'value': value
                }
            )

        name_path = os.path.join(target_dir, 'name')
        with open(name_path, 'w') as name:
            name.write(getattr(approval_lock, 'lockname'))

        metadata_path = os.path.join(target_dir, 'metadata')
        with open(metadata_path, 'w') as metadata_file:
            json.dump(metadata, metadata_file)

        return {
            'version': {"timestamp": "{timestamp}".format(
                timestamp=Decimal(getattr(approval_lock, 'timestamp').timestamp()))},
            'metadata': metadata,
        }

    def _do_claim(self, params):
        """
        This method handle the claiming of a lock. If the lock is already claimed, it wait until the lock is
        available. Else, it create the lock.
        :param params: the params passed as parameters of the resource
        :return: the approval_lock item in dynamodb
        """
        approval_lock = self.query_lock(lock_name=params['lock_name'])
        need_approval = params.get('need_approval', False)
        override_approval = params.get('override_approval', False)

        if approval_lock:
            # To override the previous approval, we need to reject the previous one
            # Then the get will see it was rejected, will release the lock and fail the job
            if override_approval:
                approval_lock.approved = False
                approval_lock.timestamp = datetime.now()
                self.engine.save(approval_lock, overwrite=True)
                log.info("Rejecting the previous approval")
                # Let the get fail before acquiring the new lock
                time.sleep(self.wait_lock + 5)

            # We want to wait until the lock is not claimed
            log_only_once = False
            while approval_lock.claimed:
                if not log_only_once:
                    log_only_once = True
                    log.info("The lock %s is already claimed" % params['lock_name'])
                refresh_approval = self.query_lock(lock_name=params['lock_name'])
                if not refresh_approval:
                    log.info("The lock does not exist")
                    exit(1)
                if not refresh_approval.claimed:
                    approval_lock.claimed = False
                else:
                    time.sleep(self.wait_lock)

        else:
            approval_lock = Approval(
                id=uuid.uuid4().urn[9:],
                lockname=params['lock_name'],
                pool=self.pool,
                claimed=True,
                team=os.getenv('BUILD_TEAM_NAME', "team"),
                pipeline=os.getenv('BUILD_PIPELINE_NAME', "pipeline"),
                description=params.get('description', None)
            )

        if need_approval:
            approval_lock.need_approval = True
        approval_lock.claimed = True
        approval_lock.approved = None
        approval_lock.timestamp = datetime.now()
        self.engine.save(approval_lock, overwrite=True)
        log.info("Claiming the lock %s" % params['lock_name'])

        return approval_lock

    def _do_release(self, params):
        """
        This method handle the release of a claimed lock

        :param params: the params passed as parameters of the resource
        :return: the approval_lock item in dynamodb
        """
        approval_lock = self.query_lock(lock_name=params['lock_name'])

        if not approval_lock:
            log.info("The lock does not exist")
            exit(1)

        approval_lock.claimed = False
        approval_lock.approved = None
        approval_lock.timestamp = datetime.now()
        self.engine.save(approval_lock, overwrite=True)
        log.info("Releasing the lock %s" % params['lock_name'])

        return approval_lock

    def query_lock(self, lock_name):
        """
        This method is used to query the lock in the approval loop to check if there is a change on it
        :param lock_name: The name of the lock to fetch
        :return: the dynamodb item
        """
        approval_lock = self.engine.query(Approval) \
            .filter(
                lockname=lock_name,
                pool=self.pool) \
            .all()
        if approval_lock:
            approval_lock = approval_lock[0]
        return approval_lock

    def out_cmd(self, target_dir, source, params):
        """
        This method is responsible to acquire or release a lock. If the lock doesn't exist yet, then the method
        create it automatically.
        If a lock is already acquired, the method will wait indefinitely until being able to acquire it.
        :param target_dir:
        :param source: is the same value as passed to check.
        :param params: is an arbitrary JSON object passed along verbatim from params on a put.
        :return: a dict with the version fetched and the metadata of the lock
        """
        metadata = []

        if 'lock_name' not in params:
            log.error('You must set a lock_name on params')
        if 'action' not in params:
            log.error('You must set an action on params')

        if 'claim' in params['action']:
            approval_lock = self._do_claim(params=params)
        elif 'release' in params['action']:
            approval_lock = self._do_release(params=params)
        else:
            log.error('Please use an available action')
            exit(1)

        metadata = []
        for key in approval_lock.keys_():
            value = getattr(approval_lock, key)
            if type(value) is datetime:
                value = str(Decimal(value.timestamp()))
            elif type(value) is bool:
                value = str(value)

            metadata.append(
                {
                    'name': key,
                    'value': value
                }
            )

        name_path = os.path.join(target_dir, 'name')
        with open(name_path, 'w') as name:
            name.write(approval_lock.lockname)

        metadata_path = os.path.join(target_dir, 'metadata')
        with open(metadata_path, 'w') as metadata_file:
            json.dump(metadata, metadata_file)

        return {
            'version': {"timestamp": "{timestamp}".format(
                timestamp=Decimal(approval_lock.timestamp.timestamp()))},
            'metadata': metadata,
        }

    def run(self):
        """Parse input/arguments, perform requested command return output."""
        # Extract informations from the json
        source = self.data.get('source', {})
        params = self.data.get('params', {})
        version = self.data.get('version', {})

        # To use AWS with efficiency, we are pushing the AWS credentials into environment
        os.environ['AWS_ACCESS_KEY_ID'] = source.get('AWS_ACCESS_KEY_ID', '')
        os.environ['AWS_SECRET_ACCESS_KEY'] = source.get('AWS_SECRET_ACCESS_KEY', '')
        os.environ['AWS_DEFAULT_REGION'] = source.get('AWS_DEFAULT_REGION', "eu-west-1")
        self.wait_lock = source.get('wait_lock', 10)

        # Ensure we are receiving the required parameters on the configuration
        if 'pool' not in source:
            log.error("pool must exist in the source configuration")
            exit(1)
        else:
            self.pool = source.get('pool')

        # Configure the connection to Dynamodb
        self.engine.connect_to_region(os.environ.get('AWS_DEFAULT_REGION', 'eu-west-1'))
        # Register our model with the engine so it can create the Dynamo table
        self.engine.register(Approval)
        # Create the dynamo table for our registered model
        self.engine.create_schema()

        # Define which operation to perform
        if self.command_name == 'check':
            response = self.check_cmd(source, version)
        elif self.command_name == 'in':
            response = self.in_cmd(self.command_argument[0], source, version, params)
        else:
            response = self.out_cmd(self.command_argument[0], source, params)

        return json.dumps(response)