Skip to content

Commit 9f0f1a8

Browse files
committed
Add cluster/consumer ID
Signed-off-by: Mangirdas Judeikis <mangirdas@judeikis.lt> On-behalf-of: @SAP mangirdas.judeikis@sap.com
1 parent 65b721c commit 9f0f1a8

28 files changed

Lines changed: 619 additions & 97 deletions

File tree

backend/auth/handler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ func (ah *AuthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request) {
8282
SessionID: params.SessionID,
8383
ClusterID: params.ClusterID,
8484
ClientType: ClientType(params.ClientType),
85+
ConsumerID: params.ConsumerID,
8586
}
8687
}
8788

backend/auth/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type AuthorizeRequest struct {
5454
SessionID string `json:"session_id" form:"session_id"`
5555
ClusterID string `json:"cluster_id" form:"cluster_id"`
5656
ClientType ClientType `json:"client_type" form:"client_type"`
57+
ConsumerID string `json:"consumer_id" form:"consumer_id"`
5758
}
5859

5960
type CallbackRequest struct {

backend/client/client.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type ClientParameters struct {
2828
ClientSideRedirectURL string
2929
SessionID string
3030
ClientType string
31+
ConsumerID string
3132

3233
IsClusterScoped bool
3334
}
@@ -40,6 +41,7 @@ func GetQueryParams(r *http.Request) *ClientParameters {
4041
ClientSideRedirectURL: r.URL.Query().Get("client_side_redirect_url"),
4142
SessionID: r.URL.Query().Get("session_id"),
4243
ClientType: r.URL.Query().Get("client_type"),
44+
ConsumerID: r.URL.Query().Get("consumer_id"),
4345
}
4446
p.IsClusterScoped = p.ClusterID != ""
4547
return p
@@ -68,6 +70,9 @@ func (r *ClientParameters) WithParams(urlStr string) string {
6870
if r.ClientType != "" {
6971
query.Set("client_type", r.ClientType)
7072
}
73+
if r.ConsumerID != "" {
74+
query.Set("consumer_id", r.ConsumerID)
75+
}
7176

7277
parsedURL.RawQuery = query.Encode()
7378
return parsedURL.String()

backend/config.go

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ limitations under the License.
1717
package backend
1818

1919
import (
20-
"context"
2120
"fmt"
22-
"net/url"
23-
"strings"
2421

2522
"github.com/kcp-dev/multicluster-provider/apiexport"
2623
apisv1alpha1 "github.com/kcp-dev/sdk/apis/apis/v1alpha1"
@@ -49,8 +46,9 @@ type Config struct {
4946

5047
Provider multicluster.Provider
5148
ExternalAddressGenerator kuberesources.ExternalAddressGeneratorFunc
52-
Manager mcmanager.Manager
53-
Scheme *runtime.Scheme
49+
50+
Manager mcmanager.Manager
51+
Scheme *runtime.Scheme
5452

5553
ClientConfig *rest.Config
5654
}
@@ -106,7 +104,7 @@ func NewConfig(options *options.CompletedOptions) (*Config, error) {
106104
return nil, fmt.Errorf("error setting up kcp provider: %w", err)
107105
}
108106

109-
gen, err := newKCPExternalAddressGenerator(options.ExternalAddress)
107+
gen, err := kcpprovider.NewKCPExternalAddressGenerator(options.ExternalAddress)
110108
if err != nil {
111109
return nil, err
112110
}
@@ -137,44 +135,3 @@ func NewConfig(options *options.CompletedOptions) (*Config, error) {
137135

138136
return config, nil
139137
}
140-
141-
func newKCPExternalAddressGenerator(externalAddress string) (kuberesources.ExternalAddressGeneratorFunc, error) {
142-
var extURL *url.URL
143-
if externalAddress != "" {
144-
var err error
145-
146-
extURL, err = url.Parse(externalAddress)
147-
if err != nil {
148-
return nil, fmt.Errorf("invalid --external-address: %w", err)
149-
}
150-
}
151-
152-
return func(_ context.Context, clusterConfig *rest.Config) (string, error) {
153-
// In kcp case, we are talking via apiexport so clientconfig will be pointing to
154-
// https://192.168.2.166:6443/services/apiexport/root:org:ws/<apiexport-name>/clusters/2p0rtkf7b697s6mj
155-
// We need to extract host and /clusters/... part
156-
u, err := url.Parse(clusterConfig.Host)
157-
if err != nil {
158-
return "", err
159-
}
160-
161-
// Extract cluster ID from the path
162-
// Path format: /services/apiexport/root:org:ws/<apiexport-name>/clusters/{cluster-id}
163-
pathParts := strings.Split(strings.Trim(u.Path, "/"), "/")
164-
if len(pathParts) < 6 || pathParts[4] != "clusters" {
165-
return "", fmt.Errorf("invalid apiexport URL format")
166-
}
167-
168-
clusterID := pathParts[5]
169-
170-
// Construct new URL with cluster path
171-
var finalURL = u
172-
if extURL != nil {
173-
finalURL = extURL
174-
}
175-
176-
finalURL.Path = "/clusters/" + clusterID
177-
178-
return finalURL.String(), nil
179-
}, nil
180-
}

backend/http/handler.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,20 @@ func (h *handler) handleBind(w http.ResponseWriter, r *http.Request) {
368368
return
369369
}
370370

371+
if bindRequest.ClusterIdentity.Identity == "" {
372+
logger.Error(fmt.Errorf("missing cluster identity"), "invalid bind request")
373+
writeErrorResponse(w, http.StatusBadRequest, kubebindv1alpha2.ErrorCodeBadRequest, "Missing cluster identity in bind request", "The cluster identity must be provided in the bind request")
374+
return
375+
}
376+
377+
kfg, err := h.kubeManager.HandleResources(r.Context(), state.Token.Subject, bindRequest.ClusterIdentity.Identity, params.ClusterID)
378+
if err != nil {
379+
logger.Error(err, "failed to handle resources")
380+
statusCode, code, details := mapErrorToCode(err)
381+
writeErrorResponse(w, statusCode, code, "Failed to handle cluster resources", details)
382+
return
383+
}
384+
371385
// Module consist of many resources and permissionClaims. Read it and translate to
372386
template, err := h.kubeManager.GetTemplates(r.Context(), params.ClusterID, bindRequest.TemplateRef.Name)
373387
if err != nil {

backend/kubernetes/manager.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ func NewKubernetesManager(
8383
return m, nil
8484
}
8585

86-
func (m *Manager) HandleResources(ctx context.Context, identity, cluster string) ([]byte, error) {
86+
func (m *Manager) HandleResources(
87+
ctx context.Context,
88+
author, identity, cluster string,
89+
) ([]byte, error) {
8790
logger := klog.FromContext(ctx).WithValues("identity", identity)
8891
ctx = klog.NewContext(ctx, logger)
8992

@@ -107,7 +110,7 @@ func (m *Manager) HandleResources(ctx context.Context, identity, cluster string)
107110
if len(nss.Items) == 1 {
108111
ns = nss.Items[0].Name
109112
} else {
110-
nsObj, err := kuberesources.CreateNamespace(ctx, c, m.namespacePrefix, identity)
113+
nsObj, err := kuberesources.CreateNamespace(ctx, c, m.namespacePrefix, identity, author)
111114
if err != nil {
112115
return nil, err
113116
}

backend/kubernetes/resources/namespace.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929

3030
const (
3131
IdentityAnnotationKey = "backend.kube-bind.io/identity"
32+
AuthorAnnotationKey = "backend.kube-bind.io/author"
3233
legacyIdentityAnnotationKey = "example-backend.kube-bind.io/identity"
3334
)
3435

@@ -53,7 +54,7 @@ func handleLegacyAnnotations(ctx context.Context, cl client.Client, namespace *c
5354
return nil
5455
}
5556

56-
func CreateNamespace(ctx context.Context, client client.Client, generateName, id string) (*corev1.Namespace, error) {
57+
func CreateNamespace(ctx context.Context, client client.Client, generateName, id, author string) (*corev1.Namespace, error) {
5758
if !strings.HasSuffix(generateName, "-") {
5859
generateName += "-"
5960
}
@@ -62,6 +63,7 @@ func CreateNamespace(ctx context.Context, client client.Client, generateName, id
6263
GenerateName: generateName,
6364
Annotations: map[string]string{
6465
IdentityAnnotationKey: id,
66+
AuthorAnnotationKey: author,
6567
},
6668
},
6769
}

cli/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ require (
2626
k8s.io/client-go v0.34.2
2727
k8s.io/component-base v0.34.2
2828
k8s.io/klog/v2 v2.130.1
29+
sigs.k8s.io/controller-runtime v0.22.4
2930
sigs.k8s.io/kind v0.30.0
3031
sigs.k8s.io/yaml v1.6.0
3132
)

cli/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8
468468
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
469469
oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
470470
oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
471+
sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A=
472+
sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=
471473
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
472474
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
473475
sigs.k8s.io/kind v0.30.0 h1:2Xi1KFEfSMm0XDcvKnUt15ZfgRPCT0OnCBbpgh8DztY=

cli/pkg/kubectl/base/identity.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package base
2+
3+
import (
4+
"context"
5+
6+
corev1 "k8s.io/api/core/v1"
7+
"k8s.io/apimachinery/pkg/types"
8+
"k8s.io/client-go/rest"
9+
"sigs.k8s.io/controller-runtime/pkg/client"
10+
)
11+
12+
func GetClusterIdentityFromNamespace(ctx context.Context, rest *rest.Config, namespaceName string) (string, error) {
13+
cl, err := client.New(rest, client.Options{})
14+
if err != nil {
15+
return "", err
16+
}
17+
18+
var namespace corev1.Namespace
19+
err = cl.Get(ctx, types.NamespacedName{Name: namespaceName}, &namespace)
20+
if err != nil {
21+
return "", err
22+
}
23+
24+
return string(namespace.UID), nil
25+
}

0 commit comments

Comments
 (0)