diff --git a/.gitignore b/.gitignore index 3c45dd1a1..0fdf5be1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ settings.yaml +metadata.json +openshift-install +.openshift-install +.openshift_install.log .vscode/ .idea .cache/ diff --git a/cloudwash/cli.py b/cloudwash/cli.py index fb2f441fa..d15263dc9 100644 --- a/cloudwash/cli.py +++ b/cloudwash/cli.py @@ -81,12 +81,13 @@ def azure(ctx, vms, discs, nics, pips, _all, _all_rg): @cleanup_providers.command(help="Cleanup Amazon provider") @common_options @click.option("--pips", is_flag=True, help="Remove only Public IPs from the provider") +@click.option("--ocps", is_flag=True, help="Remove only unused OCPs from the provider") @click.pass_context -def ec2(ctx, vms, discs, nics, pips, _all): +def ec2(ctx, vms, discs, nics, pips, ocps, _all): # Validate Amazon Settings validate_provider(ctx.command.name) is_dry_run = ctx.parent.params["dry"] - ec2Cleanup(vms=vms, discs=discs, nics=nics, pips=pips, _all=_all, dry_run=is_dry_run) + ec2Cleanup(vms=vms, discs=discs, nics=nics, pips=pips, ocps=ocps, _all=_all, dry_run=is_dry_run) @cleanup_providers.command(help="Cleanup VMWare provider") diff --git a/cloudwash/providers/ec2.py b/cloudwash/providers/ec2.py index 1e82a7c90..e9cc7b579 100644 --- a/cloudwash/providers/ec2.py +++ b/cloudwash/providers/ec2.py @@ -5,7 +5,43 @@ from cloudwash.utils import dry_data from cloudwash.utils import echo_dry from cloudwash.utils import total_running_time +from cloudwash.utils import discovery_timestamp +from cloudwash.client import compute_client +import wget +import tarfile +import subprocess +from os.path import exists +import os +def delete_ocp(ocp_name): + region = settings.providers.ec2.region + logger.info(f"Delete OCP '{ocp_name}'") + metadata = { + "clusterName": ocp_name, + "infraID": ocp_name, + "aws": { + "region": region, + "identifier": [ + { + "kubernetes.io/cluster/" + ocp_name: "owned" + } + ] + } + } + with open('metadata.json', 'w') as outfile: + json.dump(metadata, outfile) + if exists('openshift-install'): + logger.info("ocp installer exists") + else: + logger.info("ocp installer doesn't exist") + wget.download('https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest-4.10/openshift-install-linux.tar.gz') + tar = tarfile.open('openshift-install-linux.tar.gz', "r:gz") + tar.extractall() + tar.close() + my_env = os.environ.copy() + my_env["AWS_ACCESS_KEY_ID"] = settings.providers.ec2.username + my_env["AWS_SECRET_ACCESS_KEY"] = settings.providers.ec2.password + subprocess.call(['./openshift-install' , 'destroy', 'cluster', '--log-level=debug'], env=my_env) def cleanup(**kwargs): @@ -51,6 +87,21 @@ def dry_pips(): [dry_data["PIPS"]["delete"].append(dpip["AllocationId"]) for dpip in rpips] return dry_data["PIPS"]["delete"] + def dry_ocps(): + all_vpcs = ec2_client.list_networks() + for vpc in all_vpcs: + tags = vpc.raw.tags + if tags: + for tag in tags: + key = tag.get('Key') + if key.startswith('kubernetes.io/cluster/'): + ocp_name = key[22:] + #logger.info("ocp_name: " + ocp_name + " but only " + settings.delete_ocp + "* can be deletes") + discovered = discovery_timestamp(vpc) + if ocp_name.startswith(settings.delete_ocp): + dry_data['OCPS']['delete'].append(ocp_name) + return dry_data['OCPS']['delete'] + # Remove / Stop VMs def remove_vms(avms): # Remove VMs @@ -82,5 +133,12 @@ def remove_vms(avms): if not is_dry_run: ec2_client.remove_all_unused_ips() logger.info(f"Removed PIPs: \n{rpips}") + if kwargs['ocps'] or kwargs['_all']: + rocps = dry_ocps() + if not is_dry_run: + #ec2_client.remove_all_unused_volumes() + for ocp in rocps: + delete_ocp(ocp) + logger.info(f"Removed following and all unused ocp clusters from ec2 Cloud. \n{rocps}") if is_dry_run: echo_dry(dry_data) diff --git a/cloudwash/utils.py b/cloudwash/utils.py index a1be26c6c..4c6b51b61 100644 --- a/cloudwash/utils.py +++ b/cloudwash/utils.py @@ -11,8 +11,10 @@ "NICS": {"delete": []}, "DISCS": {"delete": []}, "PIPS": {"delete": []}, + "OCPS": {"delete": []}, "RESOURCES": {"delete": []}, } + dry_data.update(_vms_dict) @@ -29,18 +31,22 @@ def echo_dry(dry_data=None) -> None: deletable_discs = dry_data["DISCS"]["delete"] deletable_nics = dry_data["NICS"]["delete"] deletable_pips = dry_data["PIPS"]["delete"] if "PIPS" in dry_data else None + deletable_ocps = dry_data["OCPS"]['delete'] deletable_resources = dry_data["RESOURCES"]["delete"] if deletable_vms or stopable_vms or skipped_vms: logger.info( f"VMs:\n\tDeletable: {deletable_vms}\n\tStoppable: {stopable_vms}\n\t" "Skip: {skipped_vms}" ) + if deletable_discs: logger.info(f"DISCs:\n\tDeletable: {deletable_discs}") if deletable_nics: logger.info(f"NICs:\n\tDeletable: {deletable_nics}") if deletable_pips: logger.info(f"PIPs:\n\tDeletable: {deletable_pips}") + if deletable_ocps: + logger.info(f"OCPs:\n\tDeletable: {deletable_ocps}") if deletable_resources: logger.info(f"RESOURCEs:\n\tDeletable: {deletable_resources}") if not any( @@ -102,3 +108,11 @@ def gce_zones() -> list: _zones_combo = {**_bcds, **_abcfs, **_abcs} zones = [f"{loc}-{zone}" for loc, zones in _zones_combo.items() for zone in zones] return zones + +def discovery_timestamp(resource): + discovered = resource.get_tag_value('cloudwash-discovery-timestamp') + if not discovered: + now_time = datetime.now().astimezone(pytz.UTC) + discovered = datetime.timestamp(now_time) + resource.set_tag('cloudwash-discovery-timestamp', str(int(discovered))) + return discovered