def test_config_custom_data(self):
        target_custom_data = "custom_data"
        EFConfig.CUSTOM_DATA = {"mock_data": "custom_data"}

        ef_config_resolver = EFConfigResolver()
        result_custom_data = ef_config_resolver.lookup("customdata,mock_data")
        self.assertEquals(result_custom_data, target_custom_data)
 def test_account_alias_of_env(self):
     """Does accountaliasofenv,prod resolve to the prod account alias"""
     ef_config_resolver = EFConfigResolver()
     result_config_data = ef_config_resolver.lookup(
         "accountaliasofenv,test")
     if result_config_data is None:
         result_config_data = ''
     self.assertRegexpMatches(result_config_data, "^testaccount$")
Beispiel #3
0
  def __init__(self,
               profile=None, region=None,  # set both for user access mode
               lambda_context=None,  # set if target is 'self' and this is a lambda
               target_other=False, env=None, service=None,  # set env & service if target_other=True
               verbose=False
               ):
    """
    Depending on how this is called, access mode (how it logs into AWS) and target (what the
      various context vars report) will vary

    ACCESS MODE - how this logs in to AWS
      user: "******"
        both 'profile' and 'region' are required
        is always "operating on something else" (TARGET is never "self")
      role: "running in AWS EC2 or Lambda with a role credential"
        do not set profile

    TARGET - what context is reported
      self: "this ec2 instance or lambda is initializing itself"
        assumed for ec2 and lambda, unless target_other=True in the constructor
        never an option for "user" access mode
      other: "this local user, ec2 instance, or lambda is configuring something else"
        always "other" if access mode is "user"
        if access mode is "role", set target_other=True in the constructor
        Constructor must also set 'env' and 'service'

      self:
        lambda_context must be provided if this is a lambda; leave it unset for ec2
        INSTANCE_ID = instance ID if EC2, else None
        FUNCTION_NAME = function name if lambda, else None
        ACCOUNT = numeric account this is running in
        ACCOUNT_ALIAS = named alias of the account this is running in
        ROLE = role this is running as
        ENV = the environment this is running in, from role name
        ENV_SHORT = derived from ENV
        ENV_FULL = fully qualified environment, same as ENV unless env is a global env (mgmt.* or global.*)
        SERVICE = the service this is, from role name
        REGION = region this is running in
      something else:
        INSTANCE_ID = None
        FUNCTION_NAME = None
        ACCOUNT = the numeric account I'm logged into (look up)
        ACCOUNT_ALIAS = the alias of the account i'm logged into (look up)
        ROLE = None
        ENV = the target's environment, passed in from the constructor
        ENV_SHORT = derived from ENV
        ENV_FULL = ENV, with ".<ACCOUNT_ALIAS>" as appropriate
        SERVICE = the service name, passed in from the constructor
        REGION = the region I am in (ec2, lambda) or explicitly set (region= in constructor)

    Collects instance's environment for use in templates:
      {{ACCOUNT}}       - AWS account number
                          CloudFormation can use this or the AWS::AccountID pseudo param
      {{ACCOUNT_ALIAS}} - AWS account alias
      {{ENV}}           - environment: mgmt, prod, staging, proto<N>, etc.
      {{ENV_SHORT}}     - env with <N> or account trimmed: mgmt, prod, staging, proto, etc.
      {{ENV_FULL}}      - env fully qualified: prod, staging, proto<N>, mgmt.<account_alias>, etc.
      {{FUNCTION_NAME}} - only for lambdas
      {{INSTANCE_ID}}   - only for ec2
      {{REGION}}        - the region currently being worked in
                          CloudFormation can use this or the AWS::Region pseudo param
      {{ROLE}}          - the role bound to the ec2 instance or lambda; only for ec2 and lambda
                          CloudFormation: compose role name in template by joining other strings
    """
    # instance vars
    self.verbose = False  # print noisy status if True
    # resolved tokens - only look up symbols once per session. Protect internal names by declaring
    self.resolved = {
        "ACCOUNT": None,
        "ACCOUNT_ALIAS": None,
        "ENV": None,
        "ENV_SHORT": None,
        "ENV_FULL": None,
        "FUNCTION_NAME": None,
        "INSTANCE_ID": None,
        "REGION": None,
        "ROLE": None
    }

    # template and parameters are populated by the load() method as each template is processed
    self.template = None
    # parameters that accompany this template, if any
    self.parameters = {}
    # Sets of symbols found in the current template (only)
    # read back with self.symbols() and self.unresolved_symbols()
    self.symbols = set()
    # capture verbosity pref from constructor
    self.verbose = verbose

    # determine ACCESS MODE
    if profile:  # accessing as a user
      target_other = True
      if not region:
        fail("'region' is required with 'profile' for user-mode access")

    where = whereami()

    # require env and service params init() when target is 'other'
    if (target_other or where == "virtualbox-kvm") and (env is None or service is None):
      fail("'env' and 'service' must be set when target is 'other' or running in " + where)

    if target_other or profile:
      self.resolved["REGION"] = region
    # lambda initializing self
    elif lambda_context:
      self.resolved["REGION"] = lambda_context.invoked_function_arn.split(":")[3]
    # ec2 initializing self
    else:
      self.resolved["REGION"] = get_metadata_or_fail("placement/availability-zone/")[:-1]

    # Create clients - if accessing by role, profile should be None
    clients = [
      "cloudformation",
      "cloudfront",
      "cognito-identity",
      "cognito-idp",
      "ec2",
      "elbv2",
      "iam",
      "kms",
      "lambda",
      "route53",
      "s3",
      "sts",
      "waf"
    ]
    try:
      EFTemplateResolver.__CLIENTS = create_aws_clients(self.resolved["REGION"], profile, *clients)
    except RuntimeError as error:
      fail("Exception logging in with Session()", error)

    # Create EFAwsResolver object for interactive lookups
    EFTemplateResolver.__AWSR = EFAwsResolver(EFTemplateResolver.__CLIENTS)
    # Create EFConfigResolver object for ef tooling config lookups
    EFTemplateResolver.__EFCR = EFConfigResolver()
    # Create EFVersionResolver object for version lookups
    EFTemplateResolver.__VR = EFVersionResolver(EFTemplateResolver.__CLIENTS)

    # Set the internal parameter values for aws
    # self-configuring lambda
    if (not target_other) and lambda_context:
      arn_split = lambda_context.invoked_function_arn.split(":")
      self.resolved["ACCOUNT"] = arn_split[4]
      self.resolved["FUNCTION_NAME"] = arn_split[6]
      try:
        lambda_desc = EFTemplateResolver.__CLIENTS["lambda"].get_function()
      except:
        fail("Exception in get_function: ", sys.exc_info())
      self.resolved["ROLE"] = lambda_desc["Configuration"]["Role"]
      env = re.search("^({})-".format(EFConfig.VALID_ENV_REGEX), self.resolved["ROLE"])
      if not env:
        fail("Did not find environment in lambda function name.")
      self.resolved["ENV"] = env.group(1)
      parsed_service = re.search(self.resolved["ENV"] + "-(.*?)-lambda", self.resolved["ROLE"])
      if parsed_service:
        self.resolved["SERVICE"] = parsed_service.group(1)

    # self-configuring EC2
    elif (not target_other) and (not lambda_context):
      self.resolved["INSTANCE_ID"] = get_metadata_or_fail('instance-id')
      try:
        instance_desc = EFTemplateResolver.__CLIENTS["ec2"].describe_instances(InstanceIds=[self.resolved["INSTANCE_ID"]])
      except:
        fail("Exception in describe_instances: ", sys.exc_info())
      self.resolved["ACCOUNT"] = instance_desc["Reservations"][0]["OwnerId"]
      arn = instance_desc["Reservations"][0]["Instances"][0]["IamInstanceProfile"]["Arn"]
      self.resolved["ROLE"] = arn.split(":")[5].split("/")[1]
      env = re.search("^({})-".format(EFConfig.VALID_ENV_REGEX), self.resolved["ROLE"])
      if not env:
        fail("Did not find environment in role name")
      self.resolved["ENV"] = env.group(1)
      self.resolved["SERVICE"] = "-".join(self.resolved["ROLE"].split("-")[1:])

    # target is "other"
    else:
      try:
        if whereami() == "ec2":
          self.resolved["ACCOUNT"] = str(json.loads(http_get_metadata('iam/info'))["InstanceProfileArn"].split(":")[4])
        else:
          self.resolved["ACCOUNT"] = get_account_id(EFTemplateResolver.__CLIENTS["sts"])
      except botocore.exceptions.ClientError as error:
        fail("Exception in get_user()", error)
      self.resolved["ENV"] = env
      self.resolved["SERVICE"] = service

    # ACCOUNT_ALIAS is resolved consistently for access modes and targets other than virtualbox
    try:
      self.resolved["ACCOUNT_ALIAS"] = EFTemplateResolver.__CLIENTS["iam"].list_account_aliases()["AccountAliases"][0]
    except botocore.exceptions.ClientError as error:
      fail("Exception in list_account_aliases", error)

    # ENV_SHORT is resolved the same way for all access modes and targets
    self.resolved["ENV_SHORT"] = self.resolved["ENV"].strip(".0123456789")

    # ENV_FULL is resolved the same way for all access modes and targets, depending on previously-resolved values
    if self.resolved["ENV"] in EFConfig.ACCOUNT_SCOPED_ENVS:
      self.resolved["ENV_FULL"] = "{}.{}".format(self.resolved["ENV"], self.resolved["ACCOUNT_ALIAS"])
    else:
      self.resolved["ENV_FULL"] = self.resolved["ENV"]

    if self.verbose:
      print(repr(self.resolved), file=sys.stderr)
Beispiel #4
0
 def test_account_alias_of_env(self):
   """Does accountaliasofenv,prod resolve to the prod account alias"""
   test_string = "accountaliasofenv,prod"
   resolver = EFConfigResolver()
   self.assertRegexpMatches(resolver.lookup(test_string), "^ellation$")
    def test_config_custom_data_missing_lookup(self):
        EFConfig.CUSTOM_DATA = {}

        ef_config_resolver = EFConfigResolver()
        result_custom_data = ef_config_resolver.lookup("customdata,mock_data")
        self.assertEquals(result_custom_data, None)
 def test_config_custom_data_no_data(self):
     ef_config_resolver = EFConfigResolver()
     result_custom_data = ef_config_resolver.lookup("customdata,mock_data")
     self.assertEquals(result_custom_data, None)