-
Notifications
You must be signed in to change notification settings - Fork 37
/
binding.go
259 lines (223 loc) · 9.93 KB
/
binding.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Copyright 2019 Google LLC
//
// 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
//
// https://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 binding holds the Ondatra binding interface.
package binding
import (
"fmt"
"io"
"time"
"golang.org/x/net/context"
"github.com/open-traffic-generator/snappi/gosnappi"
"github.com/openconfig/gnoigo"
"github.com/openconfig/ondatra/binding/ixweb"
"google.golang.org/grpc"
attestzpb "github.com/openconfig/attestz/proto/tpm_attestz"
enrollzpb "github.com/openconfig/attestz/proto/tpm_enrollz"
gpb "github.com/openconfig/gnmi/proto/gnmi"
gnpsipb "github.com/openconfig/gnpsi/proto/gnpsi"
acctzpb "github.com/openconfig/gnsi/acctz"
authzpb "github.com/openconfig/gnsi/authz"
certzpb "github.com/openconfig/gnsi/certz"
credzpb "github.com/openconfig/gnsi/credentialz"
pathzpb "github.com/openconfig/gnsi/pathz"
grpb "github.com/openconfig/gribi/v1/proto/service"
opb "github.com/openconfig/ondatra/proto"
p4pb "github.com/p4lang/p4runtime/go/p4/v1"
)
// Binding is a strategy interface for Ondatra vendor implementations.
//
// The framework enforces that at most testbed is reserved at a time, so
// implementations can assume that these methods are never called out of order,
// e.g. Release() is never be called without a prior Reserve().
type Binding interface {
// Reserve reserves resources matching the criteria in the specified testbed.
// The framework has already verified that the testbed is valid, and will
// validate that the returned reservation matches the testbed criteria.
//
// The testbed resources must be reserved for the specified runTime, or
// until Release is called. A runTime of zero means the caller requested an
// unlimited runTime. The implementation is free to impose a maximum limit on
// the runTime and return an error if it exceeds that limit. The framework has
// already checked that the runTime is not negative.
//
// This method may block for up to the specified waitTime for all testbed
// resources to become available. Given a zero waitTime, the implementation
// must choose a reasonable duration. The framework has already checked that
// the waitTime is not negative.
//
// The 'partial' map gives a partial mapping of device and port IDs in the
// testbed to concrete names to constrain the topology that is reserved.
//
// Devices in the returned reservation should be initialized with a fixed
// base configuration. Implementations are encouraged to make this base
// configuration "minimal," meaning a configuration that ensures the device
// is reachable and capable of being configured further, but little else,
// so that tests make as few assumptions about the devices as possible.
Reserve(ctx context.Context, tb *opb.Testbed, runTime, waitTime time.Duration, partial map[string]string) (*Reservation, error)
// Release releases the reserved testbed.
// It is not called if the reservation was fetched.
Release(ctx context.Context) error
// FetchReservation looks up and returns the pre-existing reservation with
// the specified ID.
FetchReservation(ctx context.Context, id string) (*Reservation, error)
}
// Reservation holds the reserved DUTs and ATEs as an id map.
type Reservation struct {
ID string
DUTs map[string]DUT
ATEs map[string]ATE
}
// Device is a reserved DUT or ATE.
type Device interface {
Name() string
Vendor() opb.Device_Vendor
HardwareModel() string
SoftwareVersion() string
Ports() map[string]*Port
}
// Dims contains the dimensions of reserved DUT or ATE.
type Dims struct {
Name string
Vendor opb.Device_Vendor
HardwareModel string
SoftwareVersion string
Ports map[string]*Port
}
func (d *Dims) String() string {
return fmt.Sprintf("Dims%+v", *d)
}
// DUT is a reserved DUT.
//
// All implementations of this interface must embed AbstractDUT.
//
// For methods that dial gRPC endpoints, implementations must use a default set
// of dial options necessary to reach the endpoint, so that the dial succeeds
// when no options are provided by the caller. When the caller does specify
// options, implementations are encouraged to append those options to the
// default set, so the call can both inherit and override the default behavior.
type DUT interface {
Device
// PushConfig adds config to the device. If reset is true, the device
// is reset to its base config before the specified config is added.
// The following Go template functions are allowed in config:
// - {{ port "<portID>" }}: replaced with the physical port name
// - {{ secrets "<arg1>" "<arg2>" }}: left untouched, returned as-is
PushConfig(ctx context.Context, config string, reset bool) error
// DialCLI creates a client connection to the DUT's CLI endpoint.
DialCLI(context.Context) (CLIClient, error)
// DialConsole creates a client connection to the DUT's Console endpoint.
DialConsole(context.Context) (ConsoleClient, error)
// DialGNMI creates a client connection to the DUT's gNMI endpoint.
// See the interface comment for proper handling of dial options.
DialGNMI(context.Context, ...grpc.DialOption) (gpb.GNMIClient, error)
// DialGNOI creates a client connection to the DUT's gNOI endpoint.
// See the interface comment for proper handling of dial options.
DialGNOI(context.Context, ...grpc.DialOption) (gnoigo.Clients, error)
// DialGNSI creates a client connection to the DUT's gNSI endpoint.
// See the interface comment for proper handling of dial options.
DialGNSI(context.Context, ...grpc.DialOption) (GNSIClients, error)
// DialGRIBI creates a client connection to the DUT's gRIBI endpoint.
// See the interface comment for proper handling of dial options.
DialGRIBI(context.Context, ...grpc.DialOption) (grpb.GRIBIClient, error)
// DialP4RT creates a client connection to the DUT's P4RT endpoint.
// See the interface comment for proper handling of dial options.
DialP4RT(context.Context, ...grpc.DialOption) (p4pb.P4RuntimeClient, error)
// DialGNPSI creates a client connection to the DUT's gNPSI endpoint.
// See the interface comment for proper handling of dial options.
DialGNPSI(context.Context, ...grpc.DialOption) (gnpsipb.GNPSIClient, error)
mustEmbedAbstractDUT()
}
// ATE is a reserved ATE.
//
// All implementations of this interface must embed AbstractATE.
//
// For methods that dial gRPC endpoints, implementations must use a default set
// of dial options necessary to reach the endpoint, so that the dial succeeds
// when no options are provided by the caller. When the caller does specify
// options, implementations are encouraged to append those options to the
// default set, so the call can both inherit and override the default behavior.
type ATE interface {
Device
// DialIxNetwork creates a client connection to the ATE's IxNetwork endpoint.
DialIxNetwork(context.Context) (*IxNetwork, error)
// DialGNMI creates a client connection to the ATE's gNMI endpoint.
// See the interface comment for proper handling of dial options.
// This method must be implemented to receive gNMI from OTG but not from IxNetwork;
// Implementing DialIxNetwork is sufficient for gNMI support for IxNetwork.
DialGNMI(context.Context, ...grpc.DialOption) (gpb.GNMIClient, error)
// DialOTG creates a client connection to the ATE's OTG endpoint.
// See the interface comment for proper handling of dial options.
DialOTG(context.Context, ...grpc.DialOption) (gosnappi.Api, error)
mustEmbedAbstractATE()
}
// Port is a reserved Port.
type Port struct {
Name string
Speed opb.Port_Speed
CardModel string
PMD opb.Port_Pmd
}
func (p *Port) String() string {
return fmt.Sprintf("Port%+v", *p)
}
// IxNetwork provides information for an IxNetwork session.
type IxNetwork struct {
// Session is an IxNetwork session for an ATE.
Session *ixweb.Session
// ChassisHost is an optional hostname or IP address to use when assigning
// Ixia VPorts. If empty, defaults to the name of the reserved ATE.
ChassisHost string
// SyslogHost is an optional hostname or IP address to which IxNetwork should
// stream logs. If empty, syslog streaming is not enabled.
SyslogHost string
}
// GNSIClients stores APIs to GNSI services.
// All implementations of this interface must embed AbstractGNSIClients.
type GNSIClients interface {
Authz() authzpb.AuthzClient
Pathz() pathzpb.PathzClient
Certz() certzpb.CertzClient
Credentialz() credzpb.CredentialzClient
Acctz() acctzpb.AcctzClient
AcctzStream() acctzpb.AcctzStreamClient
Attestz() attestzpb.TpmAttestzServiceClient
Enrollz() enrollzpb.TpmEnrollzServiceClient
mustEmbedAbstractGNSIClients()
}
// CLIClient provides the interface for sending CLI commands to the DUT.
// All implementations of this interface must embed AbstractCLIClient.
type CLIClient interface {
RunCommand(context.Context, string) (CommandResult, error)
mustEmbedAbstractCLIClient()
}
// CommandResult provides the interface for the result of a CLI command.
// All implementations of this interface must embed AbstractCommandResult.
type CommandResult interface {
// Output returns the output of the command.
// The return value may be non-empty even when the command fails.
Output() string
// Error returns an error message that occurred when running the command.
// The return value is the empty string if and only if the command succeeds.
Error() string
mustEmbedAbstractCommandResult()
}
// ConsoleClient provides the interface for console access to the DUT.
// All implementations of this interface must embed AbstractConsoleClient.
type ConsoleClient interface {
Stdin() io.WriteCloser
Stdout() io.ReadCloser
Stderr() io.ReadCloser
Close() error
mustEmbedAbstractConsoleClient()
}