sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/delete.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes 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 client
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/pkg/errors"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	kerrors "k8s.io/apimachinery/pkg/util/errors"
    25  
    26  	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
    27  	"sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster"
    28  )
    29  
    30  // DeleteOptions carries the options supported by Delete.
    31  type DeleteOptions struct {
    32  	// Kubeconfig defines the kubeconfig to use for accessing the management cluster. If empty,
    33  	// default rules for kubeconfig discovery will be used.
    34  	Kubeconfig Kubeconfig
    35  
    36  	// CoreProvider version (e.g. cluster-api:v1.1.5) to delete from the management cluster.
    37  	CoreProvider string
    38  
    39  	// BootstrapProviders and versions (e.g. kubeadm:v1.1.5) to delete from the management cluster.
    40  	BootstrapProviders []string
    41  
    42  	// InfrastructureProviders and versions (e.g. aws:v0.5.0) to delete from the management cluster.
    43  	InfrastructureProviders []string
    44  
    45  	// ControlPlaneProviders and versions (e.g. kubeadm:v1.1.5) to delete from the management cluster.
    46  	ControlPlaneProviders []string
    47  
    48  	// IPAMProviders and versions (e.g. infoblox:v0.0.1) to delete from the management cluster.
    49  	IPAMProviders []string
    50  
    51  	// RuntimeExtensionProviders and versions (e.g. test:v0.0.1) to delete from the management cluster.
    52  	RuntimeExtensionProviders []string
    53  
    54  	// AddonProviders and versions (e.g. helm:v0.1.0) to delete from the management cluster.
    55  	AddonProviders []string
    56  
    57  	// DeleteAll set for deletion of all the providers.
    58  	DeleteAll bool
    59  
    60  	// IncludeNamespace forces the deletion of the namespace where the providers are hosted
    61  	// (and of all the contained objects).
    62  	IncludeNamespace bool
    63  
    64  	// IncludeCRDs forces the deletion of the provider's CRDs (and of all the related objects).
    65  	IncludeCRDs bool
    66  
    67  	// SkipInventory forces the deletion of the inventory items used by clusterctl to track providers.
    68  	SkipInventory bool
    69  }
    70  
    71  func (c *clusterctlClient) Delete(ctx context.Context, options DeleteOptions) error {
    72  	clusterClient, err := c.clusterClientFactory(ClusterClientFactoryInput{Kubeconfig: options.Kubeconfig})
    73  	if err != nil {
    74  		return err
    75  	}
    76  
    77  	// Ensure this command only runs against management clusters with the current Cluster API contract.
    78  	if err := clusterClient.ProviderInventory().CheckCAPIContract(ctx); err != nil {
    79  		return err
    80  	}
    81  
    82  	// Ensure the custom resource definitions required by clusterctl are in place.
    83  	if err := clusterClient.ProviderInventory().EnsureCustomResourceDefinitions(ctx); err != nil {
    84  		return err
    85  	}
    86  
    87  	// Get the list of installed providers.
    88  	installedProviders, err := clusterClient.ProviderInventory().List(ctx)
    89  	if err != nil {
    90  		return err
    91  	}
    92  
    93  	// Prepare the list of providers to delete.
    94  	var providersToDelete []clusterctlv1.Provider
    95  
    96  	if options.DeleteAll {
    97  		providersToDelete = installedProviders.Items
    98  	} else {
    99  		// Otherwise we are deleting only a subset of providers.
   100  		var providers []clusterctlv1.Provider
   101  		providers, err = appendProviders(providers, clusterctlv1.CoreProviderType, options.CoreProvider)
   102  		if err != nil {
   103  			return err
   104  		}
   105  
   106  		providers, err = appendProviders(providers, clusterctlv1.BootstrapProviderType, options.BootstrapProviders...)
   107  		if err != nil {
   108  			return err
   109  		}
   110  
   111  		providers, err = appendProviders(providers, clusterctlv1.ControlPlaneProviderType, options.ControlPlaneProviders...)
   112  		if err != nil {
   113  			return err
   114  		}
   115  
   116  		providers, err = appendProviders(providers, clusterctlv1.InfrastructureProviderType, options.InfrastructureProviders...)
   117  		if err != nil {
   118  			return err
   119  		}
   120  
   121  		providers, err = appendProviders(providers, clusterctlv1.IPAMProviderType, options.IPAMProviders...)
   122  		if err != nil {
   123  			return err
   124  		}
   125  
   126  		providers, err = appendProviders(providers, clusterctlv1.RuntimeExtensionProviderType, options.RuntimeExtensionProviders...)
   127  		if err != nil {
   128  			return err
   129  		}
   130  
   131  		providers, err = appendProviders(providers, clusterctlv1.AddonProviderType, options.AddonProviders...)
   132  		if err != nil {
   133  			return err
   134  		}
   135  
   136  		for _, provider := range providers {
   137  			// Try to detect the namespace where the provider lives
   138  			provider.Namespace, err = clusterClient.ProviderInventory().GetProviderNamespace(ctx, provider.ProviderName, provider.GetProviderType())
   139  			if err != nil {
   140  				return err
   141  			}
   142  			if provider.Namespace == "" {
   143  				return errors.Errorf("failed to identify the namespace for the %q provider", provider.ProviderName)
   144  			}
   145  
   146  			if provider.Version != "" {
   147  				version, err := clusterClient.ProviderInventory().GetProviderVersion(ctx, provider.ProviderName, provider.GetProviderType())
   148  				if err != nil {
   149  					return err
   150  				}
   151  				if provider.Version != version {
   152  					return errors.Errorf("failed to identify the provider %q with version %q", provider.ProviderName, provider.Version)
   153  				}
   154  			}
   155  
   156  			providersToDelete = append(providersToDelete, provider)
   157  		}
   158  	}
   159  
   160  	if options.IncludeCRDs {
   161  		errList := []error{}
   162  		for _, provider := range providersToDelete {
   163  			err = clusterClient.ProviderComponents().ValidateNoObjectsExist(ctx, provider)
   164  			if err != nil {
   165  				errList = append(errList, err)
   166  			}
   167  		}
   168  		if len(errList) > 0 {
   169  			return kerrors.NewAggregate(errList)
   170  		}
   171  	}
   172  
   173  	// Delete the selected providers.
   174  	for _, provider := range providersToDelete {
   175  		if err := clusterClient.ProviderComponents().Delete(ctx, cluster.DeleteOptions{Provider: provider, IncludeNamespace: options.IncludeNamespace, IncludeCRDs: options.IncludeCRDs, SkipInventory: options.SkipInventory}); err != nil {
   176  			return err
   177  		}
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  func appendProviders(list []clusterctlv1.Provider, providerType clusterctlv1.ProviderType, names ...string) ([]clusterctlv1.Provider, error) {
   184  	for _, name := range names {
   185  		if name == "" {
   186  			continue
   187  		}
   188  
   189  		// Parse the abbreviated syntax for name[:version]
   190  		name, version, err := parseProviderName(name)
   191  		if err != nil {
   192  			return nil, err
   193  		}
   194  
   195  		list = append(list, clusterctlv1.Provider{
   196  			ObjectMeta: metav1.ObjectMeta{
   197  				Name: clusterctlv1.ManifestLabel(name, providerType),
   198  			},
   199  			ProviderName: name,
   200  			Type:         string(providerType),
   201  			Version:      version,
   202  		})
   203  	}
   204  	return list, nil
   205  }