Skip to content

Commit 48ca4e4

Browse files
authored
API improvments for custom UI (#483)
* Handle custom named secrets * dont fail on hash images * Add consumer secret reporting
1 parent 64b647b commit 48ca4e4

10 files changed

Lines changed: 171 additions & 17 deletions

File tree

cli/pkg/kubectl/base/kubeconfig.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,17 @@ func FindRemoteKubeconfig(ctx context.Context, kubeClient *kubernetes.Clientset,
8686
// the binding session id and the kubeconfig of the service provider cluster. If it is pre-existing, the kubeconfig
8787
// is updated.
8888
//
89+
// If name is provided, the secret will be created with that name or updated if it already exists.
90+
// If name is empty, a new secret with a generated name (kubeconfig-<random>) will be created.
91+
//
8992
// It does special checking that only kubeconfigs with the same host and default namespace are updated.
9093
func EnsureKubeconfigSecret(ctx context.Context, kubeconfig, name string, client kubernetes.Interface) (*corev1.Secret, bool, error) {
9194
remoteHost, remoteNamespace, err := ParseRemoteKubeconfig([]byte(kubeconfig))
9295
if err != nil {
9396
return nil, false, err
9497
}
9598

99+
// If no name provided, create with generated name
96100
if name == "" {
97101
secret := &corev1.Secret{
98102
ObjectMeta: v1.ObjectMeta{
@@ -114,7 +118,35 @@ func EnsureKubeconfigSecret(ctx context.Context, kubeconfig, name string, client
114118
return secret, true, nil
115119
}
116120

117-
// update existing secret
121+
// Name provided - try to get existing secret
122+
_, err = client.CoreV1().Secrets("kube-bind").Get(ctx, name, v1.GetOptions{})
123+
if err != nil && !errors.IsNotFound(err) {
124+
return nil, false, err
125+
}
126+
127+
// Secret doesn't exist - create with the provided name
128+
if errors.IsNotFound(err) {
129+
secret := &corev1.Secret{
130+
ObjectMeta: v1.ObjectMeta{
131+
Namespace: "kube-bind",
132+
Name: name,
133+
Labels: map[string]string{
134+
kubebindv1alpha2.LabelProviderKubeconfig: "true",
135+
},
136+
},
137+
Data: map[string][]byte{
138+
"kubeconfig": []byte(kubeconfig),
139+
},
140+
}
141+
142+
secret, err := client.CoreV1().Secrets("kube-bind").Create(ctx, secret, v1.CreateOptions{})
143+
if err != nil {
144+
return nil, false, err
145+
}
146+
return secret, true, nil
147+
}
148+
149+
// Secret exists - update it
118150
var secret *corev1.Secret
119151
if err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
120152
var err error

cli/pkg/kubectl/bind-apiservice/plugin/konnector.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,20 @@ func (b *BindAPIServiceOptions) DeployKonnector(ctx context.Context, config *res
8585
fmt.Fprintf(b.Options.ErrOut, "konnector of %s version already installed, skipping\n", konnectorVersion)
8686
// fall through to CRD test
8787
} else {
88-
konnectorSemVer, err := semver.Parse(strings.TrimLeft(konnectorVersion, "v"))
89-
if err != nil {
90-
return fmt.Errorf("failed to parse konnector SemVer version %q: %w", konnectorVersion, err)
91-
}
92-
bindSemVer, err := semver.Parse(strings.TrimLeft(bindVersion, "v"))
93-
if err != nil {
94-
return fmt.Errorf("failed to parse kubectl-bind SemVer version %q: %w", bindVersion, err)
95-
}
96-
if bindSemVer.GT(konnectorSemVer) {
88+
konnectorSemVer, konnectorErr := semver.Parse(strings.TrimLeft(konnectorVersion, "v"))
89+
bindSemVer, bindErr := semver.Parse(strings.TrimLeft(bindVersion, "v"))
90+
91+
// If either version is not a valid SemVer (e.g., a git hash), skip version comparison
92+
switch {
93+
case konnectorErr != nil || bindErr != nil:
94+
fmt.Fprintf(b.Options.ErrOut, "konnector version %s or bind version %s is not a valid SemVer, skipping version comparison\n", konnectorVersion, bindVersion)
95+
// fall through to CRD test
96+
case bindSemVer.GT(konnectorSemVer):
9797
fmt.Fprintf(b.Options.ErrOut, "Updating konnector from %s to %s.\n", konnectorVersion, bindVersion)
9898
if err := bootstrapKonnector(ctx, discoveryClient, dynamicClient, konnectorImage, b.KonnectorHostAliasParsed); err != nil {
9999
return err
100100
}
101-
} else if bindSemVer.LT(konnectorSemVer) {
101+
case bindSemVer.LT(konnectorSemVer):
102102
fmt.Fprintf(b.Options.ErrOut, "Newer konnector %s installed. To downgrade to %s use --downgrade-konnector.\n", konnectorVersion, bindVersion)
103103
}
104104
}

cli/pkg/kubectl/bind-deploy/plugin/deploy.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ type BindDeployOptions struct {
5959
secretKey string
6060
// file is the path to a file containing the BindingResourceResponse
6161
file string
62+
// kubeconfigSecretName is the name to use for the kubeconfig secret in kube-bind namespace.
63+
// If empty, a generated name (kubeconfig-<random>) will be used.
64+
kubeconfigSecretName string
6265

6366
// skipKonnector skips the deployment of the konnector.
6467
SkipKonnector bool
@@ -93,6 +96,7 @@ func (b *BindDeployOptions) AddCmdFlags(cmd *cobra.Command) {
9396
cmd.Flags().StringVar(&b.secretRef, "secret", b.secretRef, "Reference to a secret containing the BindingResourceResponse (format: namespace/name)")
9497
cmd.Flags().StringVar(&b.secretKey, "secret-key", b.secretKey, "Key in the secret containing the BindingResourceResponse (default: kubeconfig)")
9598
cmd.Flags().StringVarP(&b.file, "file", "f", b.file, "A file with a BindingResourceResponse manifest. Use - to read from stdin")
99+
cmd.Flags().StringVar(&b.kubeconfigSecretName, "provider-kubeconfig-secret-name", b.kubeconfigSecretName, "Name for the kubeconfig secret in kube-bind namespace. If not specified, a generated name will be used")
96100

97101
// Konnector configuration
98102
cmd.Flags().BoolVar(&b.SkipKonnector, "skip-konnector", b.SkipKonnector, "Skip the deployment of the konnector")
@@ -289,10 +293,14 @@ func (b *BindDeployOptions) bindFromKubeconfig(
289293
return nil, fmt.Errorf("failed to create kube client: %w", err)
290294
}
291295

292-
// Find or create the kubeconfig secret
293-
secretName, err := base.FindRemoteKubeconfig(ctx, kubeClient, remoteNamespace, remoteHost)
294-
if err != nil {
295-
return nil, err
296+
// Determine the secret name to use
297+
secretName := b.kubeconfigSecretName
298+
if secretName == "" {
299+
// No name provided, try to find existing secret for this remote
300+
secretName, err = base.FindRemoteKubeconfig(ctx, kubeClient, remoteNamespace, remoteHost)
301+
if err != nil {
302+
return nil, err
303+
}
296304
}
297305

298306
secret, created, err := base.EnsureKubeconfigSecret(ctx, string(response.Kubeconfig), secretName, kubeClient)

contrib/kcp/deploy/resources/apiexport-kube-bind.io.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ spec:
9292
crd: {}
9393
- group: kube-bind.io
9494
name: clusterbindings
95-
schema: v260122-c9f0f376.clusterbindings.kube-bind.io
95+
schema: v260226-fc494c6a.clusterbindings.kube-bind.io
9696
storage:
9797
crd: {}
9898
- group: kube-bind.io

contrib/kcp/deploy/resources/apiresourceschema-clusterbindings.kube-bind.io.yaml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
apiVersion: apis.kcp.io/v1alpha1
22
kind: APIResourceSchema
33
metadata:
4-
name: v260122-c9f0f376.clusterbindings.kube-bind.io
4+
name: v260226-fc494c6a.clusterbindings.kube-bind.io
55
spec:
66
conversion:
77
strategy: None
@@ -295,6 +295,23 @@ spec:
295295
- type
296296
type: object
297297
type: array
298+
consumerSecretRef:
299+
description: |-
300+
consumerSecretRef is the reference to the secret in the consumer cluster
301+
that contains the kubeconfig for connecting to the service provider.
302+
properties:
303+
name:
304+
description: Name of the referent.
305+
minLength: 1
306+
type: string
307+
namespace:
308+
description: Namespace of the referent.
309+
minLength: 1
310+
type: string
311+
required:
312+
- name
313+
- namespace
314+
type: object
298315
heartbeatInterval:
299316
description: |-
300317
heartbeatInterval is the maximal interval between heartbeats that the

deploy/charts/backend/crds/kube-bind.io_clusterbindings.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,23 @@ spec:
298298
- type
299299
type: object
300300
type: array
301+
consumerSecretRef:
302+
description: |-
303+
consumerSecretRef is the reference to the secret in the consumer cluster
304+
that contains the kubeconfig for connecting to the service provider.
305+
properties:
306+
name:
307+
description: Name of the referent.
308+
minLength: 1
309+
type: string
310+
namespace:
311+
description: Namespace of the referent.
312+
minLength: 1
313+
type: string
314+
required:
315+
- name
316+
- namespace
317+
type: object
301318
heartbeatInterval:
302319
description: |-
303320
heartbeatInterval is the maximal interval between heartbeats that the

deploy/crd/kube-bind.io_clusterbindings.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,23 @@ spec:
299299
- type
300300
type: object
301301
type: array
302+
consumerSecretRef:
303+
description: |-
304+
consumerSecretRef is the reference to the secret in the consumer cluster
305+
that contains the kubeconfig for connecting to the service provider.
306+
properties:
307+
name:
308+
description: Name of the referent.
309+
minLength: 1
310+
type: string
311+
namespace:
312+
description: Namespace of the referent.
313+
minLength: 1
314+
type: string
315+
required:
316+
- name
317+
- namespace
318+
type: object
302319
heartbeatInterval:
303320
description: |-
304321
heartbeatInterval is the maximal interval between heartbeats that the

pkg/konnector/controllers/cluster/clusterbinding/clusterbinding_reconcile.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ func (r *reconciler) reconcile(ctx context.Context, binding *kubebindv1alpha2.Cl
5353
errs = append(errs, err)
5454
}
5555

56+
// Must run after ensureConsumerSecret to update the condition based on the provider secret and to set the consumer secret ref in status.
57+
if err := r.ensureConsumerSecretRef(ctx, binding); err != nil {
58+
errs = append(errs, err)
59+
}
60+
5661
if err := r.ensureHeartbeat(ctx, binding); err != nil {
5762
errs = append(errs, err)
5863
}
@@ -75,6 +80,22 @@ func (r *reconciler) ensureHeartbeat(_ context.Context, binding *kubebindv1alpha
7580
return nil
7681
}
7782

83+
func (r *reconciler) ensureConsumerSecretRef(_ context.Context, binding *kubebindv1alpha2.ClusterBinding) error {
84+
consumerSecret, err := r.getConsumerSecret()
85+
if err != nil && !errors.IsNotFound(err) {
86+
return err
87+
}
88+
89+
if consumerSecret != nil {
90+
binding.Status.ConsumerSecretRef = &kubebindv1alpha2.LocalSecretRef{
91+
Name: consumerSecret.Name,
92+
Namespace: consumerSecret.Namespace,
93+
}
94+
}
95+
96+
return nil
97+
}
98+
7899
func (r *reconciler) ensureConsumerSecret(ctx context.Context, binding *kubebindv1alpha2.ClusterBinding) error {
79100
logger := klog.FromContext(ctx)
80101

sdk/apis/kubebind/v1alpha2/clusterbinding_types.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,32 @@ type ClusterBindingStatus struct {
108108
// consumer cluster.
109109
KonnectorVersion string `json:"konnectorVersion,omitempty"`
110110

111+
// consumerSecretRef is the reference to the secret in the consumer cluster
112+
// that contains the kubeconfig for connecting to the service provider.
113+
ConsumerSecretRef *LocalSecretRef `json:"consumerSecretRef,omitempty"`
114+
111115
// conditions is a list of conditions that apply to the ClusterBinding. It is
112116
// updated by the konnector and the service provider.
113117
Conditions conditionsapi.Conditions `json:"conditions,omitempty"`
114118
}
115119

120+
// LocalSecretRef is a reference to a secret in a specific namespace.
121+
type LocalSecretRef struct {
122+
// Name of the referent.
123+
//
124+
// +required
125+
// +kubebuilder:validation:Required
126+
// +kubebuilder:validation:MinLength=1
127+
Name string `json:"name"`
128+
129+
// Namespace of the referent.
130+
//
131+
// +required
132+
// +kubebuilder:validation:Required
133+
// +kubebuilder:validation:MinLength=1
134+
Namespace string `json:"namespace"`
135+
}
136+
116137
// ClusterBindingList is the objects list that represents the ClusterBinding.
117138
//
118139
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

sdk/apis/kubebind/v1alpha2/zz_generated.deepcopy.go

Lines changed: 21 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)