user2774004
user2774004

Reputation: 513

Generic way to retrieve tags from AWS events

I have an autotagging engine based on GorillaStack's open source https://github.com/GorillaStack/auto-tag. I added code to use a DynamoDB table that contains additional tags to apply based off of the user-specified tag "BusinessUse". So if a user specifies the tag BusinessUse to be "Use_Case_XXX" the lambda function should look at the dynamodb table and apply the corresponding tags CostCenter, Department, etc. Everything works fine if the specific field within responseElements that contains the tags matches the resource type.

The problem is that the structure of the responseElements and requestParameters for each this.event vary greatly depending on the resource type. For example, IAM users have the tags inside this simple struct responseElements.user.tags[]:

responseElements:
   { user:
      { path: '/',
        userName: 'test1',
        userId: 'AIDAWV5EEBYBXINBXD2JL',
        arn: 'arn:aws:iam::123456789012:user/test1',
        createDate: 'Sep 25, 2020 4:09:56 PM',
        tags: [Array] } }

Whereas EC2 instances have their tags inside a much more complex structure, responseElements.instancesSet.tagSet.resourceType[instance].tags[] (UGH!):

responseElements:
   { requestId: '73bc65c3-b1d8-4954-aa41-d2f63ca2b5a9',
     reservationId: 'r-01a9a50db0c26034f',
     ownerId: '123456789012',
     groupSet: {},
     instancesSet: { items: [ { instanceId: 'i-08687c568bfbe3671',
       imageId: 'ami-0947d2ba12ee1ff75',
       instanceState: [Object],
       privateDnsName: 'ip-10-0-1-14.ec2.internal',
       keyName: 'foo',
       amiLaunchIndex: 0,
       productCodes: {},
       instanceType: 't2.micro',
       launchTime: 1601050311000,
       placement: [Object],
       monitoring: [Object],
       subnetId: 'subnet-01f8d0d4cabe5a3a7',
       vpcId: 'vpc-0568962eafdd8d11b',
       privateIpAddress: '10.0.1.14',
       stateReason: [Object],
       architecture: 'x86_64',
       rootDeviceType: 'ebs',
       rootDeviceName: '/dev/xvda',
       blockDeviceMapping: {},
       virtualizationType: 'hvm',
       hypervisor: 'xen',
       tagSet: [ { resourceType: 'instance', tags: [Array] },{ resourceType: 'volume', tags: [Array] } ],
       groupSet: [Object],
       sourceDestCheck: true,
       networkInterfaceSet: [Object],
       ebsOptimized: false,
       cpuOptions: [Object],
       capacityReservationSpecification: [Object],
       hibernationOptions: [Object],
       enclaveOptions: [Object],
       metadataOptions: [Object] } ] }
 } }

So my question is how to extract the tag BusinessUse from this.event in a generic way. There are thirty-three resource types that this stack supports and I would really rather not have to handle each one individually. I'm open to using other API's as well like the ResourceGroupTagging API but from what I can see this returns an ARN and each resource type for this.event also does not have a uniform ARN field (ARG!). I suppose a more general question is how to deal with non-uniform responseElements and requestParameters and why does AWS make it so hard to parse these structures instead of providing a uniform template.

FWIW, here's the code to pull values from the dynamoDB table and return a tag value; the case below works for iam users because it explicitly calls responseElements.user.tags[]. I need to make it generic so that it works for this.event of any resource type:

getTagValueFromTable(projectionExpression) {
    console.log(this.event);
    let _data;
    let done = false;
    try {
      // Create the DynamoDB service object
      var ddb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
      var params = {
        TableName: 'csv-table',
        Key: {
          'BusinessUse': {S: this.event.responseElements.user.tags[0].value}
        },
        ProjectionExpression: projectionExpression
      };
      // Retrieve the item
      ddb.getItem(params).promise().then((data) => {
        _data = data.Item[projectionExpression].S;
        done = true;
        console.log(projectionExpression + ":" + _data);
      });
      // Wait for asynchronous call to complete!
      require('deasync').loopWhile(function(){return !done;});
      return _data;
    }catch (error) {
       console.error(error);
       return "ERROR_ENTRY_NOT_FOUND";
    }
  }

The original lambda code is at https://github.com/GorillaStack/auto-tag/releases/download/0.5.3/autotag-0.5.3.zip

Upvotes: 1

Views: 186

Answers (1)

jingx
jingx

Reputation: 4014

You can use the Resource Groups Tagging API to uniformly manage tags.

Upvotes: -1

Related Questions