From 7d5f5642c5462d8cf420b2b272ce00dd5bb16c40 Mon Sep 17 00:00:00 2001 From: Berger Eugene Date: Sun, 17 Sep 2023 19:05:49 +0300 Subject: [PATCH] Support NS filters --- README.md | 6 +++ process-compose.override.yaml | 1 + process-compose.yaml | 3 -- src/admitter/admitter.go | 7 +++ src/admitter/disabled.go | 10 ++++ src/admitter/namespace.go | 19 +++++++ src/admitter/namespace_test.go | 92 ++++++++++++++++++++++++++++++++++ src/app/project_runner.go | 5 +- src/cmd/root.go | 5 ++ src/cmd/up.go | 12 +++-- src/loader/loader.go | 15 ++++++ src/loader/loader_options.go | 8 ++- src/types/project.go | 18 ++++--- 13 files changed, 184 insertions(+), 17 deletions(-) create mode 100644 src/admitter/admitter.go create mode 100644 src/admitter/disabled.go create mode 100644 src/admitter/namespace.go create mode 100644 src/admitter/namespace_test.go diff --git a/README.md b/README.md index e6e758b..85f265b 100755 --- a/README.md +++ b/README.md @@ -679,6 +679,12 @@ processes: namespace: debug # if not defined 'default' namespace is automatically assigned to each process ``` +Note: By default `process-compose` will start process from all the configured namespaces. To start a sub set of the configured namespaces (`ns1`, `ns2`, `ns3`): + +```shell +process-compose -n ns1 -n ns3 # will start only ns1 and ns3. ns2 namespace won't run and won't be visible in the TUI +``` + #### Multi-platform ##### Linux diff --git a/process-compose.override.yaml b/process-compose.override.yaml index 99a1471..b339b85 100644 --- a/process-compose.override.yaml +++ b/process-compose.override.yaml @@ -12,6 +12,7 @@ processes: process0: command: "ls -lFa --color=always" working_dir: "/" + namespace: "ns1" process1: command: "./test_loop.bash ${PROC4}" diff --git a/process-compose.yaml b/process-compose.yaml index 958440e..7d55f49 100644 --- a/process-compose.yaml +++ b/process-compose.yaml @@ -96,9 +96,6 @@ processes: working_dir: "/tmp" environment: - 'REDACTED=1' - depends_on: - process0: - condition: process_completed namespace: debug __pc_log_client: diff --git a/src/admitter/admitter.go b/src/admitter/admitter.go new file mode 100644 index 0000000..702d8c1 --- /dev/null +++ b/src/admitter/admitter.go @@ -0,0 +1,7 @@ +package admitter + +import "github.com/f1bonacc1/process-compose/src/types" + +type Admitter interface { + Admit(config *types.ProcessConfig) bool +} diff --git a/src/admitter/disabled.go b/src/admitter/disabled.go new file mode 100644 index 0000000..6b83e6b --- /dev/null +++ b/src/admitter/disabled.go @@ -0,0 +1,10 @@ +package admitter + +import "github.com/f1bonacc1/process-compose/src/types" + +type DisabledProcAdmitter struct { +} + +func (d *DisabledProcAdmitter) Admit(proc *types.ProcessConfig) bool { + return !proc.Disabled +} diff --git a/src/admitter/namespace.go b/src/admitter/namespace.go new file mode 100644 index 0000000..0a16790 --- /dev/null +++ b/src/admitter/namespace.go @@ -0,0 +1,19 @@ +package admitter + +import "github.com/f1bonacc1/process-compose/src/types" + +type NamespaceAdmitter struct { + EnabledNamespaces []string +} + +func (n *NamespaceAdmitter) Admit(proc *types.ProcessConfig) bool { + if len(n.EnabledNamespaces) == 0 { + return true + } + for _, ns := range n.EnabledNamespaces { + if ns == proc.Namespace { + return true + } + } + return false +} diff --git a/src/admitter/namespace_test.go b/src/admitter/namespace_test.go new file mode 100644 index 0000000..83a8c9c --- /dev/null +++ b/src/admitter/namespace_test.go @@ -0,0 +1,92 @@ +package admitter + +import ( + "github.com/f1bonacc1/process-compose/src/types" + "testing" +) + +func TestNamespaceAdmitter_Admit(t *testing.T) { + type fields struct { + EnabledNamespaces []string + } + type args struct { + proc *types.ProcessConfig + } + tests := []struct { + name string + fields fields + args args + want bool + }{ + { + name: "no namespace", + fields: fields{ + EnabledNamespaces: []string{}, + }, + args: args{ + proc: &types.ProcessConfig{ + Namespace: "", + }, + }, + want: true, + }, + { + name: "nil namespace", + fields: fields{ + EnabledNamespaces: nil, + }, + args: args{ + proc: &types.ProcessConfig{ + Namespace: "", + }, + }, + want: true, + }, + { + name: "mismatched namespace", + fields: fields{ + EnabledNamespaces: []string{"test"}, + }, + args: args{ + proc: &types.ProcessConfig{ + Namespace: "not-test", + }, + }, + want: false, + }, + { + name: "matched namespace", + fields: fields{ + EnabledNamespaces: []string{"test"}, + }, + args: args{ + proc: &types.ProcessConfig{ + Namespace: "test", + }, + }, + want: true, + }, + { + name: "matched namespaces", + fields: fields{ + EnabledNamespaces: []string{"not-test", "test"}, + }, + args: args{ + proc: &types.ProcessConfig{ + Namespace: "test", + }, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + n := &NamespaceAdmitter{ + EnabledNamespaces: tt.fields.EnabledNamespaces, + } + if got := n.Admit(tt.args.proc); got != tt.want { + t.Errorf("Admit() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/src/app/project_runner.go b/src/app/project_runner.go index d4d78d4..c4d24bb 100644 --- a/src/app/project_runner.go +++ b/src/app/project_runner.go @@ -43,10 +43,13 @@ func (p *ProjectRunner) init() { func (p *ProjectRunner) Run() int { p.runningProcesses = make(map[string]*Process) runOrder := []types.ProcessConfig{} - _ = p.project.WithProcesses([]string{}, func(process types.ProcessConfig) error { + err := p.project.WithProcesses([]string{}, func(process types.ProcessConfig) error { runOrder = append(runOrder, process) return nil }) + if err != nil { + log.Error().Msgf("Failed to build project run order: %s", err.Error()) + } var nameOrder []string for _, v := range runOrder { nameOrder = append(nameOrder, v.ReplicaName) diff --git a/src/cmd/root.go b/src/cmd/root.go index 46cc83e..3fb8178 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "github.com/f1bonacc1/process-compose/src/admitter" "github.com/f1bonacc1/process-compose/src/api" "github.com/f1bonacc1/process-compose/src/config" "github.com/f1bonacc1/process-compose/src/loader" @@ -53,10 +54,14 @@ func init() { FileNames: []string{}, } + nsAdmitter := &admitter.NamespaceAdmitter{} + opts.AddAdmitter(nsAdmitter) + rootCmd.Flags().BoolVarP(pcFlags.Headless, "tui", "t", true, "enable TUI (-t=false) (env: "+config.TuiEnvVarName+")") rootCmd.Flags().IntVarP(pcFlags.RefreshRate, "ref-rate", "r", *pcFlags.RefreshRate, "TUI refresh rate in seconds") rootCmd.PersistentFlags().IntVarP(pcFlags.PortNum, "port", "p", *pcFlags.PortNum, "port number (env: "+config.PortEnvVarName+")") rootCmd.Flags().StringArrayVarP(&opts.FileNames, "config", "f", config.GetConfigDefault(), "path to config files to load (env: "+config.ConfigEnvVarName+")") + rootCmd.Flags().StringArrayVarP(&nsAdmitter.EnabledNamespaces, "namespace", "n", nil, "run only specified namespaces (default all)") rootCmd.PersistentFlags().StringVarP(pcFlags.LogFile, "log-file", "L", *pcFlags.LogFile, "Specify the log file path (env: "+config.LogPathEnvVarName+")") } diff --git a/src/cmd/up.go b/src/cmd/up.go index 2f9677f..b04bf89 100644 --- a/src/cmd/up.go +++ b/src/cmd/up.go @@ -1,8 +1,8 @@ package cmd import ( + "github.com/f1bonacc1/process-compose/src/admitter" "github.com/f1bonacc1/process-compose/src/api" - "github.com/f1bonacc1/process-compose/src/config" "github.com/spf13/cobra" ) @@ -23,9 +23,13 @@ will start them and their dependencies only`, func init() { rootCmd.AddCommand(upCmd) - upCmd.Flags().BoolVarP(pcFlags.Headless, "tui", "t", *pcFlags.Headless, "disable tui (-t=false) (env: "+config.TuiEnvVarName+")") - upCmd.Flags().IntVarP(pcFlags.RefreshRate, "ref-rate", "r", *pcFlags.RefreshRate, "tui refresh rate in seconds") + nsAdmitter := &admitter.NamespaceAdmitter{} + opts.AddAdmitter(nsAdmitter) + upCmd.Flags().BoolVarP(pcFlags.NoDependencies, "no-deps", "", *pcFlags.NoDependencies, "don't start dependent processes") - upCmd.Flags().StringArrayVarP(&opts.FileNames, "config", "f", config.GetConfigDefault(), "path to config files to load (env: "+config.ConfigEnvVarName+")") + upCmd.Flags().AddFlag(rootCmd.Flags().Lookup("namespace")) + upCmd.Flags().AddFlag(rootCmd.Flags().Lookup("config")) + upCmd.Flags().AddFlag(rootCmd.Flags().Lookup("ref-rate")) + upCmd.Flags().AddFlag(rootCmd.Flags().Lookup("tui")) } diff --git a/src/loader/loader.go b/src/loader/loader.go index 769b783..e4fe412 100644 --- a/src/loader/loader.go +++ b/src/loader/loader.go @@ -28,8 +28,23 @@ func Load(opts *LoaderOptions) (*types.Project, error) { } mergedProject, err := merge(opts) err = mergedProject.ValidateAfterMerge() + admitProcesses(opts, mergedProject) return mergedProject, err +} +func admitProcesses(opts *LoaderOptions, p *types.Project) *types.Project { + if opts.admitters == nil { + return p + } + for _, process := range p.Processes { + for _, adm := range opts.admitters { + if !adm.Admit(&process) { + log.Info().Msgf("Process %s was removed due to admission policy", process.ReplicaName) + delete(p.Processes, process.ReplicaName) + } + } + } + return p } func mustLoadProjectFromFile(inputFile string) *types.Project { diff --git a/src/loader/loader_options.go b/src/loader/loader_options.go index 28d04f6..2cf5ed4 100644 --- a/src/loader/loader_options.go +++ b/src/loader/loader_options.go @@ -1,6 +1,7 @@ package loader import ( + "github.com/f1bonacc1/process-compose/src/admitter" "github.com/f1bonacc1/process-compose/src/types" "os" "path/filepath" @@ -10,9 +11,14 @@ type LoaderOptions struct { workingDir string FileNames []string projects []*types.Project + admitters []admitter.Admitter } -func (o LoaderOptions) getWorkingDir() (string, error) { +func (o *LoaderOptions) AddAdmitter(adm ...admitter.Admitter) { + o.admitters = append(o.admitters, adm...) +} + +func (o *LoaderOptions) getWorkingDir() (string, error) { if o.workingDir != "" { return o.workingDir, nil } diff --git a/src/types/project.go b/src/types/project.go index c201768..aa2e788 100644 --- a/src/types/project.go +++ b/src/types/project.go @@ -62,13 +62,13 @@ func (p *Project) getProcesses(names ...string) ([]ProcessConfig, error) { processes = append(processes, proc) } else { found := false - for _, proc := range p.Processes { - if proc.Name == name { + for _, process := range p.Processes { + if process.Name == name { found = true - if proc.Disabled { + if process.Disabled { continue } - processes = append(processes, proc) + processes = append(processes, process) } } if !found { @@ -85,6 +85,7 @@ func (p *Project) withProcesses(names []string, fn ProcessFunc, done map[string] if err != nil { return err } + var finalErr error for _, process := range processes { if done[process.ReplicaName] { continue @@ -93,14 +94,15 @@ func (p *Project) withProcesses(names []string, fn ProcessFunc, done map[string] dependencies := process.GetDependencies() if len(dependencies) > 0 { - err := p.withProcesses(dependencies, fn, done) + err = p.withProcesses(dependencies, fn, done) if err != nil { - return err + finalErr = fmt.Errorf("error in process %s dependency: %w", process.Name, err) + continue } } - if err := fn(process); err != nil { + if err = fn(process); err != nil { return err } } - return nil + return finalErr }