#!/usr/bin/env python ## Amazon S3 manager ## Author: Michal Ludvig <michal@logix.cz> ## http://www.logix.cz/michal ## License: GPL Version 2 import sys import logging import time from optparse import OptionParser from logging import debug, info, warning, error import elementtree.ElementTree as ET ## Our modules from S3.S3 import * def output(message): print message def cmd_buckets_list_all(args): s3 = S3(AwsConfig()) response = s3.list_all_buckets() for bucket in response["list"]: output("%s %s" % ( formatDateTime(bucket["CreationDate"]), s3.compose_uri(bucket["Name"]), )) def cmd_buckets_list_all_all(args): s3 = S3(AwsConfig()) response = s3.list_all_buckets() for bucket in response["list"]: cmd_bucket_list([bucket["Name"]]) output("") def cmd_bucket_list(args): s3 = S3(AwsConfig()) isuri, bucket, object = s3.parse_s3_uri(args[0]) if not isuri: bucket = args[0] output("Bucket '%s':" % bucket) try: response = s3.bucket_list(bucket) except S3Error, e: if S3.codes.has_key(e.Code): error(S3.codes[e.Code] % bucket) return else: raise for object in response["list"]: size, size_coeff = formatSize(object["Size"], AwsConfig.human_readable_sizes) output("%s %s%s %s" % ( formatDateTime(object["LastModified"]), str(size).rjust(8), size_coeff.ljust(1), s3.compose_uri(bucket, object["Key"]), )) def cmd_bucket_create(args): s3 = S3(AwsConfig()) isuri, bucket, object = s3.parse_s3_uri(args[0]) if not isuri: bucket = args[0] try: response = s3.bucket_create(bucket) except S3Error, e: if S3.codes.has_key(e.Code): error(S3.codes[e.Code] % bucket) return else: raise output("Bucket '%s' created" % bucket) def cmd_bucket_delete(args): s3 = S3(AwsConfig()) isuri, bucket, object = s3.parse_s3_uri(args[0]) if not isuri: bucket = args[0] try: response = s3.bucket_delete(bucket) except S3Error, e: if S3.codes.has_key(e.Code): error(S3.codes[e.Code] % bucket) return else: raise output("Bucket '%s' removed" % bucket) def cmd_object_put(args): s3 = S3(AwsConfig()) s3uri = args.pop() files = args[:] isuri, bucket, object = s3.parse_s3_uri(s3uri) if not isuri: raise ParameterError("Expecting S3 URI instead of '%s'" % s3uri) if len(files) > 1 and object != "" and not AwsConfig.force: error("When uploading multiple files the last argument must") error("be a S3 URI specifying just the bucket name") error("WITHOUT object name!") error("Alternatively use --force argument and the specified") error("object name will be prefixed to all stored filanames.") exit(1) for file in files: if len(files) > 1: object_final = object + os.path.basename(file) elif object == "": object_final = os.path.basename(file) else: object_final = object response = s3.object_put(file, bucket, object_final) output("File '%s' stored as %s (%d bytes)" % (file, s3.compose_uri(bucket, object_final), response["size"])) def cmd_object_get(args): s3 = S3(AwsConfig()) s3uri = args.pop(0) isuri, bucket, object = s3.parse_s3_uri(s3uri) if not isuri or not bucket or not object: raise ParameterError("Expecting S3 object URI instead of '%s'" % s3uri) destination = len(args) > 0 and args.pop(0) or object if os.path.isdir(destination): destination += ("/" + object) if not AwsConfig.force and os.path.exists(destination): raise ParameterError("File %s already exists. Use --force to overwrite it" % destination) response = s3.object_get(destination, bucket, object) output("Object %s saved as '%s' (%d bytes)" % (s3uri, destination, response["size"])) def cmd_object_del(args): s3 = S3(AwsConfig()) s3uri = args.pop(0) isuri, bucket, object = s3.parse_s3_uri(s3uri) if not isuri or not bucket or not object: raise ParameterError("Expecting S3 object URI instead of '%s'" % s3uri) response = s3.object_delete(bucket, object) output("Object %s deleted" % s3uri) commands = { "lb" : ("List all buckets", cmd_buckets_list_all, 0), "cb" : ("Create bucket", cmd_bucket_create, 1), "mb" : ("Create bucket", cmd_bucket_create, 1), "rb" : ("Remove bucket", cmd_bucket_delete, 1), "db" : ("Remove bucket", cmd_bucket_delete, 1), "ls" : ("List objects in bucket", cmd_bucket_list, 1), "la" : ("List all object in all buckets", cmd_buckets_list_all_all, 0), "put": ("Put file into bucket", cmd_object_put, 2), "get": ("Get file from bucket", cmd_object_get, 1), "del": ("Delete file from bucket", cmd_object_del, 1), } if __name__ == '__main__': if float("%d.%d" %(sys.version_info[0], sys.version_info[1])) < 2.5: sys.stderr.write("ERROR: Python 2.5 or higher required, sorry.\n") exit(1) default_verbosity = AwsConfig.verbosity optparser = OptionParser() optparser.set_defaults(config=os.getenv("HOME")+"/.s3cfg") optparser.add_option("-c", "--config", dest="config", metavar="FILE", help="Config file name") optparser.set_defaults(verbosity = default_verbosity) optparser.add_option("-d", "--debug", dest="verbosity", action="store_const", const=logging.DEBUG, help="Enable debug output") optparser.add_option("-v", "--verbose", dest="verbosity", action="store_const", const=logging.INFO, help="Enable verbose output") optparser.set_defaults(human_readable = False) optparser.add_option("-H", "--human-readable", dest="human_readable", action="store_true", help="Print sizes in human readable form") optparser.set_defaults(force = False) optparser.add_option("-f", "--force", dest="force", action="store_true", help="Force overwrite and other dangerous operations") optparser.set_defaults(show_uri = False) optparser.add_option("-u", "--show-uri", dest="show_uri", action="store_true", help="Show complete S3 URI in listings") (options, args) = optparser.parse_args() ## Some mucking with logging levels to enable ## debugging/verbose output for config file parser on request logging.basicConfig(level=options.verbosity, format='%(levelname)s: %(message)s') ## Now finally parse the config file AwsConfig(options.config) ## And again some logging level adjustments ## according to configfile and command line parameters if options.verbosity != default_verbosity: AwsConfig.verbosity = options.verbosity logging.root.setLevel(AwsConfig.verbosity) ## Update AwsConfig with other parameters AwsConfig.human_readable_sizes = options.human_readable AwsConfig.force = options.force AwsConfig.show_uri = options.show_uri if len(args) < 1: error("Missing command. Please run with --help for more information.") exit(1) command = args.pop(0) try: debug("Command: " + commands[command][0]) ## We must do this lookup in extra step to ## avoid catching all KeyError exceptions ## from inner functions. cmd_func = commands[command][1] except KeyError, e: error("Invalid command: %s" % e) exit(1) if len(args) < commands[command][2]: error("Not enough paramters for command '%s'" % command) exit(1) try: cmd_func(args) except S3Error, e: error("S3 error: " + str(e)) except ParameterError, e: error("Parameter problem: " + str(e))