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)
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)
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)
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)
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.')