-
Notifications
You must be signed in to change notification settings - Fork 0
/
ping.go
164 lines (145 loc) · 5.65 KB
/
ping.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
// Copyright (C) 2020-2022 Red Hat, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
package ping
import (
"regexp"
"strconv"
"time"
"github.com/test-network-function/test-network-function/pkg/tnf"
"github.com/test-network-function/test-network-function/pkg/tnf/dependencies"
"github.com/test-network-function/test-network-function/pkg/tnf/identifier"
"github.com/test-network-function/test-network-function/pkg/tnf/reel"
"github.com/test-network-function/test-network-function/pkg/utils"
)
// Ping provides a ping test implemented using command line tool `ping`.
type Ping struct {
result int
timeout time.Duration
args []string
transmitted int
received int
errors int
}
const (
// ConnectInvalidArgumentRegex is a regex which matches when an invalid IP address or hostname is provided as input.
ConnectInvalidArgumentRegex = `(?m)connect: Invalid argument$`
// SuccessfulOutputRegex matches a successfully run "ping" command. That does not mean that no errors or drops
// occurred during the test.
SuccessfulOutputRegex = `(?m)(\d+) packets transmitted, (\d+)( packets){0,1} received, (?:\+(\d+) errors)?.*$`
)
// Args returns the command line args for the test.
func (p *Ping) Args() []string {
return p.args
}
// GetIdentifier returns the tnf.Test specific identifier.
func (p *Ping) GetIdentifier() identifier.Identifier {
return identifier.PingIdentifier
}
// Timeout returns the timeout in seconds for the test.
func (p *Ping) Timeout() time.Duration {
return p.timeout
}
// Result returns the test result.
func (p *Ping) Result() int {
return p.result
}
// ReelFirst returns a step which expects the ping statistics within the test timeout.
func (p *Ping) ReelFirst() *reel.Step {
return &reel.Step{
Expect: p.GetReelFirstRegularExpressions(),
Timeout: p.timeout,
}
}
// ReelMatch parses the ping statistics and set the test result on match.
// The result is success if at least one response was received and the number of
// responses received is at most one less than the number received (the "missing"
// response may be in flight).
// The result is error if ping reported a protocol error (e.g. destination host
// unreachable), no requests were sent or there was some test execution error.
// Otherwise the result is failure.
// Returns no step; the test is complete.
func (p *Ping) ReelMatch(_, _, match string) *reel.Step {
re := regexp.MustCompile(ConnectInvalidArgumentRegex)
matched := re.FindStringSubmatch(match)
if matched != nil {
p.result = tnf.ERROR
}
re = regexp.MustCompile(SuccessfulOutputRegex)
matched = re.FindStringSubmatch(match)
if matched != nil {
// Ignore errors in converting matches to decimal integers.
// Regular expression `stat` is required to underwrite this assumption.
p.transmitted, _ = strconv.Atoi(matched[1])
p.received, _ = strconv.Atoi(matched[2])
p.errors, _ = strconv.Atoi(matched[4])
switch {
case p.transmitted == 0 || p.errors > 0:
p.result = tnf.ERROR
case p.received > 0 && (p.transmitted-p.received) <= 1:
p.result = tnf.SUCCESS
default:
p.result = tnf.FAILURE
}
}
return nil
}
// ReelTimeout returns a step which kills the ping test by sending it ^C.
func (p *Ping) ReelTimeout() *reel.Step {
return nil
}
// ReelEOF does nothing; ping requires no intervention on eof.
func (p *Ping) ReelEOF() {
}
// GetStats returns the transmitted, received and error counts.
func (p *Ping) GetStats() (transmitted, received, errors int) {
return p.transmitted, p.received, p.errors
}
// Command returns command line args for pinging `host` with `count` requests, or indefinitely if `count` is not
// positive.
func Command(host string, count int) []string {
if count > 0 {
return []string{dependencies.PingBinaryName, "-c", strconv.Itoa(count), host}
}
return []string{dependencies.PingBinaryName, host}
}
// Command same as command but uses nsenter to in the command
func CommandNsenter(containerPID, host string, count int) []string {
if count > 0 {
return []string{utils.AddNsenterPrefix(containerPID), dependencies.PingBinaryName, "-c", strconv.Itoa(count), host}
}
return []string{utils.AddNsenterPrefix(containerPID), dependencies.PingBinaryName, host}
}
// NewPing creates a new `Ping` test which pings `hosts` with `count` requests, or indefinitely if `count` is not
// positive, and executes within `timeout` seconds.
func NewPing(timeout time.Duration, host string, count int) *Ping {
return &Ping{
result: tnf.ERROR,
timeout: timeout,
args: Command(host, count),
}
}
// NewPingNsenter same as NewPing but takes a containerID to run ping with the nsenter command with the node OC.
func NewPingNsenter(timeout time.Duration, containerPID, host string, count int) *Ping {
return &Ping{
result: tnf.ERROR,
timeout: timeout,
args: CommandNsenter(containerPID, host, count),
}
}
// GetReelFirstRegularExpressions returns the regular expressions used for matching in ReelFirst.
func (p *Ping) GetReelFirstRegularExpressions() []string {
return []string{ConnectInvalidArgumentRegex, SuccessfulOutputRegex}
}