From 179295386280c715dfbe552b24b794cd77fc8e26 Mon Sep 17 00:00:00 2001 From: Andrea Ceccato Date: Wed, 18 Oct 2023 11:48:35 +0200 Subject: [PATCH 1/2] create list command --- cmd/list.go | 60 +++++++++++++++++++++++++++++++++++++++ main.go | 19 +++++++++++++ service/asg/selector.go | 10 +++++++ service/ecs/selector.go | 10 +++++++ service/elbv2/selector.go | 10 +++++++ service/types.go | 25 ++++++++++++++++ 6 files changed, 134 insertions(+) create mode 100644 cmd/list.go diff --git a/cmd/list.go b/cmd/list.go new file mode 100644 index 0000000..8266926 --- /dev/null +++ b/cmd/list.go @@ -0,0 +1,60 @@ +package cmd + +import ( + "fmt" + "log" + + "github.com/mcastellin/aws-fail-az/awsapis" + "github.com/mcastellin/aws-fail-az/service" + "github.com/mcastellin/aws-fail-az/state" +) + +type ListCommand struct { + Provider awsapis.AWSProvider + Namespace string +} + +type AutoScalingGroupState struct { + AutoScalingGroupName string `json:"asgName"` + Subnets []string `json:"subnets"` +} + +func (cmd *ListCommand) Run() error { + stateManager, err := state.NewStateManager(cmd.Provider, cmd.Namespace) + if err != nil { + log.Print("Failed to create AWS state manager") + return err + } + + if err := stateManager.Initialize(); err != nil { + return err + } + + states, err := stateManager.QueryStates(&state.QueryStatesInput{}) + if err != nil { + return err + } + + ns := cmd.Namespace + if len(ns) == 0 { + ns = "default" + } + + if len(states) == 0 { + fmt.Printf("No attacked resources found for namespace '%s':\n", ns) + return nil + } + + fmt.Printf("Attacked resources for namespace '%s':\n", ns) + faultTypes := service.InitServiceFaults() + for _, s := range states { + description, err := faultTypes.DescribeState(s) + if err != nil { + log.Println(err) + } else { + fmt.Println(description) + } + } + + return nil +} diff --git a/main.go b/main.go index 43b8478..4cded09 100644 --- a/main.go +++ b/main.go @@ -129,6 +129,22 @@ var stateDeleteCmd = &cobra.Command{ }, } +var listCmd = &cobra.Command{ + Use: "list", + Short: "List all the attacked resources", + RunE: func(_ *cobra.Command, args []string) error { + provider, err := createProvider() + if err != nil { + return err + } + op := &cmd.ListCommand{ + Provider: provider, + Namespace: namespace, + } + return op.Run() + }, +} + var versionCmd = &cobra.Command{ Use: "version", Short: "Print the command version", @@ -175,6 +191,8 @@ func main() { stateDeleteCmd.MarkFlagRequired("type") stateDeleteCmd.MarkFlagRequired("key") + listCmd.Flags().StringVar(&namespace, "ns", "", "The namespace assigned to this operation. Used to uniquely identify resources state for recovery.") + rootCmd.PersistentFlags().StringVar(&awsRegion, "region", "", "The AWS region") rootCmd.PersistentFlags().StringVar(&awsProfile, "profile", "", "The AWS profile") rootCmd.AddCommand(failCmd) @@ -183,6 +201,7 @@ func main() { rootCmd.AddCommand(stateSaveCmd) rootCmd.AddCommand(stateReadCmd) rootCmd.AddCommand(stateDeleteCmd) + rootCmd.AddCommand(listCmd) rootCmd.SilenceUsage = true rootCmd.SilenceErrors = true diff --git a/service/asg/selector.go b/service/asg/selector.go index 9a71652..3ece3b5 100644 --- a/service/asg/selector.go +++ b/service/asg/selector.go @@ -11,6 +11,16 @@ import ( "github.com/mcastellin/aws-fail-az/service/awsutils" ) +func DescribeAutoScalingGroupsState(stateData []byte) (string, error) { + var state AutoScalingGroupState + err := json.Unmarshal(stateData, &state) + if err != nil { + return "", err + } + + return fmt.Sprintf("- AutoScalingGroupName: %s", state.AutoScalingGroupName), nil +} + func RestoreAutoScalingGroupsFromState(stateData []byte, provider awsapis.AWSProvider) error { var state AutoScalingGroupState err := json.Unmarshal(stateData, &state) diff --git a/service/ecs/selector.go b/service/ecs/selector.go index dab2013..00b2f44 100644 --- a/service/ecs/selector.go +++ b/service/ecs/selector.go @@ -12,6 +12,16 @@ import ( "github.com/mcastellin/aws-fail-az/service/awsutils" ) +func DescribeEcsServicesState(stateData []byte) (string, error) { + var state ECSServiceState + err := json.Unmarshal(stateData, &state) + if err != nil { + return "", err + } + + return fmt.Sprintf("- Cluster: %s\n ServiceName: %s", state.ClusterArn, state.ServiceName), nil +} + func RestoreEcsServicesFromState(stateData []byte, provider awsapis.AWSProvider) error { var state ECSServiceState err := json.Unmarshal(stateData, &state) diff --git a/service/elbv2/selector.go b/service/elbv2/selector.go index adbbb33..cc80821 100644 --- a/service/elbv2/selector.go +++ b/service/elbv2/selector.go @@ -12,6 +12,16 @@ import ( "github.com/mcastellin/aws-fail-az/service/awsutils" ) +func DescribeElbv2LoadBalancersState(stateData []byte) (string, error) { + var state LoadBalancerState + err := json.Unmarshal(stateData, &state) + if err != nil { + return "", err + } + + return fmt.Sprintf("- LoadBalancerName: %s", state.LoadBalancerName), nil +} + func RestoreElbv2LoadBalancersFromState(stateData []byte, provider awsapis.AWSProvider) error { var state LoadBalancerState err := json.Unmarshal(stateData, &state) diff --git a/service/types.go b/service/types.go index ec5b8b2..a500616 100644 --- a/service/types.go +++ b/service/types.go @@ -32,6 +32,14 @@ func InitServiceFaults() *FaultsInitFns { domain.ResourceTypeAutoScalingGroup: asg.RestoreAutoScalingGroupsFromState, domain.ResourceTypeElbv2LoadBalancer: elbv2.RestoreElbv2LoadBalancersFromState, }, + + describe: map[string]func([]byte) (string, error){ + // Register describe state functions for new fault types in this structure + + domain.ResourceTypeEcsService: ecs.DescribeEcsServicesState, + domain.ResourceTypeAutoScalingGroup: asg.DescribeAutoScalingGroupsState, + domain.ResourceTypeElbv2LoadBalancer: elbv2.DescribeElbv2LoadBalancersState, + }, } return initFns } @@ -44,6 +52,9 @@ type FaultsInitFns struct { // A map of all available fault types and their restore functions restore map[string]func([]byte, awsapis.AWSProvider) error + + // A map of all available fault types and their describe functions + describe map[string]func([]byte) (string, error) } // Initialize new resource faults from their selector @@ -72,3 +83,17 @@ func (obj *FaultsInitFns) RestoreFromState(state state.ResourceState, provider a ) return err } + +// Call the specific DescribeState function for the resource type specified in the state object +func (obj *FaultsInitFns) DescribeState(state state.ResourceState) (string, error) { + describeFn, ok := obj.describe[state.ResourceType] + if ok { + return describeFn(state.State) + } + + err := fmt.Errorf("unknown resource of type %s found in state with key %s. Object will be ignored", + state.ResourceType, + state.Key, + ) + return "", err +} From e8d39001c539363366d282ca580ca0fa0b05f757 Mon Sep 17 00:00:00 2001 From: Andrea Ceccato Date: Fri, 20 Oct 2023 09:21:27 +0200 Subject: [PATCH 2/2] add Resource Type to description --- service/asg/selector.go | 2 +- service/ecs/selector.go | 2 +- service/elbv2/selector.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/service/asg/selector.go b/service/asg/selector.go index 3ece3b5..77ab5bb 100644 --- a/service/asg/selector.go +++ b/service/asg/selector.go @@ -18,7 +18,7 @@ func DescribeAutoScalingGroupsState(stateData []byte) (string, error) { return "", err } - return fmt.Sprintf("- AutoScalingGroupName: %s", state.AutoScalingGroupName), nil + return fmt.Sprintf("- Resource type: %s\n AutoScalingGroupName: %s", "AutoScaling Group", state.AutoScalingGroupName), nil } func RestoreAutoScalingGroupsFromState(stateData []byte, provider awsapis.AWSProvider) error { diff --git a/service/ecs/selector.go b/service/ecs/selector.go index 00b2f44..f4c1bd9 100644 --- a/service/ecs/selector.go +++ b/service/ecs/selector.go @@ -19,7 +19,7 @@ func DescribeEcsServicesState(stateData []byte) (string, error) { return "", err } - return fmt.Sprintf("- Cluster: %s\n ServiceName: %s", state.ClusterArn, state.ServiceName), nil + return fmt.Sprintf("- Resource type: %s\n Cluster: %s\n ServiceName: %s", "ECS Service", state.ClusterArn, state.ServiceName), nil } func RestoreEcsServicesFromState(stateData []byte, provider awsapis.AWSProvider) error { diff --git a/service/elbv2/selector.go b/service/elbv2/selector.go index cc80821..991b966 100644 --- a/service/elbv2/selector.go +++ b/service/elbv2/selector.go @@ -19,7 +19,7 @@ func DescribeElbv2LoadBalancersState(stateData []byte) (string, error) { return "", err } - return fmt.Sprintf("- LoadBalancerName: %s", state.LoadBalancerName), nil + return fmt.Sprintf("- Resource type: %s\n LoadBalancerName: %s", "ELB Load Balancer", state.LoadBalancerName), nil } func RestoreElbv2LoadBalancersFromState(stateData []byte, provider awsapis.AWSProvider) error {