| Index: third_party/boto/roboto/awsqueryrequest.py
 | 
| diff --git a/third_party/boto/roboto/awsqueryrequest.py b/third_party/boto/roboto/awsqueryrequest.py
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..6d9507189e8dda1430c91696643695a72b9e0144
 | 
| --- /dev/null
 | 
| +++ b/third_party/boto/roboto/awsqueryrequest.py
 | 
| @@ -0,0 +1,504 @@
 | 
| +# Copyright (c) 2010 Mitch Garnaat http://garnaat.org/
 | 
| +# Copyright (c) 2010, Eucalyptus Systems, Inc.
 | 
| +#
 | 
| +# Permission is hereby granted, free of charge, to any person obtaining a
 | 
| +# copy of this software and associated documentation files (the
 | 
| +# "Software"), to deal in the Software without restriction, including
 | 
| +# without limitation the rights to use, copy, modify, merge, publish, dis-
 | 
| +# tribute, sublicense, and/or sell copies of the Software, and to permit
 | 
| +# persons to whom the Software is furnished to do so, subject to the fol-
 | 
| +# lowing conditions:
 | 
| +#
 | 
| +# The above copyright notice and this permission notice shall be included
 | 
| +# in all copies or substantial portions of the Software.
 | 
| +#
 | 
| +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | 
| +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 | 
| +# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 | 
| +# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | 
| +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
| +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 | 
| +# IN THE SOFTWARE.
 | 
| +
 | 
| +import sys
 | 
| +import os
 | 
| +import boto
 | 
| +import optparse
 | 
| +import copy
 | 
| +import boto.exception
 | 
| +import boto.roboto.awsqueryservice
 | 
| +
 | 
| +import bdb
 | 
| +import traceback
 | 
| +try:
 | 
| +    import epdb as debugger
 | 
| +except ImportError:
 | 
| +    import pdb as debugger
 | 
| +
 | 
| +def boto_except_hook(debugger_flag, debug_flag):
 | 
| +    def excepthook(typ, value, tb):
 | 
| +        if typ is bdb.BdbQuit:
 | 
| +            sys.exit(1)
 | 
| +        sys.excepthook = sys.__excepthook__
 | 
| +
 | 
| +        if debugger_flag and sys.stdout.isatty() and sys.stdin.isatty():
 | 
| +            if debugger.__name__ == 'epdb':
 | 
| +                debugger.post_mortem(tb, typ, value)
 | 
| +            else:
 | 
| +                debugger.post_mortem(tb)
 | 
| +        elif debug_flag:
 | 
| +            print traceback.print_tb(tb)
 | 
| +            sys.exit(1)
 | 
| +        else:
 | 
| +            print value
 | 
| +            sys.exit(1)
 | 
| +
 | 
| +    return excepthook
 | 
| +
 | 
| +class Line(object):
 | 
| +
 | 
| +    def __init__(self, fmt, data, label):
 | 
| +        self.fmt = fmt
 | 
| +        self.data = data
 | 
| +        self.label = label
 | 
| +        self.line = '%s\t' % label
 | 
| +        self.printed = False
 | 
| +
 | 
| +    def append(self, datum):
 | 
| +        self.line += '%s\t' % datum
 | 
| +
 | 
| +    def print_it(self):
 | 
| +        if not self.printed:
 | 
| +            print self.line
 | 
| +            self.printed = True
 | 
| +
 | 
| +class RequiredParamError(boto.exception.BotoClientError):
 | 
| +
 | 
| +    def __init__(self, required):
 | 
| +        self.required = required
 | 
| +        s = 'Required parameters are missing: %s' % self.required
 | 
| +        boto.exception.BotoClientError.__init__(self, s)
 | 
| +
 | 
| +class EncoderError(boto.exception.BotoClientError):
 | 
| +
 | 
| +    def __init__(self, error_msg):
 | 
| +        s = 'Error encoding value (%s)' % error_msg
 | 
| +        boto.exception.BotoClientError.__init__(self, s)
 | 
| +        
 | 
| +class FilterError(boto.exception.BotoClientError):
 | 
| +
 | 
| +    def __init__(self, filters):
 | 
| +        self.filters = filters
 | 
| +        s = 'Unknown filters: %s' % self.filters
 | 
| +        boto.exception.BotoClientError.__init__(self, s)
 | 
| +        
 | 
| +class Encoder:
 | 
| +
 | 
| +    @classmethod
 | 
| +    def encode(cls, p, rp, v, label=None):
 | 
| +        if p.name.startswith('_'):
 | 
| +            return
 | 
| +        try:
 | 
| +            mthd = getattr(cls, 'encode_'+p.ptype)
 | 
| +            mthd(p, rp, v, label)
 | 
| +        except AttributeError:
 | 
| +            raise EncoderError('Unknown type: %s' % p.ptype)
 | 
| +        
 | 
| +    @classmethod
 | 
| +    def encode_string(cls, p, rp, v, l):
 | 
| +        if l:
 | 
| +            label = l
 | 
| +        else:
 | 
| +            label = p.name
 | 
| +        rp[label] = v
 | 
| +
 | 
| +    encode_file = encode_string
 | 
| +    encode_enum = encode_string
 | 
| +
 | 
| +    @classmethod
 | 
| +    def encode_integer(cls, p, rp, v, l):
 | 
| +        if l:
 | 
| +            label = l
 | 
| +        else:
 | 
| +            label = p.name
 | 
| +        rp[label] = '%d' % v
 | 
| +        
 | 
| +    @classmethod
 | 
| +    def encode_boolean(cls, p, rp, v, l):
 | 
| +        if l:
 | 
| +            label = l
 | 
| +        else:
 | 
| +            label = p.name
 | 
| +        if v:
 | 
| +            v = 'true'
 | 
| +        else:
 | 
| +            v = 'false'
 | 
| +        rp[label] = v
 | 
| +        
 | 
| +    @classmethod
 | 
| +    def encode_datetime(cls, p, rp, v, l):
 | 
| +        if l:
 | 
| +            label = l
 | 
| +        else:
 | 
| +            label = p.name
 | 
| +        rp[label] = v
 | 
| +        
 | 
| +    @classmethod
 | 
| +    def encode_array(cls, p, rp, v, l):
 | 
| +        v = boto.utils.mklist(v)
 | 
| +        if l:
 | 
| +            label = l
 | 
| +        else:
 | 
| +            label = p.name
 | 
| +        label = label + '.%d'
 | 
| +        for i, value in enumerate(v):
 | 
| +            rp[label%(i+1)] = value
 | 
| +            
 | 
| +class AWSQueryRequest(object):
 | 
| +
 | 
| +    ServiceClass = None
 | 
| +
 | 
| +    Description = ''
 | 
| +    Params = []
 | 
| +    Args = []
 | 
| +    Filters = []
 | 
| +    Response = {}
 | 
| +
 | 
| +    CLITypeMap = {'string' : 'string',
 | 
| +                  'integer' : 'int',
 | 
| +                  'int' : 'int',
 | 
| +                  'enum' : 'choice',
 | 
| +                  'datetime' : 'string',
 | 
| +                  'dateTime' : 'string',
 | 
| +                  'file' : 'string',
 | 
| +                  'boolean' : None}
 | 
| +
 | 
| +    @classmethod
 | 
| +    def name(cls):
 | 
| +        return cls.__name__
 | 
| +
 | 
| +    def __init__(self, **args):
 | 
| +        self.args = args
 | 
| +        self.parser = None
 | 
| +        self.cli_options = None
 | 
| +        self.cli_args = None
 | 
| +        self.cli_output_format = None
 | 
| +        self.connection = None
 | 
| +        self.list_markers = []
 | 
| +        self.item_markers = []
 | 
| +        self.request_params = {}
 | 
| +        self.connection_args = None
 | 
| +
 | 
| +    def __repr__(self):
 | 
| +        return self.name()
 | 
| +
 | 
| +    def get_connection(self, **args):
 | 
| +        if self.connection is None:
 | 
| +            self.connection = self.ServiceClass(**args)
 | 
| +        return self.connection
 | 
| +
 | 
| +    @property
 | 
| +    def status(self):
 | 
| +        retval = None
 | 
| +        if self.http_response is not None:
 | 
| +            retval = self.http_response.status
 | 
| +        return retval
 | 
| +
 | 
| +    @property
 | 
| +    def reason(self):
 | 
| +        retval = None
 | 
| +        if self.http_response is not None:
 | 
| +            retval = self.http_response.reason
 | 
| +        return retval
 | 
| +
 | 
| +    @property
 | 
| +    def request_id(self):
 | 
| +        retval = None
 | 
| +        if self.aws_response is not None:
 | 
| +            retval = getattr(self.aws_response, 'requestId')
 | 
| +        return retval
 | 
| +
 | 
| +    def process_filters(self):
 | 
| +        filters = self.args.get('filters', [])
 | 
| +        filter_names = [f['name'] for f in self.Filters]
 | 
| +        unknown_filters = [f for f in filters if f not in filter_names]
 | 
| +        if unknown_filters:
 | 
| +            raise FilterError('Unknown filters: %s' % unknown_filters)
 | 
| +        for i, filter in enumerate(self.Filters):
 | 
| +            name = filter['name']
 | 
| +            if name in filters:
 | 
| +                self.request_params['Filter.%d.Name' % (i+1)] = name
 | 
| +                for j, value in enumerate(boto.utils.mklist(filters[name])):
 | 
| +                    Encoder.encode(filter, self.request_params, value,
 | 
| +                                   'Filter.%d.Value.%d' % (i+1, j+1))
 | 
| +
 | 
| +    def process_args(self, **args):
 | 
| +        """
 | 
| +        Responsible for walking through Params defined for the request and:
 | 
| +
 | 
| +        * Matching them with keyword parameters passed to the request
 | 
| +          constructor or via the command line.
 | 
| +        * Checking to see if all required parameters have been specified
 | 
| +          and raising an exception, if not.
 | 
| +        * Encoding each value into the set of request parameters that will
 | 
| +          be sent in the request to the AWS service.
 | 
| +        """
 | 
| +        self.args.update(args)
 | 
| +        self.connection_args = copy.copy(self.args)
 | 
| +        if 'debug' in self.args and self.args['debug'] >= 2:
 | 
| +            boto.set_stream_logger(self.name())
 | 
| +        required = [p.name for p in self.Params+self.Args if not p.optional]
 | 
| +        for param in self.Params+self.Args:
 | 
| +            if param.long_name:
 | 
| +                python_name = param.long_name.replace('-', '_')
 | 
| +            else:
 | 
| +                python_name = boto.utils.pythonize_name(param.name, '_')
 | 
| +            value = None
 | 
| +            if python_name in self.args:
 | 
| +                value = self.args[python_name]
 | 
| +            if value is None:
 | 
| +                value = param.default
 | 
| +            if value is not None:
 | 
| +                if param.name in required:
 | 
| +                    required.remove(param.name)
 | 
| +                if param.request_param:
 | 
| +                    if param.encoder:
 | 
| +                        param.encoder(param, self.request_params, value)
 | 
| +                    else:
 | 
| +                        Encoder.encode(param, self.request_params, value)
 | 
| +            if python_name in self.args:
 | 
| +                del self.connection_args[python_name]
 | 
| +        if required:
 | 
| +            l = []
 | 
| +            for p in self.Params+self.Args:
 | 
| +                if p.name in required:
 | 
| +                    if p.short_name and p.long_name:
 | 
| +                        l.append('(%s, %s)' % (p.optparse_short_name,
 | 
| +                                               p.optparse_long_name))
 | 
| +                    elif p.short_name:
 | 
| +                        l.append('(%s)' % p.optparse_short_name)
 | 
| +                    else:
 | 
| +                        l.append('(%s)' % p.optparse_long_name)
 | 
| +            raise RequiredParamError(','.join(l))
 | 
| +        boto.log.debug('request_params: %s' % self.request_params)
 | 
| +        self.process_markers(self.Response)
 | 
| +
 | 
| +    def process_markers(self, fmt, prev_name=None):
 | 
| +        if fmt and fmt['type'] == 'object':
 | 
| +            for prop in fmt['properties']:
 | 
| +                self.process_markers(prop, fmt['name'])
 | 
| +        elif fmt and fmt['type'] == 'array':
 | 
| +            self.list_markers.append(prev_name)
 | 
| +            self.item_markers.append(fmt['name'])
 | 
| +        
 | 
| +    def send(self, verb='GET', **args):
 | 
| +        self.process_args(**args)
 | 
| +        self.process_filters()
 | 
| +        conn = self.get_connection(**self.connection_args)
 | 
| +        self.http_response = conn.make_request(self.name(),
 | 
| +                                               self.request_params,
 | 
| +                                               verb=verb)
 | 
| +        self.body = self.http_response.read()
 | 
| +        boto.log.debug(self.body)
 | 
| +        if self.http_response.status == 200:
 | 
| +            self.aws_response = boto.jsonresponse.Element(list_marker=self.list_markers,
 | 
| +                                                          item_marker=self.item_markers)
 | 
| +            h = boto.jsonresponse.XmlHandler(self.aws_response, self)
 | 
| +            h.parse(self.body)
 | 
| +            return self.aws_response
 | 
| +        else:
 | 
| +            boto.log.error('%s %s' % (self.http_response.status,
 | 
| +                                      self.http_response.reason))
 | 
| +            boto.log.error('%s' % self.body)
 | 
| +            raise conn.ResponseError(self.http_response.status,
 | 
| +                                     self.http_response.reason,
 | 
| +                                     self.body)
 | 
| +
 | 
| +    def add_standard_options(self):
 | 
| +        group = optparse.OptionGroup(self.parser, 'Standard Options')
 | 
| +        # add standard options that all commands get
 | 
| +        group.add_option('-D', '--debug', action='store_true',
 | 
| +                         help='Turn on all debugging output')
 | 
| +        group.add_option('--debugger', action='store_true',
 | 
| +                         default=False,
 | 
| +                         help='Enable interactive debugger on error')
 | 
| +        group.add_option('-U', '--url', action='store',
 | 
| +                         help='Override service URL with value provided')
 | 
| +        group.add_option('--region', action='store',
 | 
| +                         help='Name of the region to connect to')
 | 
| +        group.add_option('-I', '--access-key-id', action='store',
 | 
| +                         help='Override access key value')
 | 
| +        group.add_option('-S', '--secret-key', action='store',
 | 
| +                         help='Override secret key value')
 | 
| +        group.add_option('--version', action='store_true',
 | 
| +                         help='Display version string')
 | 
| +        if self.Filters:
 | 
| +            self.group.add_option('--help-filters', action='store_true',
 | 
| +                                   help='Display list of available filters')
 | 
| +            self.group.add_option('--filter', action='append',
 | 
| +                                   metavar=' name=value',
 | 
| +                                   help='A filter for limiting the results')
 | 
| +        self.parser.add_option_group(group)
 | 
| +
 | 
| +    def process_standard_options(self, options, args, d):
 | 
| +        if hasattr(options, 'help_filters') and options.help_filters:
 | 
| +            print 'Available filters:'
 | 
| +            for filter in self.Filters:
 | 
| +                print '%s\t%s' % (filter.name, filter.doc)
 | 
| +            sys.exit(0)
 | 
| +        if options.debug:
 | 
| +            self.args['debug'] = 2
 | 
| +        if options.url:
 | 
| +            self.args['url'] = options.url
 | 
| +        if options.region:
 | 
| +            self.args['region'] = options.region
 | 
| +        if options.access_key_id:
 | 
| +            self.args['aws_access_key_id'] = options.access_key_id
 | 
| +        if options.secret_key:
 | 
| +            self.args['aws_secret_access_key'] = options.secret_key
 | 
| +        if options.version:
 | 
| +            # TODO - Where should the version # come from?
 | 
| +            print 'version x.xx'
 | 
| +            exit(0)
 | 
| +        sys.excepthook = boto_except_hook(options.debugger,
 | 
| +                                          options.debug)
 | 
| +
 | 
| +    def get_usage(self):
 | 
| +        s = 'usage: %prog [options] '
 | 
| +        l = [ a.long_name for a in self.Args ]
 | 
| +        s += ' '.join(l)
 | 
| +        for a in self.Args:
 | 
| +            if a.doc:
 | 
| +                s += '\n\n\t%s - %s' % (a.long_name, a.doc)
 | 
| +        return s
 | 
| +    
 | 
| +    def build_cli_parser(self):
 | 
| +        self.parser = optparse.OptionParser(description=self.Description,
 | 
| +                                            usage=self.get_usage())
 | 
| +        self.add_standard_options()
 | 
| +        for param in self.Params:
 | 
| +            ptype = action = choices = None
 | 
| +            if param.ptype in self.CLITypeMap:
 | 
| +                ptype = self.CLITypeMap[param.ptype]
 | 
| +                action = 'store'
 | 
| +            if param.ptype == 'boolean':
 | 
| +                action = 'store_true'
 | 
| +            elif param.ptype == 'array':
 | 
| +                if len(param.items) == 1:
 | 
| +                    ptype = param.items[0]['type']
 | 
| +                    action = 'append'
 | 
| +            elif param.cardinality != 1:
 | 
| +                action = 'append'
 | 
| +            if ptype or action == 'store_true':
 | 
| +                if param.short_name:
 | 
| +                    self.parser.add_option(param.optparse_short_name,
 | 
| +                                           param.optparse_long_name,
 | 
| +                                           action=action, type=ptype,
 | 
| +                                           choices=param.choices,
 | 
| +                                           help=param.doc)
 | 
| +                elif param.long_name:
 | 
| +                    self.parser.add_option(param.optparse_long_name,
 | 
| +                                           action=action, type=ptype,
 | 
| +                                           choices=param.choices,
 | 
| +                                           help=param.doc)
 | 
| +
 | 
| +    def do_cli(self):
 | 
| +        if not self.parser:
 | 
| +            self.build_cli_parser()
 | 
| +        self.cli_options, self.cli_args = self.parser.parse_args()
 | 
| +        d = {}
 | 
| +        self.process_standard_options(self.cli_options, self.cli_args, d)
 | 
| +        for param in self.Params:
 | 
| +            if param.long_name:
 | 
| +                p_name = param.long_name.replace('-', '_')
 | 
| +            else:
 | 
| +                p_name = boto.utils.pythonize_name(param.name)
 | 
| +            value = getattr(self.cli_options, p_name)
 | 
| +            if param.ptype == 'file' and value:
 | 
| +                if value == '-':
 | 
| +                    value = sys.stdin.read()
 | 
| +                else:
 | 
| +                    path = os.path.expanduser(value)
 | 
| +                    path = os.path.expandvars(path)
 | 
| +                    if os.path.isfile(path):
 | 
| +                        fp = open(path)
 | 
| +                        value = fp.read()
 | 
| +                        fp.close()
 | 
| +                    else:
 | 
| +                        self.parser.error('Unable to read file: %s' % path)
 | 
| +            d[p_name] = value
 | 
| +        for arg in self.Args:
 | 
| +            if arg.long_name:
 | 
| +                p_name = arg.long_name.replace('-', '_')
 | 
| +            else:
 | 
| +                p_name = boto.utils.pythonize_name(arg.name)
 | 
| +            value = None
 | 
| +            if arg.cardinality == 1:
 | 
| +                if len(self.cli_args) >= 1:
 | 
| +                    value = self.cli_args[0]
 | 
| +            else:
 | 
| +                value = self.cli_args
 | 
| +            d[p_name] = value
 | 
| +        self.args.update(d)
 | 
| +        if hasattr(self.cli_options, 'filter') and self.cli_options.filter:
 | 
| +            d = {}
 | 
| +            for filter in self.cli_options.filter:
 | 
| +                name, value = filter.split('=')
 | 
| +                d[name] = value
 | 
| +            if 'filters' in self.args:
 | 
| +                self.args['filters'].update(d)
 | 
| +            else:
 | 
| +                self.args['filters'] = d
 | 
| +        try:
 | 
| +            response = self.main()
 | 
| +            self.cli_formatter(response)
 | 
| +        except RequiredParamError, e:
 | 
| +            print e
 | 
| +            sys.exit(1)
 | 
| +        except self.ServiceClass.ResponseError, err:
 | 
| +            print 'Error(%s): %s' % (err.error_code, err.error_message)
 | 
| +            sys.exit(1)
 | 
| +        except boto.roboto.awsqueryservice.NoCredentialsError, err:
 | 
| +            print 'Unable to find credentials.'
 | 
| +            sys.exit(1)
 | 
| +        except Exception, e:
 | 
| +            print e
 | 
| +            sys.exit(1)
 | 
| +
 | 
| +    def _generic_cli_formatter(self, fmt, data, label=''):
 | 
| +        if fmt['type'] == 'object':
 | 
| +            for prop in fmt['properties']:
 | 
| +                if 'name' in fmt:
 | 
| +                    if fmt['name'] in data:
 | 
| +                        data = data[fmt['name']]
 | 
| +                    if fmt['name'] in self.list_markers:
 | 
| +                        label = fmt['name']
 | 
| +                        if label[-1] == 's':
 | 
| +                            label = label[0:-1]
 | 
| +                        label = label.upper()
 | 
| +                self._generic_cli_formatter(prop, data, label)
 | 
| +        elif fmt['type'] == 'array':
 | 
| +            for item in data:
 | 
| +                line = Line(fmt, item, label)
 | 
| +                if isinstance(item, dict):
 | 
| +                    for field_name in item:
 | 
| +                        line.append(item[field_name])
 | 
| +                elif isinstance(item, basestring):
 | 
| +                    line.append(item)
 | 
| +                line.print_it()
 | 
| +
 | 
| +    def cli_formatter(self, data):
 | 
| +        """
 | 
| +        This method is responsible for formatting the output for the
 | 
| +        command line interface.  The default behavior is to call the
 | 
| +        generic CLI formatter which attempts to print something
 | 
| +        reasonable.  If you want specific formatting, you should
 | 
| +        override this method and do your own thing.
 | 
| +
 | 
| +        :type data: dict
 | 
| +        :param data: The data returned by AWS.
 | 
| +        """
 | 
| +        if data:
 | 
| +            self._generic_cli_formatter(self.Response, data)
 | 
| +
 | 
| +
 | 
| 
 |