Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Add Module tainting functionality (force codebuild rerun) #738

Open
a13zen opened this issue Oct 14, 2024 · 1 comment
Open

[FEATURE] Add Module tainting functionality (force codebuild rerun) #738

a13zen opened this issue Oct 14, 2024 · 1 comment
Labels
enhancement New feature or request

Comments

@a13zen
Copy link
Contributor

a13zen commented Oct 14, 2024

Is your feature request related to a problem? Please describe.
During module development it is sometimes required to force a module to redeploy, even when no code changes are present and the MD5 hash doesn't change. This is because some modules e.g. ones that build docker images and pull resources into the container build context will change, when the code itself hasn't.

This is also the case for when there is a CF/CDK resource drift that has occurred and you need to rerun cdk deploy to detect the changes, but don't want to change the code to force a re-trigger as nothings has changed.

Therefore it is necessary to sometimes "taint" a module that would force seedfarmer to rerun the codebuild job, even if it detects no changes.

To do this currently, different teams do things like changing the readme's or in worse scenario's, removing the SSM parameters for a module.

Describe the solution you'd like
A command to taint a module to force rerunning of codebuild & all downstream dependencies if force redeploy is enabled.

seedfarmer taint --deployment <deployment> --group <group> --module <module>

Describe alternatives you've considered
Currently to enable tainting we've implemented the following script that allows specifying a module to taint and it updates the deployspec md5 to only zeros.

import argparse
import boto3
import json


def check_parameter_exists(ssm, parameter_name):
    try:
        ssm.get_parameter(Name=parameter_name)
        return True
    except ssm.exceptions.ParameterNotFound:
        return False


def update_ssm_parameter(deployment, group, module):
    ssm = boto3.client("ssm")

    project_prefix = "addf"

    print(f"Target: Deployment: {deployment}, group: {group}, module: {module} not found")

    # Construct the parameter name
    parameter_name = f"/{project_prefix}/{deployment}/{group}/{module}/md5/deployspec"

    if not check_parameter_exists(ssm, parameter_name):
        print(f"Parameter {parameter_name} does not exists")
        print(
            "Ensure you have the credentials loaded for your target environment and not the toolchain account"
        )
        exit(1)

    # New parameter value
    invalidated_value = json.dumps({"hash": "00000000000000000000000000000000"})

    try:
        # Update the parameter
        response = ssm.put_parameter(Name=parameter_name, Value=invalidated_value, Type="String", Overwrite=True)
        if "Version" in response:
            print(f"Successfully updated parameter: {parameter_name}")
            print(f"New version: {response['Version']}")
            print(f"New value: {invalidated_value}")
            print(
                "Module has been tainted. Rerun `$ make dry-run` to test and `$ make deploy` to trigger a redeployment"
            )
        else:
            print("Failed to update parameter")

    except Exception as e:
        print(f"An error occurred: {str(e)}")


def main():
    parser = argparse.ArgumentParser(
        description="Taints module by updating deployspec MD5 value to force SeedFarmer to retrigger"
    )
    parser.add_argument("--deployment", required=True, help="Deployment")
    parser.add_argument("--group", required=True, help="Group name")
    parser.add_argument("--module", required=True, help="Module name")

    args = parser.parse_args()

    update_ssm_parameter(args.deployment, args.group, args.module)


if __name__ == "__main__":
    main()

Additional context
Obviously using this script isn't ideal and having first party support for this kind of taining is extremely useful. It would also allow using this feature properly via the toolchain -> target deployment role mapping path instead of directly on SSM in the target account.

@a13zen a13zen added the enhancement New feature or request label Oct 14, 2024
@dgraeber
Copy link
Contributor

Thanks for this, @a13zen . As we have discussed, the support for tainting is some that we have not embraced due to our declarative manifest paradigm, but we will investigate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants