in spinnaker/terminator.go [143:215]
func (s Spinnaker) OtherID(ins chaosmonkey.Instance) (otherID string, err error) {
url := s.instanceURL(ins.AccountName(), ins.RegionName(), ins.ID())
resp, err := s.client.Get(url)
if err != nil {
return "", errors.Wrap(err, fmt.Sprintf("get failed on %s", url))
}
defer func() {
if cerr := resp.Body.Close(); cerr != nil && err == nil {
err = errors.Wrap(cerr, fmt.Sprintf("failed to close response body from %s", url))
}
}()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", errors.Wrap(err, fmt.Sprintf("body read failed at %s", url))
}
// Example of response body:
/*
{
...
"health": [
{
"type": "Titus",
"healthClass": "platform",
"state": "Up"
},
{
"instanceId": "55fe33ab-5b66-450a-85f7-f3129806b87f",
"titusTaskId": "Titus-123456-worker-0-0",
...
}
],
}
*/
var fields struct {
Health []map[string]interface{} `json:"health"`
Error string `json:"error"`
}
err = json.Unmarshal(body, &fields)
if err != nil {
return "", errors.Wrap(err, fmt.Sprintf("json unmarshal failed, body: %s", body))
}
if resp.StatusCode != http.StatusOK {
if fields.Error == "" {
return "", fmt.Errorf("unexpected status code: %d. body: %s", resp.StatusCode, body)
}
return "", fmt.Errorf("unexpected status code: %d. error: %s", resp.StatusCode, fields.Error)
}
// In some cases, an instance may be missing health information.
// We just return a blank otherID in that case
if len(fields.Health) < 2 {
return "", nil
}
otherID, ok := fields.Health[1]["instanceId"].(string)
if !ok {
return "", nil
}
// If the instance id is the same, there is no alternate
if ins.ID() == otherID {
return "", nil
}
return otherID, nil
}