From 7a9302aac6a9445045b0e8568367d30322064d38 Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Sat, 15 Apr 2023 15:13:56 +0530 Subject: [PATCH 01/26] feat: support AWS CloudWatch log groups --- go.mod | 7 ++-- go.sum | 17 ++++----- providers/aws/aws.go | 1 + providers/aws/cloudwatch/log_group.go | 50 +++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 providers/aws/cloudwatch/log_group.go diff --git a/go.mod b/go.mod index 3a71e19d8..5c4839a78 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.0.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 github.com/BurntSushi/toml v1.2.1 - github.com/aws/aws-sdk-go-v2 v1.17.7 + github.com/aws/aws-sdk-go-v2 v1.17.8 github.com/aws/aws-sdk-go-v2/config v1.15.14 github.com/aws/aws-sdk-go-v2/service/apigateway v1.16.0 github.com/aws/aws-sdk-go-v2/service/autoscaling v1.27.2 @@ -94,10 +94,11 @@ require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.12.9 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.20.9 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.19 // indirect diff --git a/go.sum b/go.sum index 7912188c2..a2c3198c7 100644 --- a/go.sum +++ b/go.sum @@ -11,13 +11,9 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/container v1.16.0 h1:dALHCKAYowNhUeENL4pf3+5ToHuSiE2emTDnuzwn4kc= cloud.google.com/go/container v1.16.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/datacatalog v1.12.0 h1:3uaYULZRLByPdbuUvacGeqneudztEM4xqKQsBcxbDnY= -cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/datacatalog v1.13.0 h1:4H5IJiyUE0X6ShQBqgFFZvGGcrwGVndTwUSLP4c52gw= cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/kms v1.9.0 h1:b0votJQa/9DSsxgHwN33/tTLA7ZHVzfWhDCrfiXijSo= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= cloud.google.com/go/kms v1.10.0 h1:Imrtp8792uqNP9bdfPrjtUkjjqOMBcAJ2bdFaAnLhnk= cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= @@ -63,8 +59,9 @@ github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4 github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg= github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.17.8 h1:GMupCNNI7FARX27L7GjCJM8NgivWbRgpjNI/hOQjFS8= +github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 h1:S/ZBwevQkr7gv5YxONYpGQxlMFFYSRfz3RMcjsC9Qhk= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y= github.com/aws/aws-sdk-go-v2/config v1.15.14 h1:+BqpqlydTq4c2et9Daury7gE+o67P4lbk7eybiCBNc4= @@ -77,14 +74,16 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 h1:dpbVNUjczQ8Ae3QKHbpHBpfvaVkRdesxpTOe9pTouhU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 h1:QH2kOS3Ht7x+u0gHCh06CXL/h6G8LQJFpZfFBYBNboo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 h1:QquxR7NH3ULBsKC+NoTpilzbKKS+5AELfNREInbhvas= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15/go.mod h1:Tkrthp/0sNBShQQsamR7j/zY4p19tVTAs+nnqhH6R3c= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 h1:tEEHn+PGAxRVqMPEhtU8oCSW/1Ge3zP5nUgPrGQNUPs= @@ -97,6 +96,8 @@ github.com/aws/aws-sdk-go-v2/service/cloudfront v1.20.7 h1:RoinUS4OHD/GFpXV2Jvu2 github.com/aws/aws-sdk-go-v2/service/cloudfront v1.20.7/go.mod h1:fV9PzXIIT2xUvf5KXEGToDYxEXcqDyO33SRfv2rAs/8= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.23.1 h1:6VwY6q6RZwxZTTTXjDmS8qbeBKvWwp8ugMKCEBjdgWA= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.23.1/go.mod h1:th8fks2kW4FFCUKUQenuEG9TEzMLVxeL0ckdJn/QVbI= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.20.9 h1:sXs+JjIwgKA27t+5O8YgXl0cmZpEmctyDVO5y6cMdqA= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.20.9/go.mod h1:CpWhQvomfSbbrfUhq9sq/w2x4wbkQOAqGJbcPS2AINA= github.com/aws/aws-sdk-go-v2/service/configservice v1.31.0 h1:3EaaGPAkwUHVbDKx/TCTAubBUqV8F6++5EaiSiXQgN0= github.com/aws/aws-sdk-go-v2/service/configservice v1.31.0/go.mod h1:a+PVnn9VNPzPVUiXKXDHK21PSi/TzEKQNIsvSlVXgFY= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.3 h1:2oB4ikNEMLaPtu6lbNFJyTSayBILvrOfa2VfOffcuvU= diff --git a/providers/aws/aws.go b/providers/aws/aws.go index cd1c4d5ad..a2e4b2aba 100644 --- a/providers/aws/aws.go +++ b/providers/aws/aws.go @@ -68,6 +68,7 @@ func listOfSupportedServices() []providers.FetchDataFunction { ec2.NetworkInterfaces, cloudwatch.Dashboards, ec2.ElasticIps, + cloudwatch.LogGroups, } } diff --git a/providers/aws/cloudwatch/log_group.go b/providers/aws/cloudwatch/log_group.go new file mode 100644 index 000000000..4a31ec374 --- /dev/null +++ b/providers/aws/cloudwatch/log_group.go @@ -0,0 +1,50 @@ +package cloudwatch + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" + log "github.com/sirupsen/logrus" + + . "github.com/tailwarden/komiser/models" + . "github.com/tailwarden/komiser/providers" +) + +func LogGroups(ctx context.Context, client ProviderClient) ([]Resource, error) { + resources := make([]Resource, 0) + cloudWatchLogsClient := cloudwatchlogs.NewFromConfig(*client.AWSClient) + input := &cloudwatchlogs.DescribeLogGroupsInput{} + for { + output, err := cloudWatchLogsClient.DescribeLogGroups(ctx, input) + if err != nil { + return resources, err + } + for _, group := range output.LogGroups { + resources = append(resources, Resource{ + Provider: "AWS", + Account: client.Name, + Service: "CloudWatch Log Group", + ResourceId: aws.ToString(group.Arn), + Region: client.AWSClient.Region, + Name: aws.ToString(group.LogGroupName), + FetchedAt: time.Now(), + Link: fmt.Sprintf("https://%s.console.aws.amazon.com/cloudwatch/home?region=%s#logsV2:log-groups/log-group/%s", client.AWSClient.Region, client.AWSClient.Region, aws.ToString(group.LogGroupName)), + }) + } + if output.NextToken == nil { + break + } + input.NextToken = output.NextToken + } + log.WithFields(log.Fields{ + "provider": "AWS", + "account": client.Name, + "region": client.AWSClient.Region, + "service": "CloudWatch Log Group", + "resources": len(resources), + }).Info("Fetched resources") + return resources, nil +} From 6c9a4ff0886e6d5336e4feef016ea530d3ddb5ff Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Sat, 15 Apr 2023 15:47:54 +0530 Subject: [PATCH 02/26] feat: support AWS CloudWatch metric stream --- go.mod | 7 ++- go.sum | 8 +++ providers/aws/aws.go | 1 + providers/aws/cloudwatch/log_metrics.go | 75 +++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 providers/aws/cloudwatch/log_metrics.go diff --git a/go.mod b/go.mod index 3a71e19d8..5c4839a78 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.0.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 github.com/BurntSushi/toml v1.2.1 - github.com/aws/aws-sdk-go-v2 v1.17.7 + github.com/aws/aws-sdk-go-v2 v1.17.8 github.com/aws/aws-sdk-go-v2/config v1.15.14 github.com/aws/aws-sdk-go-v2/service/apigateway v1.16.0 github.com/aws/aws-sdk-go-v2/service/autoscaling v1.27.2 @@ -94,10 +94,11 @@ require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.12.9 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.20.9 github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.19 // indirect diff --git a/go.sum b/go.sum index 7912188c2..cb0be8721 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,8 @@ github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3eP github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg= github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.17.8 h1:GMupCNNI7FARX27L7GjCJM8NgivWbRgpjNI/hOQjFS8= +github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 h1:S/ZBwevQkr7gv5YxONYpGQxlMFFYSRfz3RMcjsC9Qhk= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y= github.com/aws/aws-sdk-go-v2/config v1.15.14 h1:+BqpqlydTq4c2et9Daury7gE+o67P4lbk7eybiCBNc4= @@ -79,12 +81,16 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBB github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 h1:dpbVNUjczQ8Ae3QKHbpHBpfvaVkRdesxpTOe9pTouhU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 h1:QH2kOS3Ht7x+u0gHCh06CXL/h6G8LQJFpZfFBYBNboo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 h1:QquxR7NH3ULBsKC+NoTpilzbKKS+5AELfNREInbhvas= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15/go.mod h1:Tkrthp/0sNBShQQsamR7j/zY4p19tVTAs+nnqhH6R3c= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 h1:tEEHn+PGAxRVqMPEhtU8oCSW/1Ge3zP5nUgPrGQNUPs= @@ -97,6 +103,8 @@ github.com/aws/aws-sdk-go-v2/service/cloudfront v1.20.7 h1:RoinUS4OHD/GFpXV2Jvu2 github.com/aws/aws-sdk-go-v2/service/cloudfront v1.20.7/go.mod h1:fV9PzXIIT2xUvf5KXEGToDYxEXcqDyO33SRfv2rAs/8= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.23.1 h1:6VwY6q6RZwxZTTTXjDmS8qbeBKvWwp8ugMKCEBjdgWA= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.23.1/go.mod h1:th8fks2kW4FFCUKUQenuEG9TEzMLVxeL0ckdJn/QVbI= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.20.9 h1:sXs+JjIwgKA27t+5O8YgXl0cmZpEmctyDVO5y6cMdqA= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.20.9/go.mod h1:CpWhQvomfSbbrfUhq9sq/w2x4wbkQOAqGJbcPS2AINA= github.com/aws/aws-sdk-go-v2/service/configservice v1.31.0 h1:3EaaGPAkwUHVbDKx/TCTAubBUqV8F6++5EaiSiXQgN0= github.com/aws/aws-sdk-go-v2/service/configservice v1.31.0/go.mod h1:a+PVnn9VNPzPVUiXKXDHK21PSi/TzEKQNIsvSlVXgFY= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.17.3 h1:2oB4ikNEMLaPtu6lbNFJyTSayBILvrOfa2VfOffcuvU= diff --git a/providers/aws/aws.go b/providers/aws/aws.go index cd1c4d5ad..edbdeb635 100644 --- a/providers/aws/aws.go +++ b/providers/aws/aws.go @@ -68,6 +68,7 @@ func listOfSupportedServices() []providers.FetchDataFunction { ec2.NetworkInterfaces, cloudwatch.Dashboards, ec2.ElasticIps, + cloudwatch.MetricStreams, } } diff --git a/providers/aws/cloudwatch/log_metrics.go b/providers/aws/cloudwatch/log_metrics.go new file mode 100644 index 000000000..440ce6c45 --- /dev/null +++ b/providers/aws/cloudwatch/log_metrics.go @@ -0,0 +1,75 @@ +package cloudwatch + +import ( + "context" + "fmt" + "time" + + log "github.com/sirupsen/logrus" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + "github.com/tailwarden/komiser/models" + "github.com/tailwarden/komiser/providers" +) + +func MetricStreams(ctx context.Context, client providers.ProviderClient) ([]models.Resource, error) { + resources := make([]models.Resource, 0) + cloudWatchMetricsClient := cloudwatch.NewFromConfig(*client.AWSClient) + + input := &cloudwatch.ListMetricStreamsInput{} + for { + output, err := cloudWatchMetricsClient.ListMetricStreams(ctx, input) + if err != nil { + return resources, err + } + + for _, stream := range output.Entries { + tags := make([]models.Tag, 0) + + streamArn := aws.ToString(stream.Arn) + tagInput := &cloudwatch.ListTagsForResourceInput{ + ResourceARN: &streamArn, + } + + tagOutput, err := cloudWatchMetricsClient.ListTagsForResource(ctx, tagInput) + if err == nil { + for _, tag := range tagOutput.Tags { + tags = append(tags, models.Tag{ + Key: aws.ToString(tag.Key), + Value: aws.ToString(tag.Value), + }) + } + } + + resources = append(resources, models.Resource{ + Provider: "AWS", + Account: client.Name, + Service: "CloudWatch Metric Stream", + ResourceId: streamArn, + Region: client.AWSClient.Region, + Name: aws.ToString(stream.Name), + Cost: 0, + Tags: tags, + FetchedAt: time.Now(), + Link: fmt.Sprintf("https://%s.console.aws.amazon.com/cloudwatch/home?region=%s#metric-streams:streamsList/%s", client.AWSClient.Region, client.AWSClient.Region, aws.ToString(stream.Name)), + }) + } + + if output.NextToken == nil { + break + } + + input.NextToken = output.NextToken + } + + log.WithFields(log.Fields{ + "provider": "AWS", + "account": client.Name, + "region": client.AWSClient.Region, + "service": "CloudWatch Metric Stream", + "resources": len(resources), + }).Info("Fetched resources") + + return resources, nil +} From 96e3c9b723bb79e20bf40462e3aac630f8e65c43 Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Sat, 15 Apr 2023 16:48:14 +0530 Subject: [PATCH 03/26] feat: support AWS EC2 self-owned snapshots --- providers/aws/aws.go | 1 + providers/aws/ec2/snapshots.go | 73 ++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 providers/aws/ec2/snapshots.go diff --git a/providers/aws/aws.go b/providers/aws/aws.go index cd1c4d5ad..89945362b 100644 --- a/providers/aws/aws.go +++ b/providers/aws/aws.go @@ -68,6 +68,7 @@ func listOfSupportedServices() []providers.FetchDataFunction { ec2.NetworkInterfaces, cloudwatch.Dashboards, ec2.ElasticIps, + ec2.Snapshots, } } diff --git a/providers/aws/ec2/snapshots.go b/providers/aws/ec2/snapshots.go new file mode 100644 index 000000000..c7bb1a1cc --- /dev/null +++ b/providers/aws/ec2/snapshots.go @@ -0,0 +1,73 @@ +package ec2 + +import ( + "context" + "fmt" + "time" + + log "github.com/sirupsen/logrus" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + . "github.com/tailwarden/komiser/models" + . "github.com/tailwarden/komiser/providers" +) + +func Snapshots(ctx context.Context, client ProviderClient) ([]Resource, error) { + resources := make([]Resource, 0) + ec2Client := ec2.NewFromConfig(*client.AWSClient) + + input := ec2.DescribeSnapshotsInput{ + OwnerIds: []string{"self"}, + } + + for { + output, err := ec2Client.DescribeSnapshots(ctx, &input) + if err != nil { + return resources, err + } + + for _, snapshot := range output.Snapshots { + tags := make([]Tag, 0) + for _, tag := range snapshot.Tags { + tags = append(tags, Tag{ + Key: *tag.Key, + Value: *tag.Value, + }) + } + + resource := Resource{ + Provider: "AWS", + Account: client.Name, + Service: "EC2 Snapshot", + ResourceId: aws.ToString(snapshot.SnapshotId), + Region: client.AWSClient.Region, + Name: aws.ToString(snapshot.SnapshotId), + Tags: tags, + FetchedAt: time.Now(), + CreatedAt: *snapshot.StartTime, + Link: fmt.Sprintf("https://%s.console.aws.amazon.com/ec2/home?region=%s#napshotDetails:snapshotId=%s", client.AWSClient.Region, client.AWSClient.Region, *snapshot.SnapshotId), + Metadata: map[string]string{ + "Description": aws.ToString(snapshot.Description), + }, + } + + resources = append(resources, resource) + } + + if aws.ToString(output.NextToken) == "" { + break + } + input.NextToken = output.NextToken + } + + log.WithFields(log.Fields{ + "provider": "AWS", + "account": client.Name, + "region": client.AWSClient.Region, + "service": "EC2 Snapshot", + "resources": len(resources), + }).Info("Fetched resources") + + return resources, nil +} From 7cdc8acb2ba2a0d0b14f9471e60b9f60fc123ce3 Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Sat, 15 Apr 2023 22:57:32 +0530 Subject: [PATCH 04/26] feat: support AWS OpenSearch service Domains --- go.mod | 7 +-- go.sum | 17 ++++--- providers/aws/aws.go | 2 + providers/aws/opensearch/service_domains.go | 56 +++++++++++++++++++++ 4 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 providers/aws/opensearch/service_domains.go diff --git a/go.mod b/go.mod index 3a71e19d8..451d197da 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/sql/armsql v1.0.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 github.com/BurntSushi/toml v1.2.1 - github.com/aws/aws-sdk-go-v2 v1.17.7 + github.com/aws/aws-sdk-go-v2 v1.17.8 github.com/aws/aws-sdk-go-v2/config v1.15.14 github.com/aws/aws-sdk-go-v2/service/apigateway v1.16.0 github.com/aws/aws-sdk-go-v2/service/autoscaling v1.27.2 @@ -94,8 +94,8 @@ require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.12.9 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 // indirect @@ -103,6 +103,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.19 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/service/opensearch v1.15.4 github.com/aws/aws-sdk-go-v2/service/sso v1.11.12 // indirect github.com/aws/smithy-go v1.13.5 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect diff --git a/go.sum b/go.sum index 7912188c2..07d0c676a 100644 --- a/go.sum +++ b/go.sum @@ -11,13 +11,9 @@ cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGB cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/container v1.16.0 h1:dALHCKAYowNhUeENL4pf3+5ToHuSiE2emTDnuzwn4kc= cloud.google.com/go/container v1.16.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/datacatalog v1.12.0 h1:3uaYULZRLByPdbuUvacGeqneudztEM4xqKQsBcxbDnY= -cloud.google.com/go/iam v0.12.0 h1:DRtTY29b75ciH6Ov1PHb4/iat2CLCvrOm40Q0a6DFpE= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/datacatalog v1.13.0 h1:4H5IJiyUE0X6ShQBqgFFZvGGcrwGVndTwUSLP4c52gw= cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/kms v1.9.0 h1:b0votJQa/9DSsxgHwN33/tTLA7ZHVzfWhDCrfiXijSo= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= cloud.google.com/go/kms v1.10.0 h1:Imrtp8792uqNP9bdfPrjtUkjjqOMBcAJ2bdFaAnLhnk= cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= @@ -63,8 +59,9 @@ github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4 github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg= github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.17.8 h1:GMupCNNI7FARX27L7GjCJM8NgivWbRgpjNI/hOQjFS8= +github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 h1:S/ZBwevQkr7gv5YxONYpGQxlMFFYSRfz3RMcjsC9Qhk= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y= github.com/aws/aws-sdk-go-v2/config v1.15.14 h1:+BqpqlydTq4c2et9Daury7gE+o67P4lbk7eybiCBNc4= @@ -77,14 +74,16 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 h1:dpbVNUjczQ8Ae3QKHbpHBpfvaVkRdesxpTOe9pTouhU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 h1:QH2kOS3Ht7x+u0gHCh06CXL/h6G8LQJFpZfFBYBNboo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 h1:QquxR7NH3ULBsKC+NoTpilzbKKS+5AELfNREInbhvas= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15/go.mod h1:Tkrthp/0sNBShQQsamR7j/zY4p19tVTAs+nnqhH6R3c= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 h1:tEEHn+PGAxRVqMPEhtU8oCSW/1Ge3zP5nUgPrGQNUPs= @@ -133,6 +132,8 @@ github.com/aws/aws-sdk-go-v2/service/kms v1.18.18 h1:VEj0VdYbmx12y3GKWSXm8hB/mPu github.com/aws/aws-sdk-go-v2/service/kms v1.18.18/go.mod h1:kZodDPTQjSH/qM6/OvyTfM5mms5JHB/EKYp5dhn/vI4= github.com/aws/aws-sdk-go-v2/service/lambda v1.23.4 h1:d1Olp+josNRAlrrtacghtos74rffKS6Mq5gEUBHfgHw= github.com/aws/aws-sdk-go-v2/service/lambda v1.23.4/go.mod h1:XiSHsT7z5ScD2AsTgfa1UEFQaAr53dHP1oWvaqSW6jQ= +github.com/aws/aws-sdk-go-v2/service/opensearch v1.15.4 h1:56esBN+m4kQrGPHZfE60PqfXDryuv8oYbSAc0aU1F10= +github.com/aws/aws-sdk-go-v2/service/opensearch v1.15.4/go.mod h1:2Azx9xDn2nuX+yv4wTR7MO5EYqJNXt2fUC/axUV67qI= github.com/aws/aws-sdk-go-v2/service/pricing v1.17.5 h1:89yKwg+Kn3jgjcpxzmbZYH0O+I2+HjEcILIQrLkj8ik= github.com/aws/aws-sdk-go-v2/service/pricing v1.17.5/go.mod h1:1YtXjD073MNbQvowCxfSsdhGUCJQOt04FVDcs8uYCmI= github.com/aws/aws-sdk-go-v2/service/rds v1.30.1 h1:/B3GswjV+ScqZSZnhs3NMLwvVFXb1/aQL/elQwo0CMM= diff --git a/providers/aws/aws.go b/providers/aws/aws.go index cd1c4d5ad..54434c570 100644 --- a/providers/aws/aws.go +++ b/providers/aws/aws.go @@ -22,6 +22,7 @@ import ( "github.com/tailwarden/komiser/providers/aws/iam" "github.com/tailwarden/komiser/providers/aws/kms" "github.com/tailwarden/komiser/providers/aws/lambda" + "github.com/tailwarden/komiser/providers/aws/opensearch" "github.com/tailwarden/komiser/providers/aws/rds" "github.com/tailwarden/komiser/providers/aws/s3" "github.com/tailwarden/komiser/providers/aws/sns" @@ -68,6 +69,7 @@ func listOfSupportedServices() []providers.FetchDataFunction { ec2.NetworkInterfaces, cloudwatch.Dashboards, ec2.ElasticIps, + opensearch.ServiceDomains, } } diff --git a/providers/aws/opensearch/service_domains.go b/providers/aws/opensearch/service_domains.go new file mode 100644 index 000000000..d95f3f41a --- /dev/null +++ b/providers/aws/opensearch/service_domains.go @@ -0,0 +1,56 @@ +package opensearch + +import ( + "context" + "fmt" + "time" + + log "github.com/sirupsen/logrus" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/opensearch" + . "github.com/tailwarden/komiser/models" + . "github.com/tailwarden/komiser/providers" +) + +func ServiceDomains(ctx context.Context, client ProviderClient) ([]Resource, error) { + resources := make([]Resource, 0) + openSearchClient := opensearch.NewFromConfig(*client.AWSClient) + input := &opensearch.ListDomainNamesInput{} + + output, err := openSearchClient.ListDomainNames(ctx, input) + if err != nil { + return resources, err + } + + for _, domainName := range output.DomainNames { + domainConfig, err := openSearchClient.DescribeDomain(ctx, &opensearch.DescribeDomainInput{ + DomainName: domainName.DomainName, + }) + if err != nil { + return resources, err + } + domain := domainConfig.DomainStatus + + resources = append(resources, Resource{ + Provider: "AWS", + Account: client.Name, + Service: "OpenSearch Service Domain", + ResourceId: aws.ToString(domain.DomainId), + Region: client.AWSClient.Region, + Name: aws.ToString(domain.DomainName), + Cost: 0, + FetchedAt: time.Now(), + Link: fmt.Sprintf("https://%s.console.aws.amazon.com/aos/home?region=%s#/opensearch/domains/%s", client.AWSClient.Region, client.AWSClient.Region, aws.ToString(domain.DomainName)), + }) + } + log.WithFields(log.Fields{ + "provider": "AWS", + "account": client.Name, + "region": client.AWSClient.Region, + "service": "OpenSearch Service Domain", + "resources": len(resources), + }).Info("Fetched resources") + + return resources, nil +} From 9cf7443e65e6cf5a4ea148dd9870716f8a567fde Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Mon, 17 Apr 2023 19:17:09 +0530 Subject: [PATCH 05/26] feat: check to only return user created policies --- providers/aws/iam/policies.go | 63 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/providers/aws/iam/policies.go b/providers/aws/iam/policies.go index 9add650e9..7acb61961 100644 --- a/providers/aws/iam/policies.go +++ b/providers/aws/iam/policies.go @@ -26,41 +26,44 @@ func Policies(ctx context.Context, client ProviderClient) ([]Resource, error) { } for _, policy := range outputPolicies.Policies { - tags := make([]Tag, 0) - for { - configTags.PolicyArn = policy.Arn - outputPolicyTags, err := iamClient.ListPolicyTags(ctx, &configTags) - if err != nil { - return resources, err - } + // only fetch user created policies + if aws.ToString(policy.Arn)[:20] != "arn:aws:iam::aws:pol" { + tags := make([]Tag, 0) + for { + configTags.PolicyArn = policy.Arn + outputPolicyTags, err := iamClient.ListPolicyTags(ctx, &configTags) + if err != nil { + return resources, err + } - for _, t := range outputPolicyTags.Tags { - tags = append(tags, Tag{ - Key: *t.Key, - Value: *t.Value, - }) - } + for _, t := range outputPolicyTags.Tags { + tags = append(tags, Tag{ + Key: *t.Key, + Value: *t.Value, + }) + } - if aws.ToString(outputPolicyTags.Marker) == "" { - break + if aws.ToString(outputPolicyTags.Marker) == "" { + break + } + + configTags.Marker = outputPolicyTags.Marker } - configTags.Marker = outputPolicyTags.Marker + resources = append(resources, Resource{ + Provider: "AWS", + Account: client.Name, + Service: "IAM Policy", + ResourceId: *policy.Arn, + Region: client.AWSClient.Region, + Name: *policy.PolicyName, + Cost: 0, + CreatedAt: *policy.CreateDate, + Tags: tags, + FetchedAt: time.Now(), + Link: fmt.Sprintf("https://%s.console.aws.amazon.com/iam/home#/policies/%s", client.AWSClient.Region, *policy.Arn), + }) } - - resources = append(resources, Resource{ - Provider: "AWS", - Account: client.Name, - Service: "IAM Policy", - ResourceId: *policy.Arn, - Region: client.AWSClient.Region, - Name: *policy.PolicyName, - Cost: 0, - CreatedAt: *policy.CreateDate, - Tags: tags, - FetchedAt: time.Now(), - Link: fmt.Sprintf("https://%s.console.aws.amazon.com/iam/home#/policies/%s", client.AWSClient.Region, *policy.Arn), - }) } if aws.ToString(outputPolicies.Marker) == "" { From 4eeb0cba88f022f844a222b2feefbfb068ff853f Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Mon, 17 Apr 2023 19:28:23 +0530 Subject: [PATCH 06/26] feat: only query user created policies in the root --- providers/aws/iam/policies.go | 68 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/providers/aws/iam/policies.go b/providers/aws/iam/policies.go index 7acb61961..a89bdab1e 100644 --- a/providers/aws/iam/policies.go +++ b/providers/aws/iam/policies.go @@ -9,13 +9,16 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/aws-sdk-go-v2/service/iam/types" . "github.com/tailwarden/komiser/models" . "github.com/tailwarden/komiser/providers" ) func Policies(ctx context.Context, client ProviderClient) ([]Resource, error) { resources := make([]Resource, 0) - var configPolicies iam.ListPoliciesInput + configPolicies := iam.ListPoliciesInput{ + Scope: types.PolicyScopeTypeLocal, + } var configTags iam.ListPolicyTagsInput iamClient := iam.NewFromConfig(*client.AWSClient) @@ -26,44 +29,41 @@ func Policies(ctx context.Context, client ProviderClient) ([]Resource, error) { } for _, policy := range outputPolicies.Policies { - // only fetch user created policies - if aws.ToString(policy.Arn)[:20] != "arn:aws:iam::aws:pol" { - tags := make([]Tag, 0) - for { - configTags.PolicyArn = policy.Arn - outputPolicyTags, err := iamClient.ListPolicyTags(ctx, &configTags) - if err != nil { - return resources, err - } - - for _, t := range outputPolicyTags.Tags { - tags = append(tags, Tag{ - Key: *t.Key, - Value: *t.Value, - }) - } + tags := make([]Tag, 0) + for { + configTags.PolicyArn = policy.Arn + outputPolicyTags, err := iamClient.ListPolicyTags(ctx, &configTags) + if err != nil { + return resources, err + } - if aws.ToString(outputPolicyTags.Marker) == "" { - break - } + for _, t := range outputPolicyTags.Tags { + tags = append(tags, Tag{ + Key: *t.Key, + Value: *t.Value, + }) + } - configTags.Marker = outputPolicyTags.Marker + if aws.ToString(outputPolicyTags.Marker) == "" { + break } - resources = append(resources, Resource{ - Provider: "AWS", - Account: client.Name, - Service: "IAM Policy", - ResourceId: *policy.Arn, - Region: client.AWSClient.Region, - Name: *policy.PolicyName, - Cost: 0, - CreatedAt: *policy.CreateDate, - Tags: tags, - FetchedAt: time.Now(), - Link: fmt.Sprintf("https://%s.console.aws.amazon.com/iam/home#/policies/%s", client.AWSClient.Region, *policy.Arn), - }) + configTags.Marker = outputPolicyTags.Marker } + + resources = append(resources, Resource{ + Provider: "AWS", + Account: client.Name, + Service: "IAM Policy", + ResourceId: *policy.Arn, + Region: client.AWSClient.Region, + Name: *policy.PolicyName, + Cost: 0, + CreatedAt: *policy.CreateDate, + Tags: tags, + FetchedAt: time.Now(), + Link: fmt.Sprintf("https://%s.console.aws.amazon.com/iam/home#/policies/%s", client.AWSClient.Region, *policy.Arn), + }) } if aws.ToString(outputPolicies.Marker) == "" { From 7ef76db9fd5472f698d7c7feebca05f4c0c39aeb Mon Sep 17 00:00:00 2001 From: "Victor F. Santos" Date: Mon, 17 Apr 2023 16:47:57 +0200 Subject: [PATCH 07/26] style: empty state --- .../empty-state/EmptyState.mocks.tsx | 8 +- .../components/empty-state/EmptyState.tsx | 51 +++++---- dashboard/components/layout/Layout.tsx | 10 +- dashboard/package-lock.json | 4 +- dashboard/pages/inventory.tsx | 2 +- .../public/assets/img/purplin/thinking.svg | 101 ++++++++++++++++++ 6 files changed, 147 insertions(+), 29 deletions(-) create mode 100644 dashboard/public/assets/img/purplin/thinking.svg diff --git a/dashboard/components/empty-state/EmptyState.mocks.tsx b/dashboard/components/empty-state/EmptyState.mocks.tsx index 45c82aa6b..1a426b21a 100644 --- a/dashboard/components/empty-state/EmptyState.mocks.tsx +++ b/dashboard/components/empty-state/EmptyState.mocks.tsx @@ -4,9 +4,11 @@ const base: EmptyStateProps = { title: 'We could not find a cloud account', message: 'It seems you have not connected a cloud account to Komiser. Connect one right now so you can start managing it from your dashboard.', - actionLabel: 'Refer to the docs', - mascotPose: 'greetings', - action: () => {} + actionLabel: 'Guide to connect account', + mascotPose: 'thinking', + secondaryActionLabel: 'Report an issue', + action: () => {}, + secondaryAction: () => {} }; const mockEmptyStateProps = { diff --git a/dashboard/components/empty-state/EmptyState.tsx b/dashboard/components/empty-state/EmptyState.tsx index 29bb67493..cd7883b32 100644 --- a/dashboard/components/empty-state/EmptyState.tsx +++ b/dashboard/components/empty-state/EmptyState.tsx @@ -1,4 +1,4 @@ -import { ReactElement, ReactNode } from 'react'; +import Image from 'next/image'; import Button from '../button/Button'; type Poses = @@ -20,13 +20,16 @@ type Poses = | 'rocket' | 'shirt' | 'whiteboard' + | 'thinking' | 'working'; export type EmptyStateProps = { title: string; message: string; action?: () => void | Element; + secondaryAction?: () => void | Element; actionLabel?: string; + secondaryActionLabel?: string; mascotPose?: Poses; }; @@ -34,32 +37,38 @@ function EmptyState({ title, message, action, - actionLabel, + secondaryAction, + actionLabel = 'Guide to connect account', + secondaryActionLabel = 'Report an issue', mascotPose }: EmptyStateProps) { return ( -
-
-

{title}

-
-

{message}

-
+
+
+ {mascotPose && ( + Purplin thinking + )} +
+

{title}

+

{message}

+
{action && ( - <> - + )} + -
- - )} - {mascotPose && ( - - Purplin - +
)}
diff --git a/dashboard/components/layout/Layout.tsx b/dashboard/components/layout/Layout.tsx index 9f7c9e859..712a5f149 100644 --- a/dashboard/components/layout/Layout.tsx +++ b/dashboard/components/layout/Layout.tsx @@ -66,11 +66,17 @@ function Layout({ children }: LayoutProps) { message="It seems you have not connected a cloud account to Komiser. Connect one right now so you can start managing it from your dashboard" action={() => { router.push( - 'https://docs.komiser.io/docs/introduction/getting-started#self-hosted' + 'https://docs.komiser.io/docs/introduction/getting-started' ); }} actionLabel="Guide to connect account" - mascotPose="greetings" + secondaryAction={() => { + router.push( + 'https://github.com/tailwarden/komiser/issues/new/choose' + ); + }} + secondaryActionLabel="Report an issue" + mascotPose="thinking" /> )} diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 21fdac3ae..9653405e9 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -1,12 +1,12 @@ { "name": "komiser-dashboard", - "version": "3.0.10", + "version": "3.0.12", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "komiser-dashboard", - "version": "3.0.10", + "version": "3.0.12", "dependencies": { "@sentry/react": "^7.41.0", "@sentry/tracing": "^7.41.0", diff --git a/dashboard/pages/inventory.tsx b/dashboard/pages/inventory.tsx index e27a3e916..28cc358b0 100644 --- a/dashboard/pages/inventory.tsx +++ b/dashboard/pages/inventory.tsx @@ -211,7 +211,7 @@ export default function Inventory() { ); }} actionLabel="Check our docs" - mascotPose="greetings" + mascotPose="thinking" /> )} diff --git a/dashboard/public/assets/img/purplin/thinking.svg b/dashboard/public/assets/img/purplin/thinking.svg new file mode 100644 index 000000000..ee51e5c5b --- /dev/null +++ b/dashboard/public/assets/img/purplin/thinking.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 072709f809276bf66ad1be390b93aabb9b96d9f8 Mon Sep 17 00:00:00 2001 From: ShubhamPalriwala Date: Mon, 17 Apr 2023 20:28:25 +0530 Subject: [PATCH 08/26] feat: support GCP Cloud functions --- providers/gcp/function/functions.go | 77 +++++++++++++++++++++++++++++ providers/gcp/gcp.go | 2 + 2 files changed, 79 insertions(+) create mode 100644 providers/gcp/function/functions.go diff --git a/providers/gcp/function/functions.go b/providers/gcp/function/functions.go new file mode 100644 index 000000000..c27b9f6ce --- /dev/null +++ b/providers/gcp/function/functions.go @@ -0,0 +1,77 @@ +package function + +import ( + "context" + "fmt" + "regexp" + "time" + + log "github.com/sirupsen/logrus" + "github.com/tailwarden/komiser/models" + "github.com/tailwarden/komiser/providers" + "google.golang.org/api/cloudfunctions/v2" + "google.golang.org/api/option" +) + +func Functions(ctx context.Context, client providers.ProviderClient) ([]models.Resource, error) { + resources := make([]models.Resource, 0) + + cloudFunctionsService, err := cloudfunctions.NewService(ctx, option.WithCredentials(client.GCPClient.Credentials)) + if err != nil { + log.WithError(err).Errorf("failed to create Cloud Functions service") + return resources, err + } + + functions, err := cloudFunctionsService.Projects.Locations.Functions.List( + "projects/" + client.GCPClient.Credentials.ProjectID + "/locations/-", + ).Do() + if err != nil { + log.WithError(err).Errorf("failed to list Cloud Functions") + return resources, err + } + + for _, function := range functions.Functions { + fmt.Printf("%+v\n", function) + + re := regexp.MustCompile(`projects\/.*?\/locations\/(.+?)\/functions\/(.+)`) + match := re.FindStringSubmatch(function.Name) + + generation := "gen1" + functionRegion := "" + functionName := function.Name + + if function.Environment == "GEN_2" { + generation = "gen2" + } + if len(match) == 3 { + functionRegion = match[1] + functionName = match[2] + + } + + resources = append(resources, models.Resource{ + Provider: "GCP", + Account: client.Name, + Service: "Cloud Functions", + ResourceId: function.Name, + Region: functionRegion, + Name: functionName, + Metadata: map[string]string{ + "Version": function.Environment, + "Last Modified": function.UpdateTime, + }, + FetchedAt: time.Now(), + Link: fmt.Sprintf("https://console.cloud.google.com/functions/details/%s/%s?env=%sproject=%s", functionRegion, functionName, generation, client.GCPClient.Credentials.ProjectID), + }) + + } + + log.WithFields(log.Fields{ + "provider": "GCP", + "account": client.Name, + "service": "Cloud Functions", + "resources": len(resources), + }).Info("Fetched resources") + + return resources, nil +} diff --git a/providers/gcp/gcp.go b/providers/gcp/gcp.go index f12421013..dd0afc8bc 100644 --- a/providers/gcp/gcp.go +++ b/providers/gcp/gcp.go @@ -9,6 +9,7 @@ import ( certficate "github.com/tailwarden/komiser/providers/gcp/certificate" "github.com/tailwarden/komiser/providers/gcp/compute" "github.com/tailwarden/komiser/providers/gcp/container" + "github.com/tailwarden/komiser/providers/gcp/function" "github.com/tailwarden/komiser/providers/gcp/gateway" "github.com/tailwarden/komiser/providers/gcp/iam" "github.com/tailwarden/komiser/providers/gcp/kms" @@ -33,6 +34,7 @@ func listOfSupportedServices() []providers.FetchDataFunction { container.Clusters, kms.Keys, gateway.ApiGateways, + function.Functions, } } From 9ce36f6915369d708d2a8b98f89ad21c9c7456ca Mon Sep 17 00:00:00 2001 From: "Victor F. Santos" Date: Tue, 18 Apr 2023 00:34:36 +0200 Subject: [PATCH 09/26] style: match buttons to designs --- dashboard/components/banner/Banner.tsx | 2 +- .../components/button/Button.stories.tsx | 18 +++---- dashboard/components/button/Button.tsx | 47 ++++--------------- .../cloud-map/DashboardCloudMapError.tsx | 2 +- .../DashboardCostExplorerError.tsx | 2 +- .../DashboardResourcesManagerError.tsx | 2 +- .../top-stats/DashboardTopStatsError.tsx | 2 +- .../error-state/ErrorState.mocks.tsx | 2 +- .../export-csv/ExportCSVButton.test.tsx | 2 +- .../components/export-csv/ExportCSVButton.tsx | 2 +- dashboard/components/icons/LoadingSpinner.tsx | 27 +++++++++++ .../components/InventorySearchNoResults.tsx | 2 +- .../components/InventorySidePanel.tsx | 4 +- .../components/view/InventoryView.tsx | 4 +- .../alerts/InventoryViewAlertsDisplay.tsx | 2 +- .../InventoryViewAlertsEditSlackAlert.tsx | 2 +- .../view/alerts/InventoryViewAlertsError.tsx | 2 +- dashboard/components/layout/Layout.tsx | 12 +++-- .../layout/hooks/useGlobalStats.tsx | 2 +- .../components/sidepanel/SidepanelHeader.tsx | 2 +- dashboard/pages/inventory.tsx | 8 +++- dashboard/tailwind.config.js | 1 + 22 files changed, 76 insertions(+), 73 deletions(-) create mode 100644 dashboard/components/icons/LoadingSpinner.tsx diff --git a/dashboard/components/banner/Banner.tsx b/dashboard/components/banner/Banner.tsx index 899e2f2b9..575f3b1b4 100644 --- a/dashboard/components/banner/Banner.tsx +++ b/dashboard/components/banner/Banner.tsx @@ -30,7 +30,7 @@ function Banner({ githubStars }: BannerProps) { > ); diff --git a/dashboard/components/dashboard/components/cloud-map/DashboardCloudMapError.tsx b/dashboard/components/dashboard/components/cloud-map/DashboardCloudMapError.tsx index 97e973bf1..04a1c1876 100644 --- a/dashboard/components/dashboard/components/cloud-map/DashboardCloudMapError.tsx +++ b/dashboard/components/dashboard/components/cloud-map/DashboardCloudMapError.tsx @@ -15,7 +15,7 @@ function DashboardCloudMapError({ fetch }: DashboardCloudMapErrorProps) { There was an error loading the cloud map.

-
@@ -252,7 +252,7 @@ function InventorySidePanel({
- diff --git a/dashboard/components/layout/Layout.tsx b/dashboard/components/layout/Layout.tsx index 712a5f149..48415c784 100644 --- a/dashboard/components/layout/Layout.tsx +++ b/dashboard/components/layout/Layout.tsx @@ -1,7 +1,8 @@ -import { useRouter } from 'next/router'; -import { ReactNode, useEffect } from 'react'; import * as Sentry from '@sentry/react'; import { BrowserTracing } from '@sentry/tracing'; +import { useRouter } from 'next/router'; +import { ReactNode, useEffect } from 'react'; +import environment from '../../environments/environment'; import Banner from '../banner/Banner'; import useGithubStarBanner from '../banner/hooks/useGithubStarBanner'; import Button from '../button/Button'; @@ -11,7 +12,6 @@ import Navbar from '../navbar/Navbar'; import GlobalAppContext from './context/GlobalAppContext'; import useGlobalStats from './hooks/useGlobalStats'; import useTelemetry from './hooks/useTelemetry'; -import environment from '../../environments/environment'; type LayoutProps = { children: ReactNode; @@ -85,7 +85,11 @@ function Layout({ children }: LayoutProps) { title="Network request error" message="There was an error fetching the cloud accounts. Please refer to the logs for more info and try again." action={ - } diff --git a/dashboard/components/layout/hooks/useGlobalStats.tsx b/dashboard/components/layout/hooks/useGlobalStats.tsx index 22b307f0e..2c84a9eb9 100644 --- a/dashboard/components/layout/hooks/useGlobalStats.tsx +++ b/dashboard/components/layout/hooks/useGlobalStats.tsx @@ -12,7 +12,7 @@ function useGlobalStats() { const [loading, setLoading] = useState(true); const [data, setData] = useState(); const [error, setError] = useState(false); - const [hasNoAccounts, setHasNoAccounts] = useState(false); + const [hasNoAccounts, setHasNoAccounts] = useState(true); function fetch() { if (!loading) { diff --git a/dashboard/components/sidepanel/SidepanelHeader.tsx b/dashboard/components/sidepanel/SidepanelHeader.tsx index f86675881..6d2bfd6bc 100644 --- a/dashboard/components/sidepanel/SidepanelHeader.tsx +++ b/dashboard/components/sidepanel/SidepanelHeader.tsx @@ -35,7 +35,7 @@ function SidepanelHeader({ )} - diff --git a/dashboard/pages/inventory.tsx b/dashboard/pages/inventory.tsx index 28cc358b0..98dd1cf7e 100644 --- a/dashboard/pages/inventory.tsx +++ b/dashboard/pages/inventory.tsx @@ -2,13 +2,13 @@ import Head from 'next/head'; import Button from '../components/button/Button'; import EmptyState from '../components/empty-state/EmptyState'; import ErrorState from '../components/error-state/ErrorState'; -import InventoryFilter from '../components/inventory/components/filter/InventoryFilter'; import InventoryActiveFilters from '../components/inventory/components/InventoryActiveFilters'; import InventoryHeader from '../components/inventory/components/InventoryHeader'; import InventoryLayout from '../components/inventory/components/InventoryLayout'; import InventorySidePanel from '../components/inventory/components/InventorySidePanel'; import InventoryStatsCards from '../components/inventory/components/InventoryStatsCards'; import InventoryTable from '../components/inventory/components/InventoryTable'; +import InventoryFilter from '../components/inventory/components/filter/InventoryFilter'; import InventoryView from '../components/inventory/components/view/InventoryView'; import useInventory from '../components/inventory/hooks/useInventory/useInventory'; import SkeletonFilters from '../components/skeleton/SkeletonFilters'; @@ -193,7 +193,11 @@ export default function Inventory() { title="Network request error" message="There was an error fetching the inventory resources. Check out the server logs for more info and try again." action={ - } diff --git a/dashboard/tailwind.config.js b/dashboard/tailwind.config.js index 9a83db1f8..87a813f09 100644 --- a/dashboard/tailwind.config.js +++ b/dashboard/tailwind.config.js @@ -13,6 +13,7 @@ module.exports = { komiser: { 100: '#F5FDFD', 120: '#e5f8f8', + 130: '#E2F6F6', 150: '#DFF5F5', 200: '#CCF2F2', 300: '#99E5E5', From 04af76dfb1f64cff4aecf8a80d69f9196620e85a Mon Sep 17 00:00:00 2001 From: "Victor F. Santos" Date: Tue, 18 Apr 2023 11:49:56 +0200 Subject: [PATCH 10/26] chore: replacing deprecated buttons with newer buttons --- dashboard/components/button/Button.mocks.tsx | 68 ++--- .../components/button/Button.stories.tsx | 13 +- dashboard/components/button/Button.tsx | 40 ++- dashboard/components/dropdown/Dropdown.tsx | 24 -- dashboard/components/export-csv/ExportCSV.tsx | 11 +- .../export-csv/ExportCSVButton.test.tsx | 7 - .../components/export-csv/ExportCSVButton.tsx | 13 +- dashboard/components/icons/CheckIcon.tsx | 20 ++ dashboard/components/icons/ErrorIcon.tsx | 20 ++ dashboard/components/icons/FilterIcon.tsx | 21 ++ dashboard/components/icons/PlusIcon.tsx | 20 ++ .../components/InventoryActiveFilters.tsx | 2 +- .../components/InventorySearchBar.tsx | 2 +- .../components/InventorySidePanel.tsx | 250 ++++++++---------- .../components/InventoryTagWrapper.tsx | 2 +- .../components/filter/InventoryFilter.tsx | 24 +- .../filter/InventoryFilterField.tsx | 3 +- .../filter/InventoryFilterOperator.tsx | 24 +- .../filter/InventoryFilterSummary.tsx | 23 +- .../components/view/InventoryView.tsx | 7 +- .../components/view/InventoryViewHeader.tsx | 23 +- dashboard/components/toast/Toast.tsx | 36 +-- dashboard/tailwind.config.js | 1 + 23 files changed, 262 insertions(+), 392 deletions(-) delete mode 100644 dashboard/components/dropdown/Dropdown.tsx create mode 100644 dashboard/components/icons/CheckIcon.tsx create mode 100644 dashboard/components/icons/ErrorIcon.tsx create mode 100644 dashboard/components/icons/FilterIcon.tsx create mode 100644 dashboard/components/icons/PlusIcon.tsx diff --git a/dashboard/components/button/Button.mocks.tsx b/dashboard/components/button/Button.mocks.tsx index 333c8777b..736305a2a 100644 --- a/dashboard/components/button/Button.mocks.tsx +++ b/dashboard/components/button/Button.mocks.tsx @@ -1,3 +1,4 @@ +import EditIcon from '../icons/EditIcon'; import { ButtonProps } from './Button'; const base: ButtonProps = { @@ -20,58 +21,33 @@ const secondary: ButtonProps = { onClick: () => {} }; -const bulk: ButtonProps = { - children: 'Bulk button', - type: 'button', - style: 'bulk', - size: 'lg', - disabled: false, - loading: false, - onClick: () => {} -}; - -const bulkOutline: ButtonProps = { - children: 'Bulk button', +const ghost: ButtonProps = { + children: 'Ghost button', type: 'button', - style: 'bulk-outline', + style: 'ghost', size: 'lg', disabled: false, loading: false, onClick: () => {} }; -const outline: ButtonProps = { - children: 'Bulk button', +const text: ButtonProps = { + children: 'Text button', type: 'button', - style: 'outline', - size: 'lg', + style: 'text', disabled: false, loading: false, onClick: () => {} }; - -const ghost: ButtonProps = { +const dropdown: ButtonProps = { children: ( - - - + <> + + Dropdown button + ), type: 'button', - style: 'ghost', - size: 'sm', + style: 'dropdown', disabled: false, loading: false, onClick: () => {} @@ -87,25 +63,13 @@ const deleteButton: ButtonProps = { onClick: () => {} }; -const deleteButtonGhost: ButtonProps = { - children: 'Delete button ghost', - type: 'button', - style: 'delete-ghost', - size: 'lg', - disabled: false, - loading: false, - onClick: () => {} -}; - const mockButtonProps = { base, secondary, - bulk, - bulkOutline, - outline, ghost, - deleteButton, - deleteButtonGhost + text, + dropdown, + deleteButton }; export default mockButtonProps; diff --git a/dashboard/components/button/Button.stories.tsx b/dashboard/components/button/Button.stories.tsx index d532eb2b0..a83a23872 100644 --- a/dashboard/components/button/Button.stories.tsx +++ b/dashboard/components/button/Button.stories.tsx @@ -48,15 +48,15 @@ export const Ghost: Story = { } }; -export const Bulk: Story = { +export const Text: Story = { args: { - ...mockButtonProps.bulk + ...mockButtonProps.text } }; -export const BulkOutline: Story = { +export const Dropdown: Story = { args: { - ...mockButtonProps.bulkOutline + ...mockButtonProps.dropdown } }; @@ -65,8 +65,3 @@ export const Delete: Story = { ...mockButtonProps.deleteButton } }; -export const DeleteGhost: Story = { - args: { - ...mockButtonProps.deleteButtonGhost - } -}; diff --git a/dashboard/components/button/Button.tsx b/dashboard/components/button/Button.tsx index 703d5b758..dedb7adec 100644 --- a/dashboard/components/button/Button.tsx +++ b/dashboard/components/button/Button.tsx @@ -4,15 +4,8 @@ import LoadingSpinner from '../icons/LoadingSpinner'; export type ButtonProps = { children: ReactNode; type?: 'button' | 'submit'; - style?: - | 'primary' - | 'secondary' - | 'ghost' - | 'bulk' - | 'bulk-outline' - | 'delete' - | 'delete-ghost'; - size?: 'xs' | 'sm' | 'md' | 'lg'; + style?: 'primary' | 'secondary' | 'ghost' | 'text' | 'dropdown' | 'delete'; + size?: 'xxs' | 'xs' | 'sm' | 'md' | 'lg'; disabled?: boolean; loading?: boolean; align?: 'left'; @@ -33,14 +26,16 @@ function Button({ transition = true, onClick }: ButtonProps) { - const xs = 'p-1'; - const sm = 'h-[2.5rem] px-3'; - const md = 'h-[3rem] px-6'; - const lg = 'h-[3.75rem] px-6'; + const xxs = 'p-1'; + const xs = 'py-2 px-4'; + const sm = 'py-2.5 px-6'; + const md = 'py-3.5 px-6'; + const lg = 'py-4 px-6'; function handleSize() { let buttonSize; + if (size === 'xxs') buttonSize = xxs; if (size === 'xs') buttonSize = xs; if (size === 'sm') buttonSize = sm; if (size === 'md') buttonSize = md; @@ -52,34 +47,31 @@ function Button({ const base = `${handleSize()} rounded flex items-center ${ align ? 'justify-start' : 'justify-center ' } ${ - gap ? 'gap-3' : 'gap-2' + gap ? 'gap-3' : 'gap-1' } text-sm font-medium box-border w-full sm:w-auto disabled:cursor-not-allowed ${ transition ? 'transition-colors' : '' }`; - const primary = `${base} bg-gradient-to-br from-primary bg-secondary hover:bg-primary active:from-secondary active:bg-secondary text-white disabled:from-primary disabled:bg-secondary disabled:opacity-50`; + const primary = `${base} font-semibold bg-gradient-to-br from-primary bg-secondary hover:bg-primary active:from-secondary active:bg-secondary text-white disabled:from-primary disabled:bg-secondary disabled:opacity-50`; const secondary = `${base} bg-transparent text-primary border-[1.5px] border-primary hover:bg-komiser-130 active:bg-komiser-200 active:text-primary disabled:bg-transparent disabled:opacity-50`; - const bulk = `${base} bg-white hover:bg-komiser-200 active:bg-komiser-300 text-secondary disabled:bg-white disabled:opacity-50`; + const ghost = `${base} bg-transparent hover:bg-black-100 active:bg-black-400/20 text-black-800 disabled:bg-transparent disabled:opacity-50`; - const bulkOutline = `${base} bg-transparent text-white border-[1.5px] border-white hover:bg-komiser-100/10 active:bg-transparent active:border-white/50 active:text-white disabled:bg-transparent disabled:opacity-50`; + const text = `font-semibold text-sm text-komiser-700 hover:underline active:text-black-800`; - const ghost = `${base} bg-transparent hover:bg-black-400/10 active:bg-black-400/20 text-black-900/60 disabled:bg-transparent disabled:opacity-50`; + const dropdown = `text-sm font-medium flex items-center gap-2 justify-start p-2 bg-transparent text-black-400 hover:bg-black-150 active:bg-black-200 rounded disabled:bg-transparent disabled:opacity-50`; const deleteStyle = `${base} border-[1.5px] border-error-600 text-error-600 hover:bg-error-100 active:bg-error-600/20 disabled:opacity-50`; - const deleteGhostStyle = `${base} bg-error-100 text-error-600 hover:bg-error-600 hover:text-white active:bg-error-100 active:text-error-600 disabled:bg-error-600 disabled:text-white`; - function handleStyle() { let buttonStyle; if (style === 'primary') buttonStyle = primary; if (style === 'secondary') buttonStyle = secondary; if (style === 'ghost') buttonStyle = ghost; - if (style === 'bulk') buttonStyle = bulk; - if (style === 'bulk-outline') buttonStyle = bulkOutline; - if (style === 'delete-ghost') buttonStyle = deleteGhostStyle; + if (style === 'text') buttonStyle = text; + if (style === 'dropdown') buttonStyle = dropdown; if (style === 'delete') buttonStyle = deleteStyle; return buttonStyle; @@ -87,8 +79,8 @@ function Button({ return ( - ); -} - -export default Dropdown; diff --git a/dashboard/components/export-csv/ExportCSV.tsx b/dashboard/components/export-csv/ExportCSV.tsx index 5aec4587d..fd17946c8 100644 --- a/dashboard/components/export-csv/ExportCSV.tsx +++ b/dashboard/components/export-csv/ExportCSV.tsx @@ -1,15 +1,13 @@ import { useRouter } from 'next/router'; -import { useState } from 'react'; import settingsService from '../../services/settingsService'; import { ToastProps } from '../toast/hooks/useToast'; import ExportCSVButton from './ExportCSVButton'; type ExportCSVProps = { - displayInTable?: boolean; setToast: (toast: ToastProps | undefined) => void; }; -function ExportCSV({ displayInTable = false, setToast }: ExportCSVProps) { +function ExportCSV({ setToast }: ExportCSVProps) { const router = useRouter(); function exportCSV(id?: string) { @@ -26,12 +24,7 @@ function ExportCSV({ displayInTable = false, setToast }: ExportCSVProps) { const id = router.query.view ? router.query.view.toString() : undefined; return ( - + ); } diff --git a/dashboard/components/export-csv/ExportCSVButton.test.tsx b/dashboard/components/export-csv/ExportCSVButton.test.tsx index f463c014a..5aeb64a1b 100644 --- a/dashboard/components/export-csv/ExportCSVButton.test.tsx +++ b/dashboard/components/export-csv/ExportCSVButton.test.tsx @@ -4,7 +4,6 @@ import ExportCSVButton from './ExportCSVButton'; const props = { id: undefined, disabled: false, - displayInTable: false, exportCSV: jest.fn() }; @@ -13,12 +12,6 @@ describe('Export CSV component', () => { render(); }); - it('should render the correct button props if displayInTable is true', () => { - render(); - const button = screen.getByTestId('ghost'); - expect(button).toBeInTheDocument(); - }); - it('should display the auxiliary info in the tooltip if disabled is true', () => { render(); const tooltip = screen.getByRole('tooltip'); diff --git a/dashboard/components/export-csv/ExportCSVButton.tsx b/dashboard/components/export-csv/ExportCSVButton.tsx index cf195c73c..4561a493a 100644 --- a/dashboard/components/export-csv/ExportCSVButton.tsx +++ b/dashboard/components/export-csv/ExportCSVButton.tsx @@ -5,25 +5,16 @@ import Tooltip from '../tooltip/Tooltip'; type ExportCSVButtonProps = { id?: string; disabled: boolean; - displayInTable: boolean; exportCSV: (id?: string) => void; }; -function ExportCSVButton({ - id, - disabled, - displayInTable, - exportCSV -}: ExportCSVButtonProps) { +function ExportCSVButton({ id, disabled, exportCSV }: ExportCSVButtonProps) { return ( <>
)} diff --git a/dashboard/components/inventory/components/InventorySidePanel.tsx b/dashboard/components/inventory/components/InventorySidePanel.tsx index cdd893031..e17969eb2 100644 --- a/dashboard/components/inventory/components/InventorySidePanel.tsx +++ b/dashboard/components/inventory/components/InventorySidePanel.tsx @@ -1,6 +1,8 @@ import formatNumber from '../../../utils/formatNumber'; import providers from '../../../utils/providerHelper'; import Button from '../../button/Button'; +import CloseIcon from '../../icons/CloseIcon'; +import PlusIcon from '../../icons/PlusIcon'; import Sidepanel from '../../sidepanel/Sidepanel'; import SidepanelTabs from '../../sidepanel/SidepanelTabs'; import { @@ -113,165 +115,131 @@ function InventorySidePanel({ {/* Tags form */} -
-
- {page === 'tags' && ( -
{ - e.preventDefault(); +
+ {page === 'tags' && ( + { + e.preventDefault(); - if (!data && bulkItems) { - updateBulkTags(); - } else { - updateTags(); + if (!data && bulkItems) { + updateBulkTags(); + } else { + updateTags(); + } + }} + className="flex flex-col gap-6 pt-2" + > + {tags && + tags.map((tag, id) => ( +
+ + {tags.length > 1 && ( + + )} +
+ ))} + +
+ {((data && data.tags && data.tags.length > 0) || + (!data && bulkItems)) && ( + + )} + - )} -
- ))} -
+ {data && data.tags && data.tags.length > 0 + ? 'Save changes' + : 'Add tags'} + +
+ + )} + + {page === 'delete' && ( + <> +
+
- - Add new tag +
+
+

+ Are you sure you want to delete all tags from{' '} + {formatNumber(bulkItems.length)}{' '} + {bulkItems.length > 1 ? 'resources' : 'resource'}? +

+

+ This is a permanent action, and it will also delete previous + tags you have added to these resources. +

- {((data && data.tags && data.tags.length > 0) || - (!data && bulkItems)) && ( - - )} +
- - )} - - {page === 'delete' && ( - <> -
-
- - - -
-
-

- Are you sure you want to delete all tags from{' '} - {formatNumber(bulkItems.length)}{' '} - {bulkItems.length > 1 ? 'resources' : 'resource'}? -

-

- This is a permanent action, and it will also delete - previous tags you have added to these resources. -

-
-
- - -
-
- - )} -
+
+ + )}
diff --git a/dashboard/components/inventory/components/InventoryTagWrapper.tsx b/dashboard/components/inventory/components/InventoryTagWrapper.tsx index dcc2b51f0..a6fb62aa2 100644 --- a/dashboard/components/inventory/components/InventoryTagWrapper.tsx +++ b/dashboard/components/inventory/components/InventoryTagWrapper.tsx @@ -13,7 +13,7 @@ function InventoryTagWrapper({ handleChange }: InventoryTagWrapperProps) { return ( -
+
- {/* Dropdown button toggle */} - - - - + {/* Dropdown open */} {isOpen && ( diff --git a/dashboard/components/inventory/components/filter/InventoryFilterField.tsx b/dashboard/components/inventory/components/filter/InventoryFilterField.tsx index 40685cf18..cd275e077 100644 --- a/dashboard/components/inventory/components/filter/InventoryFilterField.tsx +++ b/dashboard/components/inventory/components/filter/InventoryFilterField.tsx @@ -12,8 +12,7 @@ function InventoryFilterField({ handleField }: InventoryFilterFieldProps) {
)} diff --git a/dashboard/components/inventory/components/view/InventoryView.tsx b/dashboard/components/inventory/components/view/InventoryView.tsx index 20d92ac52..5de326d27 100644 --- a/dashboard/components/inventory/components/view/InventoryView.tsx +++ b/dashboard/components/inventory/components/view/InventoryView.tsx @@ -90,15 +90,14 @@ function InventoryView({
@@ -107,7 +106,7 @@ function InventoryView({ {/* Save as a view button */} {!router.query.view && ( )} diff --git a/dashboard/components/inventory/components/view/InventoryViewHeader.tsx b/dashboard/components/inventory/components/view/InventoryViewHeader.tsx index b6d7e6b2e..e51b9bb6c 100644 --- a/dashboard/components/inventory/components/view/InventoryViewHeader.tsx +++ b/dashboard/components/inventory/components/view/InventoryViewHeader.tsx @@ -5,7 +5,6 @@ import ExportCSV from '../../../export-csv/ExportCSV'; import AlertIcon from '../../../icons/AlertIcon'; import ChevronDownIcon from '../../../icons/ChevronDownIcon'; import DeleteIcon from '../../../icons/DeleteIcon'; -import DownloadIcon from '../../../icons/DownloadIcon'; import DuplicateIcon from '../../../icons/DuplicateIcon'; import EditIcon from '../../../icons/EditIcon'; import LinkIcon from '../../../icons/LinkIcon'; @@ -78,7 +77,7 @@ function InventoryViewHeader({ <>
{currentView.name} -
@@ -92,10 +91,8 @@ function InventoryViewHeader({
@@ -77,7 +51,7 @@ function Toast({ hasError, title, message, dismissToast }: ToastProp) {
-
diff --git a/dashboard/tailwind.config.js b/dashboard/tailwind.config.js index 87a813f09..6974545a7 100644 --- a/dashboard/tailwind.config.js +++ b/dashboard/tailwind.config.js @@ -47,6 +47,7 @@ module.exports = { 200: '#CFD7D7', 300: '#95A3A3', 400: '#697372', + 800: '#0C1717', 900: '#070011' } }, From 7da5fa9a2a44d60cefd4b16db665c2b845558a53 Mon Sep 17 00:00:00 2001 From: "Victor F. Santos" Date: Tue, 18 Apr 2023 15:11:08 +0200 Subject: [PATCH 11/26] chore: updating buttons on bulk actions bar --- .../components/InventoryTableBulkActions.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dashboard/components/inventory/components/InventoryTableBulkActions.tsx b/dashboard/components/inventory/components/InventoryTableBulkActions.tsx index 39bc1c17a..bece7ade0 100644 --- a/dashboard/components/inventory/components/InventoryTableBulkActions.tsx +++ b/dashboard/components/inventory/components/InventoryTableBulkActions.tsx @@ -24,8 +24,8 @@ function InventoryTableBulkActions({ return ( <> {bulkItems && bulkItems.length > 0 && ( -
-

+

+

{bulkItems.length} {bulkItems.length > 1 ? 'resources' : 'resource'}{' '} {inventoryStats && !query && @@ -34,25 +34,25 @@ function InventoryTableBulkActions({

{router.query.view && ( From 93dd9cc1e7009dd7c6f76e0ebd4687eff620fc38 Mon Sep 17 00:00:00 2001 From: "Victor F. Santos" Date: Tue, 18 Apr 2023 15:34:17 +0200 Subject: [PATCH 12/26] chore: updating button on github star banner --- dashboard/components/banner/Banner.tsx | 56 +++++++++++-------------- dashboard/components/icons/StarIcon.tsx | 20 +++++++++ 2 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 dashboard/components/icons/StarIcon.tsx diff --git a/dashboard/components/banner/Banner.tsx b/dashboard/components/banner/Banner.tsx index 575f3b1b4..1450aaca1 100644 --- a/dashboard/components/banner/Banner.tsx +++ b/dashboard/components/banner/Banner.tsx @@ -1,8 +1,9 @@ import Image from 'next/image'; import { useContext } from 'react'; +import classNames from 'classnames'; import formatNumber from '../../utils/formatNumber'; -import Button from '../button/Button'; import GlobalAppContext from '../layout/context/GlobalAppContext'; +import StarIcon from '../icons/StarIcon'; type BannerProps = { githubStars: number | undefined; @@ -13,9 +14,13 @@ function Banner({ githubStars }: BannerProps) { return (
Support Komiser by giving us a star on GitHub. @@ -26,36 +31,23 @@ function Banner({ githubStars }: BannerProps) { href="https://github.com/tailwarden/komiser" target="_blank" rel="noreferrer" - className="group" + className="group flex items-center gap-3 rounded border-[1.5px] border-white pl-4 text-sm text-white transition-colors hover:bg-white/10" > - + {formatNumber(githubStars)} +
)} diff --git a/dashboard/components/icons/StarIcon.tsx b/dashboard/components/icons/StarIcon.tsx new file mode 100644 index 000000000..fe4efe0a4 --- /dev/null +++ b/dashboard/components/icons/StarIcon.tsx @@ -0,0 +1,20 @@ +import { SVGProps } from 'react'; + +const StarIcon = (props: SVGProps) => ( + + + +); + +export default StarIcon; From 059f3eba8ab7b2898a52968d2b47b0921b6f0a5f Mon Sep 17 00:00:00 2001 From: "Victor F. Santos" Date: Tue, 18 Apr 2023 15:36:20 +0200 Subject: [PATCH 13/26] fix: remove unused flag in export csv button --- dashboard/components/export-csv/ExportCSVButton.stories.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/dashboard/components/export-csv/ExportCSVButton.stories.tsx b/dashboard/components/export-csv/ExportCSVButton.stories.tsx index 2ac770e55..be389d2d6 100644 --- a/dashboard/components/export-csv/ExportCSVButton.stories.tsx +++ b/dashboard/components/export-csv/ExportCSVButton.stories.tsx @@ -23,7 +23,6 @@ type Story = StoryObj; export const Primary: Story = { args: { disabled: false, - displayInTable: false, exportCSV: () => {} } }; From 1aa96bb669156e726a6c9c0ea26d3b19cb0ba0d0 Mon Sep 17 00:00:00 2001 From: "Victor F. Santos" Date: Tue, 18 Apr 2023 15:39:44 +0200 Subject: [PATCH 14/26] chore: change delete button from bulk actions --- .../components/inventory/components/InventorySidePanel.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashboard/components/inventory/components/InventorySidePanel.tsx b/dashboard/components/inventory/components/InventorySidePanel.tsx index e17969eb2..4b56a8723 100644 --- a/dashboard/components/inventory/components/InventorySidePanel.tsx +++ b/dashboard/components/inventory/components/InventorySidePanel.tsx @@ -189,7 +189,7 @@ function InventorySidePanel({ {page === 'delete' && ( <> -
+