diff --git a/.changeset/tender-forks-check.md b/.changeset/tender-forks-check.md new file mode 100644 index 000000000..3270cf2e0 --- /dev/null +++ b/.changeset/tender-forks-check.md @@ -0,0 +1,5 @@ +--- +'@roadiehq/catalog-backend-module-aws': minor +--- + +Add additional annotations. Add ingerators to decide resource type def diff --git a/plugins/backend/catalog-backend-module-aws/package.json b/plugins/backend/catalog-backend-module-aws/package.json index dab557f08..03add212e 100644 --- a/plugins/backend/catalog-backend-module-aws/package.json +++ b/plugins/backend/catalog-backend-module-aws/package.json @@ -54,6 +54,7 @@ "@backstage/integration-aws-node": "^0.1.12", "@backstage/backend-common": "^0.24.0", "@backstage/catalog-client": "^1.6.6", + "@backstage/plugin-kubernetes-common": "^0.8.3", "@backstage/catalog-model": "^1.6.0", "@backstage/config": "^1.2.0", "@backstage/errors": "^1.2.4", diff --git a/plugins/backend/catalog-backend-module-aws/src/annotations.ts b/plugins/backend/catalog-backend-module-aws/src/annotations.ts index c6a861645..5bed09168 100644 --- a/plugins/backend/catalog-backend-module-aws/src/annotations.ts +++ b/plugins/backend/catalog-backend-module-aws/src/annotations.ts @@ -23,6 +23,8 @@ export const ANNOTATION_AWS_EC2_INSTANCE_ID = 'amazon.com/ec2-instance-id'; export const ANNOTATION_AWS_RDS_INSTANCE_ARN = 'amazon.com/rds-instance-arn'; export const ANNOTATION_AWS_DDB_TABLE_ARN = 'amazon.com/dynamo-db-table-arn'; export const ANNOTATION_AWS_EKS_CLUSTER_ARN = 'amazon.com/eks-cluster-arn'; +export const ANNOTATION_AWS_EKS_CLUSTER_VERSION = + 'amazon.com/eks-cluster-version'; // Accounts export const ANNOTATION_ACCOUNT_ID = 'amazon.com/account-id'; diff --git a/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.test.ts b/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.test.ts index 60e1bdda9..73a60e5e0 100644 --- a/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.test.ts +++ b/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.test.ts @@ -106,12 +106,15 @@ describe('AWSEKSClusterProvider', () => { labels: { some_url: 'https---asdfhwef.com-hello-world', }, - title: 'cluster1', + name: 'a140791d2b20a847f2c74c62c384f93fb83691d871e80385720bce696a0a05f', + title: '123456789012:eu-west-1:cluster1', annotations: expect.objectContaining({ [ANNOTATION_AWS_EKS_CLUSTER_ARN]: 'arn:aws:eks:eu-west-1:123456789012:cluster/cluster1', [ANNOTATION_AWS_IAM_ROLE_ARN]: 'arn:aws:iam::123456789012:role/cluster1', + 'kubernetes.io/auth-provider': 'aws', + 'kubernetes.io/x-k8s-aws-id': 'cluster1', }), }), }), @@ -159,12 +162,15 @@ describe('AWSEKSClusterProvider', () => { labels: { some_url: 'https://asdfhwef.com/hello-world', }, - title: 'cluster1', + name: 'a140791d2b20a847f2c74c62c384f93fb83691d871e80385720bce696a0a05f', + title: '123456789012:eu-west-1:cluster1', annotations: expect.objectContaining({ [ANNOTATION_AWS_EKS_CLUSTER_ARN]: 'arn:aws:eks:eu-west-1:123456789012:cluster/cluster1', [ANNOTATION_AWS_IAM_ROLE_ARN]: 'arn:aws:iam::123456789012:role/cluster1', + 'kubernetes.io/auth-provider': 'aws', + 'kubernetes.io/x-k8s-aws-id': 'cluster1', }), }), }), diff --git a/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.ts b/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.ts index 06c1b29df..8f97342ee 100644 --- a/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.ts +++ b/plugins/backend/catalog-backend-module-aws/src/providers/AWSEKSClusterProvider.ts @@ -21,8 +21,15 @@ import { Config } from '@backstage/config'; import { AWSEntityProvider } from './AWSEntityProvider'; import { ANNOTATION_AWS_EKS_CLUSTER_ARN, + ANNOTATION_AWS_EKS_CLUSTER_VERSION, ANNOTATION_AWS_IAM_ROLE_ARN, } from '../annotations'; +import { + ANNOTATION_KUBERNETES_API_SERVER, + ANNOTATION_KUBERNETES_API_SERVER_CA, + ANNOTATION_KUBERNETES_AUTH_PROVIDER, + ANNOTATION_KUBERNETES_AWS_CLUSTER_ID, +} from '@backstage/plugin-kubernetes-common'; import { arnToName } from '../utils/arnToName'; import { LabelValueMapper, @@ -30,13 +37,15 @@ import { relationshipsFromTags, } from '../utils/tags'; import { CatalogApi } from '@backstage/catalog-client'; -import { DynamicAccountConfig } from '../types'; +import { AccountConfig, DynamicAccountConfig } from '../types'; import { duration } from '../utils/timer'; /** * Provides entities from AWS EKS Cluster service. */ export class AWSEKSClusterProvider extends AWSEntityProvider { + private readonly clusterTypeValue: string; + static fromConfig( config: Config, options: { @@ -46,6 +55,7 @@ export class AWSEKSClusterProvider extends AWSEntityProvider { ownerTag?: string; useTemporaryCredentials?: boolean; labelValueMapper?: LabelValueMapper; + clusterTypeValue?: string; }, ) { const accountId = config.getString('accountId'); @@ -60,6 +70,22 @@ export class AWSEKSClusterProvider extends AWSEntityProvider { ); } + constructor( + account: AccountConfig, + options: { + logger: winston.Logger; + catalogApi?: CatalogApi; + providerId?: string; + ownerTag?: string; + useTemporaryCredentials?: boolean; + labelValueMapper?: LabelValueMapper; + clusterTypeValue?: string; + }, + ) { + super(account, options); + this.clusterTypeValue = options.clusterTypeValue ?? 'eks-cluster'; + } + getProviderName(): string { return `aws-eks-cluster-${this.providerId ?? 0}`; } @@ -102,26 +128,50 @@ export class AWSEKSClusterProvider extends AWSEntityProvider { for (const name of clusterPage.clusters || []) { if (name) { const cluster = await eks.describeCluster({ name }); - + const clusterName = + cluster.cluster?.name + ?.trim() + ?.toLocaleLowerCase('en-US') + ?.replace(/[^a-zA-Z0-9\-]/g, '-') ?? name; const annotations: { [name: string]: string } = { ...(await defaultAnnotations), }; + if (cluster.cluster?.version) { + annotations[ANNOTATION_AWS_EKS_CLUSTER_VERSION] = + cluster.cluster.version; + } + if (cluster.cluster?.arn) { - annotations[ANNOTATION_AWS_EKS_CLUSTER_ARN] = cluster.cluster?.arn; + annotations[ANNOTATION_AWS_EKS_CLUSTER_ARN] = cluster.cluster.arn; } if (cluster.cluster?.roleArn) { - annotations[ANNOTATION_AWS_IAM_ROLE_ARN] = cluster.cluster?.roleArn; + annotations[ANNOTATION_AWS_IAM_ROLE_ARN] = cluster.cluster.roleArn; + } + + if (cluster.cluster?.endpoint) { + annotations[ANNOTATION_KUBERNETES_API_SERVER] = + cluster.cluster.endpoint; + } + + if (cluster.cluster?.certificateAuthority?.data) { + annotations[ANNOTATION_KUBERNETES_API_SERVER_CA] = + cluster.cluster.certificateAuthority.data; + } + + if (cluster.cluster?.name) { + annotations[ANNOTATION_KUBERNETES_AWS_CLUSTER_ID] = clusterName; } + annotations[ANNOTATION_KUBERNETES_AUTH_PROVIDER] = 'aws'; const resource: ResourceEntity = { kind: 'Resource', apiVersion: 'backstage.io/v1beta1', metadata: { annotations, name: arnToName(name), - title: name, + title: `${accountId}:${this.region}:${clusterName}`, labels: this.labelsFromTags(cluster.cluster?.tags), }, @@ -132,7 +182,7 @@ export class AWSEKSClusterProvider extends AWSEntityProvider { groups, ), ...relationshipsFromTags(cluster.cluster?.tags), - type: 'eks-cluster', + type: this.clusterTypeValue, }, }; diff --git a/yarn.lock b/yarn.lock index 2c23ad3eb..0982abb47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5820,6 +5820,19 @@ react-use "^17.2.4" zod "^3.22.4" +"@backstage/plugin-kubernetes-common@^0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@backstage/plugin-kubernetes-common/-/plugin-kubernetes-common-0.8.3.tgz#0c64f2d1d57edb1998d55b637e67340904c1a7f7" + integrity sha512-ZJ+Hbt/1sZ2O8WKMj4iZtzAk5bflSD4L8rqwcsEWH7pAXqhtjBxHFEHBSvyi0pDS/Q4qxmxauSvCByAfgmvnVQ== + dependencies: + "@backstage/catalog-model" "^1.7.0" + "@backstage/plugin-permission-common" "^0.8.1" + "@backstage/types" "^1.1.1" + "@kubernetes/client-node" "0.20.0" + kubernetes-models "^4.3.1" + lodash "^4.17.21" + luxon "^3.0.0" + "@backstage/plugin-org@^0.6.28": version "0.6.28" resolved "https://registry.yarnpkg.com/@backstage/plugin-org/-/plugin-org-0.6.28.tgz#c8ba13e79a833ae3590e0f2afa9494a534314488" @@ -8437,6 +8450,38 @@ dependencies: buffer "^6.0.3" +"@kubernetes-models/apimachinery@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@kubernetes-models/apimachinery/-/apimachinery-2.0.0.tgz#938649cbf07503325bc22cce5e114cf1ee7fdc36" + integrity sha512-wVeIzuXvYDMqwikrav2cLkfTMw3kuBx8Pqt6LI5bEa8a+0NWJs2p5IZONHebI3B/QLwtb2wgMKGre6JtnbQayg== + dependencies: + "@kubernetes-models/base" "^5.0.0" + "@kubernetes-models/validate" "^4.0.0" + "@swc/helpers" "^0.5.8" + +"@kubernetes-models/base@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@kubernetes-models/base/-/base-5.0.0.tgz#22c2a93b3dcbe9b2c155c520cfb0f19deac92b86" + integrity sha512-b+pVrlF1691ft/nc/tJ/v0DEPq9NK5gKWO1OHuTEBRRk/z1inH30svoqrqQL90VZhthVJNi8L7rQRQBUWuxZiw== + dependencies: + "@kubernetes-models/validate" "^4.0.0" + is-plain-object "^5.0.0" + tslib "^2.4.0" + +"@kubernetes-models/validate@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@kubernetes-models/validate/-/validate-4.0.0.tgz#669314ec4a4f0e8271d23ce4fdfa9dfffb278a9c" + integrity sha512-rsfF5t3sd5c+3ejUgcy8q0cVG2/BxT064L4Xz+CuKEe014u8T4MtFZiWjWZFpfMXSGKzFYEA6DJYm9CqjmIfZg== + dependencies: + ajv "^8.12.0" + ajv-formats "^2.1.1" + ajv-formats-draft2019 "^1.6.1" + ajv-i18n "^4.2.0" + is-cidr "^4.0.0" + tslib "^2.4.0" + optionalDependencies: + re2-wasm "^1.0.2" + "@kubernetes/client-node@0.20.0": version "0.20.0" resolved "https://registry.yarnpkg.com/@kubernetes/client-node/-/client-node-0.20.0.tgz#4447ae27fd6eef3d4830a5a039f3b84ffd5c5913" @@ -13329,6 +13374,13 @@ dependencies: tslib "^2.4.0" +"@swc/helpers@^0.5.8": + version "0.5.13" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.13.tgz#33e63ff3cd0cade557672bd7888a39ce7d115a8c" + integrity sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w== + dependencies: + tslib "^2.4.0" + "@swc/jest@^0.2.22": version "0.2.36" resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.36.tgz#2797450a30d28b471997a17e901ccad946fe693e" @@ -15079,6 +15131,16 @@ ajv-errors@^3.0.0, ajv-errors@~3.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-3.0.0.tgz#e54f299f3a3d30fe144161e5f0d8d51196c527bc" integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== +ajv-formats-draft2019@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ajv-formats-draft2019/-/ajv-formats-draft2019-1.6.1.tgz#6affe2220e7828360793776f1976de0420acccfb" + integrity sha512-JQPvavpkWDvIsBp2Z33UkYCtXCSpW4HD3tAZ+oL4iEFOk9obQZffx0yANwECt6vzr6ET+7HN5czRyqXbnq/u0Q== + dependencies: + punycode "^2.1.1" + schemes "^1.4.0" + smtp-address-parser "^1.0.3" + uri-js "^4.4.1" + ajv-formats@^2.1.0, ajv-formats@^2.1.1, ajv-formats@~2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" @@ -15086,6 +15148,11 @@ ajv-formats@^2.1.0, ajv-formats@^2.1.1, ajv-formats@~2.1.0: dependencies: ajv "^8.0.0" +ajv-i18n@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/ajv-i18n/-/ajv-i18n-4.2.0.tgz#d48750ba60e283b3dee31e3c22c8c9f7410e326f" + integrity sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg== + ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -16633,6 +16700,13 @@ ci-info@^3.2.0, ci-info@^3.6.1, ci-info@^3.7.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== +cidr-regex@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-3.1.1.tgz#ba1972c57c66f61875f18fd7dd487469770b571d" + integrity sha512-RBqYd32aDwbCMFJRL6wHOlDNYJsPNTt8vC82ErHF5vKt8QQzxm1FrkW8s/R5pVrXMf17sba09Uoy91PKiddAsw== + dependencies: + ip-regex "^4.1.0" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -21934,6 +22008,11 @@ ip-address@^9.0.5: jsbn "1.1.0" sprintf-js "^1.1.3" +ip-regex@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" + integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -22053,6 +22132,13 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" +is-cidr@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-4.0.2.tgz#94c7585e4c6c77ceabf920f8cde51b8c0fda8814" + integrity sha512-z4a1ENUajDbEl/Q6/pVBpTR1nBjjEE1X7qb7bmWYanNnPoKAvUCPFKeXV6Fe4mgTkWKBqiHIcwsI3SndiO5FeA== + dependencies: + cidr-regex "^3.1.1" + is-core-module@^2.13.0, is-core-module@^2.13.1, is-core-module@^2.5.0, is-core-module@^2.8.1: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" @@ -24045,6 +24131,16 @@ koa@2.11.0: type-is "^1.6.16" vary "^1.1.2" +kubernetes-models@^4.3.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/kubernetes-models/-/kubernetes-models-4.4.0.tgz#432f44cb7d45714d03db7875fcb8d3896cf31858" + integrity sha512-EiQUjoDT42xrEyELYS5HGU8SKeAMdQFHyjeX6mPkWwAdSfH553Cp0do2NmB5ubiAo2WYS+TeLHzI/YQoigtm/w== + dependencies: + "@kubernetes-models/apimachinery" "^2.0.0" + "@kubernetes-models/base" "^5.0.0" + "@kubernetes-models/validate" "^4.0.0" + "@swc/helpers" "^0.5.8" + kuler@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" @@ -28694,6 +28790,11 @@ re-resizable@^6.9.0: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.11.tgz#f356e27877f12d926d076ab9ad9ff0b95912b475" integrity sha512-a3hiLWck/NkmyLvGWUuvkAmN1VhwAz4yOhS6FdMTaxCUVN9joIWkT11wsO68coG/iEYuwn+p/7qAmfQzRhiPLQ== +re2-wasm@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/re2-wasm/-/re2-wasm-1.0.2.tgz#78c09dc651b8962aa814b55ae7fe5e472ec15bbb" + integrity sha512-VXUdgSiUrE/WZXn6gUIVVIsg0+Hp6VPZPOaHCay+OuFKy6u/8ktmeNEf+U5qSA8jzGGFsg8jrDNu1BeHpz2pJA== + react-beautiful-dnd@^13.0.0: version "13.1.1" resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2" @@ -30073,6 +30174,13 @@ schema-utils@^4.0.0, schema-utils@^4.2.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" +schemes@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/schemes/-/schemes-1.4.0.tgz#9d03302275e562488dd3afa7b654ed42e00569ec" + integrity sha512-ImFy9FbCsQlVgnE3TCWmLPCFnVzx0lHL/l+umHplDqAKd0dzFpnS6lFZIpagBlYhKwzVmlV36ec0Y1XTu8JBAQ== + dependencies: + extend "^3.0.0" + screenfull@^5.0.0, screenfull@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" @@ -30467,6 +30575,13 @@ smtp-address-parser@1.0.10: dependencies: nearley "^2.20.1" +smtp-address-parser@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/smtp-address-parser/-/smtp-address-parser-1.1.0.tgz#681a4cd27a2df5feb3c7425b235ac8f05ea34d49" + integrity sha512-Gz11jbNU0plrReU9Sj7fmshSBxxJ9ShdD2q4ktHIHo/rpTH6lFyQoYHYKINPJtPe8aHFnsbtW46Ls0tCCBsIZg== + dependencies: + nearley "^2.20.1" + sockjs@^0.3.24: version "0.3.24" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" @@ -32499,7 +32614,7 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" -uri-js@^4.2.2: +uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==