Example #1
0
def set_lambda_var(env_var: str,
                   value,
                   lambda_name: str,
                   quiet: bool = False) -> None:
    """Set a single variable in environment of the specified lambda function"""
    environment = get_deployed_lambda_environment(lambda_name, quiet=False)
    environment[env_var] = value
    set_deployed_lambda_environment(lambda_name, environment)
    polite_print(
        quiet,
        f"Success! Set variable {env_var} in deployed lambda function {lambda_name}"
    )
Example #2
0
def get_deployed_lambda_environment(lambda_name: str,
                                    quiet: bool = True) -> dict:
    """Get environment variables in a deployed lambda function"""
    try:
        lambda_client.get_function(FunctionName=lambda_name)
        c = lambda_client.get_function_configuration(FunctionName=lambda_name)
    except lambda_client.exceptions.ResourceNotFoundException:
        polite_print(quiet, f"{lambda_name} is not a deployed lambda function")
        return {}
    else:
        # get_function_configuration() above returns a dict, no need to convert
        return c["Environment"]["Variables"]
Example #3
0
def lambda_set(argv: typing.List[str], args: argparse.Namespace):
    """
    Set a variable in the SSM store under $DSS_DEPLOYMENT_STAGE/environment,
    then set the variable in each deployed lambda.
    """
    name = args.name

    # Use stdin for value
    if not select.select([sys.stdin], [], [], 0.0)[0]:
        raise RuntimeError(
            "Error: stdin was empty! A variable value must be provided via stdin"
        )
    val = sys.stdin.read()

    if args.dry_run:
        polite_print(
            args.quiet,
            f"Dry-run setting variable {name} in lambda environment in SSM store under "
            "$DSS_DEPLOYMENT_STAGE/environment")
        polite_print(args.quiet, f"    Name: {name}")
        polite_print(args.quiet, f"    Value: {val}")
        for lambda_name in get_deployed_lambdas():
            polite_print(
                args.quiet,
                f"Dry-run setting variable {name} in lambda {lambda_name}")

    else:
        # Set the variable in the SSM store first, then in each deployed lambda
        set_ssm_parameter(name, val, quiet=args.quiet)
        for lambda_name in get_deployed_lambdas():
            set_lambda_var(name, val, lambda_name, quiet=args.quiet)
Example #4
0
def set_ssm_parameter(env_var: str, value, quiet: bool = False) -> None:
    """
    Set a variable in the lambda environment stored in the SSM store under $DSS_DEPLOYMENT_STAGE/environment

    :param env_var: name of environment variable being set
    :param value: value of environment variable being set
    :param bool quiet: suppress all output if true
    """
    environment = get_ssm_environment()
    environment[env_var] = value
    set_ssm_environment(environment)
    polite_print(
        quiet, f"Success! Set variable in SSM parameter store environment:\n"
        f"    Name: {env_var}\n"
        f"    Value: {value}\n")
Example #5
0
def unset_lambda_var(env_var: str,
                     lambda_name: str,
                     quiet: bool = False) -> None:
    """Unset a single variable in environment of the specified lambda function"""
    environment = get_deployed_lambda_environment(lambda_name, quiet=False)
    try:
        del environment[env_var]
        set_deployed_lambda_environment(lambda_name, environment)
        polite_print(
            quiet,
            f"Success! Unset variable {env_var} in deployed lambda function {lambda_name}"
        )
    except KeyError:
        polite_print(
            quiet,
            f"Nothing to unset for variable {env_var} in deployed lambda function {lambda_name}"
        )
Example #6
0
def del_secret(argv: typing.List[str], args: argparse.Namespace):
    """
    Delete the value of the secret variable specified by the
    --secret-name flag from the secrets manager
    """
    secret_name = fix_secret_variable_prefix(args.secret_name)

    try:
        # Start by trying to get the secret variable
        sm_client.get_secret_value(SecretId=secret_name)

    except ClientError:
        # No secret var found
        polite_print(
            args.quiet,
            f"Secret variable {secret_name} not found in secrets manager!")

    except sm_client.exceptions.InvalidRequestException:
        # Already deleted secret var
        polite_print(
            args.quiet,
            f"Secret variable {secret_name} already marked for deletion in secrets manager!"
        )

    else:
        # Get operation was successful, secret variable exists
        if not args.force and not args.dry_run:
            # Make sure the user really wants to do this
            confirm = f"""
            *** WARNING!!! ****

            You are about to delete secret {secret_name} from the secrets
            manager. Are you sure you want to delete the secret?
            (Type 'y' or 'yes' to confirm):
            """
            response = input(confirm)
            if response.lower() not in ["y", "yes"]:
                raise RuntimeError(
                    "You safely aborted the delete secret operation!")

        if args.dry_run:
            # Delete it for fakes
            polite_print(
                args.quiet,
                f"Secret variable {secret_name} found in secrets manager, dry-run deleting it"
            )
        else:
            # Delete it for real
            polite_print(
                args.quiet,
                f"Secret variable {secret_name} found in secrets manager, deleting it"
            )
            sm_client.delete_secret(SecretId=secret_name)
Example #7
0
def get_local_lambda_environment(quiet: bool = True) -> dict:
    """
    For each environment variable being set in deployed lambda functions, get each environment
    variable and its value from the local environment, put them in a dict, and return it.

    :param bool quiet: if true, don't print warning messages
    :returns: dict containing local environment's value of each variable exported to deployed lambda functions
    """
    env = dict()
    for name in os.environ["EXPORT_ENV_VARS_TO_LAMBDA"].split():
        try:
            env[name] = os.environ[name]
        except KeyError:
            polite_print(
                quiet,
                f"Warning: environment variable {name} is in the list of environment variables "
                "to export to lambda functions, EXPORT_ENV_VARS_TO_LAMBDA, but variable is not "
                "defined in the local environment, so there is no value to set."
            )
    return env
Example #8
0
def lambda_unset(argv: typing.List[str], args: argparse.Namespace):
    """
    Unset a variable in the SSM store under $DSS_DEPLOYMENT_STAGE/environment,
    then unset the variable in each deployed lambda.
    """
    name = args.name

    # Unset the variable from the SSM store first, then from each deployed lambda
    if args.dry_run:
        polite_print(args.quiet,
                     f"Dry-run deleting variable {name} from SSM store")
        for lambda_name in get_deployed_lambdas():
            polite_print(
                args.quiet,
                f'Dry-run deleting variable {name} from lambda function "{lambda_name}"'
            )

    else:
        unset_ssm_parameter(name, quiet=args.quiet)
        for lambda_name in get_deployed_lambdas():
            unset_lambda_var(name, lambda_name, quiet=args.quiet)
Example #9
0
def unset_ssm_parameter(env_var: str, quiet: bool = False) -> None:
    """
    Unset a variable in the lambda environment stored in the SSM store undre $DSS_DEPLOYMENT_STAGE/environment

    :param env_var: name of environment variable being set
    :param value: value of environment variable being set
    :param bool quiet: suppress all output if true
    """
    environment = get_ssm_environment()
    try:
        prev_value = environment[env_var]
        del environment[env_var]
        set_ssm_environment(environment)
        polite_print(
            quiet,
            f"Success! Unset variable in SSM store under $DSS_DEPLOYMENT_STAGE/environment:\n"
            f"    Name: {env_var}\n"
            f"    Previous value: {prev_value}\n")
    except KeyError:
        polite_print(
            quiet,
            f"Nothing to unset for variable {env_var} in SSM store under $DSS_DEPLOYMENT_STAGE/environment"
        )
Example #10
0
def get_deployed_lambdas(quiet: bool = True):
    """
    Generator returning names of lambda functions

    :param bool quiet: if true, don't print warnings about lambdas that can't be found
    """
    stage = os.environ["DSS_DEPLOYMENT_STAGE"]

    dirs = []
    path = os.path.join(os.environ["DSS_HOME"], "daemons")
    for item in os.scandir(path):
        if not item.name.startswith('.') and item.is_dir():
            dirs.append(item.name)

    functions = [f"{name}-{stage}" for name in dirs]
    functions.append(f"dss-{stage}")
    for name in functions:
        try:
            lambda_client.get_function(FunctionName=name)
            yield name
        except lambda_client.exceptions.ResourceNotFoundException:
            polite_print(
                quiet,
                f"{name} not deployed, or does not deploy a lambda function")
Example #11
0
def set_secret(argv: typing.List[str], args: argparse.Namespace):
    """Set the value of the secret variable."""
    secret_name = fix_secret_variable_prefix(args.secret_name)

    # Decide what to use for infile
    secret_val = None
    if args.infile is not None:
        if os.path.isfile(args.infile):
            with open(args.infile, 'r') as f:
                secret_val = f.read()
        else:
            raise RuntimeError(
                f"Error: specified input file {args.infile} does not exist!")
    else:
        # Use stdin (input piped to this script) as secret value.
        # stdin provides secret value, flag --secret-name provides secret name.
        if not select.select([sys.stdin], [], [], 0.0)[0]:
            raise RuntimeError(
                "Error: stdin was empty! A secret value must be provided via stdin"
            )
        secret_val = sys.stdin.read()

    # Create or update
    try:
        # Start by trying to get the secret variable
        sm_client.get_secret_value(SecretId=secret_name)

    except ClientError:
        # A secret variable with that name does not exist, so create it
        if args.dry_run:
            polite_print(
                args.quiet,
                f"Secret variable {secret_name} not found in secrets manager, dry-run creating it"
            )
        else:
            if args.infile:
                polite_print(
                    args.quiet,
                    f"Secret variable {secret_name} not found in secrets manager, creating from input file"
                )
            else:
                polite_print(
                    args.quiet,
                    f"Secret variable {secret_name} not found in secrets manager, creating from stdin"
                )
            sm_client.create_secret(Name=secret_name, SecretString=secret_val)

    else:
        # Get operation was successful, secret variable exists
        # Prompt the user before overwriting, unless --force flag present
        if not args.force and not args.dry_run:
            # Prompt the user to make sure they really want to do this
            confirm = f"""
            *** WARNING!!! ***

            The secret you are setting currently has a value. Calling the
            set secret function will overwrite the current value of the
            secret!

            Note:
            - To do a dry run of this operation first, use the --dry-run flag.
            - To ignore this warning, use the --force flag.

            Are you really sure you want to update the secret?
            (Type 'y' or 'yes' to confirm):
            """
            response = input(confirm)
            if response.lower() not in ["y", "yes"]:
                print("You safely aborted the set secret operation!")
                sys.exit(0)

        if args.dry_run:
            polite_print(
                args.quiet,
                f"Secret variable {secret_name} found in secrets manager, dry-run updating it"
            )
        else:
            if args.infile:
                polite_print(
                    args.quiet,
                    f"Secret variable {secret_name} found in secrets manager, updating from input file"
                )
            else:
                polite_print(
                    args.quiet,
                    f"Secret variable {secret_name} found in secrets manager, updating from stdin"
                )
            sm_client.update_secret(SecretId=secret_name,
                                    SecretString=secret_val)
Example #12
0
def lambda_update(argv: typing.List[str], args: argparse.Namespace):
    """
    Update the lambda environment stored in the SSM store under $DSS_DEPLOYMENT_STAGE/environment
    by taking values from the current (local) environment. If --update-deployed flag is provided,
    also update the environment of deployed lambda functions.
    """
    if not args.force and not args.dry_run:
        # Prompt the user to make sure they really want to do this
        confirm = f"""
        *** WARNING!!! ***

        Calling the lambda update function will overwrite the current
        values of the lambda function environment stored in the
        SSM store at $DSS_DEPLOY_STAGE/environment with local
        values from environment variables on your machine.

        Note:
        - To do a dry run of this operation first, use the --dry-run flag.
        - To ignore this warning, use the --force flag.
        - To see the current environment stored in the SSM store, run:
            ./dss-ops.py lambda environment

        Are you really sure you want to update the SSM store environment?
        (Type 'y' or 'yes' to confirm):
        """
        response = input(confirm)
        if response.lower() not in ["y", "yes"]:
            raise RuntimeError(
                "You safely aborted the lambda update operation!")

    # Only elasticsearch endpoint and admin emails are updated dynamically,
    # everything else comes from the local environment.
    local_env = get_local_lambda_environment()
    local_env["DSS_ES_ENDPOINT"] = get_elasticsearch_endpoint()
    local_env["ADMIN_USER_EMAILS"] = get_admin_emails()

    if args.dry_run:
        polite_print(
            args.quiet,
            f"Dry-run redeploying local environment to lambda function environment "
            "stored in SSM store under $DSS_DEPLOYMENT_STAGE/environment")
    else:
        set_ssm_environment(local_env)
        polite_print(
            args.quiet,
            f"Finished redeploying local environment to lambda function environment "
            "stored in SSM store under $DSS_DEPLOY_STAGE/environment")

    # Optionally, update environment of each deployed lambda
    if args.update_deployed:
        for lambda_name in get_deployed_lambdas():
            # Add the new variable to each lambda's environment
            lambda_env = get_deployed_lambda_environment(lambda_name)
            lambda_env.update(local_env)
            if args.dry_run:
                polite_print(
                    args.quiet,
                    f"Dry-run redeploying lambda function environment from SSM store for {lambda_name}"
                )
            else:
                set_deployed_lambda_environment(lambda_name, lambda_env)
                polite_print(
                    args.quiet,
                    f"Finished redeploying lambda function environment from SSM store for {lambda_name}"
                )