// describeRackStacks uses credentials to describe CF service, app and rack stacks that belong to the rack name and region func describeRackStacks(rackName, distinctId string, CF *cloudformation.CloudFormation) (Stacks, error) { res, err := CF.DescribeStacks(&cloudformation.DescribeStacksInput{}) if err != nil { return Stacks{}, err } apps := []Stack{} rack := []Stack{} services := []Stack{} for _, stack := range res.Stacks { events := map[string]string{} outputs := map[string]string{} tags := map[string]string{} for _, output := range stack.Outputs { outputs[*output.OutputKey] = *output.OutputValue } for _, tag := range stack.Tags { tags[*tag.Key] = *tag.Value } name := tags["Name"] if name == "" { name = *stack.StackName } buckets := []string{} rres, err := CF.DescribeStackResources(&cloudformation.DescribeStackResourcesInput{ StackName: stack.StackId, }) if err != nil { return Stacks{}, err } for _, resource := range rres.StackResources { if *resource.ResourceType == "AWS::S3::Bucket" { if resource.PhysicalResourceId != nil { buckets = append(buckets, *resource.PhysicalResourceId) } } } eres, err := CF.DescribeStackEvents(&cloudformation.DescribeStackEventsInput{ StackName: stack.StackId, }) if err != nil { return Stacks{}, err } for _, event := range eres.StackEvents { if strings.HasSuffix(*event.ResourceStatus, "FAILED") { events[*event.LogicalResourceId] = *event.ResourceStatusReason } } s := Stack{ Name: name, StackName: *stack.StackName, Status: *stack.StackStatus, Type: tags["Type"], Buckets: buckets, Events: events, Outputs: outputs, } // collect stacks that are explicitly related to the rack if tags["Rack"] == rackName { switch tags["Type"] { case "app": apps = append(apps, s) case "service": services = append(services, s) } } // collect stack that is explicitly the rack if *stack.StackName == rackName && outputs["Dashboard"] != "" { rack = append(rack, s) } } return Stacks{ Apps: apps, Rack: rack, Services: services, }, nil }