Exemple #1
0
def GetResources(client, api_id):
    response_get_resources = client.get_resources(restApiId=api_id)
    resources = response_get_resources['items']

    resources_dict = {}

    for resource in resources:
        #print(resource)
        resource_id = resource['id']
        resource_path = resource['path']

        methods = []
        if resource_path != '/':  # avoid root path, which don't have methods
            resource_methods = resource['resourceMethods']
        for method in resource_methods:
            methods.append(method)

        resource = resource_path.split('/')
        length = len(resource)
        if length == 3:
            resource = resource[-1].replace('{', '')
            resource = resource.replace('}', '')
        elif length == 4:
            resource = resource[-2].replace('{', '') + '_' + resource[-1]
            resource = resource.replace('}', '')
        elif length == 2 and resource[-1] != '':
            resource = resource[-1]

        if type(resource) == str:
            temp_lst = [resource_id, methods]
            resources_dict[resource] = temp_lst
    logger.generatedDebug('API Resource Dictionary',
                          json.dumps(resources_dict))
    return resources_dict
def GetFeatureStageFuncs(stg_var_name_lst):
  # get stage name
  stg_name = input('Enter new feature stage sprint number: ')
  try:
    stg_name = int(stg_name)
  except:
    logger.inputError('Stage sprint number must be numeric')
    
  stg_name = 'feature-sprint' + str(stg_name)
  logger.inputTrace('Stage Name', stg_name)
    
  print ('List of stage variables:')
  length = len(stg_var_name_lst)
  for l in range(length):
    print(str(l+1)+'.'+ stg_var_name_lst[l], end=" ")
  print('')

  stg_vars_get = input('Enter method name/number-responsible party, separate by comma, or type all for all:')

  stg_vars_get = stg_vars_get.replace(" ", "")
  logger.inputTrace('Method Selection', stg_vars_get)
  if stg_vars_get.lower() == 'all':
    l = len(stg_var_name_lst)
    stg_vars_get = []
    for i in range(l):
      stg_vars_get.append(str(i+1))
  else:
    stg_vars_get = stg_vars_get.split(',')
  stg_vars_updated = {}

  if stg_vars_get[0].lower() != 'all':
    for var in stg_vars_get:
      methodName = ''
      if var.isnumeric():
        methodNum = int(var) - 1
        methodName = stg_var_name_lst[methodNum]
      elif '_' in var:
        var = var.lower()
        methodName = var.split('_')
        methodName = var.replace(methodName[-1], methodName[-1].upper())
        if methodName not in stg_var_name_lst:
          logger.inputError('Method name you enter is not a known method')
          os.abort()
      else:
        logger.inputError('Cannot identify the method number/name')
      
      lambdaName = stg_name + '-api-' + methodName.lower().replace('_','-')

      stg_vars_updated[methodName] = lambdaName
  else:
    for var in stg_var_name_lst:
      methodName = var
      lambdaName = stg_name + '-api-' + methodName.lower().replace('_','-').replace('-id', '_id')

      stg_vars_updated[methodName] = lambdaName
  
  logger.generatedDebug('Feature Functions', json.dumps(stg_vars_updated))
  
  return (stg_vars_updated)
def GetSourceArn(api_id, function_name, method, resource_path):
  source_arn = function_name.replace('lambda', 'execute-api')
  temp = api_id + '/*/'
  source_arn = source_arn.replace('function:', temp)
  source_arn = source_arn.split('${')[0]
  source_arn = source_arn + method
  resource_path = re.sub("\{\w*}",'*', resource_path)
  # logger.runTrace('Regex resource path', resource_path)
  source_arn = source_arn + resource_path
  # print(source_arn)
  logger.generatedDebug('source arn', source_arn)
  return (source_arn)
def GetFunctionName(client_api, api_id, resource_id, http_method):
  logger.runTrace('for resource_method', resource_id + '_' + http_method)
  response = client_api.get_integration(
    restApiId = api_id,
    resourceId = resource_id,
    httpMethod = http_method
  )
  logger.runTrace('get integration', json.dumps(response))
  
  function_name =''
  # avoid errors with option methods
  if response['type'] == 'AWS':
    function_name = response['uri'].rsplit('/', 1)[0]
    function_name = function_name.split('arn:')[2]
    function_name = 'arn:' + function_name
  logger.generatedDebug('Raw Function Name', function_name)
  return(function_name)
def GetResourcesDict(resources, client_api, api_id):
  
  resources_dict = {}
  for resource in resources:
    #print(resource)
    resource_id = resource['id']
    resource_path = resource['path']

    methods = []
    # this gives a dict {resource_id:[[method, statement_id, resource_path],...]}
    if resource_path != '/': # avoid root path, which don't have methods
      resource_methods = resource['resourceMethods']
      for method in resource_methods:
        method_statement_id = []
        method_statement_id.append(method)
        #T generate pesudo statement id based on the method 
        statement_id = resource_path.replace('/{', '-')
        statement_id = statement_id.replace('}/', '-')
        statement_id = statement_id.replace('}', '-')
        statement_id = statement_id.replace('_', '-')
        statement_id = statement_id.replace('/', '')
        statement_id = statement_id + '-' + method.lower()
        method_statement_id.append(statement_id)
        method_statement_id.append(resource_path)
        
        methods.append(method_statement_id)
      resources_dict[resource_id] = methods
  logger.generatedDebug('Resource Dictionary', json.dumps(resources_dict))
  
  for id, methods in resources_dict.items():
    value_sets = []
    for method in methods:
      if method[0] != 'OPTIONS':
        value_set = []
        method_function_pair = {}
        function_name = GetFunctionName(client_api, api_id, id, method[0])
        method_function_pair[method[0]] = function_name
        value_set.append(method_function_pair)
        value_set.append(method[1])
        source_arn = GetSourceArn(api_id, function_name, method[0], method[2])
        value_set.append(source_arn)
        value_sets.append(value_set)
      logger.runTrace('value set', json.dumps(value_set))
      resources_dict[id] = value_sets
  return (resources_dict)
def GetDevProdStageFunc(stg_var_name_lst):
  dev_funcs = []
  for name in stg_var_name_lst:
    method = name.split('_')[-1]
    val = name.replace('_' + method, '-' + method.lower())
    dev_funcs.append('dev-' + val)
    # print(val)
    
  prod_funcs = []
  for name in stg_var_name_lst:
    method = name.split('_')[-1]
    val = name.replace('_' + method, '-' + method.lower())
    prod_funcs.append('prod-' + val)
  
  dev_prod_funcs = list(zip(dev_funcs, prod_funcs))
  dev_prod_stg_funcs = dict(zip(stg_var_name_lst, dev_prod_funcs))
  logger.generatedDebug('Development and Production Stage Functions:', dev_prod_stg_funcs)
  return (dev_prod_stg_funcs)
Exemple #7
0
def PutOPTIONSMethod(client, api_id, resource_id):
    logger.runTrace('Create OPTIONS Method for resource', resource_id)

    response_put_option = client.put_method(
        restApiId=api_id,
        resourceId=resource_id,
        httpMethod='OPTIONS',
        authorizationType=
        'NONE'  #NONE for open access, COGNITO_USER_POOLS for cognito
    )
    logger.generatedDebug('OPTIONS Method created',
                          json.dumps(response_put_option))

    response_put_integration = client.put_integration(
        restApiId=api_id,
        resourceId=resource_id,
        httpMethod='OPTIONS',
        type='MOCK',
        requestTemplates={'application/json': '{"statusCode": 200}'
                          }  #this is needed so options will return 200
    )
    logger.generatedDebug('OPTIONS Integration set type', 'MOCK')

    response_put_method_response = client.put_method_response(
        restApiId=api_id,
        resourceId=resource_id,
        httpMethod='OPTIONS',
        statusCode='200')
    logger.generatedDebug('OPTIONS Method Response set status Code', '200')
Exemple #8
0
    logger.inputError('Cannot identify the method number/name')

  lambdaName = branch + '-' + methodName.lower().replace('_','-')

  if branch not in ['dev', 'prod']:
    partyName = 'api'
    lambdaName = branch + '-' + partyName + '-' + methodName.lower().replace('_','-')
  
  lambdaName = lambdaName.replace('_','-')
  lambdaName = lambdaName.replace('-id', '_id')


      stg_vars_updated[methodName] = lambdaName

for sv, ln in stg_vars_updated.items():
  logger.generatedDebug('Stage Variables', sv)
  logger.generatedDebug('Lambda Function Name', ln)
  # all none updated stg_vars connect to dev functions
  ln = ln.replace('_','-')
  ln = ln.replace('-id', '_id')
  stg_vars[sv] = ln 

# generate stage description
description = input('Enter description for the new stage: ')
logger.inputTrace('Description', description)

if description == '':
  description = stg_name + 'for Key Management app api development.'

#LOG stage variables and description
logger.generatedDebug('Stage Description',
Exemple #9
0
def main():
    status_code_pattern = {
        '200': 'Default',
        '201': 'Created',
        '204': 'No Content',
        '400': 'Bad Request',
        '404': 'Not Found',
        '403': 'Forbidden',
        '405': 'Not Allowed',
        '500': 'Server Error'
    }
    for status_code, pattern in status_code_pattern.items():
        if pattern.lower() != 'default':
            status_code_pattern[
                status_code] = '.*' + status_code_pattern[status_code] + '.*'
    logger.generatedDebug('Status Code Keywords',
                          json.dumps(status_code_pattern))

    responseTemplates = {
        'application/json':
        '#set($inputRoot = $input.path(\'$\'))\n$input.json("$")\n#if($inputRoot.toString().contains("Created"))\n#set($context.responseOverride.status = 201)\n#end\n#if($inputRoot.toString().contains("No Content"))\n#set($context.responseOverride.status = 204)\n#end\n#if($inputRoot.toString().contains("Bad Request"))\n#set($context.responseOverride.status = 400)\n#end\n#if($inputRoot.toString().contains("Forbidden"))\n#set($context.responseOverride.status = 403)\n#end\n#if($inputRoot.toString().contains("Not Found"))\n#set($context.responseOverride.status = 404)\n#end\n#if($inputRoot.toString().contains("Not Allowed"))\n#set($context.responseOverride.status = 405)\n#end\n#if($inputRoot.toString().contains("Server Error"))\n#set($context.responseOverride.status = 500)\n#end'
    }

    #* set logger
    logger.setLogger('api_gateway_cors_enable.log')
    #* get boto3 client
    client = boto3.client('apigateway')

    #* get api key with default to prod
    api_id = GetAPIId()
    #* get a dict of resources for the API {resource_name:resource_id,[methods]}
    resources_dict = GetResources(client, api_id)

    #* if resource does not have OPTIONS method, add OPTIONS to resource for each
    for resource in resources_dict:
        resource_id = resources_dict[resource][0]
        methods = resources_dict[resource][1]
        if 'OPTIONS' not in methods:
            methods.append('OPTIONS')
            PutOPTIONSMethod(client, api_id, resource_id)
            resources_dict[resource][1] = methods

    #* set Response Headers
    response_headers = [
        'X-Requested-With', 'Access-Control-Allow-Headers',
        'Access-Control-Allow-Origin', 'Access-Control-Allow-Methods'
    ]
    resp_headers_methods = []
    resp_headers_integration = []

    for header in response_headers:
        resp_headers_methods.append('method.response.header.' + header)
        resp_headers_integration.append('integration.response.header.' +
                                        header)
    print('Method Headers:')
    print(resp_headers_methods)
    print('Integration Headers:')
    print(resp_headers_integration)
    XRW_val = "'*'"
    ACAH_val = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,x-requested-with'"
    ACAO_val = "'https://www.2edusite.com'"  #"'*'"

    headers_vals = (XRW_val, ACAH_val, ACAO_val)

    method_respPara = {}
    for header in resp_headers_methods:
        method_respPara[header] = True
    print('Method Parameters: ')
    print(method_respPara)

    PutCORSResponds(client, api_id, resources_dict, method_respPara,
                    resp_headers_methods, headers_vals, status_code_pattern,
                    responseTemplates)
Exemple #10
0
def PutCORSResponds(client, api_id, resources_dict, method_respPara,
                    resp_headers_methods, headers_vals, status_code_pattern,
                    responseTemplates):
    for resource in resources_dict:
        logger.runTrace('for resource', resource)
        resource_id = resources_dict[resource][0]
        logger.runTrace('resource', resource)

        methods = resources_dict[resource][1]
        methods_str = ','.join(methods)
        methods_str = "'" + methods_str + "'"
        logger.runTrace('with methods', methods_str)

        integration_mapping = []
        for header_val in headers_vals:
            integration_mapping.append(header_val)
        integration_mapping.append(methods_str)
        logger.generatedDebug('Integration Mapping',
                              json.dumps(integration_mapping))

        integration_respPara = {}
        integration_respPara = dict(
            zip(resp_headers_methods, integration_mapping))
        logger.generatedDebug('Integration Parameters',
                              json.dumps(integration_respPara))

        for method in methods:
            logger.runTrace('for method', method)

            #* Get status codes
            response_get_method = client.get_method(restApiId=api_id,
                                                    resourceId=resource_id,
                                                    httpMethod=method)
            logger.generatedDebug('Method Detail',
                                  json.dumps(response_get_method))
            method_responses = response_get_method['methodResponses']
            logger.runTrace('Method Responses', json.dumps(method_responses))
            status_codes = list(method_responses.keys())
            logger.runTrace('Status Codes', json.dumps(status_codes))

            #* if status codes not include 200 add 200, as long as it is not OPTIONS
            if '200' not in status_codes and method != 'OPTIONS':
                status_codes.append('200')

            for status_code in status_codes:
                logger.runTrace('for status code', status_code)
                logger.runTrace('pattern', status_code_pattern[status_code])

                #! delete Method Response Headers if there is one
                try:
                    response_delete_method = client.delete_method_response(
                        restApiId=api_id,
                        resourceId=resource_id,
                        httpMethod=method,
                        statusCode=status_code)
                    logger.runTrace('Method deletion',
                                    json.dumps(response_delete_method))
                except:
                    logger.runTrace('Method deletion failed',
                                    'Method does not exist')

                #! delete Integration Response Headers if there is one
                try:
                    response_delete_integration = client.delete_integration_response(
                        restApiId=api_id,
                        resourceId=resource_id,
                        httpMethod=method,
                        statusCode=status_code)
                    logger.runTrace('Integration deletion',
                                    json.dumps(response_delete_integration))
                except:
                    logger.runTrace('Integration deletion failed',
                                    'Integration does not exist')

                #* put Method Response Headers
                response_put_method = client.put_method_response(
                    restApiId=api_id,
                    resourceId=resource_id,
                    httpMethod=method,
                    statusCode=status_code,
                    responseParameters=method_respPara)
                print(response_put_method)
                logger.createInfo('Method Response',
                                  json.dumps(response_put_method))

                #* put Integration Responses Header Mappings
                if status_code_pattern[status_code].lower() == 'default':
                    response_put_integration = client.put_integration_response(
                        restApiId=api_id,
                        resourceId=resource_id,
                        httpMethod=method,
                        statusCode=status_code,
                        responseParameters=integration_respPara,
                        responseTemplates=responseTemplates)
                else:
                    response_put_integration = client.put_integration_response(
                        restApiId=api_id,
                        resourceId=resource_id,
                        httpMethod=method,
                        statusCode=status_code,
                        selectionPattern=status_code_pattern[status_code],
                        responseParameters=integration_respPara)
                print(response_put_integration)
def main():
  #constant
  stg_var_name_lst = ['keybundle_GET',
                    'keybundle_id_DELETE',
                    'keybundle_id_GET',
                    'keybundle_id_PUT',
                    'keyholder_GET',
                    'keyholder_POST',
                    'keyholder_id_DELETE',
                    'keyholder_id_GET',
                    'keyholder_id_PUT',
                    'property_GET',
                    'property_POST',
                    'property_id_DELETE',
                    'property_id_GET',
                    'property_id_PUT',
                    'property_id_keybundle_GET',
                    'property_id_keybundle_POST'
                    ]
  
  #set logger
  logger.setLogger('api_gateway_lambda_stage_variable_enable.log')
  #set client for api
  client_api = boto3.client('apigateway')
  
  #get API
  api_id = GetAPIId()
  #get feature stage
  isFeature = input('Is this for the feature stage?(y/n) ')
  logger.inputTrace('Is Feature', isFeature)
  if isFeature.lower() ==  'y' or isFeature.lower() ==  'yes':
    feature_funcs = GetFeatureStageFuncs(stg_var_name_lst)
    isFeature = True
  else:
    isFeature = False
  
  response_get_resources = client_api.get_resources(
    restApiId=api_id
  )
  resources = response_get_resources['items']
  logger.generatedDebug('Resources of API', json.dumps(resources))
  # this gives {resource_id:[{method:functionName}, statement_id, source_arn],[]...}
  resources_dict = GetResourcesDict(resources, client_api, api_id)
  logger.generatedDebug('Resource Dictionary with Function Names', json.dumps(resources_dict))

  #  get boto3 clinet for lambda
  client_lambda = boto3.client('lambda')
  
  # lambda add permission
  isPandD= input('Is this also for the production and development stages?(y/n) ')
  logger.inputTrace('Is production and development', isPandD)
  function_name = ''
  if isPandD.lower() ==  'y' or isPandD.lower() ==  'yes':
    dev_prod_funcs = GetDevProdStageFunc(stg_var_name_lst)
    
    for method_set in resources_dict.values():
      # print(method_set)
      for method in method_set:
        # print(method)
        logger.runTrace('for method', json.dumps(method))
        for k in method[0].values():
          function_name = k
        # print(function_name)
        logger.runTrace('with stage variable', json.dumps(function_name))
        statement_id = method[1]
        source_arn = method[2]
        
        function_name_part = function_name.split('${stageVariables.')
        # print(function_name_part)
        function_name_part[1] = function_name_part[1].replace('}', '')
        
        # print(dev_prod_funcs.keys())
        if function_name_part[1] in dev_prod_funcs.keys():
          
          for val in dev_prod_funcs[function_name_part[1]]:
            function_name = function_name_part[0] + val.replace('id_','id-')
            logger.runTrace('invoke function', function_name)
            try:
              LambdaRemovePermission(client_lambda, function_name, statement_id) 
            except:
              logger.runTrace('Permission Removal', 'permission not exist')           
            try:
              LambdaAddPermission(client_lambda, api_id, function_name, statement_id, source_arn)
            except:
              print('AddPermission failed for', function_name)
            else:
              print('Development and Production permission successfully added!')
  if isFeature:
    for method_set in resources_dict.values():
      # print(method_set)
      for method in method_set:
        logger.runTrace('for method', json.dumps(method))
        for k in method[0].values():
          function_name = k
        # logger.runTrace('with stage variable', json.dumps(function_name))
        statement_id = method[1]
        source_arn = method[2]
        
        function_name_part = function_name.split('${stageVariables.')
        function_name_part[1] = function_name_part[1].replace('}', '')
        # print(function_name_part)
        # print(feature_funcs.keys())
        if function_name_part[1] in feature_funcs.keys():
          function_name = function_name_part[0] + feature_funcs[function_name_part[1]].replace('-id','_id')
          print(function_name)
          logger.runTrace('invoke function', function_name)
          try:
              LambdaRemovePermission(client_lambda, function_name, statement_id) 
          except:
            logger.runTrace('Permission Removal', 'permission not exist')  
          try:
            LambdaAddPermission(client_lambda, api_id, function_name, statement_id, source_arn)
          except:
            print('AddPermission failed for', function_name)
          else:
            print('Feature permission successfully added!')