Browse Source

Redo simulation code. Added Design and Level. Still need to do the simulation

pull/1/head
Stephanie Gredell 7 months ago
parent
commit
294e78c7e6
  1. 202
      internals/design/design.go
  2. 9
      internals/design/simulation.go
  3. 105
      internals/level/level.go

202
internals/design/design.go

@ -0,0 +1,202 @@
package simulation
import "encoding/json"
type Node struct {
ID string `json:"id"`
Type string `json:"type"`
Position Position `josn:"position"`
Props map[string]interface{} `json:"props"`
}
type Position struct {
X int `json:"x"`
Y int `json:"y"`
}
type Connection struct {
Source string `json:"source"`
Target string `json:"target"`
Label string `json:"label,omitempty"`
Direction string `json:"direction,omitempty"`
Protocol string `json:"protocol,omitempty"`
TLS bool `json:"tls,omitemity"`
Capacity int `json:"capacity,omitempty"`
}
type Design struct {
Nodes []Node `json:"nodes"`
Connections []Connection
}
type Cache struct {
Label string `json:"label"`
CacheTTL int `json:"cacheTTL"`
MaxEntries int `json:"maxEntries"`
EvictionPolicy string `json:"evictionPolicy"`
}
type CDN struct {
Label string `json:"label"`
TTL int `json:"ttl"`
GeoReplication string `json:"geoReplication"`
CachingStrategy string `json:"cachingStrategy"`
Compression string `json:"compression"`
HTTP2 string `json:"http2"`
}
type Database struct {
Label string `json:"label"`
Replication int `json:"replication"`
}
type DataPipeline struct {
Label string `json:"label"`
BatchSize int `json:"batchSize"`
Transformation string `json:"transformation"`
}
type LoadBalancer struct {
Label string `json:"label"`
Algorithm string `json:"algorithm"`
}
type MessageQueue struct {
Label string `json:"label"`
QueueCapacity int `json:"queueCapacity"`
RetentionSeconds int `json:"retentionSeconds"`
}
type Microservice struct {
Label string `json:"label"`
InstanceCount int `json:"instanceCount"`
CPU int `json:"cpu"`
RAMGb int `json:"ramGb"`
RPSCapacity int `json:"rpsCapacity"`
MonthlyUSD int `json:"monthlyUsd"`
ScalingStrategy string `json:"scalingStrategy"`
APIVersion string `json:"apiVersion"`
}
type Monitoring struct {
Label string `json:"label"`
Tool string `json:"tool"`
AlertMetric string `json:"alertMetric"` // e.g., "cpu", "latency"
ThresholdValue int `json:"thresholdValue"` // e.g., 80
ThresholdUnit string `json:"thresholdUnit"` // e.g., "percent", "ms"
}
type ThirdPartyService struct {
Label string `json:"label"`
Provider string `json:"provider"`
Latency int `json:"latency"`
}
type WebServer struct {
CPU int `json:"cpu"`
RamGb int `json:"ramGb"`
RPSCapacity int `json:"rpsCapacity"`
MonthlyCostUsd int `json:"monthlyCostUsd"`
}
func (n *Node) UnmarshalJSON(data []byte) error {
type Alias Node // avoid infinite recursion
aux := &struct {
Props json.RawMessage `json:"props"`
*Alias
}{
Alias: (*Alias)(n),
}
if err := json.Unmarshal(data, aux); err != nil {
return err
}
switch n.Type {
case "cache":
var p Cache
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "cdn":
var p CDN
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "database":
var p Database
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "data pipeline":
var p DataPipeline
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "loadBalancer":
var p LoadBalancer
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "messageQueue":
var p MessageQueue
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "microservice":
var p Microservice
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "monitoring/alerting":
var p Monitoring
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "third party service":
var p ThirdPartyService
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
case "webserver":
var p WebServer
if err := json.Unmarshal(aux.Props, &p); err != nil {
return err
}
n.Props = structToMap(p)
default:
var generic map[string]interface{}
if err := json.Unmarshal(aux.Props, &generic); err != nil {
return err
}
n.Props = generic
}
return nil
}
func structToMap(v interface{}) map[string]interface{} {
data, _ := json.Marshal(v)
var result map[string]interface{}
json.Unmarshal(data, &result)
return result
}

9
internals/simulation/simulation.go → internals/design/simulation.go

@ -56,15 +56,6 @@ type ComponentSpec struct {
DbReadReplica DbReadReplica DbReadReplica DbReadReplica
} }
type Design struct {
NumWebServerSmall int
NumWebServerMedium int
CacheType CacheType // Enum (see below)
CacheTTL string
NumDbReplicas int
PromotionDelaySeconds int
}
type FailureEvent struct { type FailureEvent struct {
Type string Type string
Time int Time int

105
internals/level/level.go

@ -0,0 +1,105 @@
package level
import (
"encoding/json"
"fmt"
"os"
)
type Level struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Difficulty Difficulty `json:"difficulty"`
TargetRPS int `json:"targetRps"`
DurationSec int `json:"durationSec"`
MaxMonthlyUSD int `json:"maxMonthlyUsd"`
MaxP95LatencyMs int `json:"maxP95LatencyMs"`
RequiredAvailabilityPct float64 `json:"requiredAvailabilityPct"`
MustInclude []string `json:"mustInclude,omitempty"`
MustNotInclude []string `json:"mustNotInclude,omitempty"`
EncouragedComponents []string `json:"encouragedComponents,omitempty"`
DiscouragedComponents []string `json:"discouragedComponents,omitempty"`
MinReplicas map[string]int `json:"minReplicas,omitempty"`
MaxLatencyPerNodeType map[string]int `json:"maxLatencyPerNodeType,omitempty"`
CustomValidators []string `json:"customValidators,omitempty"`
FailureEvents []FailureEvent `json:"failureEvents,omitempty"`
ScoringWeights map[string]float64 `json:"scoringWeights,omitempty"`
Hints []string `json:"hints,omitempty"`
}
type Difficulty string
const (
DifficultyEasy Difficulty = "easy"
DifficultyMedium Difficulty = "medium"
DifficultyHard Difficulty = "hard"
)
var Registry map[string]map[string]Level
type FailureEvent struct {
Type string `json:"type"`
TimeSec int `json:"timeSec"`
TargetID string `json:"targetId,omitempty"`
}
func LoadLevels(path string) ([]Level, error) {
file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("Error opening levels.json: %w", err)
}
defer file.Close()
var levels []Level
err = json.NewDecoder(file).Decode(&levels)
if err != nil {
return nil, fmt.Errorf("Error decoding levels.json: %w", err)
}
return levels, nil
}
func InitRegistry(levels []Level) {
Registry = make(map[string]map[string]Level)
for _, lvl := range levels {
// check if level already exists here
if _, ok := Registry[lvl.Name]; !ok {
Registry[lvl.Name] = make(map[string]Level)
}
// populate it
Registry[lvl.Name][string(lvl.Difficulty)] = lvl
}
}
func GetLevel(name string, difficulty Difficulty) (*Level, error) {
diffMap, ok := Registry[name]
if !ok {
return nil, fmt.Errorf("level name %s not found", name)
}
lvl, ok := diffMap[string(difficulty)]
if !ok {
return nil, fmt.Errorf("difficulty %s not available for level '%s'", difficulty, name)
}
return &lvl, nil
}
func (d *Difficulty) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
switch s {
case string(DifficultyEasy), string(DifficultyMedium), string(DifficultyHard):
*d = Difficulty(s)
return nil
default:
return fmt.Errorf("invalid difficulty: %q", s)
}
}
Loading…
Cancel
Save