Skip to content

feat: add httpproxy external patch #115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
44 changes: 44 additions & 0 deletions docs/content/http-proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: "HTTP proxy for CAPI components"
---

In some network environments it is necessary to use HTTP proxy to successfuly execute HTTP requests.
To configure Kubernetes components (`containerd`, `kubelet`) to use HTTP proxy use the `http-proxy`
external patch that will generate appropriate configuration for control plane and worker nodes.

To enable the http proxy enable the `http-proxy` external patch on `ClusterClass`.

```yaml
apiVersion: cluster.x-k8s.io/v1beta1
kind: ClusterClass
metadata:
name: <NAME>
spec:
patches:
- name: http-proxy
external:
generateExtension: "http-proxy-patch.<external-config-name>"
discoverVariablesExtension: "http-proxy-vars.<external-config-name>"
```

On the cluster resource then specify desired HTTP proxy values:

```yaml
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: <NAME>
spec:
topology:
variables:
name: proxy
values:
http: http://example.com
https: http://example.com
no:
- http://no-proxy-1.example.com
- http://no-proxy-2.example.com
```

Applying this configuration will result in new bootstrap files on the `KubeadmControlPlaneTemplate`
and `KubeadmConfigTemplate`.
2 changes: 1 addition & 1 deletion docs/content/service-loadbalancer-gc.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ This hook is enabled by default, and can be explicitly disabled by omitting the
If deploying via Helm, then this can be disabled by setting `handlers.ServiceLoadBalancerGC.enabled=false`.

By default, all clusters will be cleaned up when deleting, but this can be opted out from by setting the annotation
`capiext.labs.d2iq.io//loadbalancer-gc=false`.
`capiext.labs.d2iq.io/loadbalancer-gc=false`.
11 changes: 8 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ go 1.20

require (
github.com/go-logr/logr v1.2.4
github.com/onsi/gomega v1.27.8
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
golang.org/x/sync v0.3.0
gomodules.xyz/jsonpatch/v2 v2.3.0
k8s.io/api v0.28.0
k8s.io/apiextensions-apiserver v0.27.2
k8s.io/apimachinery v0.28.0
k8s.io/client-go v0.28.0
k8s.io/component-base v0.28.0
Expand All @@ -25,7 +28,10 @@ require (
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coredns/caddy v1.1.0 // indirect
github.com/coredns/corefile-migration v1.0.20 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
Expand All @@ -50,27 +56,26 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/gomega v1.27.8 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
golang.org/x/net v0.13.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/time v0.3.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.27.2 // indirect
k8s.io/cluster-bootstrap v0.27.2 // indirect
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
Expand Down
265 changes: 265 additions & 0 deletions go.sum

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions internal/runtimehooks/webhooks/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (

"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers"
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/cni/calico"
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/httpproxyconfig"
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/name"
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/servicelbgc"
)

Expand Down Expand Up @@ -105,9 +107,12 @@ func (s *Server) Start(ctx context.Context) error {
return err
}

httProxyConfig := httpproxyconfig.New()
allHandlers := []handlers.NamedHandler{
servicelbgc.New(client),
calico.New(client, *s.calicoCNIConfig),
name.NewDiscoveryVariables(name.Suffix("vars"), httProxyConfig),
name.NewGeneratePatches(name.Suffix("patch"), httProxyConfig),
}

for idx := range allHandlers {
Expand Down
150 changes: 150 additions & 0 deletions pkg/handlers/httpproxyconfig/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright 2023 D2iQ, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package httpproxyconfig

import (
"context"
"fmt"

apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
"sigs.k8s.io/cluster-api/exp/runtime/topologymutation"

"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers"
)

const (
// VariableName is http proxy external patch variable name.
VariableName = "proxy"
)

type httpProxyConfigHandler struct {
decoder runtime.Decoder
generator *systemdConfigGenerator
}

var (
_ handlers.NamedHandler = &httpProxyConfigHandler{}
_ handlers.DiscoverVariablesMutationHandler = &httpProxyConfigHandler{}
_ handlers.GeneratePatchesMutationHandler = &httpProxyConfigHandler{}
)

func New() *httpProxyConfigHandler {
scheme := runtime.NewScheme()
_ = bootstrapv1.AddToScheme(scheme)
_ = controlplanev1.AddToScheme(scheme)
return &httpProxyConfigHandler{
decoder: serializer.NewCodecFactory(scheme).UniversalDecoder(
controlplanev1.GroupVersion,
bootstrapv1.GroupVersion,
),
generator: &systemdConfigGenerator{
template: templates.Lookup("systemd.conf.tmpl"),
},
}
}

func (h *httpProxyConfigHandler) Name() string {
return "http-proxy"
}

func (h *httpProxyConfigHandler) GeneratePatches(
ctx context.Context,
req *runtimehooksv1.GeneratePatchesRequest,
resp *runtimehooksv1.GeneratePatchesResponse,
) {
topologymutation.WalkTemplates(
ctx,
h.decoder,
req,
resp,
func(ctx context.Context, obj runtime.Object, variables map[string]apiextensionsv1.JSON, holderRef runtimehooksv1.HolderReference) error {
httpProxyVariable, found, err := GetVariable[HTTPProxyVariables](
variables,
VariableName,
)
if err != nil {
return err
}
if !found {
return fmt.Errorf("missing variable %q value", VariableName)
}

controlPlaneSelector := clusterv1.PatchSelector{
APIVersion: controlplanev1.GroupVersion.String(),
Kind: "KubeadmControlPlaneTemplate",
MatchResources: clusterv1.PatchSelectorMatch{
ControlPlane: true,
},
}
if err := generatePatch(obj, variables, holderRef, controlPlaneSelector, func(obj *controlplanev1.KubeadmControlPlaneTemplate) error {
var err error
obj.Spec.Template.Spec.KubeadmConfigSpec.Files, err = h.generator.AddSystemdFiles(
httpProxyVariable, obj.Spec.Template.Spec.KubeadmConfigSpec.Files)
return err
}); err != nil {
return err
}

defaultWorkerSelector := clusterv1.PatchSelector{
APIVersion: bootstrapv1.GroupVersion.String(),
Kind: "KubeadmConfigTemplate",
MatchResources: clusterv1.PatchSelectorMatch{
MachineDeploymentClass: &clusterv1.PatchSelectorMatchMachineDeploymentClass{
Names: []string{
"default-worker",
},
},
},
}
if err := generatePatch(obj, variables, holderRef, defaultWorkerSelector, func(obj *bootstrapv1.KubeadmConfigTemplate) error {
var err error
obj.Spec.Template.Spec.Files, err = h.generator.AddSystemdFiles(httpProxyVariable, obj.Spec.Template.Spec.Files)
return err
}); err != nil {
return err
}

return nil
},
)
}

func (h *httpProxyConfigHandler) DiscoverVariables(
ctx context.Context,
_ *runtimehooksv1.DiscoverVariablesRequest,
resp *runtimehooksv1.DiscoverVariablesResponse,
) {
variable := HTTPProxyVariables{}
resp.Variables = append(resp.Variables, clusterv1.ClusterClassVariable{
Name: VariableName,
Required: false,
Schema: variable.VariableSchema(),
})
resp.SetStatus(runtimehooksv1.ResponseStatusSuccess)
}

func generatePatch[T runtime.Object](
obj runtime.Object,
variables map[string]apiextensionsv1.JSON,
holderRef runtimehooksv1.HolderReference,
patchSelector clusterv1.PatchSelector,
mutFn func(T) error,
) error {
typed, ok := obj.(T)
if !ok {
return nil
}

if !matchSelector(patchSelector, obj, holderRef, variables) {
return nil
}

return mutFn(typed)
}
Loading