Skip to content

Commit 4dc2ea7

Browse files
ENG-10378 | Cross vCluster APIs (#3389)
* Add vcluster.yaml resource proxy configuration * Start proxy * Move proxy config to experimental * Rename start func * Vendor in dev platform changes * Bump admin-apis
1 parent 3920f22 commit 4dc2ea7

33 files changed

+1517
-36
lines changed

chart/values.schema.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,38 @@
10241024
"additionalProperties": false,
10251025
"type": "object"
10261026
},
1027+
"CustomResourceProxy": {
1028+
"properties": {
1029+
"enabled": {
1030+
"type": "boolean",
1031+
"description": "Enabled defines if this resource proxy should be enabled"
1032+
},
1033+
"target": {
1034+
"$ref": "#/$defs/CustomResourceProxyTarget",
1035+
"description": "CustomResourceProxyTarget is the target configuration for the custom resource proxy"
1036+
}
1037+
},
1038+
"additionalProperties": false,
1039+
"type": "object"
1040+
},
1041+
"CustomResourceProxyTarget": {
1042+
"properties": {
1043+
"name": {
1044+
"type": "string",
1045+
"description": "Name is the name of the virtual cluster"
1046+
},
1047+
"project": {
1048+
"type": "string",
1049+
"description": "Project is the project of the virtual cluster"
1050+
},
1051+
"serviceAccountRef": {
1052+
"$ref": "#/$defs/NamespacedNameArgs",
1053+
"description": "ServiceAccountRef is the service account to use for the proxy in target cluster"
1054+
}
1055+
},
1056+
"additionalProperties": false,
1057+
"type": "object"
1058+
},
10271059
"Database": {
10281060
"properties": {
10291061
"embedded": {
@@ -1764,6 +1796,10 @@
17641796
"type": "array",
17651797
"description": "DenyProxyRequests denies certain requests in the vCluster proxy.",
17661798
"pro": true
1799+
},
1800+
"proxy": {
1801+
"$ref": "#/$defs/Proxy",
1802+
"description": "Proxy enables vCluster-to-vCluster proxying of resources via Tailscale"
17671803
}
17681804
},
17691805
"additionalProperties": false,
@@ -2929,6 +2965,20 @@
29292965
"additionalProperties": false,
29302966
"type": "object"
29312967
},
2968+
"NamespacedNameArgs": {
2969+
"properties": {
2970+
"namespace": {
2971+
"type": "string",
2972+
"description": "Namespace is the namespace of the resource"
2973+
},
2974+
"name": {
2975+
"type": "string",
2976+
"description": "Name is the name of the resource"
2977+
}
2978+
},
2979+
"additionalProperties": false,
2980+
"type": "object"
2981+
},
29322982
"NetworkPolicy": {
29332983
"properties": {
29342984
"enabled": {
@@ -3530,6 +3580,19 @@
35303580
"additionalProperties": false,
35313581
"type": "object"
35323582
},
3583+
"Proxy": {
3584+
"properties": {
3585+
"customResources": {
3586+
"additionalProperties": {
3587+
"$ref": "#/$defs/CustomResourceProxy"
3588+
},
3589+
"type": "object",
3590+
"description": "Resources is a map of resource keys (format: \"kind.apiGroup/version\") to proxy configuration"
3591+
}
3592+
},
3593+
"additionalProperties": false,
3594+
"type": "object"
3595+
},
35333596
"RBAC": {
35343597
"properties": {
35353598
"role": {

chart/values.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,11 @@ plugins: {}
12181218

12191219
# Experimental features for vCluster. Configuration here might change, so be careful with this.
12201220
experimental:
1221+
# Proxy enables vCluster-to-vCluster proxying of resources via Tailscale
1222+
proxy:
1223+
# Resources is a map of resource keys (format: "kind.apiGroup/version") to proxy configuration
1224+
customResources: {}
1225+
12211226
# SyncSettings are advanced settings for the syncer controller.
12221227
syncSettings:
12231228
# SetOwner specifies if vCluster should set an owner reference on the synced objects to the vCluster service. This allows for easy garbage collection.

cmd/vcluster/cmd/start.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ func StartInCluster(ctx context.Context, options *StartOptions) error {
187187
}
188188
}
189189

190+
// Check if any proxy resources are enabled
191+
if len(vConfig.Experimental.Proxy.CustomResources) > 0 {
192+
if err := pro.StartCustomResourceProxy(controllerCtx, vConfig); err != nil {
193+
return fmt.Errorf("start resource proxy: %w", err)
194+
}
195+
}
196+
190197
// start leader election + controllers
191198
err = StartLeaderElection(controllerCtx, func() error {
192199
return setup.StartControllers(controllerCtx, syncers)

config/config.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,6 +2399,38 @@ type ControlPlaneHeadlessService struct {
23992399
Labels map[string]string `json:"labels,omitempty"`
24002400
}
24012401

2402+
type Proxy struct {
2403+
// Resources is a map of resource keys (format: "kind.apiGroup/version") to proxy configuration
2404+
CustomResources map[string]CustomResourceProxy `json:"customResources,omitempty"`
2405+
}
2406+
2407+
type CustomResourceProxy struct {
2408+
// Enabled defines if this resource proxy should be enabled
2409+
Enabled bool `json:"enabled,omitempty"`
2410+
2411+
// CustomResourceProxyTarget is the target configuration for the custom resource proxy
2412+
Target CustomResourceProxyTarget `json:"target,omitempty"`
2413+
}
2414+
2415+
type NamespacedNameArgs struct {
2416+
// Namespace is the namespace of the resource
2417+
Namespace string `json:"namespace,omitempty"`
2418+
2419+
// Name is the name of the resource
2420+
Name string `json:"name,omitempty"`
2421+
}
2422+
2423+
type CustomResourceProxyTarget struct {
2424+
// Name is the name of the virtual cluster
2425+
Name string `json:"name,omitempty"`
2426+
2427+
// Project is the project of the virtual cluster
2428+
Project string `json:"project,omitempty"`
2429+
2430+
// ServiceAccountRef is the service account to use for the proxy in target cluster
2431+
ServiceAccountRef NamespacedNameArgs `json:"serviceAccountRef,omitempty"`
2432+
}
2433+
24022434
type ExternalEtcdPersistence struct {
24032435
// VolumeClaim can be used to configure the persistent volume claim.
24042436
VolumeClaim ExternalEtcdPersistenceVolumeClaim `json:"volumeClaim,omitempty"`
@@ -2992,6 +3024,9 @@ type Experimental struct {
29923024

29933025
// DenyProxyRequests denies certain requests in the vCluster proxy.
29943026
DenyProxyRequests []DenyRule `json:"denyProxyRequests,omitempty" product:"pro"`
3027+
3028+
// Proxy enables vCluster-to-vCluster proxying of resources via Tailscale
3029+
Proxy Proxy `json:"proxy,omitempty"`
29953030
}
29963031

29973032
func (e Experimental) JSONSchemaExtend(base *jsonschema.Schema) {

config/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,9 @@ external: {}
657657
plugins: {}
658658

659659
experimental:
660+
proxy:
661+
customResources: {}
662+
660663
syncSettings:
661664
setOwner: true
662665

go.mod

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ require (
2424
github.com/hashicorp/golang-lru/v2 v2.0.7
2525
github.com/invopop/jsonschema v0.12.0
2626
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0
27-
github.com/loft-sh/admin-apis v0.0.0-20250923191853-0998210fade9
27+
github.com/loft-sh/admin-apis v0.0.0-20251209063713-e076e2ddb87c
2828
github.com/loft-sh/agentapi/v4 v4.5.0-alpha.10
2929
github.com/loft-sh/analytics-client v0.0.0-20240219162240-2f4c64b2494e
3030
github.com/loft-sh/api/v4 v4.5.0-alpha.10
@@ -49,7 +49,7 @@ require (
4949
github.com/wk8/go-ordered-map/v2 v2.1.8
5050
go.etcd.io/etcd/server/v3 v3.6.4
5151
go.uber.org/atomic v1.11.0
52-
golang.org/x/mod v0.26.0
52+
golang.org/x/mod v0.27.0
5353
google.golang.org/grpc v1.72.1
5454
google.golang.org/protobuf v1.36.8
5555
gopkg.in/yaml.v3 v3.0.1
@@ -267,7 +267,7 @@ require (
267267
golang.org/x/term v0.34.0 // indirect
268268
golang.org/x/text v0.28.0 // indirect
269269
golang.org/x/time v0.12.0 // indirect
270-
golang.org/x/tools v0.35.0 // indirect
270+
golang.org/x/tools v0.36.0 // indirect
271271
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
272272
gopkg.in/inf.v0 v0.9.1 // indirect
273273
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
@@ -279,3 +279,5 @@ require (
279279
sigs.k8s.io/kustomize/api v0.20.1 // indirect
280280
sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect
281281
)
282+
283+
replace github.com/loft-sh/api/v4 => ../loft-enterprise/staging/src/github.com/loft-sh/api/v4

go.sum

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,14 +295,12 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhn
295295
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
296296
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
297297
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
298-
github.com/loft-sh/admin-apis v0.0.0-20250923191853-0998210fade9 h1:ifHh06CRNzg0Ff2rDekGDuYYAY39wMRpBU9Ym5TxXSI=
299-
github.com/loft-sh/admin-apis v0.0.0-20250923191853-0998210fade9/go.mod h1:WHCqWfljfD1hkwk41hLeqBhW2yeLvWipB1sH6vfnR7U=
298+
github.com/loft-sh/admin-apis v0.0.0-20251209063713-e076e2ddb87c h1:HAAqcQPai7ziBFN9Yhq/3Jdhrl9OWnL61Gnm6FukOIY=
299+
github.com/loft-sh/admin-apis v0.0.0-20251209063713-e076e2ddb87c/go.mod h1:WHCqWfljfD1hkwk41hLeqBhW2yeLvWipB1sH6vfnR7U=
300300
github.com/loft-sh/agentapi/v4 v4.5.0-alpha.10 h1:QK+lMUuZ7c8qWDWISyumaTxc7dTDjmttNCE3RiRE/T8=
301301
github.com/loft-sh/agentapi/v4 v4.5.0-alpha.10/go.mod h1:eK66Ey/Zcx9LHjnCHSho1C0HTlf4jjyEUaCwP/9QNn8=
302302
github.com/loft-sh/analytics-client v0.0.0-20240219162240-2f4c64b2494e h1:JcPnMaoczikvpasi8OJ47dCkWZjfgFubWa4V2SZo7h0=
303303
github.com/loft-sh/analytics-client v0.0.0-20240219162240-2f4c64b2494e/go.mod h1:FFWcGASyM2QlWTDTCG/WBVM/XYr8btqYt335TFNRCFg=
304-
github.com/loft-sh/api/v4 v4.5.0-alpha.10 h1:pcPkIAqPSJWZ+DB+9j7rBXb8iClHAMeh0QZC6Tiw6vA=
305-
github.com/loft-sh/api/v4 v4.5.0-alpha.10/go.mod h1:GzkHPh5gRBOjrYYQt1evksEdlBpB/FUvDYN7nL/sfJU=
306304
github.com/loft-sh/apiserver v0.0.0-20250910060242-4b9f3ffe0646 h1:ZWOAMcsIZN4GKESwZBWU1+uepe+L8owmrkJDe5j4KlE=
307305
github.com/loft-sh/apiserver v0.0.0-20250910060242-4b9f3ffe0646/go.mod h1:hLlplUgCm+KDLoTVfSNTGQSBx/fhsTxu5m8d1LBUXKA=
308306
github.com/loft-sh/image v0.0.0-20250625154753-87447a6ad364 h1:vSuqHqh4w2zrG+WvnyH64JAUhX+Bou19n0gvCrPirOs=
@@ -558,8 +556,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
558556
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
559557
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
560558
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
561-
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
562-
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
559+
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
560+
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
563561
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
564562
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
565563
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -664,8 +662,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
664662
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
665663
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
666664
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
667-
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
668-
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
665+
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
666+
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
669667
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
670668
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
671669
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

pkg/pro/proxy.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package pro
2+
3+
import (
4+
"github.com/loft-sh/vcluster/pkg/config"
5+
"github.com/loft-sh/vcluster/pkg/syncer/synccontext"
6+
)
7+
8+
var StartCustomResourceProxy = func(_ *synccontext.ControllerContext, _ *config.VirtualClusterConfig) error {
9+
return NewFeatureError("resource proxy")
10+
}

vendor/github.com/loft-sh/admin-apis/pkg/licenseapi/features.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/loft-sh/admin-apis/pkg/licenseapi/features_allowed_before.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)