Skip to content

Commit 73128cb

Browse files
committed
Disable APIExport ulrs
1 parent 7814220 commit 73128cb

16 files changed

+336
-196
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: apis.kcp.io/v1alpha1
2+
kind: APIExportEndpointSlice
3+
metadata:
4+
name: shards.core.kcp.io
5+
spec:
6+
export:
7+
name: shards.core.kcp.io
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: apis.kcp.io/v1alpha1
2+
kind: APIExportEndpointSlice
3+
metadata:
4+
name: tenancy.kcp.io
5+
spec:
6+
export:
7+
name: tenancy.kcp.io
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: apis.kcp.io/v1alpha1
2+
kind: APIExportEndpointSlice
3+
metadata:
4+
name: topology.kcp.io
5+
spec:
6+
export:
7+
name: topology.kcp.io

pkg/features/kcp_features.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ const (
4242
// alpha: v0.1
4343
// Enables workspace mounts via frontProxy.
4444
WorkspaceMounts featuregate.Feature = "WorkspaceMounts"
45+
46+
// owner: @mjudeikis
47+
// alpha: v0.1
48+
// Enables Poplaing VirtualWorkspace urls on APIExport. This enables to use Deprecated APIExport VirtualWorkspace urls.
49+
// This is a temporary feature to ease the migration to the new VirtualWorkspace urls.
50+
EnableDeprecatedAPIExportVirtualWorkspacesUrls featuregate.Feature = "EnableDeprecatedAPIExportVirtualWorkspacesUrls"
4551
)
4652

4753
// DefaultFeatureGate exposes the upstream feature gate, but with our gate setting applied.
@@ -112,7 +118,9 @@ var defaultVersionedGenericControlPlaneFeatureGates = map[featuregate.Feature]fe
112118
WorkspaceMounts: {
113119
{Version: version.MustParse("1.28"), Default: false, PreRelease: featuregate.Alpha},
114120
},
115-
121+
EnableDeprecatedAPIExportVirtualWorkspacesUrls: {
122+
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
123+
},
116124
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
117125
// unintentionally on either side:
118126

pkg/reconciler/apis/apiexport/apiexport_controller_test.go

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,14 @@ func TestReconcile(t *testing.T) {
5252

5353
apiBindings []interface{}
5454

55-
wantGenerationFailed bool
56-
wantError bool
57-
wantCreateSecretCalled bool
58-
wantUnsetIdentity bool
59-
wantDefaultSecretRef bool
60-
wantStatusHashSet bool
61-
wantVerifyFailure bool
62-
wantIdentityValid bool
63-
wantVirtualWorkspaceURLsError bool
64-
wantVirtualWorkspaceURLsReady bool
55+
wantGenerationFailed bool
56+
wantError bool
57+
wantCreateSecretCalled bool
58+
wantUnsetIdentity bool
59+
wantDefaultSecretRef bool
60+
wantStatusHashSet bool
61+
wantVerifyFailure bool
62+
wantIdentityValid bool
6563
}{
6664
"create secret when ref is nil and secret doesn't exist": {
6765
secretExists: false,
@@ -122,8 +120,7 @@ func TestReconcile(t *testing.T) {
122120
apiBindings: []interface{}{
123121
"something",
124122
},
125-
listShardsError: errors.New("foo"),
126-
wantVirtualWorkspaceURLsError: true,
123+
listShardsError: errors.New("foo"),
127124
},
128125
"virtualWorkspaceURLs set when APIBindings present": {
129126
secretRefSet: true,
@@ -135,7 +132,6 @@ func TestReconcile(t *testing.T) {
135132
apiBindings: []interface{}{
136133
"something",
137134
},
138-
wantVirtualWorkspaceURLsReady: true,
139135
},
140136
}
141137

@@ -287,21 +283,6 @@ func TestReconcile(t *testing.T) {
287283
if tc.wantIdentityValid {
288284
requireConditionMatches(t, apiExport, conditions.TrueCondition(apisv1alpha2.APIExportIdentityValid))
289285
}
290-
291-
if tc.wantVirtualWorkspaceURLsError {
292-
requireConditionMatches(t, apiExport,
293-
conditions.FalseCondition(
294-
apisv1alpha2.APIExportVirtualWorkspaceURLsReady,
295-
apisv1alpha2.ErrorGeneratingURLsReason,
296-
conditionsv1alpha1.ConditionSeverityError,
297-
"",
298-
),
299-
)
300-
}
301-
302-
if tc.wantVirtualWorkspaceURLsReady {
303-
requireConditionMatches(t, apiExport, conditions.TrueCondition(apisv1alpha2.APIExportVirtualWorkspaceURLsReady))
304-
}
305286
})
306287
}
307288
}

pkg/reconciler/apis/apiexport/apiexport_reconcile.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/kcp-dev/logicalcluster/v3"
3232

3333
virtualworkspacesoptions "github.com/kcp-dev/kcp/cmd/virtual-workspaces/options"
34+
kcpfeatures "github.com/kcp-dev/kcp/pkg/features"
3435
"github.com/kcp-dev/kcp/pkg/logging"
3536
apiexportbuilder "github.com/kcp-dev/kcp/pkg/virtual/apiexport/builder"
3637
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
@@ -111,15 +112,18 @@ func (c *controller) reconcile(ctx context.Context, apiExport *apisv1alpha2.APIE
111112
}
112113
*/
113114

114-
if err := c.updateVirtualWorkspaceURLs(ctx, apiExport); err != nil {
115-
conditions.MarkFalse(
116-
apiExport,
117-
apisv1alpha2.APIExportVirtualWorkspaceURLsReady,
118-
apisv1alpha2.ErrorGeneratingURLsReason,
119-
conditionsv1alpha1.ConditionSeverityError,
120-
"%v",
121-
err,
122-
)
115+
// TODO(mjudeikis): Remove this and move to batteries.
116+
if kcpfeatures.DefaultFeatureGate.Enabled(kcpfeatures.EnableDeprecatedAPIExportVirtualWorkspacesUrls) {
117+
if err := c.updateVirtualWorkspaceURLs(ctx, apiExport); err != nil {
118+
conditions.MarkFalse(
119+
apiExport,
120+
apisv1alpha2.APIExportVirtualWorkspaceURLsReady,
121+
apisv1alpha2.ErrorGeneratingURLsReason,
122+
conditionsv1alpha1.ConditionSeverityError,
123+
"%v",
124+
err,
125+
)
126+
}
123127
}
124128

125129
return nil
@@ -216,11 +220,11 @@ func (c *controller) updateVirtualWorkspaceURLs(ctx context.Context, apiExport *
216220
desiredURLs.Insert(u.String())
217221
}
218222

219-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
223+
//nolint:staticcheck
220224
apiExport.Status.VirtualWorkspaces = nil
221225

222226
for _, u := range sets.List[string](desiredURLs) {
223-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
227+
//nolint:staticcheck
224228
apiExport.Status.VirtualWorkspaces = append(apiExport.Status.VirtualWorkspaces, apisv1alpha2.VirtualWorkspace{
225229
URL: u,
226230
})

test/e2e/apibinding/apibinding_logicalcluster_test.go

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
kcpapiextensionsclientset "github.com/kcp-dev/client-go/apiextensions/client"
3333
kcpdynamic "github.com/kcp-dev/client-go/dynamic"
3434

35+
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
3536
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
3637
corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
3738
"github.com/kcp-dev/kcp/sdk/apis/third_party/conditions/util/conditions"
@@ -90,6 +91,22 @@ func TestAPIBindingLogicalCluster(t *testing.T) {
9091
_, err = kcpClusterClient.Cluster(providerPath).ApisV1alpha2().APIExports().Create(ctx, &apiExport, metav1.CreateOptions{})
9192
require.NoError(t, err, "failed to create api export")
9293

94+
t.Logf("Create an APIExportEndpointSlice for it")
95+
apiExportEndpointSlice := &apisv1alpha1.APIExportEndpointSlice{
96+
ObjectMeta: metav1.ObjectMeta{
97+
Name: exportName,
98+
},
99+
Spec: apisv1alpha1.APIExportEndpointSliceSpec{
100+
APIExport: apisv1alpha1.ExportBindingReference{
101+
Name: exportName,
102+
Path: providerPath.String(),
103+
},
104+
},
105+
}
106+
107+
_, err = kcpClusterClient.Cluster(providerPath).ApisV1alpha1().APIExportEndpointSlices().Create(ctx, apiExportEndpointSlice, metav1.CreateOptions{})
108+
require.NoError(t, err)
109+
93110
t.Logf("validate that the permission claim's conditions true")
94111
kcptestinghelpers.EventuallyCondition(t, func() (conditions.Getter, error) {
95112
return kcpClusterClient.Cluster(providerPath).ApisV1alpha2().APIExports().Get(ctx, exportName, metav1.GetOptions{})
@@ -132,7 +149,7 @@ func TestAPIBindingLogicalCluster(t *testing.T) {
132149
return kcpClusterClient.Cluster(consumerPath).ApisV1alpha2().APIBindings().Get(ctx, exportName, metav1.GetOptions{})
133150
}, kcptestinghelpers.Is(apisv1alpha2.PermissionClaimsValid), "unable to see valid claims")
134151

135-
export, err := kcpClusterClient.Cluster(providerPath).ApisV1alpha2().APIExports().Get(ctx, exportName, metav1.GetOptions{})
152+
exportEndpointSlice, err := kcpClusterClient.Cluster(providerPath).ApisV1alpha1().APIExportEndpointSlices().Get(ctx, exportName, metav1.GetOptions{})
136153
require.NoError(t, err)
137154

138155
rawConfig, err := server.RawConfig()
@@ -143,8 +160,7 @@ func TestAPIBindingLogicalCluster(t *testing.T) {
143160
kcptestinghelpers.Eventually(t, func() (bool, string) {
144161
items := []unstructured.Unstructured{}
145162

146-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
147-
for _, vw := range export.Status.VirtualWorkspaces {
163+
for _, vw := range exportEndpointSlice.Status.APIExportEndpoints {
148164
vwClusterClient, err := kcpdynamic.NewForConfig(apiexportVWConfig(t, rawConfig, vw.URL))
149165
require.NoError(t, err)
150166

@@ -223,6 +239,22 @@ func TestAPIBindingCRDs(t *testing.T) {
223239
_, err = kcpClusterClient.Cluster(providerPath).ApisV1alpha2().APIExports().Create(ctx, &apiExport, metav1.CreateOptions{})
224240
require.NoError(t, err, "failed to create api export")
225241

242+
t.Logf("Create an APIExportEndpointSlice for it")
243+
apiExportEndpointSlice := &apisv1alpha1.APIExportEndpointSlice{
244+
ObjectMeta: metav1.ObjectMeta{
245+
Name: exportName,
246+
},
247+
Spec: apisv1alpha1.APIExportEndpointSliceSpec{
248+
APIExport: apisv1alpha1.ExportBindingReference{
249+
Name: exportName,
250+
Path: providerPath.String(),
251+
},
252+
},
253+
}
254+
255+
_, err = kcpClusterClient.Cluster(providerPath).ApisV1alpha1().APIExportEndpointSlices().Create(ctx, apiExportEndpointSlice, metav1.CreateOptions{})
256+
require.NoError(t, err)
257+
226258
t.Logf("validate that the permission claim's conditions true")
227259
kcptestinghelpers.EventuallyCondition(t, func() (conditions.Getter, error) {
228260
return kcpClusterClient.Cluster(providerPath).ApisV1alpha2().APIExports().Get(ctx, exportName, metav1.GetOptions{})
@@ -265,7 +297,7 @@ func TestAPIBindingCRDs(t *testing.T) {
265297
return kcpClusterClient.Cluster(consumerPath).ApisV1alpha2().APIBindings().Get(ctx, exportName, metav1.GetOptions{})
266298
}, kcptestinghelpers.Is(apisv1alpha2.PermissionClaimsValid), "unable to see valid claims")
267299

268-
export, err := kcpClusterClient.Cluster(providerPath).ApisV1alpha2().APIExports().Get(ctx, exportName, metav1.GetOptions{})
300+
exportEndpointSlice, err := kcpClusterClient.Cluster(providerPath).ApisV1alpha1().APIExportEndpointSlices().Get(ctx, exportName, metav1.GetOptions{})
269301
require.NoError(t, err)
270302

271303
rawConfig, err := server.RawConfig()
@@ -276,8 +308,7 @@ func TestAPIBindingCRDs(t *testing.T) {
276308
kcptestinghelpers.Eventually(t, func() (bool, string) {
277309
items := []unstructured.Unstructured{}
278310

279-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
280-
for _, vw := range export.Status.VirtualWorkspaces {
311+
for _, vw := range exportEndpointSlice.Status.APIExportEndpoints {
281312
vwClusterClient, err := kcpdynamic.NewForConfig(apiexportVWConfig(t, rawConfig, vw.URL))
282313
require.NoError(t, err)
283314

test/e2e/apibinding/apibinding_protected_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,12 @@ func TestProtectedAPIFromServiceExports(t *testing.T) {
147147
kcpClusterClient, err := kcpclientset.NewForConfig(cfg)
148148
require.NoError(t, err, "failed to construct kcp cluster client for server")
149149

150-
t.Logf("Get tenancy APIExport from root workspace")
151-
tenanciesRoot, err := kcpClusterClient.ApisV1alpha2().APIExports().Cluster(rootWorkspace).Get(ctx, tenancy.GroupName, metav1.GetOptions{})
150+
t.Logf("Get tenancy APIExportEndpointSlice from root workspace")
151+
endpointSlice, err := kcpClusterClient.ApisV1alpha1().APIExportEndpointSlices().Cluster(rootWorkspace).Get(ctx, tenancy.GroupName, metav1.GetOptions{})
152152
require.NoError(t, err)
153153

154154
t.Logf("Construct VirtualWorkspace client")
155-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
156-
vwURL := tenanciesRoot.Status.VirtualWorkspaces[0].URL
155+
vwURL := endpointSlice.Status.APIExportEndpoints[0].URL
157156
cfgVW := server.RootShardSystemMasterBaseConfig(t)
158157
cfgVW.Host = vwURL
159158

test/e2e/apibinding/apibinding_test.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
"github.com/kcp-dev/logicalcluster/v3"
4747

4848
"github.com/kcp-dev/kcp/config/helpers"
49+
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
4950
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
5051
"github.com/kcp-dev/kcp/sdk/apis/core"
5152
corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
@@ -240,6 +241,22 @@ func TestAPIBinding(t *testing.T) {
240241
t.Logf("Create an APIExport today-cowboys in %q", serviceProviderWorkspace)
241242
_, err = kcpClusterClient.Cluster(serviceProviderWorkspace).ApisV1alpha2().APIExports().Create(ctx, cowboysAPIExport, metav1.CreateOptions{})
242243
require.NoError(t, err)
244+
245+
t.Logf("Create an APIExportEndpointSlice for today-cowboys in %q", serviceProviderWorkspace)
246+
endpointSlice := &apisv1alpha1.APIExportEndpointSlice{
247+
ObjectMeta: metav1.ObjectMeta{
248+
Name: "today-cowboys",
249+
},
250+
Spec: apisv1alpha1.APIExportEndpointSliceSpec{
251+
APIExport: apisv1alpha1.ExportBindingReference{
252+
Path: serviceProviderWorkspace.String(),
253+
Name: "today-cowboys",
254+
},
255+
},
256+
}
257+
258+
_, err = kcpClusterClient.Cluster(serviceProviderWorkspace).ApisV1alpha1().APIExportEndpointSlices().Create(ctx, endpointSlice, metav1.CreateOptions{})
259+
require.NoError(t, err)
243260
}
244261

245262
bindConsumerToProvider := func(consumerWorkspace logicalcluster.Path, providerPath logicalcluster.Path) {
@@ -365,16 +382,15 @@ func TestAPIBinding(t *testing.T) {
365382
expectedURLs = append(expectedURLs, u.String())
366383
}
367384

368-
t.Logf("Make sure the APIExport gets status.virtualWorkspaceURLs set")
385+
t.Logf("Make sure the APIExportEndpointSlice gets status.virtualWorkspaceURLs set")
369386
kcptestinghelpers.Eventually(t, func() (bool, string) {
370-
e, err := kcpClusterClient.Cluster(serviceProviderClusterName.Path()).ApisV1alpha2().APIExports().Get(ctx, exportName, metav1.GetOptions{})
387+
apiExportEndpointSlice, err := kcpClusterClient.Cluster(serviceProviderClusterName.Path()).ApisV1alpha1().APIExportEndpointSlices().Get(ctx, exportName, metav1.GetOptions{})
371388
if err != nil {
372-
t.Logf("Unexpected error getting APIExport %s|%s: %v", serviceProviderClusterName.Path(), exportName, err)
389+
t.Logf("Unexpected error getting APIExportEndpointSlice %s|%s: %v", serviceProviderClusterName.Path(), exportName, err)
373390
}
374391

375392
var actualURLs []string
376-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
377-
for _, u := range e.Status.VirtualWorkspaces {
393+
for _, u := range apiExportEndpointSlice.Status.APIExportEndpoints {
378394
actualURLs = append(actualURLs, u.URL)
379395
}
380396

@@ -438,15 +454,14 @@ func TestAPIBinding(t *testing.T) {
438454
t.Logf("=== Verify that %s|%s export virtual workspace shows cowboys", provider2Path, exportName)
439455
rawConfig, err := server.RawConfig()
440456
require.NoError(t, err)
441-
export2, err := kcpClusterClient.Cluster(provider2Path).ApisV1alpha2().APIExports().Get(ctx, exportName, metav1.GetOptions{})
457+
apiExportEndpointSlice2, err := kcpClusterClient.Cluster(provider2Path).ApisV1alpha1().APIExportEndpointSlices().Get(ctx, exportName, metav1.GetOptions{})
442458
require.NoError(t, err)
443459

444460
kcptestinghelpers.Eventually(t, func() (bool, string) {
445461
foundOnShards := 0
446462
var listErrs []error
447463

448-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
449-
for _, vw := range export2.Status.VirtualWorkspaces {
464+
for _, vw := range apiExportEndpointSlice2.Status.APIExportEndpoints {
450465
vw2ClusterClient, err := kcpdynamic.NewForConfig(apiexportVWConfig(t, rawConfig, vw.URL))
451466
require.NoError(t, err)
452467

@@ -476,8 +491,7 @@ func TestAPIBinding(t *testing.T) {
476491
return false, "couldn't list via virtual workspaces because the user is not ready yet"
477492
}
478493

479-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
480-
require.Equal(t, 1, foundOnShards, "cowboys not found exactly on one shard, but on %d/%d", foundOnShards, len(export2.Status.VirtualWorkspaces))
494+
require.Equal(t, 1, foundOnShards, "cowboys not found exactly on one shard, but on %d/%d", foundOnShards, len(apiExportEndpointSlice2.Status.APIExportEndpoints))
481495

482496
return true, ""
483497
}, wait.ForeverTestTimeout, 100*time.Millisecond, "expected to have cowboys exactly on one shard")

test/e2e/fixtures/apifixtures/sheriffs.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ func CreateSheriffsSchemaAndExport(
182182
t.Logf("Creating APIExport %s|%s", path, export.Name)
183183
_, err = clusterClient.Cluster(path).ApisV1alpha2().APIExports().Create(ctx, export, metav1.CreateOptions{})
184184
require.NoError(t, err, "error creating APIExport %s|%s", path, export.Name)
185+
186+
t.Logf("Creating APIExportEndpointSlice %s|%s", path, export.Name)
187+
_, err = clusterClient.Cluster(path).ApisV1alpha1().APIExportEndpointSlices().Create(ctx, &apisv1alpha1.APIExportEndpointSlice{
188+
ObjectMeta: metav1.ObjectMeta{Name: export.Name},
189+
Spec: apisv1alpha1.APIExportEndpointSliceSpec{
190+
APIExport: apisv1alpha1.ExportBindingReference{Name: export.Name, Path: path.String()},
191+
},
192+
}, metav1.CreateOptions{})
193+
require.NoError(t, err, "error creating APIExportEndpointSlice %s|%s", path, export.Name)
185194
}
186195

187196
// CreateSheriff creates an instance of a Sheriff CustomResource in the logical cluster identified by clusterName, in

test/e2e/framework/util.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import (
3232
"github.com/kcp-dev/kcp/pkg/authorization"
3333
bootstrappolicy "github.com/kcp-dev/kcp/pkg/authorization/bootstrap"
3434
"github.com/kcp-dev/kcp/pkg/server"
35-
apisv1alpha2 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha2"
35+
apisv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"
3636
tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1"
3737
kcpclientset "github.com/kcp-dev/kcp/sdk/client/clientset/versioned/cluster"
3838
testing2 "github.com/kcp-dev/kcp/sdk/testing"
@@ -84,12 +84,10 @@ func VirtualWorkspaceURL(ctx context.Context, kcpClusterClient kcpclientset.Clus
8484
}
8585

8686
// ExportVirtualWorkspaceURLs returns the URLs of the virtual workspaces of the
87-
// given APIExport.
88-
func ExportVirtualWorkspaceURLs(export *apisv1alpha2.APIExport) []string {
89-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
90-
urls := make([]string, 0, len(export.Status.VirtualWorkspaces))
91-
//nolint:staticcheck // SA1019 VirtualWorkspaces is deprecated but not removed yet
92-
for _, vw := range export.Status.VirtualWorkspaces {
87+
// given APIExportEndpointSlice.
88+
func ExportVirtualWorkspaceURLs(export *apisv1alpha1.APIExportEndpointSlice) []string {
89+
urls := make([]string, 0, len(export.Status.APIExportEndpoints))
90+
for _, vw := range export.Status.APIExportEndpoints {
9391
urls = append(urls, vw.URL)
9492
}
9593
return urls

0 commit comments

Comments
 (0)