Skip to content

Commit 0ed4ac3

Browse files
committed
wire in hostAlias into cli for dev mode
1 parent 84c2a22 commit 0ed4ac3

20 files changed

Lines changed: 901 additions & 503 deletions

File tree

backend/options/oidc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (options *OIDC) AddFlags(fs *pflag.FlagSet) {
5858
fs.StringVar(&options.CallbackURL, "oidc-callback-url", options.CallbackURL, "OpenID callback URL")
5959
fs.StringVar(&options.AuthorizeURL, "oidc-authorize-url", options.AuthorizeURL, "OpenID authorize URL")
6060
fs.StringVar(&options.CAFile, "oidc-ca-file", options.CAFile, "Path to a CA bundle to use when verifying the OIDC provider's TLS certificate.")
61-
fs.StringVar(&options.Type, "oidc-type", string(options.Type), "Type of OIDC provider (embedded or external)")
61+
fs.StringVar(&options.Type, "oidc-type", options.Type, "Type of OIDC provider (embedded or external)")
6262
}
6363

6464
func (options *OIDC) Complete(listener net.Listener) error {

backend/server.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
"sigs.k8s.io/controller-runtime/pkg/controller"
2929
mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile"
3030

31-
"github.com/davecgh/go-spew/spew"
3231
"github.com/kube-bind/kube-bind/backend/auth"
3332
"github.com/kube-bind/kube-bind/backend/controllers/clusterbinding"
3433
"github.com/kube-bind/kube-bind/backend/controllers/serviceexport"
@@ -208,7 +207,6 @@ func NewServer(ctx context.Context, c *Config) (*Server, error) {
208207

209208
func (s *Server) initializeOIDCProvider(ctx context.Context, callback string) (*auth.OIDCServiceProvider, error) {
210209
logger := klog.FromContext(ctx)
211-
spew.Dump(s.Config.Options.OIDC)
212210
logger.Info("Initializing OIDC Service Provider", "issuerURL", s.Config.Options.OIDC.IssuerURL)
213211
if s.Config.Options.OIDC.TLSConfig != nil {
214212
return auth.NewOIDCServiceProviderWithTLS(

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ type BindAPIServiceOptions struct {
6262
DowngradeKonnector bool
6363
// KonnectorHostAlias is a list of host alias entries to add to the konnector pods.
6464
KonnectorHostAlias []string
65-
// parsed KonnectorHostAlias entries
66-
konnectorHostAlias []corev1.HostAlias
65+
// KonnectorHostAliasParsed is the parsed version of KonnectorHostAlias.
66+
KonnectorHostAliasParsed []corev1.HostAlias
6767

6868
NoBanner bool
6969
DryRun bool
@@ -124,7 +124,7 @@ func (b *BindAPIServiceOptions) Complete(args []string) error {
124124
for _, hostAlias := range b.KonnectorHostAlias {
125125
parts := strings.SplitN(hostAlias, ":", 2)
126126
hostnames := strings.Split(parts[1], ",")
127-
b.konnectorHostAlias = append(b.konnectorHostAlias, corev1.HostAlias{
127+
b.KonnectorHostAliasParsed = append(b.KonnectorHostAliasParsed, corev1.HostAlias{
128128
IP: parts[0],
129129
Hostnames: hostnames,
130130
})
@@ -156,6 +156,8 @@ func (b *BindAPIServiceOptions) Validate() error {
156156
return errors.New("name is required")
157157
}
158158

159+
// TODO(mjudeikis): This code is duplicate fromn bind/plugin/bind.go. Unify.
160+
// validate konnector host alias entries
159161
for _, hostAlias := range b.KonnectorHostAlias {
160162
parts := strings.SplitN(hostAlias, ":", 2)
161163
if len(parts) != 2 {
@@ -186,7 +188,7 @@ func (b *BindAPIServiceOptions) Run(ctx context.Context) error {
186188
IOStreams: b.Options.IOStreams,
187189
SkipKonnector: b.SkipKonnector,
188190
KonnectorImageOverride: b.KonnectorImageOverride,
189-
KonnectorHostAlias: b.konnectorHostAlias,
191+
KonnectorHostAliasParsed: b.KonnectorHostAliasParsed,
190192
DowngradeKonnector: b.DowngradeKonnector,
191193
RemoteKubeconfigFile: b.remoteKubeconfigFile,
192194
RemoteKubeconfigNamespace: b.remoteKubeconfigNamespace,

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type BinderOptions struct {
3939
IOStreams genericclioptions.IOStreams
4040
SkipKonnector bool
4141
KonnectorImageOverride string
42-
KonnectorHostAlias []corev1.HostAlias
42+
KonnectorHostAliasParsed []corev1.HostAlias
4343
DowngradeKonnector bool
4444
RemoteKubeconfigFile string
4545
RemoteKubeconfigNamespace string
@@ -278,12 +278,12 @@ func (b *Binder) getRemoteKubeconfig(ctx context.Context, namespace, name string
278278

279279
func (b *Binder) deployKonnector(ctx context.Context) error {
280280
tempOpts := &BindAPIServiceOptions{
281-
Options: &base.Options{IOStreams: b.opts.IOStreams},
282-
SkipKonnector: b.opts.SkipKonnector,
283-
KonnectorImageOverride: b.opts.KonnectorImageOverride,
284-
DowngradeKonnector: b.opts.DowngradeKonnector,
285-
DryRun: b.opts.DryRun,
286-
konnectorHostAlias: b.opts.KonnectorHostAlias,
281+
Options: &base.Options{IOStreams: b.opts.IOStreams},
282+
SkipKonnector: b.opts.SkipKonnector,
283+
KonnectorImageOverride: b.opts.KonnectorImageOverride,
284+
DowngradeKonnector: b.opts.DowngradeKonnector,
285+
DryRun: b.opts.DryRun,
286+
KonnectorHostAliasParsed: b.opts.KonnectorHostAliasParsed,
287287
}
288288
return tempOpts.deployKonnector(ctx, b.config)
289289
}
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
/*
2+
Copyright 2025 The Kube Bind Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package plugin
18+
19+
import (
20+
"context"
21+
22+
appsv1 "k8s.io/api/apps/v1"
23+
corev1 "k8s.io/api/core/v1"
24+
rbacv1 "k8s.io/api/rbac/v1"
25+
"k8s.io/apimachinery/pkg/api/errors"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28+
"k8s.io/apimachinery/pkg/runtime"
29+
"k8s.io/apimachinery/pkg/runtime/schema"
30+
"k8s.io/apimachinery/pkg/util/intstr"
31+
"k8s.io/client-go/discovery"
32+
"k8s.io/client-go/dynamic"
33+
)
34+
35+
const (
36+
KonnectorNamespace = "kube-bind"
37+
KonnectorAppName = "konnector"
38+
KonnectorServiceAccount = "konnector"
39+
KonnectorClusterRole = "kube-bind-konnector"
40+
KonnectorClusterRoleBinding = "kube-bind-konnector"
41+
)
42+
43+
func bootstrapKonnector(
44+
ctx context.Context,
45+
discoveryClient discovery.DiscoveryInterface,
46+
dynamicClient dynamic.Interface,
47+
image string,
48+
hostAliases []corev1.HostAlias,
49+
) error {
50+
resources := getAllKonnectorResources(image, hostAliases)
51+
52+
for _, resource := range resources {
53+
if err := applyResource(ctx, dynamicClient, discoveryClient, resource); err != nil {
54+
return err
55+
}
56+
}
57+
58+
return nil
59+
}
60+
61+
// getAllKonnectorResources returns all konnector resources needed for deployment
62+
func getAllKonnectorResources(image string, hostAliases []corev1.HostAlias) []interface{} {
63+
return []interface{}{
64+
getKonnectorNamespace(),
65+
getKonnectorServiceAccount(),
66+
getKonnectorClusterRole(),
67+
getKonnectorClusterRoleBinding(),
68+
getKonnectorDeployment(image, hostAliases),
69+
}
70+
}
71+
72+
// getKonnectorNamespace returns the namespace for konnector deployment
73+
func getKonnectorNamespace() *corev1.Namespace {
74+
return &corev1.Namespace{
75+
TypeMeta: metav1.TypeMeta{
76+
APIVersion: "v1",
77+
Kind: "Namespace",
78+
},
79+
ObjectMeta: metav1.ObjectMeta{
80+
Name: KonnectorNamespace,
81+
},
82+
}
83+
}
84+
85+
// getKonnectorServiceAccount returns the service account for konnector
86+
func getKonnectorServiceAccount() *corev1.ServiceAccount {
87+
return &corev1.ServiceAccount{
88+
TypeMeta: metav1.TypeMeta{
89+
APIVersion: "v1",
90+
Kind: "ServiceAccount",
91+
},
92+
ObjectMeta: metav1.ObjectMeta{
93+
Name: KonnectorServiceAccount,
94+
Namespace: KonnectorNamespace,
95+
},
96+
}
97+
}
98+
99+
// getKonnectorClusterRole returns the cluster role for konnector
100+
func getKonnectorClusterRole() *rbacv1.ClusterRole {
101+
return &rbacv1.ClusterRole{
102+
TypeMeta: metav1.TypeMeta{
103+
APIVersion: "rbac.authorization.k8s.io/v1",
104+
Kind: "ClusterRole",
105+
},
106+
ObjectMeta: metav1.ObjectMeta{
107+
Name: KonnectorClusterRole,
108+
},
109+
Rules: []rbacv1.PolicyRule{
110+
{
111+
APIGroups: []string{"*"},
112+
Resources: []string{"*"},
113+
Verbs: []string{"*"},
114+
},
115+
},
116+
}
117+
}
118+
119+
// getKonnectorClusterRoleBinding returns the cluster role binding for konnector
120+
func getKonnectorClusterRoleBinding() *rbacv1.ClusterRoleBinding {
121+
return &rbacv1.ClusterRoleBinding{
122+
TypeMeta: metav1.TypeMeta{
123+
APIVersion: "rbac.authorization.k8s.io/v1",
124+
Kind: "ClusterRoleBinding",
125+
},
126+
ObjectMeta: metav1.ObjectMeta{
127+
Name: KonnectorClusterRoleBinding,
128+
},
129+
RoleRef: rbacv1.RoleRef{
130+
APIGroup: "rbac.authorization.k8s.io",
131+
Kind: "ClusterRole",
132+
Name: KonnectorClusterRole,
133+
},
134+
Subjects: []rbacv1.Subject{
135+
{
136+
Kind: "ServiceAccount",
137+
Name: KonnectorServiceAccount,
138+
Namespace: KonnectorNamespace,
139+
},
140+
},
141+
}
142+
}
143+
144+
// getKonnectorDeployment returns the deployment for konnector
145+
func getKonnectorDeployment(image string, hostAliases []corev1.HostAlias) *appsv1.Deployment {
146+
replicas := int32(2)
147+
148+
return &appsv1.Deployment{
149+
TypeMeta: metav1.TypeMeta{
150+
APIVersion: "apps/v1",
151+
Kind: "Deployment",
152+
},
153+
ObjectMeta: metav1.ObjectMeta{
154+
Name: KonnectorAppName,
155+
Namespace: KonnectorNamespace,
156+
Labels: map[string]string{
157+
"app": KonnectorAppName,
158+
},
159+
},
160+
Spec: appsv1.DeploymentSpec{
161+
Replicas: &replicas,
162+
Selector: &metav1.LabelSelector{
163+
MatchLabels: map[string]string{
164+
"app": KonnectorAppName,
165+
},
166+
},
167+
Template: corev1.PodTemplateSpec{
168+
ObjectMeta: metav1.ObjectMeta{
169+
Labels: map[string]string{
170+
"app": KonnectorAppName,
171+
},
172+
},
173+
Spec: corev1.PodSpec{
174+
RestartPolicy: corev1.RestartPolicyAlways,
175+
ServiceAccountName: KonnectorServiceAccount,
176+
HostAliases: hostAliases,
177+
Containers: []corev1.Container{
178+
{
179+
Name: KonnectorAppName,
180+
Image: image,
181+
Env: []corev1.EnvVar{
182+
{
183+
Name: "POD_NAME",
184+
ValueFrom: &corev1.EnvVarSource{
185+
FieldRef: &corev1.ObjectFieldSelector{
186+
FieldPath: "metadata.name",
187+
},
188+
},
189+
},
190+
{
191+
Name: "POD_NAMESPACE",
192+
ValueFrom: &corev1.EnvVarSource{
193+
FieldRef: &corev1.ObjectFieldSelector{
194+
FieldPath: "metadata.namespace",
195+
},
196+
},
197+
},
198+
},
199+
ReadinessProbe: &corev1.Probe{
200+
ProbeHandler: corev1.ProbeHandler{
201+
HTTPGet: &corev1.HTTPGetAction{
202+
Path: "/healthz",
203+
Port: intstr.FromInt(8090),
204+
},
205+
},
206+
},
207+
},
208+
},
209+
},
210+
},
211+
},
212+
}
213+
}
214+
215+
func applyResource(ctx context.Context, dynamicClient dynamic.Interface, discoveryClient discovery.DiscoveryInterface, obj interface{}) error {
216+
runtimeObj, ok := obj.(runtime.Object)
217+
if !ok {
218+
return nil
219+
}
220+
221+
// Convert to unstructured
222+
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(runtimeObj)
223+
if err != nil {
224+
return err
225+
}
226+
227+
// Extract metadata
228+
metadata, ok := unstructuredObj["metadata"].(map[string]interface{})
229+
if !ok {
230+
return nil
231+
}
232+
233+
name, _ := metadata["name"].(string)
234+
namespace, _ := metadata["namespace"].(string)
235+
236+
// Get GVK information
237+
gvk := runtimeObj.GetObjectKind().GroupVersionKind()
238+
239+
// Get GVR from discovery
240+
gvr := getGVRFromGVK(gvk)
241+
242+
// Apply the resource
243+
var resourceClient dynamic.ResourceInterface
244+
if namespace != "" {
245+
resourceClient = dynamicClient.Resource(gvr).Namespace(namespace)
246+
} else {
247+
resourceClient = dynamicClient.Resource(gvr)
248+
}
249+
250+
// Try to get existing resource
251+
_, err = resourceClient.Get(ctx, name, metav1.GetOptions{})
252+
if err != nil {
253+
if errors.IsNotFound(err) {
254+
// Create new resource
255+
_, err = resourceClient.Create(ctx, &unstructured.Unstructured{Object: unstructuredObj}, metav1.CreateOptions{})
256+
return err
257+
}
258+
return err
259+
}
260+
261+
// Update existing resource
262+
_, err = resourceClient.Update(ctx, &unstructured.Unstructured{Object: unstructuredObj}, metav1.UpdateOptions{})
263+
return err
264+
}
265+
266+
func getGVRFromGVK(gvk schema.GroupVersionKind) schema.GroupVersionResource {
267+
gvkMap := map[schema.GroupVersionKind]schema.GroupVersionResource{
268+
{Group: "", Version: "v1", Kind: "Namespace"}: {
269+
Group: "",
270+
Version: "v1",
271+
Resource: "namespaces",
272+
},
273+
{Group: "", Version: "v1", Kind: "ServiceAccount"}: {
274+
Group: "",
275+
Version: "v1",
276+
Resource: "serviceaccounts",
277+
},
278+
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRole"}: {
279+
Group: "rbac.authorization.k8s.io",
280+
Version: "v1",
281+
Resource: "clusterroles",
282+
},
283+
{Group: "rbac.authorization.k8s.io", Version: "v1", Kind: "ClusterRoleBinding"}: {
284+
Group: "rbac.authorization.k8s.io",
285+
Version: "v1",
286+
Resource: "clusterrolebindings",
287+
},
288+
{Group: "apps", Version: "v1", Kind: "Deployment"}: {
289+
Group: "apps",
290+
Version: "v1",
291+
Resource: "deployments",
292+
},
293+
}
294+
if gvr, found := gvkMap[gvk]; found {
295+
return gvr
296+
}
297+
298+
return schema.GroupVersionResource{}
299+
}

0 commit comments

Comments
 (0)