From 1baddc1c59e2d5f3d23de808632f4900fbb5c7ec Mon Sep 17 00:00:00 2001 From: Zeping Bai Date: Sat, 20 Jul 2024 14:27:29 +0800 Subject: [PATCH] fix(apisix): store stream route name correctly (#156) --- apps/cli/src/linter/schema.ts | 16 +++-- .../e2e/assets/apisix_conf/http.yaml | 5 ++ .../e2e/sync-and-dump-1.e2e-spec.ts | 63 +++++++++++++++++++ libs/backend-apisix/src/transformer.ts | 31 +++++++-- libs/backend-apisix/src/typing.ts | 2 +- schema.json | 6 +- 6 files changed, 108 insertions(+), 15 deletions(-) diff --git a/apps/cli/src/linter/schema.ts b/apps/cli/src/linter/schema.ts index ccd9baa2..4c65b1e5 100644 --- a/apps/cli/src/linter/schema.ts +++ b/apps/cli/src/linter/schema.ts @@ -218,12 +218,7 @@ const serviceSchema = z upstream: upstreamSchema.optional(), plugins: pluginsSchema.optional(), - path_prefix: z - .string() - .optional() - .refine((val) => val?.startsWith('/'), { - message: 'Path prefix must start with "/"', - }), + path_prefix: z.string().optional(), strip_path_prefix: z.boolean().optional(), hosts: z.array(z.string()).optional(), @@ -237,6 +232,15 @@ const serviceSchema = z message: 'HTTP routes and Stream routes are mutually exclusive and should not exist in the same service', }, + ) + .refine( + (val) => { + if (!val.path_prefix) return true; + return val.path_prefix.startsWith('/'); + }, + { + message: 'Path prefix must start with "/"', + }, ); const sslSchema = z diff --git a/libs/backend-apisix/e2e/assets/apisix_conf/http.yaml b/libs/backend-apisix/e2e/assets/apisix_conf/http.yaml index 8bc6bcbc..a24370d1 100644 --- a/libs/backend-apisix/e2e/assets/apisix_conf/http.yaml +++ b/libs/backend-apisix/e2e/assets/apisix_conf/http.yaml @@ -5,6 +5,11 @@ apisix: control: ip: "0.0.0.0" port: 9092 + proxy_mode: http&stream + stream_proxy: + tcp: + - addr: 33060 + tls: true deployment: admin: allow_admin: diff --git a/libs/backend-apisix/e2e/sync-and-dump-1.e2e-spec.ts b/libs/backend-apisix/e2e/sync-and-dump-1.e2e-spec.ts index 2e729d5b..9f340a2c 100644 --- a/libs/backend-apisix/e2e/sync-and-dump-1.e2e-spec.ts +++ b/libs/backend-apisix/e2e/sync-and-dump-1.e2e-spec.ts @@ -164,6 +164,69 @@ describe('Sync and Dump - 1', () => { }); }); + describe('Sync and dump service with stream route', () => { + const serviceName = 'test'; + const service = { + name: serviceName, + upstream: { + scheme: 'tcp', + nodes: [ + { + host: '1.1.1.1', + port: 5432, + weight: 100, + }, + ], + }, + } as ADCSDK.Service; + const route1Name = 'postgres'; + const route1 = { + name: route1Name, + server_port: 54320, + } as ADCSDK.StreamRoute; + + it('Create resources', async () => + syncEvents(backend, [ + createEvent(ADCSDK.ResourceType.SERVICE, serviceName, service), + createEvent( + ADCSDK.ResourceType.STREAM_ROUTE, + route1Name, + route1, + serviceName, + ), + ])); + + it('Dump', async () => { + const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; + expect(result.services).toHaveLength(1); + expect(result.services[0]).toMatchObject(service); + expect(result.services[0].stream_routes).toHaveLength(1); + expect(result.services[0].stream_routes[0]).toMatchObject(route1); + }); + + it('Delete stream route', async () => + syncEvents(backend, [ + deleteEvent(ADCSDK.ResourceType.STREAM_ROUTE, route1Name, serviceName), + ])); + + it('Dump again (non-route)', async () => { + const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; + expect(result.services).toHaveLength(1); + expect(result.services[0]).toMatchObject(service); + expect(result.services[0].stream_routes).toBeUndefined(); + }); + + it('Delete service', async () => + syncEvents(backend, [ + deleteEvent(ADCSDK.ResourceType.SERVICE, serviceName), + ])); + + it('Dump again (service should not exist)', async () => { + const result = (await dumpConfiguration(backend)) as ADCSDK.Configuration; + expect(result.services).toHaveLength(0); + }); + }); + describe('Sync and dump consumers', () => { const consumer1Name = 'consumer1'; const consumer1 = { diff --git a/libs/backend-apisix/src/transformer.ts b/libs/backend-apisix/src/transformer.ts index 6b2faa3a..86ab68ad 100644 --- a/libs/backend-apisix/src/transformer.ts +++ b/libs/backend-apisix/src/transformer.ts @@ -1,9 +1,20 @@ import * as ADCSDK from '@api7/adc-sdk'; -import { isEmpty, unset } from 'lodash'; +import { filter, isEmpty, unset } from 'lodash'; import * as typing from './typing'; export class ToADC { + private static transformLabels(labels?: ADCSDK.Labels): ADCSDK.Labels { + if (!labels) return undefined; + const filteredLabels = filter( + labels, + (val, key) => key !== '__ADC_NAME', + ) as unknown as ADCSDK.Labels; + return Object.values(filteredLabels).length > 0 + ? filteredLabels + : undefined; + } + public transformRoute(route: typing.Route): ADCSDK.Route { return ADCSDK.utils.recursiveOmitUndefined({ name: route.name ?? route.id, @@ -120,9 +131,9 @@ export class ToADC { streamRoute: typing.StreamRoute, ): ADCSDK.StreamRoute { return ADCSDK.utils.recursiveOmitUndefined({ - name: streamRoute.name ?? streamRoute.id, + name: streamRoute.labels?.__ADC_NAME ?? streamRoute.id, description: streamRoute.desc, - labels: streamRoute.labels, + labels: ToADC.transformLabels(streamRoute.labels), remote_addr: streamRoute.remote_addr, server_addr: streamRoute.server_addr, @@ -343,10 +354,18 @@ export class FromADC { streamRoute: ADCSDK.StreamRoute, ): typing.StreamRoute { return ADCSDK.utils.recursiveOmitUndefined({ - ...streamRoute, id: undefined, - labels: FromADC.transformLabels(streamRoute.labels), - }); + desc: streamRoute.description, + labels: { + ...FromADC.transformLabels(streamRoute.labels), + __ADC_NAME: streamRoute.name, + }, + plugins: streamRoute.plugins, + remote_addr: streamRoute.remote_addr, + server_addr: streamRoute.server_addr, + server_port: streamRoute.server_port, + sni: streamRoute.sni, + } as typing.StreamRoute); } public transformUpstream(upstream: ADCSDK.Upstream): typing.Upstream { diff --git a/libs/backend-apisix/src/typing.ts b/libs/backend-apisix/src/typing.ts index b9927d75..d75122f4 100644 --- a/libs/backend-apisix/src/typing.ts +++ b/libs/backend-apisix/src/typing.ts @@ -108,7 +108,7 @@ export interface StreamRoute { id: string; desc?: string; labels?: Labels; - name: string; + //name: string; // As of 3.9.1, APISIX does not support name on the stream route remote_addr?: string; server_addr?: string; diff --git a/schema.json b/schema.json index 105a789f..7915f7f2 100644 --- a/schema.json +++ b/schema.json @@ -230,6 +230,9 @@ "additionalProperties": false } }, + "required": [ + "active" + ], "additionalProperties": false }, "nodes": { @@ -538,8 +541,7 @@ } }, "required": [ - "name", - "path_prefix" + "name" ], "additionalProperties": false }