Example #1
0
    def get_environments(self, project_key: str) -> dict:
        """
        Retrieve all environments for a given project.

        Includes name, key, and mobile key.

        :param project_key: Key for project.

        :returns: dictionary of environments.
        """
        try:
            resp = self.client.get_project(project_key)
        except launchdarkly_api.rest.ApiException as ex:
            msg = "Unable to get environments."
            resp = "API response was {0} {1}.".format(ex.status, ex.reason)
            LOG.error("%s %s", msg, resp)
            sys.exit(1)

        envs = []

        for env in resp.environments:
            env = dict(key=env.key, api_key=env.api_key, client_id=env.id)
            envs.append(env)

        return envs
    def update_ddb_flag_record(self, feature, state):
        """Update dynamoDB record with new state.

        :param state: state for feature flag.
        :param feature_key: key for feature flag.
        """
        item = self.get_ddb_flag_record(feature)
        try:
            item['on'] = state
            item['version'] += 1
            updated_item = json.dumps(item)
        except KeyError as ex:
            LOG.error(ex)
            sys.exit(1)

        LOG.info('updating %s to %s', feature, state)

        response = self.ddb_table.update_item(
            Key={
                'namespace':
                'ld:{0}:{1}:features'.format(self.project_key,
                                             self.environment_key),
                'key':
                feature
            },
            UpdateExpression='set #state = :r',
            ExpressionAttributeValues={
                ':r': updated_item,
            },
            ExpressionAttributeNames={
                '#state': 'item',
            })
        print(response)
Example #3
0
def playback():
    """
    Execute commands in the replay/toDo directory.
    """
    try:
        execute_replay()
    except ValueError as ex:
        LOG.error(ex)
        sys.exit(1)
def valid_redis_vars() -> bool:
    """Validate that required env vars exist.

    :returns: True if required env vars exist.

    .. versionadded:: 0.0.12
    """
    for envvar in _REQUIRED_REDIS_VARS:
        try:
            _check_env_var(envvar)
        except KeyError as ex:
            LOG.error(ex)
            sys.exit(1)
Example #5
0
def update_redis(project: str, environment: str, feature: str, state: str) \
        -> None:
    """
    Update redis state for a feature flag.

    :param project: LaunchDarkly project key.
    :param environment: LaunchDarkly environment key.
    :param feature: LaunchDarkly feature key.
    :param state: State for a feature flag.
    """
    try:
        hosts = RedisWrapper.connection_string_parser(
            os.environ.get('REDIS_HOSTS'))
    except RuntimeError as ex:
        LOG.error(ex)
        sys.exit(1)

    for host in hosts:
        LOG.info("connecting to %s:%s", host.host, host.port)
        try:
            if valid_state(state):
                new_state = state.lower()
                redis = RedisWrapper(host.host, host.port, project,
                                     environment)
                redis.update_flag_record(new_state, feature)
                create_file(project, environment, feature, new_state)
                LOG.info("%s was successfully updated.", feature)
            else:
                raise Exception('Invalid state: {0}, -s needs \
                    to be either on or off.'.format(state))
        except KeyError as ex:
            LOG.error("unable to update %s. Exception: %s", host.host, ex)
            sys.exit(1)
Example #6
0
def update_dynamodb(table: str, project: str, environment: str, feature: str, state: str) \
-> None:
    """
    Update DynamoDB for a feature flag

    :param table: table name for DynamoDB.
    :param project_key: LaunchDarkly project key
    :param environment_key: LaunchDarkly environment key.
    :param feature: LaunchDarkly feature key.
    :param state: State for a feature flag.

    """
    try:
        ddb = DdbWrapper(table, project, environment)
    except RuntimeError as ex:
        LOG.error(ex)
        sys.exit(1)

    LOG.info("connecting to DynamoDB table: %s", table)

    if valid_state(state):
        if state.lower() == 'off':
            new_state = False
        else:
            new_state = True

        ddb.update_ddb_flag_record(feature, new_state)
        create_file(project, environment, feature, state)
        LOG.info("%s was successfully updated.", feature)
    else:
        LOG.error(
            'Invalid state: {0}, -s needs to be either on or off.'.format(
                state))
    def update_flag_record(self, state: str, feature_key: str) -> None:
        """Update redis record with new state.

        :param state: state for feature flag.
        :param feature_key: key for feature flag.
        """
        key_name = self._format_key_name()
        try:
            parsed_flag = json.loads(
                self.get_flag_record(feature_key).decode('utf-8'))
            parsed_flag['on'] = state
            parsed_flag['version'] += 1
            updated_flag = json.dumps(parsed_flag).encode('utf-8')
        except KeyError as ex:
            LOG.error(ex)
            sys.exit(1)

        LOG.info('updating %s to %s', feature_key, state)

        self.redis.hset(key_name, feature_key, updated_flag)
Example #8
0
    def update_flag(self, state: str, feature_key: str) \
        -> launchdarkly_api.FeatureFlag:
        """
        Update the flag status for the specified feature flag.

        :param state: New feature flag state
        :param featureKey: Feature flag key

        :returns: FeatureFlag object.
        """
        build_env = "/environments/" + self.environment_key + "/on"
        patch_comment = [{"op": "replace", "path": build_env, "value": state}]

        try:
            resp = self.feature.patch_feature_flag(self.project_key,
                                                   feature_key, patch_comment)
        except launchdarkly_api.rest.ApiException as ex:
            msg = "Unable to update flag."
            resp = "API response was {0} {1}.".format(ex.status, ex.reason)
            LOG.error("%s %s", msg, resp)
            sys.exit(1)

        return resp
    def get_ddb_flag_record(self, feature_key: str) -> str:
        """Get feature flag record from dynamoDB.

        :param feature_key: key for feature flag

        :return: value of feature flag key in dynamoDB.

        :raises: KeyError if key is not found.
        """
        response = self.ddb_table.get_item(
            Key={
                'namespace':
                'ld:{0}:{1}:features'.format(self.project_key,
                                             self.environment_key),
                'key':
                feature_key
            })

        try:
            item = json.loads(response['Item'].get('item'))
        except:
            LOG.error('flag key: {0} not found.'.format(feature_key))
            sys.exit(1)
        return item
def execute_replay() -> None:
    """
    Execute all commands.

    For every command that is found in replay/toDo, execute each of them
    and move the file to the replay/archive directory.
    """

    files = glob.glob('./replay/toDo/*')
    sorted_files = sorted(files, key=os.path.getctime)

    if sorted_files:  # list is not empty
        LOG.info('Found %s, beginning execution.', sorted_files)
        for command_file in sorted_files:
            with open(command_file, 'r') as command:
                cmd = command.read()
                LOG.debug('executing command: %s', cmd)
                resp = run([cmd, '-v', 'DEBUG'], shell=True, check=True)
                LOG.debug(resp)
                LOG.debug('moving %s to archive', command.name)
                move_command = 'mv {0} ./replay/archive/'.format(command.name)
                run(move_command, shell=True, check=True)
        LOG.info('LaunchDarkly is now up to date.')
    else:
        LOG.warning('No files found, nothing to replay.')