Skip to content

Commit

Permalink
[8.11] Azure: Send empty batch resources when missing (#1475)
Browse files Browse the repository at this point in the history
Applied **only** to 8.11, fix for main should be re-done
  • Loading branch information
orestisfl authored Oct 25, 2023
1 parent ab7699c commit 0567f28
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 8 deletions.
86 changes: 78 additions & 8 deletions resources/fetching/fetchers/azure/batch_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,29 +57,65 @@ func (f *AzureBatchAssetFetcher) Fetch(ctx context.Context, cMetadata fetching.C
}

if len(assets) == 0 {
subs := f.provider.GetSubscriptions()
if len(subs) == 0 {
f.log.Errorf("no subscriptions and asset (%s, %s, %s) is empty, skipping", assetType, pair.SubType, pair.Type)
continue
}

// Hack backported into 8.11:
// Get the first subscription (should only be one), get the sub id and name and populate a mock resource
// with an empty array.
subId, subName := func() (string, string) {
for subId, subName := range subs {
return subId, subName
}
f.log.DPanic("unreachable")
return "", ""
}()

success := f.write(ctx, fetching.ResourceInfo{
Resource: &EmptyBatchResource{
Type: pair.Type,
SubType: pair.SubType,
SubId: subId,
SubName: subName,
},
CycleMetadata: cMetadata,
})
if !success {
return nil
}
continue
}

select {
case <-ctx.Done():
f.log.Infof("AzureBatchAssetFetcher.Fetch context err: %s", ctx.Err().Error())
return nil
// TODO: Groups by subscription id to create multiple batches of assets
case f.resourceCh <- fetching.ResourceInfo{
CycleMetadata: cMetadata,
success := f.write(ctx, fetching.ResourceInfo{
Resource: &AzureBatchResource{
// Every asset in the list has the same type and subtype
Type: pair.Type,
SubType: pair.SubType,
Assets: assets,
},
}:
CycleMetadata: cMetadata,
})
if !success {
return nil
}
}

return nil
}

func (f *AzureBatchAssetFetcher) write(ctx context.Context, resourceInfo fetching.ResourceInfo) bool {
select {
case <-ctx.Done():
f.log.Infof("AzureBatchAssetFetcher.Fetch context err: %s", ctx.Err().Error())
return false
case f.resourceCh <- resourceInfo:
}
return true
}

func (f *AzureBatchAssetFetcher) Stop() {}

type AzureBatchResource struct {
Expand Down Expand Up @@ -117,3 +153,37 @@ func (r *AzureBatchResource) GetElasticCommonData() (map[string]any, error) {
},
}, nil
}

type EmptyBatchResource struct {
Type string
SubType string
SubId string
SubName string
}

func (e *EmptyBatchResource) GetMetadata() (fetching.ResourceMetadata, error) {
id := fmt.Sprintf("%s-%s", e.SubType, e.SubId)
return fetching.ResourceMetadata{
ID: id,
Type: e.Type,
SubType: e.SubType,
Name: id,
Region: azurelib.GlobalRegion,
}, nil
}

func (e *EmptyBatchResource) GetData() any {
return []any{}
}

func (e *EmptyBatchResource) GetElasticCommonData() (map[string]any, error) {
return map[string]any{
"cloud": map[string]any{
"provider": "azure",
"account": map[string]any{
"id": e.SubId,
"name": e.SubName,
},
},
}, nil
}
54 changes: 54 additions & 0 deletions resources/fetching/fetchers/azure/batch_fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/suite"

"github.com/elastic/cloudbeat/resources/fetching"
"github.com/elastic/cloudbeat/resources/providers/azurelib"
"github.com/elastic/cloudbeat/resources/providers/azurelib/inventory"
"github.com/elastic/cloudbeat/resources/utils/testhelper"
)
Expand Down Expand Up @@ -158,6 +159,59 @@ func (s *AzureBatchAssetFetcherTestSuite) TestFetcher_Fetch() {
}
}

func (s *AzureBatchAssetFetcherTestSuite) TestFetcher_Fetch_EmptyBastion() {
mockInventoryService := inventory.NewMockServiceAPI(s.T())
mockInventoryService.EXPECT().ListAllAssetTypesByName(mock.AnythingOfType("[]string")).Return(nil, nil).Times(2)
mockInventoryService.EXPECT().GetSubscriptions().Return(map[string]string{"123": "name"}).Times(2)
fetcher := AzureBatchAssetFetcher{
log: testhelper.NewLogger(s.T()),
resourceCh: s.resourceCh,
provider: mockInventoryService,
}
s.Require().NoError(fetcher.Fetch(context.Background(), fetching.CycleMetadata{}))
results := testhelper.CollectResources(s.resourceCh)
s.Require().Len(results, 2)

for _, pair := range AzureBatchAssets {
resourceInfo := func() fetching.ResourceInfo {
for _, result := range results {
r, _ := result.GetMetadata()
if r.SubType == pair.SubType {
return result
}
}
s.Require().True(false)
panic("not reached")
}()

metadata, err := resourceInfo.GetMetadata()
s.Require().NoError(err)
s.Equal(fetching.ResourceMetadata{
ID: fmt.Sprintf("%s-123", pair.SubType),
Type: pair.Type,
SubType: pair.SubType,
Name: fmt.Sprintf("%s-123", pair.SubType),
Region: azurelib.GlobalRegion,
AwsAccountId: "",
AwsAccountAlias: "",
AwsOrganizationId: "",
AwsOrganizationName: "",
}, metadata)
s.Empty(resourceInfo.GetData())
ecs, err := resourceInfo.GetElasticCommonData()
s.Require().NoError(err)
s.Equal(map[string]any{
"cloud": map[string]any{
"provider": "azure",
"account": map[string]any{
"id": "123",
"name": "name",
},
},
}, ecs)
}
}

func findResult(results []fetching.ResourceInfo, assetType string) *fetching.ResourceInfo {
for _, result := range results {
if result.GetData().([]inventory.AzureAsset)[0].Type == assetType {
Expand Down
43 changes: 43 additions & 0 deletions resources/providers/azurelib/inventory/mock_service_api.go

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

5 changes: 5 additions & 0 deletions resources/providers/azurelib/inventory/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type AzureAsset struct {
type ServiceAPI interface {
// ListAllAssetTypesByName List all content types of the given assets types
ListAllAssetTypesByName(assets []string) ([]AzureAsset, error)
GetSubscriptions() map[string]string
}

type ProviderInitializerAPI interface {
Expand Down Expand Up @@ -110,6 +111,10 @@ func (p *ProviderInitializer) Init(ctx context.Context, log *logp.Logger, azureC
}, nil
}

func (p *Provider) GetSubscriptions() map[string]string {
return p.subscriptions
}

func (p *ProviderInitializer) getSubscriptionIds(ctx context.Context, azureConfig auth.AzureFactoryConfig) (map[string]string, error) {
// TODO: mockable

Expand Down

0 comments on commit 0567f28

Please sign in to comment.