Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ func NewConfig(ctx context.Context, opts kcpserveroptions.CompletedOptions) (*Co
&virtualResourcesConfig,
vwClientConfig,
c.CacheDynamicClient,
c.Options.Extra.ShardName,
c.ShardVirtualWorkspaceURL,
c.ApiExtensionsSharedInformerFactory.Apiextensions().V1().CustomResourceDefinitions(),
c.KcpSharedInformerFactory.Apis().V1alpha2().APIBindings(),
Expand Down
3 changes: 3 additions & 0 deletions pkg/server/virtualresources/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type ExtraConfig struct {
VWClientConfig *rest.Config
DynamicClusterClient kcpdynamic.ClusterInterface

ShardName string
ShardVirtualWorkspaceURLGetter func() string

CRDLister kcpapiextensionsv1informers.CustomResourceDefinitionClusterInformer
Expand Down Expand Up @@ -85,6 +86,7 @@ func NewConfig(
cfg *genericapiserver.Config,
vwClientConfig *rest.Config,
dynamicClusterClient kcpdynamic.ClusterInterface,
shardName string,
shardVirtualWorkspaceURLGetter func() string,
crdLister kcpapiextensionsv1informers.CustomResourceDefinitionClusterInformer,
apiBindingInformer apisv1alpha2informers.APIBindingClusterInformer,
Expand All @@ -100,6 +102,7 @@ func NewConfig(
VWClientConfig: vwClientConfig,
DynamicClusterClient: dynamicClusterClient,

ShardName: shardName,
ShardVirtualWorkspaceURLGetter: shardVirtualWorkspaceURLGetter,

CRDLister: crdLister,
Expand Down
41 changes: 16 additions & 25 deletions pkg/server/virtualresources/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import (

"github.com/kcp-dev/logicalcluster/v3"

cacheclient "github.com/kcp-dev/kcp/pkg/cache/client"
"github.com/kcp-dev/kcp/pkg/cache/client/shard"
"github.com/kcp-dev/kcp/pkg/endpointslice"
"github.com/kcp-dev/kcp/pkg/indexers"
"github.com/kcp-dev/kcp/pkg/reconciler/dynamicrestmapper"
Expand All @@ -66,7 +68,7 @@ type Server struct {
delegate http.Handler

getCRD func(cluster logicalcluster.Name, name string) (*apiextensionsv1.CustomResourceDefinition, error)
getUnstructuredEndpointSlice func(ctx context.Context, cluster logicalcluster.Name, gvr schema.GroupVersionResource, name string) (*unstructured.Unstructured, error)
getUnstructuredEndpointSlice func(ctx context.Context, cluster logicalcluster.Name, shard shard.Name, gvr schema.GroupVersionResource, name string) (*unstructured.Unstructured, error)
getAPIExportByPath func(clusterPath logicalcluster.Path, name string) (*apisv1alpha2.APIExport, error)
}

Expand All @@ -76,27 +78,12 @@ func NewServer(c CompletedConfig, delegationTarget genericapiserver.DelegationTa
Extra: c.Extra,
delegate: delegationTarget.UnprotectedHandler(),

getUnstructuredEndpointSlice: func(ctx context.Context, cluster logicalcluster.Name, gvr schema.GroupVersionResource, name string) (*unstructured.Unstructured, error) {
list, err := c.Extra.DynamicClusterClient.Cluster(cluster.Path()).Resource(gvr).List(ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}

if len(list.Items) == 0 {
return nil, apierrors.NewNotFound(gvr.GroupResource(), name)
}

var slice *unstructured.Unstructured
for _, item := range list.Items {
if item.GetName() == name {
if slice != nil {
return nil, apierrors.NewInternalError(fmt.Errorf("multiple objects found"))
}
slice = &item
}
}

return slice, nil
getUnstructuredEndpointSlice: func(ctx context.Context, cluster logicalcluster.Name, shardName shard.Name, gvr schema.GroupVersionResource, name string) (*unstructured.Unstructured, error) {
// We assume the endpoint slice is cluster-scoped.
return c.Extra.DynamicClusterClient.
Cluster(cluster.Path()).
Resource(gvr).
Get(cacheclient.WithShardInContext(ctx, shardName), name, metav1.GetOptions{})
},
getCRD: func(clusterName logicalcluster.Name, name string) (*apiextensionsv1.CustomResourceDefinition, error) {
return c.Extra.CRDLister.Lister().Cluster(clusterName).Get(name)
Expand Down Expand Up @@ -283,7 +270,11 @@ func (s *Server) handleResource(w http.ResponseWriter, r *http.Request) {

// We have a virtual resource. Get the endpoint URL, create a proxy handler and serve from that endpoint.

vrEndpointURL, err := s.getVirtualResourceURL(ctx, logicalcluster.From(apiExport), virtualStorage)
apiExportShard := shard.Name(apiExport.Annotations[shard.AnnotationKey])
if apiExportShard.Empty() {
apiExportShard = shard.New(s.Extra.ShardName)
}
vrEndpointURL, err := s.getVirtualResourceURL(ctx, logicalcluster.From(apiExport), apiExportShard, virtualStorage)
if err != nil {
utilruntime.HandleError(err)
responsewriters.ErrorNegotiated(
Expand All @@ -306,7 +297,7 @@ func (s *Server) handleResource(w http.ResponseWriter, r *http.Request) {
vrHandler.ServeHTTP(w, r)
}

func (s *Server) getVirtualResourceURL(ctx context.Context, apiExportCluster logicalcluster.Name, virtual *apisv1alpha2.ResourceSchemaStorageVirtual) (string, error) {
func (s *Server) getVirtualResourceURL(ctx context.Context, apiExportCluster logicalcluster.Name, apiExportShard shard.Name, virtual *apisv1alpha2.ResourceSchemaStorageVirtual) (string, error) {
sliceMapping, err := s.drm.ForCluster(apiExportCluster).RESTMapping(schema.GroupKind{
Group: ptr.Deref(virtual.Reference.APIGroup, ""),
Kind: virtual.Reference.Kind,
Expand All @@ -315,7 +306,7 @@ func (s *Server) getVirtualResourceURL(ctx context.Context, apiExportCluster log
return "", err
}

slice, err := s.getUnstructuredEndpointSlice(ctx, apiExportCluster, schema.GroupVersionResource{
slice, err := s.getUnstructuredEndpointSlice(ctx, apiExportCluster, apiExportShard, schema.GroupVersionResource{
Group: sliceMapping.Resource.Group,
Version: sliceMapping.Resource.Version,
Resource: sliceMapping.Resource.Resource,
Expand Down