deploy/eligible_instance_groups.go (96 lines of code) (raw):
// Copyright 2016 Netflix, 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 deploy
import (
"fmt"
"log"
"github.com/Netflix/chaosmonkey/v2"
"github.com/Netflix/chaosmonkey/v2/grp"
)
// EligibleInstanceGroups returns a slice of InstanceGroups that represent
// groups of instances that are eligible for termination.
//
// Note that this code does not check for violations of minimum time between
// terminations. Chaos Monkey checks that precondition immediately before
// termination, not when considering groups of eligible instances.
//
// The way instances are divided into group will depend on
// - the grouping configuration for the app (cluster, stack, app)
// - whether regions are independent
//
// The returned InstanceGroups are guaranteed to contain at least one instance
// each
//
// Preconditions:
// - app is enabled for Chaos Monkey
func (app *App) EligibleInstanceGroups(cfg chaosmonkey.AppConfig) []grp.InstanceGroup {
if !cfg.Enabled {
log.Fatalf("app %s unexpectedly disabled", app.Name())
}
grouping := cfg.Grouping
indep := cfg.RegionsAreIndependent
switch {
case grouping == chaosmonkey.App && indep:
return appIndep(app)
case grouping == chaosmonkey.App && !indep:
return appDep(app)
case grouping == chaosmonkey.Stack && indep:
return stackIndep(app)
case grouping == chaosmonkey.Stack && !indep:
return stackDep(app)
case grouping == chaosmonkey.Cluster && indep:
return clusterIndep(app)
case grouping == chaosmonkey.Cluster && !indep:
return clusterDep(app)
default:
panic(fmt.Sprintf("Unknown grouping: %d", grouping))
}
}
// appindep returns a list of groups grouped by (app, account, region)
func appIndep(app *App) []grp.InstanceGroup {
result := []grp.InstanceGroup{}
for _, account := range app.accounts {
for _, regionName := range account.RegionNames() {
result = append(result, grp.New(app.Name(), account.Name(), regionName, "", ""))
}
}
return result
}
// stackIndep returns a list of groups grouped by (app, account)
func appDep(app *App) []grp.InstanceGroup {
result := []grp.InstanceGroup{}
for _, account := range app.accounts {
result = append(result, grp.New(app.Name(), account.Name(), "", "", ""))
}
return result
}
// stackIndep returns a list of groups grouped by (app, account, stack, region)
func stackIndep(app *App) []grp.InstanceGroup {
type asr struct {
account string
stack string
region string
}
set := make(map[asr]bool)
for _, account := range app.Accounts() {
for _, cluster := range account.Clusters() {
stackName := cluster.StackName()
for _, regionName := range cluster.RegionNames() {
set[asr{account: account.Name(), stack: stackName, region: regionName}] = true
}
}
}
result := []grp.InstanceGroup{}
for x := range set {
result = append(result, grp.New(app.Name(), x.account, x.region, x.stack, ""))
}
return result
}
// stackDep returns a list of groups grouped by (app, account, stack)
func stackDep(app *App) []grp.InstanceGroup {
result := []grp.InstanceGroup{}
for _, account := range app.accounts {
for _, stackName := range account.StackNames() {
result = append(result, grp.New(app.Name(), account.Name(), "", stackName, ""))
}
}
return result
}
// clusterDep returns a list of groups grouped by (app, account, cluster, region)
func clusterIndep(app *App) []grp.InstanceGroup {
result := []grp.InstanceGroup{}
for _, account := range app.accounts {
for _, cluster := range account.Clusters() {
for _, regionName := range cluster.RegionNames() {
result = append(result, grp.New(app.Name(), account.Name(), regionName, "", cluster.Name()))
}
}
}
return result
}
// clusterDep returns a list of groups grouped by (app, account, cluster)
func clusterDep(app *App) []grp.InstanceGroup {
result := []grp.InstanceGroup{}
for _, account := range app.accounts {
for _, cluster := range account.Clusters() {
result = append(result, grp.New(app.Name(), account.Name(), "", "", cluster.Name()))
}
}
return result
}