Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions libs/backend-apisix-standalone/e2e/cache.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,18 +117,25 @@ describe('Cache - Single APISIX', () => {
id: ADCSDK.utils.generateId('service1'),
modifiedIndex: timestamp,
name: 'service1',
upstream: {
nodes: [
{
host: '127.0.0.1',
port: 9180,
weight: 100,
},
],
},
upstream_id: ADCSDK.utils.generateId('service1'),
},
],
services_conf_version: timestamp,
upstreams: [
{
id: ADCSDK.utils.generateId('service1'),
name: 'service1',
modifiedIndex: timestamp,
nodes: [
{
host: '127.0.0.1',
port: 9180,
weight: 100,
},
],
},
],
upstreams_conf_version: timestamp,
routes: [
{
id: ADCSDK.utils.generateId('service1.route1'),
Expand Down Expand Up @@ -395,9 +402,10 @@ describe('Cache - Multiple APISIX (Partial new instances)', () => {
const rawConfig = rawConfigCache.get(cacheKey);
expect(rawConfig?.services_conf_version).toEqual(200);
expect(rawConfig?.routes_conf_version).toEqual(200);
expect(rawConfig?.upstreams_conf_version).toEqual(200); // inline upstream caused conf version increase

expect(rawConfig?.plugin_metadata_conf_version).toBeLessThan(200);
expect(rawConfig?.global_rules_conf_version).toBeLessThan(200);
expect(rawConfig?.upstreams_conf_version).toBeLessThan(200);
expect(rawConfig?.consumers_conf_version).toBeLessThan(200);
expect(rawConfig?.ssls_conf_version).toBeLessThan(200);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { DifferV3 } from '@api7/adc-differ';
import * as ADCSDK from '@api7/adc-sdk';

import { BackendAPISIXStandalone } from '../../src';
import {
config as configCache,
rawConfig as rawConfigCache,
} from '../../src/cache';
import { server1, token1 } from '../support/constants';
import { dumpConfiguration, restartAPISIX, syncEvents } from '../support/utils';

const cacheKey = 'default';
describe('Service E2E - inline upstream', () => {
let backend: BackendAPISIXStandalone;

beforeAll(async () => {
await restartAPISIX();
backend = new BackendAPISIXStandalone({
server: server1,
token: token1,
cacheKey,
});
});

it('Initialize cache', () =>
expect(dumpConfiguration(backend)).resolves.not.toThrow());

const serviceName = 'test';
it('Create service', async () => {
const events = DifferV3.diff(
{
services: [
{
name: serviceName,
upstream: {
nodes: [
{
host: '127.0.0.1',
port: 9180,
weight: 100,
},
],
},
},
],
},
await dumpConfiguration(backend),
);
return syncEvents(backend, events);
});

it('Check configuration', () => {
expect(rawConfigCache.get(cacheKey)?.upstreams).not.toBeUndefined();
expect(rawConfigCache.get(cacheKey)!.upstreams).toHaveLength(1);
expect(rawConfigCache.get(cacheKey)!.upstreams![0].id).toEqual(
ADCSDK.utils.generateId(serviceName),
);
expect(rawConfigCache.get(cacheKey)!.upstreams![0].name).toEqual(
serviceName,
);

expect(configCache.get(cacheKey)?.services).not.toBeUndefined();
expect(
configCache.get(cacheKey)?.services![0].upstream,
).not.toBeUndefined();
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DifferV3 } from '@api7/adc-differ';
import * as ADCSDK from '@api7/adc-sdk';

import { BackendAPISIXStandalone } from '../../src';
Expand Down Expand Up @@ -51,10 +52,10 @@ describe('Sync and Dump - 1', () => {
expect(dumpConfiguration(backend)).resolves.not.toThrow());

it('Create services', async () =>
syncEvents(backend, [
createEvent(ADCSDK.ResourceType.SERVICE, service1Name, service1),
createEvent(ADCSDK.ResourceType.SERVICE, service2Name, service2),
]));
syncEvents(
backend,
DifferV3.diff({ services: [service1, service2] }, {}),
));

it('Dump', async () => {
const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration;
Expand All @@ -64,10 +65,15 @@ describe('Sync and Dump - 1', () => {
});

it('Update service1', async () => {
service1.description = 'desc';
await syncEvents(backend, [
updateEvent(ADCSDK.ResourceType.SERVICE, service1Name, service1),
]);
const newService = structuredClone(service1);
newService.description = 'desc';
await syncEvents(
backend,
DifferV3.diff(
{ services: [newService, service2] },
await dumpConfiguration(backend),
),
);
});

it('Dump again (service1 updated)', async () => {
Expand Down
2 changes: 1 addition & 1 deletion libs/backend-apisix-standalone/e2e/support/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const conditionalIt = (cond: cond): typeof it =>
export const semverCondition = (
op: (v1: string | semver.SemVer, v2: string | semver.SemVer) => boolean,
base: string,
target = semver.coerce(process.env.BACKEND_APISIX_VERSION) ?? '0.0.0',
target = semver.coerce(process.env.BACKEND_APISIX_VERSION) ?? '999.999.999',
) => op(target, base);

export const restartAPISIX = () =>
Expand Down
2 changes: 1 addition & 1 deletion libs/backend-apisix-standalone/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class BackendAPISIXStandalone implements ADCSDK.Backend {
}

public async ping(): Promise<void> {
await this.client.head(`/apisix/admin/configs`);
await this.client.head(`/apisix/admin`);
}

public async version() {
Expand Down
82 changes: 77 additions & 5 deletions libs/backend-apisix-standalone/src/operator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DifferV3 } from '@api7/adc-differ';
import * as ADCSDK from '@api7/adc-sdk';
import axios, {
type AxiosError,
Expand Down Expand Up @@ -68,19 +69,35 @@ export class Operator extends ADCSDK.backend.BackendEventSource {
? ADCSDK.ResourceType.CONSUMER
: (event.resourceType as typing.UsedResourceTypes);
const resourceKey = typing.APISIXStandaloneKeyMap[resourceType];
const upstreamResourceKey =
typing.APISIXStandaloneKeyMap[ADCSDK.ResourceType.UPSTREAM];

if (event.type === ADCSDK.EventType.CREATE) {
if (!newConfig[resourceKey]) newConfig[resourceKey] = [];
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- infer error
newConfig[resourceKey].push(this.fromADC(event, timestamp) as any);
increaseVersion[resourceType] = true;

// Emit inline upstream
if (event.resourceType === ADCSDK.ResourceType.SERVICE) {
if (!newConfig[upstreamResourceKey])
newConfig[upstreamResourceKey] = [];
newConfig[upstreamResourceKey].push({
...this.fromADCUpstream(
(event.newValue as ADCSDK.Service).upstream!,
),
id: event.resourceId,
modifiedIndex: timestamp,
name: event.resourceName,
});
Comment on lines +84 to +92
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
newConfig[upstreamResourceKey] = [];
newConfig[upstreamResourceKey].push({
...this.fromADCUpstream(
(event.newValue as ADCSDK.Service).upstream!,
),
id: event.resourceId,
modifiedIndex: timestamp,
name: event.resourceName,
});
newConfig[upstreamResourceKey] = [{
...this.fromADCUpstream(
(event.newValue as ADCSDK.Service).upstream!,
),
id: event.resourceId,
modifiedIndex: timestamp,
name: event.resourceName,
}];

If there are no other considerations, this change is more concise.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newConfig is derived from the old configuration as a deep clone, not an empty object. Therefore, the key is not necessarily empty, and it is not feasible to override it directly.

increaseVersion[ADCSDK.ResourceType.UPSTREAM] = true;
}
} else if (
event.type === ADCSDK.EventType.UPDATE ||
event.type === ADCSDK.EventType.DELETE
) {
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion --
* Since this resource should be updated, it must already exist in the old configuration */
const resources = newConfig[resourceKey]!;
if (!newConfig[resourceKey]) newConfig[resourceKey] = [];
const resources = newConfig[resourceKey];
const eventGeneratedId = this.generateIdFromEvent(event);
const index = resources?.findIndex((item) =>
'id' in item ? item.id : item.username === eventGeneratedId,
Expand All @@ -97,6 +114,60 @@ export class Operator extends ADCSDK.backend.BackendEventSource {
}
increaseVersion[resourceType] = true;
}

// Emit inline upstream
if (event.resourceType === ADCSDK.ResourceType.SERVICE) {
if (event.type === ADCSDK.EventType.UPDATE) {
const baseUpstream = {
id: event.resourceId,
name: event.resourceName,
};
const newUpstream = (event.newValue as ADCSDK.Service)?.upstream;
const oldUpstream = (event.oldValue as ADCSDK.Service)?.upstream;
const events = DifferV3.diff(
{
...(newUpstream && {
upstreams: [Object.assign(baseUpstream, newUpstream)],
}),
},
{
...(oldUpstream && {
upstreams: [Object.assign(baseUpstream, oldUpstream)],
}),
},
);
if (events.length > 0) {
if (!newConfig[upstreamResourceKey])
newConfig[upstreamResourceKey] = [];
const resources = newConfig[upstreamResourceKey];
const index = resources?.findIndex(
(item) => item.id === eventGeneratedId,
);
if (!isNil(index) && index != -1) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!isNil(index) && index != -1) {
if (index != -1) {

If findIndex is the only assignment method, then the value of index can only be a number.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The index is calculated by resources?.findIndex. Among ?, it is decided that if resources are undefined, this value may be undefined.

resources[index] = {
...this.fromADCUpstream(
(event.newValue as ADCSDK.Service).upstream!,
),
id: event.resourceId,
modifiedIndex: timestamp,
name: event.resourceName,
};
increaseVersion[ADCSDK.ResourceType.UPSTREAM] = true;
}
}
} else {
if (!newConfig[upstreamResourceKey])
newConfig[upstreamResourceKey] = [];
const resources = newConfig[upstreamResourceKey];
const index = resources?.findIndex(
(item) => item.id === eventGeneratedId,
);
if (!isNil(index) && index != -1) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!isNil(index) && index != -1) {
if (!isNil(index) && index != -1) {

ditto

resources.splice(index, 1);
increaseVersion[ADCSDK.ResourceType.UPSTREAM] = true;
}
}
}
}
}),
// filtering of new consumer configurations to ensure
Expand Down Expand Up @@ -232,14 +303,15 @@ export class Operator extends ADCSDK.backend.BackendEventSource {
}
case ADCSDK.ResourceType.SERVICE: {
const res = event.newValue as ADCSDK.Service;
const id = this.generateIdFromEvent(event);
return {
modifiedIndex,
id: this.generateIdFromEvent(event),
id,
name: res.name,
desc: res.description,
labels: this.fromADCLabels(res.labels),
hosts: res.hosts,
upstream: this.fromADCUpstream(res.upstream!),
upstream_id: id,
plugins: res.plugins,
} satisfies typing.Service as typing.Service;
}
Expand Down
14 changes: 10 additions & 4 deletions libs/backend-apisix-standalone/src/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@ export const toADC = (input: typing.APISIXStandalone) => {
name: service.name,
description: service.desc,
labels: service.labels,
upstream: ADCSDK.utils.recursiveOmitUndefined(
transformUpstream(service.upstream!),
),
...(service.upstream_id && {
upstream: ADCSDK.utils.recursiveOmitUndefined(
transformUpstream(
input.upstreams!.find(
(item) => item.id === service.upstream_id,
)!,
),
),
}),
plugins: service.plugins,
hosts: service.hosts,
routes: input.routes
Expand Down Expand Up @@ -81,7 +87,7 @@ export const toADC = (input: typing.APISIXStandalone) => {
upstreams: input.upstreams
?.filter(
(upstream) =>
upstream.labels![typing.ADC_UPSTREAM_SERVICE_ID_LABEL] ===
upstream.labels?.[typing.ADC_UPSTREAM_SERVICE_ID_LABEL] ===
service.id,
)
.map(transformUpstream)
Expand Down
5 changes: 1 addition & 4 deletions libs/backend-apisix-standalone/src/typing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,7 @@ const ServiceSchema = z.strictObject({
...ModifiedIndex,
...Metadata,
hosts: z.array(z.string()).min(1).optional(),
upstream: UpstreamSchema.extend({
id: Metadata.id.optional(),
name: Metadata.name.optional(),
}).optional(),
upstream_id: z.string().optional(),
plugins: Plugins.optional(),
});
export type Service = z.infer<typeof ServiceSchema>;
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"webpack": "5.98.0"
},
"dependencies": {
"axios": "^1.7.9",
"axios": "^1.11.0",
"chalk": "^4.1.2",
"commander": "^13.1.0",
"deep-diff": "^1.0.2",
Expand All @@ -63,7 +63,6 @@
"lodash": "^4.17.21",
"parse-duration": "^1.1.0",
"pluralize": "^8.0.0",
"reflect-metadata": "^0.1.14",
"rxjs": "^7.8.1",
"semver": "^7.6.3",
"signale": "^1.4.0",
Expand Down
Loading
Loading