SEBA-767 Directory restructuring in accordance with best practices
Change-Id: Id651366a3545ad0141a7854e99fa46867e543295
diff --git a/internal/pkg/commands/command.go b/internal/pkg/commands/command.go
new file mode 100644
index 0000000..45ccd5d
--- /dev/null
+++ b/internal/pkg/commands/command.go
@@ -0,0 +1,277 @@
+/*
+ * Portions copyright 2019-present Open Networking Foundation
+ * Original copyright 2019-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 (
+ "encoding/json"
+ "fmt"
+ "github.com/opencord/cordctl/pkg/format"
+ "github.com/opencord/cordctl/pkg/order"
+ "google.golang.org/grpc"
+ "gopkg.in/yaml.v2"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "strings"
+ "time"
+ "net"
+)
+
+type OutputType uint8
+
+const (
+ OUTPUT_TABLE OutputType = iota
+ OUTPUT_JSON
+ OUTPUT_YAML
+
+ CORE_VERSION_CONSTRAINT = ">= 3, < 4" // Support XOS major version 3
+)
+
+// Make it easy to override output stream for testing
+var OutputStream io.Writer = os.Stdout
+
+var CharReplacer = strings.NewReplacer("\\t", "\t", "\\n", "\n")
+
+type GrpcConfigSpec 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 string `yaml:"verify"`
+}
+
+type GlobalConfigSpec struct {
+ Server string `yaml:"server"`
+ Username string `yaml:"username"`
+ Password string `yaml:"password"`
+ Protoset string `yaml:"protoset"`
+ Tls TlsConfigSpec `yaml:"tls"`
+ Grpc GrpcConfigSpec
+}
+
+var GlobalConfig = GlobalConfigSpec{
+ Server: "localhost",
+ Tls: TlsConfigSpec{
+ UseTls: false,
+ },
+ Grpc: GrpcConfigSpec{
+ Timeout: time.Second * 10,
+ },
+}
+
+var GlobalOptions struct {
+ Config string `short:"c" long:"config" env:"CORDCONFIG" value-name:"FILE" default:"" description:"Location of client config file"`
+ Server string `short:"s" long:"server" default:"" value-name:"SERVER:PORT" description:"IP/Host and port of XOS"`
+ Username string `short:"u" long:"username" value-name:"USERNAME" default:"" description:"Username to authenticate with XOS"`
+ Password string `short:"p" long:"password" value-name:"PASSWORD" default:"" description:"Password to authenticate with XOS"`
+ Protoset string `long:"protoset" value-name:"FILENAME" description:"Load protobuf definitions from protoset instead of reflection api"`
+ Debug bool `short:"d" long:"debug" description:"Enable debug mode"`
+ UseTLS bool `long:"tls" description:"Use TLS"`
+ CACert string `long:"tlscacert" value-name:"CA_CERT_FILE" description:"Trust certs signed only by this CA"`
+ Cert string `long:"tlscert" value-name:"CERT_FILE" description:"Path to TLS vertificate file"`
+ Key string `long:"tlskey" value-name:"KEY_FILE" description:"Path to TLS key file"`
+ Verify bool `long:"tlsverify" description:"Use TLS and verify the remote"`
+ Yes bool `short:"y" long:"yes" description:"answer yes to any confirmation prompts"`
+}
+
+type OutputOptions struct {
+ Format string `long:"format" value-name:"FORMAT" default:"" description:"Format to use to output structured data"`
+ Quiet bool `short:"q" long:"quiet" description:"Output only the IDs of the objects"`
+ OutputAs string `short:"o" long:"outputas" default:"table" choice:"table" choice:"json" choice:"yaml" description:"Type of output to generate"`
+}
+
+type ListOutputOptions struct {
+ OutputOptions
+ OrderBy string `short:"r" long:"orderby" default:"" description:"Specify the sort order of the results"`
+}
+
+func toOutputType(in string) OutputType {
+ switch in {
+ case "table":
+ fallthrough
+ default:
+ return OUTPUT_TABLE
+ case "json":
+ return OUTPUT_JSON
+ case "yaml":
+ return OUTPUT_YAML
+ }
+}
+
+type CommandResult struct {
+ Format format.Format
+ OrderBy string
+ OutputAs OutputType
+ Data interface{}
+}
+
+type config struct {
+ Server string `yaml:"server"`
+}
+
+func ProcessGlobalOptions() {
+ if len(GlobalOptions.Config) == 0 {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ log.Printf("Unable to discover the users home directory: %s\n", err)
+ }
+ GlobalOptions.Config = fmt.Sprintf("%s/.cord/config", home)
+ }
+
+ info, err := os.Stat(GlobalOptions.Config)
+ if err == nil && !info.IsDir() {
+ configFile, err := ioutil.ReadFile(GlobalOptions.Config)
+ if err != nil {
+ log.Printf("configFile.Get err #%v ", err)
+ }
+ err = yaml.Unmarshal(configFile, &GlobalConfig)
+ if err != nil {
+ log.Fatalf("Unmarshal: %v", err)
+ }
+ }
+
+ // Override from environment
+ // in particualr, for passing env vars via `go test`
+ env_server, present := os.LookupEnv("CORDCTL_SERVER")
+ if present {
+ GlobalConfig.Server = env_server
+ }
+ env_username, present := os.LookupEnv("CORDCTL_USERNAME")
+ if present {
+ GlobalConfig.Username = env_username
+ }
+ env_password, present := os.LookupEnv("CORDCTL_PASSWORD")
+ if present {
+ GlobalConfig.Password = env_password
+ }
+ env_protoset, present := os.LookupEnv("CORDCTL_PROTOSET")
+ if present {
+ GlobalConfig.Protoset = env_protoset
+ }
+
+ // Override from command line
+ if GlobalOptions.Server != "" {
+ GlobalConfig.Server = GlobalOptions.Server
+ }
+ if GlobalOptions.Username != "" {
+ GlobalConfig.Username = GlobalOptions.Username
+ }
+ if GlobalOptions.Password != "" {
+ GlobalConfig.Password = GlobalOptions.Password
+ }
+ if GlobalOptions.Protoset != "" {
+ GlobalConfig.Protoset = GlobalOptions.Protoset
+ }
+
+ // Generate error messages for required settings
+ if GlobalConfig.Server == "" {
+ log.Fatal("Server is not set. Please update config file or use the -s option")
+ }
+ if GlobalConfig.Username == "" {
+ log.Fatal("Username is not set. Please update config file or use the -u option")
+ }
+ if GlobalConfig.Password == "" {
+ log.Fatal("Password is not set. Please update config file or use the -p option")
+ }
+ //Try to resolve hostname if provided for the server
+ if host, port, err := net.SplitHostPort(GlobalConfig.Server); err == nil {
+ if addrs, err := net.LookupHost(host); err == nil {
+ GlobalConfig.Server = net.JoinHostPort(addrs[0], port)
+ }
+ }
+}
+
+func NewConnection() (*grpc.ClientConn, error) {
+ ProcessGlobalOptions()
+ return grpc.Dial(GlobalConfig.Server, grpc.WithInsecure())
+}
+
+func GenerateOutput(result *CommandResult) {
+ if result != nil && result.Data != nil {
+ data := result.Data
+ if result.OrderBy != "" {
+ s, err := order.Parse(result.OrderBy)
+ if err != nil {
+ panic(err)
+ }
+ data, err = s.Process(data)
+ if err != nil {
+ panic(err)
+ }
+ }
+ if result.OutputAs == OUTPUT_TABLE {
+ tableFormat := format.Format(result.Format)
+ tableFormat.Execute(OutputStream, true, data)
+ } else if result.OutputAs == OUTPUT_JSON {
+ asJson, err := json.Marshal(&data)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Fprintf(OutputStream, "%s", asJson)
+ } else if result.OutputAs == OUTPUT_YAML {
+ asYaml, err := yaml.Marshal(&data)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Fprintf(OutputStream, "%s", asYaml)
+ }
+ }
+}
+
+// Applies common output options to format and generate output
+func FormatAndGenerateOutput(options *OutputOptions, default_format string, quiet_format string, data interface{}) {
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = default_format
+ }
+ if options.Quiet {
+ outputFormat = quiet_format
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ OutputAs: toOutputType(options.OutputAs),
+ Data: data,
+ }
+
+ GenerateOutput(&result)
+}
+
+// Applies common output options to format and generate output
+func FormatAndGenerateListOutput(options *ListOutputOptions, default_format string, quiet_format string, data interface{}) {
+ outputFormat := CharReplacer.Replace(options.Format)
+ if outputFormat == "" {
+ outputFormat = default_format
+ }
+ if options.Quiet {
+ outputFormat = quiet_format
+ }
+
+ result := CommandResult{
+ Format: format.Format(outputFormat),
+ OutputAs: toOutputType(options.OutputAs),
+ Data: data,
+ OrderBy: options.OrderBy,
+ }
+
+ GenerateOutput(&result)
+}