Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

Commit

Permalink
chore(cmd/cli): Reduce cyclomatic complexity of uninstall command (#4825
Browse files Browse the repository at this point in the history
)

* chore(cmd/cli): Reduce cyclomatic complexity of uninstall command

Separate code into functions to reduce the cyclomatic complexity
And adds unit tests to functions created
Helps unblock #4555

Signed-off-by: Shalier Xia <shalierxia@microsoft.com>
  • Loading branch information
shalier authored Jul 14, 2022
1 parent 41139b9 commit d5d3a25
Show file tree
Hide file tree
Showing 2 changed files with 289 additions and 46 deletions.
122 changes: 76 additions & 46 deletions cmd/cli/uninstall_mesh.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@ func newUninstallMeshCmd(config *action.Configuration, in io.Reader, out io.Writ
// get kubeconfig and initialize k8s client
kubeconfig, err := settings.RESTClientGetter().ToRESTConfig()
if err != nil {
return errors.Errorf("Error fetching kubeconfig: %s", err)
return fmt.Errorf("Error fetching kubeconfig: %s", err)
}
uninstall.config = kubeconfig

uninstall.clientSet, err = kubernetes.NewForConfig(kubeconfig)
if err != nil {
return errors.Errorf("Could not access Kubernetes cluster, check kubeconfig: %s", err)
return fmt.Errorf("Could not access Kubernetes cluster, check kubeconfig: %s", err)
}

uninstall.extensionsClientset, err = extensionsClientset.NewForConfig(kubeconfig)
if err != nil {
return errors.Errorf("Could not access extension client set: %s", err)
return fmt.Errorf("Could not access extension client set: %s", err)
}

uninstall.meshNamespace = settings.Namespace()
Expand Down Expand Up @@ -118,10 +118,10 @@ func (d *uninstallMeshCmd) run() error {
fmt.Fprintf(d.out, "No OSM control planes found\n")
return nil
}
// Searches for the mesh specified by the mesh-name flag if specified
specifiedMeshFound := false
if d.meshName != "" {
specifiedMeshFound = d.findMesh(meshInfoList)

if d.meshSpecified() {
// Searches for the mesh specified by the mesh-name flag if specified
specifiedMeshFound := d.findSpecifiedMesh(meshInfoList)
if !specifiedMeshFound {
return nil
}
Expand All @@ -143,19 +143,11 @@ func (d *uninstallMeshCmd) run() error {
return err
}
// Prompts user on whether to uninstall each OSM mesh in the cluster
for _, mesh := range meshInfoList {
// Only prompt for specified mesh if `mesh-name` is specified
if specifiedMeshFound && mesh.name != d.meshName {
continue
}
confirm, err := confirm(d.in, d.out, fmt.Sprintf("\nUninstall OSM [mesh name: %s] in namespace [%s] and/or OSM resources?", mesh.name, mesh.namespace), 3)
if err != nil {
return err
}
if confirm {
meshesToUninstall = append(meshesToUninstall, mesh)
}
uninstallMeshes, err := d.promptMeshUninstall(meshInfoList, meshesToUninstall)
if err != nil {
return err
}
meshesToUninstall = append(meshesToUninstall, uninstallMeshes...)
}

for _, m := range meshesToUninstall {
Expand All @@ -175,22 +167,16 @@ func (d *uninstallMeshCmd) run() error {
return err
}

fmt.Fprintf(d.out, "Error %v when trying to uninstall mesh name [%s] in namespace [%s] - continuing to deleteClusterWideResources and/or deleteNamespace\n", err, m.name, m.namespace)
fmt.Fprintf(d.out, "Could not uninstall mesh name [%s] in namespace [%s]- %v - continuing to deleteClusterWideResources and/or deleteNamespace\n", m.name, m.namespace, err)
}

if err == nil {
fmt.Fprintf(d.out, "OSM [mesh name: %s] in namespace [%s] uninstalled\n", m.name, m.namespace)
}

if d.deleteNamespace {
if err := d.clientSet.CoreV1().Namespaces().Delete(ctx, m.namespace, v1.DeleteOptions{}); err != nil {
if k8sApiErrors.IsNotFound(err) {
fmt.Fprintf(d.out, "OSM namespace [%s] not found\n", m.namespace)
return nil
}
return errors.Errorf("Error occurred while deleting OSM namespace [%s] - %v", m.namespace, err)
}
fmt.Fprintf(d.out, "OSM namespace [%s] deleted successfully\n", m.namespace)
err = d.deleteNs(ctx, m.namespace)
if err != nil {
return err
}
}
} else {
Expand All @@ -199,6 +185,61 @@ func (d *uninstallMeshCmd) run() error {
fmt.Fprintf(d.out, "OSM namespace CANNOT be deleted in a managed environment\n")
}
}

err := d.deleteClusterResources()
return err
}

func (d *uninstallMeshCmd) meshSpecified() bool {
return d.meshName != ""
}

func (d *uninstallMeshCmd) findSpecifiedMesh(meshInfoList []meshInfo) bool {
specifiedMeshFound := d.findMesh(meshInfoList)
if !specifiedMeshFound {
fmt.Fprintf(d.out, "Did not find mesh [%s] in namespace [%s]\n", d.meshName, d.meshNamespace)
// print a list of meshes within the cluster for a better user experience
if err := d.printMeshes(); err != nil {
fmt.Fprintf(d.out, "Unable to list meshes in the cluster - [%v]", err)
}
}

return specifiedMeshFound
}

func (d *uninstallMeshCmd) promptMeshUninstall(meshInfoList, meshesToUninstall []meshInfo) ([]meshInfo, error) {
for _, mesh := range meshInfoList {
// Only prompt for specified mesh if `mesh-name` is specified
if d.meshSpecified() && mesh.name != d.meshName {
continue
}
confirm, err := confirm(d.in, d.out, fmt.Sprintf("\nUninstall OSM [mesh name: %s] in namespace [%s] and/or OSM resources?", mesh.name, mesh.namespace), 3)
if err != nil {
return nil, err
}
if confirm {
meshesToUninstall = append(meshesToUninstall, mesh)
}
}
return meshesToUninstall, nil
}

func (d *uninstallMeshCmd) deleteNs(ctx context.Context, ns string) error {
if !d.deleteNamespace {
return nil
}
if err := d.clientSet.CoreV1().Namespaces().Delete(ctx, ns, v1.DeleteOptions{}); err != nil {
if k8sApiErrors.IsNotFound(err) {
fmt.Fprintf(d.out, "OSM namespace [%s] not found\n", ns)
return nil
}
return fmt.Errorf("Could not delete OSM namespace [%s] - %v", ns, err)
}
fmt.Fprintf(d.out, "OSM namespace [%s] deleted successfully\n", ns)
return nil
}

func (d *uninstallMeshCmd) deleteClusterResources() error {
if d.deleteClusterWideResources {
meshInfoList, err := getMeshInfoList(d.config, d.clientSet)
if err != nil {
Expand All @@ -213,10 +254,9 @@ func (d *uninstallMeshCmd) run() error {

failedDeletions := d.uninstallClusterResources()
if len(failedDeletions) != 0 {
return errors.Errorf("Failed to completely delete the following OSM resource types: %+v", failedDeletions)
return fmt.Errorf("Failed to completely delete the following OSM resource types: %+v", failedDeletions)
}
}

return nil
}

Expand Down Expand Up @@ -278,7 +318,7 @@ func (d *uninstallMeshCmd) uninstallCustomResourceDefinitions() error {
}

if len(failedDeletions) != 0 {
return errors.Errorf("Failed to delete the following OSM CRDs: %+v", failedDeletions)
return fmt.Errorf("Failed to delete the following OSM CRDs: %+v", failedDeletions)
}

return nil
Expand Down Expand Up @@ -325,7 +365,7 @@ func (d *uninstallMeshCmd) uninstallMutatingWebhookConfigurations() error {
}

if len(failedDeletions) != 0 {
return errors.Errorf("Found but failed to delete the following OSM MutatingWebhookConfigurations: %+v", failedDeletions)
return fmt.Errorf("Found but failed to delete the following OSM MutatingWebhookConfigurations: %+v", failedDeletions)
}

return nil
Expand Down Expand Up @@ -373,7 +413,7 @@ func (d *uninstallMeshCmd) uninstallValidatingWebhookConfigurations() error {
}

if len(failedDeletions) != 0 {
return errors.Errorf("Found but failed to delete the following OSM ValidatingWebhookConfigurations: %+v", failedDeletions)
return fmt.Errorf("Found but failed to delete the following OSM ValidatingWebhookConfigurations: %+v", failedDeletions)
}

return nil
Expand Down Expand Up @@ -407,7 +447,7 @@ func (d *uninstallMeshCmd) uninstallSecrets() error {
}

if len(failedDeletions) != 0 {
return errors.Errorf("Found but failed to delete the following OSM secrets in namespace %s: %+v", d.meshNamespace, failedDeletions)
return fmt.Errorf("Found but failed to delete the following OSM secrets in namespace %s: %+v", d.meshNamespace, failedDeletions)
}

return nil
Expand All @@ -422,17 +462,7 @@ func (d *uninstallMeshCmd) findMesh(meshInfoList []meshInfo) bool {
break
}
}
if found {
return true
}

fmt.Fprintf(d.out, "Did not find mesh [%s] in namespace [%s]\n", d.meshName, d.meshNamespace)
// print a list of meshes within the cluster for a better user experience
err := d.printMeshes()
if err != nil {
fmt.Fprintf(d.out, "Unable to list meshes in the cluster - [%v]", err)
}
return false
return found
}

// printMeshes prints list of meshes within the cluster for a better user experience
Expand Down
Loading

0 comments on commit d5d3a25

Please sign in to comment.