Skip to content

Commit

Permalink
Merge pull request #366 from errordeveloper/cmd-timoni-refactor
Browse files Browse the repository at this point in the history
Refactor `cmd/timoni` and extract reconciler logic to dedicated package
  • Loading branch information
stefanprodan authored Jun 11, 2024
2 parents 228a3ab + b8686f0 commit 770e822
Show file tree
Hide file tree
Showing 32 changed files with 978 additions and 702 deletions.
179 changes: 29 additions & 150 deletions cmd/timoni/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,16 @@ import (
"fmt"
"os"
"strings"
"time"

"cuelang.org/go/cue/cuecontext"
"github.com/fluxcd/pkg/ssa"
"github.com/go-logr/logr"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

apiv1 "github.com/stefanprodan/timoni/api/v1alpha1"
"github.com/stefanprodan/timoni/internal/engine"
"github.com/stefanprodan/timoni/internal/engine/fetcher"
"github.com/stefanprodan/timoni/internal/flags"
"github.com/stefanprodan/timoni/internal/logger"
"github.com/stefanprodan/timoni/internal/reconciler"
"github.com/stefanprodan/timoni/internal/runtime"
)

Expand Down Expand Up @@ -142,7 +140,7 @@ func runApplyCmd(cmd *cobra.Command, args []string) error {
applyArgs.name = args[0]
applyArgs.module = args[1]

log := LoggerInstance(cmd.Context(), applyArgs.name)
log := loggerInstance(cmd.Context(), applyArgs.name, true)

version := applyArgs.version.String()
if version == "" {
Expand Down Expand Up @@ -224,155 +222,36 @@ func runApplyCmd(cmd *cobra.Command, args []string) error {
return describeErr(f.GetModuleRoot(), "build failed", err)
}

finalValues, err := builder.GetDefaultValues()
if err != nil {
return fmt.Errorf("failed to extract values: %w", err)
}

applySets, err := builder.GetApplySets(buildResult)
if err != nil {
return fmt.Errorf("failed to extract objects: %w", err)
}

var objects []*unstructured.Unstructured
for _, set := range applySets {
objects = append(objects, set.Objects...)
}

rm, err := runtime.NewResourceManager(kubeconfigArgs)
if err != nil {
return err
}

rm.SetOwnerLabels(objects, applyArgs.name, *kubeconfigArgs.Namespace)

ctx, cancel := context.WithTimeout(cmd.Context(), rootArgs.timeout)
defer cancel()

exists := false
sm := runtime.NewStorageManager(rm)
instance, err := sm.Get(ctx, applyArgs.name, *kubeconfigArgs.Namespace)
if err == nil {
exists = true
}

nsExists, err := sm.NamespaceExists(ctx, *kubeconfigArgs.Namespace)
if err != nil {
return fmt.Errorf("instance init failed: %w", err)
}

if !applyArgs.overwriteOwnership && exists {
err = instanceOwnershipConflicts(*instance)
if err != nil {
return err
}
instance := &engine.BundleInstance{
Name: applyArgs.name,
Namespace: *kubeconfigArgs.Namespace,
Module: *mod,
Bundle: "",
}

im := runtime.NewInstanceManager(applyArgs.name, *kubeconfigArgs.Namespace, finalValues, *mod)

if err := im.AddObjects(objects); err != nil {
return fmt.Errorf("adding objects to instance failed: %w", err)
}

staleObjects, err := sm.GetStaleObjects(ctx, &im.Instance)
if err != nil {
return fmt.Errorf("getting stale objects failed: %w", err)
}

if applyArgs.dryrun || applyArgs.diff {
if !nsExists {
log.Info(colorizeJoin(colorizeNamespaceFromArgs(), ssa.CreatedAction, dryRunServer))
}
return instanceDryRunDiff(logr.NewContext(ctx, log), rm, objects, staleObjects, nsExists, tmpDir, applyArgs.diff)
}

if !exists {
log.Info(fmt.Sprintf("installing %s in namespace %s", applyArgs.name, *kubeconfigArgs.Namespace))

if err := sm.Apply(ctx, &im.Instance, true); err != nil {
return fmt.Errorf("instance init failed: %w", err)
}

if !nsExists {
log.Info(colorizeJoin(colorizeNamespaceFromArgs(), ssa.CreatedAction))
}
} else {
log.Info(fmt.Sprintf("upgrading %s in namespace %s", applyArgs.name, *kubeconfigArgs.Namespace))
}

applyOpts := runtime.ApplyOptions(applyArgs.force, rootArgs.timeout)
applyOpts.WaitInterval = 5 * time.Second

waitOptions := ssa.WaitOptions{
Interval: applyOpts.WaitInterval,
Timeout: rootArgs.timeout,
FailFast: true,
}

for _, set := range applySets {
if len(applySets) > 1 {
log.Info(fmt.Sprintf("applying %s", set.Name))
}

cs, err := rm.ApplyAllStaged(ctx, set.Objects, applyOpts)
if err != nil {
return err
}
for _, change := range cs.Entries {
log.Info(colorizeJoin(change))
}

if applyArgs.wait {
spin := StartSpinner(fmt.Sprintf("waiting for %v resource(s) to become ready...", len(set.Objects)))
err = rm.Wait(set.Objects, waitOptions)
spin.Stop()
if err != nil {
return err
}
log.Info("resources are ready")
}
}

if images, err := builder.GetContainerImages(buildResult); err == nil {
im.Instance.Images = images
}

if err := sm.Apply(ctx, &im.Instance, true); err != nil {
return fmt.Errorf("storing instance failed: %w", err)
}

var deletedObjects []*unstructured.Unstructured
if len(staleObjects) > 0 {
deleteOpts := runtime.DeleteOptions(applyArgs.name, *kubeconfigArgs.Namespace)
changeSet, err := rm.DeleteAll(ctx, staleObjects, deleteOpts)
if err != nil {
return fmt.Errorf("pruning objects failed: %w", err)
}
deletedObjects = runtime.SelectObjectsFromSet(changeSet, ssa.DeletedAction)
for _, change := range changeSet.Entries {
log.Info(colorizeJoin(change))
}
}

if applyArgs.wait {
if len(deletedObjects) > 0 {
spin := StartSpinner(fmt.Sprintf("waiting for %v resource(s) to be finalized...", len(deletedObjects)))
err = rm.WaitForTermination(deletedObjects, waitOptions)
spin.Stop()
if err != nil {
return fmt.Errorf("waiting for termination failed: %w", err)
}

log.Info("all resources are ready")
}
}

return nil
}

func instanceOwnershipConflicts(instance apiv1.Instance) error {
if currentOwnerBundle := instance.Labels[apiv1.BundleNameLabelKey]; currentOwnerBundle != "" {
return fmt.Errorf("instance ownership conflict encountered. Apply with \"--overwrite-ownership\" to gain instance ownership. Conflict: instance \"%s\" exists and is managed by bundle \"%s\"", instance.Name, currentOwnerBundle)
r := reconciler.NewInteractiveReconciler(log,
&reconciler.CommonOptions{
Dir: tmpDir,
Wait: applyArgs.wait,
Force: applyArgs.force,
OverwriteOwnership: applyArgs.overwriteOwnership,
},
&reconciler.InteractiveOptions{
DryRun: applyArgs.dryrun,
Diff: applyArgs.diff,
DiffOutput: cmd.OutOrStdout(),
ProgressStart: logger.StartSpinner,
},
rootArgs.timeout,
)
if err := r.Init(ctx, builder, buildResult, instance, kubeconfigArgs); err != nil {
return annotateInstanceOwnershipConflictErr(err)
}
return nil
return r.ApplyInstance(ctx, log,
builder,
buildResult,
)
}
2 changes: 1 addition & 1 deletion cmd/timoni/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ bundle: {
modPath,
))
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("instance \"%s\" exists and is managed by bundle \"%s\"", instanceName, bundleName)))
g.Expect(err.Error()).To(ContainSubstring(fmt.Sprintf("instance \"%s\" exists and is managed by another bundle \"%s\"", instanceName, bundleName)))

output, err := executeCommand(fmt.Sprintf("ls -n %[1]s", namespace))
g.Expect(err).ToNot(HaveOccurred())
Expand Down
3 changes: 2 additions & 1 deletion cmd/timoni/artifact_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"

"github.com/stefanprodan/timoni/internal/flags"
"github.com/stefanprodan/timoni/internal/logger"
"github.com/stefanprodan/timoni/internal/oci"
)

Expand Down Expand Up @@ -64,7 +65,7 @@ func listArtifactCmdRun(cmd *cobra.Command, args []string) error {
}
ociURL := args[0]

spin := StartSpinner("fetching tags")
spin := logger.StartSpinner("fetching tags")
defer spin.Stop()

ctx, cancel := context.WithTimeout(cmd.Context(), rootArgs.timeout)
Expand Down
5 changes: 3 additions & 2 deletions cmd/timoni/artifact_pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/spf13/cobra"

"github.com/stefanprodan/timoni/internal/flags"
"github.com/stefanprodan/timoni/internal/logger"
"github.com/stefanprodan/timoni/internal/oci"
)

Expand Down Expand Up @@ -125,7 +126,7 @@ func pullArtifactCmdRun(cmd *cobra.Command, args []string) error {
}
}

spin := StartSpinner("pulling artifact")
spin := logger.StartSpinner("pulling artifact")
defer spin.Stop()

ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
Expand All @@ -138,7 +139,7 @@ func pullArtifactCmdRun(cmd *cobra.Command, args []string) error {
}

spin.Stop()
log.Info(fmt.Sprintf("extracted: %s", colorizeSubject(pullArtifactArgs.output)))
log.Info(fmt.Sprintf("extracted: %s", logger.ColorizeSubject(pullArtifactArgs.output)))

return nil
}
7 changes: 4 additions & 3 deletions cmd/timoni/artifact_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
apiv1 "github.com/stefanprodan/timoni/api/v1alpha1"
"github.com/stefanprodan/timoni/internal/engine"
"github.com/stefanprodan/timoni/internal/flags"
"github.com/stefanprodan/timoni/internal/logger"
"github.com/stefanprodan/timoni/internal/oci"
)

Expand Down Expand Up @@ -128,7 +129,7 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
}
oci.AppendGitMetadata(pushArtifactArgs.path, annotations)

spin := StartSpinner("pushing artifact")
spin := logger.StartSpinner("pushing artifact")
defer spin.Stop()

opts := oci.Options(ctx, pushArtifactArgs.creds.String(), rootArgs.registryInsecure)
Expand Down Expand Up @@ -164,8 +165,8 @@ func pushArtifactCmdRun(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
log.Info(fmt.Sprintf("artifact: %s", colorizeSubject(ociURL)))
log.Info(fmt.Sprintf("digest: %s", colorizeSubject(digest.DigestStr())))
log.Info(fmt.Sprintf("artifact: %s", logger.ColorizeSubject(ociURL)))
log.Info(fmt.Sprintf("digest: %s", logger.ColorizeSubject(digest.DigestStr())))

return nil
}
5 changes: 3 additions & 2 deletions cmd/timoni/artifact_tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/spf13/cobra"

"github.com/stefanprodan/timoni/internal/flags"
"github.com/stefanprodan/timoni/internal/logger"
"github.com/stefanprodan/timoni/internal/oci"
)

Expand Down Expand Up @@ -62,7 +63,7 @@ func tagArtifactCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("at least one tag is required")
}

spin := StartSpinner("tagging artifact")
spin := logger.StartSpinner("tagging artifact")
defer spin.Stop()

log := LoggerFrom(cmd.Context())
Expand All @@ -86,7 +87,7 @@ func tagArtifactCmdRun(cmd *cobra.Command, args []string) error {
}

for _, tag := range tagArtifactArgs.tags {
log.Info(fmt.Sprintf("tagged: %s", colorizeSubject(fmt.Sprintf("%s:%s", baseURL, tag))))
log.Info(fmt.Sprintf("tagged: %s", logger.ColorizeSubject(fmt.Sprintf("%s:%s", baseURL, tag))))
}

return nil
Expand Down
Loading

0 comments on commit 770e822

Please sign in to comment.