Skip to content

Commit 131a8e0

Browse files
feat: Added changes to support workspace with konnect flow
1 parent ef04ee6 commit 131a8e0

File tree

9 files changed

+208
-78
lines changed

9 files changed

+208
-78
lines changed

cmd/common.go

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ func getMode(targetContent *file.Content) mode {
5656
return modeKong
5757
}
5858

59-
// workspaceExists checks if workspace exists in Kong.
60-
func workspaceExists(ctx context.Context, config reconcilerUtils.KongClientConfig, workspaceName string) (bool, error) {
59+
// workspaceExists checks if workspace exists in Kong or Konnect
60+
func workspaceExists(ctx context.Context, config reconcilerUtils.KongClientConfig, workspaceName string,
61+
isKonnectMode bool) (bool, error) {
6162
rootConfig := config.ForWorkspace("")
6263
if workspaceName == "" {
6364
// default workspace always exists
@@ -69,6 +70,18 @@ func workspaceExists(ctx context.Context, config reconcilerUtils.KongClientConfi
6970
return true, nil
7071
}
7172

73+
if isKonnectMode {
74+
konnectClient, err := GetKongClientForKonnectMode(ctx, &konnectConfig)
75+
if err != nil {
76+
return false, fmt.Errorf("creating Konnect client: %w", err)
77+
}
78+
exists, err := konnectClient.KonnectWorkspaces.ExistsByName(ctx, &workspaceName)
79+
if err != nil {
80+
return false, fmt.Errorf("checking Konnect workspace exists: %w", err)
81+
}
82+
return exists, nil
83+
}
84+
// For Kong Gateway mode
7285
rootClient, err := reconcilerUtils.GetKongClient(rootConfig)
7386
if err != nil {
7487
return false, err
@@ -190,21 +203,15 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
190203

191204
var kongClient *kong.Client
192205
mode := getMode(targetContent)
206+
isKonnect := false
207+
workspaceName := getWorkspaceName(workspace, targetContent, enableJSONOutput)
208+
193209
if mode == modeKonnect {
210+
isKonnect = true
194211
// Konnect ConsumerGroup APIs don't support the query-parameter list_consumers yet
195212
if dumpConfig.SkipConsumersWithConsumerGroups {
196213
return errors.New("the flag --skip-consumers-with-consumer-groups can not be used with Konnect")
197214
}
198-
199-
if targetContent.Workspace != "" {
200-
return fmt.Errorf("_workspace set in config file.\n"+
201-
"Workspaces are not supported in Konnect. "+
202-
"Please remove '_workspace: %s' from your "+
203-
"configuration and try again", targetContent.Workspace)
204-
}
205-
if workspace != "" {
206-
return fmt.Errorf("--workspace flag is not supported when running against Konnect")
207-
}
208215
if targetContent.Konnect != nil {
209216
if err := evaluateTargetRuntimeGroupOrControlPlaneName(targetContent); err != nil {
210217
return err
@@ -214,6 +221,9 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
214221
konnectControlPlane = konnectRuntimeGroup
215222
}
216223
konnectConfig.TLSConfig = rootConfig.TLSConfig
224+
if workspaceName != "" {
225+
konnectConfig.WorkspaceName = workspaceName
226+
}
217227
kongClient, err = GetKongClientForKonnectMode(ctx, &konnectConfig)
218228
if err != nil {
219229
return err
@@ -232,15 +242,14 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
232242

233243
// prepare to read the current state from Kong
234244
var wsConfig reconcilerUtils.KongClientConfig
235-
workspaceName := getWorkspaceName(workspace, targetContent, enableJSONOutput)
236-
wsConfig = rootConfig.ForWorkspace(workspaceName)
237245

238246
// load Kong version after workspace
239247
var kongVersion string
240248
var parsedKongVersion semver.Version
241249
if mode == modeKonnect {
242250
kongVersion = fetchKonnectKongVersion()
243251
} else {
252+
wsConfig = rootConfig.ForWorkspace(workspaceName)
244253
kongVersion, err = fetchKongVersion(ctx, wsConfig)
245254
if err != nil {
246255
return fmt.Errorf("reading Kong version: %w", err)
@@ -267,7 +276,7 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
267276
// workspace name and kong client to be present on that level.
268277
_ = sendAnalytics(cmd, kongVersion, mode)
269278

270-
workspaceExists, err := workspaceExists(ctx, rootConfig, workspaceName)
279+
workspaceExists, err := workspaceExists(ctx, rootConfig, workspaceName, isKonnect)
271280
if err != nil {
272281
return err
273282
}
@@ -404,9 +413,16 @@ func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
404413
cprint.CreatePrintln("Creating workspace", wsConfig.Workspace)
405414
}
406415
if !dry {
407-
_, err = rootClient.Workspaces.Create(ctx, &kong.Workspace{Name: &wsConfig.Workspace})
408-
if err != nil {
409-
return err
416+
if mode == modeKonnect {
417+
_, err := kongClient.KonnectWorkspaces.Create(ctx, &kong.Workspace{Name: &konnectConfig.WorkspaceName})
418+
if err != nil {
419+
return err
420+
}
421+
} else {
422+
_, err = rootClient.Workspaces.Create(ctx, &kong.Workspace{Name: &wsConfig.Workspace})
423+
if err != nil {
424+
return err
425+
}
410426
}
411427
}
412428
}

cmd/common_konnect.go

Lines changed: 128 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,18 @@ func GetKongClientForKonnectMode(
6363
}
6464

6565
if konnectConfig.Token != "" {
66-
konnectConfig.Headers = append(
67-
konnectConfig.Headers, "Authorization:Bearer "+konnectConfig.Token,
68-
)
66+
found := false
67+
for _, h := range konnectConfig.Headers {
68+
if strings.HasPrefix(h, "Authorization:") {
69+
found = true
70+
break
71+
}
72+
}
73+
if !found {
74+
konnectConfig.Headers = append(
75+
konnectConfig.Headers, "Authorization:Bearer "+konnectConfig.Token,
76+
)
77+
}
6978
}
7079

7180
if konnectConfig.Address == "" {
@@ -101,6 +110,7 @@ func GetKongClientForKonnectMode(
101110
Headers: konnectConfig.Headers,
102111
Retryable: true,
103112
TLSConfig: konnectConfig.TLSConfig,
113+
Workspace: konnectConfig.WorkspaceName,
104114
})
105115
}
106116

@@ -113,22 +123,57 @@ func resetKonnectV2(ctx context.Context) error {
113123
}
114124
dumpConfig.KonnectControlPlane = konnectControlPlane
115125
konnectConfig.TLSConfig = rootConfig.TLSConfig
116-
client, err := GetKongClientForKonnectMode(ctx, &konnectConfig)
117-
if err != nil {
118-
return err
119-
}
120-
currentState, err := fetchCurrentState(ctx, client, dumpConfig)
121-
if err != nil {
122-
return err
123-
}
124-
targetState, err := state.NewKongState()
125-
if err != nil {
126-
return err
127-
}
128-
_, err = performDiff(ctx, currentState, targetState, false, 10, 0, client, true, resetJSONOutput, ApplyTypeFull)
129-
if err != nil {
130-
return err
126+
baseKonnectClient, err := GetKongClientForKonnectMode(ctx, &konnectConfig)
127+
128+
var workspaces []string
129+
if resetAllWorkspaces {
130+
if err != nil {
131+
return fmt.Errorf("getting initial konnect client: %w", err)
132+
}
133+
workspaces, err = listWorkspaces(ctx, baseKonnectClient)
134+
if err != nil {
135+
return fmt.Errorf("listing Konnect workspaces: %w", err)
136+
}
137+
} else if resetWorkspace != "" {
138+
workspaces = append(workspaces, resetWorkspace)
139+
} else {
140+
// No workspace provided: reset global entities only
141+
workspaces = append(workspaces, "")
142+
}
143+
for _, ws := range workspaces {
144+
// Update the config for this specific workspace iteration
145+
exists, err := workspaceExists(ctx, rootConfig, ws, true)
146+
if err != nil {
147+
return err
148+
}
149+
if !exists {
150+
return fmt.Errorf("workspace '%v' does not exist in Konnect", ws)
151+
}
152+
153+
konnectConfig.WorkspaceName = ws
154+
155+
client, err := GetKongClientForKonnectMode(ctx, &konnectConfig)
156+
if err != nil {
157+
return fmt.Errorf("getting client for workspace '%s': %w", ws, err)
158+
}
159+
160+
currentState, err := fetchCurrentState(ctx, client, dumpConfig)
161+
if err != nil {
162+
return fmt.Errorf("fetching state for workspace '%s': %w", ws, err)
163+
}
164+
165+
targetState, err := state.NewKongState()
166+
if err != nil {
167+
return err
168+
}
169+
170+
// Perform the diff/reset
171+
_, err = performDiff(ctx, currentState, targetState, false, 10, 0, client, true, resetJSONOutput, ApplyTypeFull)
172+
if err != nil {
173+
return fmt.Errorf("resetting workspace '%s': %w", ws, err)
174+
}
131175
}
176+
132177
return nil
133178
}
134179

@@ -141,34 +186,86 @@ func dumpKonnectV2(ctx context.Context) error {
141186
}
142187
dumpConfig.KonnectControlPlane = konnectControlPlane
143188
konnectConfig.TLSConfig = rootConfig.TLSConfig
189+
190+
format := file.Format(strings.ToUpper(dumpCmdStateFormat))
191+
writeConfig := file.WriteConfig{
192+
SelectTags: dumpConfig.SelectorTags,
193+
FileFormat: format,
194+
WithID: dumpWithID,
195+
ControlPlaneName: konnectControlPlane,
196+
KongVersion: fetchKonnectKongVersion(),
197+
SanitizeContent: dumpConfig.SanitizeContent,
198+
}
199+
200+
var workspacesList []string
201+
202+
if dumpWorkspace != "" {
203+
workspacesList = append(workspacesList, dumpWorkspace)
204+
}
205+
206+
if dumpAllWorkspaces {
207+
baseClient, err := GetKongClientForKonnectMode(ctx, &konnectConfig)
208+
if err != nil {
209+
return err
210+
}
211+
workspaces, err := listWorkspaces(ctx, baseClient)
212+
if err != nil {
213+
return err
214+
}
215+
workspacesList = append(workspacesList, workspaces...)
216+
}
217+
218+
for _, workspace := range workspacesList {
219+
konnectConfig.WorkspaceName = workspace
220+
exists, err := workspaceExists(ctx, rootConfig, workspace, true)
221+
if err != nil {
222+
return err
223+
}
224+
if !exists {
225+
return fmt.Errorf("workspace '%v' does not exist in Konnect", workspace)
226+
}
227+
wsKonnectClient, err := GetKongClientForKonnectMode(ctx, &konnectConfig)
228+
if err != nil {
229+
return fmt.Errorf("getting client for workspace %s: %w", workspace, err)
230+
}
231+
writeConfig.Workspace = workspace
232+
writeConfig.Filename = workspace
233+
if err := performKonnectDump(ctx, wsKonnectClient, workspace, writeConfig); err != nil {
234+
return err
235+
}
236+
}
237+
238+
// No workspace (default)
239+
// If dumpWorkspace is empty, GetKongClientForKonnectMode builds the CP-level URL
144240
client, err := GetKongClientForKonnectMode(ctx, &konnectConfig)
145241
if err != nil {
146242
return err
147243
}
244+
245+
return performKonnectDump(ctx, client, dumpWorkspace, writeConfig)
246+
}
247+
248+
func performKonnectDump(ctx context.Context, client *kong.Client, wsName string, cfg file.WriteConfig) error {
148249
rawState, err := dump.Get(ctx, client, dumpConfig)
149250
if err != nil {
150-
return fmt.Errorf("reading configuration from Kong: %w", err)
251+
return fmt.Errorf("reading configuration: %w", err)
151252
}
152253
ks, err := state.Get(rawState)
153254
if err != nil {
154255
return fmt.Errorf("building state: %w", err)
155256
}
156257

157-
writeConfig := file.WriteConfig{
158-
SelectTags: dumpConfig.SelectorTags,
159-
Filename: dumpCmdKongStateFile,
160-
FileFormat: file.Format(strings.ToUpper(dumpCmdStateFormat)),
161-
WithID: dumpWithID,
162-
ControlPlaneName: konnectControlPlane,
163-
KongVersion: fetchKonnectKongVersion(),
164-
SanitizeContent: dumpConfig.SanitizeContent,
258+
cfg.Workspace = wsName
259+
if dumpAllWorkspaces {
260+
cfg.Filename = wsName
261+
} else {
262+
cfg.Filename = dumpCmdKongStateFile
165263
}
166264

167-
if dumpConfig.SanitizeContent {
168-
return sanitizeContent(ctx, client, ks, writeConfig, true)
265+
if cfg.SanitizeContent {
266+
return sanitizeContent(ctx, client, ks, cfg, true)
169267
}
170-
171-
return file.KongStateToFile(ks, writeConfig)
268+
return file.KongStateToFile(ks, cfg)
172269
}
173270

174271
func syncKonnect(ctx context.Context,

cmd/gateway_dump.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func listWorkspaces(ctx context.Context, client *kong.Client) ([]string, error)
4343

4444
func getWorkspaceClient(ctx context.Context, workspace string) (*kong.Client, error) {
4545
wsConfig := rootConfig.ForWorkspace(workspace)
46-
exists, err := workspaceExists(ctx, rootConfig, workspace)
46+
exists, err := workspaceExists(ctx, rootConfig, workspace, false)
4747
if err != nil {
4848
return nil, err
4949
}

cmd/gateway_reset.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func executeReset(cmd *cobra.Command, _ []string) error {
7373
}
7474
}
7575
if resetWorkspace != "" {
76-
exists, err := workspaceExists(ctx, rootConfig, resetWorkspace)
76+
exists, err := workspaceExists(ctx, rootConfig, resetWorkspace, false)
7777
if err != nil {
7878
return err
7979
}

cmd/gateway_validate.go

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -335,40 +335,44 @@ func validateWithKong(
335335
func getKongClient(
336336
ctx context.Context, targetContent *file.Content, mode mode,
337337
) (*kong.Client, error) {
338-
workspaceName := validateWorkspace
339-
if validateWorkspace != "" {
340-
if mode == modeKonnect {
341-
return nil, fmt.Errorf("[workspaces] not supported by Konnect - use control planes instead")
342-
}
343-
// check if workspace exists
344-
workspaceName := getWorkspaceName(validateWorkspace, targetContent, false)
345-
workspaceExists, err := workspaceExists(ctx, rootConfig, workspaceName)
346-
if err != nil {
347-
return nil, err
348-
}
349-
if !workspaceExists {
350-
return nil, fmt.Errorf("workspace doesn't exist: %s", workspaceName)
351-
}
352-
}
353-
354338
var (
355339
kongClient *kong.Client
356340
err error
357341
)
358342
if mode == modeKonnect {
343+
dumpConfig.KonnectControlPlane = konnectControlPlane
344+
if validateWorkspace != "" {
345+
konnectWorkspaceName := getWorkspaceName(validateWorkspace, targetContent, false)
346+
if konnectWorkspaceName != "" {
347+
konnectConfig.WorkspaceName = konnectWorkspaceName
348+
}
349+
exists, err := workspaceExists(ctx, rootConfig, konnectConfig.WorkspaceName, true)
350+
if err != nil {
351+
return nil, err
352+
}
353+
if !exists {
354+
return nil, fmt.Errorf("workspace doesn't exist: %s", konnectConfig.WorkspaceName)
355+
}
356+
}
359357
kongClient, err = GetKongClientForKonnectMode(ctx, &konnectConfig)
360358
if err != nil {
361359
return nil, err
362360
}
363-
dumpConfig.KonnectControlPlane = konnectControlPlane
364-
} else {
365-
wsConfig := rootConfig.ForWorkspace(workspaceName)
366-
kongClient, err = reconcilerUtils.GetKongClient(wsConfig)
361+
return kongClient, nil
362+
}
363+
workspaceName := ""
364+
if validateWorkspace != "" {
365+
workspaceName = getWorkspaceName(validateWorkspace, targetContent, false)
366+
exists, err := workspaceExists(ctx, rootConfig, workspaceName, false)
367367
if err != nil {
368368
return nil, err
369369
}
370+
if !exists {
371+
return nil, fmt.Errorf("workspace doesn't exist: %s", workspaceName)
372+
}
370373
}
371-
return kongClient, nil
374+
wsConfig := rootConfig.ForWorkspace(workspaceName)
375+
return reconcilerUtils.GetKongClient(wsConfig)
372376
}
373377

374378
// ensureGetAllMethod ensures at init time that `GetAll()` method exists on the relevant structs.

0 commit comments

Comments
 (0)