feat: add google_compute_instance_group
parent
4cf88893d4
commit
dcc0130237
|
@ -0,0 +1,58 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
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 GoogleComputeInstanceGroupEnumerator struct {
|
||||
repository repository.AssetRepository
|
||||
factory resource.ResourceFactory
|
||||
}
|
||||
|
||||
func NewGoogleComputeInstanceGroupEnumerator(repo repository.AssetRepository, factory resource.ResourceFactory) *GoogleComputeInstanceGroupEnumerator {
|
||||
return &GoogleComputeInstanceGroupEnumerator{
|
||||
repository: repo,
|
||||
factory: factory,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *GoogleComputeInstanceGroupEnumerator) SupportedType() resource.ResourceType {
|
||||
return google.GoogleComputeInstanceGroupResourceType
|
||||
}
|
||||
|
||||
func (e *GoogleComputeInstanceGroupEnumerator) Enumerate() ([]*resource.Resource, error) {
|
||||
groups, err := e.repository.SearchAllInstanceGroups()
|
||||
if err != nil {
|
||||
return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType()))
|
||||
}
|
||||
|
||||
results := make([]*resource.Resource, 0, len(groups))
|
||||
for _, res := range groups {
|
||||
splittedName := strings.Split(res.GetName(), "/")
|
||||
if len(splittedName) != 9 {
|
||||
logrus.WithField("name", res.GetName()).Error("Unable to decode project from instance group name")
|
||||
continue
|
||||
}
|
||||
project := splittedName[4]
|
||||
results = append(
|
||||
results,
|
||||
e.factory.CreateAbstractResource(
|
||||
string(e.SupportedType()),
|
||||
trimResourceName(res.GetName()),
|
||||
map[string]interface{}{
|
||||
"display_name": res.GetDisplayName(),
|
||||
"project": project,
|
||||
"location": res.GetLocation(),
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return results, err
|
||||
}
|
|
@ -69,6 +69,9 @@ func Init(version string, alerter *alerter.Alerter,
|
|||
|
||||
remoteLibrary.AddEnumerator(NewGoogleDNSManagedZoneEnumerator(assetRepository, factory))
|
||||
|
||||
remoteLibrary.AddEnumerator(NewGoogleComputeInstanceGroupEnumerator(assetRepository, factory))
|
||||
remoteLibrary.AddDetailsFetcher(google.GoogleComputeInstanceGroupResourceType, common.NewGenericDetailsFetcher(google.GoogleComputeInstanceGroupResourceType, provider, deserializer))
|
||||
|
||||
err = resourceSchemaRepository.Init(terraform.GOOGLE, provider.Version(), provider.Schema())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -13,12 +13,13 @@ import (
|
|||
|
||||
// https://cloud.google.com/asset-inventory/docs/supported-asset-types#supported_resource_types
|
||||
const (
|
||||
storageBucketAssetType = "storage.googleapis.com/Bucket"
|
||||
computeFirewallAssetType = "compute.googleapis.com/Firewall"
|
||||
computeRouterAssetType = "compute.googleapis.com/Router"
|
||||
computeInstanceAssetType = "compute.googleapis.com/Instance"
|
||||
computeNetworkAssetType = "compute.googleapis.com/Network"
|
||||
dnsManagedZoneAssetType = "dns.googleapis.com/ManagedZone"
|
||||
storageBucketAssetType = "storage.googleapis.com/Bucket"
|
||||
computeFirewallAssetType = "compute.googleapis.com/Firewall"
|
||||
computeRouterAssetType = "compute.googleapis.com/Router"
|
||||
computeInstanceAssetType = "compute.googleapis.com/Instance"
|
||||
computeNetworkAssetType = "compute.googleapis.com/Network"
|
||||
dnsManagedZoneAssetType = "dns.googleapis.com/ManagedZone"
|
||||
computeInstanceGroupAssetType = "compute.googleapis.com/InstanceGroup"
|
||||
)
|
||||
|
||||
type AssetRepository interface {
|
||||
|
@ -28,6 +29,7 @@ type AssetRepository interface {
|
|||
SearchAllInstances() ([]*assetpb.ResourceSearchResult, error)
|
||||
SearchAllNetworks() ([]*assetpb.ResourceSearchResult, error)
|
||||
SearchAllDNSManagedZones() ([]*assetpb.ResourceSearchResult, error)
|
||||
SearchAllInstanceGroups() ([]*assetpb.ResourceSearchResult, error)
|
||||
}
|
||||
|
||||
type assetRepository struct {
|
||||
|
@ -54,6 +56,7 @@ func (s assetRepository) searchAllResources(ty string) ([]*assetpb.ResourceSearc
|
|||
computeInstanceAssetType,
|
||||
computeNetworkAssetType,
|
||||
dnsManagedZoneAssetType,
|
||||
computeInstanceGroupAssetType,
|
||||
},
|
||||
}
|
||||
var results []*assetpb.ResourceSearchResult
|
||||
|
@ -113,3 +116,7 @@ func (s assetRepository) SearchAllNetworks() ([]*assetpb.ResourceSearchResult, e
|
|||
func (s assetRepository) SearchAllDNSManagedZones() ([]*assetpb.ResourceSearchResult, error) {
|
||||
return s.searchAllResources(dnsManagedZoneAssetType)
|
||||
}
|
||||
|
||||
func (s assetRepository) SearchAllInstanceGroups() ([]*assetpb.ResourceSearchResult, error) {
|
||||
return s.searchAllResources(computeInstanceGroupAssetType)
|
||||
}
|
||||
|
|
|
@ -81,6 +81,29 @@ func (_m *MockAssetRepository) SearchAllFirewalls() ([]*asset.ResourceSearchResu
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// SearchAllInstanceGroups provides a mock function with given fields:
|
||||
func (_m *MockAssetRepository) SearchAllInstanceGroups() ([]*asset.ResourceSearchResult, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 []*asset.ResourceSearchResult
|
||||
if rf, ok := ret.Get(0).(func() []*asset.ResourceSearchResult); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*asset.ResourceSearchResult)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SearchAllInstances provides a mock function with given fields:
|
||||
func (_m *MockAssetRepository) SearchAllInstances() ([]*asset.ResourceSearchResult, error) {
|
||||
ret := _m.Called()
|
||||
|
|
|
@ -499,3 +499,126 @@ func TestGoogleComputeNetwork(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoogleComputeInstanceGroup(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
test string
|
||||
dirName string
|
||||
response []*assetpb.ResourceSearchResult
|
||||
responseErr error
|
||||
setupAlerterMock func(alerter *mocks.AlerterInterface)
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
test: "no instance group",
|
||||
dirName: "google_compute_instance_group_empty",
|
||||
response: []*assetpb.ResourceSearchResult{},
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
test: "multiple instance groups",
|
||||
dirName: "google_compute_instance_group",
|
||||
response: []*assetpb.ResourceSearchResult{
|
||||
{
|
||||
AssetType: "compute.googleapis.com/InstanceGroup",
|
||||
DisplayName: "driftctl-unittest-1",
|
||||
Name: "//compute.googleapis.com/projects/driftctl-qa-1/zones/us-central1-a/instanceGroups/driftctl-unittest-1",
|
||||
},
|
||||
{
|
||||
AssetType: "compute.googleapis.com/InstanceGroup",
|
||||
DisplayName: "driftctl-unittest-2",
|
||||
Name: "//compute.googleapis.com/projects/driftctl-qa-1/zones/us-central1-a/instanceGroups/driftctl-unittest-2",
|
||||
},
|
||||
{
|
||||
AssetType: "compute.googleapis.com/InstanceGroup",
|
||||
DisplayName: "driftctl-unittest-3",
|
||||
Name: "//compute.googleapis.com/projects/driftctl-qa-1/zones/us-central1-a/instanceGroups/driftctl-unittest-3",
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
{
|
||||
test: "cannot list instance groups",
|
||||
dirName: "google_compute_instance_group_empty",
|
||||
responseErr: status.Error(codes.PermissionDenied, "The caller does not have permission"),
|
||||
setupAlerterMock: func(alerter *mocks.AlerterInterface) {
|
||||
alerter.On(
|
||||
"SendAlert",
|
||||
"google_compute_instance_group",
|
||||
alerts.NewRemoteAccessDeniedAlert(
|
||||
common.RemoteGoogleTerraform,
|
||||
remoteerr.NewResourceListingError(
|
||||
status.Error(codes.PermissionDenied, "The caller does not have permission"),
|
||||
"google_compute_instance_group",
|
||||
),
|
||||
alerts.EnumerationPhase,
|
||||
),
|
||||
).Once()
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
providerVersion := "3.78.0"
|
||||
resType := resource.ResourceType(googleresource.GoogleComputeInstanceGroupResourceType)
|
||||
schemaRepository := testresource.InitFakeSchemaRepository("google", providerVersion)
|
||||
googleresource.InitResourcesMetadata(schemaRepository)
|
||||
factory := terraform.NewTerraformResourceFactory(schemaRepository)
|
||||
deserializer := resource.NewDeserializer(factory)
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.test, func(tt *testing.T) {
|
||||
shouldUpdate := c.dirName == *goldenfile.Update
|
||||
|
||||
scanOptions := ScannerOptions{Deep: true}
|
||||
providerLibrary := terraform.NewProviderLibrary()
|
||||
remoteLibrary := common.NewRemoteLibrary()
|
||||
|
||||
// Initialize mocks
|
||||
alerter := &mocks.AlerterInterface{}
|
||||
if c.setupAlerterMock != nil {
|
||||
c.setupAlerterMock(alerter)
|
||||
}
|
||||
|
||||
assetClient, err := testgoogle.NewFakeAssetServer(c.response, c.responseErr)
|
||||
if err != nil {
|
||||
tt.Fatal(err)
|
||||
}
|
||||
|
||||
realProvider, err := terraform2.InitTestGoogleProvider(providerLibrary, providerVersion)
|
||||
if err != nil {
|
||||
tt.Fatal(err)
|
||||
}
|
||||
provider := terraform2.NewFakeTerraformProvider(realProvider)
|
||||
provider.WithResponse(c.dirName)
|
||||
|
||||
// Replace mock by real resources if we are in update mode
|
||||
if shouldUpdate {
|
||||
err = realProvider.Init()
|
||||
if err != nil {
|
||||
tt.Fatal(err)
|
||||
}
|
||||
provider.ShouldUpdate()
|
||||
}
|
||||
|
||||
repo := repository.NewAssetRepository(assetClient, realProvider.GetConfig(), cache.New(0))
|
||||
|
||||
remoteLibrary.AddEnumerator(google.NewGoogleComputeInstanceGroupEnumerator(repo, factory))
|
||||
remoteLibrary.AddDetailsFetcher(googleresource.GoogleComputeInstanceGroupResourceType, common.NewGenericDetailsFetcher(googleresource.GoogleComputeInstanceGroupResourceType, provider, deserializer))
|
||||
|
||||
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)
|
||||
test.TestAgainstGoldenFile(got, resType.String(), c.dirName, provider, deserializer, shouldUpdate, tt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[]
|
|
@ -0,0 +1,12 @@
|
|||
provider "google" {}
|
||||
|
||||
resource "google_compute_network" "default" {
|
||||
name = "test-network"
|
||||
}
|
||||
|
||||
resource "google_compute_instance_group" "test" {
|
||||
name = "terraform-test"
|
||||
description = "Terraform test instance group"
|
||||
zone = "us-central1-a"
|
||||
network = google_compute_network.default.id
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package google
|
||||
|
||||
import "github.com/cloudskiff/driftctl/pkg/resource"
|
||||
|
||||
const GoogleComputeInstanceGroupResourceType = "google_compute_instance_group"
|
||||
|
||||
func initGoogleComputeInstanceGroupMetadata(resourceSchemaRepository resource.SchemaRepositoryInterface) {
|
||||
resourceSchemaRepository.SetResolveReadAttributesFunc(GoogleComputeInstanceGroupResourceType, func(res *resource.Resource) map[string]string {
|
||||
return map[string]string{
|
||||
"name": *res.Attributes().GetString("display_name"),
|
||||
"project": *res.Attributes().GetString("project"),
|
||||
"zone": *res.Attributes().GetString("location"),
|
||||
}
|
||||
})
|
||||
resourceSchemaRepository.SetHumanReadableAttributesFunc(GoogleComputeInstanceGroupResourceType, func(res *resource.Resource) map[string]string {
|
||||
attrs := make(map[string]string)
|
||||
if v := res.Attributes().GetString("display_name"); v != nil && *v != "" {
|
||||
attrs["Name"] = *v
|
||||
}
|
||||
return attrs
|
||||
})
|
||||
}
|
|
@ -8,4 +8,5 @@ func InitResourcesMetadata(resourceSchemaRepository resource.SchemaRepositoryInt
|
|||
initGoogleComputeRouterMetadata(resourceSchemaRepository)
|
||||
initGoogleComputeNetworkMetadata(resourceSchemaRepository)
|
||||
initGoogleStorageBucketIamBMemberMetadata(resourceSchemaRepository)
|
||||
initGoogleComputeInstanceGroupMetadata(resourceSchemaRepository)
|
||||
}
|
||||
|
|
|
@ -140,7 +140,8 @@ var supportedTypes = map[string]ResourceTypeMeta{
|
|||
"google_storage_bucket_iam_policy": {children: []ResourceType{
|
||||
"google_storage_bucket_iam_member",
|
||||
}},
|
||||
"google_dns_managed_zone": {},
|
||||
"google_dns_managed_zone": {},
|
||||
"google_compute_instance_group": {},
|
||||
|
||||
"azurerm_storage_account": {},
|
||||
"azurerm_storage_container": {},
|
||||
|
|
Loading…
Reference in New Issue