250 lines
6.7 KiB
Go
250 lines
6.7 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/testground/sdk-go/ptypes"
|
||
|
"github.com/testground/sdk-go/runtime"
|
||
|
)
|
||
|
|
||
|
type NodeType string
|
||
|
|
||
|
const (
|
||
|
NodeTypeHonest NodeType = "honest"
|
||
|
)
|
||
|
|
||
|
type TopicConfig struct {
|
||
|
Id string `json:"id"`
|
||
|
MessageRate ptypes.Rate `json:"message_rate"`
|
||
|
MessageSize ptypes.Size `json:"message_size"`
|
||
|
}
|
||
|
|
||
|
type HeartbeatParams struct {
|
||
|
InitialDelay time.Duration
|
||
|
Interval time.Duration
|
||
|
}
|
||
|
|
||
|
type NetworkParams struct {
|
||
|
latency time.Duration
|
||
|
latencyMax time.Duration
|
||
|
jitterPct int
|
||
|
bandwidthMB int
|
||
|
}
|
||
|
|
||
|
// ScoreParams is mapped to pubsub.PeerScoreParams when targeting the hardened_api pubsub branch
|
||
|
type ScoreParams struct {
|
||
|
Topics map[string]*TopicScoreParams
|
||
|
Thresholds PeerScoreThresholds
|
||
|
|
||
|
// TODO: figure out how to parameterize the app score function
|
||
|
|
||
|
IPColocationFactorWeight float64
|
||
|
IPColocationFactorThreshold int
|
||
|
|
||
|
DecayInterval ptypes.Duration
|
||
|
DecayToZero float64
|
||
|
RetainScore ptypes.Duration
|
||
|
}
|
||
|
|
||
|
type OverlayParams struct {
|
||
|
d int
|
||
|
dlo int
|
||
|
dhi int
|
||
|
dscore int
|
||
|
dlazy int
|
||
|
gossipFactor float64
|
||
|
}
|
||
|
|
||
|
type PeerScoreThresholds struct {
|
||
|
GossipThreshold float64
|
||
|
PublishThreshold float64
|
||
|
GraylistThreshold float64
|
||
|
AcceptPXThreshold float64
|
||
|
OpportunisticGraftThreshold float64
|
||
|
}
|
||
|
|
||
|
// TopicScoreParams is mapped to pubsub.TopicScoreParams when targeting the hardened_api pubsub branch
|
||
|
type TopicScoreParams struct {
|
||
|
TopicWeight float64
|
||
|
|
||
|
TimeInMeshWeight float64
|
||
|
TimeInMeshQuantum ptypes.Duration
|
||
|
TimeInMeshCap float64
|
||
|
|
||
|
FirstMessageDeliveriesWeight float64
|
||
|
FirstMessageDeliveriesDecay float64
|
||
|
FirstMessageDeliveriesCap float64
|
||
|
|
||
|
MeshMessageDeliveriesWeight, MeshMessageDeliveriesDecay float64
|
||
|
MeshMessageDeliveriesCap, MeshMessageDeliveriesThreshold float64
|
||
|
MeshMessageDeliveriesWindow, MeshMessageDeliveriesActivation ptypes.Duration
|
||
|
|
||
|
MeshFailurePenaltyWeight, MeshFailurePenaltyDecay float64
|
||
|
|
||
|
InvalidMessageDeliveriesWeight, InvalidMessageDeliveriesDecay float64
|
||
|
}
|
||
|
|
||
|
|
||
|
type testParams struct {
|
||
|
heartbeat HeartbeatParams
|
||
|
setup time.Duration
|
||
|
warmup time.Duration
|
||
|
runtime time.Duration
|
||
|
cooldown time.Duration
|
||
|
|
||
|
nodeType NodeType
|
||
|
publisher bool
|
||
|
floodPublishing bool
|
||
|
fullTraces bool
|
||
|
topics []TopicConfig
|
||
|
degree int
|
||
|
|
||
|
containerNodesTotal int
|
||
|
nodesPerContainer int
|
||
|
|
||
|
connectDelays []time.Duration
|
||
|
connectDelayJitterPct int
|
||
|
connsDef map[string]*ConnectionsDef
|
||
|
connectToPublishersOnly bool
|
||
|
|
||
|
netParams NetworkParams
|
||
|
overlayParams OverlayParams
|
||
|
scoreParams ScoreParams
|
||
|
scoreInspectPeriod time.Duration
|
||
|
validateQueueSize int
|
||
|
outboundQueueSize int
|
||
|
|
||
|
opportunisticGraftTicks int
|
||
|
}
|
||
|
|
||
|
func durationParam(runenv *runtime.RunEnv, name string) time.Duration {
|
||
|
if !runenv.IsParamSet(name) {
|
||
|
runenv.RecordMessage("duration param %s not set, defaulting to zero", name)
|
||
|
return 0
|
||
|
}
|
||
|
return parseDuration(runenv.StringParam(name))
|
||
|
}
|
||
|
|
||
|
func parseDuration(val string) time.Duration {
|
||
|
d, err := time.ParseDuration(val)
|
||
|
if err != nil {
|
||
|
panic(fmt.Errorf("param %s is not a valid duration: %s", val, err))
|
||
|
}
|
||
|
return d
|
||
|
}
|
||
|
|
||
|
func parseParams(runenv *runtime.RunEnv) testParams {
|
||
|
np := NetworkParams{
|
||
|
latency: durationParam(runenv, "t_latency"),
|
||
|
latencyMax: durationParam(runenv, "t_latency_max"),
|
||
|
jitterPct: runenv.IntParam("jitter_pct"),
|
||
|
bandwidthMB: runenv.IntParam("bandwidth_mb"),
|
||
|
}
|
||
|
|
||
|
op := OverlayParams{
|
||
|
d: runenv.IntParam("overlay_d"),
|
||
|
dlo: runenv.IntParam("overlay_dlo"),
|
||
|
dhi: runenv.IntParam("overlay_dhi"),
|
||
|
dscore: runenv.IntParam("overlay_dscore"),
|
||
|
dlazy: runenv.IntParam("overlay_dlazy"),
|
||
|
gossipFactor: runenv.FloatParam("gossip_factor"),
|
||
|
}
|
||
|
|
||
|
p := testParams{
|
||
|
heartbeat: HeartbeatParams{
|
||
|
InitialDelay: durationParam(runenv, "t_heartbeat_initial_delay"),
|
||
|
Interval: durationParam(runenv, "t_heartbeat"),
|
||
|
},
|
||
|
setup: durationParam(runenv, "t_setup"),
|
||
|
warmup: durationParam(runenv, "t_warm"),
|
||
|
runtime: durationParam(runenv, "t_run"),
|
||
|
cooldown: durationParam(runenv, "t_cool"),
|
||
|
publisher: runenv.BooleanParam("publisher"),
|
||
|
floodPublishing: runenv.BooleanParam("flood_publishing"),
|
||
|
fullTraces: runenv.BooleanParam("full_traces"),
|
||
|
nodeType: NodeTypeHonest,
|
||
|
connectToPublishersOnly: runenv.BooleanParam("connect_to_publishers_only"),
|
||
|
degree: runenv.IntParam("degree"),
|
||
|
containerNodesTotal: runenv.IntParam("n_container_nodes_total"),
|
||
|
nodesPerContainer: runenv.IntParam("n_nodes_per_container"),
|
||
|
scoreInspectPeriod: durationParam(runenv, "t_score_inspect_period"),
|
||
|
netParams: np,
|
||
|
overlayParams: op,
|
||
|
validateQueueSize: runenv.IntParam("validate_queue_size"),
|
||
|
outboundQueueSize: runenv.IntParam("outbound_queue_size"),
|
||
|
opportunisticGraftTicks: runenv.IntParam("opportunistic_graft_ticks"),
|
||
|
}
|
||
|
|
||
|
if runenv.IsParamSet("topics") {
|
||
|
jsonstr := runenv.StringParam("topics")
|
||
|
err := json.Unmarshal([]byte(jsonstr), &p.topics)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
runenv.RecordMessage("topics: %v", p.topics)
|
||
|
}
|
||
|
|
||
|
if runenv.IsParamSet("score_params") {
|
||
|
jsonstr := runenv.StringParam("score_params")
|
||
|
err := json.Unmarshal([]byte(jsonstr), &p.scoreParams)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
// add warmup time to the mesh delivery activation window for each topic
|
||
|
for _, topic := range p.scoreParams.Topics {
|
||
|
topic.MeshMessageDeliveriesActivation.Duration += p.warmup
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if runenv.IsParamSet("topology") {
|
||
|
jsonstr := runenv.StringParam("topology")
|
||
|
err := json.Unmarshal([]byte(jsonstr), &p.connsDef)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if runenv.IsParamSet("connect_delays") {
|
||
|
// eg: "5@10s,15@1m,5@2m"
|
||
|
connDelays := runenv.StringParam("connect_delays")
|
||
|
if connDelays != "" && connDelays != "\"\"" {
|
||
|
cds := strings.Split(connDelays, ",")
|
||
|
for _, cd := range cds {
|
||
|
parts := strings.Split(cd, "@")
|
||
|
if len(parts) != 2 {
|
||
|
panic(fmt.Sprintf("Badly formatted connect_delays param %s", connDelays))
|
||
|
}
|
||
|
count, err := strconv.Atoi(parts[0])
|
||
|
if err != nil {
|
||
|
panic(fmt.Sprintf("Badly formatted connect_delays param %s", connDelays))
|
||
|
}
|
||
|
|
||
|
dur := parseDuration(parts[1])
|
||
|
for i := 0; i < count; i++ {
|
||
|
p.connectDelays = append(p.connectDelays, dur)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p.connectDelayJitterPct = 5
|
||
|
if runenv.IsParamSet("connect_delay_jitter_pct") {
|
||
|
p.connectDelayJitterPct = runenv.IntParam("connect_delay_jitter_pct")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return p
|
||
|
}
|
||
|
|
||
|
func parseNodeType(nt string) NodeType {
|
||
|
switch nt {
|
||
|
// currently only honest nodes are supported
|
||
|
default:
|
||
|
return NodeTypeHonest
|
||
|
}
|
||
|
}
|