feat: implement memestore pkg
parent
a07f7d2544
commit
d1ed5e18d9
|
@ -9,6 +9,7 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/memstore"
|
||||
"github.com/cloudskiff/driftctl/pkg/remote/common"
|
||||
"github.com/cloudskiff/driftctl/pkg/telemetry"
|
||||
"github.com/fatih/color"
|
||||
|
@ -179,6 +180,7 @@ func NewScanCmd() *cobra.Command {
|
|||
}
|
||||
|
||||
func scanRun(opts *pkg.ScanOptions) error {
|
||||
store := memstore.New()
|
||||
selectedOutput := output.GetOutput(opts.Output, opts.Quiet)
|
||||
|
||||
c := make(chan os.Signal)
|
||||
|
@ -216,7 +218,7 @@ func scanRun(opts *pkg.ScanOptions) error {
|
|||
return err
|
||||
}
|
||||
|
||||
ctl := pkg.NewDriftCTL(scanner, iacSupplier, alerter, resFactory, opts, scanProgress, iacProgress, resourceSchemaRepository)
|
||||
ctl := pkg.NewDriftCTL(scanner, iacSupplier, alerter, resFactory, opts, scanProgress, iacProgress, resourceSchemaRepository, store)
|
||||
|
||||
go func() {
|
||||
<-c
|
||||
|
@ -237,7 +239,7 @@ func scanRun(opts *pkg.ScanOptions) error {
|
|||
globaloutput.Printf(color.WhiteString("Scan duration: %s\n", analysis.Duration.Round(time.Second)))
|
||||
|
||||
if !opts.DisableTelemetry {
|
||||
telemetry.SendTelemetry(analysis)
|
||||
telemetry.SendTelemetry(store)
|
||||
}
|
||||
|
||||
globaloutput.Printf(color.WhiteString("Provider version used to scan: %s. Use --tf-provider-version to use another version.\n"), resourceSchemaRepository.ProviderVersion.String())
|
||||
|
|
|
@ -2,9 +2,12 @@ package pkg
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/memstore"
|
||||
globaloutput "github.com/cloudskiff/driftctl/pkg/output"
|
||||
"github.com/cloudskiff/driftctl/pkg/version"
|
||||
"github.com/jmespath/go-jmespath"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
|
@ -45,6 +48,7 @@ type DriftCTL struct {
|
|||
iacProgress globaloutput.Progress
|
||||
resourceSchemaRepository resource.SchemaRepositoryInterface
|
||||
opts *ScanOptions
|
||||
s memstore.Store
|
||||
}
|
||||
|
||||
func NewDriftCTL(remoteSupplier resource.Supplier,
|
||||
|
@ -54,7 +58,8 @@ func NewDriftCTL(remoteSupplier resource.Supplier,
|
|||
opts *ScanOptions,
|
||||
scanProgress globaloutput.Progress,
|
||||
iacProgress globaloutput.Progress,
|
||||
resourceSchemaRepository resource.SchemaRepositoryInterface) *DriftCTL {
|
||||
resourceSchemaRepository resource.SchemaRepositoryInterface,
|
||||
store memstore.Store) *DriftCTL {
|
||||
return &DriftCTL{
|
||||
remoteSupplier,
|
||||
iacSupplier,
|
||||
|
@ -65,6 +70,7 @@ func NewDriftCTL(remoteSupplier resource.Supplier,
|
|||
iacProgress,
|
||||
resourceSchemaRepository,
|
||||
opts,
|
||||
store,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +144,13 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) {
|
|||
analysis.Duration = time.Since(start)
|
||||
analysis.Date = time.Now()
|
||||
|
||||
d.s.Bucket(memstore.TelemetryBucket).Set("version", version.Current())
|
||||
d.s.Bucket(memstore.TelemetryBucket).Set("os", runtime.GOOS)
|
||||
d.s.Bucket(memstore.TelemetryBucket).Set("arch", runtime.GOARCH)
|
||||
d.s.Bucket(memstore.TelemetryBucket).Set("total_resources", analysis.Summary().TotalResources)
|
||||
d.s.Bucket(memstore.TelemetryBucket).Set("total_managed", analysis.Summary().TotalManaged)
|
||||
d.s.Bucket(memstore.TelemetryBucket).Set("duration", uint(analysis.Duration.Seconds()+0.5))
|
||||
|
||||
return &analysis, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/cloudskiff/driftctl/pkg/alerter"
|
||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||
"github.com/cloudskiff/driftctl/pkg/filter"
|
||||
"github.com/cloudskiff/driftctl/pkg/memstore"
|
||||
"github.com/cloudskiff/driftctl/pkg/output"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource"
|
||||
"github.com/cloudskiff/driftctl/pkg/resource/aws"
|
||||
|
@ -98,7 +99,7 @@ func runTest(t *testing.T, cases TestCases) {
|
|||
iacProgress.On("Start").Return().Once()
|
||||
iacProgress.On("Stop").Return().Once()
|
||||
|
||||
driftctl := pkg.NewDriftCTL(remoteSupplier, stateSupplier, testAlerter, resourceFactory, c.options, scanProgress, iacProgress, repo)
|
||||
driftctl := pkg.NewDriftCTL(remoteSupplier, stateSupplier, testAlerter, resourceFactory, c.options, scanProgress, iacProgress, repo, memstore.New())
|
||||
|
||||
analysis, err := driftctl.Run()
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package memstore
|
||||
|
||||
const (
|
||||
// TelemetryBucket is the name of the store bucket used by the telemetry service
|
||||
TelemetryBucket = "telemetry"
|
||||
)
|
|
@ -0,0 +1,63 @@
|
|||
package memstore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Bucket interface {
|
||||
Set(string, interface{})
|
||||
Get(string) interface{}
|
||||
MarshallJSON() ([]byte, error)
|
||||
}
|
||||
|
||||
type Store interface {
|
||||
Bucket(string) Bucket
|
||||
}
|
||||
|
||||
type store struct {
|
||||
m *sync.Mutex
|
||||
s map[string]*bucket
|
||||
}
|
||||
|
||||
type bucket struct {
|
||||
m *sync.RWMutex
|
||||
s map[string]interface{}
|
||||
}
|
||||
|
||||
func New() Store {
|
||||
return &store{
|
||||
m: &sync.Mutex{},
|
||||
s: map[string]*bucket{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s store) Bucket(name string) Bucket {
|
||||
s.m.Lock()
|
||||
defer s.m.Unlock()
|
||||
|
||||
if _, ok := s.s[name]; !ok {
|
||||
s.s[name] = &bucket{
|
||||
m: &sync.RWMutex{},
|
||||
s: map[string]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
return s.s[name]
|
||||
}
|
||||
|
||||
func (b bucket) Set(key string, value interface{}) {
|
||||
b.m.Lock()
|
||||
defer b.m.Unlock()
|
||||
b.s[key] = value
|
||||
}
|
||||
|
||||
func (b bucket) Get(key string) interface{} {
|
||||
b.m.RLock()
|
||||
defer b.m.RUnlock()
|
||||
return b.s[key]
|
||||
}
|
||||
|
||||
func (b bucket) MarshallJSON() ([]byte, error) {
|
||||
return json.Marshal(b.s)
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package memstore
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/cloudskiff/driftctl/test/resource"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStore(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
bucket string
|
||||
values map[string]interface{}
|
||||
expectedJSON string
|
||||
}{
|
||||
{
|
||||
name: "test basic store usage",
|
||||
bucket: "test-bucket-1",
|
||||
values: map[string]interface{}{
|
||||
"test-value_|)": 13,
|
||||
"duration_key": "23",
|
||||
"null": nil,
|
||||
"res": &resource.FakeResource{Id: "id", Type: "type"},
|
||||
},
|
||||
expectedJSON: `{"duration_key":"23","null":null,"res":{"Id":"id","Type":"type","Attrs":null},"test-value_|)":13}`,
|
||||
},
|
||||
{
|
||||
name: "test empty bucket",
|
||||
bucket: "test-bucket-empty",
|
||||
values: map[string]interface{}{},
|
||||
expectedJSON: `{}`,
|
||||
},
|
||||
{
|
||||
name: "test bucket with nil values",
|
||||
bucket: "test-bucket-empty",
|
||||
values: map[string]interface{}{
|
||||
"version": nil,
|
||||
"total_resources": nil,
|
||||
"total_managed": nil,
|
||||
},
|
||||
expectedJSON: `{"total_managed":null,"total_resources":null,"version":null}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
kv := New()
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for key, val := range tt.values {
|
||||
wg.Add(1)
|
||||
go func(key string, val interface{}, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
kv.Bucket(tt.bucket).Set(key, val)
|
||||
assert.Equal(t, val, kv.Bucket(tt.bucket).Get(key))
|
||||
assert.Equal(t, nil, kv.Bucket("dummybucketname").Get(key))
|
||||
}(key, val, &wg)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
b, err := kv.Bucket(tt.bucket).MarshallJSON()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tt.expectedJSON, string(b))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -2,40 +2,14 @@ package telemetry
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"runtime"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||
"github.com/cloudskiff/driftctl/pkg/version"
|
||||
"github.com/cloudskiff/driftctl/pkg/memstore"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type telemetry struct {
|
||||
Version string `json:"version"`
|
||||
Os string `json:"os"`
|
||||
Arch string `json:"arch"`
|
||||
TotalResources int `json:"total_resources"`
|
||||
TotalManaged int `json:"total_managed"`
|
||||
Duration uint `json:"duration"`
|
||||
}
|
||||
|
||||
func SendTelemetry(analysis *analyser.Analysis) {
|
||||
|
||||
if analysis == nil {
|
||||
return
|
||||
}
|
||||
|
||||
t := telemetry{
|
||||
Version: version.Current(),
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
TotalResources: analysis.Summary().TotalResources,
|
||||
TotalManaged: analysis.Summary().TotalManaged,
|
||||
Duration: uint(analysis.Duration.Seconds() + 0.5),
|
||||
}
|
||||
|
||||
body, err := json.Marshal(t)
|
||||
func SendTelemetry(s memstore.Store) {
|
||||
body, err := s.Bucket(memstore.TelemetryBucket).MarshallJSON()
|
||||
if err != nil {
|
||||
logrus.Debug(err)
|
||||
return
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cloudskiff/driftctl/pkg/analyser"
|
||||
"github.com/cloudskiff/driftctl/pkg/memstore"
|
||||
"github.com/cloudskiff/driftctl/pkg/version"
|
||||
"github.com/cloudskiff/driftctl/test/resource"
|
||||
"github.com/jarcoal/httpmock"
|
||||
|
@ -15,6 +16,14 @@ import (
|
|||
)
|
||||
|
||||
func TestSendTelemetry(t *testing.T) {
|
||||
type telemetry struct {
|
||||
Version string `json:"version"`
|
||||
Os string `json:"os"`
|
||||
Arch string `json:"arch"`
|
||||
TotalResources int `json:"total_resources"`
|
||||
TotalManaged int `json:"total_managed"`
|
||||
Duration uint `json:"duration"`
|
||||
}
|
||||
|
||||
httpmock.Activate()
|
||||
defer httpmock.DeactivateAndReset()
|
||||
|
@ -64,6 +73,17 @@ func TestSendTelemetry(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := memstore.New()
|
||||
|
||||
if tt.analysis != nil {
|
||||
s.Bucket(memstore.TelemetryBucket).Set("version", version.Current())
|
||||
s.Bucket(memstore.TelemetryBucket).Set("os", runtime.GOOS)
|
||||
s.Bucket(memstore.TelemetryBucket).Set("arch", runtime.GOARCH)
|
||||
s.Bucket(memstore.TelemetryBucket).Set("total_resources", tt.analysis.Summary().TotalResources)
|
||||
s.Bucket(memstore.TelemetryBucket).Set("total_managed", tt.analysis.Summary().TotalManaged)
|
||||
s.Bucket(memstore.TelemetryBucket).Set("duration", uint(tt.analysis.Duration.Seconds()+0.5))
|
||||
}
|
||||
|
||||
httpmock.Reset()
|
||||
if tt.expectedBody != nil {
|
||||
httpmock.RegisterResponder(
|
||||
|
@ -91,7 +111,7 @@ func TestSendTelemetry(t *testing.T) {
|
|||
},
|
||||
)
|
||||
}
|
||||
SendTelemetry(tt.analysis)
|
||||
SendTelemetry(s)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue