signature:
def get_route_tables ( vpc , ** conn ) :
    """Gets the VPC Route Tables"""

implementation:
route_tables = describe_route_tables ( Filters = [ { "Name" : "vpc-id" , "Values" : [ vpc [ "id" ] ] } ] , ** conn )
rt_ids = [ ]
for r in route_tables :
    rt_ids . append ( r [ "RouteTableId" ] )
return rt_ids


signature:
def get_network_acls ( vpc , ** conn ) :
    """Gets the VPC Network ACLs"""

implementation:
route_tables = describe_network_acls ( Filters = [ { "Name" : "vpc-id" , "Values" : [ vpc [ "id" ] ] } ] , ** conn )
nacl_ids = [ ]
for r in route_tables :
    nacl_ids . append ( r [ "NetworkAclId" ] )
return nacl_ids


signature:
def get_base ( vpc , ** conn ) :
    """The base will return :
 - ARN
 - Region
 - Name
 - Id
 - Tags
 - IsDefault
 - InstanceTenancy
 - CidrBlock
 - CidrBlockAssociationSet
 - Ipv6CidrBlockAssociationSet
 - DhcpOptionsId
 - Attributes
 - _ version
 : param bucket _ name :
 : param conn :
 : return :"""

implementation:
# Get the base :
base_result = describe_vpcs ( VpcIds = [ vpc [ "id" ] ] , ** conn ) [ 0 ]
# The name of the VPC is in the tags :
vpc_name = None
for t in base_result . get ( "Tags" , [ ] ) :
    if t [ "Key" ] == "Name" :
        vpc_name = t [ "Value" ]
dhcp_opts = None
# Get the DHCP Options :
if base_result . get ( "DhcpOptionsId" ) : # There should only be exactly 1 attached to a VPC :
    dhcp_opts = describe_dhcp_options ( DhcpOptionsIds = [ base_result [ "DhcpOptionsId" ] ] , ** conn ) [ 0 ] [ "DhcpOptionsId" ]
# Get the Attributes :
attributes = { }
attr_vals = [ ( "EnableDnsHostnames" , "enableDnsHostnames" ) , ( "EnableDnsSupport" , "enableDnsSupport" ) ]
for attr , query in attr_vals :
    attributes [ attr ] = describe_vpc_attribute ( VpcId = vpc [ "id" ] , Attribute = query , ** conn ) [ attr ]
vpc . update ( { 'name' : vpc_name , 'region' : conn [ "region" ] , 'tags' : base_result . get ( "Tags" , [ ] ) , 'is_default' : base_result [ "IsDefault" ] , 'instance_tenancy' : base_result [ "InstanceTenancy" ] , 'dhcp_options_id' : dhcp_opts , 'cidr_block' : base_result [ "CidrBlock" ] , 'cidr_block_association_set' : base_result . get ( "CidrBlockAssociationSet" , [ ] ) , 'ipv6_cidr_block_association_set' : base_result . get ( "Ipv6CidrBlockAssociationSet" , [ ] ) , 'attributes' : attributes , '_version' : 1 } )
return vpc


signature:
def get_vpc ( vpc_id , flags = FLAGS . ALL , ** conn ) :
    """Orchestrates all the calls required to fully fetch details about a VPC :
 " Arn " : . . . ,
 " Region " : . . . ,
 " Name " : . . . ,
 " Id " : . . . ,
 " Tags : . . . ,
 " VpcPeeringConnections " : . . . ,
 " ClassicLink " : . . . ,
 " DhcpOptionsId " : . . . ,
 " InternetGateway " : . . . ,
 " IsDefault " : . . . ,
 " CidrBlock " : . . . ,
 " CidrBlockAssociationSet " : . . . ,
 " Ipv6CidrBlockAssociationSet " : . . . ,
 " InstanceTenancy " : . . . ,
 " RouteTables " : . . . ,
 " NetworkAcls " : . . . ,
 " FlowLogs " : . . . ,
 " Subnets " : . . . ,
 " Attributes " : . . . ,
 " FlowLogs " : . . . ,
 " _ version " : 1
 : param vpc _ id : The ID of the VPC
 : param flags :
 : param conn :
 : return :"""

implementation:
# Is the account number that ' s passed in the same as in the connection dictionary ?
if not conn . get ( "account_number" ) :
    raise CloudAuxException ( { "message" : "Must supply account number in the connection dict to construct " "the VPC ARN." , "vpc_id" : vpc_id } )
if not conn . get ( "region" ) :
    raise CloudAuxException ( { "message" : "Must supply region in the connection dict to construct " "the VPC ARN." , "vpc_id" : vpc_id } )
start = { 'arn' : "arn:aws:ec2:{region}:{account}:vpc/{vpc_id}" . format ( region = conn [ "region" ] , account = conn [ "account_number" ] , vpc_id = vpc_id ) , 'id' : vpc_id }
return registry . build_out ( flags , start_with = start , pass_datastructure = True , ** conn )


signature:
def get_client ( service , service_type = 'client' , ** conn_args ) :
    """User function to get the correct client .
 Based on the GOOGLE _ CLIENT _ MAP dictionary , the return will be a cloud or general
 client that can interact with the desired service .
 : param service : GCP service to connect to . E . g . ' gce ' , ' iam '
 : type service : ` ` str ` `
 : param conn _ args : Dictionary of connection arguments . ' project ' is required .
 ' user _ agent ' can be specified and will be set in the client
 returned .
 : type conn _ args : ` ` dict ` `
 : return : client _ details , client
 : rtype : ` ` tuple ` ` of ` ` dict ` ` , ` ` object ` `"""

implementation:
client_details = choose_client ( service )
user_agent = get_user_agent ( ** conn_args )
if client_details :
    if client_details [ 'client_type' ] == 'cloud' :
        client = get_gcp_client ( mod_name = client_details [ 'module_name' ] , pkg_name = conn_args . get ( 'pkg_name' , 'google.cloud' ) , key_file = conn_args . get ( 'key_file' , None ) , project = conn_args [ 'project' ] , user_agent = user_agent )
    else :
        client = get_google_client ( mod_name = client_details [ 'module_name' ] , key_file = conn_args . get ( 'key_file' , None ) , user_agent = user_agent , api_version = conn_args . get ( 'api_version' , 'v1' ) )
else : # There is no client known for this service . We can try the standard API .
    try :
        client = get_google_client ( mod_name = service , key_file = conn_args . get ( 'key_file' , None ) , user_agent = user_agent , api_version = conn_args . get ( 'api_version' , 'v1' ) )
    except Exception as e :
        raise e
return client_details , client


signature:
def get_gcp_client ( ** kwargs ) :
    """Public GCP client builder ."""

implementation: return _gcp_client ( project = kwargs [ 'project' ] , mod_name = kwargs [ 'mod_name' ] , pkg_name = kwargs . get ( 'pkg_name' , 'google.cloud' ) , key_file = kwargs . get ( 'key_file' , None ) , http_auth = kwargs . get ( 'http' , None ) , user_agent = kwargs . get ( 'user_agent' , None ) )


signature:
def _gcp_client ( project , mod_name , pkg_name , key_file = None , http_auth = None , user_agent = None ) :
    """Private GCP client builder .
 : param project : Google Cloud project string .
 : type project : ` ` str ` `
 : param mod _ name : Module name to load . Should be found in sys . path .
 : type mod _ name : ` ` str ` `
 : param pkg _ name : package name that mod _ name is part of . Default is ' google . cloud ' .
 : type pkg _ name : ` ` str ` `
 : param key _ file : Default is None .
 : type key _ file : ` ` str ` ` or None
 : param http _ auth : httplib2 authorized client . Default is None .
 : type http _ auth : : class : ` HTTPLib2 `
 : param user _ agent : User Agent string to use in requests . Default is None .
 : type http _ auth : ` ` str ` ` or None
 : return : GCP client
 : rtype : ` ` object ` `"""

implementation:
client = None
if http_auth is None :
    http_auth = _googleauth ( key_file = key_file , user_agent = user_agent )
try : # Using a relative path , so we prefix with a dot ( . )
    google_module = importlib . import_module ( '.' + mod_name , package = pkg_name )
    client = google_module . Client ( use_GAX = USE_GAX , project = project , http = http_auth )
except ImportError as ie :
    import_err = 'Unable to import %s.%s' % ( pkg_name , mod_name )
    raise ImportError ( import_err )
except TypeError : # Not all clients use gRPC
    client = google_module . Client ( project = project , http = http_auth )
if user_agent and hasattr ( client , 'user_agent' ) :
    client . user_agent = user_agent
return client


signature:
def _googleauth ( key_file = None , scopes = [ ] , user_agent = None ) :
    """Google http _ auth helper .
 If key _ file is not specified , default credentials will be used .
 If scopes is specified ( and key _ file ) , will be used instead of DEFAULT _ SCOPES
 : param key _ file : path to key file to use . Default is None
 : type key _ file : ` ` str ` `
 : param scopes : scopes to set . Default is DEFAUL _ SCOPES
 : type scopes : ` ` list ` `
 : param user _ agent : User Agent string to use in requests . Default is None .
 : type http _ auth : ` ` str ` ` or None
 : return : HTTPLib2 authorized client .
 : rtype : : class : ` HTTPLib2 `"""

implementation:
if key_file :
    if not scopes :
        scopes = DEFAULT_SCOPES
    creds = ServiceAccountCredentials . from_json_keyfile_name ( key_file , scopes = scopes )
else :
    creds = GoogleCredentials . get_application_default ( )
http = Http ( )
if user_agent :
    http = set_user_agent ( http , user_agent )
http_auth = creds . authorize ( http )
return http_auth


signature:
def _build_google_client ( service , api_version , http_auth ) :
    """Google build client helper .
 : param service : service to build client for
 : type service : ` ` str ` `
 : param api _ version : API version to use .
 : type api _ version : ` ` str ` `
 : param http _ auth : Initialized HTTP client to use .
 : type http _ auth : ` ` object ` `
 : return : google - python - api client initialized to use ' service '
 : rtype : ` ` object ` `"""

implementation:
client = build ( service , api_version , http = http_auth )
return client


signature:
def gcp_conn ( service , service_type = 'client' , future_expiration_minutes = 15 ) :
    """service _ type : not currently used ."""

implementation:
def decorator ( f ) :
    @ wraps ( f )
    def decorated_function ( * args , ** kwargs ) : # Import here to avoid circular import issue
        from cloudaux . gcp . auth import get_client
        ( conn_args , kwargs ) = get_creds_from_kwargs ( kwargs )
        client_details , client = get_client ( service , service_type = service_type , future_expiration_minutes = 15 , ** conn_args )
        if client_details :
            kwargs = rewrite_kwargs ( client_details [ 'client_type' ] , kwargs , client_details [ 'module_name' ] )
        kwargs [ 'client' ] = client
        return f ( * args , ** kwargs )
    return decorated_function
return decorator


signature:
def gcp_stats ( ) :
    """Collect stats
 Specifically , time function calls
 : returns : function response
 : rtype : varies"""

implementation:
def decorator ( f ) :
    @ wraps ( f )
    def decorated_function ( * args , ** kwargs ) :
        start_time = time . time ( )
        result = f ( * args , ** kwargs )
        end_time = time . time ( )
        strkey = _build_key ( f . __name__ , args , kwargs )
        _GCP_STATS . setdefault ( strkey , [ ] ) . append ( end_time - start_time )
        return result
    return decorated_function
return decorator


signature:
def gcp_cache ( future_expiration_minutes = 15 ) :
    """Cache function output
 : param future _ expiration _ minutes : Number of minutes in the future until item
 expires . Default is 15.
 : returns : function response , optionally from the cache
 : rtype : varies"""

implementation:
def decorator ( f ) :
    @ wraps ( f )
    def decorated_function ( * args , ** kwargs ) :
        strkey = _build_key ( f . __name__ , args , kwargs )
        cached_result = _GCP_CACHE . get ( strkey )
        if cached_result :
            return cached_result
        else :
            result = f ( * args , ** kwargs )
            _GCP_CACHE . insert ( strkey , result , future_expiration_minutes )
        return result
    return decorated_function
return decorator


signature:
def iter_project ( projects , key_file = None ) :
    """Call decorated function for each item in project list .
 Note : the function ' decorated ' is expected to return a value plus a dictionary of exceptions .
 If item in list is a dictionary , we look for a ' project ' and ' key _ file ' entry , respectively .
 If item in list is of type string _ types , we assume it is the project string . Default credentials
 will be used by the underlying client library .
 : param projects : list of project strings or list of dictionaries
 Example : { ' project ' : . . . , ' keyfile ' : . . . } . Required .
 : type projects : ` ` list ` ` of ` ` str ` ` or ` ` list ` ` of ` ` dict ` `
 : param key _ file : path on disk to keyfile , for use with all projects
 : type key _ file : ` ` str ` `
 : returns : tuple containing a list of function output and an exceptions map
 : rtype : ` ` tuple of ` ` list ` ` , ` ` dict ` `"""

implementation:
def decorator ( func ) :
    @ wraps ( func )
    def decorated_function ( * args , ** kwargs ) :
        item_list = [ ]
        exception_map = { }
        for project in projects :
            if isinstance ( project , string_types ) :
                kwargs [ 'project' ] = project
                if key_file :
                    kwargs [ 'key_file' ] = key_file
            elif isinstance ( project , dict ) :
                kwargs [ 'project' ] = project [ 'project' ]
                kwargs [ 'key_file' ] = project [ 'key_file' ]
            itm , exc = func ( * args , ** kwargs )
            item_list . extend ( itm )
            exception_map . update ( exc )
        return ( item_list , exception_map )
    return decorated_function
return decorator


signature:
def get_creds_from_kwargs ( kwargs ) :
    """Helper to get creds out of kwargs ."""

implementation:
creds = { 'key_file' : kwargs . pop ( 'key_file' , None ) , 'http_auth' : kwargs . pop ( 'http_auth' , None ) , 'project' : kwargs . get ( 'project' , None ) , 'user_agent' : kwargs . pop ( 'user_agent' , None ) , 'api_version' : kwargs . pop ( 'api_version' , 'v1' ) }
return ( creds , kwargs )


signature:
def rewrite_kwargs ( conn_type , kwargs , module_name = None ) :
    """Manipulate connection keywords .
 Modifieds keywords based on connection type .
 There is an assumption here that the client has
 already been created and that these keywords are being
 passed into methods for interacting with various services .
 Current modifications :
 - if conn _ type is not cloud and module is ' compute ' ,
 then rewrite project as name .
 - if conn _ type is cloud and module is ' storage ' ,
 then remove ' project ' from dict .
 : param conn _ type : E . g . ' cloud ' or ' general '
 : type conn _ type : ` ` str ` `
 : param kwargs : Dictionary of keywords sent in by user .
 : type kwargs : ` ` dict ` `
 : param module _ name : Name of specific module that will be loaded .
 Default is None .
 : type conn _ type : ` ` str ` ` or None
 : returns kwargs with client and module specific changes
 : rtype : ` ` dict ` `"""

implementation:
if conn_type != 'cloud' and module_name != 'compute' :
    if 'project' in kwargs :
        kwargs [ 'name' ] = 'projects/%s' % kwargs . pop ( 'project' )
if conn_type == 'cloud' and module_name == 'storage' :
    if 'project' in kwargs :
        del kwargs [ 'project' ]
return kwargs


signature:
def gce_list_aggregated ( service = None , key_name = 'name' , ** kwargs ) :
    """General aggregated list function for the GCE service ."""

implementation:
resp_list = [ ]
req = service . aggregatedList ( ** kwargs )
while req is not None :
    resp = req . execute ( )
    for location , item in resp [ 'items' ] . items ( ) :
        if key_name in item :
            resp_list . extend ( item [ key_name ] )
    req = service . aggregatedList_next ( previous_request = req , previous_response = resp )
return resp_list


signature:
def gce_list ( service = None , ** kwargs ) :
    """General list function for the GCE service ."""

implementation:
resp_list = [ ]
req = service . list ( ** kwargs )
while req is not None :
    resp = req . execute ( )
    for item in resp . get ( 'items' , [ ] ) :
        resp_list . append ( item )
    req = service . list_next ( previous_request = req , previous_response = resp )
return resp_list


signature:
def service_list ( service = None , key_name = None , ** kwargs ) :
    """General list function for Google APIs ."""

implementation:
resp_list = [ ]
req = service . list ( ** kwargs )
while req is not None :
    resp = req . execute ( )
    if key_name and key_name in resp :
        resp_list . extend ( resp [ key_name ] )
    else :
        resp_list . append ( resp )
    # Not all list calls have a list _ next
    if hasattr ( service , 'list_next' ) :
        req = service . list_next ( previous_request = req , previous_response = resp )
    else :
        req = None
return resp_list


signature:
def get_cache_access_details ( key = None ) :
    """Retrieve detailed cache information ."""

implementation:
from cloudaux . gcp . decorators import _GCP_CACHE
return _GCP_CACHE . get_access_details ( key = key )


signature:
def get_user_agent_default ( pkg_name = 'cloudaux' ) :
    """Get default User Agent String .
 Try to import pkg _ name to get an accurate version number .
 return : string"""

implementation:
version = '0.0.1'
try :
    import pkg_resources
    version = pkg_resources . get_distribution ( pkg_name ) . version
except pkg_resources . DistributionNotFound :
    pass
except ImportError :
    pass
return 'cloudaux/%s' % ( version )


signature:
def get_elbv2 ( alb , flags = FLAGS . ALL , ** conn ) :
    """Fully describes an ALB ( ELBv2 ) .
 : param alb : Could be an ALB Name , ALB ARN , or a dictionary . Likely the return value from a previous call to describe _ load _ balancers . At a minimum , must contain a key titled ' LoadBalancerArn ' .
 : param flags : Flags describing which sections should be included in the return value . Default is FLAGS . ALL .
 : return : Returns a dictionary describing the ALB with the fields described in the flags parameter ."""

implementation:
# Python 2 and 3 support :
try :
    basestring
except NameError as _ :
    basestring = str
if isinstance ( alb , basestring ) :
    from cloudaux . orchestration . aws . arn import ARN
    alb_arn = ARN ( alb )
    if alb_arn . error :
        alb = dict ( LoadBalancerName = alb )
    else :
        alb = dict ( LoadBalancerArn = alb )
return registry . build_out ( flags , start_with = alb , pass_datastructure = True , ** conn )


signature:
def get_event ( rule , flags = FLAGS . ALL , ** conn ) :
    """Orchestrates all the calls required to fully build out a CloudWatch Event Rule in the following format :
 " Arn " : . . . ,
 " Name " : . . . ,
 " Region " : . . . ,
 " Description " : . . . ,
 " State " : . . . ,
 " Rule " : . . . ,
 " Targets " . . . ,
 " _ version " : 1
 : param rule : str cloudwatch event name
 : param flags : By default , set to ALL fields
 : param conn : dict containing enough information to make a connection to the desired account .
 Must at least have ' assume _ role ' key .
 : return : dict containing a fully built out event rule with targets ."""

implementation:
# Python 2 and 3 support :
try :
    basestring
except NameError as _ :
    basestring = str
# If string is passed in , determine if it ' s a name or ARN . Build a dict .
if isinstance ( rule , basestring ) :
    rule_arn = ARN ( rule )
    if rule_arn . error :
        rule_name = rule
    else :
        rule_name = rule_arn . name
rule = describe_rule ( Name = rule_name , ** conn )
return registry . build_out ( flags , rule , ** conn )


signature:
def list_rules ( client = None , ** kwargs ) :
    """NamePrefix = ' string '"""

implementation:
result = client . list_rules ( ** kwargs )
if not result . get ( "Rules" ) :
    result . update ( { "Rules" : [ ] } )
return result


signature:
def list_targets_by_rule ( client = None , ** kwargs ) :
    """Rule = ' string '"""

implementation:
result = client . list_targets_by_rule ( ** kwargs )
if not result . get ( "Targets" ) :
    result . update ( { "Targets" : [ ] } )
return result


signature:
def get_image ( image_id , flags = FLAGS . ALL , ** conn ) :
    """Orchestrates all the calls required to fully build out an EC2 Image ( AMI , AKI , ARI )
 " Architecture " : " x86_64 " ,
 " Arn " : " arn : aws : ec2 : us - east - 1 : : image / ami - 11111 " ,
 " BlockDeviceMappings " : [ ] ,
 " CreationDate " : " 2013-07-11T16:04:06.000Z " ,
 " Description " : " . . . " ,
 " Hypervisor " : " xen " ,
 " ImageId " : " ami - 11111 " ,
 " ImageLocation " : " 11111 / . . . " ,
 " ImageType " : " machine " ,
 " KernelId " : " aki - 88888 " ,
 " LaunchPermissions " : [ ] ,
 " Name " : " . . . " ,
 " OwnerId " : " 11111 " ,
 " ProductCodes " : [ ] ,
 " Public " : false ,
 " RamdiskId " : { } ,
 " RootDeviceName " : " / dev / sda1 " ,
 " RootDeviceType " : " ebs " ,
 " SriovNetSupport " : " simple " ,
 " State " : " available " ,
 " Tags " : [ ] ,
 " VirtualizationType " : " hvm " ,
 " _ version " : 1
 : param image _ id : str ami id
 : param flags : By default , set to ALL fields
 : param conn : dict containing enough information to make a connection to the desired account .
 Must at least have ' assume _ role ' key .
 : return : dict containing a fully built out image ."""

implementation:
image = dict ( ImageId = image_id )
conn [ 'region' ] = conn . get ( 'region' , 'us-east-1' )
return registry . build_out ( flags , image , ** conn )


signature:
def call ( self , function_expr , ** kwargs ) :
    """cloudaux = CloudAux (
 * * { ' account _ number ' : ' 00000 ' ,
 ' assume _ role ' : ' role _ name ' ,
 ' session _ name ' : ' testing ' ,
 ' region ' : ' us - east - 1 ' ,
 ' tech ' : ' kms ' ,
 ' service _ type ' : ' client '
 cloudaux . call ( " list _ aliases " )
 cloudaux . call ( " kms . client . list _ aliases " )"""

implementation:
if '.' in function_expr :
    tech , service_type , function_name = function_expr . split ( '.' )
else :
    tech = self . conn_details . get ( 'tech' )
    service_type = self . conn_details . get ( 'service_type' , 'client' )
    function_name = function_expr
@ sts_conn ( tech , service_type = service_type )
def wrapped_method ( function_name , ** nargs ) :
    service_type = nargs . pop ( nargs . pop ( 'service_type' , 'client' ) )
    return getattr ( service_type , function_name ) ( ** nargs )
kwargs . update ( self . conn_details )
if 'tech' in kwargs :
    del kwargs [ 'tech' ]
return wrapped_method ( function_name , ** kwargs )


signature:
def go ( function_expr , ** kwargs ) :
    """CloudAux . go (
 ' list _ aliases ' ,
 ' account _ number ' : ' 00000 ' ,
 ' assume _ role ' : ' role _ name ' ,
 ' session _ name ' : ' cloudaux ' ,
 ' region ' : ' us - east - 1 ' ,
 ' tech ' : ' kms ' ,
 ' service _ type ' : ' client '
 CloudAux . go (
 ' kms . client . list _ aliases ' ,
 ' account _ number ' : ' 00000 ' ,
 ' assume _ role ' : ' role _ name ' ,
 ' session _ name ' : ' cloudaux ' ,
 ' region ' : ' us - east - 1'"""

implementation:
if '.' in function_expr :
    tech , service_type , function_name = function_expr . split ( '.' )
else :
    tech = kwargs . pop ( 'tech' )
    service_type = kwargs . get ( 'service_type' )
    function_name = function_expr
@ sts_conn ( tech , service_type = service_type )
def wrapped_method ( function_name , ** nargs ) :
    service_type = nargs . pop ( nargs . pop ( 'service_type' , 'client' ) )
    return getattr ( service_type , function_name ) ( ** nargs )
return wrapped_method ( function_name , ** kwargs )


signature:
def list_buckets ( client = None , ** kwargs ) :
    """List buckets for a project .
 : param client : client object to use .
 : type client : Google Cloud Storage client
 : returns : list of dictionary reprsentation of Bucket
 : rtype : ` ` list ` ` of ` ` dict ` `"""

implementation:
buckets = client . list_buckets ( ** kwargs )
return [ b . __dict__ for b in buckets ]


signature:
def list_objects_in_bucket ( ** kwargs ) :
    """List objects in bucket .
 : param Bucket : name of bucket
 : type Bucket : ` ` str ` `
 : returns list of objects in bucket
 : rtype : ` ` list ` `"""

implementation:
bucket = get_bucket ( ** kwargs )
if bucket :
    return [ o for o in bucket . list_blobs ( ) ]
else :
    return None


signature:
def _modify ( item , func ) :
    """Modifies each item . keys ( ) string based on the func passed in .
 Often used with inflection ' s camelize or underscore methods .
 : param item : dictionary representing item to be modified
 : param func : function to run on each key string
 : return : dictionary where each key has been modified by func ."""

implementation:
result = dict ( )
for key in item :
    result [ func ( key ) ] = item [ key ]
return result


signature:
def modify ( item , output = 'camelized' ) :
    """Calls _ modify and either passes the inflection . camelize method or the inflection . underscore method .
 : param item : dictionary representing item to be modified
 : param output : string ' camelized ' or ' underscored '
 : return :"""

implementation:
if output == 'camelized' :
    return _modify ( item , camelize )
elif output == 'underscored' :
    return _modify ( item , underscore )


signature:
def get_role_managed_policy_documents ( role , client = None , ** kwargs ) :
    """Retrieve the currently active policy version document for every managed policy that is attached to the role ."""

implementation:
policies = get_role_managed_policies ( role , force_client = client )
policy_names = ( policy [ 'name' ] for policy in policies )
delayed_gmpd_calls = ( delayed ( get_managed_policy_document ) ( policy [ 'arn' ] , force_client = client ) for policy in policies )
policy_documents = Parallel ( n_jobs = 20 , backend = "threading" ) ( delayed_gmpd_calls )
return dict ( zip ( policy_names , policy_documents ) )


signature:
def get_managed_policy_document ( policy_arn , policy_metadata = None , client = None , ** kwargs ) :
    """Retrieve the currently active ( i . e . ' default ' ) policy version document for a policy .
 : param policy _ arn :
 : param policy _ metadata : This is a previously fetch managed policy response from boto / cloudaux .
 This is used to prevent unnecessary API calls to get the initial policy default version id .
 : param client :
 : param kwargs :
 : return :"""

implementation:
if not policy_metadata :
    policy_metadata = client . get_policy ( PolicyArn = policy_arn )
policy_document = client . get_policy_version ( PolicyArn = policy_arn , VersionId = policy_metadata [ 'Policy' ] [ 'DefaultVersionId' ] )
return policy_document [ 'PolicyVersion' ] [ 'Document' ]


signature:
def get_group ( group_name , users = True , client = None , ** kwargs ) :
    """Get ' s the IAM Group details .
 : param group _ name :
 : param users : Optional - - will return the IAM users that the group is attached to if desired ( paginated ) .
 : param client :
 : param kwargs :
 : return :"""

implementation:
# First , make the initial call to get the details for the group :
result = client . get_group ( GroupName = group_name , ** kwargs )
# If we care about the user details , then fetch them :
if users :
    if result . get ( 'IsTruncated' ) :
        kwargs_to_send = { 'GroupName' : group_name }
        kwargs_to_send . update ( kwargs )
        user_list = result [ 'Users' ]
        kwargs_to_send [ 'Marker' ] = result [ 'Marker' ]
        result [ 'Users' ] = user_list + _get_users_for_group ( client , ** kwargs_to_send )
else :
    result . pop ( 'Users' , None )
    result . pop ( 'IsTruncated' , None )
    result . pop ( 'Marker' , None )
return result


signature:
def get_group_policy_document ( group_name , policy_name , client = None , ** kwargs ) :
    """Fetches the specific IAM group inline - policy document ."""

implementation: return client . get_group_policy ( GroupName = group_name , PolicyName = policy_name , ** kwargs ) [ 'PolicyDocument' ]


signature:
def _get_base ( server_certificate , ** conn ) :
    """Fetch the base IAM Server Certificate ."""

implementation:
server_certificate [ '_version' ] = 1
# Get the initial cert details :
cert_details = get_server_certificate_api ( server_certificate [ 'ServerCertificateName' ] , ** conn )
if cert_details :
    server_certificate . update ( cert_details [ 'ServerCertificateMetadata' ] )
    server_certificate [ 'CertificateBody' ] = cert_details [ 'CertificateBody' ]
    server_certificate [ 'CertificateChain' ] = cert_details . get ( 'CertificateChain' , None )
    # Cast dates from a datetime to something JSON serializable .
    server_certificate [ 'UploadDate' ] = get_iso_string ( server_certificate [ 'UploadDate' ] )
    server_certificate [ 'Expiration' ] = get_iso_string ( server_certificate [ 'Expiration' ] )
return server_certificate


signature:
def get_server_certificate ( server_certificate , flags = FLAGS . BASE , ** conn ) :
    """Orchestrates all the calls required to fully build out an IAM User in the following format :
 " Arn " : . . . ,
 " ServerCertificateName " : . . . ,
 " Path " : . . . ,
 " ServerCertificateId " : . . . ,
 " UploadDate " : . . . , # str
 " Expiration " : . . . , # str
 " CertificateBody " : . . . ,
 " CertificateChain " : . . . ,
 " _ version " : 1
 : param flags : By default , Users is disabled . This is somewhat expensive as it has to call the
 ` get _ server _ certificate ` call multiple times .
 : param server _ certificate : dict MUST contain the ServerCertificateName and also a combination of
 either the ARN or the account _ number .
 : param output : Determines whether keys should be returned camelized or underscored .
 : param conn : dict containing enough information to make a connection to the desired account .
 Must at least have ' assume _ role ' key .
 : return : dict containing fully built out Server Certificate ."""

implementation:
if not server_certificate . get ( 'ServerCertificateName' ) :
    raise MissingFieldException ( 'Must include ServerCertificateName.' )
server_certificate = modify ( server_certificate , output = 'camelized' )
_conn_from_args ( server_certificate , conn )
return registry . build_out ( flags , start_with = server_certificate , pass_datastructure = True , ** conn )


signature:
def get_item ( item , ** kwargs ) :
    """API versioning for each OpenStack service is independent . Generically capture
 the public members ( non - routine and non - private ) of the OpenStack SDK objects .
 Note the lack of the modify _ output decorator . Preserving the field naming allows
 us to reconstruct objects and orchestrate from stored items ."""

implementation:
_item = { }
for k , v in inspect . getmembers ( item , lambda a : not ( inspect . isroutine ( a ) ) ) :
    if not k . startswith ( '_' ) and not k in ignore_list :
        _item [ k ] = v
return sub_dict ( _item )


signature:
def sub_list ( l ) :
    """Recursively walk a data - structure sorting any lists along the way .
 Any unknown types get mapped to string representation
 : param l : list
 : return : sorted list , where any child lists are also sorted ."""

implementation:
r = [ ]
for i in l :
    if type ( i ) in prims :
        r . append ( i )
    elif type ( i ) is list :
        r . append ( sub_list ( i ) )
    elif type ( i ) is dict :
        r . append ( sub_dict ( i ) )
    else :
        r . append ( str ( i ) )
r = sorted ( r )
return r


signature:
def sub_dict ( d ) :
    """Recursively walk a data - structure sorting any lists along the way .
 Any unknown types get mapped to string representation
 : param d : dict
 : return : dict where any lists , even those buried deep in the structure , have been sorted ."""

implementation:
r = { }
for k in d :
    if type ( d [ k ] ) in prims :
        r [ k ] = d [ k ]
    elif type ( d [ k ] ) is list :
        r [ k ] = sub_list ( d [ k ] )
    elif type ( d [ k ] ) is dict :
        r [ k ] = sub_dict ( d [ k ] )
    else :
        r [ k ] = str ( d [ k ] )
return r


signature:
def boto3_cached_conn ( service , service_type = 'client' , future_expiration_minutes = 15 , account_number = None , assume_role = None , session_name = 'cloudaux' , region = 'us-east-1' , return_credentials = False , external_id = None , arn_partition = 'aws' ) :
    """Used to obtain a boto3 client or resource connection .
 For cross account , provide both account _ number and assume _ role .
 : usage :
 # Same Account :
 client = boto3 _ cached _ conn ( ' iam ' )
 resource = boto3 _ cached _ conn ( ' iam ' , service _ type = ' resource ' )
 # Cross Account Client :
 client = boto3 _ cached _ conn ( ' iam ' , account _ number = ' 00000 ' , assume _ role = ' role _ name ' )
 # Cross Account Resource :
 resource = boto3 _ cached _ conn ( ' iam ' , service _ type = ' resource ' , account _ number = ' 00000 ' , assume _ role = ' role _ name ' )
 : param service : AWS service ( i . e . ' iam ' , ' ec2 ' , ' kms ' )
 : param service _ type : ' client ' or ' resource '
 : param future _ expiration _ minutes : Connections will expire from the cache
 when their expiration is within this many minutes of the present time . [ Default 15]
 : param account _ number : Required if assume _ role is provided .
 : param assume _ role : Name of the role to assume into for account described by account _ number .
 : param session _ name : Session name to attach to requests . [ Default ' cloudaux ' ]
 : param region : Region name for connection . [ Default us - east - 1]
 : param return _ credentials : Indicates if the STS credentials should be returned with the client [ Default False ]
 : param external _ id : Optional external id to pass to sts : AssumeRole .
 See https : / / docs . aws . amazon . com / IAM / latest / UserGuide / id _ roles _ create _ for - user _ externalid . html
 : param arn _ partition : Optional parameter to specify other aws partitions such as aws - us - gov for aws govcloud
 : return : boto3 client or resource connection"""

implementation:
key = ( account_number , assume_role , session_name , external_id , region , service_type , service , arn_partition )
if key in CACHE :
    retval = _get_cached_creds ( key , service , service_type , region , future_expiration_minutes , return_credentials )
    if retval :
        return retval
role = None
if assume_role :
    sts = boto3 . session . Session ( ) . client ( 'sts' )
    # prevent malformed ARN
    if not all ( [ account_number , assume_role ] ) :
        raise ValueError ( "Account number and role to assume are both required" )
    arn = 'arn:{partition}:iam::{0}:role/{1}' . format ( account_number , assume_role , partition = arn_partition )
    assume_role_kwargs = { 'RoleArn' : arn , 'RoleSessionName' : session_name }
    if external_id :
        assume_role_kwargs [ 'ExternalId' ] = external_id
    role = sts . assume_role ( ** assume_role_kwargs )
if service_type == 'client' :
    conn = _client ( service , region , role )
elif service_type == 'resource' :
    conn = _resource ( service , region , role )
if role :
    CACHE [ key ] = role
if return_credentials :
    return conn , role [ 'Credentials' ]
return conn


signature:
def sts_conn ( service , service_type = 'client' , future_expiration_minutes = 15 ) :
    """This will wrap all calls with an STS AssumeRole if the required parameters are sent over .
 Namely , it requires the following in the kwargs :
 - Service Type ( Required )
 - Account Number ( Required for Assume Role )
 - IAM Role Name ( Required for Assume Role )
 - Region ( Optional , but recommended )
 - AWS Partition ( Optional , defaults to ' aws ' if none specified )
 - IAM Session Name ( Optional , but recommended to appear in CloudTrail )
 If ` force _ client ` is set to a boto3 client , then this will simply pass that in as the client .
 ` force _ client ` is mostly useful for mocks and tests .
 : param service :
 : param service _ type :
 : param future _ expiration _ minutes :
 : return :"""

implementation:
def decorator ( f ) :
    @ wraps ( f )
    def decorated_function ( * args , ** kwargs ) :
        if kwargs . get ( "force_client" ) :
            kwargs [ service_type ] = kwargs . pop ( "force_client" )
            kwargs . pop ( "account_number" , None )
            kwargs . pop ( "region" , None )
        else :
            kwargs [ service_type ] = boto3_cached_conn ( service , service_type = service_type , future_expiration_minutes = future_expiration_minutes , account_number = kwargs . pop ( 'account_number' , None ) , assume_role = kwargs . pop ( 'assume_role' , None ) , session_name = kwargs . pop ( 'session_name' , 'cloudaux' ) , external_id = kwargs . pop ( 'external_id' , None ) , region = kwargs . pop ( 'region' , 'us-east-1' ) , arn_partition = kwargs . pop ( 'arn_partition' , 'aws' ) )
        return f ( * args , ** kwargs )
    return decorated_function
return decorator


signature:
def list_bucket_analytics_configurations ( client = None , ** kwargs ) :
    """Bucket = ' string '"""

implementation:
result = client . list_bucket_analytics_configurations ( ** kwargs )
if not result . get ( "AnalyticsConfigurationList" ) :
    result . update ( { "AnalyticsConfigurationList" : [ ] } )
return result


signature:
def list_bucket_metrics_configurations ( client = None , ** kwargs ) :
    """Bucket = ' string '"""

implementation:
result = client . list_bucket_metrics_configurations ( ** kwargs )
if not result . get ( "MetricsConfigurationList" ) :
    result . update ( { "MetricsConfigurationList" : [ ] } )
return result


signature:
def list_bucket_inventory_configurations ( client = None , ** kwargs ) :
    """Bucket = ' string '"""

implementation:
result = client . list_bucket_inventory_configurations ( ** kwargs )
if not result . get ( "InventoryConfigurationList" ) :
    result . update ( { "InventoryConfigurationList" : [ ] } )
return result


signature:
def get_queue ( queue , flags = FLAGS . ALL , ** conn ) :
    """Orchestrates all the calls required to fully fetch details about an SQS Queue :
 " Arn " : . . . ,
 " Region " : . . . ,
 " Name " : . . . ,
 " Url " : . . . ,
 " Attributes " : . . . ,
 " Tags " : . . . ,
 " DeadLetterSourceQueues " : . . . ,
 " _ version " : 1
 : param queue : Either the queue name OR the queue url
 : param flags : By default , set to ALL fields .
 : param conn : dict containing enough information to make a connection to the desired account . Must at least have
 ' assume _ role ' key .
 : return : dict containing a fully built out SQS queue ."""

implementation:
# Check if this is a Queue URL or a queue name :
if queue . startswith ( "https://" ) or queue . startswith ( "http://" ) :
    queue_name = queue
else :
    queue_name = get_queue_url ( QueueName = queue , ** conn )
sqs_queue = { "QueueUrl" : queue_name }
return registry . build_out ( flags , sqs_queue , ** conn )


signature:
def get_bucket ( bucket_name , include_created = None , flags = FLAGS . ALL ^ FLAGS . CREATED_DATE , ** conn ) :
    """Orchestrates all the calls required to fully build out an S3 bucket in the following format :
 " Arn " : . . . ,
 " Name " : . . . ,
 " Region " : . . . ,
 " Owner " : . . . ,
 " Grants " : . . . ,
 " GrantReferences " : . . . ,
 " LifecycleRules " : . . . ,
 " Logging " : . . . ,
 " Policy " : . . . ,
 " Tags " : . . . ,
 " Versioning " : . . . ,
 " Website " : . . . ,
 " Cors " : . . . ,
 " Notifications " : . . . ,
 " Acceleration " : . . . ,
 " Replication " : . . . ,
 " CreationDate " : . . . ,
 " AnalyticsConfigurations " : . . . ,
 " MetricsConfigurations " : . . . ,
 " InventoryConfigurations " : . . . ,
 " _ version " : 9
 NOTE : " GrantReferences " is an ephemeral field that is not guaranteed to be consistent - - do not base logic off of it
 : param include _ created : legacy param moved to FLAGS .
 : param bucket _ name : str bucket name
 : param flags : By default , set to ALL fields except for FLAGS . CREATED _ DATE as obtaining that information is a slow
 and expensive process .
 : param conn : dict containing enough information to make a connection to the desired account . Must at least have
 ' assume _ role ' key .
 : return : dict containing a fully built out bucket ."""

implementation:
if type ( include_created ) is bool : # coerce the legacy param " include _ created " into the flags param .
    if include_created :
        flags = flags | FLAGS . CREATED_DATE
    else :
        flags = flags & ~ FLAGS . CREATED_DATE
region = get_bucket_region ( Bucket = bucket_name , ** conn )
if not region :
    return dict ( Error = 'Unauthorized' )
conn [ 'region' ] = region
return registry . build_out ( flags , bucket_name , ** conn )


signature:
def _get_base ( role , ** conn ) :
    """Determine whether the boto get _ role call needs to be made or if we already have all that data
 in the role object .
 : param role : dict containing ( at the very least ) role _ name and / or arn .
 : param conn : dict containing enough information to make a connection to the desired account .
 : return : Camelized dict describing role containing all all base _ fields ."""

implementation:
base_fields = frozenset ( [ 'Arn' , 'AssumeRolePolicyDocument' , 'Path' , 'RoleId' , 'RoleName' , 'CreateDate' ] )
needs_base = False
for field in base_fields :
    if field not in role :
        needs_base = True
        break
if needs_base :
    role_name = _get_name_from_structure ( role , 'RoleName' )
    role = CloudAux . go ( 'iam.client.get_role' , RoleName = role_name , ** conn )
    role = role [ 'Role' ]
# cast CreateDate from a datetime to something JSON serializable .
role . update ( dict ( CreateDate = get_iso_string ( role [ 'CreateDate' ] ) ) )
role [ '_version' ] = 3
return role


signature:
def get_role ( role , flags = FLAGS . ALL , ** conn ) :
    """Orchestrates all the calls required to fully build out an IAM Role in the following format :
 " Arn " : . . . ,
 " AssumeRolePolicyDocument " : . . . ,
 " CreateDate " : . . . , # str
 " InlinePolicies " : . . . ,
 " InstanceProfiles " : . . . ,
 " ManagedPolicies " : . . . ,
 " Path " : . . . ,
 " RoleId " : . . . ,
 " RoleName " : . . . ,
 " Tags " : { } ,
 " _ version " : 3
 : param role : dict containing ( at the very least ) role _ name and / or arn .
 : param output : Determines whether keys should be returned camelized or underscored .
 : param conn : dict containing enough information to make a connection to the desired account .
 Must at least have ' assume _ role ' key .
 : return : dict containing a fully built out role ."""

implementation:
role = modify ( role , output = 'camelized' )
_conn_from_args ( role , conn )
return registry . build_out ( flags , start_with = role , pass_datastructure = True , ** conn )


signature:
def get_all_roles ( ** conn ) :
    """Returns a List of Roles represented as the dictionary below :
 " Arn " : . . . ,
 " AssumeRolePolicyDocument " : . . . ,
 " CreateDate " : . . . , # str
 " InlinePolicies " : . . . ,
 " InstanceProfiles " : . . . ,
 " ManagedPolicies " : . . . ,
 " Path " : . . . ,
 " RoleId " : . . . ,
 " RoleName " : . . . ,
 : param conn : dict containing enough information to make a connection to the desired account .
 : return : list containing dicts or fully built out roles"""

implementation:
roles = [ ]
account_roles = get_account_authorization_details ( 'Role' , ** conn )
for role in account_roles :
    roles . append ( { 'Arn' : role [ 'Arn' ] , 'AssumeRolePolicyDocument' : role [ 'AssumeRolePolicyDocument' ] , 'CreateDate' : get_iso_string ( role [ 'CreateDate' ] ) , 'InlinePolicies' : role [ 'RolePolicyList' ] , 'InstanceProfiles' : [ { 'path' : ip [ 'Path' ] , 'instance_profile_name' : ip [ 'InstanceProfileName' ] , 'create_date' : get_iso_string ( ip [ 'CreateDate' ] ) , 'instance_profile_id' : ip [ 'InstanceProfileId' ] , 'arn' : ip [ 'Arn' ] } for ip in role [ 'InstanceProfileList' ] ] , 'ManagedPolicies' : [ { "name" : x [ 'PolicyName' ] , "arn" : x [ 'PolicyArn' ] } for x in role [ 'AttachedManagedPolicies' ] ] , 'Path' : role [ 'Path' ] , 'RoleId' : role [ 'RoleId' ] , 'RoleName' : role [ 'RoleName' ] } )
return roles


signature:
def _get_policy ( lambda_function , ** conn ) :
    """Get LambdaFunction Policies . ( there can be many of these ! )
 Lambda Function Policies are overly complicated . They can be attached to a label ,
 a version , and there is also a default policy .
 This method attempts to gather all three types .
 AWS returns an exception if the policy requested does not exist . We catch and ignore these exceptions ."""

implementation:
policies = dict ( Versions = dict ( ) , Aliases = dict ( ) , DEFAULT = dict ( ) )
for version in [ v [ 'Version' ] for v in lambda_function [ 'versions' ] ] :
    try :
        policies [ 'Versions' ] [ version ] = get_policy ( FunctionName = lambda_function [ 'FunctionName' ] , Qualifier = version , ** conn )
        policies [ 'Versions' ] [ version ] = json . loads ( policies [ 'Versions' ] [ version ] )
    except Exception as e :
        pass
for alias in [ v [ 'Name' ] for v in lambda_function [ 'aliases' ] ] :
    try :
        policies [ 'Aliases' ] [ alias ] = get_policy ( FunctionName = lambda_function [ 'FunctionName' ] , Qualifier = alias , ** conn )
        policies [ 'Aliases' ] [ alias ] = json . loads ( policies [ 'Aliases' ] [ alias ] )
    except Exception as e :
        pass
try :
    policies [ 'DEFAULT' ] = get_policy ( FunctionName = lambda_function [ 'FunctionName' ] , ** conn )
    policies [ 'DEFAULT' ] = json . loads ( policies [ 'DEFAULT' ] )
except Exception as e :
    pass
return policies


signature:
def get_lambda_function ( lambda_function , flags = FLAGS . ALL , ** conn ) :
    """Fully describes a lambda function .
 Args :
 lambda _ function : Name , ARN , or dictionary of lambda function . If dictionary , should likely be the return value from list _ functions . At a minimum , must contain a key titled ' FunctionName ' .
 flags : Flags describing which sections should be included in the return value . Default ALL
 Returns :
 dictionary describing the requested lambda function ."""

implementation:
# Python 2 and 3 support :
try :
    basestring
except NameError as _ :
    basestring = str
# If STR is passed in , determine if it ' s a name or ARN and built a dict .
if isinstance ( lambda_function , basestring ) :
    lambda_function_arn = ARN ( lambda_function )
    if lambda_function_arn . error :
        lambda_function = dict ( FunctionName = lambda_function )
    else :
        lambda_function = dict ( FunctionName = lambda_function_arn . name , FunctionArn = lambda_function )
# If an ARN is available , override the account _ number / region from the conn dict .
if 'FunctionArn' in lambda_function :
    lambda_function_arn = ARN ( lambda_function [ 'FunctionArn' ] )
    if not lambda_function_arn . error :
        if lambda_function_arn . account_number :
            conn [ 'account_number' ] = lambda_function_arn . account_number
        if lambda_function_arn . region :
            conn [ 'region' ] = lambda_function_arn . region
return registry . build_out ( flags , start_with = lambda_function , pass_datastructure = True , ** conn )


signature:
def list_items ( conn = None , ** kwargs ) :
    """: rtype : ` ` list ` `"""

implementation: return [ x for x in getattr ( getattr ( conn , kwargs . pop ( 'service' ) ) , kwargs . pop ( 'generator' ) ) ( ** kwargs ) ]


signature:
def get_serviceaccount ( client = None , ** kwargs ) :
    """service _ account = ' string '"""

implementation:
service_account = kwargs . pop ( 'service_account' )
resp = client . projects ( ) . serviceAccounts ( ) . get ( name = service_account ) . execute ( )
return resp


signature:
def get_serviceaccount_keys ( client = None , ** kwargs ) :
    """service _ account = ' string '"""

implementation:
service_account = kwargs . pop ( 'service_account' )
kwargs [ 'name' ] = service_account
return service_list ( client . projects ( ) . serviceAccounts ( ) . keys ( ) , key_name = 'keys' , ** kwargs )


signature:
def get_iam_policy ( client = None , ** kwargs ) :
    """service _ account = ' string '"""

implementation:
service_account = kwargs . pop ( 'service_account' )
resp = client . projects ( ) . serviceAccounts ( ) . getIamPolicy ( resource = service_account ) . execute ( )
# TODO ( supertom ) : err handling , check if ' bindings ' is correct
if 'bindings' in resp :
    return resp [ 'bindings' ]
else :
    return None


signature:
def get_vault ( vault_obj , flags = FLAGS . ALL , ** conn ) :
    """Orchestrates calls to build a Glacier Vault in the following format :
 " VaultARN " : . . . ,
 " VaultName " : . . . ,
 " CreationDate " . . . ,
 " LastInventoryDate " . . . ,
 " NumberOfArchives " . . . ,
 " SizeInBytes " . . . ,
 " Policy " . . . ,
 " Tags " . . .
 Args :
 vault _ obj : name , ARN , or dict of Glacier Vault
 flags : Flags describing which sections should be included in the return value . Default ALL
 Returns :
 dictionary describing the requested Vault"""

implementation:
if isinstance ( vault_obj , string_types ) :
    vault_arn = ARN ( vault_obj )
    if vault_arn . error :
        vault_obj = { 'VaultName' : vault_obj }
    else :
        vault_obj = { 'VaultName' : vault_arn . parsed_name }
return registry . build_out ( flags , vault_obj , ** conn )


signature:
def get_rules ( security_group , ** kwargs ) :
    """format the rule fields to match AWS to support auditor reuse ,
 will need to remap back if we want to orchestrate from our stored items"""

implementation:
rules = security_group . pop ( 'security_group_rules' , [ ] )
for rule in rules :
    rule [ 'ip_protocol' ] = rule . pop ( 'protocol' )
    rule [ 'from_port' ] = rule . pop ( 'port_range_max' )
    rule [ 'to_port' ] = rule . pop ( 'port_range_min' )
    rule [ 'cidr_ip' ] = rule . pop ( 'remote_ip_prefix' )
    rule [ 'rule_type' ] = rule . pop ( 'direction' )
security_group [ 'rules' ] = sorted ( rules )
return security_group


signature:
def get_security_group ( security_group , flags = FLAGS . ALL , ** kwargs ) :
    result = registry . build_out ( flags , start_with = security_group , pass_datastructure = True , ** kwargs )
    """just store the AWS formatted rules"""

implementation:
result . pop ( 'security_group_rules' , [ ] )
return result


signature:
def _conn_from_arn ( arn ) :
    """Extracts the account number from an ARN .
 : param arn : Amazon ARN containing account number .
 : return : dictionary with a single account _ number key that can be merged with an existing
 connection dictionary containing fields such as assume _ role , session _ name , region ."""

implementation:
arn = ARN ( arn )
if arn . error :
    raise CloudAuxException ( 'Bad ARN: {arn}' . format ( arn = arn ) )
return dict ( account_number = arn . account_number , )


signature:
def _get_name_from_structure ( item , default ) :
    """Given a possibly sparsely populated item dictionary , try to retrieve the item name .
 First try the default field . If that doesn ' t exist , try to parse the from the ARN .
 : param item : dict containing ( at the very least ) item _ name and / or arn
 : return : item name"""

implementation:
if item . get ( default ) :
    return item . get ( default )
if item . get ( 'Arn' ) :
    arn = item . get ( 'Arn' )
    item_arn = ARN ( arn )
    if item_arn . error :
        raise CloudAuxException ( 'Bad ARN: {arn}' . format ( arn = arn ) )
    return item_arn . parsed_name
raise MissingFieldException ( 'Cannot extract item name from input: {input}.' . format ( input = item ) )


signature:
def describe_load_balancers ( arns = None , names = None , client = None ) :
    """Permission : elasticloadbalancing : DescribeLoadBalancers"""

implementation:
kwargs = dict ( )
if arns :
    kwargs . update ( dict ( LoadBalancerArns = arns ) )
if names :
    kwargs . update ( dict ( Names = names ) )
return client . describe_load_balancers ( ** kwargs )


signature:
def describe_listeners ( load_balancer_arn = None , listener_arns = None , client = None ) :
    """Permission : elasticloadbalancing : DescribeListeners"""

implementation:
kwargs = dict ( )
if load_balancer_arn :
    kwargs . update ( dict ( LoadBalancerArn = load_balancer_arn ) )
if listener_arns :
    kwargs . update ( dict ( ListenerArns = listener_arns ) )
return client . describe_listeners ( ** kwargs )


signature:
def describe_rules ( listener_arn = None , rule_arns = None , client = None ) :
    """Permission : elasticloadbalancing : DescribeRules"""

implementation:
kwargs = dict ( )
if listener_arn :
    kwargs . update ( dict ( ListenerArn = listener_arn ) )
if rule_arns :
    kwargs . update ( dict ( RuleArns = rule_arns ) )
return client . describe_rules ( ** kwargs ) [ 'Rules' ]


signature:
def describe_target_groups ( load_balancer_arn = None , target_group_arns = None , names = None , client = None ) :
    """Permission : elasticloadbalancing : DescribeTargetGroups"""

implementation:
kwargs = dict ( )
if load_balancer_arn :
    kwargs . update ( LoadBalancerArn = load_balancer_arn )
if target_group_arns :
    kwargs . update ( TargetGroupArns = target_group_arns )
if names :
    kwargs . update ( Names = names )
return client . describe_target_groups ( ** kwargs )


signature:
def describe_target_health ( target_group_arn , targets = None , client = None ) :
    """Permission : elasticloadbalancing : DescribeTargetHealth"""

implementation:
kwargs = dict ( TargetGroupArn = target_group_arn )
if targets :
    kwargs . update ( Targets = targets )
return client . describe_target_health ( ** kwargs ) [ 'TargetHealthDescriptions' ]


signature:
def get_inline_policies ( group , ** conn ) :
    """Get the inline policies for the group ."""

implementation:
policy_list = list_group_policies ( group [ 'GroupName' ] )
policy_documents = { }
for policy in policy_list :
    policy_documents [ policy ] = get_group_policy_document ( group [ 'GroupName' ] , policy , ** conn )
return policy_documents


signature:
def get_managed_policies ( group , ** conn ) :
    """Get a list of the managed policy names that are attached to the group ."""

implementation:
managed_policies = list_attached_group_managed_policies ( group [ 'GroupName' ] , ** conn )
managed_policy_names = [ ]
for policy in managed_policies :
    managed_policy_names . append ( policy [ 'PolicyName' ] )
return managed_policy_names


signature:
def get_users ( group , ** conn ) :
    """Gets a list of the usernames that are a part of this group ."""

implementation:
group_details = get_group_api ( group [ 'GroupName' ] , ** conn )
user_list = [ ]
for user in group_details . get ( 'Users' , [ ] ) :
    user_list . append ( user [ 'UserName' ] )
return user_list


signature:
def _get_base ( group , ** conn ) :
    """Fetch the base IAM Group ."""

implementation:
group [ '_version' ] = 1
# Get the initial group details ( only needed if we didn ' t grab the users ) :
group . update ( get_group_api ( group [ 'GroupName' ] , users = False , ** conn ) [ 'Group' ] )
# Cast CreateDate from a datetime to something JSON serializable .
group [ 'CreateDate' ] = get_iso_string ( group [ 'CreateDate' ] )
return group


signature:
def get_group ( group , flags = FLAGS . BASE | FLAGS . INLINE_POLICIES | FLAGS . MANAGED_POLICIES , ** conn ) :
    """Orchestrates all the calls required to fully build out an IAM Group in the following format :
 " Arn " : . . . ,
 " GroupName " : . . . ,
 " Path " : . . . ,
 " GroupId " : . . . ,
 " CreateDate " : . . . , # str
 " InlinePolicies " : . . . ,
 " ManagedPolicies " : . . . , # These are just the names of the Managed Policies .
 " Users " : . . . , # False by default - - these are just the names of the users .
 " _ version " : 1
 : param flags : By default , Users is disabled . This is somewhat expensive as it has to call the ` get _ group ` call
 multiple times .
 : param group : dict MUST contain the GroupName and also a combination of either the ARN or the account _ number .
 : param output : Determines whether keys should be returned camelized or underscored .
 : param conn : dict containing enough information to make a connection to the desired account .
 Must at least have ' assume _ role ' key .
 : return : dict containing fully built out Group ."""

implementation:
if not group . get ( 'GroupName' ) :
    raise MissingFieldException ( 'Must include GroupName.' )
group = modify ( group , output = 'camelized' )
_conn_from_args ( group , conn )
return registry . build_out ( flags , start_with = group , pass_datastructure = True , ** conn )


signature:
def get_base ( managed_policy , ** conn ) :
    """Fetch the base Managed Policy .
 This includes the base policy and the latest version document .
 : param managed _ policy :
 : param conn :
 : return :"""

implementation:
managed_policy [ '_version' ] = 1
arn = _get_name_from_structure ( managed_policy , 'Arn' )
policy = get_policy ( arn , ** conn )
document = get_managed_policy_document ( arn , policy_metadata = policy , ** conn )
managed_policy . update ( policy [ 'Policy' ] )
managed_policy [ 'Document' ] = document
# Fix the dates :
managed_policy [ 'CreateDate' ] = get_iso_string ( managed_policy [ 'CreateDate' ] )
managed_policy [ 'UpdateDate' ] = get_iso_string ( managed_policy [ 'UpdateDate' ] )
return managed_policy


signature:
def get_managed_policy ( managed_policy , flags = FLAGS . ALL , ** conn ) :
    """Orchestrates all of the calls required to fully build out an IAM Managed Policy in the following format :
 " Arn " : " . . . " ,
 " PolicyName " : " . . . " ,
 " PolicyId " : " . . . " ,
 " Path " : " . . . " ,
 " DefaultVersionId " : " . . . " ,
 " AttachmentCount " : 123,
 " PermissionsBoundaryUsageCount " : 123,
 " IsAttachable " : . . . ,
 " Description " : " . . . " ,
 " CreateDate " : " . . . " ,
 " UpdateDate " : " . . . " ,
 " Document " : " . . . " ,
 " _ version " : 1
 : param managed _ policy : dict MUST contain the ARN .
 : param flags :
 : param conn :
 : return :"""

implementation:
_conn_from_args ( managed_policy , conn )
return registry . build_out ( flags , start_with = managed_policy , pass_datastructure = True , ** conn )


signature:
def _name ( named ) :
    """Get the name out of an object . This varies based on the type of the input :
 * the " name " of a string is itself
 * the " name " of None is itself
 * the " name " of an object with a property named name is that property -
 as long as it ' s a string
 * otherwise , we raise a ValueError"""

implementation:
if isinstance ( named , basestring ) or named is None :
    return named
elif hasattr ( named , 'name' ) and isinstance ( named . name , basestring ) :
    return named . name
else :
    raise ValueError ( "Can't interpret %s as a name or a configuration object" % named )


signature:
def get_version ( self ) :
    '''obtain the version or just 2.2 . x if < 2.3 . x
 Raises :
 FailedRequestError : If the request fails .'''

implementation:
if self . _version :
    return self . _version
url = "{}/about/version.xml" . format ( self . service_url )
resp = self . http_request ( url )
version = None
if resp . status_code == 200 :
    dom = XML ( resp . content )
    resources = dom . findall ( "resource" )
    for resource in resources :
        if resource . attrib [ "name" ] == "GeoServer" :
            try :
                version = resource . find ( "Version" ) . text
                break
            except AttributeError :
                pass
# This will raise an exception if the catalog is not available
# If the catalog is available but could not return version information ,
# it is an old version that does not support that
if version is None : # just to inform that version < 2.3 . x
    version = "2.2.x"
self . _version = version
return version


signature:
def get_short_version ( self ) :
    '''obtain the shory geoserver version'''

implementation:
gs_version = self . get_version ( )
match = re . compile ( r'[^\d.]+' )
return match . sub ( '' , gs_version ) . strip ( '.' )


signature:
def delete ( self , config_object , purge = None , recurse = False ) :
    """send a delete request
 XXX [ more here ]"""

implementation:
rest_url = config_object . href
params = [ ]
# purge deletes the SLD from disk when a style is deleted
if purge :
    params . append ( "purge=" + str ( purge ) )
# recurse deletes the resource when a layer is deleted .
if recurse :
    params . append ( "recurse=true" )
if params :
    rest_url = rest_url + "?" + "&" . join ( params )
headers = { "Content-type" : "application/xml" , "Accept" : "application/xml" }
resp = self . http_request ( rest_url , method = 'delete' , headers = headers )
if resp . status_code != 200 :
    raise FailedRequestError ( 'Failed to make DELETE request: {}, {}' . format ( resp . status_code , resp . text ) )
self . _cache . clear ( )
# do we really need to return anything other than None ?
return ( resp )


signature:
def save ( self , obj , content_type = "application/xml" ) :
    """saves an object to the REST service
 gets the object ' s REST location and the data from the object ,
 then POSTS the request ."""

implementation:
rest_url = obj . href
data = obj . message ( )
headers = { "Content-type" : content_type , "Accept" : content_type }
logger . debug ( "{} {}" . format ( obj . save_method , obj . href ) )
resp = self . http_request ( rest_url , method = obj . save_method . lower ( ) , data = data , headers = headers )
if resp . status_code not in ( 200 , 201 ) :
    raise FailedRequestError ( 'Failed to save to Geoserver catalog: {}, {}' . format ( resp . status_code , resp . text ) )
self . _cache . clear ( )
return resp


signature:
def get_stores ( self , names = None , workspaces = None ) :
    '''Returns a list of stores in the catalog . If workspaces is specified will only return stores in those workspaces .
 If names is specified , will only return stores that match .
 names can either be a comma delimited string or an array .
 Will return an empty list if no stores are found .'''

implementation:
if isinstance ( workspaces , Workspace ) :
    workspaces = [ workspaces ]
elif isinstance ( workspaces , list ) and [ w for w in workspaces if isinstance ( w , Workspace ) ] : # nothing
    pass
else :
    workspaces = self . get_workspaces ( names = workspaces )
stores = [ ]
for ws in workspaces :
    ds_list = self . get_xml ( ws . datastore_url )
    cs_list = self . get_xml ( ws . coveragestore_url )
    wms_list = self . get_xml ( ws . wmsstore_url )
    stores . extend ( [ datastore_from_index ( self , ws , n ) for n in ds_list . findall ( "dataStore" ) ] )
    stores . extend ( [ coveragestore_from_index ( self , ws , n ) for n in cs_list . findall ( "coverageStore" ) ] )
    stores . extend ( [ wmsstore_from_index ( self , ws , n ) for n in wms_list . findall ( "wmsStore" ) ] )
if names is None :
    names = [ ]
elif isinstance ( names , basestring ) :
    names = [ s . strip ( ) for s in names . split ( ',' ) if s . strip ( ) ]
if stores and names :
    return ( [ store for store in stores if store . name in names ] )
return stores


signature:
def get_store ( self , name , workspace = None ) :
    '''Returns a single store object .
 Will return None if no store is found .
 Will raise an error if more than one store with the same name is found .'''

implementation:
stores = self . get_stores ( workspaces = workspace , names = name )
return self . _return_first_item ( stores )


signature:
def create_coveragestore ( self , name , workspace = None , path = None , type = 'GeoTIFF' , create_layer = True , layer_name = None , source_name = None , upload_data = False , contet_type = "image/tiff" ) :
    """Create a coveragestore for locally hosted rasters .
 If create _ layer is set to true , will create a coverage / layer .
 layer _ name and source _ name are only used if create _ layer ia enabled . If not specified , the raster name will be used for both ."""

implementation:
if path is None :
    raise Exception ( 'You must provide a full path to the raster' )
if layer_name is not None and ":" in layer_name :
    ws_name , layer_name = layer_name . split ( ':' )
allowed_types = [ 'ImageMosaic' , 'GeoTIFF' , 'Gtopo30' , 'WorldImage' , 'AIG' , 'ArcGrid' , 'DTED' , 'EHdr' , 'ERDASImg' , 'ENVIHdr' , 'GeoPackage (mosaic)' , 'NITF' , 'RPFTOC' , 'RST' , 'VRT' ]
if type is None :
    raise Exception ( 'Type must be declared' )
elif type not in allowed_types :
    raise Exception ( 'Type must be one of {}' . format ( ", " . join ( allowed_types ) ) )
if workspace is None :
    workspace = self . get_default_workspace ( )
workspace = _name ( workspace )
if upload_data is False :
    cs = UnsavedCoverageStore ( self , name , workspace )
    cs . type = type
    cs . url = path if path . startswith ( "file:" ) else "file:{}" . format ( path )
    self . save ( cs )
    if create_layer :
        if layer_name is None :
            layer_name = os . path . splitext ( os . path . basename ( path ) ) [ 0 ]
        if source_name is None :
            source_name = os . path . splitext ( os . path . basename ( path ) ) [ 0 ]
        data = "<coverage><name>{}</name><nativeName>{}</nativeName></coverage>" . format ( layer_name , source_name )
        url = "{}/workspaces/{}/coveragestores/{}/coverages.xml" . format ( self . service_url , workspace , name )
        headers = { "Content-type" : "application/xml" }
        resp = self . http_request ( url , method = 'post' , data = data , headers = headers )
        if resp . status_code != 201 :
            FailedRequestError ( 'Failed to create coverage/layer {} for : {}, {}' . format ( layer_name , name , resp . status_code , resp . text ) )
        self . _cache . clear ( )
        return self . get_resources ( names = layer_name , workspaces = workspace ) [ 0 ]
else :
    data = open ( path , 'rb' )
    params = { "configure" : "first" , "coverageName" : name }
    url = build_url ( self . service_url , [ "workspaces" , workspace , "coveragestores" , name , "file.{}" . format ( type . lower ( ) ) ] , params )
    headers = { "Content-type" : contet_type }
    resp = self . http_request ( url , method = 'put' , data = data , headers = headers )
    if hasattr ( data , "close" ) :
        data . close ( )
    if resp . status_code != 201 :
        FailedRequestError ( 'Failed to create coverage/layer {} for : {}, {}' . format ( layer_name , name , resp . status_code , resp . text ) )
return self . get_stores ( names = name , workspaces = workspace ) [ 0 ]


signature:
def add_granule ( self , data , store , workspace = None ) :
    '''Harvest / add a granule into an existing imagemosaic'''

implementation:
ext = os . path . splitext ( data ) [ - 1 ]
if ext == ".zip" :
    type = "file.imagemosaic"
    upload_data = open ( data , 'rb' )
    headers = { "Content-type" : "application/zip" , "Accept" : "application/xml" }
else :
    type = "external.imagemosaic"
    upload_data = data if data . startswith ( "file:" ) else "file:{data}" . format ( data = data )
    headers = { "Content-type" : "text/plain" , "Accept" : "application/xml" }
params = dict ( )
workspace_name = workspace
if isinstance ( store , basestring ) :
    store_name = store
else :
    store_name = store . name
    workspace_name = store . workspace . name
if workspace_name is None :
    raise ValueError ( "Must specify workspace" )
url = build_url ( self . service_url , [ "workspaces" , workspace_name , "coveragestores" , store_name , type ] , params )
try :
    resp = self . http_request ( url , method = 'post' , data = upload_data , headers = headers )
    if resp . status_code != 202 :
        FailedRequestError ( 'Failed to add granule to mosaic {} : {}, {}' . format ( store , resp . status_code , resp . text ) )
    self . _cache . clear ( )
finally :
    if hasattr ( upload_data , "close" ) :
        upload_data . close ( )
# maybe return a list of all granules ?
return None


signature:
def delete_granule ( self , coverage , store , granule_id , workspace = None ) :
    '''Deletes a granule of an existing imagemosaic'''

implementation:
params = dict ( )
workspace_name = workspace
if isinstance ( store , basestring ) :
    store_name = store
else :
    store_name = store . name
    workspace_name = store . workspace . name
if workspace_name is None :
    raise ValueError ( "Must specify workspace" )
url = build_url ( self . service_url , [ "workspaces" , workspace_name , "coveragestores" , store_name , "coverages" , coverage , "index/granules" , granule_id , ".json" ] , params )
# DELETE / workspaces / < ws > / coveragestores / < name > / coverages / < coverage > / index / granules / < granule _ id > . json
headers = { "Content-type" : "application/json" , "Accept" : "application/json" }
resp = self . http_request ( url , method = 'delete' , headers = headers )
if resp . status_code != 200 :
    FailedRequestError ( 'Failed to delete granule from mosaic {} : {}, {}' . format ( store , resp . status_code , resp . text ) )
self . _cache . clear ( )
# maybe return a list of all granules ?
return None


signature:
def list_granules ( self , coverage , store , workspace = None , filter = None , limit = None , offset = None ) :
    '''List granules of an imagemosaic'''

implementation:
params = dict ( )
if filter is not None :
    params [ 'filter' ] = filter
if limit is not None :
    params [ 'limit' ] = limit
if offset is not None :
    params [ 'offset' ] = offset
workspace_name = workspace
if isinstance ( store , basestring ) :
    store_name = store
else :
    store_name = store . name
    workspace_name = store . workspace . name
if workspace_name is None :
    raise ValueError ( "Must specify workspace" )
url = build_url ( self . service_url , [ "workspaces" , workspace_name , "coveragestores" , store_name , "coverages" , coverage , "index/granules.json" ] , params )
# GET / workspaces / < ws > / coveragestores / < name > / coverages / < coverage > / index / granules . json
headers = { "Content-type" : "application/json" , "Accept" : "application/json" }
resp = self . http_request ( url , headers = headers )
if resp . status_code != 200 :
    FailedRequestError ( 'Failed to list granules in mosaic {} : {}, {}' . format ( store , resp . status_code , resp . text ) )
self . _cache . clear ( )
return resp . json ( )


signature:
def mosaic_coverages ( self , store ) :
    '''Returns all coverages in a coverage store'''

implementation:
params = dict ( )
url = build_url ( self . service_url , [ "workspaces" , store . workspace . name , "coveragestores" , store . name , "coverages.json" ] , params )
# GET / workspaces / < ws > / coveragestores / < name > / coverages . json
headers = { "Content-type" : "application/json" , "Accept" : "application/json" }
resp = self . http_request ( url , headers = headers )
if resp . status_code != 200 :
    FailedRequestError ( 'Failed to get mosaic coverages {} : {}, {}' . format ( store , resp . status_code , resp . text ) )
self . _cache . clear ( )
return resp . json ( )


signature:
def publish_featuretype ( self , name , store , native_crs , srs = None , jdbc_virtual_table = None , native_name = None ) :
    '''Publish a featuretype from data in an existing store'''

implementation:
# @ todo native _ srs doesn ' t seem to get detected , even when in the DB
# metadata ( at least for postgis in geometry _ columns ) and then there
# will be a misconfigured layer
if native_crs is None :
    raise ValueError ( "must specify native_crs" )
srs = srs or native_crs
feature_type = FeatureType ( self , store . workspace , store , name )
# because name is the in FeatureType base class , work around that
# and hack in these others that don ' t have xml properties
feature_type . dirty [ 'name' ] = name
feature_type . dirty [ 'srs' ] = srs
feature_type . dirty [ 'nativeCRS' ] = native_crs
feature_type . enabled = True
feature_type . advertised = True
feature_type . title = name
if native_name is not None :
    feature_type . native_name = native_name
headers = { "Content-type" : "application/xml" , "Accept" : "application/xml" }
resource_url = store . resource_url
if jdbc_virtual_table is not None :
    feature_type . metadata = ( { 'JDBC_VIRTUAL_TABLE' : jdbc_virtual_table } )
    params = dict ( )
    resource_url = build_url ( self . service_url , [ "workspaces" , store . workspace . name , "datastores" , store . name , "featuretypes.xml" ] , params )
resp = self . http_request ( resource_url , method = 'post' , data = feature_type . message ( ) , headers = headers )
if resp . status_code not in ( 200 , 201 , 202 ) :
    FailedRequestError ( 'Failed to publish feature type {} : {}, {}' . format ( name , resp . status_code , resp . text ) )
self . _cache . clear ( )
feature_type . fetch ( )
return feature_type


signature:
def get_resources ( self , names = None , stores = None , workspaces = None ) :
    '''Resources include feature stores , coverage stores and WMS stores , however does not include layer groups .
 names , stores and workspaces can be provided as a comma delimited strings or as arrays , and are used for filtering .
 Will always return an array .'''

implementation:
stores = self . get_stores ( names = stores , workspaces = workspaces )
resources = [ ]
for s in stores :
    try :
        resources . extend ( s . get_resources ( ) )
    except FailedRequestError :
        continue
if names is None :
    names = [ ]
elif isinstance ( names , basestring ) :
    names = [ s . strip ( ) for s in names . split ( ',' ) if s . strip ( ) ]
if resources and names :
    return ( [ resource for resource in resources if resource . name in names ] )
return resources


signature:
def get_resource ( self , name = None , store = None , workspace = None ) :
    '''returns a single resource object .
 Will return None if no resource is found .
 Will raise an error if more than one resource with the same name is found .'''

implementation:
resources = self . get_resources ( names = name , stores = store , workspaces = workspace )
return self . _return_first_item ( resources )


signature:
def get_layergroups ( self , names = None , workspaces = None ) :
    '''names and workspaces can be provided as a comma delimited strings or as arrays , and are used for filtering .
 If no workspaces are provided , will return all layer groups in the catalog ( global and workspace specific ) .
 Will always return an array .'''

implementation:
layergroups = [ ]
if workspaces is None or len ( workspaces ) == 0 : # Add global layergroups
    url = "{}/layergroups.xml" . format ( self . service_url )
    groups = self . get_xml ( url )
    layergroups . extend ( [ LayerGroup ( self , g . find ( "name" ) . text , None ) for g in groups . findall ( "layerGroup" ) ] )
    workspaces = [ ]
elif isinstance ( workspaces , basestring ) :
    workspaces = [ s . strip ( ) for s in workspaces . split ( ',' ) if s . strip ( ) ]
elif isinstance ( workspaces , Workspace ) :
    workspaces = [ workspaces ]
if not workspaces :
    workspaces = self . get_workspaces ( )
for ws in workspaces :
    ws_name = _name ( ws )
    url = "{}/workspaces/{}/layergroups.xml" . format ( self . service_url , ws_name )
    try :
        groups = self . get_xml ( url )
    except FailedRequestError as e :
        if "no such workspace" in str ( e ) . lower ( ) :
            continue
        else :
            raise FailedRequestError ( "Failed to get layergroups: {}" . format ( e ) )
    layergroups . extend ( [ LayerGroup ( self , g . find ( "name" ) . text , ws_name ) for g in groups . findall ( "layerGroup" ) ] )
if names is None :
    names = [ ]
elif isinstance ( names , basestring ) :
    names = [ s . strip ( ) for s in names . split ( ',' ) if s . strip ( ) ]
if layergroups and names :
    return ( [ lg for lg in layergroups if lg . name in names ] )
return layergroups


signature:
def get_layergroup ( self , name , workspace = None ) :
    '''returns a single layergroup object .
 Will return None if no layergroup is found .
 Will raise an error if more than one layergroup with the same name is found .'''

implementation:
layergroups = self . get_layergroups ( names = name , workspaces = workspace )
return self . _return_first_item ( layergroups )


signature:
def get_styles ( self , names = None , workspaces = None ) :
    '''names and workspaces can be provided as a comma delimited strings or as arrays , and are used for filtering .
 If no workspaces are provided , will return all styles in the catalog ( global and workspace specific ) .
 Will always return an array .'''

implementation:
all_styles = [ ]
if workspaces is None : # Add global styles
    url = "{}/styles.xml" . format ( self . service_url )
    styles = self . get_xml ( url )
    all_styles . extend ( [ Style ( self , s . find ( 'name' ) . text ) for s in styles . findall ( "style" ) ] )
    workspaces = [ ]
elif isinstance ( workspaces , basestring ) :
    workspaces = [ s . strip ( ) for s in workspaces . split ( ',' ) if s . strip ( ) ]
elif isinstance ( workspaces , Workspace ) :
    workspaces = [ workspaces ]
if not workspaces :
    workspaces = self . get_workspaces ( )
for ws in workspaces :
    url = "{}/workspaces/{}/styles.xml" . format ( self . service_url , _name ( ws ) )
    try :
        styles = self . get_xml ( url )
    except FailedRequestError as e :
        if "no such workspace" in str ( e ) . lower ( ) :
            continue
        elif "workspace {} not found" . format ( _name ( ws ) ) in str ( e ) . lower ( ) :
            continue
        else :
            raise FailedRequestError ( "Failed to get styles: {}" . format ( e ) )
    all_styles . extend ( [ Style ( self , s . find ( "name" ) . text , _name ( ws ) ) for s in styles . findall ( "style" ) ] )
if names is None :
    names = [ ]
elif isinstance ( names , basestring ) :
    names = [ s . strip ( ) for s in names . split ( ',' ) if s . strip ( ) ]
if all_styles and names :
    return ( [ style for style in all_styles if style . name in names ] )
return all_styles


signature:
def get_style ( self , name , workspace = None ) :
    '''returns a single style object .
 Will return None if no style is found .
 Will raise an error if more than one style with the same name is found .'''

implementation:
styles = self . get_styles ( names = name , workspaces = workspace )
return self . _return_first_item ( styles )


signature:
def get_workspaces ( self , names = None ) :
    '''Returns a list of workspaces in the catalog .
 If names is specified , will only return workspaces that match .
 names can either be a comma delimited string or an array .
 Will return an empty list if no workspaces are found .'''

implementation:
if names is None :
    names = [ ]
elif isinstance ( names , basestring ) :
    names = [ s . strip ( ) for s in names . split ( ',' ) if s . strip ( ) ]
data = self . get_xml ( "{}/workspaces.xml" . format ( self . service_url ) )
workspaces = [ ]
workspaces . extend ( [ workspace_from_index ( self , node ) for node in data . findall ( "workspace" ) ] )
if workspaces and names :
    return ( [ ws for ws in workspaces if ws . name in names ] )
return workspaces


signature:
def get_workspace ( self , name ) :
    '''returns a single workspace object .
 Will return None if no workspace is found .
 Will raise an error if more than one workspace with the same name is found .'''

implementation:
workspaces = self . get_workspaces ( names = name )
return self . _return_first_item ( workspaces )


signature:
def md_link ( node ) :
    """Extract a metadata link tuple from an xml node"""

implementation:
mimetype = node . find ( "type" )
mdtype = node . find ( "metadataType" )
content = node . find ( "content" )
if None in [ mimetype , mdtype , content ] :
    return None
else :
    return ( mimetype . text , mdtype . text , content . text )


signature:
def prepare_upload_bundle ( name , data ) :
    """GeoServer ' s REST API uses ZIP archives as containers for file formats such
 as Shapefile and WorldImage which include several ' boxcar ' files alongside
 the main data . In such archives , GeoServer assumes that all of the relevant
 files will have the same base name and appropriate extensions , and live in
 the root of the ZIP archive . This method produces a zip file that matches
 these expectations , based on a basename , and a dict of extensions to paths or
 file - like objects . The client code is responsible for deleting the zip
 archive when it ' s done ."""

implementation:
fd , path = mkstemp ( )
zip_file = ZipFile ( path , 'w' )
for ext , stream in data . items ( ) :
    fname = "%s.%s" % ( name , ext )
    if ( isinstance ( stream , basestring ) ) :
        zip_file . write ( stream , fname )
    else :
        zip_file . writestr ( fname , stream . read ( ) )
zip_file . close ( )
os . close ( fd )
return path


signature:
def md_dimension_info ( name , node ) :
    """Extract metadata Dimension Info from an xml node"""

implementation:
def _get_value ( child_name ) :
    return getattr ( node . find ( child_name ) , 'text' , None )
resolution = _get_value ( 'resolution' )
defaultValue = node . find ( "defaultValue" )
strategy = defaultValue . find ( "strategy" ) if defaultValue is not None else None
strategy = strategy . text if strategy is not None else None
return DimensionInfo ( name , _get_value ( 'enabled' ) == 'true' , _get_value ( 'presentation' ) , int ( resolution ) if resolution else None , _get_value ( 'units' ) , _get_value ( 'unitSymbol' ) , strategy , _get_value ( 'attribute' ) , _get_value ( 'endAttribute' ) , _get_value ( 'referenceValue' ) , _get_value ( 'nearestMatchEnabled' ) )


signature:
def md_dynamic_default_values_info ( name , node ) :
    """Extract metadata Dynamic Default Values from an xml node"""

implementation:
configurations = node . find ( "configurations" )
if configurations is not None :
    configurations = [ ]
    for n in node . findall ( "configuration" ) :
        dimension = n . find ( "dimension" )
        dimension = dimension . text if dimension is not None else None
        policy = n . find ( "policy" )
        policy = policy . text if policy is not None else None
        defaultValueExpression = n . find ( "defaultValueExpression" )
        defaultValueExpression = defaultValueExpression . text if defaultValueExpression is not None else None
        configurations . append ( DynamicDefaultValuesConfiguration ( dimension , policy , defaultValueExpression ) )
return DynamicDefaultValues ( name , configurations )


signature:
def md_jdbc_virtual_table ( key , node ) :
    """Extract metadata JDBC Virtual Tables from an xml node"""

implementation:
name = node . find ( "name" )
sql = node . find ( "sql" )
escapeSql = node . find ( "escapeSql" )
escapeSql = escapeSql . text if escapeSql is not None else None
keyColumn = node . find ( "keyColumn" )
keyColumn = keyColumn . text if keyColumn is not None else None
n_g = node . find ( "geometry" )
geometry = JDBCVirtualTableGeometry ( n_g . find ( "name" ) , n_g . find ( "type" ) , n_g . find ( "srid" ) )
parameters = [ ]
for n_p in node . findall ( "parameter" ) :
    p_name = n_p . find ( "name" )
    p_defaultValue = n_p . find ( "defaultValue" )
    p_defaultValue = p_defaultValue . text if p_defaultValue is not None else None
    p_regexpValidator = n_p . find ( "regexpValidator" )
    p_regexpValidator = p_regexpValidator . text if p_regexpValidator is not None else None
    parameters . append ( JDBCVirtualTableParam ( p_name , p_defaultValue , p_regexpValidator ) )
return JDBCVirtualTable ( name , sql , escapeSql , geometry , keyColumn , parameters )


signature:
def md_entry ( node ) :
    """Extract metadata entries from an xml node"""

implementation:
key = None
value = None
if 'key' in node . attrib :
    key = node . attrib [ 'key' ]
else :
    key = None
if key in [ 'time' , 'elevation' ] or key . startswith ( 'custom_dimension' ) :
    value = md_dimension_info ( key , node . find ( "dimensionInfo" ) )
elif key == 'DynamicDefaultValues' :
    value = md_dynamic_default_values_info ( key , node . find ( "DynamicDefaultValues" ) )
elif key == 'JDBC_VIRTUAL_TABLE' :
    value = md_jdbc_virtual_table ( key , node . find ( "virtualTable" ) )
else :
    value = node . text
if None in [ key , value ] :
    return None
else :
    return ( key , value )


signature:
def resolution_millis ( self ) :
    '''if set , get the value of resolution in milliseconds'''

implementation:
if self . resolution is None or not isinstance ( self . resolution , basestring ) :
    return self . resolution
val , mult = self . resolution . split ( ' ' )
return int ( float ( val ) * self . _multipier ( mult ) * 1000 )


signature:
def resolution_str ( self ) :
    '''if set , get the value of resolution as " < n > < period > s " , for example : " 8 seconds "'''

implementation:
if self . resolution is None or isinstance ( self . resolution , basestring ) :
    return self . resolution
seconds = self . resolution / 1000.
biggest = self . _lookup [ 0 ]
for entry in self . _lookup :
    if seconds < entry [ 1 ] :
        break
    biggest = entry
val = seconds / biggest [ 1 ]
if val == int ( val ) :
    val = int ( val )
return '%s %s' % ( val , biggest [ 0 ] )


signature:
def _init ( self ) :
    """Read resource information into self . _ cache , for cached access .
 See DAVResource . _ init ( )"""

implementation:
# TODO : recalc self . path from < self . _ file _ path > , to fix correct file system case
# On windows this would lead to correct URLs
self . provider . _count_get_resource_inst_init += 1
tableName , primKey = self . provider . _split_path ( self . path )
display_type = "Unknown"
displayTypeComment = ""
contentType = "text/html"
# _ logger . debug ( " getInfoDict ( % s ) , nc = % s " % ( path , self . connectCount ) )
if tableName is None :
    display_type = "Database"
elif primKey is None : # " database " and table name
    display_type = "Database Table"
else :
    contentType = "text/csv"
    if primKey == "_ENTIRE_CONTENTS" :
        display_type = "Database Table Contents"
        displayTypeComment = "CSV Representation of Table Contents"
    else :
        display_type = "Database Record"
        displayTypeComment = "Attributes available as properties"
# Avoid calling is _ collection , since it would call isExisting - > _ init _ connection
is_collection = primKey is None
self . _cache = { "content_length" : None , "contentType" : contentType , "created" : time . time ( ) , "display_name" : self . name , "etag" : hashlib . md5 ( ) . update ( self . path ) . hexdigest ( ) , # " etag " : md5 . new ( self . path ) . hexdigest ( ) ,
"modified" : None , "support_ranges" : False , "display_info" : { "type" : display_type , "typeComment" : displayTypeComment } , }
# Some resource - only infos :
if not is_collection :
    self . _cache [ "modified" ] = time . time ( )
_logger . debug ( "---> _init, nc=%s" % self . provider . _count_initConnection )


signature:
def get_member_list ( self ) :
    """Return list of ( direct ) collection member names ( UTF - 8 byte strings ) .
 See DAVResource . get _ member _ list ( )"""

implementation:
members = [ ]
conn = self . provider . _init_connection ( )
try :
    tableName , primKey = self . provider . _split_path ( self . path )
    if tableName is None :
        retlist = self . provider . _list_tables ( conn )
        for name in retlist :
            members . append ( MySQLBrowserResource ( self . provider , util . join_uri ( self . path , name ) , True , self . environ , ) )
    elif primKey is None :
        pri_key = self . provider . _find_primary_key ( conn , tableName )
        if pri_key is not None :
            retlist = self . provider . _list_fields ( conn , tableName , pri_key )
            for name in retlist :
                members . append ( MySQLBrowserResource ( self . provider , util . join_uri ( self . path , name ) , False , self . environ , ) )
        members . insert ( 0 , MySQLBrowserResource ( self . provider , util . join_uri ( self . path , "_ENTIRE_CONTENTS" ) , False , self . environ , ) , )
finally :
    conn . close ( )
return members


signature:
def get_content ( self ) :
    """Open content as a stream for reading .
 See DAVResource . get _ content ( )"""

implementation:
filestream = compat . StringIO ( )
tableName , primKey = self . provider . _split_path ( self . path )
if primKey is not None :
    conn = self . provider . _init_connection ( )
    listFields = self . provider . _get_field_list ( conn , tableName )
    csvwriter = csv . DictWriter ( filestream , listFields , extrasaction = "ignore" )
    dictFields = { }
    for field_name in listFields :
        dictFields [ field_name ] = field_name
    csvwriter . writerow ( dictFields )
    if primKey == "_ENTIRE_CONTENTS" :
        cursor = conn . cursor ( MySQLdb . cursors . DictCursor )
        cursor . execute ( "SELECT * from " + self . provider . _db + "." + tableName )
        result_set = cursor . fetchall ( )
        for row in result_set :
            csvwriter . writerow ( row )
        cursor . close ( )
    else :
        row = self . provider . _get_record_by_primary_key ( conn , tableName , primKey )
        if row is not None :
            csvwriter . writerow ( row )
    conn . close ( )
# this suffices for small dbs , but
# for a production big database , I imagine you would have a FileMixin that
# does the retrieving and population even as the file object is being read
filestream . seek ( 0 )
return filestream


signature:
def get_property_names ( self , is_allprop ) :
    """Return list of supported property names in Clark Notation .
 Return supported live and dead properties . ( See also DAVProvider . get _ property _ names ( ) . )
 In addition , all table field names are returned as properties ."""

implementation:
# Let default implementation return supported live and dead properties
propNames = super ( MySQLBrowserResource , self ) . get_property_names ( is_allprop )
# Add fieldnames as properties
tableName , primKey = self . provider . _split_path ( self . path )
if primKey is not None :
    conn = self . provider . _init_connection ( )
    fieldlist = self . provider . _get_field_list ( conn , tableName )
    for fieldname in fieldlist :
        propNames . append ( "{%s:}%s" % ( tableName , fieldname ) )
    conn . close ( )
return propNames


signature:
def get_property_value ( self , name ) :
    """Return the value of a property .
 The base implementation handles :
 - ` ` { DAV : } lockdiscovery ` ` and ` ` { DAV : } supportedlock ` ` using the
 associated lock manager .
 - All other * live * properties ( i . e . name starts with ` ` { DAV : } ` ` ) are
 delegated to self . getLivePropertyValue ( )
 - Finally , other properties are considered * dead * , and are handled using
 the associated property manager , if one is present ."""

implementation:
# Return table field as property
tableName , primKey = self . provider . _split_path ( self . path )
if primKey is not None :
    ns , localName = util . split_namespace ( name )
    if ns == ( tableName + ":" ) :
        conn = self . provider . _init_connection ( )
        fieldlist = self . provider . _get_field_list ( conn , tableName )
        if localName in fieldlist :
            val = self . provider . _get_field_by_primary_key ( conn , tableName , primKey , localName )
            conn . close ( )
            return val
        conn . close ( )
# else , let default implementation return supported live and dead properties
return super ( MySQLBrowserResource , self ) . get_property_value ( name )


signature:
def set_property_value ( self , name , value , dry_run = False ) :
    """Set or remove property value .
 See DAVResource . set _ property _ value ( )"""

implementation: raise DAVError ( HTTP_FORBIDDEN , err_condition = PRECONDITION_CODE_ProtectedProperty )


signature:
def _split_path ( self , path ) :
    """Return ( tableName , primaryKey ) tuple for a request path ."""

implementation:
if path . strip ( ) in ( None , "" , "/" ) :
    return ( None , None )
tableName , primKey = util . save_split ( path . strip ( "/" ) , "/" , 1 )
# _ logger . debug ( " ' % s ' - > ( ' % s ' , ' % s ' ) " % ( path , tableName , primKey ) )
return ( tableName , primKey )


signature:
def get_resource_inst ( self , path , environ ) :
    """Return info dictionary for path .
 See get _ resource _ inst ( )"""

implementation:
# TODO : calling exists ( ) makes directory browsing VERY slow .
# At least compared to PyFileServer , which simply used string
# functions to get display _ type and displayTypeComment
self . _count_get_resource_inst += 1
if not self . exists ( path , environ ) :
    return None
_tableName , primKey = self . _split_path ( path )
is_collection = primKey is None
return MySQLBrowserResource ( self , path , is_collection , environ )


signature:
def get_http_status_string ( v ) :
    """Return HTTP response string , e . g . 204 - > ( ' 204 No Content ' ) .
 The return string always includes descriptive text , to satisfy Apache mod _ dav .
 ` v ` : status code or DAVError"""

implementation:
code = get_http_status_code ( v )
try :
    return ERROR_DESCRIPTIONS [ code ]
except KeyError :
    return "{} Status" . format ( code )


signature:
def as_DAVError ( e ) :
    """Convert any non - DAVError exception to HTTP _ INTERNAL _ ERROR ."""

implementation:
if isinstance ( e , DAVError ) :
    return e
elif isinstance ( e , Exception ) : # traceback . print _ exc ( )
    return DAVError ( HTTP_INTERNAL_ERROR , src_exception = e )
else :
    return DAVError ( HTTP_INTERNAL_ERROR , "{}" . format ( e ) )


signature:
def get_user_info ( self ) :
    """Return readable string ."""

implementation:
if self . value in ERROR_DESCRIPTIONS :
    s = "{}" . format ( ERROR_DESCRIPTIONS [ self . value ] )
else :
    s = "{}" . format ( self . value )
if self . context_info :
    s += ": {}" . format ( self . context_info )
elif self . value in ERROR_RESPONSES :
    s += ": {}" . format ( ERROR_RESPONSES [ self . value ] )
if self . src_exception :
    s += "\n    Source exception: '{}'" . format ( self . src_exception )
if self . err_condition :
    s += "\n    Error condition: '{}'" . format ( self . err_condition )
return s


signature:
def get_response_page ( self ) :
    """Return a tuple ( content - type , response page ) ."""

implementation:
# If it has pre - or post - condition : return as XML response
if self . err_condition :
    return ( "application/xml" , compat . to_bytes ( self . err_condition . as_string ( ) ) )
# Else return as HTML
status = get_http_status_string ( self )
html = [ ]
html . append ( "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' " "'http://www.w3.org/TR/html4/strict.dtd'>" )
html . append ( "" )
html . append ( "  <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>" )
html . append ( "  <title>{}</title>" . format ( status ) )
html . append ( "" )
html . append ( "
{}
" . format ( status ) )
html . append ( "
{}
" . format ( compat . html_escape ( self . get_user_info ( ) ) ) )
html . append ( "
" )
html . append ( "WsgiDAV/{} - {}" . format ( __version__ , compat . html_escape ( str ( datetime . datetime . now ( ) ) , "utf-8" ) ) )
html . append ( "" )
html = "\n" . join ( html )
return ( "text/html" , compat . to_bytes ( html ) )


signature:
def handle_delete ( self ) :
    """Change semantic of DELETE to remove resource tags ."""

implementation:
# DELETE is only supported for the ' / by _ tag / ' collection
if "/by_tag/" not in self . path :
    raise DAVError ( HTTP_FORBIDDEN )
# path must be ' / by _ tag / < tag > / < resname > '
catType , tag , _rest = util . save_split ( self . path . strip ( "/" ) , "/" , 2 )
assert catType == "by_tag"
assert tag in self . data [ "tags" ]
self . data [ "tags" ] . remove ( tag )
return True


signature:
def handle_copy ( self , dest_path , depth_infinity ) :
    """Change semantic of COPY to add resource tags ."""

implementation:
# destPath must be ' / by _ tag / < tag > / < resname > '
if "/by_tag/" not in dest_path :
    raise DAVError ( HTTP_FORBIDDEN )
catType , tag , _rest = util . save_split ( dest_path . strip ( "/" ) , "/" , 2 )
assert catType == "by_tag"
if tag not in self . data [ "tags" ] :
    self . data [ "tags" ] . append ( tag )
return True


signature:
def handle_move ( self , dest_path ) :
    """Change semantic of MOVE to change resource tags ."""

implementation:
# path and destPath must be ' / by _ tag / < tag > / < resname > '
if "/by_tag/" not in self . path :
    raise DAVError ( HTTP_FORBIDDEN )
if "/by_tag/" not in dest_path :
    raise DAVError ( HTTP_FORBIDDEN )
catType , tag , _rest = util . save_split ( self . path . strip ( "/" ) , "/" , 2 )
assert catType == "by_tag"
assert tag in self . data [ "tags" ]
self . data [ "tags" ] . remove ( tag )
catType , tag , _rest = util . save_split ( dest_path . strip ( "/" ) , "/" , 2 )
assert catType == "by_tag"
if tag not in self . data [ "tags" ] :
    self . data [ "tags" ] . append ( tag )
return True


signature:
def get_property_names ( self , is_allprop ) :
    """Return list of supported property names in Clark Notation .
 See DAVResource . get _ property _ names ( )"""

implementation:
# Let base class implementation add supported live and dead properties
propNameList = super ( VirtualResource , self ) . get_property_names ( is_allprop )
# Add custom live properties ( report on ' allprop ' and ' propnames ' )
propNameList . extend ( VirtualResource . _supportedProps )
return propNameList


signature:
def get_property_value ( self , name ) :
    """Return the value of a property .
 See get _ property _ value ( )"""

implementation:
# Supported custom live properties
if name == "{virtres:}key" :
    return self . data [ "key" ]
elif name == "{virtres:}title" :
    return self . data [ "title" ]
elif name == "{virtres:}status" :
    return self . data [ "status" ]
elif name == "{virtres:}orga" :
    return self . data [ "orga" ]
elif name == "{virtres:}tags" : # ' tags ' is a string list
    return "," . join ( self . data [ "tags" ] )
elif name == "{virtres:}description" :
    return self . data [ "description" ]
# Let base class implementation report live and dead properties
return super ( VirtualResource , self ) . get_property_value ( name )


implementation:
if value is None : # We can never remove properties
    raise DAVError ( HTTP_FORBIDDEN )
if name == "{virtres:}tags" : # value is of type etree . Element
    self . data [ "tags" ] = value . text . split ( "," )
elif name == "{virtres:}description" : # value is of type etree . Element
    self . data [ "description" ] = value . text
elif name in VirtualResource . _supportedProps : # Supported property , but read - only
    raise DAVError ( HTTP_FORBIDDEN , err_condition = PRECONDITION_CODE_ProtectedProperty )
else : # Unsupported property
    raise DAVError ( HTTP_FORBIDDEN )
# Write OK
return


signature:
def get_resource_inst ( self , path , environ ) :
    """Return _ VirtualResource object for path .
 path is expected to be
 categoryType / category / name / artifact
 for example :
 ' by _ tag / cool / My doc 2 / info . html '
 See DAVProvider . get _ resource _ inst ( )"""

implementation:
_logger . info ( "get_resource_inst('%s')" % path )
self . _count_get_resource_inst += 1
root = RootCollection ( environ )
return root . resolve ( "" , path )