Skip to content

Commit 2ecb315

Browse files
ZilinIBmwfarb
authored andcommitted
basic functionality of scmp echo added into webapp (#73)
* basic functionality of scmp echo added into webapp * imporved duration parser for scmpecho command, formatted. * Ignored unrelevant files.
1 parent d140151 commit 2ecb315

File tree

11 files changed

+655
-94
lines changed

11 files changed

+655
-94
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,6 @@ tools/pathdb_dump/pathdb_dump
5151
netcat/netcat
5252
roughtime/timeclient/timeclient
5353
roughtime/timeserver/timeserver
54+
55+
# vscode workspace
56+
*.code-workspace

webapp/config/servers_default.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,31 @@
7070
"addr": "192.168.1.111",
7171
"port": 42003
7272
}
73+
],
74+
"echo": [
75+
{
76+
"name": "17-ffaa:0:1107 Attachment Point",
77+
"isdas": "17-ffaa:0:1107",
78+
"addr": "10.0.8.1",
79+
"port": 30100
80+
},
81+
{
82+
"name": "18-ffaa:0:1202 Attachment Point",
83+
"isdas": "18-ffaa:0:1202",
84+
"addr": "10.0.8.1",
85+
"port": 30100
86+
},
87+
{
88+
"name": "19-ffaa:0:1303 Attachment Point",
89+
"isdas": "19-ffaa:0:1303",
90+
"addr": "10.0.8.1",
91+
"port": 30100
92+
},
93+
{
94+
"name": "20-ffaa:0:1404 Attachment Point",
95+
"isdas": "20-ffaa:0:1404",
96+
"addr": "10.0.8.1",
97+
"port": 30100
98+
}
7399
]
74100
}

webapp/lib/bwcont.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func ExtractBwtestRespData(resp string, d *model.BwTestItem, start time.Time) {
139139
func GetBwByTimeHandler(w http.ResponseWriter, r *http.Request, active bool, srcpath string) {
140140
r.ParseForm()
141141
since := r.PostFormValue("since")
142-
log.Info("Requesting data since", "timestamp", since)
142+
log.Info("Requesting bwtest data since", "timestamp", since)
143143
// find undisplayed test results
144144
bwTestResults, err := model.ReadBwTestItemsSince(since)
145145
if CheckError(err) {
@@ -171,28 +171,28 @@ func removeOuterQuotes(s string) string {
171171
return s
172172
}
173173

174-
// WriteBwtestCsv appends the bwtest data in csv-format to srcpath.
175-
func WriteBwtestCsv(bwtest *model.BwTestItem, srcpath string) {
174+
// WriteContCmdCsv appends the continuous cmd data (bwtest or echo) in csv-format to srcpath.
175+
func WriteContCmdCsv(d model.CmdItem, srcpath string, appSel string) {
176176
// newfile name for every day
177-
dataFileBwtester := "data/bwtester-" + time.Now().Format("2006-01-02") + ".csv"
178-
bwdataPath := path.Join(srcpath, dataFileBwtester)
177+
dataFileCmd := "data/" + appSel + "-" + time.Now().Format("2006-01-02") + ".csv"
178+
cmdDataPath := path.Join(srcpath, dataFileCmd)
179179
// write headers if file is new
180180
writeHeader := false
181-
if _, err := os.Stat(dataFileBwtester); os.IsNotExist(err) {
181+
if _, err := os.Stat(dataFileCmd); os.IsNotExist(err) {
182182
writeHeader = true
183183
}
184184
// open/create file
185-
f, err := os.OpenFile(bwdataPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
185+
f, err := os.OpenFile(cmdDataPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
186186
if CheckError(err) {
187187
return
188188
}
189189
w := csv.NewWriter(f)
190190
// export headers if this is a new file
191191
if writeHeader {
192-
headers := bwtest.GetHeaders()
192+
headers := d.GetHeaders()
193193
w.Write(headers)
194194
}
195-
values := bwtest.ToSlice()
195+
values := d.ToSlice()
196196
w.Write(values)
197197
w.Flush()
198198
}

webapp/lib/config.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ func GenServerNodeDefaults(srcpath string) {
9898
serIaDef + `", "addr":"` + serDefAddr + `","port":` + serPortDefImg + `}], `)
9999
jsonBuf = append(jsonBuf, json...)
100100
json = []byte(`"sensorapp": [{"name":"localhost","isdas":"` +
101-
serIaDef + `", "addr":"` + serDefAddr + `","port":` + serPortDefSen + `}] `)
101+
serIaDef + `", "addr":"` + serDefAddr + `","port":` + serPortDefSen + `}], `)
102+
jsonBuf = append(jsonBuf, json...)
103+
json = []byte(`"echo": [{"name":"localhost","isdas":"` +
104+
serIaDef + `", "addr":"` + serDefAddr + `","port":` + serPortDefSen + `}]`)
102105
jsonBuf = append(jsonBuf, json...)
103106

104107
jsonBuf = append(jsonBuf, []byte(` }`)...)

webapp/lib/echocont.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package lib
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"regexp"
8+
"strconv"
9+
"strings"
10+
"time"
11+
12+
log "github.com/inconshreveable/log15"
13+
model "github.com/netsec-ethz/scion-apps/webapp/models"
14+
. "github.com/netsec-ethz/scion-apps/webapp/util"
15+
)
16+
17+
// results data extraction regex
18+
var reRunTime = `(packet loss, time )(\S*)`
19+
var reRespTime = `(scmp_seq=0 time=)(\S*)`
20+
var rePktLoss = `(\d+)(% packet loss,)`
21+
22+
// ExtractEchoRespData will parse cmd line output from scmp echo for adding EchoItem fields.
23+
func ExtractEchoRespData(resp string, d *model.EchoItem, start time.Time) {
24+
// store duration in ms
25+
diff := time.Now().Sub(start)
26+
d.ActualDuration = int(diff.Nanoseconds() / 1e6)
27+
28+
// store current epoch in ms
29+
d.Inserted = time.Now().UnixNano() / 1e6
30+
31+
log.Info("resp response", "content", resp)
32+
33+
var data = make(map[string]float32)
34+
// -1 if no match for response time, indicating response timeout or packets out of order
35+
data["response_time"] = -1
36+
var path, err string
37+
var match bool
38+
pathNext := false
39+
r := strings.Split(resp, "\n")
40+
for i := range r {
41+
// match response time in unit ms
42+
match, _ = regexp.MatchString(reRespTime, r[i])
43+
if match {
44+
re := regexp.MustCompile(reRespTime)
45+
tStr := re.FindStringSubmatch(r[i])[2]
46+
t, _ := time.ParseDuration(tStr)
47+
data["response_time"] = float32(t.Nanoseconds()) / 1e6
48+
}
49+
50+
// match run time
51+
match, _ = regexp.MatchString(reRunTime, r[i])
52+
if match {
53+
re := regexp.MustCompile(reRunTime)
54+
tStr := re.FindStringSubmatch(r[i])[2]
55+
t, _ := time.ParseDuration(tStr)
56+
data["run_time"] = float32(t.Nanoseconds()) / 1e6
57+
}
58+
59+
// match packet loss
60+
match, _ = regexp.MatchString(rePktLoss, r[i])
61+
if match {
62+
re := regexp.MustCompile(rePktLoss)
63+
loss := re.FindStringSubmatch(r[i])[1]
64+
l, _ := strconv.ParseFloat(loss, 32)
65+
data["packet_loss"] = float32(l)
66+
}
67+
68+
// save used path (default or interactive) for later user display
69+
if pathNext {
70+
path = strings.TrimSpace(r[i])
71+
}
72+
match, _ = regexp.MatchString(reUPath, r[i])
73+
pathNext = match
74+
75+
// evaluate error message potential
76+
match1, _ := regexp.MatchString(reErr1, r[i])
77+
match2, _ := regexp.MatchString(reErr2, r[i])
78+
match3, _ := regexp.MatchString(reErr3, r[i])
79+
80+
if match1 {
81+
re := regexp.MustCompile(reErr1)
82+
err = re.FindStringSubmatch(r[i])[1]
83+
//log.Info("match1", "err", err)
84+
} else if match2 {
85+
re := regexp.MustCompile(reErr2)
86+
err = re.FindStringSubmatch(r[i])[1]
87+
} else if match3 {
88+
re := regexp.MustCompile(reErr3)
89+
err = re.FindStringSubmatch(r[i])[1]
90+
}
91+
}
92+
log.Info("app response", "data", data)
93+
94+
//log.Info("print parsed result", "error", err)
95+
//log.Info("print parsed result", "path", path)
96+
97+
d.RunTime, _ = data["run_time"]
98+
d.ResponseTime, _ = data["response_time"]
99+
d.PktLoss = int(data["packet_loss"])
100+
d.Error = err
101+
d.Path = path
102+
d.CmdOutput = resp // pipe log output to render in display later
103+
}
104+
105+
// GetEchoByTimeHandler request the echo results stored since provided time.
106+
func GetEchoByTimeHandler(w http.ResponseWriter, r *http.Request, active bool, srcpath string) {
107+
r.ParseForm()
108+
since := r.PostFormValue("since")
109+
log.Info("Requesting echo data since", "timestamp", since)
110+
// find undisplayed test results
111+
echoResults, err := model.ReadEchoItemsSince(since)
112+
if CheckError(err) {
113+
returnError(w, err)
114+
return
115+
}
116+
log.Debug("Requested data:", "echoResults", echoResults)
117+
118+
echoJSON, err := json.Marshal(echoResults)
119+
if CheckError(err) {
120+
returnError(w, err)
121+
return
122+
}
123+
jsonBuf := []byte(`{ "graph": ` + string(echoJSON))
124+
json := []byte(`, "active": ` + strconv.FormatBool(active))
125+
jsonBuf = append(jsonBuf, json...)
126+
jsonBuf = append(jsonBuf, []byte(`}`)...)
127+
128+
// ensure % if any, is escaped correctly before writing to printf formatter
129+
fmt.Fprintf(w, strings.Replace(string(jsonBuf), "%", "%%", -1))
130+
}

webapp/models/bwtests.go

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,8 @@ package models
33
import (
44
"fmt"
55
"reflect"
6-
"strconv"
7-
"time"
8-
9-
log "github.com/inconshreveable/log15"
10-
. "github.com/netsec-ethz/scion-apps/webapp/util"
116
)
127

13-
var bwTestDbExpire = time.Duration(24) * time.Hour
14-
158
// BwTestItem reflects one row in the bwtests table with all columns.
169
type BwTestItem struct {
1710
Inserted int64 // v0, ms
@@ -111,7 +104,7 @@ func createBwTestTable() error {
111104
SCArrAvg INT,
112105
SCArrMin INT,
113106
SCArrMax INT,
114-
Error TEXT
107+
Error TEXT
115108
);
116109
`
117110
_, err := db.Exec(sqlCreateTable)
@@ -337,17 +330,3 @@ func DeleteBwTestItemsBefore(before string) (int64, error) {
337330
}
338331
return count, nil
339332
}
340-
341-
// MaintainDatabase is a goroutine that runs independanly to cleanup the
342-
// database according to the defined schedule.
343-
func MaintainDatabase() {
344-
for {
345-
before := time.Now().Add(-bwTestDbExpire)
346-
count, err := DeleteBwTestItemsBefore(strconv.FormatInt(before.UnixNano()/1e6, 10))
347-
CheckError(err)
348-
if count > 0 {
349-
log.Warn(fmt.Sprint("Deleting", count, "bwtests db rows older than", bwTestDbExpire))
350-
}
351-
time.Sleep(bwTestDbExpire)
352-
}
353-
}

webapp/models/db.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ package models
33
import (
44
"database/sql"
55
"fmt"
6+
"strconv"
7+
"time"
68

79
log "github.com/inconshreveable/log15"
10+
. "github.com/netsec-ethz/scion-apps/webapp/util"
811
)
912

1013
var db *sql.DB
11-
var bwDbVer = 2
14+
var dbVer = 2
15+
var dbExpire = time.Duration(24) * time.Hour
1216

1317
// InitDB controls the opening connection to the database.
1418
func InitDB(filepath string) error {
@@ -33,6 +37,10 @@ func LoadDB() error {
3337
if err != nil {
3438
return err
3539
}
40+
err = createEchoTable()
41+
if err != nil {
42+
return err
43+
}
3644
version, err := getUserVersion()
3745
if err != nil {
3846
return err
@@ -48,17 +56,39 @@ func LoadDB() error {
4856
if err != nil {
4957
return err
5058
}
59+
5160
//set updated version
52-
if version < bwDbVer {
53-
err := setUserVersion(bwDbVer)
61+
if version < dbVer {
62+
err := setUserVersion(dbVer)
5463
if err != nil {
5564
return err
5665
}
57-
log.Info("Migrated to database version", "version", bwDbVer)
66+
log.Info("Migrated to database version", "version", dbVer)
5867
}
5968
return err
6069
}
6170

71+
// MaintainDatabase is a goroutine that runs independanly to cleanup the
72+
// database according to the defined schedule.
73+
func MaintainDatabase() {
74+
for {
75+
before := time.Now().Add(-dbExpire)
76+
77+
count1, err1 := DeleteBwTestItemsBefore(strconv.FormatInt(before.UnixNano()/1e6, 10))
78+
CheckError(err1)
79+
if count1 > 0 {
80+
log.Warn(fmt.Sprint("Deleting ", count1, " bwtests db rows older than", dbExpire))
81+
}
82+
83+
count2, err2 := DeleteEchoItemsBefore(strconv.FormatInt(before.UnixNano()/1e6, 10))
84+
CheckError(err2)
85+
if count2 > 0 {
86+
log.Warn(fmt.Sprint("Deleting ", count2, " echo db rows older than", dbExpire))
87+
}
88+
time.Sleep(dbExpire)
89+
}
90+
}
91+
6292
func addColumn(table string, column string) error {
6393
sqlAddCol := fmt.Sprintf(`ALTER TABLE %s ADD COLUMN %s;`, table, column)
6494
log.Info(sqlAddCol)

0 commit comments

Comments
 (0)