def detach_volume(): """Create a snapshot of a volume identified by it's mount path""" parser = _get_parser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument("-m", "--mount-path", help="Mount point of the volume to be detached" ).completer = FilesCompleter() group.add_argument( "-i", "--volume-id", help="Volume id to detach").completer = ChoicesCompleter( info().volume_ids()) group.add_argument("-d", "--device", help="Device to detach").completer = ChoicesCompleter( info().volume_ids()) parser.add_argument("-x", "--delete", help="Delete volume after detaching", action="store_true") argcomplete.autocomplete(parser) args = parser.parse_args() if is_ec2(): ebs.detach_volume( mount_path=args.mount_path, volume_id=args.volume_id, device=args.device, delete_volume=args.delete, ) else: parser.error("Only makes sense on an EC2 instance")
def list_attached_enis(): """List all enis in the same availability-zone, i.e. ones that can be attached to this instance. """ parser = _get_parser() group = parser.add_mutually_exclusive_group() group.add_argument( "-i", "--ip-address", help= "Include first private ip addresses for the interfaces in the output", action="store_true", ) group.add_argument( "-f", "--full", help="Print all available data about attached enis as json", action="store_true", ) argcomplete.autocomplete(parser) args = parser.parse_args() if is_ec2(): enis = info().network_interfaces() if args.full: print(json.dumps(enis, indent=2, default=dthandler)) else: for eni in enis: ip_addr = (":" + eni["PrivateIpAddresses"][0]["PrivateIpAddress"] if args.ip_address and "PrivateIpAddresses" in eni and eni["PrivateIpAddresses"] and "PrivateIpAddress" in eni["PrivateIpAddresses"][0] else "") print(eni["NetworkInterfaceId"] + ip_addr) else: parser.error("Only makes sense on an EC2 instance")
def subnet_id(): """Get subnet id for instance""" parser = _get_parser() argcomplete.autocomplete(parser) parser.parse_args() if is_ec2(): print(info().subnet_id()) else: parser.error("Only makes sense on an EC2 instance")
def snapshot_from_volume(): """Create a snapshot of a volume identified by it's mount path""" parser = _get_parser() parser.add_argument( "-w", "--wait", help="Wait for the snapshot to finish" + " before returning", action="store_true", ) parser.add_argument("tag_key", help="Key of the tag to find volume with") parser.add_argument("tag_value", help="Value of the tag to find volume with") parser.add_argument("mount_path", help="Where to mount the volume") parser.add_argument( "-c", "--copytags", nargs="*", help= "Tag to copy to the snapshot from instance. Multiple values allowed.", ) parser.add_argument( "-t", "--tags", nargs="*", help= "Tag to add to the snapshot in the format name=value. Multiple values allowed.", ) parser.add_argument( "-i", "--ignore-missing-copytags", action="store_true", help="If set, missing copytags are ignored.", ) argcomplete.autocomplete(parser) args = parser.parse_args() tags = {} if args.tags: for tag in args.tags: try: key, value = tag.split("=", 1) tags[key] = value except ValueError: parser.error("Invalid tag/value input: " + tag) if is_ec2(): print( ebs.create_snapshot( args.tag_key, args.tag_value, args.mount_path, wait=args.wait, tags=tags, copytags=args.copytags, ignore_missing_copytags=args.ignore_missing_copytags, )) else: parser.error("Only makes sense on an EC2 instance")
def list_tags(): """List all tags associated with the instance""" parser = _get_parser() argcomplete.autocomplete(parser) parser.parse_args() if is_ec2(): for key, value in info().tags().items(): print(key + "=" + value) else: parser.error("Only makes sense on an EC2 instance")
def list_attached_volumes(): """List attached volumes""" parser = _get_parser() argcomplete.autocomplete(parser) _ = parser.parse_args() if is_ec2(): for volume_id in info().volume_ids(): print(volume_id) else: parser.error("Only makes sense on an EC2 instance")
def cf_stack_id(): """Get id of the stack the creted this instance""" parser = _get_parser() argcomplete.autocomplete(parser) parser.parse_args() if is_ec2(): print(info().stack_id()) else: parser.error( "Only makes sense on an EC2 instance cretated from a CF stack")
def cf_logical_id(): """Get the logical id that is expecting a signal from this instance""" parser = _get_parser() argcomplete.autocomplete(parser) parser.parse_args() if is_ec2(): print(info().logical_id()) else: parser.error( "Only makes sense on an EC2 instance cretated from a CF stack")
def availability_zone(): """Get availability zone for the instance""" parser = _get_parser() argcomplete.autocomplete(parser) parser.parse_args() if is_ec2(): print(info().availability_zone()) else: parser.error( "Only makes sense on an EC2 instance cretated from a CF stack")
def list_compatible_subnets(): """List all subnets in the same availability-zone, i.e. ones that can have ENIs that can be attached to this instance. """ parser = _get_parser() argcomplete.autocomplete(parser) parser.parse_args() if is_ec2(): for subnet_id in interface.list_compatible_subnet_ids(): print(subnet_id) else: parser.error("Only makes sense on an EC2 instance")
def list_attachable_enis(): """List all enis in the same availability-zone, i.e. ones that can be attached to this instance. """ parser = _get_parser() argcomplete.autocomplete(parser) _ = parser.parse_args() if is_ec2(): for eni_id in interface.list_attachable_eni_ids(): print(eni_id) else: parser.error("Only makes sense on an EC2 instance")
def get_tag(): """Get the value of a tag for an ec2 instance""" parser = _get_parser() parser.add_argument("name", help="The name of the tag to get") argcomplete.autocomplete(parser) args = parser.parse_args() if is_ec2(): value = info().tag(args.name) if value is not None: print(value) else: sys.exit("Tag " + args.name + " not found") else: parser.error("Only makes sense on an EC2 instance")
def volume_info(): """Get information about an EBS volume via a mountpoint, device or volume-id""" parser = _get_parser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument("-m", "--mount-path", help="Mount point of the volume to be detached" ).completer = FilesCompleter() group.add_argument( "-i", "--volume-id", help="Volume id to detach").completer = ChoicesCompleter( info().volume_ids()) group.add_argument("-d", "--device", help="Device to detach").completer = ChoicesCompleter( info().volume_ids()) parser.add_argument( "-j", "--jmespath", help= "A jemspath expression to get a specific piece of info from volume", ) argcomplete.autocomplete(parser) args = parser.parse_args() if is_ec2(): vol_info = ebs.volume_info(mount_path=args.mount_path, volume_id=args.volume_id, device=args.device) if vol_info: if args.jmespath: vol_info = search(args.jmespath, vol_info) if isinstance(vol_info, dict): print(json.dumps(vol_info, indent=2, default=dthandler)) else: print(str(vol_info)) else: print("No volume info found") exit(1) else: parser.error("Only makes sense on an EC2 instance")
def volume_from_snapshot(): """Create a volume from an existing snapshot and mount it on the given path. The snapshot is identified by a tag key and value. If no tag is found, an empty volume is created, attached, formatted and mounted. """ parser = _get_parser() parser.add_argument("tag_key", help="Key of the tag to find volume with") parser.add_argument("tag_value", help="Value of the tag to find volume with") parser.add_argument("mount_path", help="Where to mount the volume") parser.add_argument( "size_gb", nargs="?", help="Size in GB for the volum" + "e. If different from sna" + "pshot size, volume and " + "filesystem are resized", default=None, type=int, ) parser.add_argument( "-n", "--no_delete_on_termination", help="Whether to skip deleting the volume on termi" + "nation, defaults to false", action="store_true", ) parser.add_argument( "-c", "--copytags", nargs="*", help= "Tag to copy to the volume from instance. Multiple values allowed.", ) parser.add_argument( "-t", "--tags", nargs="*", help= "Tag to add to the volume in the format name=value. Multiple values allowed.", ) parser.add_argument( "-i", "--ignore-missing-copytags", action="store_true", help="If set, missing copytags are ignored.", ) parser.add_argument( "-u", "--unencrypted", action="store_false", help="If set, create unencrypted volume", ) volume_type_arg = parser.add_mutually_exclusive_group(required=False) volume_type_arg.add_argument("--gp2", action="store_true", help="GP2 volume type (default)") volume_type_arg.add_argument("--gp3", action="store_true", help="GP3 volume type") argcomplete.autocomplete(parser) args = parser.parse_args() tags = {} if args.tags: for tag in args.tags: try: key, value = tag.split("=", 1) tags[key] = value except ValueError: parser.error("Invalid tag/value input: " + tag) if args.gp3: volume_type = "gp3" else: volume_type = "gp2" if is_ec2(): ebs.volume_from_snapshot( args.tag_key, args.tag_value, args.mount_path, size_gb=args.size_gb, del_on_termination=not args.no_delete_on_termination, copytags=args.copytags, tags=tags, ignore_missing_copytags=args.ignore_missing_copytags, encrypted=args.unencrypted, volume_type=volume_type, ) else: parser.error("Only makes sense on an EC2 instance")
def __init__(self): if (os.path.isfile(INSTANCE_DATA) and time.time() - os.path.getmtime(INSTANCE_DATA) < 900): try: self._info = json.load(open(INSTANCE_DATA)) except BaseException: pass if not self._info and is_ec2(): try: if not wait_net_service("169.254.169.254", 80, 120): raise Exception( "Failed to connect to instance identity service") response = get_retry(INSTANCE_IDENTITY_URL) self._info = json.loads(response.text) os.environ["AWS_DEFAULT_REGION"] = self.region() instance_info = {} try: instance_info = _get_instance_info( self._info["instanceId"]) except ClientError: pass if instance_info: self._info.update(instance_info) tags = {} tag_response = {"Tags": []} try: tag_response = self._get_tag_response() except ClientError: pass for tag in tag_response["Tags"]: tags[tag["Key"]] = tag["Value"] self._info["Tags"] = tags if "aws:cloudformation:stack-name" in self._info["Tags"]: self._info["stack_name"] = tags[ "aws:cloudformation:stack-name"] if "aws:cloudformation:stack-id" in self._info["Tags"]: self._info["stack_id"] = tags[ "aws:cloudformation:stack-id"] if self.stack_name(): stack_parameters, stack = stack_params_and_outputs_and_stack( stack_name=self.stack_name()) self._info["StackData"] = stack_parameters self._info["FullStackData"] = stack except ConnectionError: self._info = {} info_file = None info_file_dir = tempfile.gettempdir() info_file_parent = os.path.dirname(info_file_dir) if not os.path.isdir(info_file_dir) and os.access( info_file_parent, os.W_OK): os.makedirs(info_file_dir) if not os.access(info_file_dir, os.W_OK): home = expanduser("~") info_file_dir = home + os.sep + ".ndt" if not os.path.isdir(info_file_dir) and os.access( info_file_parent, os.W_OK): os.makedirs(info_file_dir) if os.access(info_file_dir, os.W_OK): info_file = info_file_dir + os.sep + "instance-data.json" with open(info_file, "w") as outf: outf.write( json.dumps(self._info, skipkeys=True, indent=2, default=dthandler)) try: os.chmod(info_file, 0o666) os.chmod(info_file_dir, 0o777) except BaseException: pass if self.region(): os.environ["AWS_DEFAULT_REGION"] = self.region() if ("FullStackData" in self._info and "StackStatus" in self._info["FullStackData"]): self._info["initial_status"] = self._info["FullStackData"][ "StackStatus"] if "Tags" in self._info: tags = self._info["Tags"] if "aws:cloudformation:stack-name" in tags: self._info["stack_name"] = tags[ "aws:cloudformation:stack-name"] if "aws:cloudformation:stack-id" in tags: self._info["stack_id"] = tags["aws:cloudformation:stack-id"] if "aws:cloudformation:logical-id" in tags: self._info["logical_id"] = tags[ "aws:cloudformation:logical-id"]