From e4a3063b6cdbe62a527e8a62281c9b9ff1965b8e Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 15:28:58 +0800 Subject: [PATCH 01/26] feat: add consumer credential resource type definition --- libs/sdk/src/core/index.ts | 16 +++++++++++++++- libs/sdk/src/core/resource.ts | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libs/sdk/src/core/index.ts b/libs/sdk/src/core/index.ts index ac09d61..e69cdbb 100644 --- a/libs/sdk/src/core/index.ts +++ b/libs/sdk/src/core/index.ts @@ -178,12 +178,25 @@ export type GlobalRule = Record; export type PluginMetadata = Record; +export interface ConsumerCredential { + name: string; + description?: string; + labels?: Labels; + + type: 'key-auth' | 'basic-auth' | 'jwt-auth' | 'hmac-auth'; + + config: Plugin; + + metadata?: ResourceMetadata; +} + export interface Consumer { username: string; description?: string; labels?: Labels; plugins?: Plugins; + credentials?: Array; } export interface ConsumerGroup { @@ -226,9 +239,10 @@ export interface Configuration { global_rules?: Record; plugin_metadata?: Record; - // APISIX only resources + // internal use only routes?: Array; stream_routes?: Array; + consumer_credentials?: Array; /* consumer_groups?: Array; plugin_configs?: Array; upstreams?: Array; */ diff --git a/libs/sdk/src/core/resource.ts b/libs/sdk/src/core/resource.ts index 445703a..7efb6c7 100644 --- a/libs/sdk/src/core/resource.ts +++ b/libs/sdk/src/core/resource.ts @@ -8,6 +8,7 @@ export enum ResourceType { PLUGIN_METADATA = 'plugin_metadata', CONSUMER = 'consumer', CONSUMER_GROUP = 'consumer_group', + CONSUMER_CREDENTIAL = 'consumer_credential', STREAM_ROUTE = 'stream_route', // internal use only From f11a2e05effe1f568db53f716726e5513b9aa2c3 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 15:35:43 +0800 Subject: [PATCH 02/26] feat: add credential differ support --- apps/cli/src/differ/differv3.ts | 84 ++++++++++++--- apps/cli/src/differ/specs/consumer.spec.ts | 119 +++++++++++++++++++++ 2 files changed, 191 insertions(+), 12 deletions(-) create mode 100644 apps/cli/src/differ/specs/consumer.spec.ts diff --git a/apps/cli/src/differ/differv3.ts b/apps/cli/src/differ/differv3.ts index f838a5a..feb1d89 100644 --- a/apps/cli/src/differ/differv3.ts +++ b/apps/cli/src/differ/differv3.ts @@ -38,6 +38,9 @@ const order = { [`${ADCSDK.ResourceType.PLUGIN_METADATA}.${ADCSDK.EventType.DELETE}`]: 27, [`${ADCSDK.ResourceType.PLUGIN_METADATA}.${ADCSDK.EventType.CREATE}`]: 28, [`${ADCSDK.ResourceType.PLUGIN_METADATA}.${ADCSDK.EventType.UPDATE}`]: 29, + [`${ADCSDK.ResourceType.CONSUMER_CREDENTIAL}.${ADCSDK.EventType.DELETE}`]: 30, + [`${ADCSDK.ResourceType.CONSUMER_CREDENTIAL}.${ADCSDK.EventType.CREATE}`]: 31, + [`${ADCSDK.ResourceType.CONSUMER_CREDENTIAL}.${ADCSDK.EventType.UPDATE}`]: 32, }; export class DifferV3 { @@ -163,6 +166,19 @@ export class DifferV3 { res, ]) ?? [], ), + ...differ.diffResource( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + local?.consumer_credentials?.map((res) => [ + res.name, + ADCSDK.utils.generateId(generateResourceName(res.name)), + res, + ]) ?? [], + remote?.consumer_credentials?.map((res) => [ + res.name, + ADCSDK.utils.generateId(generateResourceName(res.name)), + res, + ]) ?? [], + ), /* ...differ.diffResource( ADCSDK.ResourceType.UPSTREAM, local?.upstreams?.map((res) => [ @@ -262,6 +278,15 @@ export class DifferV3 { local: Array<[ADCSDK.ResourceName, ADCSDK.ResourceId, ADCSDK.StreamRoute]>, remote: Array<[ADCSDK.ResourceName, ADCSDK.ResourceId, ADCSDK.StreamRoute]>, ): Array; + private diffResource( + resourceType: ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + local: Array< + [ADCSDK.ResourceName, ADCSDK.ResourceId, ADCSDK.ConsumerCredential] + >, + remote: Array< + [ADCSDK.ResourceName, ADCSDK.ResourceId, ADCSDK.ConsumerCredential] + >, + ): Array; private diffResource( resourceType: ADCSDK.ResourceType.UPSTREAM, local: Array<[ADCSDK.ResourceName, ADCSDK.ResourceId, ADCSDK.Upstream]>, @@ -316,6 +341,8 @@ export class DifferV3 { oldValue: remoteItem, // Special handling of resources containing nested resources + // When a consumer is deleted, its credentials are not taken into + // consideration. subEvents: DifferV3.diff( {}, resourceType === ADCSDK.ResourceType.SERVICE @@ -392,33 +419,55 @@ export class DifferV3 { // Special handling of resources containing nested resources: routes, consumer_groups const subEvents: Array = []; if ( - resourceType === ADCSDK.ResourceType.SERVICE || - resourceType === ADCSDK.ResourceType.CONSUMER_GROUP + [ + ADCSDK.ResourceType.SERVICE, + ADCSDK.ResourceType.CONSUMER_GROUP, + ADCSDK.ResourceType.CONSUMER, + ].includes(resourceType) ) { subEvents.push( ...DifferV3.diff( - resourceType === ADCSDK.ResourceType.SERVICE + resourceType === + (ADCSDK.ResourceType.SERVICE as ADCSDK.ResourceType) ? { routes: (localItem as ADCSDK.Service).routes, stream_routes: (localItem as ADCSDK.Service).stream_routes, } - : resourceType === ADCSDK.ResourceType.CONSUMER_GROUP + : resourceType === + (ADCSDK.ResourceType.CONSUMER_GROUP as ADCSDK.ResourceType) ? { consumers: (localItem as ADCSDK.ConsumerGroup).consumers, } - : {}, - resourceType === ADCSDK.ResourceType.SERVICE + : resourceType === + (ADCSDK.ResourceType.CONSUMER as ADCSDK.ResourceType) + ? { + consumer_credentials: (localItem as ADCSDK.Consumer) + .credentials, + } + : {}, + resourceType === + (ADCSDK.ResourceType.SERVICE as ADCSDK.ResourceType) ? { routes: (remoteItem as ADCSDK.Service).routes, stream_routes: (remoteItem as ADCSDK.Service).stream_routes, } - : resourceType === ADCSDK.ResourceType.CONSUMER_GROUP + : resourceType === + (ADCSDK.ResourceType.CONSUMER_GROUP as ADCSDK.ResourceType) ? { consumers: (remoteItem as ADCSDK.ConsumerGroup).consumers, } - : {}, + : resourceType === + (ADCSDK.ResourceType.CONSUMER as ADCSDK.ResourceType) + ? { + consumer_credentials: (remoteItem as ADCSDK.Consumer) + .credentials, + } + : {}, this.defaultValue, - resourceType === ADCSDK.ResourceType.SERVICE + [ + ADCSDK.ResourceType.SERVICE, + ADCSDK.ResourceType.CONSUMER, + ].includes(resourceType) ? remoteName : undefined, ).map(this.postprocessSubEvent(remoteName, remoteId)), @@ -434,7 +483,9 @@ export class DifferV3 { // Remove nested resources to indeed compare the main resource itself. (resourceType === ADCSDK.ResourceType.SERVICE ? ['routes', 'stream_routes'] - : ['consumers'] + : resourceType === ADCSDK.ResourceType.CONSUMER_GROUP + ? ['consumers'] + : ['credentials'] ).map((key) => { unset(mergedLocalItem, key); unset(remoteItem, key); @@ -555,10 +606,19 @@ export class DifferV3 { ? { consumers: (localItem as ADCSDK.ConsumerGroup).consumers, } - : {}, + : resourceType === ADCSDK.ResourceType.CONSUMER + ? { + consumer_credentials: (localItem as ADCSDK.Consumer) + .credentials, + } + : {}, {}, this.defaultValue, - resourceType === ADCSDK.ResourceType.SERVICE ? localName : undefined, + [ADCSDK.ResourceType.SERVICE, ADCSDK.ResourceType.CONSUMER].includes( + resourceType, + ) + ? localName + : undefined, ).map(this.postprocessSubEvent(localName, localId)), }); }); diff --git a/apps/cli/src/differ/specs/consumer.spec.ts b/apps/cli/src/differ/specs/consumer.spec.ts new file mode 100644 index 0000000..2813659 --- /dev/null +++ b/apps/cli/src/differ/specs/consumer.spec.ts @@ -0,0 +1,119 @@ +import * as ADCSDK from '@api7/adc-sdk'; + +import { DifferV3 } from '../differv3'; + +describe('Differ V3 - consumer', () => { + it('should create/update/delete consumer credentials', () => { + const consumerName = 'jack'; + const changeme = 'changeme'; + expect( + DifferV3.diff( + { + consumers: [ + { + username: consumerName, + credentials: [ + { + name: ADCSDK.EventType.CREATE, + type: 'key-auth', + config: { + key: consumerName, + }, + }, + { + name: ADCSDK.EventType.UPDATE, + type: 'basic-auth', + config: { + username: consumerName, + password: `${changeme}.new`, + }, + }, + ], + }, + ], + }, + { + consumers: [ + { + username: consumerName, + credentials: [ + { + name: ADCSDK.EventType.UPDATE, + type: 'basic-auth', + config: { + username: consumerName, + password: changeme, + }, + }, + { + name: ADCSDK.EventType.DELETE, + type: 'jwt-auth', + config: { + key: consumerName, + secret: changeme, + }, + }, + ], + }, + ], + }, + ), + ).toEqual([ + { + oldValue: { + config: { key: consumerName, secret: changeme }, + name: ADCSDK.EventType.DELETE, + type: 'jwt-auth', + }, + parentId: consumerName, + resourceId: ADCSDK.utils.generateId( + `${consumerName}.${ADCSDK.EventType.DELETE}`, + ), + resourceName: ADCSDK.EventType.DELETE, + resourceType: ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + type: ADCSDK.EventType.DELETE, + }, + { + newValue: { + config: { key: consumerName }, + name: ADCSDK.EventType.CREATE, + type: 'key-auth', + }, + parentId: consumerName, + resourceId: ADCSDK.utils.generateId( + `${consumerName}.${ADCSDK.EventType.CREATE}`, + ), + resourceName: ADCSDK.EventType.CREATE, + resourceType: ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + type: ADCSDK.EventType.CREATE, + }, + { + diff: [ + { + kind: 'E', + lhs: changeme, + path: ['config', 'password'], + rhs: `${changeme}.new`, + }, + ], + newValue: { + config: { password: `${changeme}.new`, username: consumerName }, + name: ADCSDK.EventType.UPDATE, + type: 'basic-auth', + }, + oldValue: { + config: { password: changeme, username: consumerName }, + name: ADCSDK.EventType.UPDATE, + type: 'basic-auth', + }, + parentId: consumerName, + resourceId: ADCSDK.utils.generateId( + `${consumerName}.${ADCSDK.EventType.UPDATE}`, + ), + resourceName: ADCSDK.EventType.UPDATE, + resourceType: ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + type: ADCSDK.EventType.UPDATE, + }, + ]); + }); +}); From de1dd30b293b249aa34366eae234c3fcb2ad30f2 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 15:36:26 +0800 Subject: [PATCH 03/26] feat: add api7 api type definition --- libs/backend-api7/src/typing.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libs/backend-api7/src/typing.ts b/libs/backend-api7/src/typing.ts index 3ee14ed..ab3b1a0 100644 --- a/libs/backend-api7/src/typing.ts +++ b/libs/backend-api7/src/typing.ts @@ -61,11 +61,21 @@ export interface Service { routes?: Array; stream_routes?: Array; } +export interface ConsumerCredential { + id?: string; + name: string; + desc?: string; + labels?: Labels; + + plugins: Plugins; +} export interface Consumer { username: string; desc?: string; labels?: Labels; plugins?: Plugins; + + credentials?: Array; } export interface SSL { id?: string; From 796c3487b9ce2267b216149fae36ed4e7a3063ca Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 15:38:22 +0800 Subject: [PATCH 04/26] feat: add consumer credential fetcher --- libs/backend-api7/src/fetcher.ts | 23 ++++++++++++++++++++- libs/backend-api7/src/transformer.ts | 31 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/libs/backend-api7/src/fetcher.ts b/libs/backend-api7/src/fetcher.ts index 26f29d1..a14b3a6 100644 --- a/libs/backend-api7/src/fetcher.ts +++ b/libs/backend-api7/src/fetcher.ts @@ -81,6 +81,26 @@ export class Fetcher { ); task.output = buildReqAndRespDebugOutput(resp, 'Get consumers'); + const consumers = resp?.data?.list; + const fetchCredentials = consumers.map(async (consumer) => { + const resp = await this.client.get<{ + list: Array; + }>(`/apisix/admin/consumers/${consumer.username}/credentials`, { + // In the current design, the consumer's credentials are not filtered + // using labels because nested labels filters can be misleading. Even + // if labels set for the consumer, the labels filter is not attached. + params: { + gateway_group_id: ctx.gatewayGroupId, + }, + }); + task.output = buildReqAndRespDebugOutput( + resp, + `Get credentials of consumer "${consumer.username}"`, + ); + consumer.credentials = resp?.data?.list; + }); + await Promise.all(fetchCredentials); + ctx.remote.consumers = resp?.data?.list?.map((item) => this.toADC.transformConsumer(item), ); @@ -192,7 +212,8 @@ export class Fetcher { ); }; - // Get plugin metadata below API7 3.2.14.0 + // [DEPRECATED] Get plugin metadata below API7 3.2.14.0 + // Support for 3.2.14.0 has been dropped, so this code will be removed in the future. private listMetadatasLT03021400: FetchTask['task'] = async (ctx, task) => { const resp = await this.client.get>( '/apisix/admin/plugins/list', diff --git a/libs/backend-api7/src/transformer.ts b/libs/backend-api7/src/transformer.ts index 948d3cd..92e2b79 100644 --- a/libs/backend-api7/src/transformer.ts +++ b/libs/backend-api7/src/transformer.ts @@ -65,6 +65,23 @@ export class ToADC { description: consumer.desc, labels: ToADC.transformLabels(consumer.labels), plugins: consumer.plugins, + credentials: consumer.credentials?.map((item) => + this.transformConsumerCredential(item), + ), + }); + } + + public transformConsumerCredential( + credential: typing.ConsumerCredential, + ): ADCSDK.ConsumerCredential { + const [pluginName, config] = Object.entries(credential.plugins)[0]; + return ADCSDK.utils.recursiveOmitUndefined({ + name: credential.name, + description: credential.desc, + labels: credential.labels, + type: pluginName as ADCSDK.ConsumerCredential['type'], + config, + metadata: { id: credential.id }, }); } @@ -175,6 +192,20 @@ export class FromADC { }); } + public transformConsumerCredential( + credential: ADCSDK.ConsumerCredential, + ): typing.ConsumerCredential { + return ADCSDK.utils.recursiveOmitUndefined({ + id: ADCSDK.utils.generateId(credential.name), + name: credential.name, + desc: credential.description, + labels: FromADC.transformLabels(credential.labels), + plugins: { + [credential.type]: credential.config, + }, + }); + } + public transformSSL(ssl: ADCSDK.SSL): typing.SSL { return ADCSDK.utils.recursiveOmitUndefined({ id: ADCSDK.utils.generateId(ssl.snis.join(',')), From 6507dd3cd41bd1b89efe59cf52b74b973d69b5cf Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 15:58:49 +0800 Subject: [PATCH 05/26] feat: add consumer credential operator --- libs/backend-api7/src/operator.ts | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/libs/backend-api7/src/operator.ts b/libs/backend-api7/src/operator.ts index a73a108..ea4eb1f 100644 --- a/libs/backend-api7/src/operator.ts +++ b/libs/backend-api7/src/operator.ts @@ -53,6 +53,20 @@ export class Operator { { validateStatus: () => true }, ); task.output = buildReqAndRespDebugOutput(resp); + } else if ( + event.resourceType === ADCSDK.ResourceType.CONSUMER_CREDENTIAL + ) { + resp = await this.client.put( + `/apisix/admin/consumers/${event.parentId}/credentials/${event.resourceId}`, + this.fromADC(event), + { + params: { + gateway_group_id: ctx.gatewayGroupId, + }, + validateStatus: () => true, + }, + ); + task.output = buildReqAndRespDebugOutput(resp); } else { resp = await this.client.put( `/apisix/admin/${this.generateResourceTypeInAPI(event.resourceType)}/${event.resourceId}`, @@ -152,6 +166,20 @@ export class Operator { ); task.output = buildReqAndRespDebugOutput(resp); return; + } else if ( + event.resourceType === ADCSDK.ResourceType.CONSUMER_CREDENTIAL + ) { + const resp = await this.client.delete( + `/apisix/admin/consumers/${event.parentId}/credentials/${event.resourceId}`, + { + params: { + gateway_group_id: ctx.gatewayGroupId, + }, + validateStatus: () => true, + }, + ); + task.output = buildReqAndRespDebugOutput(resp); + return; } const resp = await this.client.delete( @@ -258,6 +286,10 @@ export class Operator { ); case ADCSDK.ResourceType.SSL: return fromADC.transformSSL(event.newValue as ADCSDK.SSL); + case ADCSDK.ResourceType.CONSUMER_CREDENTIAL: + return fromADC.transformConsumerCredential( + event.newValue as ADCSDK.ConsumerCredential, + ); } } } From eb2ffbb942362e8464f36ff8f3c1c73c5b856e47 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 16:04:41 +0800 Subject: [PATCH 06/26] fix: apisix --- libs/backend-apisix/src/fetcher.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/backend-apisix/src/fetcher.ts b/libs/backend-apisix/src/fetcher.ts index 73f67ff..5157543 100644 --- a/libs/backend-apisix/src/fetcher.ts +++ b/libs/backend-apisix/src/fetcher.ts @@ -34,7 +34,10 @@ export class Fetcher { return Object.values(ADCSDK.ResourceType) .filter( (resourceType) => - resourceType !== ADCSDK.ResourceType.INTERNAL_STREAM_SERVICE, // ignore internal only types + ![ + ADCSDK.ResourceType.INTERNAL_STREAM_SERVICE, + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + ].includes(resourceType), // ignore internal only types ) .map((resourceType): [ADCSDK.ResourceType, string] => [ resourceType, From 3709e56aa45d5cff88dad0e746f042be926d171a Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 16:28:12 +0800 Subject: [PATCH 07/26] feat: add credential version requirement --- libs/backend-api7/src/fetcher.ts | 39 +++++++++++++++++-------------- libs/backend-api7/src/operator.ts | 8 +++++-- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/libs/backend-api7/src/fetcher.ts b/libs/backend-api7/src/fetcher.ts index a14b3a6..c90106b 100644 --- a/libs/backend-api7/src/fetcher.ts +++ b/libs/backend-api7/src/fetcher.ts @@ -82,26 +82,29 @@ export class Fetcher { task.output = buildReqAndRespDebugOutput(resp, 'Get consumers'); const consumers = resp?.data?.list; - const fetchCredentials = consumers.map(async (consumer) => { - const resp = await this.client.get<{ - list: Array; - }>(`/apisix/admin/consumers/${consumer.username}/credentials`, { - // In the current design, the consumer's credentials are not filtered - // using labels because nested labels filters can be misleading. Even - // if labels set for the consumer, the labels filter is not attached. - params: { - gateway_group_id: ctx.gatewayGroupId, - }, + + if (semVerGTE(ctx.api7Version, '3.2.15')) { + const fetchCredentials = consumers.map(async (consumer) => { + const resp = await this.client.get<{ + list: Array; + }>(`/apisix/admin/consumers/${consumer.username}/credentials`, { + // In the current design, the consumer's credentials are not filtered + // using labels because nested labels filters can be misleading. Even + // if labels set for the consumer, the labels filter is not attached. + params: { + gateway_group_id: ctx.gatewayGroupId, + }, + }); + task.output = buildReqAndRespDebugOutput( + resp, + `Get credentials of consumer "${consumer.username}"`, + ); + consumer.credentials = resp?.data?.list; }); - task.output = buildReqAndRespDebugOutput( - resp, - `Get credentials of consumer "${consumer.username}"`, - ); - consumer.credentials = resp?.data?.list; - }); - await Promise.all(fetchCredentials); + await Promise.all(fetchCredentials); + } - ctx.remote.consumers = resp?.data?.list?.map((item) => + ctx.remote.consumers = consumers?.map((item) => this.toADC.transformConsumer(item), ); }, diff --git a/libs/backend-api7/src/operator.ts b/libs/backend-api7/src/operator.ts index ea4eb1f..7bb7fe0 100644 --- a/libs/backend-api7/src/operator.ts +++ b/libs/backend-api7/src/operator.ts @@ -2,12 +2,14 @@ import * as ADCSDK from '@api7/adc-sdk'; import { Axios, AxiosResponse } from 'axios'; import { ListrTask } from 'listr2'; import { size } from 'lodash'; +import { SemVer, gte as semVerGTE } from 'semver'; import { FromADC } from './transformer'; import * as typing from './typing'; import { buildReqAndRespDebugOutput, capitalizeFirstLetter } from './utils'; export interface OperateContext { + api7Version: SemVer; diff: Array; gatewayGroupId: string; needPublishServices: Record; @@ -54,7 +56,8 @@ export class Operator { ); task.output = buildReqAndRespDebugOutput(resp); } else if ( - event.resourceType === ADCSDK.ResourceType.CONSUMER_CREDENTIAL + event.resourceType === ADCSDK.ResourceType.CONSUMER_CREDENTIAL && + semVerGTE(ctx.api7Version, '3.2.15') ) { resp = await this.client.put( `/apisix/admin/consumers/${event.parentId}/credentials/${event.resourceId}`, @@ -167,7 +170,8 @@ export class Operator { task.output = buildReqAndRespDebugOutput(resp); return; } else if ( - event.resourceType === ADCSDK.ResourceType.CONSUMER_CREDENTIAL + event.resourceType === ADCSDK.ResourceType.CONSUMER_CREDENTIAL && + semVerGTE(ctx.api7Version, '3.2.15') ) { const resp = await this.client.delete( `/apisix/admin/consumers/${event.parentId}/credentials/${event.resourceId}`, From 8664eb4014840d8b64d0a0b16cfa36892a528abc Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 16:55:47 +0800 Subject: [PATCH 08/26] feat: add credentials schema for linter --- apps/cli/src/linter/schema.ts | 23 +++++- apps/cli/src/linter/specs/consumer.spec.ts | 93 ++++++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 apps/cli/src/linter/specs/consumer.spec.ts diff --git a/apps/cli/src/linter/schema.ts b/apps/cli/src/linter/schema.ts index dbd59eb..ae4bb4b 100644 --- a/apps/cli/src/linter/schema.ts +++ b/apps/cli/src/linter/schema.ts @@ -12,7 +12,8 @@ const labelsSchema = z.record( z.string(), z.union([z.string(), z.array(z.string())]), ); -const pluginsSchema = z.record(z.string(), z.record(z.string(), z.any())); +const pluginSchema = z.record(z.string(), z.any()); +const pluginsSchema = z.record(z.string(), pluginSchema); const exprSchema = z.array(z.any()); const timeoutSchema = z.object({ connect: z.number().gt(0), @@ -289,6 +290,25 @@ const sslSchema = z }) .strict(); +const consumerCredentialSchema = z + .object({ + name: nameSchema, + description: descriptionSchema.optional(), + labels: labelsSchema.optional(), + + type: z + .string() + .refine( + (type) => + ['key-auth', 'basic-auth', 'jwt-auth', 'hmac-auth'].includes(type), + { + message: + 'Consumer credential only supports "key-auth", "basic-auth", "jwt-auth" and "hmac-auth" types', + }, + ), + config: pluginSchema, + }) + .strict(); const consumerSchema = z .object({ username: nameSchema, @@ -296,6 +316,7 @@ const consumerSchema = z labels: labelsSchema.optional(), plugins: pluginsSchema.optional(), + credentials: z.array(consumerCredentialSchema).optional(), }) .strict(); diff --git a/apps/cli/src/linter/specs/consumer.spec.ts b/apps/cli/src/linter/specs/consumer.spec.ts new file mode 100644 index 0000000..885ee09 --- /dev/null +++ b/apps/cli/src/linter/specs/consumer.spec.ts @@ -0,0 +1,93 @@ +import * as ADCSDK from '@api7/adc-sdk'; + +import { check } from '..'; + +describe('Consumer Linter', () => { + const cases = [ + { + name: 'should check consumer credentials (success)', + input: { + consumers: [ + { + username: 'jack', + credentials: [ + { + name: 'jack-1', + type: 'key-auth', + config: { + key: 'jack', + }, + }, + ], + }, + ], + } as ADCSDK.Configuration, + expect: true, + errors: [], + }, + { + name: 'should check consumer credentials (miss config)', + input: { + consumers: [ + { + username: 'jack', + credentials: [ + { + name: 'jack-1', + type: 'key-auth', + }, + ], + }, + ], + } as ADCSDK.Configuration, + expect: false, + errors: [ + { + code: 'invalid_type', + expected: 'object', + message: 'Required', + path: ['consumers', 0, 'credentials', 0, 'config'], + received: 'undefined', + }, + ], + }, + { + name: 'should check consumer credentials (unsupported type)', + //@ts-expect-error for test + input: { + consumers: [ + { + username: 'jack', + credentials: [ + { + name: 'jack-1', + type: 'none-auth', + config: {}, + }, + ], + }, + ], + } as ADCSDK.Configuration, + expect: false, + errors: [ + { + code: 'custom', + message: + 'Consumer credential only supports "key-auth", "basic-auth", "jwt-auth" and "hmac-auth" types', + path: ['consumers', 0, 'credentials', 0, 'type'], + }, + ], + }, + ]; + + // test cases runner + cases.forEach((item) => { + it(item.name, () => { + const result = check(item.input); + expect(result.success).toEqual(item.expect); + if (!item.expect) { + expect(result.error.errors).toEqual(item.errors); + } + }); + }); +}); From be226efa006af2702cc6914e89c164008c9290a7 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Sun, 1 Sep 2024 16:57:38 +0800 Subject: [PATCH 09/26] chore: update schema.json --- schema.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/schema.json b/schema.json index b9afd10..b2b2327 100644 --- a/schema.json +++ b/schema.json @@ -648,6 +648,35 @@ }, "plugins": { "$ref": "#/properties/services/items/properties/plugins" + }, + "credentials": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "$ref": "#/properties/services/items/properties/name" + }, + "description": { + "$ref": "#/properties/services/items/properties/description" + }, + "labels": { + "$ref": "#/properties/services/items/properties/labels" + }, + "type": { + "type": "string" + }, + "config": { + "$ref": "#/properties/services/items/properties/plugins/additionalProperties" + } + }, + "required": [ + "name", + "type", + "config" + ], + "additionalProperties": false + } } }, "required": [ From 9700a719e53890949d2f15afcbc8969cff406dbd Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 2 Sep 2024 13:47:40 +0800 Subject: [PATCH 10/26] test: add sync and dump case --- .../e2e/sync-and-dump-1.e2e-spec.ts | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts b/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts index 532d310..b8991b7 100644 --- a/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts +++ b/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts @@ -514,4 +514,82 @@ describe('Sync and Dump - 1', () => { expect(Object.keys(result.plugin_metadata)).toHaveLength(0); }); }); + + describe('Sync and dump consumer credentials', () => { + const consumer1Name = 'consumer1'; + const consumer1Key = 'consumer1-key'; + const consumer1Cred = { + name: consumer1Key, + type: 'key-auth', + config: { key: consumer1Key }, + }; + const consumer1 = { + username: consumer1Name, + credentials: [consumer1Cred], + } as ADCSDK.Consumer; + + it('Create consumers', async () => + syncEvents(backend, [ + createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), + createEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + consumer1Key, + consumer1Cred, + consumer1Name, + ), + ])); + + it('Dump', async () => { + const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer1); + expect(result.consumers[0].credentials).toMatchObject( + consumer1.credentials, + ); + }); + + it('Update consumer credential', async () => { + consumer1.credentials[0].config.key = 'new-key'; + await syncEvents(backend, [ + updateEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + consumer1Key, + consumer1, + consumer1Name, + ), + ]); + }); + + it('Dump again (consumer credential updated)', async () => { + const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; + expect(result.consumers[0]).toMatchObject(consumer1); + expect(result.consumers[0].credentials[0].config.key).toEqual('new-key'); + }); + + it('Delete consumer credential', async () => + syncEvents(backend, [ + deleteEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + consumer1Key, + consumer1Name, + ), + ])); + + it('Dump again (consumer credential should not exist)', async () => { + const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer1); + expect(result.consumers[0].credentials).toHaveLength(0); + }); + + it('Delete consumer', async () => + syncEvents(backend, [ + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), + ])); + + it('Dump again (consumer should not exist)', async () => { + const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(0); + }); + }); }); From 1300521aaf9fa803daf6892a2f4d66c55041125e Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 00:15:35 +0800 Subject: [PATCH 11/26] test: move consumer e2e to sperated spec file --- .../e2e/resources/consumer.e2e-spec.ts | 195 ++++++++++++++++++ libs/backend-api7/e2e/support/utils.ts | 13 ++ .../e2e/sync-and-dump-1.e2e-spec.ts | 145 ------------- 3 files changed, 208 insertions(+), 145 deletions(-) create mode 100644 libs/backend-api7/e2e/resources/consumer.e2e-spec.ts diff --git a/libs/backend-api7/e2e/resources/consumer.e2e-spec.ts b/libs/backend-api7/e2e/resources/consumer.e2e-spec.ts new file mode 100644 index 0000000..28b9a38 --- /dev/null +++ b/libs/backend-api7/e2e/resources/consumer.e2e-spec.ts @@ -0,0 +1,195 @@ +import * as ADCSDK from '@api7/adc-sdk'; +import { gte } from 'lodash'; +import { lt } from 'semver'; + +import { BackendAPI7 } from '../../src'; +import { conditionalDescribe, semverCondition } from '../support/utils'; +import { + createEvent, + deleteEvent, + dumpConfiguration, + syncEvents, + updateEvent, +} from '../support/utils'; + +describe('Consumer E2E', () => { + let backend: BackendAPI7; + + beforeAll(() => { + backend = new BackendAPI7({ + server: process.env.SERVER, + token: process.env.TOKEN, + tlsSkipVerify: true, + gatewayGroup: 'default', + }); + }); + + conditionalDescribe(semverCondition(lt, '3.2.15'))( + 'Sync and dump consumers (without credentials support)', + () => { + const consumer1Name = 'consumer1'; + const consumer1 = { + username: consumer1Name, + plugins: { + 'key-auth': { + key: consumer1Name, + }, + }, + } as ADCSDK.Consumer; + const consumer2Name = 'consumer2'; + const consumer2 = { + username: consumer2Name, + plugins: { + 'key-auth': { + key: consumer2Name, + }, + }, + } as ADCSDK.Consumer; + + it('Create consumers', async () => + syncEvents(backend, [ + createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), + createEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name, consumer2), + ])); + + it('Dump', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(2); + expect(result.consumers[0]).toMatchObject(consumer2); + expect(result.consumers[1]).toMatchObject(consumer1); + }); + + it('Update consumer1', async () => { + consumer1.description = 'desc'; + await syncEvents(backend, [ + updateEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), + ]); + }); + + it('Dump again (consumer1 updated)', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers[0]).toMatchObject(consumer1); + }); + + it('Delete consumer1', async () => + syncEvents(backend, [ + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), + ])); + + it('Dump again (consumer1 should not exist)', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer2); + }); + + it('Delete consumer2', async () => + syncEvents(backend, [ + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name), + ])); + + it('Dump again (consumer2 should not exist)', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(0); + }); + }, + ); + + conditionalDescribe(semverCondition(gte, '3.2.15'))( + 'Sync and dump consumers (with credentials support)', + () => { + const consumer1Name = 'consumer1'; + const consumer1Key = 'consumer1-key'; + const consumer1Cred = { + name: consumer1Key, + type: 'key-auth', + config: { key: consumer1Key }, + }; + const consumer1 = { + username: consumer1Name, + credentials: [consumer1Cred], + } as ADCSDK.Consumer; + + it('Create consumers', async () => + syncEvents(backend, [ + createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), + createEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + consumer1Key, + consumer1Cred, + consumer1Name, + ), + ])); + + it('Dump', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer1); + expect(result.consumers[0].credentials).toMatchObject( + consumer1.credentials, + ); + }); + + it('Update consumer credential', async () => { + consumer1.credentials[0].config.key = 'new-key'; + await syncEvents(backend, [ + updateEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + consumer1Key, + consumer1, + consumer1Name, + ), + ]); + }); + + it('Dump again (consumer credential updated)', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers[0]).toMatchObject(consumer1); + expect(result.consumers[0].credentials[0].config.key).toEqual( + 'new-key', + ); + }); + + it('Delete consumer credential', async () => + syncEvents(backend, [ + deleteEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + consumer1Key, + consumer1Name, + ), + ])); + + it('Dump again (consumer credential should not exist)', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer1); + expect(result.consumers[0].credentials).toHaveLength(0); + }); + + it('Delete consumer', async () => + syncEvents(backend, [ + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), + ])); + + it('Dump again (consumer should not exist)', async () => { + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(0); + }); + }, + ); +}); diff --git a/libs/backend-api7/e2e/support/utils.ts b/libs/backend-api7/e2e/support/utils.ts index 33f66da..50e0d80 100644 --- a/libs/backend-api7/e2e/support/utils.ts +++ b/libs/backend-api7/e2e/support/utils.ts @@ -92,3 +92,16 @@ export const deleteEvent = ( ), parentId: parentName ? ADCSDK.utils.generateId(parentName) : undefined, }); + +type cond = boolean | (() => boolean); + +export const conditionalDescribe = (cond: cond) => + cond ? describe : describe.skip; + +export const conditionalIt = (cond: cond) => (cond ? it : it.skip); + +export const semverCondition = ( + op: (v1: string, v2: string) => boolean, + target: string, + base = process.env.BACKEND_API7_VERSION ?? '0.0.0', +) => op(target, base); diff --git a/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts b/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts index b8991b7..dfe8009 100644 --- a/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts +++ b/libs/backend-api7/e2e/sync-and-dump-1.e2e-spec.ts @@ -247,73 +247,6 @@ describe('Sync and Dump - 1', () => { }); }); - describe('Sync and dump consumers', () => { - const consumer1Name = 'consumer1'; - const consumer1 = { - username: consumer1Name, - plugins: { - 'key-auth': { - key: consumer1Name, - }, - }, - } as ADCSDK.Consumer; - const consumer2Name = 'consumer2'; - const consumer2 = { - username: consumer2Name, - plugins: { - 'key-auth': { - key: consumer2Name, - }, - }, - } as ADCSDK.Consumer; - - it('Create consumers', async () => - syncEvents(backend, [ - createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), - createEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name, consumer2), - ])); - - it('Dump', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(2); - expect(result.consumers[0]).toMatchObject(consumer2); - expect(result.consumers[1]).toMatchObject(consumer1); - }); - - it('Update consumer1', async () => { - consumer1.description = 'desc'; - await syncEvents(backend, [ - updateEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), - ]); - }); - - it('Dump again (consumer1 updated)', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers[0]).toMatchObject(consumer1); - }); - - it('Delete consumer1', async () => - syncEvents(backend, [ - deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), - ])); - - it('Dump again (consumer1 should not exist)', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(1); - expect(result.consumers[0]).toMatchObject(consumer2); - }); - - it('Delete consumer2', async () => - syncEvents(backend, [ - deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name), - ])); - - it('Dump again (consumer2 should not exist)', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(0); - }); - }); - describe('Sync and dump ssls', () => { const certificates = [ { @@ -514,82 +447,4 @@ describe('Sync and Dump - 1', () => { expect(Object.keys(result.plugin_metadata)).toHaveLength(0); }); }); - - describe('Sync and dump consumer credentials', () => { - const consumer1Name = 'consumer1'; - const consumer1Key = 'consumer1-key'; - const consumer1Cred = { - name: consumer1Key, - type: 'key-auth', - config: { key: consumer1Key }, - }; - const consumer1 = { - username: consumer1Name, - credentials: [consumer1Cred], - } as ADCSDK.Consumer; - - it('Create consumers', async () => - syncEvents(backend, [ - createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), - createEvent( - ADCSDK.ResourceType.CONSUMER_CREDENTIAL, - consumer1Key, - consumer1Cred, - consumer1Name, - ), - ])); - - it('Dump', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(1); - expect(result.consumers[0]).toMatchObject(consumer1); - expect(result.consumers[0].credentials).toMatchObject( - consumer1.credentials, - ); - }); - - it('Update consumer credential', async () => { - consumer1.credentials[0].config.key = 'new-key'; - await syncEvents(backend, [ - updateEvent( - ADCSDK.ResourceType.CONSUMER_CREDENTIAL, - consumer1Key, - consumer1, - consumer1Name, - ), - ]); - }); - - it('Dump again (consumer credential updated)', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers[0]).toMatchObject(consumer1); - expect(result.consumers[0].credentials[0].config.key).toEqual('new-key'); - }); - - it('Delete consumer credential', async () => - syncEvents(backend, [ - deleteEvent( - ADCSDK.ResourceType.CONSUMER_CREDENTIAL, - consumer1Key, - consumer1Name, - ), - ])); - - it('Dump again (consumer credential should not exist)', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(1); - expect(result.consumers[0]).toMatchObject(consumer1); - expect(result.consumers[0].credentials).toHaveLength(0); - }); - - it('Delete consumer', async () => - syncEvents(backend, [ - deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), - ])); - - it('Dump again (consumer should not exist)', async () => { - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(0); - }); - }); }); From 5d46633ffe4b4e8e676c2367bb366b4889d098e5 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 00:17:23 +0800 Subject: [PATCH 12/26] test: add 3.2.15 --- .github/workflows/e2e.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 6652f50..cb46a14 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -39,8 +39,9 @@ jobs: if: contains(github.event.pull_request.labels.*.name, 'test/api7') || github.event_name == 'push' strategy: matrix: - version: [3.2.14.6] + version: [3.2.14.6, 3.2.15.0] env: + BACKEND_API7_VERSION: ${{ matrix.version }} BACKEND_API7_DOWNLOAD_URL: https://run.api7.ai/api7-ee/api7-ee-v${{ matrix.version }}.tar.gz BACKEND_API7_LICENSE: ${{ secrets.BACKEND_API7_LICENSE }} steps: From e8be0415a448b803a9fe11035220f1b648856c09 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 00:22:31 +0800 Subject: [PATCH 13/26] test: fix global setup --- libs/backend-api7/e2e/support/global-setup.ts | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/libs/backend-api7/e2e/support/global-setup.ts b/libs/backend-api7/e2e/support/global-setup.ts index c0f30a6..3040d6e 100644 --- a/libs/backend-api7/e2e/support/global-setup.ts +++ b/libs/backend-api7/e2e/support/global-setup.ts @@ -5,15 +5,29 @@ import { Agent } from 'node:https'; const httpClient = axios.create({ baseURL: 'https://localhost:7443', - auth: { - username: 'admin', - password: 'admin', - }, + withCredentials: true, httpsAgent: new Agent({ rejectUnauthorized: false, }), }); +httpClient.interceptors.response.use((response) => { + if (response.headers['set-cookie']?.[0]) { + //@ts-expect-error forced + httpClient.sessionToken = response.headers['set-cookie']?.[0].split(';')[0]; + } + return response; +}); + +httpClient.interceptors.request.use( + (config) => { + //@ts-expect-error forced + config.headers['Cookie'] = httpClient.sessionToken; + return config; + }, + (error) => Promise.reject(error), +); + const setupAPI7 = async () => { return new Promise((resolve, reject) => { const ls = spawn( @@ -45,13 +59,56 @@ const setupAPI7 = async () => { }); }; +const initUser = async (username = 'admin', password = 'admin') => { + console.log('Log in'); + await httpClient.post(`/api/login`, { + username: username, + password: password, + }); + + console.log('Modify password'); + await httpClient.put(`/api/password`, { + old_password: password, + new_password: 'Admin12345!', + }); + + //@ts-expect-error forced + httpClient.sessionToken = ''; + + console.log('Log in again'); + await httpClient.post(`/api/login`, { + username: username, + password: 'Admin12345!', + }); +}; + const activateAPI7 = async () => { + console.log('Upload license'); await httpClient.put(`/api/license`, { data: process.env.BACKEND_API7_LICENSE, }); }; const generateToken = async () => { + console.log('Create test user'); + const user = await httpClient.post(`/api/invites`, { + username: 'test', + password: 'test', + }); + const userId: string = user.data.value.id; + + console.log('Update role'); + await httpClient.put(`/api/users/${userId}/assigned_roles`, { + roles: ['super_admin_id'], + }); + + //@ts-expect-error forced + httpClient.sessionToken = ''; + + console.log('Log in to test user'); + await initUser('test', 'test'); + + console.log('Generate token'); const resp = await httpClient.post<{ value: { token: string } }>( `/api/tokens`, { @@ -66,6 +123,7 @@ const generateToken = async () => { export default async () => { if (process.env['SKIP_API7_SETUP'] !== 'true') await setupAPI7(); + await initUser(); await activateAPI7(); await generateToken(); From 5a684cdbbcc8700fec0337399ac26c8022945fff Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 00:40:18 +0800 Subject: [PATCH 14/26] fix --- libs/backend-api7/e2e/support/global-setup.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/backend-api7/e2e/support/global-setup.ts b/libs/backend-api7/e2e/support/global-setup.ts index 3040d6e..dd7b45f 100644 --- a/libs/backend-api7/e2e/support/global-setup.ts +++ b/libs/backend-api7/e2e/support/global-setup.ts @@ -2,6 +2,7 @@ import axios from 'axios'; import { spawn } from 'node:child_process'; import { randomUUID } from 'node:crypto'; import { Agent } from 'node:https'; +import { gte, lt } from 'semver'; const httpClient = axios.create({ baseURL: 'https://localhost:7443', @@ -66,6 +67,10 @@ const initUser = async (username = 'admin', password = 'admin') => { password: password, }); + // If the version is lower than 3.2.15, the license should be activated first. + if (lt('3.2.15', process.env.BACKEND_API7_VERSION ?? '0.0.0')) + await activateAPI7(); + console.log('Modify password'); await httpClient.put(`/api/password`, { old_password: password, @@ -80,6 +85,11 @@ const initUser = async (username = 'admin', password = 'admin') => { username: username, password: 'Admin12345!', }); + + // If the version is greater than or equal to 3.2.15, the license should + // be activated after changing the password. + if (gte('3.2.15', process.env.BACKEND_API7_VERSION ?? '0.0.0')) + await activateAPI7(); }; const activateAPI7 = async () => { @@ -124,7 +134,6 @@ const generateToken = async () => { export default async () => { if (process.env['SKIP_API7_SETUP'] !== 'true') await setupAPI7(); await initUser(); - await activateAPI7(); await generateToken(); process.env.SERVER = 'https://localhost:7443'; From ce39fac73ffb8055946b258a1c72f54c891df672 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 00:47:18 +0800 Subject: [PATCH 15/26] fix --- libs/backend-api7/e2e/support/global-setup.ts | 16 +++++++++++++--- libs/backend-api7/e2e/support/utils.ts | 5 +++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/libs/backend-api7/e2e/support/global-setup.ts b/libs/backend-api7/e2e/support/global-setup.ts index dd7b45f..5ad55ac 100644 --- a/libs/backend-api7/e2e/support/global-setup.ts +++ b/libs/backend-api7/e2e/support/global-setup.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { spawn } from 'node:child_process'; import { randomUUID } from 'node:crypto'; import { Agent } from 'node:https'; -import { gte, lt } from 'semver'; +import * as semver from 'semver'; const httpClient = axios.create({ baseURL: 'https://localhost:7443', @@ -68,7 +68,12 @@ const initUser = async (username = 'admin', password = 'admin') => { }); // If the version is lower than 3.2.15, the license should be activated first. - if (lt('3.2.15', process.env.BACKEND_API7_VERSION ?? '0.0.0')) + if ( + semver.lt( + '3.2.15', + semver.coerce(process.env.BACKEND_API7_VERSION) ?? '0.0.0', + ) + ) await activateAPI7(); console.log('Modify password'); @@ -88,7 +93,12 @@ const initUser = async (username = 'admin', password = 'admin') => { // If the version is greater than or equal to 3.2.15, the license should // be activated after changing the password. - if (gte('3.2.15', process.env.BACKEND_API7_VERSION ?? '0.0.0')) + if ( + semver.gte( + '3.2.15', + semver.coerce(process.env.BACKEND_API7_VERSION) ?? '0.0.0', + ) + ) await activateAPI7(); }; diff --git a/libs/backend-api7/e2e/support/utils.ts b/libs/backend-api7/e2e/support/utils.ts index 50e0d80..2dd5483 100644 --- a/libs/backend-api7/e2e/support/utils.ts +++ b/libs/backend-api7/e2e/support/utils.ts @@ -1,5 +1,6 @@ import * as ADCSDK from '@api7/adc-sdk'; import { Listr, SilentRenderer } from 'listr2'; +import * as semver from 'semver'; import { BackendAPI7 } from '../../src'; @@ -101,7 +102,7 @@ export const conditionalDescribe = (cond: cond) => export const conditionalIt = (cond: cond) => (cond ? it : it.skip); export const semverCondition = ( - op: (v1: string, v2: string) => boolean, + op: (v1: string, v2: string | semver.SemVer) => boolean, target: string, - base = process.env.BACKEND_API7_VERSION ?? '0.0.0', + base = semver.coerce(process.env.BACKEND_API7_VERSION) ?? '0.0.0', ) => op(target, base); From ade750e295d8ffe2ffc4198b89c227e3da16c746 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 00:58:46 +0800 Subject: [PATCH 16/26] fix --- libs/backend-api7/e2e/support/global-setup.ts | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/libs/backend-api7/e2e/support/global-setup.ts b/libs/backend-api7/e2e/support/global-setup.ts index 5ad55ac..46b6a3c 100644 --- a/libs/backend-api7/e2e/support/global-setup.ts +++ b/libs/backend-api7/e2e/support/global-setup.ts @@ -60,7 +60,11 @@ const setupAPI7 = async () => { }); }; -const initUser = async (username = 'admin', password = 'admin') => { +const initUser = async ( + username = 'admin', + password = 'admin', + fisrtTime = true, +) => { console.log('Log in'); await httpClient.post(`/api/login`, { username: username, @@ -70,9 +74,10 @@ const initUser = async (username = 'admin', password = 'admin') => { // If the version is lower than 3.2.15, the license should be activated first. if ( semver.lt( - '3.2.15', semver.coerce(process.env.BACKEND_API7_VERSION) ?? '0.0.0', - ) + '3.2.15', + ) && + fisrtTime ) await activateAPI7(); @@ -95,9 +100,10 @@ const initUser = async (username = 'admin', password = 'admin') => { // be activated after changing the password. if ( semver.gte( - '3.2.15', semver.coerce(process.env.BACKEND_API7_VERSION) ?? '0.0.0', - ) + '3.2.15', + ) && + fisrtTime ) await activateAPI7(); }; @@ -126,7 +132,7 @@ const generateToken = async () => { httpClient.sessionToken = ''; console.log('Log in to test user'); - await initUser('test', 'test'); + await initUser('test', 'test', false); console.log('Generate token'); const resp = await httpClient.post<{ value: { token: string } }>( @@ -143,8 +149,13 @@ const generateToken = async () => { export default async () => { if (process.env['SKIP_API7_SETUP'] !== 'true') await setupAPI7(); - await initUser(); - await generateToken(); + try { + await initUser(); + await generateToken(); + } catch (err) { + console.log(err); + throw err; + } process.env.SERVER = 'https://localhost:7443'; }; From d658a3a20c8dfea78aef4201ffe25fe6ee59a878 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 01:04:28 +0800 Subject: [PATCH 17/26] fix: e2e --- libs/backend-api7/e2e/assets/testdata/mixed-1.json | 5 +++-- libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/backend-api7/e2e/assets/testdata/mixed-1.json b/libs/backend-api7/e2e/assets/testdata/mixed-1.json index 870dce4..21139bf 100644 --- a/libs/backend-api7/e2e/assets/testdata/mixed-1.json +++ b/libs/backend-api7/e2e/assets/testdata/mixed-1.json @@ -260,8 +260,9 @@ "username": "tom", "description": "", "plugins": { - "key-auth": { - "key": "tom" + "limit-count": { + "window": 1, + "count": 1 } } } diff --git a/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts b/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts index 4795309..d48950e 100644 --- a/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts +++ b/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts @@ -177,8 +177,9 @@ describe('Sync and Dump - 2', () => { expect(dump.consumers[0]).toMatchObject({ username: 'tom', plugins: { - 'key-auth': { - key: 'tom', + 'limit-count': { + window: 1, + count: 1, }, }, }); From bf5af5217379dc1679473d905cd04748106c8291 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 01:09:43 +0800 Subject: [PATCH 18/26] fix: e2e --- .../e2e/assets/testdata/mixed-1-clean.json | 6 - .../e2e/assets/testdata/mixed-1.json | 104 ++++++++++++------ .../e2e/sync-and-dump-2.e2e-spec.ts | 10 -- 3 files changed, 69 insertions(+), 51 deletions(-) diff --git a/libs/backend-api7/e2e/assets/testdata/mixed-1-clean.json b/libs/backend-api7/e2e/assets/testdata/mixed-1-clean.json index 5220887..5c40aeb 100644 --- a/libs/backend-api7/e2e/assets/testdata/mixed-1-clean.json +++ b/libs/backend-api7/e2e/assets/testdata/mixed-1-clean.json @@ -39,12 +39,6 @@ "resourceId": "45d48919804fadc2db9d0180a65fe0ee0a8ddf9a", "resourceName": "service2" }, - { - "resourceType": "consumer", - "type": "delete", - "resourceId": "tom", - "resourceName": "tom" - }, { "resourceType": "ssl", "type": "delete", diff --git a/libs/backend-api7/e2e/assets/testdata/mixed-1.json b/libs/backend-api7/e2e/assets/testdata/mixed-1.json index 21139bf..870d51a 100644 --- a/libs/backend-api7/e2e/assets/testdata/mixed-1.json +++ b/libs/backend-api7/e2e/assets/testdata/mixed-1.json @@ -6,7 +6,9 @@ "resourceName": "test.com", "newValue": { "type": "server", - "snis": ["test.com"], + "snis": [ + "test.com" + ], "certificates": [ { "certificate": "-----BEGIN CERTIFICATE-----\nMIICrTCCAZUCFCcH5+jEDUhpTxEQo/pZYC91e2aYMA0GCSqGSIb3DQEBCwUAMBEx\nDzANBgNVBAMMBlJPT1RDQTAgFw0yNDAxMTgwNjAzMDNaGA8yMTIzMTIyNTA2MDMw\nM1owEzERMA8GA1UEAwwIdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\nggEKAoIBAQCVkfufMRK2bckdpQ/aRfcaTxmjsv5Mb+sJdhb0QuEuXp/VgN3yzFM0\nzCmAeBZwNKpU3HZDv0tnkTx7OARYpj5Bw1ole0EfPVPKBRjlLE56tabzyd4vdLV2\nbk7jYH+H8NjGZNEYLm9MdWiB4Ulyc0+XFA0ZL5WWKOi+oSQVUibT8QK0CENFKNLP\nQjEXlbyujzRS3u6r99EEEy8+3psBA2EELq8GAjEp+jilWggBhUEpLQxCHhHeNevR\nkg5iEvhOhEVKtr5xvgolg5Wvz7GmDulIW9MCu0dIXim52H/spPwgi3yRraY1XjxU\nREyj5tcY7n7LBESkx/ODXEyCkICIPpo9AgMBAAEwDQYJKoZIhvcNAQELBQADggEB\nADBU5XvbnjaF4rpQoqdzgK6BuRvD/Ih/rh+xc+G9mm+qaHx0g3TdTqyhCvSg6aRW\njDq4Z0NILdb6wmJcunua1jjmOQMXER5y34Xfn21+dzjLN2Bl+/vZ/HyXlCjxkppG\nZAsd1H0/jmXqN1zddIThxOccmRcDEP+9GT3hba50sijFbO30Zx+ORJCoT8he6Kyw\nKdOs/yyukafoAtlpoPR+ao/kumto6w/rLfFlEsehU0dMGNgPVSxxVNtBSdxPTUBk\nD6mfqB4f//2DuAmiO+l5RmPUmumqzcYlpd+oAdy3OSnNEHbgxishZr/GI3s6DmUh\n16bgI69aQ5F+MnN3trvaufc=\n-----END CERTIFICATE-----\n", @@ -47,12 +49,24 @@ "https_verify_certificate": true, "healthy": { "interval": 1, - "http_statuses": [200, 302], + "http_statuses": [ + 200, + 302 + ], "successes": 2 }, "unhealthy": { "interval": 1, - "http_statuses": [429, 404, 500, 501, 502, 503, 504, 505], + "http_statuses": [ + 429, + 404, + 500, + 501, + 502, + 503, + 504, + 505 + ], "http_failures": 5, "tcp_failures": 2, "timeouts": 3 @@ -77,10 +91,14 @@ }, "routes": [ { - "uris": ["/anything"], + "uris": [ + "/anything" + ], "name": "route1.1", "description": "", - "methods": ["GET"], + "methods": [ + "GET" + ], "enable_websocket": false, "plugins": { "limit-count": { @@ -99,10 +117,14 @@ } }, { - "uris": ["/anything"], + "uris": [ + "/anything" + ], "name": "route1.2", "description": "", - "methods": ["POST"], + "methods": [ + "POST" + ], "enable_websocket": false } ] @@ -134,10 +156,15 @@ }, "routes": [ { - "uris": ["/getSomething"], + "uris": [ + "/getSomething" + ], "name": "route2.1", "description": "", - "methods": ["GET", "POST"], + "methods": [ + "GET", + "POST" + ], "enable_websocket": false, "plugins": { "limit-count": { @@ -156,10 +183,15 @@ } }, { - "uris": ["/postSomething"], + "uris": [ + "/postSomething" + ], "name": "route2.2", "description": "", - "methods": ["POST", "PUT"], + "methods": [ + "POST", + "PUT" + ], "enable_websocket": false } ] @@ -171,10 +203,14 @@ "resourceId": "801b75f6eb1432c889cd15d3cffb2fa28b7bf95c", "resourceName": "route1.1", "newValue": { - "uris": ["/anything"], + "uris": [ + "/anything" + ], "name": "route1.1", "description": "", - "methods": ["GET"], + "methods": [ + "GET" + ], "enable_websocket": false, "plugins": { "limit-count": { @@ -200,10 +236,14 @@ "resourceId": "9764db8eeb0f13c2a9762161c418504d74ac64a2", "resourceName": "route1.2", "newValue": { - "uris": ["/anything"], + "uris": [ + "/anything" + ], "name": "route1.2", "description": "", - "methods": ["POST"], + "methods": [ + "POST" + ], "enable_websocket": false }, "parentId": "6e899c1108b88e75d4887b85f9a62c26d9571739" @@ -214,10 +254,15 @@ "resourceId": "143e485dfbcace6afb3d40cd26a20cb6f3d8a469", "resourceName": "route2.1", "newValue": { - "uris": ["/getSomething"], + "uris": [ + "/getSomething" + ], "name": "route2.1", "description": "", - "methods": ["GET", "POST"], + "methods": [ + "GET", + "POST" + ], "enable_websocket": false, "plugins": { "limit-count": { @@ -243,30 +288,19 @@ "resourceId": "12e10811f0bf2d39998936bf81e33314ad7ff6ae", "resourceName": "route2.2", "newValue": { - "uris": ["/postSomething"], + "uris": [ + "/postSomething" + ], "name": "route2.2", "description": "", - "methods": ["POST", "PUT"], + "methods": [ + "POST", + "PUT" + ], "enable_websocket": false }, "parentId": "45d48919804fadc2db9d0180a65fe0ee0a8ddf9a" }, - { - "resourceType": "consumer", - "type": "create", - "resourceId": "tom", - "resourceName": "tom", - "newValue": { - "username": "tom", - "description": "", - "plugins": { - "limit-count": { - "window": 1, - "count": 1 - } - } - } - }, { "resourceType": "global_rule", "type": "create", diff --git a/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts b/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts index d48950e..f2cb744 100644 --- a/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts +++ b/libs/backend-api7/e2e/sync-and-dump-2.e2e-spec.ts @@ -174,16 +174,6 @@ describe('Sync and Dump - 2', () => { }, }); - expect(dump.consumers[0]).toMatchObject({ - username: 'tom', - plugins: { - 'limit-count': { - window: 1, - count: 1, - }, - }, - }); - expect(dump.global_rules.prometheus).toMatchObject({ prefer_name: false, }); From 2ada8c05f1e21fce2e2ce742909ebdbf9b9e6616 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 01:20:17 +0800 Subject: [PATCH 19/26] fix --- .../e2e/label-selector.e2e-spec.ts | 190 +++++++++++++----- .../e2e/resources/consumer.e2e-spec.ts | 4 +- 2 files changed, 145 insertions(+), 49 deletions(-) diff --git a/libs/backend-api7/e2e/label-selector.e2e-spec.ts b/libs/backend-api7/e2e/label-selector.e2e-spec.ts index e875ca0..dca03ad 100644 --- a/libs/backend-api7/e2e/label-selector.e2e-spec.ts +++ b/libs/backend-api7/e2e/label-selector.e2e-spec.ts @@ -1,13 +1,16 @@ import * as ADCSDK from '@api7/adc-sdk'; -import { unset } from 'lodash'; +import { create, unset } from 'lodash'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; +import { gte, lt } from 'semver'; import { BackendAPI7 } from '../src'; import { + conditionalDescribe, createEvent, deleteEvent, dumpConfiguration, + semverCondition, syncEvents, } from './support/utils'; @@ -24,60 +27,153 @@ describe('Label Selector', () => { backend = new BackendAPI7(commonBackendOpts); }); - describe('Consumer', () => { - const consumer1Name = 'consumer1'; - const consumer1 = { - username: consumer1Name, - labels: { team: '1' }, - plugins: { - 'key-auth': { - key: consumer1Name, + conditionalDescribe(semverCondition(lt, '3.2.15'))( + 'Consumer (without credential support)', + () => { + const consumer1Name = 'consumer1'; + const consumer1 = { + username: consumer1Name, + labels: { team: '1' }, + plugins: { + 'key-auth': { + key: consumer1Name, + }, }, - }, - } as ADCSDK.Consumer; - const consumer2Name = 'consumer2'; - const consumer2 = { - username: consumer2Name, - labels: { team: '2' }, - plugins: { - 'key-auth': { - key: consumer2Name, + } as ADCSDK.Consumer; + const consumer2Name = 'consumer2'; + const consumer2 = { + username: consumer2Name, + labels: { team: '2' }, + plugins: { + 'key-auth': { + key: consumer2Name, + }, }, - }, - } as ADCSDK.Consumer; + } as ADCSDK.Consumer; - it('Create consumers', async () => - syncEvents(backend, [ - createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), - createEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name, consumer2), - ])); + it('Create consumers', async () => + syncEvents(backend, [ + createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), + createEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name, consumer2), + ])); - it('Dump consumer whit label team = 1', async () => { - const backend = new BackendAPI7({ - ...commonBackendOpts, - labelSelector: { team: '1' }, // add custom label selector + it('Dump consumer whit label team = 1', async () => { + const backend = new BackendAPI7({ + ...commonBackendOpts, + labelSelector: { team: '1' }, // add custom label selector + }); + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer1); }); - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(1); - expect(result.consumers[0]).toMatchObject(consumer1); - }); - it('Dump consumer whit label team = 2', async () => { - const backend = new BackendAPI7({ - ...commonBackendOpts, - labelSelector: { team: '2' }, // add custom label selector + it('Dump consumer whit label team = 2', async () => { + const backend = new BackendAPI7({ + ...commonBackendOpts, + labelSelector: { team: '2' }, // add custom label selector + }); + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer2); }); - const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; - expect(result.consumers).toHaveLength(1); - expect(result.consumers[0]).toMatchObject(consumer2); - }); - it('Delete consumers', async () => - syncEvents(backend, [ - deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), - deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name), - ])); - }); + it('Delete consumers', async () => + syncEvents(backend, [ + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name), + ])); + }, + ); + + conditionalDescribe(semverCondition(gte, '3.2.15'))( + 'Consumer (with credential support)', + () => { + const credential1 = { + name: 'key-1', + labels: { team: '1' }, + type: 'key-auth', + config: { + key: 'key-1', + }, + }; + const credential2 = { + name: 'key-2', + labels: { team: '2' }, + type: 'key-auth', + config: { + key: 'key-2', + }, + }; + const consumer1Name = 'consumer1'; + const consumer1 = { + username: consumer1Name, + labels: { team: '1' }, + } as ADCSDK.Consumer; + const consumer2Name = 'consumer2'; + const consumer2 = { + username: consumer2Name, + labels: { team: '2' }, + } as ADCSDK.Consumer; + + it('Create consumers', async () => + syncEvents(backend, [ + createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1), + createEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name, consumer2), + createEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + credential1.name, + credential1, + consumer1Name, + ), + createEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + credential2.name, + credential2, + consumer2Name, + ), + ])); + + it('Dump consumer whit label team = 1', async () => { + const backend = new BackendAPI7({ + ...commonBackendOpts, + labelSelector: { team: '1' }, // add custom label selector + }); + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer1); + expect(result.consumers[0].credentials).toHaveLength(2); + }); + + it('Dump consumer whit label team = 2', async () => { + const backend = new BackendAPI7({ + ...commonBackendOpts, + labelSelector: { team: '2' }, // add custom label selector + }); + const result = (await dumpConfiguration( + backend, + )) as ADCSDK.Configuration; + expect(result.consumers).toHaveLength(1); + expect(result.consumers[0]).toMatchObject(consumer2); + }); + + it('Delete consumers', async () => + syncEvents(backend, [ + deleteEvent( + ADCSDK.ResourceType.CONSUMER_CREDENTIAL, + credential1.name, + consumer1Name, + ), + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name), + deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name), + ])); + }, + ); describe('SSL', () => { const certificates = [ diff --git a/libs/backend-api7/e2e/resources/consumer.e2e-spec.ts b/libs/backend-api7/e2e/resources/consumer.e2e-spec.ts index 28b9a38..d9c5d18 100644 --- a/libs/backend-api7/e2e/resources/consumer.e2e-spec.ts +++ b/libs/backend-api7/e2e/resources/consumer.e2e-spec.ts @@ -25,7 +25,7 @@ describe('Consumer E2E', () => { }); conditionalDescribe(semverCondition(lt, '3.2.15'))( - 'Sync and dump consumers (without credentials support)', + 'Sync and dump consumers (without credential support)', () => { const consumer1Name = 'consumer1'; const consumer1 = { @@ -103,7 +103,7 @@ describe('Consumer E2E', () => { ); conditionalDescribe(semverCondition(gte, '3.2.15'))( - 'Sync and dump consumers (with credentials support)', + 'Sync and dump consumers (with credential support)', () => { const consumer1Name = 'consumer1'; const consumer1Key = 'consumer1-key'; From eef638b0c41df18a4796d7ff0f60c574433787c0 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 01:30:21 +0800 Subject: [PATCH 20/26] fix --- libs/backend-api7/e2e/label-selector.e2e-spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/backend-api7/e2e/label-selector.e2e-spec.ts b/libs/backend-api7/e2e/label-selector.e2e-spec.ts index dca03ad..80b1bf7 100644 --- a/libs/backend-api7/e2e/label-selector.e2e-spec.ts +++ b/libs/backend-api7/e2e/label-selector.e2e-spec.ts @@ -2,7 +2,7 @@ import * as ADCSDK from '@api7/adc-sdk'; import { create, unset } from 'lodash'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; -import { gte, lt } from 'semver'; +import { gte, lt, lte } from 'semver'; import { BackendAPI7 } from '../src'; import { @@ -27,7 +27,7 @@ describe('Label Selector', () => { backend = new BackendAPI7(commonBackendOpts); }); - conditionalDescribe(semverCondition(lt, '3.2.15'))( + conditionalDescribe(!semverCondition(lte, '3.2.15'))( 'Consumer (without credential support)', () => { const consumer1Name = 'consumer1'; From 0a8442bc1d36b2743562d8c653ff5e66de403bff Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 01:36:00 +0800 Subject: [PATCH 21/26] fix: ver logic --- libs/backend-api7/e2e/label-selector.e2e-spec.ts | 2 +- libs/backend-api7/e2e/support/utils.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/backend-api7/e2e/label-selector.e2e-spec.ts b/libs/backend-api7/e2e/label-selector.e2e-spec.ts index 80b1bf7..dd7b94f 100644 --- a/libs/backend-api7/e2e/label-selector.e2e-spec.ts +++ b/libs/backend-api7/e2e/label-selector.e2e-spec.ts @@ -27,7 +27,7 @@ describe('Label Selector', () => { backend = new BackendAPI7(commonBackendOpts); }); - conditionalDescribe(!semverCondition(lte, '3.2.15'))( + conditionalDescribe(semverCondition(lt, '3.2.15'))( 'Consumer (without credential support)', () => { const consumer1Name = 'consumer1'; diff --git a/libs/backend-api7/e2e/support/utils.ts b/libs/backend-api7/e2e/support/utils.ts index 2dd5483..ba93929 100644 --- a/libs/backend-api7/e2e/support/utils.ts +++ b/libs/backend-api7/e2e/support/utils.ts @@ -102,7 +102,7 @@ export const conditionalDescribe = (cond: cond) => export const conditionalIt = (cond: cond) => (cond ? it : it.skip); export const semverCondition = ( - op: (v1: string, v2: string | semver.SemVer) => boolean, - target: string, - base = semver.coerce(process.env.BACKEND_API7_VERSION) ?? '0.0.0', + op: (v1: string | semver.SemVer, v2: string | semver.SemVer) => boolean, + base: string, + target = semver.coerce(process.env.BACKEND_API7_VERSION) ?? '0.0.0', ) => op(target, base); From b161198a28456549240eea4820e92a0377cb0fe8 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 01:40:40 +0800 Subject: [PATCH 22/26] fix --- libs/backend-api7/e2e/label-selector.e2e-spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/backend-api7/e2e/label-selector.e2e-spec.ts b/libs/backend-api7/e2e/label-selector.e2e-spec.ts index dd7b94f..d676ac6 100644 --- a/libs/backend-api7/e2e/label-selector.e2e-spec.ts +++ b/libs/backend-api7/e2e/label-selector.e2e-spec.ts @@ -112,6 +112,7 @@ describe('Label Selector', () => { const consumer1 = { username: consumer1Name, labels: { team: '1' }, + credentials: [credential1, credential2], } as ADCSDK.Consumer; const consumer2Name = 'consumer2'; const consumer2 = { From fac44744d4c3d25468f5d22179f8bf9ef107cf9a Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 01:46:53 +0800 Subject: [PATCH 23/26] fix --- libs/backend-api7/e2e/label-selector.e2e-spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/backend-api7/e2e/label-selector.e2e-spec.ts b/libs/backend-api7/e2e/label-selector.e2e-spec.ts index d676ac6..99b5047 100644 --- a/libs/backend-api7/e2e/label-selector.e2e-spec.ts +++ b/libs/backend-api7/e2e/label-selector.e2e-spec.ts @@ -134,7 +134,7 @@ describe('Label Selector', () => { ADCSDK.ResourceType.CONSUMER_CREDENTIAL, credential2.name, credential2, - consumer2Name, + consumer1Name, ), ])); From 53d5b2018a651bbcd8a7cdb3c8dec281cd3e86ae Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 02:07:02 +0800 Subject: [PATCH 24/26] fix --- libs/backend-api7/e2e/label-selector.e2e-spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/backend-api7/e2e/label-selector.e2e-spec.ts b/libs/backend-api7/e2e/label-selector.e2e-spec.ts index 99b5047..1096bb7 100644 --- a/libs/backend-api7/e2e/label-selector.e2e-spec.ts +++ b/libs/backend-api7/e2e/label-selector.e2e-spec.ts @@ -112,7 +112,6 @@ describe('Label Selector', () => { const consumer1 = { username: consumer1Name, labels: { team: '1' }, - credentials: [credential1, credential2], } as ADCSDK.Consumer; const consumer2Name = 'consumer2'; const consumer2 = { From c53c6bf2da7c10d017645c092ae07b0d389ad31d Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 02:09:54 +0800 Subject: [PATCH 25/26] fix --- libs/backend-api7/e2e/support/utils.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/backend-api7/e2e/support/utils.ts b/libs/backend-api7/e2e/support/utils.ts index ba93929..5a264a0 100644 --- a/libs/backend-api7/e2e/support/utils.ts +++ b/libs/backend-api7/e2e/support/utils.ts @@ -61,7 +61,11 @@ export const createEvent = ( parentName ? `${parentName}.${resourceName}` : resourceName, ), newValue: resource, - parentId: parentName ? ADCSDK.utils.generateId(parentName) : undefined, + parentId: parentName + ? resourceType === ADCSDK.ResourceType.CONSUMER_CREDENTIAL + ? parentName + : ADCSDK.utils.generateId(parentName) + : undefined, }); export const updateEvent = ( From 621e1cce9d783f06eccb436ec26d3e0c3ae3db2c Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Mon, 16 Sep 2024 02:32:41 +0800 Subject: [PATCH 26/26] fix: typo --- libs/backend-api7/e2e/label-selector.e2e-spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/backend-api7/e2e/label-selector.e2e-spec.ts b/libs/backend-api7/e2e/label-selector.e2e-spec.ts index 1096bb7..e52d514 100644 --- a/libs/backend-api7/e2e/label-selector.e2e-spec.ts +++ b/libs/backend-api7/e2e/label-selector.e2e-spec.ts @@ -57,7 +57,7 @@ describe('Label Selector', () => { createEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name, consumer2), ])); - it('Dump consumer whit label team = 1', async () => { + it('Dump consumer with label team = 1', async () => { const backend = new BackendAPI7({ ...commonBackendOpts, labelSelector: { team: '1' }, // add custom label selector @@ -69,7 +69,7 @@ describe('Label Selector', () => { expect(result.consumers[0]).toMatchObject(consumer1); }); - it('Dump consumer whit label team = 2', async () => { + it('Dump consumer with label team = 2', async () => { const backend = new BackendAPI7({ ...commonBackendOpts, labelSelector: { team: '2' }, // add custom label selector @@ -137,7 +137,7 @@ describe('Label Selector', () => { ), ])); - it('Dump consumer whit label team = 1', async () => { + it('Dump consumer with label team = 1', async () => { const backend = new BackendAPI7({ ...commonBackendOpts, labelSelector: { team: '1' }, // add custom label selector @@ -150,7 +150,7 @@ describe('Label Selector', () => { expect(result.consumers[0].credentials).toHaveLength(2); }); - it('Dump consumer whit label team = 2', async () => { + it('Dump consumer with label team = 2', async () => { const backend = new BackendAPI7({ ...commonBackendOpts, labelSelector: { team: '2' }, // add custom label selector @@ -219,7 +219,7 @@ describe('Label Selector', () => { createEvent(ADCSDK.ResourceType.SSL, sslName(ssl2SNIs), ssl2), ])); - it('Dump consumer whit label team = 1', async () => { + it('Dump consumer with label team = 1', async () => { const backend = new BackendAPI7({ ...commonBackendOpts, labelSelector: { team: '1' }, // add custom label selector @@ -229,7 +229,7 @@ describe('Label Selector', () => { expect(result.ssls[0]).toMatchObject(ssl1test); }); - it('Dump consumer whit label team = 2', async () => { + it('Dump consumer with label team = 2', async () => { const backend = new BackendAPI7({ ...commonBackendOpts, labelSelector: { team: '2' }, // add custom label selector