Skip to content
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

Make provider support more modular #795

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ COPY go.sum go.sum
RUN go mod download

# Copy the go source
COPY cmd/main.go cmd/main.go
COPY cmd/app.go cmd/app.go
COPY api/ api/
COPY internal/ internal/
COPY pkg/ pkg/

# Build
# the GOARCH has not a default value to allow the binary be built according to the host where the command
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -ldflags="${LD_FLAGS}" -a -o manager cmd/main.go
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -ldflags="${LD_FLAGS}" -a -o manager cmd/app.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,11 @@ LD_FLAGS += -X github.com/K0rdent/kcm/internal/telemetry.segmentToken=$(SEGMENT_

.PHONY: build
build: generate-all ## Build manager binary.
go build -ldflags="${LD_FLAGS}" -o bin/manager cmd/main.go
go build -ldflags="${LD_FLAGS}" -o bin/manager cmd/app.go

.PHONY: run
run: generate-all ## Run a controller from your host.
go run ./cmd/main.go
go run ./cmd/app.go

# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
Expand Down
8 changes: 0 additions & 8 deletions api/v1alpha1/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,6 @@ type (
)

const (
// Provider CAPA
ProviderAWSName = "cluster-api-provider-aws"
// Provider Azure
ProviderAzureName = "cluster-api-provider-azure"
// Provider vSphere
ProviderVSphereName = "cluster-api-provider-vsphere"
// Provider OpenStack
ProviderOpenStackName = "cluster-api-provider-openstack"
// Provider K0smotron
ProviderK0smotronName = "k0smotron"
// Provider Sveltos
Expand Down
15 changes: 4 additions & 11 deletions api/v1alpha1/management_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,17 @@ type Provider struct {
Name string `json:"name"`
}

func (p Provider) String() string {
return p.Name
}

func (in *Component) HelmValues() (values map[string]any, err error) {
if in.Config != nil {
err = yaml.Unmarshal(in.Config.Raw, &values)
}
return values, err
}

func GetDefaultProviders() []Provider {
return []Provider{
{Name: ProviderK0smotronName},
{Name: ProviderAWSName},
{Name: ProviderAzureName},
{Name: ProviderVSphereName},
{Name: ProviderOpenStackName},
{Name: ProviderSveltosName},
}
}

// Templates returns a list of provider templates explicitly defined in the Management object
func (in *Management) Templates() []string {
templates := []string{}
Expand Down
30 changes: 30 additions & 0 deletions cmd/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2024
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"os"

"github.com/K0rdent/kcm/pkg/manager"
_ "github.com/K0rdent/kcm/pkg/providers/azure"
_ "github.com/K0rdent/kcm/pkg/providers/openstack"
_ "github.com/K0rdent/kcm/pkg/providers/vsphere"
)

func main() {
if err := manager.Main(); err != nil {
os.Exit(1)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/fluxcd/pkg/apis/meta v1.9.0
github.com/fluxcd/pkg/runtime v0.50.1
github.com/fluxcd/source-controller/api v1.4.1
github.com/go-logr/logr v1.4.2
github.com/google/uuid v1.6.0
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/onsi/ginkgo/v2 v2.22.2
Expand Down Expand Up @@ -85,7 +86,6 @@ require (
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-ldap/ldap/v3 v3.4.8 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
Expand Down
112 changes: 28 additions & 84 deletions internal/controller/clusterdeployment_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"

hmc "github.com/K0rdent/kcm/api/v1alpha1"
"github.com/K0rdent/kcm/internal/credspropagation"
"github.com/K0rdent/kcm/internal/helm"
"github.com/K0rdent/kcm/internal/sveltos"
"github.com/K0rdent/kcm/internal/telemetry"
"github.com/K0rdent/kcm/internal/utils"
"github.com/K0rdent/kcm/internal/utils/status"
"github.com/K0rdent/kcm/pkg/credspropagation"
providersloader "github.com/K0rdent/kcm/pkg/providers"
)

const (
Expand Down Expand Up @@ -572,35 +573,16 @@ func (r *ClusterDeploymentReconciler) releaseCluster(ctx context.Context, namesp
return err
}

var (
gvkAWSCluster = schema.GroupVersionKind{
Group: "infrastructure.cluster.x-k8s.io",
Version: "v1beta2",
Kind: "AWSCluster",
}

gvkAzureCluster = schema.GroupVersionKind{
Group: "infrastructure.cluster.x-k8s.io",
Version: "v1beta1",
Kind: "AzureCluster",
}

gvkMachine = schema.GroupVersionKind{
Group: "cluster.x-k8s.io",
Version: "v1beta1",
Kind: "Machine",
}
)

providerGVKs := map[string]schema.GroupVersionKind{
"aws": gvkAWSCluster,
"azure": gvkAzureCluster,
gvkMachine := schema.GroupVersionKind{
Group: "cluster.x-k8s.io",
Version: "v1beta1",
Kind: "Machine",
}

// Associate the provider with it's GVK
for _, provider := range providers {
gvk, ok := providerGVKs[provider]
if !ok {
gvk := providersloader.GetClusterGVK(provider)
if !gvk.Empty() {
continue
}

Expand Down Expand Up @@ -634,13 +616,12 @@ func (r *ClusterDeploymentReconciler) getInfraProvidersNames(ctx context.Context
return nil, err
}

const infraPrefix = "infrastructure-"
var (
ips = make([]string, 0, len(template.Status.Providers))
lprefix = len(infraPrefix)
lprefix = len(providersloader.InfraPrefix)
)
for _, v := range template.Status.Providers {
if idx := strings.Index(v, infraPrefix); idx > -1 {
if idx := strings.Index(v, providersloader.InfraPrefix); idx > -1 {
ips = append(ips, v[idx+lprefix:])
}
}
Expand Down Expand Up @@ -717,73 +698,36 @@ func (r *ClusterDeploymentReconciler) reconcileCredentialPropagation(ctx context
}

for _, provider := range providers {
switch provider {
case "aws":
l.Info("Skipping creds propagation for AWS")
case "azure":
l.Info("Azure creds propagation start")
if err := credspropagation.PropagateAzureSecrets(ctx, propnCfg); err != nil {
errMsg := fmt.Sprintf("failed to create Azure CCM credentials: %s", err)
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metav1.Condition{
Type: hmc.CredentialsPropagatedCondition,
Status: metav1.ConditionFalse,
Reason: hmc.FailedReason,
Message: errMsg,
})

return errors.New(errMsg)
}
titleName := providersloader.GetProviderTitleName(provider)

f, ok := providersloader.CredentialPropagationFunc(provider)
if !ok || titleName == "" {
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metav1.Condition{
Type: hmc.CredentialsPropagatedCondition,
Status: metav1.ConditionTrue,
Reason: hmc.SucceededReason,
Message: "Azure CCM credentials created",
Status: metav1.ConditionFalse,
Reason: hmc.FailedReason,
Message: "unsupported infrastructure provider " + provider,
})
case "vsphere":
l.Info("vSphere creds propagation start")
if err := credspropagation.PropagateVSphereSecrets(ctx, propnCfg); err != nil {
errMsg := fmt.Sprintf("failed to create vSphere CCM credentials: %s", err)
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metav1.Condition{
Type: hmc.CredentialsPropagatedCondition,
Status: metav1.ConditionFalse,
Reason: hmc.FailedReason,
Message: errMsg,
})
return errors.New(errMsg)
}

continue
}

enabled, err := f(ctx, propnCfg, l)
if err != nil {
errMsg := fmt.Sprintf("failed to create %s CCM credentials: %s", titleName, err)
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metav1.Condition{
Type: hmc.CredentialsPropagatedCondition,
Status: metav1.ConditionTrue,
Reason: hmc.SucceededReason,
Message: "vSphere CCM credentials created",
Status: metav1.ConditionFalse,
Reason: hmc.FailedReason,
Message: errMsg,
})
case "openstack":
l.Info("OpenStack creds propagation start")
if err := credspropagation.PropagateOpenStackSecrets(ctx, propnCfg); err != nil {
errMsg := fmt.Sprintf("failed to create OpenStack CCM credentials: %s", err)
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metav1.Condition{
Type: hmc.CredentialsPropagatedCondition,
Status: metav1.ConditionFalse,
Reason: hmc.FailedReason,
Message: errMsg,
})
return errors.New(errMsg)
}

return errors.New(errMsg)
} else if enabled {
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metav1.Condition{
Type: hmc.CredentialsPropagatedCondition,
Status: metav1.ConditionTrue,
Reason: hmc.SucceededReason,
Message: "OpenStack CCM credentials created",
})
default:
apimeta.SetStatusCondition(clusterDeployment.GetConditions(), metav1.Condition{
Type: hmc.CredentialsPropagatedCondition,
Status: metav1.ConditionFalse,
Reason: hmc.FailedReason,
Message: "unsupported infrastructure provider " + provider,
Message: titleName + " CCM credentials created",
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion internal/controller/release_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import (
"github.com/K0rdent/kcm/internal/build"
"github.com/K0rdent/kcm/internal/helm"
"github.com/K0rdent/kcm/internal/utils"
"github.com/K0rdent/kcm/pkg/providers"
)

// ReleaseReconciler reconciles a Template object
Expand Down Expand Up @@ -200,7 +201,7 @@ func (r *ReleaseReconciler) ensureManagement(ctx context.Context) error {
if err != nil {
return err
}
mgmtObj.Spec.Providers = hmc.GetDefaultProviders()
mgmtObj.Spec.Providers = providers.List()

getter := helm.NewMemoryRESTClientGetter(r.Config, r.RESTMapper())
actionConfig := new(action.Configuration)
Expand Down
36 changes: 16 additions & 20 deletions internal/webhook/clusterdeployment_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

hmcv1alpha1 "github.com/K0rdent/kcm/api/v1alpha1"
providersloader "github.com/K0rdent/kcm/pkg/providers"
)

type ClusterDeploymentValidator struct {
Expand Down Expand Up @@ -239,7 +240,7 @@ func (v *ClusterDeploymentValidator) validateCredential(ctx context.Context, clu

hasInfra := false
for _, v := range template.Status.Providers {
if strings.HasPrefix(v, "infrastructure-") {
if strings.HasPrefix(v, providersloader.InfraPrefix) {
hasInfra = true
break
}
Expand Down Expand Up @@ -269,30 +270,25 @@ func isCredMatchTemplate(cred *hmcv1alpha1.Credential, template *hmcv1alpha1.Clu
}

for _, provider := range template.Status.Providers {
switch provider {
case "infrastructure-aws":
if idtyKind != "AWSClusterStaticIdentity" &&
idtyKind != "AWSClusterRoleIdentity" &&
idtyKind != "AWSClusterControllerIdentity" {
return errMsg(provider)
}
case "infrastructure-azure":
if idtyKind != "AzureClusterIdentity" &&
idtyKind != "Secret" {
return errMsg(provider)
}
case "infrastructure-vsphere":
if idtyKind != "VSphereClusterIdentity" {
return errMsg(provider)
}
case "infrastructure-openstack", "infrastructure-internal":
if provider == providersloader.InfraPrefix+"internal" {
if idtyKind != "Secret" {
return errMsg(provider)
}
default:
if strings.HasPrefix(provider, "infrastructure-") {

continue
}

idtys, found := providersloader.GetClusterIdentityKind(provider)
if !found {
if strings.HasPrefix(provider, providersloader.InfraPrefix) {
return fmt.Errorf("unsupported infrastructure provider %s", provider)
}

continue
}

if !slices.Contains(idtys, idtyKind) {
return errMsg(provider)
}
}

Expand Down
Loading
Loading