Skip to content

Commit

Permalink
Merge pull request #1162 from cloudskiff/add_google_bigtable_table
Browse files Browse the repository at this point in the history
Add google_bigtable_table
  • Loading branch information
eliecharra authored Oct 25, 2021
2 parents 05abd2d + d583cef commit cfd2a3a
Show file tree
Hide file tree
Showing 14 changed files with 346 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/iac/terraform/state/terraform_state_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ func TestTerraformStateReader_Google_Resources(t *testing.T) {
{name: "compute subnetwork", dirName: "google_compute_subnetwork", wantErr: false},
{name: "compute disk", dirName: "google_compute_disk", wantErr: false},
{name: "bigtable instance", dirName: "google_bigtable_instance", wantErr: false},
{name: "bigtable table", dirName: "google_bigtable_table", wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"Id": "projects/cloudskiff-dev-elie/instances/tf-instance/tables/tf-table",
"Type": "google_bigtable_table",
"Attrs": {
"id": "projects/cloudskiff-dev-elie/instances/tf-instance/tables/tf-table",
"instance_name": "tf-instance",
"name": "tf-table",
"project": "cloudskiff-dev-elie"
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"version": 4,
"terraform_version": "0.15.5",
"serial": 53,
"lineage": "0738cef4-9d69-9ccc-aebd-1177cafa0aa9",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "google_bigtable_table",
"name": "table",
"provider": "provider[\"registry.terraform.io/hashicorp/google\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"column_family": [],
"id": "projects/cloudskiff-dev-elie/instances/tf-instance/tables/tf-table",
"instance_name": "tf-instance",
"name": "tf-table",
"project": "cloudskiff-dev-elie",
"split_keys": null
},
"sensitive_attributes": [],
"private": "bnVsbA==",
"dependencies": [
"google_bigtable_instance.instance"
]
}
]
}
]
}
53 changes: 53 additions & 0 deletions pkg/remote/google/google_bigtable_table_enumerator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package google

import (
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
"github.com/cloudskiff/driftctl/pkg/remote/google/repository"
"github.com/cloudskiff/driftctl/pkg/resource"
"github.com/cloudskiff/driftctl/pkg/resource/google"
"github.com/sirupsen/logrus"
)

type GoogleBigtableTableEnumerator struct {
repository repository.AssetRepository
factory resource.ResourceFactory
}

func NewGoogleBigtableTableEnumerator(repo repository.AssetRepository, factory resource.ResourceFactory) *GoogleBigtableTableEnumerator {
return &GoogleBigtableTableEnumerator{
repository: repo,
factory: factory,
}
}

func (e *GoogleBigtableTableEnumerator) SupportedType() resource.ResourceType {
return google.GoogleBigtableTableResourceType
}

func (e *GoogleBigtableTableEnumerator) Enumerate() ([]*resource.Resource, error) {
resources, err := e.repository.SearchAllBigtableTables()

if err != nil {
return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType()))
}

results := make([]*resource.Resource, 0, len(resources))

for _, res := range resources {
name, exist := res.GetResource().GetData().GetFields()["name"]
if !exist || name.GetStringValue() == "" {
logrus.WithField("name", res.GetName()).Warn("Unable to retrieve resource name")
continue
}
results = append(
results,
e.factory.CreateAbstractResource(
string(e.SupportedType()),
name.GetStringValue(),
map[string]interface{}{},
),
)
}

return results, err
}
1 change: 1 addition & 0 deletions pkg/remote/google/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func Init(version string, alerter *alerter.Alerter,
remoteLibrary.AddEnumerator(NewGoogleCloudFunctionsFunctionEnumerator(assetRepository, factory))
remoteLibrary.AddEnumerator(NewGoogleComputeDiskEnumerator(assetRepository, factory))
remoteLibrary.AddEnumerator(NewGoogleBigTableInstanceEnumerator(assetRepository, factory))
remoteLibrary.AddEnumerator(NewGoogleBigtableTableEnumerator(assetRepository, factory))

err = resourceSchemaRepository.Init(terraform.GOOGLE, provider.Version(), provider.Schema())
if err != nil {
Expand Down
7 changes: 7 additions & 0 deletions pkg/remote/google/repository/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const (
computeAddressAssetType = "compute.googleapis.com/Address"
cloudFunctionsFunction = "cloudfunctions.googleapis.com/CloudFunction"
bigtableInstanceAssetType = "bigtableadmin.googleapis.com/Instance"
bigtableTableAssetType = "bigtableadmin.googleapis.com/Table"
)

type AssetRepository interface {
Expand All @@ -44,6 +45,7 @@ type AssetRepository interface {
SearchAllFunctions() ([]*assetpb.Asset, error)
SearchAllSubnetworks() ([]*assetpb.ResourceSearchResult, error)
SearchAllBigtableInstances() ([]*assetpb.Asset, error)
SearchAllBigtableTables() ([]*assetpb.Asset, error)
}

type assetRepository struct {
Expand All @@ -67,6 +69,7 @@ func (s assetRepository) listAllResources(ty string) ([]*assetpb.Asset, error) {
AssetTypes: []string{
cloudFunctionsFunction,
bigtableInstanceAssetType,
bigtableTableAssetType,
},
}
var results []*assetpb.Asset
Expand Down Expand Up @@ -210,3 +213,7 @@ func (s assetRepository) SearchAllDisks() ([]*assetpb.ResourceSearchResult, erro
func (s assetRepository) SearchAllBigtableInstances() ([]*assetpb.Asset, error) {
return s.listAllResources(bigtableInstanceAssetType)
}

func (s assetRepository) SearchAllBigtableTables() ([]*assetpb.Asset, error) {
return s.listAllResources(bigtableTableAssetType)
}
23 changes: 23 additions & 0 deletions pkg/remote/google/repository/mock_AssetRepository.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

126 changes: 126 additions & 0 deletions pkg/remote/google_bigtable_scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,129 @@ func TestGoogleBigtableInstance(t *testing.T) {
})
}
}

func TestGoogleBigtableTable(t *testing.T) {

cases := []struct {
test string
assertExpected func(t *testing.T, got []*resource.Resource)
response []*assetpb.Asset
responseErr error
setupAlerterMock func(alerter *mocks.AlerterInterface)
wantErr error
}{
{
test: "no table",
response: []*assetpb.Asset{},
assertExpected: func(t *testing.T, got []*resource.Resource) {
assert.Len(t, got, 0)
},
},
{
test: "one resource returned",
assertExpected: func(t *testing.T, got []*resource.Resource) {
assert.Len(t, got, 1)
assert.Equal(t, "projects/cloudskiff-dev-elie/instances/tf-instance/tables/tf-table", got[0].ResourceId())
assert.Equal(t, "google_bigtable_table", got[0].ResourceType())
},
response: []*assetpb.Asset{
{
AssetType: "bigtableadmin.googleapis.com/Table",
Name: "//bigtable.googleapis.com/projects/cloudskiff-dev-elie/instances/tf-instance/tables/tf-table",
Resource: &assetpb.Resource{
Data: func() *structpb.Struct {
v, err := structpb.NewStruct(map[string]interface{}{
"name": "projects/cloudskiff-dev-elie/instances/tf-instance/tables/tf-table",
})
if err != nil {
t.Fatal(err)
}
return v
}(),
},
},
},
},
{
test: "one resource without resource data",
assertExpected: func(t *testing.T, got []*resource.Resource) {
assert.Len(t, got, 0)
},
response: []*assetpb.Asset{
{
AssetType: "bigtableadmin.googleapis.com/Table",
Name: "//bigtable.googleapis.com/projects/cloudskiff-dev-elie/instances/tf-instance/tables/tf-table",
},
},
},
{
test: "cannot list cloud functions",
assertExpected: func(t *testing.T, got []*resource.Resource) {
assert.Len(t, got, 0)
},
responseErr: status.Error(codes.PermissionDenied, "The caller does not have permission"),
setupAlerterMock: func(alerter *mocks.AlerterInterface) {
alerter.On(
"SendAlert",
"google_bigtable_table",
alerts.NewRemoteAccessDeniedAlert(
common.RemoteGoogleTerraform,
remoteerr.NewResourceListingError(
status.Error(codes.PermissionDenied, "The caller does not have permission"),
"google_bigtable_table",
),
alerts.EnumerationPhase,
),
).Once()
},
},
}

providerVersion := "3.78.0"
schemaRepository := testresource.InitFakeSchemaRepository("google", providerVersion)
googleresource.InitResourcesMetadata(schemaRepository)
factory := terraform.NewTerraformResourceFactory(schemaRepository)

for _, c := range cases {
t.Run(c.test, func(tt *testing.T) {
scanOptions := ScannerOptions{}
providerLibrary := terraform.NewProviderLibrary()
remoteLibrary := common.NewRemoteLibrary()

// Initialize mocks
alerter := &mocks.AlerterInterface{}
if c.setupAlerterMock != nil {
c.setupAlerterMock(alerter)
}

assetClient, err := testgoogle.NewFakeAssertServerWithList(c.response, c.responseErr)
if err != nil {
tt.Fatal(err)
}

realProvider, err := terraform2.InitTestGoogleProvider(providerLibrary, providerVersion)
if err != nil {
tt.Fatal(err)
}

repo := repository.NewAssetRepository(assetClient, realProvider.GetConfig(), cache.New(0))

remoteLibrary.AddEnumerator(google.NewGoogleBigtableTableEnumerator(repo, factory))

testFilter := &filter.MockFilter{}
testFilter.On("IsTypeIgnored", mock.Anything).Return(false)

s := NewScanner(remoteLibrary, alerter, scanOptions, testFilter)
got, err := s.Resources()
assert.Equal(tt, err, c.wantErr)
if err != nil {
return
}
alerter.AssertExpectations(tt)
testFilter.AssertExpectations(tt)
if c.assertExpected != nil {
c.assertExpected(t, got)
}
})
}
}
3 changes: 3 additions & 0 deletions pkg/resource/google/google_bigtable_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package google

const GoogleBigtableTableResourceType = "google_bigtable_table"
36 changes: 36 additions & 0 deletions pkg/resource/google/google_bigtable_table_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package google_test

import (
"testing"
"time"

"github.com/cloudskiff/driftctl/test"
"github.com/cloudskiff/driftctl/test/acceptance"
)

func TestAcc_Google_BigtableTable(t *testing.T) {
acceptance.Run(t, acceptance.AccTestCase{
TerraformVersion: "0.15.5",
Paths: []string{"./testdata/acc/google_bigtable_table"},
Args: []string{
"scan",
"--to", "gcp+tf",
},
Checks: []acceptance.AccCheck{
{
// New resources are not visible immediately on GCP api after an apply
// Logic below retry driftctl scan until we can retrieve the results (infra will be in sync) and for maximum 60 seconds
ShouldRetry: func(result *test.ScanResult, retryDuration time.Duration, retryCount uint8) bool {
return !result.IsSync() && retryDuration < time.Minute
},
Check: func(result *test.ScanResult, stdout string, err error) {
if err != nil {
t.Fatal(err)
}
result.AssertInfrastructureIsInSync()
result.AssertManagedCount(1)
},
},
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!google_bigtable_table

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit cfd2a3a

Please sign in to comment.