blob: 6d975cf53d898021079107040c197ba9e79aab26 [file] [log] [blame]
Scott Baker2c0ebda2019-05-06 16:55:47 -07001/*
2 * Portions copyright 2019-present Open Networking Foundation
3 * Original copyright 2019-present Ciena Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package commands
18
19import (
20 "encoding/json"
21 "fmt"
22 "github.com/opencord/cordctl/format"
23 "google.golang.org/grpc"
24 "gopkg.in/yaml.v2"
25 "io/ioutil"
26 "log"
27 "os"
28 "strings"
29 "time"
30)
31
32type OutputType uint8
33
34const (
35 OUTPUT_TABLE OutputType = iota
36 OUTPUT_JSON
37 OUTPUT_YAML
38)
39
40var CharReplacer = strings.NewReplacer("\\t", "\t", "\\n", "\n")
41
42type GrpcConfigSpec struct {
43 Timeout time.Duration `yaml:"timeout"`
44}
45
46type TlsConfigSpec struct {
47 UseTls bool `yaml:"useTls"`
48 CACert string `yaml:"caCert"`
49 Cert string `yaml:"cert"`
50 Key string `yaml:"key"`
51 Verify string `yaml:"verify"`
52}
53
54type GlobalConfigSpec struct {
Scott Baker6cf525a2019-05-09 12:25:08 -070055 Server string `yaml:"server"`
56 Username string `yaml:"username"`
57 Password string `yaml:"password"`
58 Tls TlsConfigSpec `yaml:"tls"`
59 Grpc GrpcConfigSpec
Scott Baker2c0ebda2019-05-06 16:55:47 -070060}
61
62var GlobalConfig = GlobalConfigSpec{
Scott Baker6cf525a2019-05-09 12:25:08 -070063 Server: "localhost",
Scott Baker2c0ebda2019-05-06 16:55:47 -070064 Tls: TlsConfigSpec{
65 UseTls: false,
66 },
67 Grpc: GrpcConfigSpec{
68 Timeout: time.Second * 10,
69 },
70}
71
72var GlobalOptions struct {
Scott Baker6cf525a2019-05-09 12:25:08 -070073 Config string `short:"c" long:"config" env:"CORDCONFIG" value-name:"FILE" default:"" description:"Location of client config file"`
74 Server string `short:"s" long:"server" default:"" value-name:"SERVER:PORT" description:"IP/Host and port of XOS"`
75 Username string `short:"u" long:"username" value-name:"USERNAME" default:"" description:"Username to authenticate with XOS"`
76 Password string `short:"p" long:"password" value-name:"PASSWORD" default:"" description:"Password to authenticate with XOS"`
77 Debug bool `short:"d" long:"debug" description:"Enable debug mode"`
78 UseTLS bool `long:"tls" description:"Use TLS"`
79 CACert string `long:"tlscacert" value-name:"CA_CERT_FILE" description:"Trust certs signed only by this CA"`
80 Cert string `long:"tlscert" value-name:"CERT_FILE" description:"Path to TLS vertificate file"`
81 Key string `long:"tlskey" value-name:"KEY_FILE" description:"Path to TLS key file"`
82 Verify bool `long:"tlsverify" description:"Use TLS and verify the remote"`
Scott Baker5281d002019-05-16 10:45:26 -070083 Yes bool `short:"y" long:"yes" description:"answer yes to any confirmation prompts"`
Scott Baker2c0ebda2019-05-06 16:55:47 -070084}
85
86type OutputOptions struct {
87 Format string `long:"format" value-name:"FORMAT" default:"" description:"Format to use to output structured data"`
88 Quiet bool `short:"q" long:"quiet" description:"Output only the IDs of the objects"`
89 OutputAs string `short:"o" long:"outputas" default:"table" choice:"table" choice:"json" choice:"yaml" description:"Type of output to generate"`
90}
91
92func toOutputType(in string) OutputType {
93 switch in {
94 case "table":
95 fallthrough
96 default:
97 return OUTPUT_TABLE
98 case "json":
99 return OUTPUT_JSON
100 case "yaml":
101 return OUTPUT_YAML
102 }
103}
104
105type CommandResult struct {
106 Format format.Format
107 OutputAs OutputType
108 Data interface{}
109}
110
111type config struct {
Scott Baker6cf525a2019-05-09 12:25:08 -0700112 Server string `yaml:"server"`
Scott Baker2c0ebda2019-05-06 16:55:47 -0700113}
114
Scott Baker63ce82e2019-05-15 09:01:42 -0700115func ProcessGlobalOptions() {
Scott Baker2c0ebda2019-05-06 16:55:47 -0700116 if len(GlobalOptions.Config) == 0 {
Scott Baker63ce82e2019-05-15 09:01:42 -0700117 home, err := os.UserHomeDir()
118 if err != nil {
119 log.Printf("Unable to discover the users home directory: %s\n", err)
120 }
Scott Baker2c0ebda2019-05-06 16:55:47 -0700121 GlobalOptions.Config = fmt.Sprintf("%s/.cord/config", home)
122 }
123
124 info, err := os.Stat(GlobalOptions.Config)
125 if err == nil && !info.IsDir() {
126 configFile, err := ioutil.ReadFile(GlobalOptions.Config)
127 if err != nil {
128 log.Printf("configFile.Get err #%v ", err)
129 }
130 err = yaml.Unmarshal(configFile, &GlobalConfig)
131 if err != nil {
132 log.Fatalf("Unmarshal: %v", err)
133 }
134 }
135
136 // Override from command line
137 if GlobalOptions.Server != "" {
138 GlobalConfig.Server = GlobalOptions.Server
139 }
Scott Baker2c0ebda2019-05-06 16:55:47 -0700140 if GlobalOptions.Username != "" {
141 GlobalConfig.Username = GlobalOptions.Username
142 }
143 if GlobalOptions.Password != "" {
144 GlobalConfig.Password = GlobalOptions.Password
145 }
146
Scott Baker5281d002019-05-16 10:45:26 -0700147 // Generate error messages for required settings
Scott Baker63ce82e2019-05-15 09:01:42 -0700148 if GlobalConfig.Server == "" {
149 log.Fatal("Server is not set. Please update config file or use the -s option")
150 }
151 if GlobalConfig.Username == "" {
152 log.Fatal("Username is not set. Please update config file or use the -u option")
153 }
154 if GlobalConfig.Password == "" {
155 log.Fatal("Password is not set. Please update config file or use the -p option")
156 }
157}
158
159func NewConnection() (*grpc.ClientConn, error) {
160 ProcessGlobalOptions()
Scott Baker2c0ebda2019-05-06 16:55:47 -0700161 return grpc.Dial(GlobalConfig.Server, grpc.WithInsecure())
162}
163
164func GenerateOutput(result *CommandResult) {
165 if result != nil && result.Data != nil {
166 if result.OutputAs == OUTPUT_TABLE {
167 tableFormat := format.Format(result.Format)
168 tableFormat.Execute(os.Stdout, true, result.Data)
169 } else if result.OutputAs == OUTPUT_JSON {
170 asJson, err := json.Marshal(&result.Data)
171 if err != nil {
172 panic(err)
173 }
174 fmt.Printf("%s", asJson)
175 } else if result.OutputAs == OUTPUT_YAML {
176 asYaml, err := yaml.Marshal(&result.Data)
177 if err != nil {
178 panic(err)
179 }
180 fmt.Printf("%s", asYaml)
181 }
182 }
183}
Scott Baker5281d002019-05-16 10:45:26 -0700184
185// Applies common output options to format and generate output
186func FormatAndGenerateOutput(options *OutputOptions, default_format string, quiet_format string, data interface{}) {
187 outputFormat := CharReplacer.Replace(options.Format)
188 if outputFormat == "" {
189 outputFormat = default_format
190 }
Scott Baker175cb402019-05-17 16:13:06 -0700191 if options.Quiet {
Scott Baker5281d002019-05-16 10:45:26 -0700192 outputFormat = quiet_format
193 }
194
195 result := CommandResult{
196 Format: format.Format(outputFormat),
197 OutputAs: toOutputType(options.OutputAs),
198 Data: data,
199 }
200
201 GenerateOutput(&result)
202}