Skip to content

Commit

Permalink
WIP: adding more spinners for pkg verification and download
Browse files Browse the repository at this point in the history
  • Loading branch information
UncleGedd committed Mar 21, 2024
1 parent cfdbf69 commit c8562c3
Show file tree
Hide file tree
Showing 11 changed files with 364 additions and 168 deletions.
6 changes: 3 additions & 3 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var rootCmd = &cobra.Command{

// don't load log configs for the logs command
if cmd.Use != "logs" {
cliSetup()
cliSetup(cmd.Use)
}
},
Short: lang.RootCmdShort,
Expand Down Expand Up @@ -92,7 +92,7 @@ func init() {
rootCmd.PersistentFlags().BoolVar(&config.CommonOptions.NoTea, "no-tea", v.GetBool(V_NO_TEA), lang.RootCmdNoTea)
}

func cliSetup() {
func cliSetup(op string) {
match := map[string]message.LogLevel{
"warn": message.WarnLevel,
"info": message.InfoLevel,
Expand All @@ -113,7 +113,7 @@ func cliSetup() {
}

if !config.SkipLogFile && !config.ListTasks {
err := utils.ConfigureLogs()
err := utils.ConfigureLogs(op)
if err != nil {
message.Fatalf(err, "Error configuring logs")
}
Expand Down
53 changes: 23 additions & 30 deletions src/cmd/uds.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/defenseunicorns/uds-cli/src/config/lang"
"github.com/defenseunicorns/uds-cli/src/pkg/bundle"
"github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy"
"github.com/defenseunicorns/uds-cli/src/pkg/utils"
zarfConfig "github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/pkg/message"
zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils"
Expand Down Expand Up @@ -77,13 +76,6 @@ var deployCmd = &cobra.Command{
Short: lang.CmdBundleDeployShort,
Args: cobra.MaximumNArgs(1),
Run: func(_ *cobra.Command, args []string) {
// reconfigure logs for the deploy command so we can use BubbleTea
config.TeaEnabled = true
err := utils.ConfigureLogs()
if err != nil {
message.Fatalf(err, "Error configuring logs")
}

bundleCfg.DeployOpts.Source = chooseBundle(args)
configureZarf()

Expand All @@ -98,37 +90,18 @@ var deployCmd = &cobra.Command{
bndlClient := bundle.NewOrDie(&bundleCfg)
defer bndlClient.ClearPaths()

// pre-deploy validation
bundleYAML := ""
bundleYAML, err = bndlClient.PreDeployValidation()
if err != nil {
return
}

// don't use bubbletea if --no-tea flag is set
if config.CommonOptions.NoTea {
// confirm deployment
if ok := bndlClient.ConfirmBundleDeploy(); !ok {
message.Fatal(nil, "bundle deployment cancelled")
}
// create an empty program and kill it, this makes Program.Send a no-op
deploy.Program = tea.NewProgram(nil)
deploy.Program.Kill()

// deploy the bundle
if err := bndlClient.Deploy(); err != nil {
bndlClient.ClearPaths()
message.Fatalf(err, "Failed to deploy bundle: %s", err.Error())
}
deployWithoutTea(bndlClient)
return
}

// start up bubbletea
m := deploy.InitModel(bndlClient, bundleYAML)
m := deploy.InitModel(bndlClient)

// detect tty so CI/containers don't break
if term.IsTerminal(int(os.Stdout.Fd())) {
deploy.Program = tea.NewProgram(&m, tea.WithMouseCellMotion())
deploy.Program = tea.NewProgram(&m)
} else {
deploy.Program = tea.NewProgram(&m, tea.WithInput(nil))
}
Expand All @@ -139,6 +112,26 @@ var deployCmd = &cobra.Command{
},
}

func deployWithoutTea(bndlClient *bundle.Bundle) {
_, _, _, err := bndlClient.PreDeployValidation()
if err != nil {
message.Fatalf(err, "Failed to validate bundle: %s", err.Error())
}
// confirm deployment
if ok := bndlClient.ConfirmBundleDeploy(); !ok {
message.Fatal(nil, "bundle deployment cancelled")
}
// create an empty program and kill it, this makes Program.Send a no-op
deploy.Program = tea.NewProgram(nil)
deploy.Program.Kill()

// deploy the bundle
if err := bndlClient.Deploy(); err != nil {
bndlClient.ClearPaths()
message.Fatalf(err, "Failed to deploy bundle: %s", err.Error())
}
}

var inspectCmd = &cobra.Command{
Use: "inspect [BUNDLE_TARBALL|OCI_REF]",
Aliases: []string{"i"},
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var versionCmd = &cobra.Command{
Aliases: []string{"v"},
PersistentPreRun: func(_ *cobra.Command, _ []string) {
config.SkipLogFile = true
cliSetup()
cliSetup("")
},
Short: lang.CmdVersionShort,
Long: lang.CmdVersionLong,
Expand Down
21 changes: 11 additions & 10 deletions src/pkg/bundle/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,57 +281,58 @@ func (b *Bundle) loadChartOverrides(pkg types.Package, pkgVars map[string]string
return processed, nil
}

func (b *Bundle) PreDeployValidation() (string, error) {
func (b *Bundle) PreDeployValidation() (string, string, string, error) {

// Check that provided oci source path is valid, and update it if it's missing the full path
source, err := CheckOCISourcePath(b.cfg.DeployOpts.Source)
if err != nil {
return "", err
return "", "", "", err
}
b.cfg.DeployOpts.Source = source

// validate config's arch against cluster
err = ValidateArch(config.GetArch())
if err != nil {
return "", err
return "", "", "", err
}

// create a new provider
provider, err := NewBundleProvider(b.cfg.DeployOpts.Source, b.tmp)
if err != nil {
return "", err
return "", "", "", err
}

// pull the bundle's metadata + sig
loaded, err := provider.LoadBundleMetadata()
if err != nil {
return "", err
return "", "", "", err
}

// validate the sig (if present)
if err := ValidateBundleSignature(loaded[config.BundleYAML], loaded[config.BundleYAMLSignature], b.cfg.DeployOpts.PublicKeyPath); err != nil {
return "", err
return "", "", "", err
}

// read in file at config.BundleYAML
message.Debugf("Reading YAML at %s", loaded[config.BundleYAML])
bundleYAML, err := os.ReadFile(loaded[config.BundleYAML])
if err != nil {
return "", err
return "", "", "", err
}

// todo: we also read the SHAs from the uds-bundle.yaml here, should we refactor so that we use the bundle's root manifest?
if err := goyaml.Unmarshal(bundleYAML, &b.bundle); err != nil {
return "", err
return "", "", "", err
}

// Maps name given to zarf package in the bundle to the actual name of the zarf package
zarfPackageNameMap, err := provider.ZarfPackageNameMap()
if err != nil {
return "", err
return "", "", "", err
}
b.cfg.DeployOpts.ZarfPackageNameMap = zarfPackageNameMap
return string(bundleYAML), err
bundleName := b.bundle.Metadata.Name
return bundleName, string(bundleYAML), source, err
}

// processOverrideValues processes a bundles values overrides and adds them to the override map
Expand Down
5 changes: 4 additions & 1 deletion src/pkg/bundle/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -289,7 +290,9 @@ func getOCIValidatedSource(source string) (string, error) {
_, err = remote.ResolveRoot(ctx)
}
if err != nil {
message.Fatalf(nil, "%s: not found", originalSource)
errMsg := fmt.Sprintf("%s: not found", originalSource)
message.Debug(errMsg)
return "", errors.New(errMsg)
}
}
}
Expand Down
23 changes: 20 additions & 3 deletions src/pkg/bundle/tarball.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,26 @@ func (tp *tarballBundleProvider) PublishBundle(bundle types.UDSBundle, remote *o
return err
}

_, err = oras.Copy(tp.ctx, store, ref, remote.Repo(), ref, copyOpts)
if err != nil {
return err
// copy bundle layers to remote with retries
maxRetries := 3
retries := 0

// reset retries if a desc was successful
copyOpts.PostCopy = func(_ context.Context, desc ocispec.Descriptor) error {
retries = 0
return nil
}

for {
_, err = oras.Copy(tp.ctx, store, ref, remote.Repo(), ref, copyOpts)
if err != nil && retries < maxRetries {
retries++
message.Debugf("Encountered err during publish: %s\nRetrying %d/%d", err, retries, maxRetries)
continue
} else if err != nil {
return err
}
break
}

// create or update, then push index.json
Expand Down
67 changes: 44 additions & 23 deletions src/pkg/bundle/tui/deploy/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package deploy
import (
"fmt"
"os"
"strings"

"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
Expand Down Expand Up @@ -37,14 +38,45 @@ func (m *Model) handleNewPackage(pkgName string, currentPkgIdx int) tea.Cmd {
deploySpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
newPkg.deploySpinner = deploySpinner

// for remote packages, create spinner to track verification progress
// for remote packages, create spinner to track verification and download progress
verifySpinner := spinner.New()
verifySpinner.Spinner = spinner.Dot
verifySpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
newPkg.verifySpinner = verifySpinner
downloadSpinner := spinner.New()
downloadSpinner.Spinner = spinner.Dot
downloadSpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
newPkg.downloadSpinner = downloadSpinner

// create spinner to track total bundle progress
bundleSpinner := spinner.New()
bundleSpinner.Spinner = spinner.Ellipsis
bundleSpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))

m.packages = append(m.packages, newPkg)
return tea.Batch(m.packages[m.pkgIdx].deploySpinner.Tick, m.packages[m.pkgIdx].verifySpinner.Tick)
return tea.Batch(m.packages[m.pkgIdx].deploySpinner.Tick,
m.packages[m.pkgIdx].verifySpinner.Tick,
m.packages[m.pkgIdx].downloadSpinner.Tick,
)
}

func (m *Model) handlePreDeploy() tea.Cmd {
cmd := func() tea.Msg {
name, bundleYAML, source, err := m.bndlClient.PreDeployValidation()
if err != nil {
m.errChan <- err
}
m.validatingBundle = false
m.bundleYAML = bundleYAML
m.bundleName = name
// check if the bundle is remote
if strings.HasPrefix(source, "oci://") {
m.isRemoteBundle = true
}
return doDeploy
}

return cmd
}

func (m *Model) handleDeploy() tea.Cmd {
Expand All @@ -70,15 +102,21 @@ func (m *Model) handleDeploy() tea.Cmd {
}

func (m *Model) handleDone(err error) tea.Cmd {
var cmds []tea.Cmd
//uds := " __ ______ _____\n / / / / __ \\/ ___/\n / / / / / / /\\__ \\ \n/ /_/ / /_/ /___/ / \n\\____/_____//____/ \n \n"
cmds := []tea.Cmd{tea.Println(), tea.Println(m.udsTitle()), tea.Println()}
m.done = true // remove the current view
cmds = append(cmds, genSuccessOrFailCmds(m)...)
if err != nil {
hint := lightBlueText.Render("uds logs")
errMsg := lipgloss.NewStyle().Padding(0, 3).Render(fmt.Sprintf("\n❌ Error deploying bundle: %s\n\nRun %s to view deployment logs", lightGrayText.Render(err.Error()), hint) + "\n")
cmds = []tea.Cmd{tea.Println(errMsg)}
errMsg := lipgloss.NewStyle().Padding(0, 4).Render(fmt.Sprintf("\n❌ Error deploying bundle: %s\n\nRun %s to view deployment logs", lightGrayText.Render(err.Error()), hint) + "\n")
cmds = []tea.Cmd{tea.Println(errMsg), tui.Pause(), tea.Quit}
return tea.Sequence(cmds...)
}
cmds = append(cmds, tui.Pause(), tea.Quit)
styledBundleName := lipgloss.NewStyle().Foreground(lipgloss.Color("#FFF258")).Render(m.bundleName)
successMsg := tea.Println(lipgloss.NewStyle().
Padding(0, 4).
Render(fmt.Sprintf("\n✨ Bundle %s deployed successfully\n", styledBundleName)))
cmds = append(cmds, successMsg, tui.Pause(), tea.Quit)
return tea.Sequence(cmds...)
}

Expand Down Expand Up @@ -138,20 +176,3 @@ func (m *Model) handleDeployTick() (tea.Model, tea.Cmd) {

return m, tickCmd()
}

// genSuccessOrFailCmds generates the success or failure messages for each package
func genSuccessOrFailCmds(m *Model) []tea.Cmd {
cmds := []tea.Cmd{tea.Println(fmt.Sprintf("%s\n", logMsg))}
for i := 0; i < len(m.packages); i++ {
if m.packages[i].complete {
successStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#32A852")).Padding(0, 3)
successMsg := fmt.Sprintf("✅ Package %s deployed\n", m.packages[i].name)
cmds = append(cmds, tea.Println(successStyle.Render(successMsg)))
} else {
failStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#FF0000")).Padding(0, 3)
failMsg := fmt.Sprintf("❌ Package %s failed to deploy\n", m.packages[i].name)
cmds = append(cmds, tea.Println(failStyle.Render(failMsg)))
}
}
return cmds
}
Loading

0 comments on commit c8562c3

Please sign in to comment.