deploy/deployment.go (133 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 contains information about all of the deployed instances, and how
// they are organized across accounts, apps, regions, clusters, and autoscaling
// groups.
package deploy
import (
"fmt"
"github.com/SmartThingsOSS/frigga-go"
)
// Deployment contains information about how apps are deployed
type Deployment interface {
// Apps sends App objects over a channel
Apps(c chan<- *App, appNames []string)
// GetApp retrieves a single App
GetApp(name string) (*App, error)
// AppNames returns the names of all apps
AppNames() ([]string, error)
// GetInstanceIDs returns the ids for instances in a cluster
GetInstanceIDs(app string, account AccountName, cloudProvider string, region RegionName, cluster ClusterName) (asgName ASGName, instances []InstanceID, err error)
// GetClusterNames returns the list of cluster names
GetClusterNames(app string, account AccountName) ([]ClusterName, error)
// GetRegionNames returns the list of regions associated with a cluster
GetRegionNames(app string, account AccountName, cluster ClusterName) ([]RegionName, error)
// CloudProvider returns the provider associated with an account
CloudProvider(account string) (provider string, err error)
}
// Account represents the set of clusters associated with an App that reside
// in one AWS account (e.g., "prod", "test").
type Account struct {
name string // e.g., "prod", "test"
clusters []*Cluster
app *App
cloudProvider string // e.g., "aws"
}
// Name returns the name of the account associated with this account
func (a *Account) Name() string {
return a.name
}
// Clusters returns a slice of clusters
func (a *Account) Clusters() []*Cluster {
return a.clusters
}
// AppName returns the name of the app associated with this Account
func (a *Account) AppName() string {
return a.app.name
}
// RegionNames returns the name of the regions that clusters in this account are
// running in
func (a *Account) RegionNames() []string {
m := make(map[string]bool)
// Get the region names of the clusters
for _, cluster := range a.Clusters() {
for _, name := range cluster.RegionNames() {
m[name] = true
}
}
result := make([]string, 0, len(m))
for name := range m {
result = append(result, name)
}
return result
}
// CloudProvider returns the cloud provider (e.g., "aws")
func (a *Account) CloudProvider() string {
return a.cloudProvider
}
type stringSet map[string]bool
func (s *stringSet) add(val string) {
(*s)[val] = true
}
// slice converts a stringSet to a string slice
func (s stringSet) slice() []string {
result := []string{}
for val := range s {
result = append(result, val)
}
return result
}
// StackNames returns the names of the stacks associated with this account
func (a *Account) StackNames() []string {
stacks := make(stringSet)
for _, cluster := range a.Clusters() {
stacks.add(cluster.StackName())
}
return stacks.slice()
}
// Cluster represents what Spinnaker refers to as a "cluster", which
// contains app-stack-detail.
// Every ASG is associated with exactly one cluster.
// Note that clusters can span regions
type Cluster struct {
name string
asgs []*ASG
account *Account
}
// Name returns the name of the cluster, convention: app-stack-detail
func (c *Cluster) Name() string {
return c.name
}
// AppName returns the name of the app associated with this cluster
func (c *Cluster) AppName() string {
return c.account.AppName()
}
// StackName returns the name of the stack, following the app-stack-detail convention
func (c *Cluster) StackName() string {
names, err := frigga.Parse(c.Name())
if err != nil {
panic(err)
}
return names.Stack
}
// AccountName returns the name of the account associated with this cluster
func (c *Cluster) AccountName() string {
return c.account.Name()
}
// ASGs returns a slice of ASGs
func (c *Cluster) ASGs() []*ASG {
return c.asgs
}
// RegionNames returns the name of the region that this cluster runs in
func (c *Cluster) RegionNames() []string {
m := make(map[string]bool)
for _, asg := range c.ASGs() {
m[asg.RegionName()] = true
}
result := []string{}
for name := range m {
result = append(result, name)
}
return result
}
// CloudProvider returns the cloud provider (e.g., "aws")
func (c *Cluster) CloudProvider() string {
return c.account.CloudProvider()
}
// Instance implements instance.Instance
type Instance struct {
// instance id (e.g., "i-74e93ddb")
id string
// ASG that this instance is part of
asg *ASG
}
func (i *Instance) String() string {
return fmt.Sprintf("app=%s account=%s region=%s stack=%s cluster=%s asg=%s instance-id=%s",
i.AppName(), i.AccountName(), i.RegionName(), i.StackName(), i.ClusterName(), i.ASGName(), i.ID())
}
// AppName returns the name of the app associated with this instance
func (i *Instance) AppName() string {
return i.asg.AppName()
}
// AccountName returns the name of the AWS account associated with the instance
func (i *Instance) AccountName() string {
return i.asg.AccountName()
}
// ClusterName returns the name of the cluster associated with the instance
func (i *Instance) ClusterName() string {
return i.asg.ClusterName()
}
// RegionName returns the name of the region associated with the instance
func (i *Instance) RegionName() string {
return i.asg.RegionName()
}
// ASGName returns the name of the ASG associated with the instance
func (i *Instance) ASGName() string {
return i.asg.Name()
}
// StackName returns the name of the stack associated with the instance
func (i *Instance) StackName() string {
return i.asg.StackName()
}
// CloudProvider returns the cloud provider (e.g., "aws")
func (i *Instance) CloudProvider() string {
return i.asg.CloudProvider()
}
// ID returns the instance id
func (i *Instance) ID() string {
return i.id
}