Skip to content

Commit

Permalink
Group feature implementations in a swappable interface (#417)
Browse files Browse the repository at this point in the history
* Move features to subpackages

* Group features behind a main implementation
  • Loading branch information
neoaggelos authored May 16, 2024
1 parent 004575e commit 723e369
Show file tree
Hide file tree
Showing 17 changed files with 227 additions and 105 deletions.
14 changes: 7 additions & 7 deletions src/k8s/pkg/k8sd/controllers/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,31 @@ func (c *FeatureController) Run(ctx context.Context, getClusterConfig func(conte
c.waitReady()

go c.reconcileLoop(ctx, getClusterConfig, "network", c.triggerNetworkCh, c.reconciledNetworkCh, func(cfg types.ClusterConfig) error {
return features.ApplyNetwork(ctx, c.snap, cfg.Network)
return features.Implementation.ApplyNetwork(ctx, c.snap, cfg.Network)
})

go c.reconcileLoop(ctx, getClusterConfig, "gateway", c.triggerGatewayCh, c.reconciledGatewayCh, func(cfg types.ClusterConfig) error {
return features.ApplyGateway(ctx, c.snap, cfg.Gateway, cfg.Network)
return features.Implementation.ApplyGateway(ctx, c.snap, cfg.Gateway, cfg.Network)
})

go c.reconcileLoop(ctx, getClusterConfig, "ingress", c.triggerIngressCh, c.reconciledIngressCh, func(cfg types.ClusterConfig) error {
return features.ApplyIngress(ctx, c.snap, cfg.Ingress, cfg.Network)
return features.Implementation.ApplyIngress(ctx, c.snap, cfg.Ingress, cfg.Network)
})

go c.reconcileLoop(ctx, getClusterConfig, "load balancer", c.triggerLoadBalancerCh, c.reconciledLoadBalancerCh, func(cfg types.ClusterConfig) error {
return features.ApplyLoadBalancer(ctx, c.snap, cfg.LoadBalancer, cfg.Network)
return features.Implementation.ApplyLoadBalancer(ctx, c.snap, cfg.LoadBalancer, cfg.Network)
})

go c.reconcileLoop(ctx, getClusterConfig, "local storage", c.triggerLocalStorageCh, c.reconciledLocalStorageCh, func(cfg types.ClusterConfig) error {
return features.ApplyLocalStorage(ctx, c.snap, cfg.LocalStorage)
return features.Implementation.ApplyLocalStorage(ctx, c.snap, cfg.LocalStorage)
})

go c.reconcileLoop(ctx, getClusterConfig, "metrics server", c.triggerMetricsServerCh, c.reconciledMetricsServerCh, func(cfg types.ClusterConfig) error {
return features.ApplyMetricsServer(ctx, c.snap, cfg.MetricsServer)
return features.Implementation.ApplyMetricsServer(ctx, c.snap, cfg.MetricsServer)
})

go c.reconcileLoop(ctx, getClusterConfig, "DNS", c.triggerDNSCh, c.reconciledDNSCh, func(cfg types.ClusterConfig) error {
if dnsIP, err := features.ApplyDNS(ctx, c.snap, cfg.DNS, cfg.Kubelet); err != nil {
if dnsIP, err := features.Implementation.ApplyDNS(ctx, c.snap, cfg.DNS, cfg.Kubelet); err != nil {
return fmt.Errorf("failed to apply DNS configuration: %w", err)
} else if dnsIP != "" {
if err := notifyDNSChangedIP(ctx, dnsIP); err != nil {
Expand Down
42 changes: 42 additions & 0 deletions src/k8s/pkg/k8sd/features/cilium/chart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cilium

import (
"path"

"github.com/canonical/k8s/pkg/client/helm"
)

var (
// chartCilium represents manifests to deploy Cilium.
chartCilium = helm.InstallableChart{
Name: "ck-network",
Namespace: "kube-system",
ManifestPath: path.Join("charts", "cilium-1.15.2.tgz"),
}

// chartCiliumLoadBalancer represents manifests to deploy Cilium LoadBalancer resources.
chartCiliumLoadBalancer = helm.InstallableChart{
Name: "ck-loadbalancer",
Namespace: "kube-system",
ManifestPath: path.Join("charts", "ck-loadbalancer"),
}

// chartGateway represents manifests to deploy Gateway API CRDs.
chartGateway = helm.InstallableChart{
Name: "ck-gateway",
Namespace: "kube-system",
ManifestPath: path.Join("charts", "gateway-api-1.0.0.tgz"),
}

// ciliumAgentImageRepo represents the image to use for cilium-agent.
ciliumAgentImageRepo = "ghcr.io/canonical/cilium"

// ciliumAgentImageTag is the tag to use for the cilium-agent image.
ciliumAgentImageTag = "1.15.2-ck1"

// ciliumOperatorImageRepo is the image to use for cilium-operator.
ciliumOperatorImageRepository = "ghcr.io/canonical/cilium-operator"

// ciliumOperatorImageTag is the tag to use for the cilium-operator image.
ciliumOperatorImageTag = "1.15.2-ck1"
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package features
package cilium

import (
"context"
Expand All @@ -9,7 +9,6 @@ import (
"github.com/canonical/k8s/pkg/snap"
)

// ApplyGateway is used to configure the gateway feature on Canonical Kubernetes.
// ApplyGateway assumes that the managed Cilium CNI is already installed on the cluster. It will fail if that is not the case.
// ApplyGateway will deploy the Gateway API CRDs on the cluster and enable the GatewayAPI controllers on Cilium, when gateway.Enabled is true.
// ApplyGateway will remove the Gateway API CRDs from the cluster and disable the GatewayAPI controllers on Cilium, when gateway.Enabled is false.
Expand All @@ -18,7 +17,7 @@ import (
func ApplyGateway(ctx context.Context, snap snap.Snap, gateway types.Gateway, network types.Network) error {
m := snap.HelmClient()

if _, err := m.Apply(ctx, chartCiliumGateway, helm.StatePresentOrDeleted(gateway.GetEnabled()), nil); err != nil {
if _, err := m.Apply(ctx, chartGateway, helm.StatePresentOrDeleted(gateway.GetEnabled()), nil); err != nil {
return fmt.Errorf("failed to install Gateway API CRDs: %w", err)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package features
package cilium

import (
"context"
Expand All @@ -9,7 +9,6 @@ import (
"github.com/canonical/k8s/pkg/snap"
)

// ApplyIngress is used to configure the ingress controller feature on Canonical Kubernetes.
// ApplyIngress assumes that the managed Cilium CNI is already installed on the cluster. It will fail if that is not the case.
// ApplyIngress will enable Cilium's ingress controller when ingress.Enabled is true.
// ApplyIngress will disable Cilium's ingress controller when ingress.Disabled is false.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package features
package cilium

import (
"context"
Expand All @@ -10,7 +10,6 @@ import (
"github.com/canonical/k8s/pkg/utils/control"
)

// ApplyLoadBalancer is used to configure the load-balancer feature on Canonical Kubernetes.
// ApplyLoadBalancer assumes that the managed Cilium CNI is already installed on the cluster. It will fail if that is not the case.
// ApplyLoadBalancer will configure Cilium to enable L2 or BGP mode, and deploy necessary CRs for announcing the LoadBalancer external IPs when loadbalancer.Enabled is true.
// ApplyLoadBalancer will disable L2 and BGP on Cilium, and remove any previously created CRs when loadbalancer.Enabled is false.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package features
package cilium

import (
"context"
Expand All @@ -14,7 +14,6 @@ import (
"github.com/canonical/k8s/pkg/utils/control"
)

// ApplyNetwork is used to configure the CNI feature on Canonical Kubernetes.
// ApplyNetwork will deploy Cilium when cfg.Enabled is true.
// ApplyNetwork will remove Cilium when cfg.Enabled is false.
// ApplyNetwork requires that bpf and cgroups2 are already mounted and available when running under strict snap confinement. If they are not, it will fail (since Cilium will not have the required permissions to mount them).
Expand Down Expand Up @@ -53,7 +52,7 @@ func ApplyNetwork(ctx context.Context, snap snap.Snap, cfg types.Network) error

values := map[string]any{
"image": map[string]any{
"repository": ciliumAgentImageRepository,
"repository": ciliumAgentImageRepo,
"tag": ciliumAgentImageTag,
"useDigest": false,
},
Expand Down
22 changes: 22 additions & 0 deletions src/k8s/pkg/k8sd/features/coredns/chart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package coredns

import (
"path"

"github.com/canonical/k8s/pkg/client/helm"
)

var (
// chartCoreDNS represents manifests to deploy CoreDNS.
chart = helm.InstallableChart{
Name: "ck-dns",
Namespace: "kube-system",
ManifestPath: path.Join("charts", "coredns-1.29.0.tgz"),
}

// imageRepo is the image to use for CoreDNS.
imageRepo = "ghcr.io/canonical/coredns"

// imageTag is the tag to use for the CoreDNS image.
imageTag = "1.11.1-ck4"
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package features
package coredns

import (
"context"
Expand All @@ -10,7 +10,6 @@ import (
"github.com/canonical/k8s/pkg/snap"
)

// ApplyDNS is used to configure the DNS feature on Canonical Kubernetes.
// ApplyDNS manages the deployment of CoreDNS, with customization options from dns and kubelet, which are retrieved from the cluster configuration.
// ApplyDNS will uninstall CoreDNS from the cluster if dns.Enabled is false.
// ApplyDNS will install or refresh CoreDNS if dns.Enabled is true.
Expand All @@ -20,16 +19,16 @@ func ApplyDNS(ctx context.Context, snap snap.Snap, dns types.DNS, kubelet types.
m := snap.HelmClient()

if !dns.GetEnabled() {
if _, err := m.Apply(ctx, chartCoreDNS, helm.StateDeleted, nil); err != nil {
if _, err := m.Apply(ctx, chart, helm.StateDeleted, nil); err != nil {
return "", fmt.Errorf("failed to uninstall coredns: %w", err)
}
return "", nil
}

values := map[string]any{
"image": map[string]any{
"repository": dnsImageRepository,
"tag": dnsImageTag,
"repository": imageRepo,
"tag": imageTag,
},
"service": map[string]any{
"name": "coredns",
Expand Down Expand Up @@ -64,7 +63,7 @@ func ApplyDNS(ctx context.Context, snap snap.Snap, dns types.DNS, kubelet types.
},
}

if _, err := m.Apply(ctx, chartCoreDNS, helm.StatePresent, values); err != nil {
if _, err := m.Apply(ctx, chart, helm.StatePresent, values); err != nil {
return "", fmt.Errorf("failed to apply coredns: %w", err)
}

Expand Down
51 changes: 0 additions & 51 deletions src/k8s/pkg/k8sd/features/features.go

This file was deleted.

16 changes: 0 additions & 16 deletions src/k8s/pkg/k8sd/features/images.go

This file was deleted.

23 changes: 23 additions & 0 deletions src/k8s/pkg/k8sd/features/implementation_default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package features

import (
"github.com/canonical/k8s/pkg/k8sd/features/cilium"
"github.com/canonical/k8s/pkg/k8sd/features/coredns"
"github.com/canonical/k8s/pkg/k8sd/features/localpv"
metrics_server "github.com/canonical/k8s/pkg/k8sd/features/metrics-server"
)

// Default implements the Canonical Kubernetes built-in features.
// Cilium is used for networking (network + load-balancer + ingress + gateway).
// CoreDNS is used for DNS.
// MetricsServer is used for metrics-server.
// LocalPV Rawfile CSI is used for local-storage.
var Implementation Interface = &implementation{
applyDNS: coredns.ApplyDNS,
applyNetwork: cilium.ApplyNetwork,
applyLoadBalancer: cilium.ApplyLoadBalancer,
applyIngress: cilium.ApplyIngress,
applyGateway: cilium.ApplyGateway,
applyMetricsServer: metrics_server.ApplyMetricsServer,
applyLocalStorage: localpv.ApplyLocalStorage,
}
65 changes: 65 additions & 0 deletions src/k8s/pkg/k8sd/features/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package features

import (
"context"

"github.com/canonical/k8s/pkg/k8sd/types"
"github.com/canonical/k8s/pkg/snap"
)

// Interface abstracts the management of built-in Canonical Kubernetes features.
type Interface interface {
// ApplyDNS is used to configure the DNS feature on Canonical Kubernetes.
ApplyDNS(context.Context, snap.Snap, types.DNS, types.Kubelet) (string, error)
// ApplyNetwork is used to configure the network feature on Canonical Kubernetes.
ApplyNetwork(context.Context, snap.Snap, types.Network) error
// ApplyLoadBalancer is used to configure the load-balancer feature on Canonical Kubernetes.
ApplyLoadBalancer(context.Context, snap.Snap, types.LoadBalancer, types.Network) error
// ApplyIngress is used to configure the ingress controller feature on Canonical Kubernetes.
ApplyIngress(context.Context, snap.Snap, types.Ingress, types.Network) error
// ApplyGateway is used to configure the gateway feature on Canonical Kubernetes.
ApplyGateway(context.Context, snap.Snap, types.Gateway, types.Network) error
// ApplyMetricsServer is used to configure the metrics-server feature on Canonical Kubernetes.
ApplyMetricsServer(context.Context, snap.Snap, types.MetricsServer) error
// ApplyLocalStorage is used to configure the Local Storage feature on Canonical Kubernetes.
ApplyLocalStorage(context.Context, snap.Snap, types.LocalStorage) error
}

// implementation implements Interface.
type implementation struct {
applyDNS func(context.Context, snap.Snap, types.DNS, types.Kubelet) (string, error)
applyNetwork func(context.Context, snap.Snap, types.Network) error
applyLoadBalancer func(context.Context, snap.Snap, types.LoadBalancer, types.Network) error
applyIngress func(context.Context, snap.Snap, types.Ingress, types.Network) error
applyGateway func(context.Context, snap.Snap, types.Gateway, types.Network) error
applyMetricsServer func(context.Context, snap.Snap, types.MetricsServer) error
applyLocalStorage func(context.Context, snap.Snap, types.LocalStorage) error
}

func (i *implementation) ApplyDNS(ctx context.Context, snap snap.Snap, dns types.DNS, kubelet types.Kubelet) (string, error) {
return i.applyDNS(ctx, snap, dns, kubelet)
}

func (i *implementation) ApplyNetwork(ctx context.Context, snap snap.Snap, cfg types.Network) error {
return i.applyNetwork(ctx, snap, cfg)
}

func (i *implementation) ApplyLoadBalancer(ctx context.Context, snap snap.Snap, loadbalancer types.LoadBalancer, network types.Network) error {
return i.applyLoadBalancer(ctx, snap, loadbalancer, network)
}

func (i *implementation) ApplyIngress(ctx context.Context, snap snap.Snap, ingress types.Ingress, network types.Network) error {
return i.applyIngress(ctx, snap, ingress, network)
}

func (i *implementation) ApplyGateway(ctx context.Context, snap snap.Snap, gateway types.Gateway, network types.Network) error {
return i.applyGateway(ctx, snap, gateway, network)
}

func (i *implementation) ApplyMetricsServer(ctx context.Context, snap snap.Snap, cfg types.MetricsServer) error {
return i.applyMetricsServer(ctx, snap, cfg)
}

func (i *implementation) ApplyLocalStorage(ctx context.Context, snap snap.Snap, cfg types.LocalStorage) error {
return i.applyLocalStorage(ctx, snap, cfg)
}
Loading

0 comments on commit 723e369

Please sign in to comment.