VOL-3943 - multiple stack configuration support
Change-Id: I28cb26b6cd6fbc5b3f0e8d406a68bf5c964a57fd
diff --git a/internal/pkg/commands/stacks.go b/internal/pkg/commands/stacks.go
new file mode 100644
index 0000000..9a894cc
--- /dev/null
+++ b/internal/pkg/commands/stacks.go
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2021-present Ciena Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package commands
+
+import (
+ "fmt"
+ "os"
+
+ flags "github.com/jessevdk/go-flags"
+ configv3 "github.com/opencord/voltctl/internal/pkg/apis/config/v3"
+ "github.com/opencord/voltctl/pkg/format"
+ yaml "gopkg.in/yaml.v2"
+)
+
+const (
+ DefaultOutputFormat = "table{{.Current}}\t{{.Name}}\t{{.Server}}\t{{.KvStore}}\t{{.Kafka}}"
+)
+
+type StackUse struct {
+ Args struct {
+ Name string `positional-arg-name:"NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type StackAdd struct {
+ Args struct {
+ Name string `positional-arg-name:"NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type StackDelete struct {
+ Args struct {
+ Name string `positional-arg-name:"NAME" required:"yes"`
+ } `positional-args:"yes"`
+}
+
+type StackList struct {
+ ListOutputOptions
+}
+
+type StackOptions struct {
+ List StackList `command:"list" description:"list all configured stacks"`
+ Add StackAdd `command:"add" description:"add or update the named stack using command line options"`
+ Delete StackDelete `command:"delete" description:"delete the specified stack configuration"`
+ Use StackUse `command:"use" description:"perist the specified stack to be used by default"`
+}
+
+func RegisterStackCommands(parent *flags.Parser) {
+ if _, err := parent.AddCommand("stack", "generate voltctl configuration", "Commands to generate voltctl configuration", &StackOptions{}); err != nil {
+ Error.Fatalf("Unexpected error while attempting to register config commands : %s", err)
+ }
+}
+
+type StackInfo struct {
+ Current string `json:"current"`
+ Name string `json:"name"`
+ Server string `json:"server"`
+ Kafka string `json:"kafka"`
+ KvStore string `json:"kvstore"`
+}
+
+func write() error {
+ w, err := os.OpenFile(GlobalOptions.Config, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ encode := yaml.NewEncoder(w)
+ if err := encode.Encode(GlobalConfig); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (options *StackList) Execute(args []string) error {
+
+ ReadConfig()
+ ApplyOptionOverrides(nil)
+
+ var data []StackInfo
+ for _, stack := range GlobalConfig.Stacks {
+ s := StackInfo{
+ Name: stack.Name,
+ Server: stack.Server,
+ Kafka: stack.Kafka,
+ KvStore: stack.KvStore,
+ }
+ if stack.Name == GlobalConfig.CurrentStack {
+ s.Current = "*"
+ }
+ data = append(data, s)
+ }
+
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = GetCommandOptionWithDefault("stack-list", "format",
+ DefaultOutputFormat)
+ }
+ if options.Quiet {
+ outputFormat = "{{.Name}}"
+ }
+ orderBy := options.OrderBy
+ if orderBy == "" {
+ orderBy = GetCommandOptionWithDefault("stack-list", "order", "")
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ Filter: options.Filter,
+ OrderBy: orderBy,
+ OutputAs: toOutputType(options.OutputAs),
+ NameLimit: options.NameLimit,
+ Data: data,
+ }
+
+ GenerateOutput(&result)
+ return nil
+}
+
+func (options *StackUse) Execute(args []string) error {
+
+ ReadConfig()
+
+ for _, stack := range GlobalConfig.Stacks {
+ if stack.Name == options.Args.Name {
+ GlobalConfig.CurrentStack = stack.Name
+ ApplyOptionOverrides(stack)
+ if err := write(); err != nil {
+ Error.Fatal(err.Error())
+ }
+ fmt.Printf("wrote: '%s'\n", GlobalOptions.Config)
+ return nil
+ }
+ }
+
+ Error.Fatalf("unknown stack: '%s'", options.Args.Name)
+
+ return nil
+}
+
+func (options *StackDelete) Execute(args []string) error {
+
+ ReadConfig()
+ ApplyOptionOverrides(nil)
+
+ for i, stack := range GlobalConfig.Stacks {
+ if stack.Name == options.Args.Name {
+ GlobalConfig.Stacks = append(GlobalConfig.Stacks[:i], GlobalConfig.Stacks[i+1:]...)
+ if GlobalConfig.CurrentStack == stack.Name {
+ GlobalConfig.CurrentStack = ""
+ }
+ if err := write(); err != nil {
+ Error.Fatal(err.Error())
+ }
+ fmt.Printf("wrote: '%s'\n", GlobalOptions.Config)
+ return nil
+ }
+ }
+
+ Error.Fatalf("stack not found, '%s'", options.Args.Name)
+ return nil
+}
+
+func (options *StackAdd) Execute(args []string) error {
+
+ ReadConfig()
+ stack := GlobalConfig.StackByName(options.Args.Name)
+
+ if stack == nil {
+ stack = configv3.NewDefaultStack(options.Args.Name)
+ GlobalConfig.Stacks = append(GlobalConfig.Stacks, stack)
+ }
+ if GlobalConfig.CurrentStack == "" {
+ GlobalConfig.CurrentStack = options.Args.Name
+ }
+ ApplyOptionOverrides(stack)
+ if err := write(); err != nil {
+ Error.Fatal(err.Error())
+ }
+ return nil
+}