blob: bb2627357c52d27f4420ea71dfe1ad47c0f92fc6 [file] [log] [blame]
Scott Baker2c0ebda2019-05-06 16:55:47 -07001/*
2 * Copyright 2019-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package commands
17
18import (
Scott Baker5281d002019-05-16 10:45:26 -070019 "bufio"
Scott Baker2c0ebda2019-05-06 16:55:47 -070020 b64 "encoding/base64"
Scott Baker6cf525a2019-05-09 12:25:08 -070021 "fmt"
22 "github.com/fullstorydev/grpcurl"
Scott Baker867aa302019-06-19 13:18:45 -070023 versionUtils "github.com/hashicorp/go-version"
24 "github.com/jhump/protoreflect/dynamic"
Scott Baker6cf525a2019-05-09 12:25:08 -070025 "github.com/jhump/protoreflect/grpcreflect"
26 "golang.org/x/net/context"
27 "google.golang.org/grpc"
28 reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
Scott Baker175cb402019-05-17 16:13:06 -070029 "google.golang.org/grpc/status"
Scott Baker5281d002019-05-16 10:45:26 -070030 "log"
31 "os"
32 "strings"
Scott Baker2c0ebda2019-05-06 16:55:47 -070033)
34
Scott Baker867aa302019-06-19 13:18:45 -070035// Flags for calling the InitReflectionClient Method
36const (
37 INIT_DEFAULT = 0
38 INIT_NO_VERSION_CHECK = 1 // Do not check whether server is allowed version
39)
40
Scott Baker2c0ebda2019-05-06 16:55:47 -070041func GenerateHeaders() []string {
42 username := GlobalConfig.Username
43 password := GlobalConfig.Password
44 sEnc := b64.StdEncoding.EncodeToString([]byte(username + ":" + password))
45 headers := []string{"authorization: basic " + sEnc}
46 return headers
47}
Scott Baker6cf525a2019-05-09 12:25:08 -070048
Scott Baker867aa302019-06-19 13:18:45 -070049// Perform the GetVersion API call on the core to get the version
50func GetVersion(conn *grpc.ClientConn, descriptor grpcurl.DescriptorSource) (*dynamic.Message, error) {
51 ctx, cancel := context.WithTimeout(context.Background(), GlobalConfig.Grpc.Timeout)
52 defer cancel()
53
54 headers := GenerateHeaders()
55
56 h := &RpcEventHandler{}
57 err := grpcurl.InvokeRPC(ctx, descriptor, conn, "xos.utility.GetVersion", headers, h, h.GetParams)
58 if err != nil {
59 return nil, err
60 }
61
62 if h.Status != nil && h.Status.Err() != nil {
63 return nil, h.Status.Err()
64 }
65
66 d, err := dynamic.AsDynamicMessage(h.Response)
67
68 return d, err
69}
70
71// Initialize client connection
72// flags is a set of optional flags that may influence how the connection is setup
73// INIT_DEFAULT - default behavior (0)
74// INIT_NO_VERSION_CHECK - do not perform core version check
75
76func InitClient(flags uint32) (*grpc.ClientConn, grpcurl.DescriptorSource, error) {
Scott Baker6cf525a2019-05-09 12:25:08 -070077 conn, err := NewConnection()
78 if err != nil {
79 return nil, nil, err
80 }
81
82 refClient := grpcreflect.NewClient(context.Background(), reflectpb.NewServerReflectionClient(conn))
83 defer refClient.Reset()
84
Scott Baker14c8f182019-05-22 18:05:29 -070085 // Intended method of use is to download the protos via reflection API. Loading the
86 // protos from a file is supported for unit testing, as the mock server does not
87 // support the reflection API.
88
89 var descriptor grpcurl.DescriptorSource
90 if GlobalConfig.Protoset != "" {
91 descriptor, err = grpcurl.DescriptorSourceFromProtoSets(GlobalConfig.Protoset)
92 if err != nil {
93 return nil, nil, err
94 }
95 } else {
96 descriptor = grpcurl.DescriptorSourceFromServer(context.Background(), refClient)
97 }
Scott Baker6cf525a2019-05-09 12:25:08 -070098
Scott Baker867aa302019-06-19 13:18:45 -070099 if flags&INIT_NO_VERSION_CHECK == 0 {
100 d, err := GetVersion(conn, descriptor)
101 if err != nil {
102 return nil, nil, err
103 }
104 // Note: NewVersion doesn't like the `-dev` suffix, so strip it off.
105 serverVersion, err := versionUtils.NewVersion(strings.Split(d.GetFieldByName("version").(string), "-")[0])
106 if err != nil {
107 return nil, nil, err
108 }
109
110 constraint, err := versionUtils.NewConstraint(CORE_VERSION_CONSTRAINT)
111 if err != nil {
112 return nil, nil, err
113 }
114
115 if !constraint.Check(serverVersion) {
116 return nil, nil, fmt.Errorf("Core version %s does not match constraint '%s'",
117 serverVersion, CORE_VERSION_CONSTRAINT)
118 }
119
120 }
121
Scott Baker6cf525a2019-05-09 12:25:08 -0700122 return conn, descriptor, nil
123}
124
125// A makeshift substitute for C's Ternary operator
126func Ternary_uint32(condition bool, value_true uint32, value_false uint32) uint32 {
127 if condition {
128 return value_true
129 } else {
130 return value_false
131 }
132}
133
134// call printf only if visible is True
135func conditional_printf(visible bool, format string, args ...interface{}) {
136 if visible {
137 fmt.Printf(format, args...)
138 }
139}
Scott Baker5281d002019-05-16 10:45:26 -0700140
141// Print a confirmation prompt and get a response from the user
142func Confirmf(format string, args ...interface{}) bool {
143 if GlobalOptions.Yes {
144 return true
145 }
146
147 reader := bufio.NewReader(os.Stdin)
148
149 for {
150 msg := fmt.Sprintf(format, args...)
151 fmt.Print(msg)
152
153 response, err := reader.ReadString('\n')
154 if err != nil {
155 log.Fatal(err)
156 }
157
158 response = strings.ToLower(strings.TrimSpace(response))
159
160 if response == "y" || response == "yes" {
161 return true
162 } else if response == "n" || response == "no" {
163 return false
164 }
165 }
166}
Scott Baker175cb402019-05-17 16:13:06 -0700167
168func HumanReadableError(err error) string {
169 st, ok := status.FromError(err)
170 if ok {
171 grpc_message := st.Message()
172 if strings.HasPrefix(grpc_message, "Exception calling application: ") {
173 return st.Message()[31:]
174 } else {
175 return st.Message()
176 }
177 }
178 return err.Error()
179}