Skip to content

Commit

Permalink
WIP adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric Wollesen committed Mar 1, 2023
1 parent 240ad87 commit 412df1e
Show file tree
Hide file tree
Showing 13 changed files with 765 additions and 147 deletions.
2 changes: 1 addition & 1 deletion cmd/eksctl-anywhere/cmd/installpackagecontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func installPackageController(ctx context.Context) error {
}

curatedpackages.PrintLicense()
err = ctrlClient.EnableCuratedPackages(ctx)
err = ctrlClient.Enable(ctx)
if err != nil {
return err
}
Expand Down
137 changes: 84 additions & 53 deletions controllers/cluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type ClusterReconciler struct {
providerReconcilerRegistry ProviderClusterReconcilerRegistry
awsIamAuth AWSIamConfigReconciler
clusterValidator ClusterValidator
packageControllerClient PackageControllerClient
packagesClient PackagesClient
}

type ProviderClusterReconcilerRegistry interface {
Expand All @@ -68,13 +68,13 @@ type ClusterValidator interface {
}

// NewClusterReconciler constructs a new ClusterReconciler.
func NewClusterReconciler(client client.Client, registry ProviderClusterReconcilerRegistry, awsIamAuth AWSIamConfigReconciler, clusterValidator ClusterValidator, packageControllerClient PackageControllerClient) *ClusterReconciler {
func NewClusterReconciler(client client.Client, registry ProviderClusterReconcilerRegistry, awsIamAuth AWSIamConfigReconciler, clusterValidator ClusterValidator, pkgs PackagesClient) *ClusterReconciler {
return &ClusterReconciler{
client: client,
providerReconcilerRegistry: registry,
awsIamAuth: awsIamAuth,
clusterValidator: clusterValidator,
packageControllerClient: packageControllerClient,
packagesClient: pkgs,
}
}

Expand Down Expand Up @@ -270,7 +270,7 @@ func (r *ClusterReconciler) postClusterProviderReconcile(ctx context.Context, lo
}
}

if !cluster.IsSelfManaged() {
if cluster.IsPackagesEnabled() {
if err := r.postReconcilePackagesForWorkloadCluster(ctx, log, cluster); err != nil {
return controller.Result{}, err
}
Expand All @@ -279,88 +279,124 @@ func (r *ClusterReconciler) postClusterProviderReconcile(ctx context.Context, lo
return controller.Result{}, nil
}

type PackageControllerClient interface {
EnableCuratedPackagesFullLifecycle(context.Context, logr.Logger, string, string, *v1alpha1.Image, *registrymirror.RegistryMirror, ...curatedpackages.PackageControllerClientOpt) error
// PackagesClient handles curated packages operations from within the cluster
// controller.
type PackagesClient interface {
EnableFullLifecycle(context.Context, logr.Logger, string, string, *v1alpha1.Image, *registrymirror.RegistryMirror, ...curatedpackages.PackageControllerClientOpt) error
ReconcileDelete(context.Context, logr.Logger, client.Client, *anywherev1.Cluster) error
}

var _ PackageControllerClient = (*curatedpackages.PackageControllerClient)(nil)

func (r *ClusterReconciler) postReconcilePackagesForWorkloadCluster(ctx context.Context, log logr.Logger, cluster *anywherev1.Cluster) (err error) {
image, err := r.getBundleFromCluster(ctx, cluster)
if err != nil {
return err
}

kubeConfig, err := r.writeKubeConfigSecret(ctx, cluster)
if err != nil {
return err
}
defer func() {
if err := kubeConfig.Remove(); err != nil {
log.Error(err, "removing kubeconfig file", "filename", kubeConfig.Name())
}
}()

registry := registrymirror.FromCluster(cluster)

if err := r.packagesClient.EnableFullLifecycle(ctx, log, cluster.Name, kubeConfig.Name(), image, registry); err != nil {
return fmt.Errorf("packages client error: %w", err)
}

log.V(6).Info("Installed curated packages on workload cluster", "cluster", cluster.Name)

return nil
}

// getBundleFromCluster based on the cluster's k8s version.
func (r *ClusterReconciler) getBundleFromCluster(ctx context.Context, cluster *anywherev1.Cluster) (*v1alpha1.Image, error) {
bundles := &v1alpha1.Bundles{}
nn := types.NamespacedName{
Name: cluster.Spec.BundlesRef.Name,
Namespace: cluster.Spec.BundlesRef.Namespace,
}
if err := r.client.Get(ctx, nn, bundles); err != nil {
return err
return nil, fmt.Errorf("retrieving bundle: %w", err)
}

verBundle, err := r.findMatchingBundle(bundles, string(cluster.Spec.KubernetesVersion))
if err != nil {
return err
return nil, err
}

image, ok := verBundle.Charts()["eks-anywhere-packages"]
if !ok {
return fmt.Errorf("no chart image")
return &verBundle.PackageController.HelmChart, nil
}

func (r *ClusterReconciler) findMatchingBundle(bundles *v1alpha1.Bundles, kubeVersion string) (*v1alpha1.VersionsBundle, error) {
var verBundle *v1alpha1.VersionsBundle
for _, b := range bundles.Spec.VersionsBundles {
if b.KubeVersion == string(kubeVersion) {
verBundle = &b
break
}
}
if verBundle == nil {
return nil, fmt.Errorf("no bundle for kube version %q", kubeVersion)
}

return verBundle, nil
}

// writeKubeConfigSecret so that the helm executable can pick it up to install
// curated packages helm charts.
func (r *ClusterReconciler) writeKubeConfigSecret(ctx context.Context, cluster *anywherev1.Cluster) (kubeconfigFile, error) {
kubeConfigSecret := &corev1.Secret{}
kubeConfigNN := types.NamespacedName{
Namespace: constants.EksaSystemNamespace,
Name: cluster.Name + "-kubeconfig",
}
kubeConfigSecret := &corev1.Secret{}
if err := r.client.Get(ctx, kubeConfigNN, kubeConfigSecret); err != nil {
return fmt.Errorf("getting kubeconfig secret: %w", err)
return nil, fmt.Errorf("getting kubeconfig secret: %w", err)
}
secretBytes, err := yaml.Marshal(kubeConfigSecret)
if err != nil {
return fmt.Errorf("marshaling secret %w", err)
return nil, fmt.Errorf("marshaling secret %w", err)
}
f, err := os.CreateTemp("", "kubeconfig-*.yaml")
if err != nil {
return fmt.Errorf("opening kubeconfig file %w", err)
return nil, fmt.Errorf("opening kubeconfig file %w", err)
}
defer f.Close()
// TODO unlink

if _, err := f.Write(secretBytes); err != nil {
return fmt.Errorf("writing kubeconfig file %w", err)
return nil, fmt.Errorf("writing kubeconfig file %w", err)
}
f.Close()

rm := registrymirror.FromCluster(cluster)
var options []curatedpackages.PackageControllerClientOpt
err = r.packageControllerClient.EnableCuratedPackagesFullLifecycle(ctx, log,
cluster.Name,
f.Name(),
image,
rm,
options...,
)
if err != nil {
return fmt.Errorf("package controller client error: %w", err)
}
return &removeableFile{f}, nil
}

log.V(6).Info("Installed curated packages on workload cluster", "cluster", cluster.Name)
// kubeconfigFile adds utility operations to delete a filename after its no
// longer needed.
type kubeconfigFile interface {
// Name is the file's name on disk.
Name() string
// Remove is a best-effort deletion of the file on disk.
Remove() error
}

return nil
// removeableFile wraps os.File to implement kubeconfigFile.
type removeableFile struct {
*os.File
}

func (r *ClusterReconciler) findMatchingBundle(bundles *v1alpha1.Bundles, kubeVersion string) (*v1alpha1.VersionsBundle, error) {
var verBundle *v1alpha1.VersionsBundle
for _, b := range bundles.Spec.VersionsBundles {
if b.KubeVersion == string(kubeVersion) {
verBundle = &b
break
// Remove the file from disk.
func (f *removeableFile) Remove() error {
f.Close()
if err := os.Remove(f.Name()); err != nil {
if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("removing removeableFile: %w", err)
}
}
if verBundle == nil {
return nil, fmt.Errorf("no bundle for kube version %q", kubeVersion)
}

return verBundle, nil
return nil
}

func (r *ClusterReconciler) reconcileDelete(ctx context.Context, log logr.Logger, cluster *anywherev1.Cluster) (ctrl.Result, error) {
Expand Down Expand Up @@ -409,13 +445,8 @@ func (r *ClusterReconciler) reconcileDelete(ctx context.Context, log logr.Logger
}

if !cluster.IsSelfManaged() {
// TODO all those tests that pass a nil package controller client will bork here, as the packageControllerClient will be nil.
if r.packageControllerClient == nil {
return ctrl.Result{}, nil
// return ctrl.Result{}, fmt.Errorf("controller has a nil package controller client, cannot delete package bundle controller")
}
if err := r.packageControllerClient.ReconcileDelete(ctx, log, r.client, cluster); err != nil {
return ctrl.Result{}, fmt.Errorf("deleting packages controller for cluster %q %w", cluster.Name, err)
if err := r.packagesClient.ReconcileDelete(ctx, log, r.client, cluster); err != nil {
return ctrl.Result{}, fmt.Errorf("deleting packages for cluster %q: %w", cluster.Name, err)
}
}

Expand Down
Loading

0 comments on commit 412df1e

Please sign in to comment.