Skip to content

Commit 9fee954

Browse files
authored
[TF] Cleanup echo Port (istio#37808)
We currently have Port and PortName and the former is a pointer. This leads to a lot of complexity to the logic. This PR removes PortName and makes Port a struct rather than a pointer.
1 parent f0745fa commit 9fee954

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+764
-531
lines changed

pkg/config/protocol/instance.go

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import "strings"
1919
// Instance defines network protocols for ports
2020
type Instance string
2121

22+
func (i Instance) String() string {
23+
return string(i)
24+
}
25+
2226
const (
2327
// GRPC declares that the port carries gRPC traffic.
2428
GRPC Instance = "GRPC"

pkg/test/framework/components/echo/calloptions.go

+94-54
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,17 @@ type CallOptions struct {
9292
// To is the Target to be called. Required.
9393
To Instance
9494

95-
// Port on the target Instance. Either Port or PortName must be specified.
96-
Port *Port
95+
// Port to be used for the call. Ignored if Scheme == DNS. If the Port.ServicePort is set,
96+
// either Port.Protocol or Scheme must also be set. If Port.ServicePort is not set,
97+
// the port is looked up in To by either Port.Name or Port.Protocol.
98+
Port Port
9799

98-
// PortName of the port on the target Instance. Either Port or PortName must be specified.
99-
PortName string
100-
101-
// Scheme to be used when making the call. If not provided, an appropriate default for the
102-
// port will be used (if feasible).
100+
// Scheme to be used when making the call. If not provided, the Scheme will be selected
101+
// based on the Port.Protocol.
103102
Scheme scheme.Instance
104103

105104
// Address specifies the host name or IP address to be used on the request. If not provided,
106-
// an appropriate default is chosen for the target Instance.
105+
// an appropriate default is chosen for To.
107106
Address string
108107

109108
// Count indicates the number of exchanges that should be made with the service endpoint.
@@ -161,10 +160,6 @@ func (o CallOptions) GetHost() string {
161160

162161
func (o CallOptions) DeepCopy() CallOptions {
163162
clone := o
164-
if o.Port != nil {
165-
dc := *o.Port
166-
clone.Port = &dc
167-
}
168163
if o.TLS.Alpn != nil {
169164
clone.TLS.Alpn = make([]string, len(o.TLS.Alpn))
170165
copy(clone.TLS.Alpn, o.TLS.Alpn)
@@ -174,50 +169,112 @@ func (o CallOptions) DeepCopy() CallOptions {
174169

175170
// FillDefaults fills out any defaults that haven't been explicitly specified.
176171
func (o *CallOptions) FillDefaults() error {
172+
// Fill in the address if not set.
173+
if err := o.fillAddress(); err != nil {
174+
return err
175+
}
176+
177+
// Fill in the port if not set or the service port is missing.
178+
if err := o.fillPort(); err != nil {
179+
return err
180+
}
181+
182+
// Fill in the scheme if not set, using the port information.
183+
if err := o.fillScheme(); err != nil {
184+
return err
185+
}
186+
187+
// Fill in HTTP headers
188+
o.fillHeaders()
189+
190+
if o.Timeout <= 0 {
191+
o.Timeout = common.DefaultRequestTimeout
192+
}
193+
194+
if o.Count <= 0 {
195+
o.Count = common.DefaultCount
196+
}
197+
198+
// Add any user-specified options after the default options (last option wins for each type of option).
199+
o.Retry.Options = append(append([]retry.Option{}, DefaultCallRetryOptions()...), o.Retry.Options...)
200+
201+
// If no Check was specified, assume no error.
202+
if o.Check == nil {
203+
o.Check = check.None()
204+
}
205+
return nil
206+
}
207+
208+
func (o *CallOptions) fillAddress() error {
209+
if o.Address == "" {
210+
if o.To == nil {
211+
return errors.New("if address is not set, then To must be set")
212+
}
213+
214+
// No host specified, use the fully qualified domain name for the service.
215+
o.Address = o.To.Config().ClusterLocalFQDN()
216+
}
217+
return nil
218+
}
219+
220+
func (o *CallOptions) fillPort() error {
221+
if o.Scheme == scheme.DNS {
222+
// Port is not used for DNS.
223+
return nil
224+
}
225+
226+
if o.Port.ServicePort > 0 {
227+
if o.Port.Protocol == "" && o.Scheme == "" {
228+
return errors.New("callOptions: servicePort specified, but no protocol or scheme was set")
229+
}
230+
231+
// The service port was set explicitly. Nothing else to do.
232+
return nil
233+
}
234+
177235
if o.To != nil {
178236
servicePorts := o.To.Config().Ports.GetServicePorts()
179-
if o.PortName == "" {
180-
// Validate the Port value.
181237

182-
if o.Port == nil {
183-
return errors.New("callOptions: PortName or Port must be provided")
238+
if o.Port.Name != "" {
239+
// Look up the port by name.
240+
p, found := servicePorts.ForName(o.Port.Name)
241+
if !found {
242+
return fmt.Errorf("callOptions: no port named %s available in To Instance", o.Port.Name)
184243
}
244+
o.Port = p
245+
return nil
246+
}
185247

186-
// Check the specified port for a match against the To Instance
187-
if !servicePorts.Contains(*o.Port) {
188-
return fmt.Errorf("callOptions: Port does not match any To port")
189-
}
190-
} else {
191-
// Look up the port.
192-
p, found := servicePorts.ForName(o.PortName)
248+
if o.Port.Protocol != "" {
249+
// Look up the port by protocol.
250+
p, found := servicePorts.ForProtocol(o.Port.Protocol)
193251
if !found {
194-
return fmt.Errorf("callOptions: no port named %s available in To Instance", o.PortName)
252+
return fmt.Errorf("callOptions: no port for protocol %s available in To Instance", o.Port.Protocol)
195253
}
196-
o.Port = &p
197-
}
198-
} else if o.Scheme == scheme.DNS {
199-
// Just need address
200-
if o.Address == "" {
201-
return fmt.Errorf("for DNS, address must be set")
254+
o.Port = p
255+
return nil
202256
}
203-
o.Port = &Port{}
204-
} else if o.Port == nil || o.Port.ServicePort <= 0 || (o.Port.Protocol == "" && o.Scheme == "") || o.Address == "" {
257+
}
258+
259+
if o.Port.ServicePort <= 0 || (o.Port.Protocol == "" && o.Scheme == "") || o.Address == "" {
205260
return fmt.Errorf("if target is not set, then port.servicePort, port.protocol or schema, and address must be set")
206261
}
207262

263+
return nil
264+
}
265+
266+
func (o *CallOptions) fillScheme() error {
208267
if o.Scheme == "" {
209268
// No protocol, fill it in.
210269
var err error
211270
if o.Scheme, err = o.Port.Scheme(); err != nil {
212271
return err
213272
}
214273
}
274+
return nil
275+
}
215276

216-
if o.Address == "" {
217-
// No host specified, use the fully qualified domain name for the service.
218-
o.Address = o.To.Config().ClusterLocalFQDN()
219-
}
220-
277+
func (o *CallOptions) fillHeaders() {
221278
// Initialize the headers and add a default Host header if none provided.
222279
if o.HTTP.Headers == nil {
223280
o.HTTP.Headers = make(http.Header)
@@ -229,21 +286,4 @@ func (o *CallOptions) FillDefaults() error {
229286
if h := o.GetHost(); len(h) > 0 {
230287
o.HTTP.Headers.Set(headers.Host, h)
231288
}
232-
233-
if o.Timeout <= 0 {
234-
o.Timeout = common.DefaultRequestTimeout
235-
}
236-
237-
if o.Count <= 0 {
238-
o.Count = common.DefaultCount
239-
}
240-
241-
// Add any user-specified options after the default options (last option wins for each type of option).
242-
o.Retry.Options = append(append([]retry.Option{}, DefaultCallRetryOptions()...), o.Retry.Options...)
243-
244-
// If no Check was specified, assume no error.
245-
if o.Check == nil {
246-
o.Check = check.None()
247-
}
248-
return nil
249289
}

pkg/test/framework/components/echo/common/call.go

+7-10
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,13 @@ func ForwardEcho(srcName string, clientProvider EchoClientProvider, opts *echo.C
156156
return c.ForwardEcho(context.Background(), req)
157157
})
158158
if err != nil {
159-
if opts.Port != nil {
160-
err = fmt.Errorf("failed calling %s->'%s://%s:%d/%s': %v",
161-
srcName,
162-
strings.ToLower(string(opts.Port.Protocol)),
163-
opts.Address,
164-
opts.Port.ServicePort,
165-
opts.HTTP.Path,
166-
err)
167-
}
168-
return nil, err
159+
return nil, fmt.Errorf("failed calling %s->'%s://%s:%d/%s': %v",
160+
srcName,
161+
strings.ToLower(string(opts.Port.Protocol)),
162+
opts.Address,
163+
opts.Port.ServicePort,
164+
opts.HTTP.Path,
165+
err)
169166
}
170167
return res, nil
171168
}

pkg/test/framework/components/echo/kube/instance.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (c *instance) Restart() error {
193193
// aggregateResponses forwards an echo request from all workloads belonging to this echo instance and aggregates the results.
194194
func (c *instance) aggregateResponses(opts echo.CallOptions) (echoClient.Responses, error) {
195195
// TODO put this somewhere else, or require users explicitly set the protocol - quite hacky
196-
if c.Config().IsProxylessGRPC() && (opts.Scheme == scheme.GRPC || opts.PortName == "grpc" || opts.Port != nil && opts.Port.Protocol == protocol.GRPC) {
196+
if c.Config().IsProxylessGRPC() && (opts.Scheme == scheme.GRPC || opts.Port.Name == "grpc" || opts.Port.Protocol == protocol.GRPC) {
197197
// for gRPC calls, use XDS resolver
198198
opts.Scheme = scheme.XDS
199199
}

pkg/test/framework/components/istio/ingress.go

+39-23
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import (
2222
"strconv"
2323
"time"
2424

25-
"istio.io/istio/pkg/config/protocol"
2625
"istio.io/istio/pkg/http/headers"
2726
"istio.io/istio/pkg/test"
2827
echoClient "istio.io/istio/pkg/test/echo"
28+
"istio.io/istio/pkg/test/echo/common/scheme"
2929
"istio.io/istio/pkg/test/framework/components/cluster"
3030
"istio.io/istio/pkg/test/framework/components/echo"
3131
"istio.io/istio/pkg/test/framework/components/echo/common"
@@ -182,51 +182,67 @@ func (c *ingressImpl) CallOrFail(t test.Failer, options echo.CallOptions) echoCl
182182
return resp
183183
}
184184

185-
func (c *ingressImpl) callEcho(options echo.CallOptions) (echoClient.Responses, error) {
186-
if options.Port == nil || options.Port.Protocol == "" {
187-
return nil, fmt.Errorf("must provide protocol")
188-
}
185+
func (c *ingressImpl) callEcho(opts echo.CallOptions) (echoClient.Responses, error) {
189186
var (
190187
addr string
191188
port int
192189
)
193-
options = options.DeepCopy()
194-
if options.Port.ServicePort == 0 {
190+
opts = opts.DeepCopy()
191+
192+
if opts.Port.ServicePort == 0 {
193+
s, err := c.schemeFor(opts)
194+
if err != nil {
195+
return nil, err
196+
}
197+
opts.Scheme = s
198+
195199
// Default port based on protocol
196-
switch options.Port.Protocol {
197-
case protocol.HTTP:
200+
switch s {
201+
case scheme.HTTP:
198202
addr, port = c.HTTPAddress()
199-
case protocol.HTTPS:
203+
case scheme.HTTPS:
200204
addr, port = c.HTTPSAddress()
201-
case protocol.TCP:
205+
case scheme.TCP:
202206
addr, port = c.TCPAddress()
203207
default:
204-
return nil, fmt.Errorf("protocol %v not supported, provide explicit port", options.Port.Protocol)
208+
return nil, fmt.Errorf("ingress: scheme %v not supported. Options: %v+", s, opts)
205209
}
206210
} else {
207-
addr, port = c.AddressForPort(options.Port.ServicePort)
211+
addr, port = c.AddressForPort(opts.Port.ServicePort)
208212
}
209213

210214
if addr == "" || port == 0 {
211-
scopes.Framework.Warnf("failed to get host and port for %s/%d", options.Port.Protocol, options.Port.ServicePort)
215+
scopes.Framework.Warnf("failed to get host and port for %s/%d", opts.Port.Protocol, opts.Port.ServicePort)
212216
}
213217

214218
// Even if they set ServicePort, when load balancer is disabled, we may need to switch to NodePort, so replace it.
215-
options.Port.ServicePort = port
216-
if len(options.Address) == 0 {
219+
opts.Port.ServicePort = port
220+
if len(opts.Address) == 0 {
217221
// Default address based on port
218-
options.Address = addr
222+
opts.Address = addr
219223
}
220-
if options.HTTP.Headers == nil {
221-
options.HTTP.Headers = map[string][]string{}
224+
if opts.HTTP.Headers == nil {
225+
opts.HTTP.Headers = map[string][]string{}
222226
}
223-
if host := options.GetHost(); len(host) > 0 {
224-
options.HTTP.Headers.Set(headers.Host, host)
227+
if host := opts.GetHost(); len(host) > 0 {
228+
opts.HTTP.Headers.Set(headers.Host, host)
225229
}
226230
if len(c.cluster.HTTPProxy()) > 0 {
227-
options.HTTP.HTTPProxy = c.cluster.HTTPProxy()
231+
opts.HTTP.HTTPProxy = c.cluster.HTTPProxy()
228232
}
229-
return common.CallEcho(&options)
233+
return common.CallEcho(&opts)
234+
}
235+
236+
func (c *ingressImpl) schemeFor(opts echo.CallOptions) (scheme.Instance, error) {
237+
if opts.Scheme == "" && opts.Port.Protocol == "" {
238+
return "", fmt.Errorf("must provide either protocol or scheme")
239+
}
240+
241+
if opts.Scheme != "" {
242+
return opts.Scheme, nil
243+
}
244+
245+
return opts.Port.Scheme()
230246
}
231247

232248
func (c *ingressImpl) ProxyStats() (map[string]int, error) {

0 commit comments

Comments
 (0)