Skip to content

Commit

Permalink
Add /api/v2/jim endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ian-kent committed Jan 4, 2015
1 parent cd3c7a5 commit 1094ce8
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 31 deletions.
95 changes: 92 additions & 3 deletions api/v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
gotcha "github.com/ian-kent/gotcha/app"
"github.com/ian-kent/gotcha/http"
"github.com/mailhog/MailHog-Server/config"
"github.com/mailhog/MailHog-Server/monkey"
"github.com/mailhog/data"

"github.com/ian-kent/goose"
Expand Down Expand Up @@ -38,6 +39,12 @@ func CreateAPIv2(conf *config.Config, app *gotcha.App) *APIv2 {
r.Get("/api/v2/search/?", apiv2.search)
r.Options("/api/v2/search/?", apiv2.defaultOptions)

r.Get("/api/v2/jim/?", apiv2.jim)
r.Post("/api/v2/jim/?", apiv2.createJim)
r.Put("/api/v2/jim/?", apiv2.updateJim)
r.Delete("/api/v2/jim/?", apiv2.deleteJim)
r.Options("/api/v2/jim/?", apiv2.defaultOptions)

return apiv2
}

Expand Down Expand Up @@ -125,7 +132,89 @@ func (apiv2 *APIv2) search(session *http.Session) {
res.Items = []data.Message(*messages)
res.Total = total

bytes, _ := json.Marshal(res)
session.Response.Headers.Add("Content-Type", "text/json")
session.Response.Write(bytes)
b, _ := json.Marshal(res)
session.Response.Headers.Add("Content-Type", "application/json")
session.Response.Write(b)
}

func (apiv2 *APIv2) jim(session *http.Session) {
log.Println("[APIv2] GET /jim")

apiv2.defaultOptions(session)

if apiv2.config.Monkey == nil {
session.Response.Status = 404
return
}

b, _ := json.Marshal(apiv2.config.Monkey)
session.Response.Headers.Add("Content-Type", "application/json")
session.Response.Write(b)
}

func (apiv2 *APIv2) deleteJim(session *http.Session) {
log.Println("[APIv2] DELETE /jim")

apiv2.defaultOptions(session)

if apiv2.config.Monkey == nil {
session.Response.Status = 404
return
}

apiv2.config.Monkey = nil
}

func (apiv2 *APIv2) createJim(session *http.Session) {
log.Println("[APIv2] POST /jim")

apiv2.defaultOptions(session)

if apiv2.config.Monkey != nil {
session.Response.Status = 400
return
}

apiv2.config.Monkey = config.Jim

// Try, but ignore errors
// Could be better (e.g., ok if no json, error if badly formed json)
// but this works for now
apiv2.newJimFromBody(session)

session.Response.Status = 201
}

func (apiv2 *APIv2) newJimFromBody(session *http.Session) error {
var jim monkey.Jim

dec := json.NewDecoder(session.Request.Body())
err := dec.Decode(&jim)

if err != nil {
return err
}

jim.ConfigureFrom(config.Jim)

config.Jim = &jim
apiv2.config.Monkey = &jim

return nil
}

func (apiv2 *APIv2) updateJim(session *http.Session) {
log.Println("[APIv2] PUT /jim")

apiv2.defaultOptions(session)

if apiv2.config.Monkey == nil {
session.Response.Status = 404
return
}

err := apiv2.newJimFromBody(session)
if err != nil {
session.Response.Status = 400
}
}
8 changes: 4 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type Config struct {
}

var cfg = DefaultConfig()
var jim = &monkey.Jim{}
var Jim = &monkey.Jim{}

func Configure() *Config {
switch cfg.StorageType {
Expand All @@ -63,10 +63,10 @@ func Configure() *Config {
}

if cfg.InviteJim {
jim.Configure(func(message string, args ...interface{}) {
Jim.Configure(func(message string, args ...interface{}) {
log.Printf(message, args...)
})
cfg.Monkey = jim
cfg.Monkey = Jim
}

return cfg
Expand All @@ -82,5 +82,5 @@ func RegisterFlags() {
flag.StringVar(&cfg.MongoColl, "mongo-coll", envconf.FromEnvP("MH_MONGO_COLLECTION", "messages").(string), "MongoDB collection, e.g. messages")
flag.StringVar(&cfg.CORSOrigin, "cors-origin", envconf.FromEnvP("MH_CORS_ORIGIN", "").(string), "CORS Access-Control-Allow-Origin header for API endpoints")
flag.BoolVar(&cfg.InviteJim, "invite-jim", envconf.FromEnvP("MH_INVITE_JIM", false).(bool), "Decide whether to invite Jim (beware, he causes trouble)")
jim.RegisterFlags()
Jim.RegisterFlags()
}
54 changes: 30 additions & 24 deletions monkey/jim.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ import (

// Jim is a chaos monkey
type Jim struct {
disconnectChance float64
acceptChance float64
linkSpeedAffect float64
linkSpeedMin float64
linkSpeedMax float64
rejectSenderChance float64
rejectRecipientChance float64
rejectAuthChance float64
DisconnectChance float64
AcceptChance float64
LinkSpeedAffect float64
LinkSpeedMin float64
LinkSpeedMax float64
RejectSenderChance float64
RejectRecipientChance float64
RejectAuthChance float64
logf func(message string, args ...interface{})
}

// RegisterFlags implements ChaosMonkey.RegisterFlags
func (j *Jim) RegisterFlags() {
flag.Float64Var(&j.disconnectChance, "jim-disconnect", 0.005, "Chance of disconnect")
flag.Float64Var(&j.acceptChance, "jim-accept", 0.99, "Chance of accept")
flag.Float64Var(&j.linkSpeedAffect, "jim-linkspeed-affect", 0.1, "Chance of affecting link speed")
flag.Float64Var(&j.linkSpeedMin, "jim-linkspeed-min", 1024, "Minimum link speed (in bytes per second)")
flag.Float64Var(&j.linkSpeedMax, "jim-linkspeed-max", 10240, "Maximum link speed (in bytes per second)")
flag.Float64Var(&j.rejectSenderChance, "jim-reject-sender", 0.05, "Chance of rejecting a sender (MAIL FROM)")
flag.Float64Var(&j.rejectRecipientChance, "jim-reject-recipient", 0.05, "Chance of rejecting a recipient (RCPT TO)")
flag.Float64Var(&j.rejectAuthChance, "jim-reject-auth", 0.05, "Chance of rejecting authentication (AUTH)")
flag.Float64Var(&j.DisconnectChance, "jim-disconnect", 0.005, "Chance of disconnect")
flag.Float64Var(&j.AcceptChance, "jim-accept", 0.99, "Chance of accept")
flag.Float64Var(&j.LinkSpeedAffect, "jim-linkspeed-affect", 0.1, "Chance of affecting link speed")
flag.Float64Var(&j.LinkSpeedMin, "jim-linkspeed-min", 1024, "Minimum link speed (in bytes per second)")
flag.Float64Var(&j.LinkSpeedMax, "jim-linkspeed-max", 10240, "Maximum link speed (in bytes per second)")
flag.Float64Var(&j.RejectSenderChance, "jim-reject-sender", 0.05, "Chance of rejecting a sender (MAIL FROM)")
flag.Float64Var(&j.RejectRecipientChance, "jim-reject-recipient", 0.05, "Chance of rejecting a recipient (RCPT TO)")
flag.Float64Var(&j.RejectAuthChance, "jim-reject-auth", 0.05, "Chance of rejecting authentication (AUTH)")
}

// Configure implements ChaosMonkey.Configure
Expand All @@ -40,9 +40,15 @@ func (j *Jim) Configure(logf func(string, ...interface{})) {
rand.Seed(time.Now().Unix())
}

// ConfigureFrom lets us configure a new Jim from an old one without
// having to expose logf (and any other future private vars)
func (j *Jim) ConfigureFrom(j2 *Jim) {
j.Configure(j2.logf)
}

// Accept implements ChaosMonkey.Accept
func (j *Jim) Accept(conn net.Conn) bool {
if rand.Float64() > j.acceptChance {
if rand.Float64() > j.AcceptChance {
j.logf("Jim: Rejecting connection\n")
return false
}
Expand All @@ -53,9 +59,9 @@ func (j *Jim) Accept(conn net.Conn) bool {
// LinkSpeed implements ChaosMonkey.LinkSpeed
func (j *Jim) LinkSpeed() *linkio.Throughput {
rand.Seed(time.Now().Unix())
if rand.Float64() < j.linkSpeedAffect {
lsDiff := j.linkSpeedMax - j.linkSpeedMin
lsAffect := j.linkSpeedMin + (lsDiff * rand.Float64())
if rand.Float64() < j.LinkSpeedAffect {
lsDiff := j.LinkSpeedMax - j.LinkSpeedMin
lsAffect := j.LinkSpeedMin + (lsDiff * rand.Float64())
f := linkio.Throughput(lsAffect) * linkio.BytePerSecond
j.logf("Jim: Restricting throughput to %s\n", f)
return &f
Expand All @@ -66,7 +72,7 @@ func (j *Jim) LinkSpeed() *linkio.Throughput {

// ValidRCPT implements ChaosMonkey.ValidRCPT
func (j *Jim) ValidRCPT(rcpt string) bool {
if rand.Float64() < j.rejectRecipientChance {
if rand.Float64() < j.RejectRecipientChance {
j.logf("Jim: Rejecting recipient %s\n", rcpt)
return false
}
Expand All @@ -76,7 +82,7 @@ func (j *Jim) ValidRCPT(rcpt string) bool {

// ValidMAIL implements ChaosMonkey.ValidMAIL
func (j *Jim) ValidMAIL(mail string) bool {
if rand.Float64() < j.rejectSenderChance {
if rand.Float64() < j.RejectSenderChance {
j.logf("Jim: Rejecting sender %s\n", mail)
return false
}
Expand All @@ -86,7 +92,7 @@ func (j *Jim) ValidMAIL(mail string) bool {

// ValidAUTH implements ChaosMonkey.ValidAUTH
func (j *Jim) ValidAUTH(mechanism string, args ...string) bool {
if rand.Float64() < j.rejectAuthChance {
if rand.Float64() < j.RejectAuthChance {
j.logf("Jim: Rejecting authentication %s: %s\n", mechanism, args)
return false
}
Expand All @@ -96,7 +102,7 @@ func (j *Jim) ValidAUTH(mechanism string, args ...string) bool {

// Disconnect implements ChaosMonkey.Disconnect
func (j *Jim) Disconnect() bool {
if rand.Float64() < j.disconnectChance {
if rand.Float64() < j.DisconnectChance {
j.logf("Jim: Being nasty, kicking them off\n")
return true
}
Expand Down

0 comments on commit 1094ce8

Please sign in to comment.