Skip to content
This repository has been archived by the owner on Jun 29, 2022. It is now read-only.

Commit

Permalink
cli/cmd: move all CLI independent code into cluster subpackage
Browse files Browse the repository at this point in the history
This draws clear distinction between the CLI code sitting in cli/cmd
package right now and Lokomotive "core" logic.

cli/cmd/cluster package still contains some UI parts, like user input
confirmation or output printed directly to standard output, which should
also be addressed in the future.

Refs #603

Signed-off-by: Mateusz Gozdek <mateusz@kinvolk.io>
  • Loading branch information
invidian committed Oct 21, 2020
1 parent 632c529 commit fb445ec
Show file tree
Hide file tree
Showing 16 changed files with 944 additions and 798 deletions.
180 changes: 9 additions & 171 deletions cli/cmd/cluster-apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,11 @@
package cmd

import (
"fmt"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/kinvolk/lokomotive/internal"
"github.com/kinvolk/lokomotive/pkg/helm"
"github.com/kinvolk/lokomotive/pkg/k8sutil"
"github.com/kinvolk/lokomotive/pkg/lokomotive"
"github.com/kinvolk/lokomotive/pkg/platform"
"github.com/kinvolk/lokomotive/cli/cmd/cluster"
)

var (
Expand Down Expand Up @@ -58,172 +52,16 @@ func runClusterApply(cmd *cobra.Command, args []string) {
"args": args,
})

options := clusterApplyOptions{
confirm: confirm,
upgradeKubelets: upgradeKubelets,
skipComponents: skipComponents,
verbose: verbose,
configPath: viper.GetString("lokocfg"),
valuesPath: viper.GetString("lokocfg-vars"),
options := cluster.ApplyOptions{
Confirm: confirm,
UpgradeKubelets: upgradeKubelets,
SkipComponents: skipComponents,
Verbose: verbose,
ConfigPath: viper.GetString("lokocfg"),
ValuesPath: viper.GetString("lokocfg-vars"),
}

if err := clusterApply(contextLogger, options); err != nil {
if err := cluster.Apply(contextLogger, options); err != nil {
contextLogger.Fatalf("Applying cluster failed: %v", err)
}
}

type clusterApplyOptions struct {
confirm bool
upgradeKubelets bool
skipComponents bool
verbose bool
configPath string
valuesPath string
}

//nolint:funlen
func clusterApply(contextLogger *log.Entry, options clusterApplyOptions) error {
cc := clusterConfig{
verbose: options.verbose,
configPath: options.configPath,
valuesPath: options.valuesPath,
}

c, err := cc.initialize(contextLogger)
if err != nil {
return fmt.Errorf("initializing: %w", err)
}

exists, err := clusterExists(c.terraformExecutor)
if err != nil {
return fmt.Errorf("checking if cluster exists: %w", err)
}

if exists && !options.confirm {
// TODO: We could plan to a file and use it when installing.
if err := c.terraformExecutor.Plan(); err != nil {
return fmt.Errorf("reconciling cluster state: %v", err)
}

if !askForConfirmation("Do you want to proceed with cluster apply?") {
contextLogger.Println("Cluster apply cancelled")

return nil
}
}

if err := c.platform.Apply(&c.terraformExecutor); err != nil {
return fmt.Errorf("applying platform: %v", err)
}

fmt.Printf("\nYour configurations are stored in %s\n", c.assetDir)

kg := kubeconfigGetter{
platformRequired: true,
}

kubeconfig, err := kg.getKubeconfig(contextLogger, c.lokomotiveConfig)
if err != nil {
return fmt.Errorf("getting kubeconfig: %v", err)
}

if err := verifyCluster(kubeconfig, c.platform.Meta().ExpectedNodes); err != nil {
return fmt.Errorf("verifying cluster: %v", err)
}

// Update all the pre installed namespaces with lokomotive specific label.
// `lokomotive.kinvolk.io/name: <namespace_name>`.
if err := updateInstalledNamespaces(kubeconfig); err != nil {
return fmt.Errorf("updating installed namespace: %v", err)
}

// Do controlplane upgrades only if cluster already exists and it is not a managed platform.
if exists && !c.platform.Meta().Managed {
fmt.Printf("\nEnsuring that cluster controlplane is up to date.\n")

cu := controlplaneUpdater{
kubeconfig: kubeconfig,
assetDir: c.assetDir,
contextLogger: *contextLogger,
ex: c.terraformExecutor,
}

charts := platform.CommonControlPlaneCharts()

if options.upgradeKubelets {
charts = append(charts, helm.LokomotiveChart{
Name: "kubelet",
Namespace: "kube-system",
})
}

for _, c := range charts {
if err := cu.upgradeComponent(c.Name, c.Namespace); err != nil {
return fmt.Errorf("upgrading controlplane component %q: %w", c.Name, err)
}
}
}

if ph, ok := c.platform.(platform.PlatformWithPostApplyHook); ok {
if err := ph.PostApplyHook(kubeconfig); err != nil {
return fmt.Errorf("running platform post install hook: %v", err)
}
}

if options.skipComponents {
return nil
}

componentObjects, err := componentNamesToObjects(selectComponentNames(nil, *c.lokomotiveConfig.RootConfig))
if err != nil {
return fmt.Errorf("getting component objects: %w", err)
}

contextLogger.Println("Applying component configuration")

if err := applyComponents(c.lokomotiveConfig, kubeconfig, componentObjects); err != nil {
return fmt.Errorf("applying component configuration: %v", err)
}

return nil
}

func verifyCluster(kubeconfig []byte, expectedNodes int) error {
cs, err := k8sutil.NewClientset(kubeconfig)
if err != nil {
return fmt.Errorf("creating Kubernetes clientset: %w", err)
}

cluster := lokomotive.NewCluster(cs, expectedNodes)

return cluster.Verify()
}

func updateInstalledNamespaces(kubeconfig []byte) error {
cs, err := k8sutil.NewClientset(kubeconfig)
if err != nil {
return fmt.Errorf("create clientset: %v", err)
}

nsclient := cs.CoreV1().Namespaces()

namespaces, err := k8sutil.ListNamespaces(nsclient)
if err != nil {
return fmt.Errorf("getting list of namespaces: %v", err)
}

for _, ns := range namespaces.Items {
ns := k8sutil.Namespace{
Name: ns.ObjectMeta.Name,
Labels: map[string]string{
internal.NamespaceLabelKey: ns.ObjectMeta.Name,
},
}

if err := k8sutil.CreateOrUpdateNamespace(ns, nsclient); err != nil {
return fmt.Errorf("namespace %q with labels: %v", ns, err)
}
}

return nil
}
65 changes: 8 additions & 57 deletions cli/cmd/cluster-destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
package cmd

import (
"fmt"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/kinvolk/lokomotive/cli/cmd/cluster"
)

var confirm bool
Expand All @@ -43,63 +43,14 @@ func runClusterDestroy(cmd *cobra.Command, args []string) {
"args": args,
})

options := clusterDestroyOptions{
confirm: confirm,
verbose: verbose,
configPath: viper.GetString("lokocfg"),
valuesPath: viper.GetString("lokocfg-vars"),
options := cluster.DestroyOptions{
Confirm: confirm,
Verbose: verbose,
ConfigPath: viper.GetString("lokocfg"),
ValuesPath: viper.GetString("lokocfg-vars"),
}

if err := clusterDestroy(contextLogger, options); err != nil {
if err := cluster.Destroy(contextLogger, options); err != nil {
contextLogger.Fatalf("Destroying cluster: %v", err)
}
}

type clusterDestroyOptions struct {
confirm bool
verbose bool
configPath string
valuesPath string
}

func clusterDestroy(contextLogger *log.Entry, options clusterDestroyOptions) error {
cc := clusterConfig{
verbose: options.verbose,
configPath: options.configPath,
valuesPath: options.valuesPath,
}

c, err := cc.initialize(contextLogger)
if err != nil {
return fmt.Errorf("initializing: %w", err)
}

exists, err := clusterExists(c.terraformExecutor)
if err != nil {
return fmt.Errorf("checking if cluster exists: %w", err)
}

if !exists {
contextLogger.Println("Cluster already destroyed, nothing to do")

return nil
}

if !options.confirm {
confirmation := askForConfirmation("WARNING: This action cannot be undone. Do you really want to destroy the cluster?")
if !confirmation {
contextLogger.Println("Cluster destroy canceled")

return nil
}
}

if err := c.platform.Destroy(&c.terraformExecutor); err != nil {
return fmt.Errorf("destroying cluster: %v", err)
}

contextLogger.Println("Cluster destroyed successfully")
contextLogger.Println("You can safely remove the assets directory now")

return nil
}
Loading

0 comments on commit fb445ec

Please sign in to comment.