From 5a088caea77c6006fa3d0fb1ee576cff23eab455 Mon Sep 17 00:00:00 2001 From: Shota Ito Date: Sat, 12 Feb 2022 18:04:06 +0900 Subject: [PATCH 1/7] Change function name from printEc2Instances to showEc2Instances --- cmd/vaws/ec2.go | 4 ++-- cmd/vaws/ec2_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/vaws/ec2.go b/cmd/vaws/ec2.go index bb85575..a0fe27f 100644 --- a/cmd/vaws/ec2.go +++ b/cmd/vaws/ec2.go @@ -42,7 +42,7 @@ var ec2Cmd = &cobra.Command{ fmt.Println(err) os.Exit(1) } - err = printEc2Instances(outputs, tablewriter.NewWriter(os.Stdout), sortPosition) + err = showEc2Instances(outputs, tablewriter.NewWriter(os.Stdout), sortPosition) if err != nil { fmt.Println(err) os.Exit(1) @@ -74,7 +74,7 @@ func getEc2Instances(cfg aws.Config) ([]*ec2.DescribeInstancesOutput, error) { return outputs, nil } -func printEc2Instances(outputs []*ec2.DescribeInstancesOutput, table *tablewriter.Table, sortPosition int) error { +func showEc2Instances(outputs []*ec2.DescribeInstancesOutput, table *tablewriter.Table, sortPosition int) error { header := []string{"NAME", "ID", "TYPE", "PRIVATE_IP", "PUBLIC_IP", "STATE", "SECURITY_GROUP"} if sortPosition > len(header) || 1 > sortPosition { return fmt.Errorf("out of sort range number when using --sort option") diff --git a/cmd/vaws/ec2_test.go b/cmd/vaws/ec2_test.go index 0efde8e..354ae75 100644 --- a/cmd/vaws/ec2_test.go +++ b/cmd/vaws/ec2_test.go @@ -347,7 +347,7 @@ func Test_printEc2Instances(t *testing.T) { for _, tt := range tests { var buf bytes.Buffer t.Run(tt.name, func(t *testing.T) { - printEc2Instances(tt.args.outputs, tablewriter.NewWriter(&buf), tt.args.sortPosition) + showEc2Instances(tt.args.outputs, tablewriter.NewWriter(&buf), tt.args.sortPosition) if buf.String() != tt.want { t.Errorf("failed to test: %s\n", tt.name) t.Errorf("\nwant:\n%s\n", tt.want) From 75fe2c73b59a1f32f02643004b7e845e754d9ec8 Mon Sep 17 00:00:00 2001 From: Shota Ito Date: Sat, 12 Feb 2022 18:40:23 +0900 Subject: [PATCH 2/7] Add rds subcommand --- cmd/vaws/rds.go | 154 +++++++++++++++++++++++++++++++++++++++++++ cmd/vaws/rds_test.go | 113 +++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 cmd/vaws/rds.go create mode 100644 cmd/vaws/rds_test.go diff --git a/cmd/vaws/rds.go b/cmd/vaws/rds.go new file mode 100644 index 0000000..65e48ef --- /dev/null +++ b/cmd/vaws/rds.go @@ -0,0 +1,154 @@ +package vaws + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/rds" + "github.com/olekukonko/tablewriter" + "os" + "sort" + + "github.com/spf13/cobra" +) + +// rdsCmd represents the rds command +var rdsCmd = &cobra.Command{ + Use: "rds", + Short: "Show RDS instances.", + Long: `Show RDS instances.`, + Run: func(cmd *cobra.Command, args []string) { + profile, err := cmd.Flags().GetString("aws-profile") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + if profile != "" { + err := os.Setenv("AWS_PROFILE", profile) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + } + sortPosition, err := cmd.Flags().GetInt("sort-position") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + instanceFlg, err := cmd.Flags().GetBool("instance") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + if instanceFlg { + output, err := getRdsInstances(newAwsConfig()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + err = showRdsInstances(output, tablewriter.NewWriter(os.Stdout), sortPosition) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + } else { + output, err := getRdsClusters(newAwsConfig()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + err = showRdsClusters(output, tablewriter.NewWriter(os.Stdout), sortPosition) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + } + }, +} + +func init() { + rootCmd.AddCommand(rdsCmd) + rdsCmd.Flags().BoolP("instance", "i", false, "Show instances") +} + +func getRdsClusters(cfg aws.Config) (*rds.DescribeDBClustersOutput, error) { + client := rds.NewFromConfig(cfg) + output, err := client.DescribeDBClusters(context.TODO(), &rds.DescribeDBClustersInput{ + DBClusterIdentifier: nil, + Filters: nil, + IncludeShared: false, + Marker: nil, + MaxRecords: nil, + }) + if err != nil { + return nil, err + } + return output, nil +} + +func getRdsInstances(cfg aws.Config) (*rds.DescribeDBInstancesOutput, error) { + client := rds.NewFromConfig(cfg) + output, err := client.DescribeDBInstances(context.TODO(), &rds.DescribeDBInstancesInput{ + DBInstanceIdentifier: nil, + Filters: nil, + Marker: nil, + MaxRecords: nil, + }) + if err != nil { + return nil, err + } + return output, nil +} + +func showRdsClusters(instances *rds.DescribeDBClustersOutput, table *tablewriter.Table, sortPosition int) error { + header := []string{"CLUSTER", "STATUS", "INSTANCES", "WRITE-ENDPOINT", "READ-ENDPOINT"} + if sortPosition > len(header) || 1 > sortPosition { + return fmt.Errorf("out of sort range number when using --sort option") + } + recordIndex := sortPosition - 1 + table.SetHeader(header) + var records [][]string + for _, object := range instances.DBClusters { + cluster := *object.DBClusterIdentifier + status := *object.Status + wEndpoint := *object.Endpoint + rEndpoint := *object.ReaderEndpoint + instanceId := "" + for i, v := range object.DBClusterMembers { + if i == 0 { + instanceId += *v.DBInstanceIdentifier + } else { + instanceId += fmt.Sprintf(", %s", *v.DBInstanceIdentifier) + } + } + records = append(records, []string{cluster, status, instanceId, wEndpoint, rEndpoint}) + } + sort.Slice(records, func(i, j int) bool { return records[i][recordIndex] < records[j][recordIndex] }) + table.AppendBulk(records) + table.Render() + return nil +} + +func showRdsInstances(instances *rds.DescribeDBInstancesOutput, table *tablewriter.Table, sortPosition int) error { + header := []string{"CLUSTER", "INSTANCE", "TYPE", "ENGINE", "STATUS", "ENDPOINT(INSTANCE)"} + if sortPosition > len(header) || 1 > sortPosition { + return fmt.Errorf("out of sort range number when using --sort option") + } + recordIndex := sortPosition - 1 + table.SetHeader(header) + var records [][]string + for _, object := range instances.DBInstances { + cluster := *object.DBClusterIdentifier + instanceName := *object.DBInstanceIdentifier + class := *object.DBInstanceClass + engine := *object.EngineVersion + status := *object.DBInstanceStatus + endpoint := *object.Endpoint.Address + records = append(records, []string{cluster, instanceName, class, engine, status, endpoint}) + } + sort.Slice(records, func(i, j int) bool { return records[i][recordIndex] < records[j][recordIndex] }) + table.AppendBulk(records) + table.Render() + return nil +} diff --git a/cmd/vaws/rds_test.go b/cmd/vaws/rds_test.go new file mode 100644 index 0000000..a0fba70 --- /dev/null +++ b/cmd/vaws/rds_test.go @@ -0,0 +1,113 @@ +package vaws + +import ( + "bytes" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/rds" + "github.com/aws/aws-sdk-go-v2/service/rds/types" + "github.com/olekukonko/tablewriter" + "testing" +) + +func Test_showRdsClusters(t *testing.T) { + type args struct { + instances *rds.DescribeDBClustersOutput + table *tablewriter.Table + sortPosition int + } + tests := []struct { + name string + args args + want string + }{ + { + name: "default", + args: args{ + instances: &rds.DescribeDBClustersOutput{ + DBClusters: []types.DBCluster{ + { + DBClusterIdentifier: aws.String("test-cluster-01"), + DBClusterMembers: []types.DBClusterMember{ + { + DBInstanceIdentifier: aws.String("test-cluster-instance-01"), + }, + }, + Endpoint: aws.String("test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + ReaderEndpoint: aws.String("test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + Status: aws.String("available"), + }, + { + DBClusterIdentifier: aws.String("test-cluster-01"), + DBClusterMembers: []types.DBClusterMember{ + { + DBInstanceIdentifier: aws.String("test-cluster-instance-02"), + }, + }, + Endpoint: aws.String("test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + ReaderEndpoint: aws.String("test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + Status: aws.String("available"), + }, + }, + }, + sortPosition: 1, + }, + want: `+-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +| CLUSTER | STATUS | INSTANCES | WRITE-ENDPOINT | READ-ENDPOINT | ++-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +| test-cluster-01 | available | test-cluster-instance-01 | test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | +| test-cluster-01 | available | test-cluster-instance-02 | test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | ++-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +`, + }, + { + name: "sort request", + args: args{ + instances: &rds.DescribeDBClustersOutput{ + DBClusters: []types.DBCluster{ + { + DBClusterIdentifier: aws.String("test-cluster-01"), + DBClusterMembers: []types.DBClusterMember{ + { + DBInstanceIdentifier: aws.String("test-cluster-instance-02"), + }, + }, + Endpoint: aws.String("test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + ReaderEndpoint: aws.String("test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + Status: aws.String("available"), + }, + { + DBClusterIdentifier: aws.String("test-cluster-01"), + DBClusterMembers: []types.DBClusterMember{ + { + DBInstanceIdentifier: aws.String("test-cluster-instance-01"), + }, + }, + Endpoint: aws.String("test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + ReaderEndpoint: aws.String("test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com"), + Status: aws.String("available"), + }, + }, + }, + sortPosition: 3, + }, + want: `+-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +| CLUSTER | STATUS | INSTANCES | WRITE-ENDPOINT | READ-ENDPOINT | ++-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +| test-cluster-01 | available | test-cluster-instance-01 | test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | +| test-cluster-01 | available | test-cluster-instance-02 | test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | ++-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +`, + }, + } + for _, tt := range tests { + var buf bytes.Buffer + t.Run(tt.name, func(t *testing.T) { + showRdsClusters(tt.args.instances, tablewriter.NewWriter(&buf), tt.args.sortPosition) + if buf.String() != tt.want { + t.Errorf("failed to test: %s\n", tt.name) + t.Errorf("\nwant:\n%s\n", tt.want) + t.Errorf("\ninput:\n%s\n", buf.String()) + } + }) + } +} From dfb2096acea9fb4893bcfacd1f4c2e6301c81cb9 Mon Sep 17 00:00:00 2001 From: Shota Ito Date: Sat, 12 Feb 2022 18:41:26 +0900 Subject: [PATCH 3/7] Add sg subcommand --- cmd/vaws/securityGroup.go | 134 ++++++++++ cmd/vaws/securityGroup_test.go | 442 +++++++++++++++++++++++++++++++++ 2 files changed, 576 insertions(+) create mode 100644 cmd/vaws/securityGroup.go create mode 100644 cmd/vaws/securityGroup_test.go diff --git a/cmd/vaws/securityGroup.go b/cmd/vaws/securityGroup.go new file mode 100644 index 0000000..7b72053 --- /dev/null +++ b/cmd/vaws/securityGroup.go @@ -0,0 +1,134 @@ +package vaws + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/olekukonko/tablewriter" + "github.com/spf13/cobra" + "os" + "sort" + "strconv" +) + +const sgMaxResult = 1000 + +// securityGroupCmd represents the securityGroup command +var securityGroupCmd = &cobra.Command{ + Use: "sg", + Short: "Show Security Group", + Long: `Show Security Group`, + Run: func(cmd *cobra.Command, args []string) { + profile, err := cmd.Flags().GetString("aws-profile") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + if profile != "" { + err := os.Setenv("AWS_PROFILE", profile) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + } + output, err := getSecurityGroups(newAwsConfig()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + sortPosition, err := cmd.Flags().GetInt("sort-position") + if err != nil { + fmt.Println(err) + os.Exit(1) + } + err = showSecurityGroup(output, tablewriter.NewWriter(os.Stdout), sortPosition) + }, +} + +func init() { + rootCmd.AddCommand(securityGroupCmd) +} + +func getSecurityGroups(cfg aws.Config) ([]*ec2.DescribeSecurityGroupsOutput, error) { + var outputs []*ec2.DescribeSecurityGroupsOutput + var err error + client := ec2.NewFromConfig(cfg) + output := &ec2.DescribeSecurityGroupsOutput{ + NextToken: aws.String(""), + } + for output.NextToken != nil { + output, err = client.DescribeSecurityGroups(context.TODO(), &ec2.DescribeSecurityGroupsInput{ + MaxResults: aws.Int32(sgMaxResult), + NextToken: output.NextToken, + }) + if err != nil { + return nil, err + } + outputs = append(outputs, output) + } + return outputs, nil +} + +func showSecurityGroup(outputs []*ec2.DescribeSecurityGroupsOutput, table *tablewriter.Table, sortPosition int) error { + header := []string{"NAME", "TYPE", "ID", "PORT", "SOURCE", "VPC"} + if sortPosition > len(header) || 1 > sortPosition { + return fmt.Errorf("out of sort range number when using --sort option") + } + recordIndex := sortPosition - 1 + table.SetHeader(header) + var records [][]string + var allowPort int32 + for _, o := range outputs { + for _, sg := range o.SecurityGroups { + for _, in := range sg.IpPermissions { + allowType := "inbound" + if in.ToPort != nil { + allowPort = *in.ToPort + } else { + allowPort = -1 + } + if in.IpRanges != nil { + for _, v := range in.IpRanges { + records = append(records, []string{ + *sg.GroupName, + allowType, + *sg.GroupId, + strconv.Itoa(int(allowPort)), + *v.CidrIp, + *sg.VpcId, + }) + } + } + if in.PrefixListIds != nil { + for _, prefix := range in.PrefixListIds { + records = append(records, []string{ + *sg.GroupName, + allowType, + *sg.GroupId, + strconv.Itoa(int(allowPort)), + *prefix.PrefixListId, + *sg.VpcId, + }) + } + } + if in.UserIdGroupPairs != nil { + for _, v := range in.UserIdGroupPairs { + records = append(records, []string{ + *sg.GroupName, + allowType, + *sg.GroupId, + strconv.Itoa(int(allowPort)), + *v.GroupId, + *sg.VpcId, + }) + } + } + } + } + } + sort.Slice(records, func(i, j int) bool { return records[i][recordIndex] < records[j][recordIndex] }) + table.AppendBulk(records) + table.Render() + return nil +} diff --git a/cmd/vaws/securityGroup_test.go b/cmd/vaws/securityGroup_test.go new file mode 100644 index 0000000..4e5bc7d --- /dev/null +++ b/cmd/vaws/securityGroup_test.go @@ -0,0 +1,442 @@ +package vaws + +import ( + "bytes" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/aws/smithy-go/middleware" + "github.com/olekukonko/tablewriter" + "testing" +) + +func Test_showSecurityGroup(t *testing.T) { + type args struct { + outputs []*ec2.DescribeSecurityGroupsOutput + table *tablewriter.Table + sortPosition int + } + tests := []struct { + name string + args args + want string + }{ + { + name: "default", + args: args{ + outputs: []*ec2.DescribeSecurityGroupsOutput{ + { + SecurityGroups: []types.SecurityGroup{ + { + GroupName: aws.String("default"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: nil, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-1"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("8.8.8.8/32"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + UserIdGroupPairs: []types.UserIdGroupPair{ + { + GroupId: aws.String("sg-0d642190887707fd0"), + }, + }, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + ToPort: aws.Int32(53), + PrefixListIds: []types.PrefixListId{ + { + PrefixListId: aws.String("pl-61a12345"), + }, + }, + }, + }, + }, + }, + ResultMetadata: middleware.Metadata{}, + }, + }, + table: nil, + sortPosition: 1, + }, + want: `+-----------------+---------+----------------------+------+----------------------+-----------------------+ +| NAME | TYPE | ID | PORT | SOURCE | VPC | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +| default | inbound | sg-0d642190887707fd0 | -1 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-1 | inbound | sg-0d642190887707fd0 | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 8.8.8.8/32 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | sg-0d642190887707fd0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 53 | pl-61a12345 | vpc-0f9999c7db8c44b21 | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +`, + }, + { + name: "sort_port", + args: args{ + outputs: []*ec2.DescribeSecurityGroupsOutput{ + { + SecurityGroups: []types.SecurityGroup{ + { + GroupName: aws.String("default"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: nil, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-1"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("8.8.8.8/32"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + UserIdGroupPairs: []types.UserIdGroupPair{ + { + GroupId: aws.String("sg-0d642190887707fd0"), + }, + }, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + ToPort: aws.Int32(53), + PrefixListIds: []types.PrefixListId{ + { + PrefixListId: aws.String("pl-61a12345"), + }, + }, + }, + }, + }, + }, + ResultMetadata: middleware.Metadata{}, + }, + }, + table: nil, + sortPosition: 5, + }, + want: `+-----------------+---------+----------------------+------+----------------------+-----------------------+ +| NAME | TYPE | ID | PORT | SOURCE | VPC | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +| default | inbound | sg-0d642190887707fd0 | -1 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-1 | inbound | sg-0d642190887707fd0 | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 8.8.8.8/32 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 53 | pl-61a12345 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | sg-0d642190887707fd0 | vpc-0f9999c7db8c44b21 | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +`, + }, + { + name: "two request", + args: args{ + outputs: []*ec2.DescribeSecurityGroupsOutput{ + { + SecurityGroups: []types.SecurityGroup{ + { + GroupName: aws.String("default"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: nil, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-1"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("8.8.8.8/32"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + UserIdGroupPairs: []types.UserIdGroupPair{ + { + GroupId: aws.String("sg-0d642190887707fd0"), + }, + }, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + ToPort: aws.Int32(53), + PrefixListIds: []types.PrefixListId{ + { + PrefixListId: aws.String("pl-61a12345"), + }, + }, + }, + }, + }, + }, + ResultMetadata: middleware.Metadata{}, + }, + { + SecurityGroups: []types.SecurityGroup{ + { + GroupName: aws.String("default"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: nil, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-1"), + GroupId: aws.String("sg-0d642190887707fd0"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("8.8.8.8/32"), + }, + }, + ToPort: aws.Int32(22), + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + IpRanges: []types.IpRange{ + { + CidrIp: aws.String("0.0.0.0/0"), + }, + }, + ToPort: aws.Int32(22), + UserIdGroupPairs: []types.UserIdGroupPair{ + { + GroupId: aws.String("sg-0d642190887707fd0"), + }, + }, + }, + }, + }, + { + GroupName: aws.String("launch-wizard-2"), + GroupId: aws.String("sg-08d35fef29987e75e"), + VpcId: aws.String("vpc-0f9999c7db8c44b21"), + IpPermissions: []types.IpPermission{ + { + ToPort: aws.Int32(53), + PrefixListIds: []types.PrefixListId{ + { + PrefixListId: aws.String("pl-61a12345"), + }, + }, + }, + }, + }, + }, + ResultMetadata: middleware.Metadata{}, + }, + }, + table: nil, + sortPosition: 1, + }, + want: `+-----------------+---------+----------------------+------+----------------------+-----------------------+ +| NAME | TYPE | ID | PORT | SOURCE | VPC | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +| default | inbound | sg-0d642190887707fd0 | -1 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| default | inbound | sg-0d642190887707fd0 | -1 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-1 | inbound | sg-0d642190887707fd0 | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-1 | inbound | sg-0d642190887707fd0 | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 8.8.8.8/32 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | sg-0d642190887707fd0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 53 | pl-61a12345 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 8.8.8.8/32 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | sg-0d642190887707fd0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 53 | pl-61a12345 | vpc-0f9999c7db8c44b21 | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +`, + }, + } + for _, tt := range tests { + var buf bytes.Buffer + t.Run(tt.name, func(t *testing.T) { + showSecurityGroup(tt.args.outputs, tablewriter.NewWriter(&buf), tt.args.sortPosition) + if buf.String() != tt.want { + t.Errorf("failed to test: %s\n", tt.name) + t.Errorf("\nwant:\n%s\n", tt.want) + t.Errorf("\ninput:\n%s\n", buf.String()) + } + }) + } +} From bf21eec2fd5c64bdc0d8d3b136c06b2f00a7033f Mon Sep 17 00:00:00 2001 From: Shota Ito Date: Sat, 12 Feb 2022 18:41:46 +0900 Subject: [PATCH 4/7] Fix go.mod and go.sum --- go.mod | 3 ++- go.sum | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 435966f..72b45fd 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,8 @@ require ( github.com/aws/aws-sdk-go-v2 v1.13.0 github.com/aws/aws-sdk-go-v2/config v1.13.1 github.com/aws/aws-sdk-go-v2/service/ec2 v1.29.0 + github.com/aws/aws-sdk-go-v2/service/rds v1.16.0 + github.com/aws/smithy-go v1.10.0 github.com/olekukonko/tablewriter v0.0.5 github.com/spf13/cobra v1.3.0 ) @@ -19,7 +21,6 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect - github.com/aws/smithy-go v1.10.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect diff --git a/go.sum b/go.sum index 0943498..9cd0e8d 100644 --- a/go.sum +++ b/go.sum @@ -78,6 +78,8 @@ github.com/aws/aws-sdk-go-v2/service/ec2 v1.29.0 h1:7jk4NfzDnnSbaR9E4mOBWRZXQThq github.com/aws/aws-sdk-go-v2/service/ec2 v1.29.0/go.mod h1:HoTu0hnXGafTpKIZQ60jw0ybhhCH1QYf20oL7GEJFdg= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI1ApJK14sliGr3Ie2pjyvNypn/lfzDHfUw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU= +github.com/aws/aws-sdk-go-v2/service/rds v1.16.0 h1:xYxIpmqlnc+U/miylJaNmEty34MC4BmxpVOqkF2DFpo= +github.com/aws/aws-sdk-go-v2/service/rds v1.16.0/go.mod h1:U1tzFmWLyt4AqSRLONL0RXcYsQg0huiInDdRmCecz1w= github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 h1:1qLJeQGBmNQW3mBNzK2CFmrQNmoXWrscPqsrAaU1aTA= github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU= github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW5yjNQ8Nx9Sn2c0E= From 9448e9cad380c53ae5eb8e0357826df57883c2be Mon Sep 17 00:00:00 2001 From: Shota Ito Date: Sat, 12 Feb 2022 18:43:17 +0900 Subject: [PATCH 5/7] Remove toggle option --- cmd/vaws/root.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/vaws/root.go b/cmd/vaws/root.go index fc3a83b..354d6ee 100644 --- a/cmd/vaws/root.go +++ b/cmd/vaws/root.go @@ -22,7 +22,6 @@ func Execute() { } func init() { - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") rootCmd.PersistentFlags().StringP("aws-profile", "p", "", "-p my-aws") rootCmd.PersistentFlags().IntP("sort-position", "s", 1, "-s 1") } From 812e9ff58d9af70fb5fcc257bdd17f8d0b55d9a7 Mon Sep 17 00:00:00 2001 From: Shota Ito Date: Sat, 12 Feb 2022 18:54:40 +0900 Subject: [PATCH 6/7] Fix README.md --- README.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af41814..f0379c8 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,11 @@ The vaws command was created to simplify the display of AWS resources. This repository is a Go version of the command that was created in the following repository. https://github.com/st1t/vaws +## Install + +Download the appropriate one for your CPU architecture from the following site. +https://github.com/st1t/vaws/releases + ## Usage ```bash @@ -17,18 +22,73 @@ Available Commands: completion Generate the autocompletion script for the specified shell ec2 Show EC2 instances. help Help about any command + rds Show RDS instances. + sg Show Security Group Flags: -p, --aws-profile string -p my-aws -h, --help help for vaws -s, --sort-position int -s 1 (default 1) - -t, --toggle Help message for toggle -v, --version version for vaws Use "vaws [command] --help" for more information about a command. $ ``` +### EC2 + +```shell +$ vaws ec2 -p my-aws ++-------+---------------------+----------+---------------+---------------+---------+---------------------------------------+ +| NAME | ID | TYPE | PRIVATE IP | PUBLIC IP | STATE | SECURITY GROUP | ++-------+---------------------+----------+---------------+---------------+---------+---------------------------------------+ +| app01 | i-06d4c29e4e5ccadc4 | t2.micro | 172.31.35.175 | 54.238.30.226 | running | launch-wizard-2(sg-0f0b4c4642ffb5ef2) | +| app02 | i-06723a6629e542c50 | t3.small | 172.31.21.33 | 18.179.33.182 | running | launch-wizard-3(sg-08d35fef29987e75e) | +| web01 | i-0abee92626b0a28a7 | t3.nano | 172.31.18.8 | 35.73.127.100 | running | launch-wizard-1(sg-0d642190887707fd0) | ++-------+---------------------+----------+---------------+---------------+---------+---------------------------------------+ +``` + +If you want to sort by a specific column, use the S option. +The following command sorts by SecurityGroup column. +```shell +$ vaws ec2 -p my-aws -s 7 ++-------+---------------------+----------+---------------+---------------+---------+---------------------------------------+ +| NAME | ID | TYPE | PRIVATE IP | PUBLIC IP | STATE | SECURITY GROUP | ++-------+---------------------+----------+---------------+---------------+---------+---------------------------------------+ +| web01 | i-0abee92626b0a28a7 | t3.nano | 172.31.18.8 | 35.73.127.100 | running | launch-wizard-1(sg-0d642190887707fd0) | +| app01 | i-06d4c29e4e5ccadc4 | t2.micro | 172.31.35.175 | 54.238.30.226 | running | launch-wizard-2(sg-0f0b4c4642ffb5ef2) | +| app02 | i-06723a6629e542c50 | t3.small | 172.31.21.33 | 18.179.33.182 | running | launch-wizard-3(sg-08d35fef29987e75e) | ++-------+---------------------+----------+---------------+---------------+---------+---------------------------------------+ +``` + +## RDS + +```shell +$ vaws rds -p my-aws ++-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +| CLUSTER | STATUS | INSTANCES | WRITE-ENDPOINT | READ-ENDPOINT | ++-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +| test-cluster-01 | available | test-cluster-instance-01 | test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | +| test-cluster-01 | available | test-cluster-instance-02 | test-cluster-01.cluster-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | test-cluster-01.cluster-ro-cb8aaaaaaaaa.ap-northeast-1.rds.amazonaws.com | ++-----------------+-----------+--------------------------+-----------------------------------------------------------------------+--------------------------------------------------------------------------+ +``` + +## SecurityGroup + +```shell +$ vaws sg -p my-aws ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +| NAME | TYPE | ID | PORT | SOURCE | VPC | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +| default | inbound | sg-0d642190887707fd0 | -1 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-1 | inbound | sg-0d642190887707fd0 | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 8.8.8.8/32 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | 0.0.0.0/0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 22 | sg-0d642190887707fd0 | vpc-0f9999c7db8c44b21 | +| launch-wizard-2 | inbound | sg-08d35fef29987e75e | 53 | pl-61a12345 | vpc-0f9999c7db8c44b21 | ++-----------------+---------+----------------------+------+----------------------+-----------------------+ +``` + ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). From eb35ca459e91205e6371dafea1f3fd6840616a36 Mon Sep 17 00:00:00 2001 From: Shota Ito Date: Sat, 12 Feb 2022 18:55:06 +0900 Subject: [PATCH 7/7] Release 0.2.0 --- cmd/vaws/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/vaws/root.go b/cmd/vaws/root.go index 354d6ee..fe156ec 100644 --- a/cmd/vaws/root.go +++ b/cmd/vaws/root.go @@ -11,7 +11,7 @@ var rootCmd = &cobra.Command{ Use: "vaws", Short: "The vaws command was created to simplify the display of AWS resources.", Long: `The vaws command was created to simplify the display of AWS resources.`, - Version: "0.1.0", + Version: "0.2.0", } func Execute() {