Skip to content

Commit 9674289

Browse files
authored
feat(api7): support API-level label selector (#150)
1 parent d678c65 commit 9674289

File tree

4 files changed

+180
-14
lines changed

4 files changed

+180
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import * as ADCSDK from '@api7/adc-sdk';
2+
import { unset } from 'lodash';
3+
import { readFileSync } from 'node:fs';
4+
import { join } from 'node:path';
5+
6+
import { BackendAPI7 } from '../src';
7+
import {
8+
createEvent,
9+
deleteEvent,
10+
dumpConfiguration,
11+
syncEvents,
12+
} from './support/utils';
13+
14+
describe('Label Selector', () => {
15+
const commonBackendOpts = {
16+
server: process.env.SERVER,
17+
token: process.env.TOKEN,
18+
tlsSkipVerify: true,
19+
gatewayGroup: 'default',
20+
};
21+
let backend: BackendAPI7;
22+
23+
beforeAll(() => {
24+
backend = new BackendAPI7(commonBackendOpts);
25+
});
26+
27+
describe('Consumer', () => {
28+
const consumer1Name = 'consumer1';
29+
const consumer1 = {
30+
username: consumer1Name,
31+
labels: { team: '1' },
32+
plugins: {
33+
'key-auth': {
34+
key: consumer1Name,
35+
},
36+
},
37+
} as ADCSDK.Consumer;
38+
const consumer2Name = 'consumer2';
39+
const consumer2 = {
40+
username: consumer2Name,
41+
labels: { team: '2' },
42+
plugins: {
43+
'key-auth': {
44+
key: consumer2Name,
45+
},
46+
},
47+
} as ADCSDK.Consumer;
48+
49+
it('Create consumers', async () =>
50+
syncEvents(backend, [
51+
createEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name, consumer1),
52+
createEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name, consumer2),
53+
]));
54+
55+
it('Dump consumer whit label team = 1', async () => {
56+
const backend = new BackendAPI7({
57+
...commonBackendOpts,
58+
labelSelector: { team: '1' }, // add custom label selector
59+
});
60+
const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration;
61+
expect(result.consumers).toHaveLength(1);
62+
expect(result.consumers[0]).toMatchObject(consumer1);
63+
});
64+
65+
it('Dump consumer whit label team = 2', async () => {
66+
const backend = new BackendAPI7({
67+
...commonBackendOpts,
68+
labelSelector: { team: '2' }, // add custom label selector
69+
});
70+
const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration;
71+
expect(result.consumers).toHaveLength(1);
72+
expect(result.consumers[0]).toMatchObject(consumer2);
73+
});
74+
75+
it('Delete consumers', async () =>
76+
syncEvents(backend, [
77+
deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer1Name),
78+
deleteEvent(ADCSDK.ResourceType.CONSUMER, consumer2Name),
79+
]));
80+
});
81+
82+
describe('SSL', () => {
83+
const certificates = [
84+
{
85+
certificate: readFileSync(
86+
join(__dirname, 'assets/certs/test-ssl1.cer'),
87+
).toString('utf-8'),
88+
key: readFileSync(
89+
join(__dirname, 'assets/certs/test-ssl1.key'),
90+
).toString('utf-8'),
91+
},
92+
{
93+
certificate: readFileSync(
94+
join(__dirname, 'assets/certs/test-ssl2.cer'),
95+
).toString('utf-8'),
96+
key: readFileSync(
97+
join(__dirname, 'assets/certs/test-ssl2.key'),
98+
).toString('utf-8'),
99+
},
100+
];
101+
const ssl1SNIs = ['ssl1-1.com', 'ssl1-2.com'];
102+
const ssl1 = {
103+
snis: ssl1SNIs,
104+
labels: { team: '1' },
105+
certificates: [certificates[0]],
106+
} as ADCSDK.SSL;
107+
const ssl2SNIs = ['ssl2-1.com', 'ssl2-2.com'];
108+
const ssl2 = {
109+
snis: ssl2SNIs,
110+
labels: { team: '2' },
111+
certificates: [certificates[1]],
112+
} as ADCSDK.SSL;
113+
const sslName = (snis: Array<string>) => snis.join(',');
114+
115+
const ssl1test = structuredClone(ssl1);
116+
const ssl2test = structuredClone(ssl2);
117+
unset(ssl1test, 'certificates.0.key');
118+
unset(ssl2test, 'certificates.0.key');
119+
120+
it('Create ssls', async () =>
121+
syncEvents(backend, [
122+
createEvent(ADCSDK.ResourceType.SSL, sslName(ssl1SNIs), ssl1),
123+
createEvent(ADCSDK.ResourceType.SSL, sslName(ssl2SNIs), ssl2),
124+
]));
125+
126+
it('Dump consumer whit label team = 1', async () => {
127+
const backend = new BackendAPI7({
128+
...commonBackendOpts,
129+
labelSelector: { team: '1' }, // add custom label selector
130+
});
131+
const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration;
132+
expect(result.ssls).toHaveLength(1);
133+
expect(result.ssls[0]).toMatchObject(ssl1test);
134+
});
135+
136+
it('Dump consumer whit label team = 2', async () => {
137+
const backend = new BackendAPI7({
138+
...commonBackendOpts,
139+
labelSelector: { team: '2' }, // add custom label selector
140+
});
141+
const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration;
142+
expect(result.ssls).toHaveLength(1);
143+
expect(result.ssls[0]).toMatchObject(ssl2test);
144+
});
145+
146+
it('Delete ssls', async () =>
147+
syncEvents(backend, [
148+
deleteEvent(ADCSDK.ResourceType.SSL, sslName(ssl1SNIs)),
149+
deleteEvent(ADCSDK.ResourceType.SSL, sslName(ssl2SNIs)),
150+
]));
151+
});
152+
});

libs/backend-api7/src/fetcher.ts

+24-10
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ export class Fetcher {
7272
const resp = await this.client.get<{ list: Array<typing.Consumer> }>(
7373
'/apisix/admin/consumers',
7474
{
75-
params: { gateway_group_id: ctx.gatewayGroupId },
75+
params: this.attachLabelSelector({
76+
gateway_group_id: ctx.gatewayGroupId,
77+
}),
7678
},
7779
);
7880
task.output = buildReqAndRespDebugOutput(resp, 'Get consumers');
@@ -92,7 +94,9 @@ export class Fetcher {
9294
const resp = await this.client.get<{ list: Array<typing.SSL> }>(
9395
'/apisix/admin/ssls',
9496
{
95-
params: { gateway_group_id: ctx.gatewayGroupId },
97+
params: this.attachLabelSelector({
98+
gateway_group_id: ctx.gatewayGroupId,
99+
}),
96100
},
97101
);
98102
task.output = buildReqAndRespDebugOutput(resp, 'Get ssls');
@@ -169,6 +173,16 @@ export class Fetcher {
169173
};
170174
}
171175

176+
public allTask() {
177+
return [
178+
this.listServices(),
179+
this.listConsumers(),
180+
this.listSSLs(),
181+
this.listGlobalRules(),
182+
this.listMetadatas(),
183+
];
184+
}
185+
172186
private isSkip(
173187
requiredTypes: Array<ADCSDK.ResourceType>,
174188
): () => string | undefined {
@@ -194,13 +208,13 @@ export class Fetcher {
194208
};
195209
}
196210

197-
public allTask() {
198-
return [
199-
this.listServices(),
200-
this.listConsumers(),
201-
this.listSSLs(),
202-
this.listGlobalRules(),
203-
this.listMetadatas(),
204-
];
211+
private attachLabelSelector(
212+
params: Record<string, string>,
213+
): Record<string, string> {
214+
if (this.backendOpts?.labelSelector)
215+
Object.entries(this.backendOpts.labelSelector).forEach(([key, value]) => {
216+
params[`labels[${key}]`] = value;
217+
});
218+
return params;
205219
}
206220
}

libs/backend-api7/src/utils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AxiosResponse } from 'axios';
1+
import axios, { AxiosResponse } from 'axios';
22

33
export const capitalizeFirstLetter = (str: string) =>
44
str.charAt(0).toUpperCase() + str.slice(1);
@@ -24,7 +24,7 @@ export const buildReqAndRespDebugOutput = (
2424
messages: [
2525
`${desc ?? ''}\n`, //TODO time consumption
2626
// request
27-
`${config.method.toUpperCase()} ${config.url}\n`,
27+
`${config.method.toUpperCase()} ${axios.getUri(config)}\n`,
2828
...transformHeaders(config.headers),
2929
config?.data ? `\n${config.data}\n` : '',
3030
'\n',

libs/backend-apisix/src/utils.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as ADCSDK from '@api7/adc-sdk';
2-
import { AxiosResponse } from 'axios';
2+
import axios, { AxiosResponse } from 'axios';
33

44
export const resourceTypeToAPIName = (resourceType: ADCSDK.ResourceType) =>
55
resourceType !== ADCSDK.ResourceType.PLUGIN_METADATA
@@ -30,7 +30,7 @@ export const buildReqAndRespDebugOutput = (
3030
messages: [
3131
`${desc ?? ''}\n`, //TODO time consumption
3232
// request
33-
`${config.method.toUpperCase()} ${config.url}\n`,
33+
`${config.method.toUpperCase()} ${axios.getUri(config)}\n`,
3434
...transformHeaders(config.headers),
3535
config?.data ? `\n${config.data}\n` : '',
3636
'\n',

0 commit comments

Comments
 (0)