VOL-3943 - multiple stack configuration support
Change-Id: I28cb26b6cd6fbc5b3f0e8d406a68bf5c964a57fd
diff --git a/MULTIPLE_STACKS.md b/MULTIPLE_STACKS.md
new file mode 100644
index 0000000..412f4cf
--- /dev/null
+++ b/MULTIPLE_STACKS.md
@@ -0,0 +1,27 @@
+# Multiple Stack Support
+
+`voltctl` supports multiple stack configurations in a single configuration
+file. The format of the **v3** configuration file that supports multiple
+stacks is of the format
+
+```yaml
+apiVersion: v3
+currentStack: <stack-name-reference>
+stacks:
+ - name: <stack-name-reference>
+ <values>
+```
+
+## `--stack` command line option
+
+As part of the support for multiple stacks a new command line option,
+`--stack` was added. This option can be used to specify which stack
+configuration should be used for each command invocation.
+
+## Configuration File Manipulations
+
+A new `voltctl` subcommand, `stack` was added to support the listing,
+deletion, and addition of stacks to the configuration file. In addtion
+the `stack use` command was added to persistently set the current
+stack name back to the configuration. _(see `voltctl stack --help`
+for more information)_
diff --git a/VERSION b/VERSION
index bc80560..26ca594 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.5.0
+1.5.1
diff --git a/cmd/voltctl/voltctl.go b/cmd/voltctl/voltctl.go
index e3da44f..074297a 100644
--- a/cmd/voltctl/voltctl.go
+++ b/cmd/voltctl/voltctl.go
@@ -69,6 +69,7 @@
commands.RegisterLogCommands(parser)
commands.RegisterEventCommands(parser)
commands.RegisterMessageCommands(parser)
+ commands.RegisterStackCommands(parser)
_, err = parser.Parse()
if err != nil {
diff --git a/internal/pkg/apis/config/v3/convert.go b/internal/pkg/apis/config/v3/convert.go
new file mode 100644
index 0000000..edb6595
--- /dev/null
+++ b/internal/pkg/apis/config/v3/convert.go
@@ -0,0 +1,66 @@
+/*
+ * 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 config
+
+import (
+ "strconv"
+
+ configv1 "github.com/opencord/voltctl/internal/pkg/apis/config/v1"
+ configv2 "github.com/opencord/voltctl/internal/pkg/apis/config/v2"
+)
+
+func FromConfigV1(v1 *configv1.GlobalConfigSpec) *GlobalConfigSpec {
+ v3 := NewDefaultConfig()
+ s3 := v3.Current()
+
+ s3.Server = v1.Server
+ s3.Kafka = v1.Kafka
+ s3.KvStore = v1.KvStore
+ s3.Tls.UseTls = v1.Tls.UseTls
+ s3.Tls.CACert = v1.Tls.CACert
+ s3.Tls.Cert = v1.Tls.Cert
+ s3.Tls.Key = v1.Tls.Key
+ if v1.Tls.Verify != "" {
+ if b, err := strconv.ParseBool(v1.Tls.Verify); err == nil {
+ s3.Tls.Verify = b
+ }
+ }
+ s3.Grpc.Timeout = v1.Grpc.Timeout
+ s3.Grpc.MaxCallRecvMsgSize = v1.Grpc.MaxCallRecvMsgSize
+ s3.KvStoreConfig.Timeout = v1.KvStoreConfig.Timeout
+ s3.K8sConfig = v1.K8sConfig
+ return v3
+}
+
+func FromConfigV2(v2 *configv2.GlobalConfigSpec) *GlobalConfigSpec {
+ v3 := NewDefaultConfig()
+ s3 := v3.Current()
+
+ s3.Server = v2.Server
+ s3.Kafka = v2.Kafka
+ s3.KvStore = v2.KvStore
+ s3.Tls.UseTls = v2.Tls.UseTls
+ s3.Tls.CACert = v2.Tls.CACert
+ s3.Tls.Cert = v2.Tls.Cert
+ s3.Tls.Key = v2.Tls.Key
+ s3.Tls.Verify = v2.Tls.Verify
+ s3.Grpc.ConnectTimeout = v2.Grpc.ConnectTimeout
+ s3.Grpc.Timeout = v2.Grpc.Timeout
+ s3.Grpc.MaxCallRecvMsgSize = v2.Grpc.MaxCallRecvMsgSize
+ s3.KvStoreConfig.Timeout = v2.KvStoreConfig.Timeout
+ s3.K8sConfig = v2.K8sConfig
+ return v3
+}
diff --git a/internal/pkg/apis/config/v3/defaults.go b/internal/pkg/apis/config/v3/defaults.go
new file mode 100644
index 0000000..2fcdff2
--- /dev/null
+++ b/internal/pkg/apis/config/v3/defaults.go
@@ -0,0 +1,84 @@
+/*
+ * 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 config
+
+import (
+ "log"
+ "os"
+ "time"
+)
+
+func NewDefaultConfig() *GlobalConfigSpec {
+ return &GlobalConfigSpec{
+ ApiVersion: "v3",
+ CurrentStack: "",
+ Stacks: []*StackConfigSpec{NewDefaultStack("default")},
+ }
+}
+
+func NewDefaultStack(name string) *StackConfigSpec {
+ return &StackConfigSpec{
+ Name: name,
+ Server: "localhost:55555",
+ Kafka: "localhost:9093",
+ KvStore: "localhost:2379",
+ Tls: TlsConfigSpec{
+ UseTls: false,
+ Verify: false,
+ },
+ Grpc: GrpcConfigSpec{
+ ConnectTimeout: 5 * time.Second,
+ Timeout: 5 * time.Minute,
+ MaxCallRecvMsgSize: "4MB",
+ },
+ KvStoreConfig: KvStoreConfigSpec{
+ Timeout: 5 * time.Second,
+ },
+ }
+}
+
+func (g *GlobalConfigSpec) StackByName(name string) *StackConfigSpec {
+ for _, stack := range g.Stacks {
+ if stack.Name == name {
+ return stack
+ }
+ }
+ return nil
+}
+
+func (g *GlobalConfigSpec) CurrentAsStack() *StackConfigSpec {
+ if g.CurrentStack == "" {
+ if len(g.Stacks) == 0 {
+ return nil
+ }
+ return g.Stacks[0]
+ }
+ return g.StackByName(g.CurrentStack)
+}
+
+func (g GlobalConfigSpec) Current() *StackConfigSpec {
+ stack := g.CurrentAsStack()
+ if stack == nil {
+ if len(g.Stacks) > 1 {
+ log.New(os.Stderr, "ERROR: ", 0).
+ Fatal("multiple stacks configured without current specified")
+ }
+ log.New(os.Stderr, "ERROR: ", 0).
+ Fatalf("current stack specified, '%s', does not exist as a configured stack",
+ g.CurrentStack)
+ }
+ return stack
+}
diff --git a/internal/pkg/apis/config/v3/types.go b/internal/pkg/apis/config/v3/types.go
new file mode 100644
index 0000000..9639baa
--- /dev/null
+++ b/internal/pkg/apis/config/v3/types.go
@@ -0,0 +1,55 @@
+/*
+ * 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 config
+
+import (
+ "time"
+)
+
+type GrpcConfigSpec struct {
+ ConnectTimeout time.Duration `yaml:"connectTimeout"`
+ Timeout time.Duration `yaml:"timeout"`
+ MaxCallRecvMsgSize string `yaml:"maxCallRecvMsgSize"`
+}
+
+type KvStoreConfigSpec struct {
+ Timeout time.Duration `yaml:"timeout"`
+}
+
+type TlsConfigSpec struct {
+ UseTls bool `yaml:"useTLS"`
+ CACert string `yaml:"caCert"`
+ Cert string `yaml:"cert"`
+ Key string `yaml:"key"`
+ Verify bool `yaml:"verify"`
+}
+
+type StackConfigSpec struct {
+ Name string `yaml:"name"`
+ Server string `yaml:"server"`
+ Kafka string `yaml:"kafka"`
+ KvStore string `yaml:"kvstore"`
+ Tls TlsConfigSpec `yaml:"tls"`
+ Grpc GrpcConfigSpec `yaml:"grpc"`
+ KvStoreConfig KvStoreConfigSpec `yaml:"kvstoreconfig"`
+ K8sConfig string `yaml:"-"`
+}
+
+type GlobalConfigSpec struct {
+ ApiVersion string `yaml:"apiVersion"`
+ Stacks []*StackConfigSpec `yaml:"stacks"`
+ CurrentStack string `yaml:"currentStack"`
+}
diff --git a/internal/pkg/commands/adapter.go b/internal/pkg/commands/adapter.go
index b4183c0..73b91e1 100644
--- a/internal/pkg/commands/adapter.go
+++ b/internal/pkg/commands/adapter.go
@@ -17,8 +17,9 @@
import (
"context"
+
"github.com/golang/protobuf/ptypes/empty"
- "github.com/jessevdk/go-flags"
+ flags "github.com/jessevdk/go-flags"
"github.com/opencord/voltctl/pkg/format"
"github.com/opencord/voltha-protos/v4/go/voltha"
)
@@ -52,7 +53,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
adapters, err := client.ListAdapters(ctx, &empty.Empty{})
diff --git a/internal/pkg/commands/command.go b/internal/pkg/commands/command.go
index 3e1beb4..93944a8 100644
--- a/internal/pkg/commands/command.go
+++ b/internal/pkg/commands/command.go
@@ -35,6 +35,7 @@
"github.com/golang/protobuf/proto"
configv1 "github.com/opencord/voltctl/internal/pkg/apis/config/v1"
configv2 "github.com/opencord/voltctl/internal/pkg/apis/config/v2"
+ configv3 "github.com/opencord/voltctl/internal/pkg/apis/config/v3"
"github.com/opencord/voltctl/pkg/filter"
"github.com/opencord/voltctl/pkg/format"
"github.com/opencord/voltctl/pkg/order"
@@ -70,12 +71,13 @@
CharReplacer = strings.NewReplacer("\\t", "\t", "\\n", "\n")
- GlobalConfig = configv2.NewDefaultConfig()
+ GlobalConfig = configv3.NewDefaultConfig()
GlobalCommandOptions = make(map[string]map[string]string)
GlobalOptions struct {
Config string `short:"c" long:"config" env:"VOLTCONFIG" value-name:"FILE" default:"" description:"Location of client config file"`
+ Stack string `short:"v" long:"stack" env:"STACK" value-name:"STACK" default:"" description:"Name of stack to use in multistack deployment"`
Server string `short:"s" long:"server" default:"" value-name:"SERVER:PORT" description:"IP/Host and port of VOLTHA"`
Kafka string `short:"k" long:"kafka" default:"" value-name:"SERVER:PORT" description:"IP/Host and port of Kafka"`
KvStore string `short:"e" long:"kvstore" env:"KVSTORE" value-name:"SERVER:PORT" description:"IP/Host and port of KV store (etcd)"`
@@ -194,75 +196,18 @@
}
func ProcessGlobalOptions() {
- if len(GlobalOptions.Config) == 0 {
- home, err := os.UserHomeDir()
- if err != nil {
- Warn.Printf("Unable to discover the user's home directory: %s", err)
- home = "~"
+ ReadConfig()
+
+ // If a stack is selected via command line set it
+ if GlobalOptions.Stack != "" {
+ if GlobalConfig.StackByName(GlobalOptions.Stack) == nil {
+ Error.Fatalf("stack specified, '%s', not found in configuration",
+ GlobalOptions.Stack)
}
- GlobalOptions.Config = filepath.Join(home, ".volt", "config")
+ GlobalConfig.CurrentStack = GlobalOptions.Stack
}
- if info, err := os.Stat(GlobalOptions.Config); err == nil && !info.IsDir() {
- configFile, err := ioutil.ReadFile(GlobalOptions.Config)
- if err != nil {
- Error.Fatalf("Unable to read the configuration file '%s': %s",
- GlobalOptions.Config, err.Error())
- }
- // First try the latest version of the config api then work
- // backwards
- if err = yaml.Unmarshal(configFile, &GlobalConfig); err != nil {
- GlobalConfigV1 := configv1.NewDefaultConfig()
- if err = yaml.Unmarshal(configFile, &GlobalConfigV1); err != nil {
- Error.Fatalf("Unable to parse the configuration file '%s': %s",
- GlobalOptions.Config, err.Error())
- }
- GlobalConfig = configv2.FromConfigV1(GlobalConfigV1)
- }
- }
-
- // Override from command line
- if GlobalOptions.Server != "" {
- GlobalConfig.Server = GlobalOptions.Server
- }
-
- if GlobalOptions.UseTLS {
- GlobalConfig.Tls.UseTls = true
- }
-
- if GlobalOptions.Verify {
- GlobalConfig.Tls.Verify = true
- }
-
- if GlobalOptions.Kafka != "" {
- GlobalConfig.Kafka = GlobalOptions.Kafka
- }
-
- if GlobalOptions.KvStore != "" {
- GlobalConfig.KvStore = GlobalOptions.KvStore
- }
-
- if GlobalOptions.KvStoreTimeout != "" {
- timeout, err := time.ParseDuration(GlobalOptions.KvStoreTimeout)
- if err != nil {
- Error.Fatalf("Unable to parse specified KV strore timeout duration '%s': %s",
- GlobalOptions.KvStoreTimeout, err.Error())
- }
- GlobalConfig.KvStoreConfig.Timeout = timeout
- }
-
- if GlobalOptions.Timeout != "" {
- timeout, err := time.ParseDuration(GlobalOptions.Timeout)
- if err != nil {
- Error.Fatalf("Unable to parse specified timeout duration '%s': %s",
- GlobalOptions.Timeout, err.Error())
- }
- GlobalConfig.Grpc.Timeout = timeout
- }
-
- if GlobalOptions.MaxCallRecvMsgSize != "" {
- GlobalConfig.Grpc.MaxCallRecvMsgSize = GlobalOptions.MaxCallRecvMsgSize
- }
+ ApplyOptionOverrides(GlobalConfig.Current())
// If a k8s cert/key were not specified, then attempt to read it from
// any $HOME/.kube/config if it exists
@@ -297,13 +242,98 @@
}
}
+func ApplyOptionOverrides(stack *configv3.StackConfigSpec) {
+
+ if stack == nil {
+ // nothing to do
+ return
+ }
+ // Override from command line
+ if GlobalOptions.Server != "" {
+ stack.Server = GlobalOptions.Server
+ }
+
+ if GlobalOptions.UseTLS {
+ stack.Tls.UseTls = true
+ }
+
+ if GlobalOptions.Verify {
+ stack.Tls.Verify = true
+ }
+
+ if GlobalOptions.Kafka != "" {
+ stack.Kafka = GlobalOptions.Kafka
+ }
+
+ if GlobalOptions.KvStore != "" {
+ stack.KvStore = GlobalOptions.KvStore
+ }
+
+ if GlobalOptions.KvStoreTimeout != "" {
+ timeout, err := time.ParseDuration(GlobalOptions.KvStoreTimeout)
+ if err != nil {
+ Error.Fatalf("Unable to parse specified KV strore timeout duration '%s': %s",
+ GlobalOptions.KvStoreTimeout, err.Error())
+ }
+ stack.KvStoreConfig.Timeout = timeout
+ }
+
+ if GlobalOptions.Timeout != "" {
+ timeout, err := time.ParseDuration(GlobalOptions.Timeout)
+ if err != nil {
+ Error.Fatalf("Unable to parse specified timeout duration '%s': %s",
+ GlobalOptions.Timeout, err.Error())
+ }
+ stack.Grpc.Timeout = timeout
+ }
+
+ if GlobalOptions.MaxCallRecvMsgSize != "" {
+ stack.Grpc.MaxCallRecvMsgSize = GlobalOptions.MaxCallRecvMsgSize
+ }
+}
+
+func ReadConfig() {
+ if len(GlobalOptions.Config) == 0 {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ Warn.Printf("Unable to discover the user's home directory: %s", err)
+ home = "~"
+ }
+ GlobalOptions.Config = filepath.Join(home, ".volt", "config")
+ }
+
+ if info, err := os.Stat(GlobalOptions.Config); err == nil && !info.IsDir() {
+ configFile, err := ioutil.ReadFile(GlobalOptions.Config)
+ if err != nil {
+ Error.Fatalf("Unable to read the configuration file '%s': %s",
+ GlobalOptions.Config, err.Error())
+ }
+ // First try the latest version of the config api then work
+ // backwards
+ if err = yaml.Unmarshal(configFile, &GlobalConfig); err != nil {
+ GlobalConfigV2 := configv2.NewDefaultConfig()
+ if err = yaml.Unmarshal(configFile, &GlobalConfigV2); err != nil {
+ GlobalConfigV1 := configv1.NewDefaultConfig()
+ if err = yaml.Unmarshal(configFile, &GlobalConfigV1); err != nil {
+ Error.Fatalf("Unable to parse the configuration file '%s': %s",
+ GlobalOptions.Config, err.Error())
+ }
+ GlobalConfig = configv3.FromConfigV1(GlobalConfigV1)
+ } else {
+ GlobalConfig = configv3.FromConfigV2(GlobalConfigV2)
+ }
+ }
+ }
+
+}
+
func NewConnection() (*grpc.ClientConn, error) {
ProcessGlobalOptions()
// convert grpc.msgSize into bytes
- n, err := parseSize(GlobalConfig.Grpc.MaxCallRecvMsgSize)
+ n, err := parseSize(GlobalConfig.Current().Grpc.MaxCallRecvMsgSize)
if err != nil {
- Error.Fatalf("Cannot convert msgSize %s to bytes", GlobalConfig.Grpc.MaxCallRecvMsgSize)
+ Error.Fatalf("Cannot convert msgSize %s to bytes", GlobalConfig.Current().Grpc.MaxCallRecvMsgSize)
}
var opts []grpc.DialOption
@@ -313,17 +343,17 @@
grpc.WithBlock(),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(n))))
- if GlobalConfig.Tls.UseTls {
+ if GlobalConfig.Current().Tls.UseTls {
creds := credentials.NewTLS(&tls.Config{
- InsecureSkipVerify: !GlobalConfig.Tls.Verify})
+ InsecureSkipVerify: !GlobalConfig.Current().Tls.Verify})
opts = append(opts, grpc.WithTransportCredentials(creds))
} else {
opts = append(opts, grpc.WithInsecure())
}
ctx, cancel := context.WithTimeout(context.TODO(),
- GlobalConfig.Grpc.ConnectTimeout)
+ GlobalConfig.Current().Grpc.ConnectTimeout)
defer cancel()
- return grpc.DialContext(ctx, GlobalConfig.Server, opts...)
+ return grpc.DialContext(ctx, GlobalConfig.Current().Server, opts...)
}
func ConvertJsonProtobufArray(data_in interface{}) (string, error) {
diff --git a/internal/pkg/commands/command_test.go b/internal/pkg/commands/command_test.go
index e0bd4bd..f17e06d 100644
--- a/internal/pkg/commands/command_test.go
+++ b/internal/pkg/commands/command_test.go
@@ -37,7 +37,7 @@
assert.Nil(t, err, "unexpected error paring arguments")
ProcessGlobalOptions()
- assert.Equal(t, "localhost:55555", GlobalConfig.Server, "wrong default hostname for server")
+ assert.Equal(t, "localhost:55555", GlobalConfig.Current().Server, "wrong default hostname for server")
}
func TestParseSize(t *testing.T) {
diff --git a/internal/pkg/commands/config.go b/internal/pkg/commands/config.go
index 59a1df1..28cb6e2 100644
--- a/internal/pkg/commands/config.go
+++ b/internal/pkg/commands/config.go
@@ -36,10 +36,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.`
-type CommandOptionsDump struct{}
-
type ConfigOptions struct {
- Commands CommandOptionsDump `command:"commands"`
}
func RegisterConfigCommands(parent *flags.Parser) {
@@ -51,8 +48,8 @@
}
func (options *ConfigOptions) Execute(args []string) error {
- //GlobalConfig
- ProcessGlobalOptions()
+ ReadConfig()
+ ApplyOptionOverrides(nil)
b, err := yaml.Marshal(GlobalConfig)
if err != nil {
return err
@@ -61,14 +58,3 @@
fmt.Println(string(b))
return nil
}
-
-func (commands *CommandOptionsDump) Execute(args []string) error {
- ProcessGlobalOptions()
- b, err := yaml.Marshal(GlobalCommandOptions)
- if err != nil {
- return err
- }
- fmt.Println(copyrightNotice)
- fmt.Println(string(b))
- return nil
-}
diff --git a/internal/pkg/commands/devicegroups.go b/internal/pkg/commands/devicegroups.go
index 05b681b..f42547b 100644
--- a/internal/pkg/commands/devicegroups.go
+++ b/internal/pkg/commands/devicegroups.go
@@ -17,6 +17,7 @@
import (
"context"
+
"github.com/golang/protobuf/ptypes/empty"
flags "github.com/jessevdk/go-flags"
"github.com/opencord/voltctl/pkg/format"
@@ -54,7 +55,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
deviceGroups, err := client.ListDeviceGroups(ctx, &empty.Empty{})
diff --git a/internal/pkg/commands/devices.go b/internal/pkg/commands/devices.go
index 58bf6e4..d1e0340 100644
--- a/internal/pkg/commands/devices.go
+++ b/internal/pkg/commands/devices.go
@@ -366,7 +366,7 @@
return nil
}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(deviceId)}
@@ -419,7 +419,7 @@
return nil
}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(deviceId)}
@@ -477,7 +477,7 @@
return nil
}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(deviceId)}
@@ -507,7 +507,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
devices, err := client.ListDevices(ctx, &empty.Empty{})
@@ -535,7 +535,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
devices, err := client.ListDevices(ctx, &empty.Empty{})
@@ -597,7 +597,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
createdDevice, err := client.CreateDevice(ctx, &device)
@@ -621,7 +621,7 @@
client := voltha.NewVolthaServiceClient(conn)
var lastErr error
for _, i := range options.Args.Ids {
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(i)}
@@ -656,7 +656,7 @@
var lastErr error
for _, i := range options.Args.Ids {
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(i)}
@@ -687,7 +687,7 @@
var lastErr error
for _, i := range options.Args.Ids {
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(i)}
@@ -718,7 +718,7 @@
var lastErr error
for _, i := range options.Args.Ids {
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(i)}
@@ -748,7 +748,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -803,7 +803,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -841,7 +841,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
port := voltha.Port{DeviceId: string(options.Args.Id), PortNo: uint32(options.Args.PortId)}
@@ -865,7 +865,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
port := voltha.Port{DeviceId: string(options.Args.Id), PortNo: uint32(options.Args.PortId)}
@@ -888,7 +888,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -918,7 +918,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -962,7 +962,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1014,7 +1014,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1061,7 +1061,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1109,7 +1109,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1152,7 +1152,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1197,7 +1197,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1245,7 +1245,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1298,7 +1298,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1356,7 +1356,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -1403,7 +1403,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := common.ID{Id: string(options.Args.Id)}
@@ -1451,7 +1451,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
downloadImage := voltha.ImageDownload{
@@ -1481,7 +1481,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
downloadImage := voltha.ImageDownload{
@@ -1536,7 +1536,7 @@
},
}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
rv, err := client.GetExtValue(ctx, &singleGetValReq)
if err != nil {
@@ -1581,7 +1581,7 @@
},
},
}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
rv, err := client.GetExtValue(ctx, &singleGetValReq)
if err != nil {
@@ -1622,7 +1622,7 @@
val := voltha.ValueSpecifier{Id: string(options.Args.Id), Value: common.ValueType_Type(valueflag)}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
rv, err := client.GetExtValue(ctx, &val)
diff --git a/internal/pkg/commands/events.go b/internal/pkg/commands/events.go
index 2aaa03a..06f6aee 100644
--- a/internal/pkg/commands/events.go
+++ b/internal/pkg/commands/events.go
@@ -19,6 +19,12 @@
"encoding/json"
"errors"
"fmt"
+ "log"
+ "os"
+ "os/signal"
+ "strings"
+ "time"
+
"github.com/Shopify/sarama"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
@@ -28,11 +34,6 @@
"github.com/opencord/voltctl/pkg/filter"
"github.com/opencord/voltctl/pkg/format"
"github.com/opencord/voltha-protos/v4/go/voltha"
- "log"
- "os"
- "os/signal"
- "strings"
- "time"
)
const (
@@ -289,7 +290,7 @@
func (options *EventListenOpts) Execute(args []string) error {
ProcessGlobalOptions()
- if GlobalConfig.Kafka == "" {
+ if GlobalConfig.Current().Kafka == "" {
return errors.New("Kafka address is not specified")
}
@@ -297,7 +298,7 @@
config.ClientID = "go-kafka-consumer"
config.Consumer.Return.Errors = true
config.Version = sarama.V1_0_0_0
- brokers := []string{GlobalConfig.Kafka}
+ brokers := []string{GlobalConfig.Current().Kafka}
client, err := sarama.NewClient(brokers, config)
if err != nil {
diff --git a/internal/pkg/commands/flows.go b/internal/pkg/commands/flows.go
index 0c94f96..4127545 100644
--- a/internal/pkg/commands/flows.go
+++ b/internal/pkg/commands/flows.go
@@ -116,7 +116,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
diff --git a/internal/pkg/commands/log.go b/internal/pkg/commands/log.go
index a1110b4..8663b70 100644
--- a/internal/pkg/commands/log.go
+++ b/internal/pkg/commands/log.go
@@ -251,15 +251,15 @@
func constructConfigManager(ctx context.Context) (*config.ConfigManager, func(), error) {
var tlsConfig *tls.Config
- if GlobalConfig.Tls.UseTls {
- tlsConfig = &tls.Config{InsecureSkipVerify: !GlobalConfig.Tls.Verify}
+ if GlobalConfig.Current().Tls.UseTls {
+ tlsConfig = &tls.Config{InsecureSkipVerify: !GlobalConfig.Current().Tls.Verify}
}
logconfig := log.ConstructZapConfig(log.JSON, log.FatalLevel, log.Fields{})
client, err := kvstore.NewEtcdCustomClient(
ctx,
&v3Client.Config{
- Endpoints: []string{GlobalConfig.KvStore},
- DialTimeout: GlobalConfig.KvStoreConfig.Timeout,
+ Endpoints: []string{GlobalConfig.Current().KvStore},
+ DialTimeout: GlobalConfig.Current().KvStoreConfig.Timeout,
LogConfig: &logconfig,
TLS: tlsConfig,
})
@@ -267,7 +267,7 @@
return nil, nil, fmt.Errorf("Unable to create kvstore client %s", err)
}
- cm := config.NewConfigManager(ctx, client, supportedKvStoreType, GlobalConfig.KvStore, GlobalConfig.KvStoreConfig.Timeout)
+ cm := config.NewConfigManager(ctx, client, supportedKvStoreType, GlobalConfig.Current().KvStore, GlobalConfig.Current().KvStoreConfig.Timeout)
return cm, func() { client.Close(ctx) }, nil
}
@@ -279,7 +279,7 @@
ProcessGlobalOptions()
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -399,7 +399,7 @@
ProcessGlobalOptions()
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -581,7 +581,7 @@
return fmt.Errorf(err.Error())
}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -683,7 +683,7 @@
ProcessGlobalOptions()
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -695,7 +695,7 @@
if len(options.Args.Component) == 0 {
componentList, err = cm.RetrieveComponentList(ctx, config.ConfigTypeLogLevel)
if err != nil {
- return fmt.Errorf("Unable to retrieve list of voltha components : %s \nIs ETCD available at %s?", err, GlobalConfig.KvStore)
+ return fmt.Errorf("Unable to retrieve list of voltha components : %s \nIs ETCD available at %s?", err, GlobalConfig.Current().KvStore)
}
} else {
componentList = toStringArray(options.Args.Component)
@@ -801,7 +801,7 @@
return fmt.Errorf("%s", err)
}
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -862,7 +862,7 @@
ProcessGlobalOptions()
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -939,7 +939,7 @@
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -1018,7 +1018,7 @@
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -1099,7 +1099,7 @@
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -1183,7 +1183,7 @@
ProcessGlobalOptions()
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -1258,7 +1258,7 @@
ProcessGlobalOptions()
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
@@ -1332,7 +1332,7 @@
func (options *ListLogCorrelationOpts) Execute(args []string) error {
ProcessGlobalOptions()
log.SetAllLogLevel(log.FatalLevel)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.KvStoreConfig.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().KvStoreConfig.Timeout)
defer cancel()
cm, cleanupFunc, err := constructConfigManager(ctx)
diff --git a/internal/pkg/commands/logicaldevices.go b/internal/pkg/commands/logicaldevices.go
index c529603..9191385 100644
--- a/internal/pkg/commands/logicaldevices.go
+++ b/internal/pkg/commands/logicaldevices.go
@@ -89,7 +89,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
logicalDevices, err := client.ListLogicalDevices(ctx, &empty.Empty{})
@@ -117,7 +117,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
logicalDevices, err := client.ListLogicalDevices(ctx, &empty.Empty{})
@@ -165,7 +165,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
@@ -232,7 +232,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
id := voltha.ID{Id: string(options.Args.Id)}
diff --git a/internal/pkg/commands/message.go b/internal/pkg/commands/message.go
index bef4cac..338affd 100644
--- a/internal/pkg/commands/message.go
+++ b/internal/pkg/commands/message.go
@@ -353,7 +353,7 @@
func (options *MessageListenOpts) Execute(args []string) error {
ProcessGlobalOptions()
- if GlobalConfig.Kafka == "" {
+ if GlobalConfig.Current().Kafka == "" {
return errors.New("Kafka address is not specified")
}
@@ -361,7 +361,7 @@
config.ClientID = "go-kafka-consumer"
config.Consumer.Return.Errors = true
config.Version = sarama.V1_0_0_0
- brokers := []string{GlobalConfig.Kafka}
+ brokers := []string{GlobalConfig.Current().Kafka}
client, err := sarama.NewClient(brokers, config)
if err != nil {
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
+}
diff --git a/internal/pkg/commands/version.go b/internal/pkg/commands/version.go
index db47ed8..4e3946f 100644
--- a/internal/pkg/commands/version.go
+++ b/internal/pkg/commands/version.go
@@ -136,7 +136,7 @@
client := voltha.NewVolthaServiceClient(conn)
- ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
+ ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Current().Grpc.Timeout)
defer cancel()
voltha, err := client.GetVoltha(ctx, &empty.Empty{})
diff --git a/voltctl.v3.config b/voltctl.v3.config
new file mode 100644
index 0000000..d890fb7
--- /dev/null
+++ b/voltctl.v3.config
@@ -0,0 +1,33 @@
+# 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.
+apiVersion: v2
+stacks:
+- name: default
+ server: localhost:55555
+ kafka: localhost:9093
+ kvstore: localhost:2379
+ tls:
+ useTLS: false
+ caCert: ""
+ cert: ""
+ key: ""
+ verify: false
+ grpc:
+ connectTimeout: 5s
+ timeout: 5m0s
+ maxCallRecvMsgSize: 4M
+ kvstoreconfig:
+ timeout: 5s
+currentStack: ""
+