From b2b7289a50310ee7501249afa4dcc5807d1954e7 Mon Sep 17 00:00:00 2001 From: John Long Date: Fri, 20 Oct 2023 13:51:11 -0400 Subject: [PATCH] fixed wait when no pods exist, cleaned up info output --- cmd/build.go | 2 +- cmd/deploy.go | 3 +-- cmd/publish.go | 20 ++++++++---------- cmd/release.go | 2 +- internal/config/config.go | 21 +++++++++---------- internal/repo/build.go | 9 ++++---- internal/repo/deploy.go | 43 +++++++++++++++++++++++---------------- internal/repo/init.go | 37 ++++++++++++++++----------------- internal/repo/publish.go | 9 ++++++-- internal/repo/repo.go | 8 ++++++-- 10 files changed, 83 insertions(+), 71 deletions(-) diff --git a/cmd/build.go b/cmd/build.go index 3a5ad45..6449fb9 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -39,5 +39,5 @@ func addCommonBuildFlags(cmd *cobra.Command) { func build(cmd *cobra.Command, args []string) { r := repo.New(cfg) - r.BuildComp(args[0]) + r.Build(args[0]) } diff --git a/cmd/deploy.go b/cmd/deploy.go index 4ebf0c6..9dd57dd 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -12,7 +12,7 @@ var deployCmd = &cobra.Command{ Args: cobra.ExactArgs(1), PreRun: setup, Run: runDeploy, - Short: "Deploy app using the version of the currently checked out Git commit", + Short: "Deploy KubeFox app using the version from the currently checked out Git commit", Long: ``, } @@ -44,6 +44,5 @@ func runDeploy(cmd *cobra.Command, args []string) { d := r.Deploy(name) // Makes output less cluttered. d.ManagedFields = nil - log.InfoNewline() log.Marshal(d) } diff --git a/cmd/publish.go b/cmd/publish.go index f7a3ee6..89fd37f 100644 --- a/cmd/publish.go +++ b/cmd/publish.go @@ -13,7 +13,7 @@ var publishCmd = &cobra.Command{ Args: cobra.MaximumNArgs(1), PreRun: setup, RunE: runPublish, - Short: "Builds, pushes, and deploys app using the version of the currently checked out Git commit", + Short: "Builds, pushes, and deploys KubeFox apps using the version of the currently checked out Git commit", } var ( @@ -39,20 +39,18 @@ func runPublish(cmd *cobra.Command, args []string) error { if !cfg.Flags.SkipDeploy && len(args) == 0 { return fmt.Errorf("accepts 1 arg(s), received 0") } + + var name string if !cfg.Flags.SkipDeploy { - checkCommonDeployFlags(args[0]) + name = args[0] + checkCommonDeployFlags(name) } r := repo.New(cfg) - r.Publish() - - if !cfg.Flags.SkipDeploy { - d := r.Deploy(args[0]) - // Makes output less cluttered. - d.ManagedFields = nil - log.InfoNewline() - log.Marshal(d) - } + d := r.Publish(name) + // Makes output less cluttered. + d.ManagedFields = nil + log.Marshal(d) return nil } diff --git a/cmd/release.go b/cmd/release.go index c7d16f1..3d8072d 100644 --- a/cmd/release.go +++ b/cmd/release.go @@ -11,7 +11,7 @@ var releaseCmd = &cobra.Command{ Args: cobra.ExactArgs(1), PreRun: setup, Run: release, - Short: "Release app using the version of the currently checked out Git commit", + Short: "Release app using the version from the currently checked out Git commit", Long: ` The release command will ensure all components are deployed and then activate their routes. This causes genesis events matching component's routes to be diff --git a/internal/config/config.go b/internal/config/config.go index 4941db2..0cadaa5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -91,7 +91,7 @@ func (cfg *Config) Load() { if errors.Is(err, fs.ErrNotExist) { log.Info("It looks like this is the first time you are using 🦊 Fox. Welcome!") log.InfoNewline() - log.Info("Fox needs some information from you to configure itself. The setup process only") + log.Info("🦊 Fox needs some information from you to configure itself. The setup process only") log.Info("needs to be run once, but if you ever want change things you can use the") log.Info("command 'fox config setup'.") log.InfoNewline() @@ -119,41 +119,40 @@ func (cfg *Config) Setup() { log.Info("If you don't have a Kubernetes cluster you can run one locally with Kind (https://kind.sigs.k8s.io)") log.Info("to experiment with KubeFox.") log.InfoNewline() - log.Info("Fox needs a place to store the KubeFox Component images it will build, normally") - log.Info("this is a remote container registry. However, if you only want to use KubeFox") - log.Info("locally with Kind you can skip this step.") + log.Info("🦊 Fox needs a place to store the component images it will build, normally this is") + log.Info("a remote container registry. However, if you only want to use KubeFox locally") + log.Info("with Kind you can skip this step.") kindOnly := utils.YesNoPrompt("Are you only using KubeFox with local Kind cluster?", false) if kindOnly { cfg.ContainerRegistry.Address = LocalRegistry cfg.ContainerRegistry.Token = "" - cfg.Kind.ClusterName = utils.NamePrompt("Kind cluster name", "kind", true) + cfg.Kind.ClusterName = utils.NamePrompt("Kind cluster", "kind", true) cfg.Kind.AlwaysLoad = true + log.InfoNewline() cfg.done() return } - log.InfoNewline() log.Info("Great! If you don't already have a container registry 🦊 Fox can help setup the") log.Info("GitHub container registry (ghcr.io).") useGH := utils.YesNoPrompt("Would you like to use ghcr.io?", true) + log.InfoNewline() if useGH { cfg.setupGitHub() - } else { - log.InfoNewline() log.Info("No problem. 🦊 Fox just needs to know which container registry to use. Please be") log.Info("sure you have permissions to pull and push images to the registry.") cfg.ContainerRegistry.Address = utils.InputPrompt("Enter the container registry you'd like to use", "", true) cfg.ContainerRegistry.Token = utils.InputPrompt("Enter the container registry access token", "", false) } + log.InfoNewline() cfg.done() } func (cfg *Config) done() { cfg.Fresh = true cfg.Write() - log.InfoNewline() log.Info("Congrats, you are ready to use KubeFox!") log.Info("Check out the quickstart for next steps (https://docs.kubefox.io/quickstart/).") @@ -162,8 +161,7 @@ func (cfg *Config) done() { } func (cfg *Config) setupGitHub() { - log.InfoNewline() - log.Info("Fox needs to create two access tokens. The first is used by 🦊 Fox and is only") + log.Info("🦊 Fox needs to create two access tokens. The first is used by 🦊 Fox and is only") log.Info("stored locally. It allows 🦊 Fox to read your GitHub user and organizations and to") log.Info("push and pull container images to ghcr.io. This information never leaves your") log.Info("workstation.") @@ -193,6 +191,7 @@ func (cfg *Config) setupGitHub() { cfg.GitHub.Org = *pickOrg(orgs) } cfg.ContainerRegistry.Address = fmt.Sprintf("ghcr.io/%s", cfg.GitHub.Org.Name) + log.InfoNewline() } func getToken(scopes []string) string { diff --git a/internal/repo/build.go b/internal/repo/build.go index 808174d..a58fca4 100644 --- a/internal/repo/build.go +++ b/internal/repo/build.go @@ -36,8 +36,8 @@ type DockerfileTar struct { read int } -func (r *repo) BuildComp(compDirName string) string { - img := r.GetContainerImage(compDirName) +func (r *repo) Build(compDirName string) string { + img := r.GetCompImageFromDir(compDirName) compDir := filepath.Join(ComponentsDirName, compDirName) compName := utils.Clean(compDirName) gitCommit := r.GetCompCommit(compDirName) @@ -48,12 +48,12 @@ func (r *repo) BuildComp(compDirName string) string { if found, _ := r.ensureImageExists(img, false); found { log.Info("Component image '%s' exists, skipping build.", img) r.KindLoad(img) + log.InfoNewline() return img } } log.Info("Building component image '%s'.", img) - dfPath := filepath.Join(r.cfg.Flags.RepoPath, ComponentsDirName, compDirName, "Dockerfile") df, err := os.ReadFile(dfPath) if err != nil { @@ -106,8 +106,9 @@ func (r *repo) BuildComp(compDirName string) string { } logResp(pushResp, true) } - r.KindLoad(img) + r.KindLoad(img) + log.InfoNewline() return img } diff --git a/internal/repo/deploy.go b/internal/repo/deploy.go index bbe7709..3b302f9 100644 --- a/internal/repo/deploy.go +++ b/internal/repo/deploy.go @@ -102,7 +102,7 @@ func (r *repo) prepareDeployment() (*v1alpha1.Platform, *v1alpha1.DeploymentSpec if apierrors.IsNotFound(err) { platform = r.pickPlatform() } else { - log.Fatal("Unable to get Platform: %v", err) + log.Fatal("Unable to get KubeFox platform: %v", err) } } } @@ -111,19 +111,22 @@ func (r *repo) prepareDeployment() (*v1alpha1.Platform, *v1alpha1.DeploymentSpec allFound := true for n, c := range spec.Components { - img := fmt.Sprintf("%s/%s:%s", spec.App.ContainerRegistry, n, c.Commit) - found, _ := r.ensureImageExists(img, false) - if !found { + img := r.GetCompImage(n, c.Commit) + if found, _ := r.ensureImageExists(img, false); found { + log.Info("Component image '%s' exists.", img) + } else { + log.Warn("Component image '%s' does not exist.", img) allFound = false - break } } + log.InfoNewline() if !allFound { log.Info("There are one or more missing component images. 🦊 Fox will need to build and") log.Info("push them to the container registry before continuing with the operation.") if utils.YesNoPrompt("Missing component images, would you like to publish them?", true) { - r.Publish() + log.InfoNewline() + r.Publish("") } else { log.Fatal("There are one or more missing component images.") } @@ -181,14 +184,14 @@ func (r *repo) pickPlatform() *v1alpha1.Platform { if !r.cfg.Flags.Info { context := r.k8s.KubeConfig.CurrentContext cluster := r.k8s.KubeConfig.Contexts[context].Cluster - log.Warn("No Platforms found on the current cluster '%s'.", cluster) + log.Warn("No KubeFox platforms found on the current cluster '%s'.", cluster) } - log.Info("You need to have a KubeFox Platform instance running to deploy your components.") + log.Info("You need to have a KubeFox platform instance running to deploy your components.") log.Info("Don't worry, 🦊 Fox can create one for you.") - if utils.YesNoPrompt("Would you like to create a Platform?", true) { + if utils.YesNoPrompt("Would you like to create a KubeFox platform?", true) { return r.createPlatform() } else { - log.Fatal("Error you must create a Platform before deploying Components.") + log.Fatal("Error you must create a KubeFox platform before deploying components.") } case 1: return &pList[0] @@ -199,7 +202,7 @@ func (r *repo) pickPlatform() *v1alpha1.Platform { } var input string - log.Printf("Select the KubeFox Platform to use: ") + log.Printf("Select the KubeFox platform to use: ") fmt.Scanln(&input) i, err := strconv.Atoi(input) if err != nil { @@ -212,20 +215,22 @@ func (r *repo) pickPlatform() *v1alpha1.Platform { p := &pList[i] if len(pList) > 1 { - if utils.YesNoPrompt("Remember selected Platform?", true) { + if utils.YesNoPrompt("Remember selected KubeFox platform?", true) { r.cfg.KubeFox.Namespace = p.Namespace r.cfg.KubeFox.Platform = p.Name r.cfg.Write() } } + log.InfoNewline() return p } func (r *repo) createPlatform() *v1alpha1.Platform { - name := utils.NamePrompt("Platform", "", true) - namespace := utils.InputPrompt("Enter the Kubernetes namespace of the Platform", + name := utils.NamePrompt("KubeFox platform", "", true) + namespace := utils.InputPrompt("Enter the Kubernetes namespace of the KubeFox platform", fmt.Sprintf("kubefox-%s", name), true) + log.InfoNewline() ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() @@ -268,7 +273,7 @@ func (r *repo) waitForReady(p *v1alpha1.Platform, spec *v1alpha1.DeploymentSpec) ctx, cancel := context.WithTimeout(context.Background(), r.cfg.Flags.WaitTime) defer cancel() - log.Info("Waiting for Platform '%s' to be ready.", p.Name) + log.Info("Waiting for KubeFox platform '%s' to be ready.", p.Name) if err := r.checkAllPodsRdy(ctx, p, "nats", ""); err != nil { log.Fatal("Error while waiting: %v", err) } @@ -277,15 +282,17 @@ func (r *repo) waitForReady(p *v1alpha1.Platform, spec *v1alpha1.DeploymentSpec) } for n, c := range spec.Components { - log.Info("Waiting for Component '%s' to be ready.", n) + log.Info("Waiting for component '%s' to be ready.", n) if err := r.checkAllPodsRdy(ctx, p, n, c.Commit); err != nil { log.Fatal("Error while waiting: %v", err) } } + log.InfoNewline() } func (r *repo) checkAllPodsRdy(ctx context.Context, p *v1alpha1.Platform, comp, commit string) error { - log.Verbose("Waiting for Component '%s' with commit '%s' to be ready.", comp, commit) + log.Verbose("Waiting for component '%s' with commit '%s' to be ready.", comp, commit) + hasLabels := client.MatchingLabels{ kubefox.LabelK8sComponent: comp, kubefox.LabelK8sPlatform: p.Name, @@ -299,7 +306,7 @@ func (r *repo) checkAllPodsRdy(ctx context.Context, p *v1alpha1.Platform, comp, return fmt.Errorf("unable to list pods: %w", err) } - ready := true + ready := len(l.Items) > 0 for _, p := range l.Items { for _, c := range p.Status.ContainerStatuses { if !c.Ready { diff --git a/internal/repo/init.go b/internal/repo/init.go index 404774b..8939cfd 100644 --- a/internal/repo/init.go +++ b/internal/repo/init.go @@ -26,38 +26,36 @@ func Init(cfg *config.Config) { app, err := ReadApp(repoPath) if err != nil && !errors.Is(err, fs.ErrNotExist) { - log.Error("An app definition already exists but appears to be invalid: %v.", err) - if !utils.YesNoPrompt("Would you like to reinitialize the repo?", true) { + log.Error("An KubeFox app definition already exists but appears to be invalid: %v.", err) + if !utils.YesNoPrompt("Would you like to reinitialize the app?", true) { return } } else if !errors.Is(err, fs.ErrNotExist) { log.VerboseMarshal(app, "App definition:") - log.Info("A valid app definition already exists.") + log.Info("A valid KubeFox app definition already exists.") initGit(repoPath, app, cfg) return } app = &App{} - log.Info("Let's initialize a KubeFox repo!") - + log.Info("Let's initialize a KubeFox app!") log.InfoNewline() - log.Info("To get things started quickly 🦊 Fox can create a hello-world app which includes") - log.Info("two components and example environments for testing.") - if utils.YesNoPrompt("Would you like to initialize the hello-world app?", false) { + log.Info("To get things started quickly 🦊 Fox can create a 'hello-world' KubeFox app which") + log.Info("includes two components and example environments for testing.") + if utils.YesNoPrompt("Would you like to initialize the 'hello-world' KubeFox app?", false) { initDir(efs.HelloWorldPath, repoPath) initGit(repoPath, app, cfg) return } - log.InfoNewline() - log.Info("Fox needs to create an app definition for the repo. The definition is stored in") - log.Info("the 'app.yaml' file in the root of the repo. The first thing it needs is a name") - log.Info("for the app. The name is used as part of Kubernetes resource names so it must") - log.Info("contain only lowercase alpha-numeric characters and dashes. But don't worry") - log.Info("you can enter a more human friendly title and description.") - app.Name = utils.NamePrompt("app", utils.Clean(repoPath), true) - app.Title = utils.InputPrompt("Enter the app's title", "", false) - app.Description = utils.InputPrompt("Enter the app's description", "", false) + log.Info("🦊 Fox needs to create an KubeFox app definition. The definition is stored in the") + log.Info("'app.yaml' file in the root of the repo. The first thing it needs is a name for") + log.Info("the app. The name is used as part of Kubernetes resource names so it must") + log.Info("contain only lowercase alpha-numeric characters and dashes. But don't worry you") + log.Info("can enter a more human friendly title and description.") + app.Name = utils.NamePrompt("KubeFox app", utils.Clean(repoPath), true) + app.Title = utils.InputPrompt("Enter the KubeFox app's title", "", false) + app.Description = utils.InputPrompt("Enter the KubeFox app's description", "", false) WriteApp(repoPath, app) utils.EnsureDir(filepath.Join(repoPath, ComponentsDirName)) @@ -88,7 +86,8 @@ func initGit(repoPath string, app *App, cfg *config.Config) { } log.InfoNewline() - log.Info("KubeFox repo initialization complete!") + log.Info("KubeFox app initialization complete!") + log.InfoNewline() } func initDir(in, out string) { @@ -98,7 +97,7 @@ func initDir(in, out string) { fs.WalkDir(efs.EFS, in, func(efsPath string, d fs.DirEntry, err error) error { if err != nil { - log.Fatal("Error initializing repo: %v", err) + log.Fatal("Error initializing app: %v", err) } if d.IsDir() { return nil diff --git a/internal/repo/publish.go b/internal/repo/publish.go index 3a361c9..67d83b1 100644 --- a/internal/repo/publish.go +++ b/internal/repo/publish.go @@ -5,9 +5,10 @@ import ( "path/filepath" "github.com/xigxog/kubefox-cli/internal/log" + "github.com/xigxog/kubefox/libs/api/kubernetes/v1alpha1" ) -func (r *repo) Publish() { +func (r *repo) Publish(deployName string) *v1alpha1.Deployment { compsDirPath := filepath.Join(r.cfg.Flags.RepoPath, ComponentsDirName) compsDir, err := os.ReadDir(compsDirPath) if err != nil { @@ -18,7 +19,11 @@ func (r *repo) Publish() { if !compDir.IsDir() { continue } + r.Build(compDir.Name()) + } - r.BuildComp(compDir.Name()) + if !r.cfg.Flags.SkipDeploy && deployName != "" { + return r.Deploy(deployName) } + return nil } diff --git a/internal/repo/repo.go b/internal/repo/repo.go index 816195a..385e407 100644 --- a/internal/repo/repo.go +++ b/internal/repo/repo.go @@ -42,7 +42,7 @@ func New(cfg *config.Config) *repo { app, err := ReadApp(repoPath) if err != nil { - log.Fatal("Error reading the Repo's 'app.yaml', try running 'fox init': %v", err) + log.Fatal("Error reading the repo's 'app.yaml', try running 'fox init': %v", err) } log.Verbose("Opening git repo '%s'", repoPath) @@ -111,9 +111,13 @@ func (r *repo) CommitAll(msg string) string { return hash.String() } -func (r *repo) GetContainerImage(compDirName string) string { +func (r *repo) GetCompImageFromDir(compDirName string) string { name := utils.Clean(compDirName) commit := r.GetCompCommit(compDirName) + return r.GetCompImage(name, commit) +} + +func (r *repo) GetCompImage(name, commit string) string { return fmt.Sprintf("%s/%s/%s:%s", r.cfg.ContainerRegistry.Address, r.app.Name, name, commit) }