-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathcommand_query_status.go
754 lines (672 loc) · 23.8 KB
/
command_query_status.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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
// Copyright 2019. Akamai Technologies, Inc
//
// 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
//
// http://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 main
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"github.com/akamai/AkamaiOPEN-edgegrid-golang/configgtm-v1_4"
"github.com/akamai/AkamaiOPEN-edgegrid-golang/reportsgtm-v1"
akamai "github.com/akamai/cli-common-golang"
"github.com/fatih/color"
"github.com/olekukonko/tablewriter"
"github.com/urfave/cli"
)
var domainName string
var qsProperty string
var qsDatacenters *arrayFlags
var statusPeriodLen = "15m"
var qsNicknames []string
// DCTrafficStati represents Data Center Traffic Status returned structure. Contains a list of individual DC stati.
type DCTrafficStati struct {
Domain string
PeriodStart string
PeriodEnd string
StatusByDatacenter []*DCStatusDetail
}
// Enhanced DCTData struct
type EnhancedPropertyStatus struct {
Timestamp string
Properties []TimestampPropertyStatus
}
// Timestamp DC Prop Status
type TimestampPropertyStatus struct {
reportsgtm.DCTDRow
Enabled bool
Weight float64
}
// DCStatusDetail represents individual data center traffic status.
type DCStatusDetail struct {
DatacenterId int
DatacenterNickname string
ReportInterval string
DCStatusByProperty []EnhancedPropertyStatus
}
// PropertyStatus represents returned Property Status structure.
type PropertyStatus struct {
Domain string
PropertyName string
PeriodStart string
PeriodEnd string
ReportInterval string
StatusSummary *PropertyStatusSummary
DatacenterIntervalStatus []*reportsgtm.PropertyTData
}
// PropertyStatusSummary represents Property IP Status Summary struct
type PropertyStatusSummary struct {
LastUpdate string
CutOff float64
PropertyDCStatus []*PropertyDCStatus
}
// PropertyDCStatus represents Property DC Status Summary struct
type PropertyDCStatus struct {
reportsgtm.IpStatPerPropDRow
DCTotalPeriodRequests int64
DCPropertyUsage string
DCEnabled bool
DCWeight float64
}
var defaultPeriod time.Duration = 15 * 60 * 1000 * 1000
// Calc period start and end. Input string specifying duration, e.g. 15m. Returns formatted strings consumable by GTM Reports API.
func calcPeriodStartandEnd(trafficType string, periodLen string) (string, string, error) {
dur, err := time.ParseDuration(periodLen)
if err != nil {
dur = defaultPeriod
}
var window *reportsgtm.WindowResponse
if trafficType == "datacenter" {
window, err = reportsgtm.GetDatacentersTrafficWindow()
} else if trafficType == "property" {
window, err = reportsgtm.GetPropertiesTrafficWindow()
} else {
// shouldn't get here. If so, return invalid date
err := configgtm.CommonError{}
err.SetItem("entityName", "Window")
err.SetItem("name", "Data Window")
err.SetItem("apiErrorMessage", "Traffic Type "+trafficType+" not supported")
}
if err != nil {
// return invalid dates
return "", "", err
}
end := window.EndTime
start := end.Add(-dur)
return start.Format(time.RFC3339), end.Format(time.RFC3339), nil
}
type trafficTargetEnabledStatus struct {
ttDCID int
ttEnabled bool
ttWeight float64
}
// Build DC Properties enabled Map
func buildDCPropertiesEnabledMap(domain *configgtm.Domain, dcID int) map[string]*trafficTargetEnabledStatus {
propEnabledMap := make(map[string]*trafficTargetEnabledStatus)
for _, prop := range domain.Properties {
for _, tgt := range prop.TrafficTargets {
// collect enabled status
if tgt.DatacenterId == dcID {
ttMapEntry := &trafficTargetEnabledStatus{ttDCID: tgt.DatacenterId, ttEnabled: tgt.Enabled,
ttWeight: tgt.Weight}
propEnabledMap[prop.Name] = ttMapEntry
}
}
}
return propEnabledMap
}
// Build DC property List
func buildDCPropertyList(domain *configgtm.Domain, dcID int) []EnhancedPropertyStatus {
var dcPropList []EnhancedPropertyStatus
var dcProps []TimestampPropertyStatus
dcStat := EnhancedPropertyStatus{Timestamp: time.Now().Format(time.RFC3339)}
for _, propPtr := range domain.Properties {
for _, traffTarg := range propPtr.TrafficTargets {
if traffTarg.DatacenterId == dcID {
dcTimedProp := TimestampPropertyStatus{}
dcTimedProp.Name = propPtr.Name
dcTimedProp.Requests = 0
dcTimedProp.Status = "0"
dcTimedProp.Enabled = traffTarg.Enabled
dcTimedProp.Weight = traffTarg.Weight
dcProps = append(dcProps, dcTimedProp)
break
}
}
}
dcStat.Properties = dcProps
dcPropList = append(dcPropList, dcStat)
return dcPropList
}
// Retrieve a Datacenter
func findDatacenterInDomain(domain *configgtm.Domain, dcID int) (*configgtm.Datacenter, bool) {
for _, dc := range domain.Datacenters {
if dcID == dc.DatacenterId {
return dc, true
}
}
return nil, false
}
// Populate a list of empty DCStatusDetail structures
func populateEmptyDCStatusList() ([]*DCStatusDetail, error) {
var dcStatDetailList []*DCStatusDetail
dom, err := configgtm.GetDomain(domainName)
if err != nil {
return dcStatDetailList, err
}
for _, dcID := range qsDatacenters.flagList {
dcEntry := &DCStatusDetail{DatacenterId: dcID} // Do we need the nickname also?
if dc, ok := findDatacenterInDomain(dom, dcID); ok {
dcEntry.DatacenterNickname = dc.Nickname
}
dcEntry.DCStatusByProperty = buildDCPropertyList(dom, dcID)
dcStatDetailList = append(dcStatDetailList, dcEntry)
}
return dcStatDetailList, nil
}
// Retrieve Datacenter status for domain
func gatherDatacenterStatus() (*DCTrafficStati, error) {
dcTrafficStati := &DCTrafficStati{Domain: domainName}
// calc period start and end
pstart, pend, err := calcPeriodStartandEnd("datacenter", statusPeriodLen)
if err != nil {
return nil, err
}
// get the domain struct. Will need as cycle thru DCs
dom, err := configgtm.GetDomain(domainName)
if err != nil {
return nil, err
}
dcTrafficStati.PeriodStart = pstart
dcTrafficStati.PeriodEnd = pend
optArgs := make(map[string]string)
optArgs["start"] = pstart
optArgs["end"] = pend
// Looping on DCs
for _, dcID := range qsDatacenters.flagList {
dcTStatus, err := reportsgtm.GetTrafficPerDatacenter(domainName, dcID, optArgs)
if err != nil {
return nil, err
}
// Build DC Properties enabled list
enabledPropertiesMap := buildDCPropertiesEnabledMap(dom, dcID)
dcEntry := &DCStatusDetail{DatacenterId: dcID, DatacenterNickname: dcTStatus.Metadata.DatacenterNickname, ReportInterval: dcTStatus.Metadata.Interval}
if dcTStatus.DataRows == nil || len(dcTStatus.DataRows) < 1 {
dcEntry.DCStatusByProperty = buildDCPropertyList(dom, dcID)
} else {
// Need to poulate dc properties status structure by timestamp
enhPropList := make([]EnhancedPropertyStatus, 0)
for _, dctData := range dcTStatus.DataRows {
// make map copy
enabledPropMapCopy := make(map[string]*trafficTargetEnabledStatus)
for i, d := range enabledPropertiesMap {
enabledPropMapCopy[i] = d
}
enhPropStat := EnhancedPropertyStatus{Timestamp: dctData.Timestamp}
propsList := make([]TimestampPropertyStatus, 0)
for _, props := range dctData.Properties {
propRowData := TimestampPropertyStatus{}
propRowData.Name = props.Name
propRowData.Requests = props.Requests
propRowData.Status = props.Status
if dcEnb, ok := enabledPropMapCopy[props.Name]; ok {
propRowData.Enabled = dcEnb.ttEnabled
propRowData.Weight = dcEnb.ttWeight
}
delete(enabledPropMapCopy, props.Name)
propsList = append(propsList, propRowData)
}
// Add in any missing Properties
for propName, eInfo := range enabledPropMapCopy {
propRowData := TimestampPropertyStatus{}
propRowData.Name = propName
propRowData.Requests = 0
propRowData.Status = "0"
propRowData.Enabled = eInfo.ttEnabled
propRowData.Weight = eInfo.ttWeight
propsList = append(propsList, propRowData)
}
enhPropStat.Properties = propsList
enhPropList = append(enhPropList, enhPropStat)
}
dcEntry.DCStatusByProperty = enhPropList
}
dcTrafficStati.StatusByDatacenter = append(dcTrafficStati.StatusByDatacenter, dcEntry)
}
return dcTrafficStati, nil
}
// Retrieve Domain status
func getDomainStatus() (*configgtm.ResponseStatus, error) {
domStatus, err := configgtm.GetDomainStatus(domainName)
if err != nil {
return nil, err
}
return domStatus, nil
}
// Retrieve Status and DC status for property
func gatherPropertyStatus() (*PropertyStatus, error) {
propStat := &PropertyStatus{PropertyName: qsProperty}
// calc traffic period start and end
pstart, pend, err := calcPeriodStartandEnd("property", statusPeriodLen)
if err != nil {
return nil, err
}
optArgs := make(map[string]string)
// Retrieve IP Availability status
optArgs["mostRecent"] = "true"
propertyIpAvail, err := reportsgtm.GetIpStatusPerProperty(domainName, qsProperty, optArgs)
if err != nil {
return nil, err
}
var propertyTraffic *reportsgtm.PropertyTrafficResponse
// Retrieve Property Traffic status
delete(optArgs, "mostRecent")
optArgs["start"] = pstart
optArgs["end"] = pend
propertyTraffic, err = reportsgtm.GetTrafficPerProperty(domainName, qsProperty, optArgs)
if err != nil {
return nil, err
}
// Calc requests % per datacenter
type dcReqs struct {
reqs int64
perc float64
}
var dcReqMap map[int]dcReqs
var propertyTotalReqs int64
dcReqMap = make(map[int]dcReqs)
for _, tData := range propertyTraffic.DataRows {
for _, dcData := range tData.Datacenters {
dcRow, ok := dcReqMap[dcData.DatacenterId] // try to get entry
if !ok {
dcRow = dcReqs{}
}
dcRow.reqs += dcData.Requests
dcReqMap[dcData.DatacenterId] = dcRow
propertyTotalReqs += dcData.Requests
}
}
// find any missing datacenters. as aside,build map of targets capturing name and enabled flag.
var disabledDCPeriodList []*reportsgtm.PropertyDRow
type trafficTargetEnabledStatus struct {
ttName string
ttNickname string
ttEnabled bool
ttWeight float64
}
ttEnabledMap := make(map[int]trafficTargetEnabledStatus)
prop, err := configgtm.GetProperty(qsProperty, domainName)
// if error, can't find disabled targets ... results in incomplete set
if err != nil {
return nil, err
}
for _, tgt := range prop.TrafficTargets {
// collect enabled status for later use
ttMapEntry := trafficTargetEnabledStatus{ttName: tgt.Name, ttEnabled: tgt.Enabled,
ttWeight: tgt.Weight}
// need info from DC, e.g. nickname
dc, err := configgtm.GetDatacenter(tgt.DatacenterId, domainName)
if err == nil {
ttMapEntry.ttNickname = dc.Nickname
}
ttEnabledMap[tgt.DatacenterId] = ttMapEntry
if _, ok := dcReqMap[tgt.DatacenterId]; !ok {
// not in map so not in returned results ...
//create and populate
disabledDCP := &reportsgtm.PropertyDRow{DatacenterId: tgt.DatacenterId, TrafficTargetName: tgt.Name, Requests: 0}
disabledDCP.Status = "0" // if wasn't reported on, likely not responding to requests
// collect enabled status for later use
disabledDCP.Nickname = ttMapEntry.ttNickname
disabledDCPeriodList = append(disabledDCPeriodList, disabledDCP)
// add an entry to dcReqMap
dcReqMap[tgt.DatacenterId] = dcReqs{reqs: 0, perc: 0.0}
}
}
// append to datarow dc lists
for _, drEntry := range propertyTraffic.DataRows {
drEntry.Datacenters = append(drEntry.Datacenters, disabledDCPeriodList...)
}
// Calculate percentage for WHOLE period
for k, dcRow := range dcReqMap {
if propertyTotalReqs > 0 {
dcRow.perc = (float64(dcRow.reqs) / float64(propertyTotalReqs)) * 100
} else {
dcRow.perc = float64(0)
}
dcReqMap[k] = dcRow
}
// Build PropertyResponse struct
propStat.Domain = propertyIpAvail.Metadata.Domain
propStat.PropertyName = propertyIpAvail.Metadata.Property
propStat.PeriodStart = propertyTraffic.Metadata.Start
propStat.PeriodEnd = propertyTraffic.Metadata.End
propStat.ReportInterval = propertyTraffic.Metadata.Interval
propStat.DatacenterIntervalStatus = propertyTraffic.DataRows
var statusSummary *PropertyStatusSummary
statusSummary = &PropertyStatusSummary{}
if len(propertyIpAvail.DataRows) > 0 {
statusSummary.LastUpdate = propertyIpAvail.DataRows[0].Timestamp
statusSummary.CutOff = propertyIpAvail.DataRows[0].CutOff
} else {
statusSummary.LastUpdate = "Not Available"
}
var propertyDCStatusArray []*PropertyDCStatus
if len(propertyIpAvail.DataRows) > 0 {
for _, dr := range propertyIpAvail.DataRows {
for _, dc := range dr.Datacenters {
propertyDCStatus := &PropertyDCStatus{}
propertyDCStatus.Nickname = dc.Nickname
propertyDCStatus.DatacenterId = dc.DatacenterId
propertyDCStatus.TrafficTargetName = dc.TrafficTargetName
propertyDCStatus.IPs = dc.IPs
propertyDCStatus.DCPropertyUsage = fmt.Sprintf("%.2f", dcReqMap[dc.DatacenterId].perc) + "%"
propertyDCStatus.DCTotalPeriodRequests = dcReqMap[dc.DatacenterId].reqs
propertyDCStatus.DCEnabled = ttEnabledMap[dc.DatacenterId].ttEnabled
propertyDCStatus.DCWeight = ttEnabledMap[dc.DatacenterId].ttWeight
propertyDCStatusArray = append(propertyDCStatusArray, propertyDCStatus)
// remove entry from map ...
delete(ttEnabledMap, dc.DatacenterId)
}
}
}
// Add in disabled DCs
var disabledDCSumList []*PropertyDCStatus
for dcId, eMap := range ttEnabledMap {
disabledDCSum := &PropertyDCStatus{}
disabledDCSum.DatacenterId = dcId
disabledDCSum.TrafficTargetName = eMap.ttName
disabledDCSum.DCEnabled = eMap.ttEnabled
disabledDCSum.DCWeight = eMap.ttWeight
disabledDCSum.Nickname = eMap.ttNickname
disabledDCSum.DCPropertyUsage = "0.00%"
disabledDCSum.IPs = make([]*reportsgtm.IpStatIp, 0)
disabledDCSumList = append(disabledDCSumList, disabledDCSum)
}
propertyDCStatusArray = append(propertyDCStatusArray, disabledDCSumList...)
statusSummary.PropertyDCStatus = propertyDCStatusArray
propStat.StatusSummary = statusSummary
return propStat, nil
}
// worker function for query-status
func cmdQueryStatus(c *cli.Context) error {
config, err := akamai.GetEdgegridConfig(c)
if err != nil {
return err
}
reportsgtm.Init(config)
configgtm.Init(config)
if c.NArg() == 0 {
cli.ShowCommandHelp(c, c.Command.Name)
return cli.NewExitError(color.RedString("domain is required"), 1)
}
domainName = c.Args().Get(0)
qsProperty = c.String("property")
qsDatacenters = (c.Generic("datacenter")).(*arrayFlags)
if c.IsSet("verbose") {
verboseStatus = true
}
if c.IsSet("property") && c.IsSet("datacenter") {
return cli.NewExitError(color.RedString("property OR datacenter(s) must be specified"), 1)
}
err = ParseNicknames(qsDatacenters.nicknamesList, domainName)
if err != nil {
if verboseStatus {
return cli.NewExitError(color.RedString("Unable to retrieve datacenter list. "+err.Error()), 1)
} else {
return cli.NewExitError(color.RedString("Unable to retrieve datacenter."), 1)
}
}
if !c.IsSet("json") {
fmt.Println("Querying status")
}
var objStatus interface{}
if c.IsSet("datacenter") {
if !c.IsSet("json") {
akamai.StartSpinner("Collecting DC status ", "")
}
objStatus, err = gatherDatacenterStatus()
} else if c.IsSet("property") {
if !c.IsSet("json") {
akamai.StartSpinner("Collecting Property status ", "")
}
objStatus, err = gatherPropertyStatus()
} else {
if !c.IsSet("json") {
akamai.StartSpinner("Collecting Domain status ", "")
}
objStatus, err = getDomainStatus()
}
// check for failure
if err != nil {
akamai.StopSpinnerFail()
if verboseStatus {
return cli.NewExitError(color.RedString("Unable to retrieve status. "+err.Error()), 1)
} else {
return cli.NewExitError(color.RedString("Unable to retrieve status."), 1)
}
}
if c.IsSet("json") && c.Bool("json") {
json, err := json.MarshalIndent(objStatus, "", " ")
if err != nil {
return cli.NewExitError(color.RedString("Unable to display status results"), 1)
}
fmt.Fprintln(c.App.Writer, string(json))
} else {
akamai.StopSpinnerOk()
fmt.Fprintln(c.App.Writer, "")
if c.IsSet("datacenter") {
fmt.Fprintln(c.App.Writer, renderDatacenterTable(objStatus.(*DCTrafficStati), c))
} else if c.IsSet("property") {
fmt.Fprintln(c.App.Writer, renderPropertyTable(objStatus.(*PropertyStatus), c))
} else {
fmt.Fprintln(c.App.Writer, renderDomainTable(objStatus.(*configgtm.ResponseStatus), c))
}
}
return nil
}
// Generate pretty print DC status
func renderDatacenterTable(objStatus *DCTrafficStati, c *cli.Context) string {
var outString string
outString += fmt.Sprintln("Domain: ", objStatus.Domain)
outString += fmt.Sprintln("Period Start: ", objStatus.PeriodStart)
outString += fmt.Sprintln("Period End: ", objStatus.PeriodEnd)
outString += fmt.Sprintln(" ")
tableString := &strings.Builder{}
table := tablewriter.NewWriter(tableString)
table.SetHeader([]string{"Datacenter", "Nickname", "Timestamp", "Property", "Enabled", "Requests", "Status"})
table.SetReflowDuringAutoWrap(false)
table.SetCenterSeparator(" ")
table.SetColumnSeparator(" ")
table.SetRowSeparator(" ")
table.SetBorder(false)
table.SetAutoWrapText(false)
table.SetColumnAlignment([]int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER})
table.SetAlignment(tablewriter.ALIGN_CENTER)
dclid := " "
dcln := " "
dcptl := " "
if len(objStatus.StatusByDatacenter) == 0 {
rowData := []string{"No datacenter status available", " ", " ", " ", " ", " ", " "}
table.Append(rowData)
} else {
for _, dc := range objStatus.StatusByDatacenter {
for pk, dcprop := range dc.DCStatusByProperty {
for k, prop := range dcprop.Properties {
if k == 0 {
dcptl = dcprop.Timestamp
if pk == 0 {
dclid = strconv.Itoa(dc.DatacenterId)
dcln = dc.DatacenterNickname
} else {
dclid = " "
dcln = " "
}
} else {
dcptl = " "
dclid = " "
dcln = " "
}
rowData := []string{dclid, dcln,
dcptl, prop.Name, strconv.FormatBool(prop.Enabled), strconv.FormatInt(prop.Requests, 10), prop.Status}
table.Append(rowData)
}
}
}
}
table.Render()
outString += fmt.Sprintln(tableString.String())
return outString
}
func renderPropertyTable(objStatus *PropertyStatus, c *cli.Context) string {
var outString string
outString += fmt.Sprintln("Domain: ", objStatus.Domain)
outString += fmt.Sprintln("Property: ", objStatus.PropertyName)
outString += fmt.Sprintln("Period Start: ", objStatus.PeriodStart)
outString += fmt.Sprintln("Period End: ", objStatus.PeriodEnd)
outString += fmt.Sprintln(" ")
// Build Summary Table
tableString := &strings.Builder{}
table := tablewriter.NewWriter(tableString)
outString += fmt.Sprintln("Status Summary -- Last Update: ", objStatus.StatusSummary.LastUpdate, ", CutOff: ", objStatus.StatusSummary.CutOff)
outString += fmt.Sprintln(" ")
table.SetHeader([]string{"Datacenter", "Nickname", "Target Name", "Enabled", "Weight", "Total Requests", "Property Usage", "IP", "State"})
table.SetReflowDuringAutoWrap(false)
table.SetCenterSeparator(" ")
table.SetColumnSeparator(" ")
table.SetRowSeparator(" ")
table.SetBorder(false)
table.SetAutoWrapText(false)
table.SetColumnAlignment([]int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER})
table.SetAlignment(tablewriter.ALIGN_CENTER)
dclid := " "
dcln := " "
dctn := " "
dcptl := " "
dcptr := " "
dcpperc := " "
dcip := " "
dcenabled := " "
dcweight := " "
if len(objStatus.StatusSummary.PropertyDCStatus) == 0 {
rowData := []string{"No status summary data available", " ", " ", " ", " ", " ", " ", " ", " "}
table.Append(rowData)
} else {
for _, dc := range objStatus.StatusSummary.PropertyDCStatus {
dcln = dc.Nickname
dclid = strconv.Itoa(dc.DatacenterId)
dctn = dc.TrafficTargetName
dcpperc = dc.DCPropertyUsage
dcenabled = strconv.FormatBool(dc.DCEnabled)
dcweight = strconv.FormatFloat(dc.DCWeight, 'f', 1, 64)
dcptr = strconv.FormatInt(dc.DCTotalPeriodRequests, 10)
if len(dc.IPs) < 1 {
dc.IPs = []*reportsgtm.IpStatIp{&reportsgtm.IpStatIp{}}
}
for k, ip := range dc.IPs {
if k == 0 {
dcip = ip.Ip
} else {
dctn = " "
dclid = " "
dcln = " "
dcip = " "
dcpperc = " "
dcptr = " "
dcenabled = " "
dcweight = " "
}
rowData := []string{dclid, dcln, dctn, dcenabled, dcweight, dcptr, dcpperc, dcip, fmt.Sprintf("HandedOut: %s", strconv.FormatBool(ip.HandedOut))}
table.Append(rowData)
rowData = []string{"", "", "", "", "", "", " ", fmt.Sprintf("Score: %s", fmt.Sprintf("%.2f", ip.Score))}
table.Append(rowData)
rowData = []string{"", "", "", "", "", "", " ", fmt.Sprintf("Alive: %s", strconv.FormatBool(ip.Alive))}
table.Append(rowData)
}
}
}
table.Render()
outString += fmt.Sprintln(tableString.String())
// Build Datacenter Status table
outString += fmt.Sprintln(" ")
outString += fmt.Sprintln("Datacenter Status")
outString += fmt.Sprintln(" ")
tableString = &strings.Builder{}
dcTable := tablewriter.NewWriter(tableString)
dcTable.SetHeader([]string{"Timestamp", "Datacenter", "Nickname", "Requests", "Status"})
dcTable.SetReflowDuringAutoWrap(false)
dcTable.SetCenterSeparator(" ")
dcTable.SetColumnSeparator(" ")
dcTable.SetRowSeparator(" ")
dcTable.SetBorder(false)
dcTable.SetAutoWrapText(false)
dcTable.SetColumnAlignment([]int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER})
dcTable.SetAlignment(tablewriter.ALIGN_CENTER)
dclid = " "
dcln = " "
dcptl = " "
if len(objStatus.DatacenterIntervalStatus) == 0 {
rowData := []string{"No datacenter interval status available", " ", " ", " ", " "}
dcTable.Append(rowData)
} else {
for _, dcis := range objStatus.DatacenterIntervalStatus {
dcptl = dcis.Timestamp
for k, dc := range dcis.Datacenters {
if k == 0 {
dcptl = dcis.Timestamp
} else {
dcptl = " "
}
dcln = dc.Nickname
dclid = strconv.Itoa(dc.DatacenterId)
rowData := []string{dcptl, dclid, dcln, strconv.FormatInt(dc.Requests, 10), dc.Status}
dcTable.Append(rowData)
}
}
}
dcTable.Render()
outString += fmt.Sprintln(tableString.String())
return outString
}
// Pretty print output
func renderDomainTable(status *configgtm.ResponseStatus, c *cli.Context) string {
var outString string
outString += fmt.Sprintln(" ")
outString += fmt.Sprintln(fmt.Sprintf("Domain: %s", domainName))
outString += fmt.Sprintln("Current Status")
outString += fmt.Sprintln(" ")
tableString := &strings.Builder{}
table := tablewriter.NewWriter(tableString)
table.SetReflowDuringAutoWrap(false)
table.SetCenterSeparator(" ")
table.SetColumnSeparator(" ")
table.SetRowSeparator(" ")
table.SetBorder(false)
table.SetAutoWrapText(false)
table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT})
table.SetAlignment(tablewriter.ALIGN_CENTER)
// Build status table. Exclude Links.
rowData := []string{"ChangeId", status.ChangeId}
table.Append(rowData)
rowData = []string{"Message", status.Message}
table.Append(rowData)
rowData = []string{"Passing Validation", strconv.FormatBool(status.PassingValidation)}
table.Append(rowData)
rowData = []string{"Propagation Status", status.PropagationStatus}
table.Append(rowData)
rowData = []string{"Propagation Status Date", status.PropagationStatusDate}
table.Append(rowData)
table.Render()
outString += fmt.Sprintln(tableString.String())
return outString
}