File

src/providers/aws/aws.provider.ts

Index

Methods

Methods

Async decryptConfig
decryptConfig(awsConfig: AWSConfig)
Parameters :
Name Type Optional
awsConfig AWSConfig No
Returns : unknown
Async encryptConfig
encryptConfig(awsConfig: AWSConfig)
Parameters :
Name Type Optional
awsConfig AWSConfig No
Returns : unknown
Async getCostAndUsage
getCostAndUsage(awsConfig: AWSConfig, getCostAndUsageInput: GetCostAndUsageRequest, useNextToken: boolean)

Get cost and usage data from AWS

Parameters :
Name Type Optional Default value Description
awsConfig AWSConfig No

AWSConfig object

getCostAndUsageInput GetCostAndUsageRequest No

GetCostAndUsageRequest object

useNextToken boolean No false

boolean to use NextToken

Returns : Promise<GetCostAndUsageResponse>

Promise that resolves to GetCostAndUsageResponse

Async GetCostAndUsageWithResources
GetCostAndUsageWithResources(awsConfig: AWSConfig, getCostAndUsageWithResourcesInput: GetCostAndUsageWithResourcesRequest, useNextToken: boolean)
Parameters :
Name Type Optional Default value
awsConfig AWSConfig No
getCostAndUsageWithResourcesInput GetCostAndUsageWithResourcesRequest No
useNextToken boolean No true
Returns : Promise<GetCostAndUsageWithResourcesResponse>
Async getResourcesByTags
getResourcesByTags(awsConfig: AWSConfig, tagList: string[], useNextToken: boolean)
Parameters :
Name Type Optional Default value
awsConfig AWSConfig No
tagList string[] No
useNextToken boolean No true
Returns : Promise<GetResourcesOutput>
Async getTagKeys
getTagKeys(awsConfig: AWSConfig, useNextToken: boolean)

Function to get all tags keys from AWS

Parameters :
Name Type Optional Default value
awsConfig AWSConfig No
useNextToken boolean No true
Returns : unknown
Async getTags
getTags(awsConfig: AWSConfig, getTagsInput: GetTagsRequest, useNextToken: boolean)

Get all tags data from AWS

Parameters :
Name Type Optional Default value Description
awsConfig AWSConfig No

AWSConfig object

getTagsInput GetTagsRequest No

GetTagsRequest object

useNextToken boolean No false

boolean to use NextToken

Returns : Promise<GetTagsResponse>

Promise that resolves to GetTagsResponse

Async getTagsData
getTagsData(awsConfig: AWSConfig, getTagsInput: GetTagsRequest, useNextToken: boolean)
Parameters :
Name Type Optional Default value
awsConfig AWSConfig No
getTagsInput GetTagsRequest No
useNextToken boolean No false
Returns : unknown
Async getTagValuesForKey
getTagValuesForKey(awsConfig: AWSConfig, getTagValesInput: GetTagValuesInput, useNextToken: boolean)

Function to get all tag values from AWS

Parameters :
Name Type Optional Default value
awsConfig AWSConfig No
getTagValesInput GetTagValuesInput No
useNextToken boolean No true
Returns : unknown
maskConfigSecret
maskConfigSecret(awsConfig: AWSConfig)
Parameters :
Name Type Optional
awsConfig AWSConfig No
Returns : AWSConfig
Async testConnection
testConnection(awsConfig: AWSConfig)

Test connection to AWS

Parameters :
Name Type Optional
awsConfig AWSConfig No
Returns : unknown

Promise that resolves to any

import { decryptText, encryptText } from "../../common/helper";
import {
  CostExplorer,
  GetTagsCommand,
  GetCostAndUsageCommand,
  GetTagsRequest,
  GetTagsResponse,
  GetCostAndUsageRequest,
  GetCostAndUsageResponse,
  GetCostAndUsageWithResourcesCommand,
  CostExplorerClient,
  GetCostAndUsageWithResourcesRequest,
  GetCostAndUsageWithResourcesResponse,
} from "@aws-sdk/client-cost-explorer";
import {
  ResourceGroupsTaggingAPIClient,
  GetResourcesCommand,
  GetResourcesInput,
  GetResourcesOutput,
  GetTagKeysCommand,
  GetTagValuesCommand,
  GetTagKeysOutput,
  GetTagValuesInput,
  GetTagValuesOutput,
} from "@aws-sdk/client-resource-groups-tagging-api";

import { Injectable } from "@nestjs/common";
import { AWSConfig } from "./aws.types";
import { AwsConnectionError } from "./aws.errors";

@Injectable()
export class AWSCostProvider {
  /**
   * Function to get all tags keys from AWS
   * @param awsConfig
   * @param getTagsKeysInput
   * @param useNextToken
   * @returns
   */
  async getTagKeys(awsConfig: AWSConfig, useNextToken: boolean = true) {
    const client = new ResourceGroupsTaggingAPIClient({
      credentials: awsConfig.credentials,
      region: awsConfig.region,
    });

    const allTagsKeys: GetTagKeysOutput = {
      TagKeys: [],
    };

    let nextToken: string | undefined = undefined;

    do {
      try {
        const answer = await client.send(
          new GetTagKeysCommand({
            PaginationToken: useNextToken ? nextToken : undefined,
          }),
        );
        allTagsKeys.TagKeys.push(...answer.TagKeys);
        nextToken = answer.PaginationToken;
      } catch (error) {
        console.error("Error fetching tags:", error);

        throw new AwsConnectionError(
          `Failed to fetch tags: ${error}`,
        );
      }
    } while (useNextToken && nextToken);

    return allTagsKeys;
  }

  /**
   * Function to get all tag values from AWS
   * @param awsConfig
   * @param getTagValesInput
   * @param useNextToken
   * @returns
   */
  async getTagValuesForKey(
    awsConfig: AWSConfig,
    getTagValesInput: GetTagValuesInput,
    useNextToken: boolean = true,
  ) {
    const client = new ResourceGroupsTaggingAPIClient({
      credentials: awsConfig.credentials,
      region: awsConfig.region,
    });

    const allTagsValues: GetTagValuesOutput = {
      TagValues: [],
    };

    let nextToken: string | undefined = undefined;

    do {
      try {
        const answer = await client.send(
          new GetTagValuesCommand({
            ...getTagValesInput,
            PaginationToken: useNextToken ? nextToken : undefined,
          }),
        );
        allTagsValues.TagValues.push(...answer.TagValues);
        nextToken = answer.PaginationToken;
      } catch (error) {
        console.error("Error fetching tag values for key:", error);

        throw new AwsConnectionError(
          `Failed to fetch tag values for key: ${error}`,
        );
      }
    } while (useNextToken && nextToken);

    return allTagsValues;
  }

  /**
   * Get all tags data from AWS
   * @param awsConfig AWSConfig object
   * @param getTagsInput GetTagsRequest object
   * @param useNextToken boolean to use NextToken
   * @returns {Promise<GetTagsResponse>} Promise that resolves to GetTagsResponse
   */
  async getTags(
    awsConfig: AWSConfig,
    getTagsInput: GetTagsRequest,
    useNextToken: boolean = false,
  ): Promise<GetTagsResponse> {
    const client = new CostExplorer({
      credentials: awsConfig.credentials,
      region: awsConfig.region,
    });

    const allTagsData: GetTagsResponse = {
      Tags: [],
      ReturnSize: 0,
      TotalSize: 0,
    };

    let nextToken: string | undefined = undefined;

    do {
      try {
        const answer = await client.send(
          new GetTagsCommand({
            ...getTagsInput,
            NextPageToken: useNextToken ? nextToken : undefined,
          }),
        );
        allTagsData.Tags.push(
          ...answer.Tags.filter((tag) => tag.split(":").length < 2),
        );
        nextToken = answer.NextPageToken;
      } catch (error) {
        console.error("Error fetching tags:", error);

        throw new AwsConnectionError(
          `Failed to fetch tags: ${error}`,
        );
      }
    } while (useNextToken && nextToken);

    allTagsData.ReturnSize = allTagsData.TotalSize = allTagsData.Tags.length;
    return allTagsData;
  }

  async getTagsData(
    awsConfig: AWSConfig,
    getTagsInput: GetTagsRequest,
    useNextToken: boolean = false,
  ) {
    const data = await this.getTags(awsConfig, getTagsInput, useNextToken);
    const response = await Promise.all(
      data.Tags.map((tagKey) => {
        return this.getTags(
          awsConfig,
          {
            ...getTagsInput,
            TagKey: tagKey,
          },
          useNextToken,
        ).then((values) => {
          return [tagKey, values];
        });
      }),
    );
    const result = [];
    response.forEach(([key, values]: [string, GetTagsResponse]) => {
      values.Tags.forEach((value) => {
        result.push(`${key}:${value}`);
      });
    });
    return result;
  }

  /**
   * Test connection to AWS
   * @returns {Promise<any>} Promise that resolves to any
   */
  async testConnection(awsConfig: AWSConfig) {
    const currentDate = new Date();
    const data = await this.getTags(
      awsConfig,
      {
        TimePeriod: {
          Start: `${currentDate.getFullYear()}-01-01`, // Start of the year
          End: currentDate.toISOString().split("T")[0], // Current date
        },
      },
      false,
    );
    return `${data.ReturnSize}`;
  }

  async GetCostAndUsageWithResources(
    awsConfig: AWSConfig,
    getCostAndUsageWithResourcesInput: GetCostAndUsageWithResourcesRequest,
    useNextToken: boolean = true,
  ): Promise<GetCostAndUsageWithResourcesResponse> {
    const client = new CostExplorerClient({
      credentials: awsConfig.credentials,
      region: awsConfig.region,
    });

    const allCostAndUsageData: GetCostAndUsageWithResourcesResponse = {
      ResultsByTime: [],
      GroupDefinitions: [],
      DimensionValueAttributes: [],
    };

    let nextToken: string | undefined = undefined;

    do {
      try {
        const answer = await client.send(
          new GetCostAndUsageWithResourcesCommand({
            ...getCostAndUsageWithResourcesInput,
            NextPageToken: useNextToken ? nextToken : undefined,
          }),
        );
        allCostAndUsageData.ResultsByTime.push(...answer.ResultsByTime);
        allCostAndUsageData.GroupDefinitions.push(...answer.GroupDefinitions);
        allCostAndUsageData.DimensionValueAttributes.push(
          ...answer.DimensionValueAttributes,
        );
        nextToken = answer.NextPageToken;
      } catch (error) {
        console.error("Error fetching cost and usage data:", error);

        throw new AwsConnectionError(
          `Failed to fetch cost and usage data: ${error}`,
        );
      }
    } while (useNextToken && nextToken);

    return allCostAndUsageData;
  }

  /**
   * Get cost and usage data from AWS
   * @param awsConfig AWSConfig object
   * @param getCostAndUsageInput GetCostAndUsageRequest object
   * @param useNextToken boolean to use NextToken
   * @returns {Promise<GetCostAndUsageResponse>} Promise that resolves to GetCostAndUsageResponse
   */
  async getCostAndUsage(
    awsConfig: AWSConfig,
    getCostAndUsageInput: GetCostAndUsageRequest,
    useNextToken: boolean = false,
  ): Promise<GetCostAndUsageResponse> {
    const client = new CostExplorer({
      credentials: awsConfig.credentials,
      region: awsConfig.region,
    });

    const allCostAndUsageData: GetCostAndUsageResponse = {
      ResultsByTime: [],
      GroupDefinitions: [],
      DimensionValueAttributes: [],
    };

    let nextToken: string | undefined = undefined;

    do {
      try {
        const answer = await client.send(
          new GetCostAndUsageCommand({
            ...getCostAndUsageInput,
            NextPageToken: useNextToken ? nextToken : undefined,
          }),
        );
        allCostAndUsageData.ResultsByTime.push(...answer.ResultsByTime);
        allCostAndUsageData.GroupDefinitions.push(...answer.GroupDefinitions);
        allCostAndUsageData.DimensionValueAttributes.push(
          ...answer.DimensionValueAttributes,
        );
        nextToken = answer.NextPageToken;
      } catch (error) {
        console.error("Error fetching cost and usage data:", error);

        throw new AwsConnectionError(
          `Failed to fetch cost and usage data: ${error}`,
        );
      }
    } while (useNextToken && nextToken);

    return allCostAndUsageData;
  }

  async getResourcesByTags(
    awsConfig: AWSConfig,
    tagList: string[],
    useNextToken: boolean = true,
  ): Promise<GetResourcesOutput> {
    const client = new ResourceGroupsTaggingAPIClient(awsConfig);

    const input: GetResourcesInput = {
      // GetResourcesInput
      TagFilters: tagList.map((tag) => {
        const [key, value] = tag.split(":");
        return {
          Key: key,
          Values: [
            // TagValueList
            value,
          ],
        };
      }),
    };

    const output: GetResourcesOutput = {
      ResourceTagMappingList: [],
    };

    let nextToken: string | undefined = undefined;

    do {
      try {
        const answer = await client.send(
          new GetResourcesCommand({
            ...input,
            PaginationToken: useNextToken ? nextToken : undefined,
          }),
        );
        output.ResourceTagMappingList.push(
          ...(answer.ResourceTagMappingList || []),
        );
        
        nextToken = answer.PaginationToken;
      } catch (error) {
        console.error("Error fetching tags:", error);

        throw new AwsConnectionError(
          `Failed to fetch tags: ${error}`,
        );
      }
    } while (useNextToken && nextToken);

    return output;
  }

  async encryptConfig(awsConfig: AWSConfig) {
    if (awsConfig.hasOwnProperty("credentials")) {
      if (
        awsConfig.credentials.hasOwnProperty("accessKeyId") &&
        awsConfig.credentials["accessKeyId"]
      ) {
        awsConfig.credentials["accessKeyId"] = await encryptText(
          awsConfig.credentials["accessKeyId"],
        );
      }
      if (
        awsConfig.credentials.hasOwnProperty("secretAccessKey") &&
        awsConfig.credentials["secretAccessKey"]
      ) {
        awsConfig.credentials["secretAccessKey"] = await encryptText(
          awsConfig.credentials["secretAccessKey"],
        );
      }
    }
    return awsConfig;
  }

  async decryptConfig(awsConfig: AWSConfig) {
    if (awsConfig.hasOwnProperty("credentials")) {
      if (
        awsConfig.credentials.hasOwnProperty("accessKeyId") &&
        awsConfig.credentials["accessKeyId"]
      ) {
        awsConfig.credentials["accessKeyId"] = await decryptText(
          awsConfig.credentials["accessKeyId"],
        );
      }
      if (
        awsConfig.credentials.hasOwnProperty("secretAccessKey") &&
        awsConfig.credentials["secretAccessKey"]
      ) {
        awsConfig.credentials["secretAccessKey"] = await decryptText(
          awsConfig.credentials["secretAccessKey"],
        );
      }
    }
    return awsConfig;
  }

  maskConfigSecret(awsConfig: AWSConfig) {
    if (awsConfig.hasOwnProperty("credentials")) {
      delete awsConfig.credentials;
    }
    return awsConfig;
  }
}

results matching ""

    No results matching ""