Skip to content

Commit

Permalink
feat: Inventory Table
Browse files Browse the repository at this point in the history
  • Loading branch information
cmendible committed Jul 30, 2024
1 parent 2ab8e27 commit 69673f6
Show file tree
Hide file tree
Showing 56 changed files with 123 additions and 867 deletions.
40 changes: 25 additions & 15 deletions internal/azqr/azqr.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,26 @@ type (
}

AzqrRecommendation struct {
RecommendationID string
ResourceType string
Recommendation string
Category RecommendationCategory
Impact RecommendationImpact
LearnMoreUrl string
Eval func(target interface{}, scanContext *ScanContext) (bool, string)
RecommendationID string
ResourceType string
Recommendation string
Category RecommendationCategory
Impact RecommendationImpact
RecommendationType RecommendationType
LearnMoreUrl string
Eval func(target interface{}, scanContext *ScanContext) (bool, string)
}

AzqrResult struct {
RecommendationID string
ResourceType string
Category RecommendationCategory
Recommendation string
Impact RecommendationImpact
LearnMoreUrl string
Result string
NotCompliant bool
RecommendationID string
ResourceType string
Recommendation string
Category RecommendationCategory
Impact RecommendationImpact
RecommendationType RecommendationType
LearnMoreUrl string
NotCompliant bool
Result string
}

Resource struct {
Expand All @@ -86,6 +88,10 @@ type (
Type string
Location string
Name string
SkuName string
SkuTier string
Kind string
SLA string
}

ResourceTypeCount struct {
Expand Down Expand Up @@ -147,6 +153,7 @@ type (

RecommendationImpact string
RecommendationCategory string
RecommendationType string
)

const (
Expand All @@ -161,6 +168,9 @@ const (
CategorySecurity RecommendationCategory = "Security"
CategoryGovernance RecommendationCategory = "Governance"
CategoryOtherBestPractices RecommendationCategory = "Other Best Practices"

TypeRecommendation RecommendationType = ""
TypeSLA RecommendationType = "SLA"
)

func (r *AzqrRecommendation) ToAzureAprlRecommendation() AprlRecommendation {
Expand Down
11 changes: 7 additions & 4 deletions internal/renderers/csv/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,18 @@ import (
)

func CreateCsvReport(data *renderers.ReportData) {
records := data.ServicesTable()
writeData(records, data.OutputFileName, "services")

records = data.RecommendationsTable()
records := data.RecommendationsTable()
writeData(records, data.OutputFileName, "recommendations")

records = data.ImpactedTable()
writeData(records, data.OutputFileName, "impacted")

records = data.ResourceTypesTable()
writeData(records, data.OutputFileName, "resourceType")

records = data.ResourcesTable()
writeData(records, data.OutputFileName, "inventory")

records = data.DefenderTable()
writeData(records, data.OutputFileName, "defender")

Expand Down
4 changes: 2 additions & 2 deletions internal/renderers/excel/excel.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ func CreateExcelReport(data *renderers.ReportData) {
lastRow := renderRecommendations(f, data)
renderImpactedResources(f, data)
renderResourceTypes(f, data)
renderServices(f, data)
renderDefender(f, data)
renderResources(f, data)
renderAdvisor(f, data)
renderDefender(f, data)
renderCosts(f, data)
renderRecommendationsPivotTables(f, lastRow)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ import (
"github.com/xuri/excelize/v2"
)

func renderServices(f *excelize.File, data *renderers.ReportData) {
if len(data.AzqrData) > 0 {
_, err := f.NewSheet("Services")
func renderResources(f *excelize.File, data *renderers.ReportData) {
sheetName := "Inventory"
if len(data.Resources) > 0 {
_, err := f.NewSheet(sheetName)
if err != nil {
log.Fatal().Err(err).Msg("Failed to create Services sheet")
log.Fatal().Err(err).Msg("Failed to create Inventory sheet")
}

records := data.ServicesTable()
records := data.ResourcesTable()
headers := records[0]
records = records[1:]

createFirstRow(f, "Services", headers)
createFirstRow(f, sheetName, headers)

currentRow := 4
for _, row := range records {
Expand All @@ -31,14 +32,14 @@ func renderServices(f *excelize.File, data *renderers.ReportData) {
if err != nil {
log.Fatal().Err(err).Msg("Failed to get cell")
}
err = f.SetSheetRow("Services", cell, &row)
err = f.SetSheetRow(sheetName, cell, &row)
if err != nil {
log.Fatal().Err(err).Msg("Failed to set row")
}
setHyperLink(f, "Services", 12, currentRow)
setHyperLink(f, sheetName, 12, currentRow)
}

configureSheet(f, "Services", headers, currentRow)
configureSheet(f, sheetName, headers, currentRow)
} else {
log.Info().Msg("Skipping Services. No data to render")
}
Expand Down
50 changes: 18 additions & 32 deletions internal/renderers/report_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type (
AdvisorData []scanners.AdvisorResult
CostData *scanners.CostResult
Recomendations map[string]map[string]azqr.AprlRecommendation
Resources []*azqr.Resource
ResourceTypeCount []azqr.ResourceTypeCount
}

Expand Down Expand Up @@ -63,37 +64,26 @@ type (
}
)

func (rd *ReportData) ServicesTable() [][]string {
headers := []string{"Subscription", "Subscription Name", "Resource Group", "Location", "Type", "Service Name", "Compliant", "Impact", "Category", "Recommendation", "Result", "Learn", "RId"}
func (rd *ReportData) ResourcesTable() [][]string {
headers := []string{"Subscription ID", "Resource Group", "Location", "Type", "Name", "Sku Name", "Sku Tier", "Kind", "SLA", "Resource ID"}

rbroken := [][]string{}
rok := [][]string{}
for _, d := range rd.AzqrData {
for _, r := range d.Recommendations {
row := []string{
MaskSubscriptionID(d.SubscriptionID, rd.Mask),
d.SubscriptionName,
d.ResourceGroup,
rd.parseLocation(d.Location),
d.Type,
d.ServiceName,
fmt.Sprintf("%t", !r.NotCompliant),
string(r.Impact),
string(r.Category),
r.Recommendation,
r.Result,
r.LearnMoreUrl,
r.RecommendationID,
}
if r.NotCompliant {
rbroken = append([][]string{row}, rbroken...)
} else {
rok = append([][]string{row}, rok...)
}
rows := [][]string{}
for _, r := range rd.Resources {
row := []string{
MaskSubscriptionID(r.SubscriptionID, rd.Mask),
r.ResourceGroup,
r.Location,
r.Type,
r.Name,
r.SkuName,
r.SkuTier,
r.Kind,
"",
r.ID,
}
rows = append(rows, row)
}

rows := append(rbroken, rok...)
rows = append([][]string{headers}, rows...)
return rows
}
Expand Down Expand Up @@ -198,7 +188,7 @@ func (rd *ReportData) DefenderTable() [][]string {
}

func (rd *ReportData) AdvisorTable() [][]string {
headers := []string{"Subscription", "Subscription Name", "Type", "Name", "Category", "Impact", "Description", "ResourceID", "RecommendationID"}
headers := []string{"Subscription", "Subscription Name", "Type", "Name", "Category", "Impact", "Description", "ResourceID", "RecommendationID"}
rows := [][]string{}
for _, d := range rd.AdvisorData {
row := []string{
Expand Down Expand Up @@ -302,10 +292,6 @@ func (rd *ReportData) ResourceTypesTable() [][]string {
return rows
}

func (rd *ReportData) parseLocation(location string) string {
return strings.ToLower(strings.ReplaceAll(location, " ", ""))
}

func NewReportData(outputFile string, mask bool) ReportData {
return ReportData{
OutputFileName: outputFile,
Expand Down
1 change: 1 addition & 0 deletions internal/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func (sc Scanner) Scan(params *ScanParams) {

resourceScanner := scanners.ResourceScanner{}
reportData.ResourceTypeCount = resourceScanner.GetCountPerResourceType(ctx, cred, subscriptions, reportData.Recomendations)
reportData.Resources = resourceScanner.GetAllResources(ctx, cred, subscriptions)

// render excel report
excel.CreateExcelReport(&reportData)
Expand Down
12 changes: 0 additions & 12 deletions internal/scanners/afd/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,6 @@ func (a *FrontDoorScanner) GetRecommendations() map[string]azqr.AzqrRecommendati
},
LearnMoreUrl: "https://www.azure.cn/en-us/support/sla/cdn/",
},
"afd-005": {
RecommendationID: "afd-005",
ResourceType: "Microsoft.Cdn/profiles",
Category: azqr.CategoryHighAvailability,
Recommendation: "Azure FrontDoor SKU",
Impact: azqr.ImpactHigh,
Eval: func(target interface{}, scanContext *azqr.ScanContext) (bool, string) {
c := target.(*armcdn.Profile)
return false, string(*c.SKU.Name)
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/frontdoor/standard-premium/tier-comparison",
},
"afd-006": {
RecommendationID: "afd-006",
ResourceType: "Microsoft.Cdn/profiles",
Expand Down
16 changes: 0 additions & 16 deletions internal/scanners/afd/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,6 @@ func TestFrontDoorScanner_Rules(t *testing.T) {
result: "99.99%",
},
},
{
name: "FrontDoorScanner SKU",
fields: fields{
rule: "afd-005",
target: &armcdn.Profile{
SKU: &armcdn.SKU{
Name: to.Ptr(armcdn.SKUNameStandardMicrosoft),
},
},
scanContext: &azqr.ScanContext{},
},
want: want{
broken: false,
result: "Standard_Microsoft",
},
},
{
name: "FrontDoorScanner CAF",
fields: fields{
Expand Down
12 changes: 0 additions & 12 deletions internal/scanners/afw/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,6 @@ func (a *FirewallScanner) GetRecommendations() map[string]azqr.AzqrRecommendatio
},
LearnMoreUrl: "https://www.microsoft.com/licensing/docs/view/Service-Level-Agreements-SLA-for-Online-Services",
},
"afw-005": {
RecommendationID: "afw-005",
ResourceType: "Microsoft.Network/azureFirewalls",
Category: azqr.CategoryHighAvailability,
Recommendation: "Azure Firewall SKU",
Impact: azqr.ImpactHigh,
Eval: func(target interface{}, scanContext *azqr.ScanContext) (bool, string) {
c := target.(*armnetwork.AzureFirewall)
return false, string(*c.Properties.SKU.Name)
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/firewall/choose-firewall-sku",
},
"afw-006": {
RecommendationID: "afw-006",
ResourceType: "Microsoft.Network/azureFirewalls",
Expand Down
18 changes: 0 additions & 18 deletions internal/scanners/afw/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,6 @@ func TestFirewallScanner_Rules(t *testing.T) {
result: "99.99%",
},
},
{
name: "FirewallScanner SKU",
fields: fields{
rule: "afw-005",
target: &armnetwork.AzureFirewall{
Properties: &armnetwork.AzureFirewallPropertiesFormat{
SKU: &armnetwork.AzureFirewallSKU{
Name: to.Ptr(armnetwork.AzureFirewallSKUNameAZFWVnet),
},
},
},
scanContext: &azqr.ScanContext{},
},
want: want{
broken: false,
result: "AZFW_VNet",
},
},
{
name: "FirewallScanner CAF",
fields: fields{
Expand Down
12 changes: 0 additions & 12 deletions internal/scanners/agw/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,6 @@ func (a *ApplicationGatewayScanner) GetRecommendations() map[string]azqr.AzqrRec
},
LearnMoreUrl: "https://www.azure.cn/en-us/support/sla/application-gateway/",
},
"agw-104": {
RecommendationID: "agw-104",
ResourceType: "Microsoft.Network/applicationGateways",
Category: azqr.CategoryHighAvailability,
Recommendation: "Application Gateway SKU",
Impact: azqr.ImpactHigh,
Eval: func(target interface{}, scanContext *azqr.ScanContext) (bool, string) {
g := target.(*armnetwork.ApplicationGateway)
return false, string(*g.Properties.SKU.Name)
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/application-gateway/understanding-pricing",
},
"agw-105": {
RecommendationID: "agw-105",
ResourceType: "Microsoft.Network/applicationGateways",
Expand Down
18 changes: 0 additions & 18 deletions internal/scanners/agw/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,6 @@ func TestApplicationGatewayScanner_Rules(t *testing.T) {
result: "99.95%",
},
},
{
name: "ApplicationGatewayScanner SKU",
fields: fields{
rule: "agw-104",
target: &armnetwork.ApplicationGateway{
Properties: &armnetwork.ApplicationGatewayPropertiesFormat{
SKU: &armnetwork.ApplicationGatewaySKU{
Name: to.Ptr(armnetwork.ApplicationGatewaySKUNameStandardV2),
},
},
},
scanContext: &azqr.ScanContext{},
},
want: want{
broken: false,
result: "Standard_v2",
},
},
{
name: "ApplicationGatewayScanner CAF",
fields: fields{
Expand Down
13 changes: 0 additions & 13 deletions internal/scanners/apim/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,6 @@ func (a *APIManagementScanner) GetRecommendations() map[string]azqr.AzqrRecommen
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/private-endpoint",
},
"apim-005": {
RecommendationID: "apim-005",
ResourceType: "Microsoft.ApiManagement/service",
Category: azqr.CategoryHighAvailability,
Recommendation: "Azure APIM SKU",
Impact: azqr.ImpactHigh,
Eval: func(target interface{}, scanContext *azqr.ScanContext) (bool, string) {
a := target.(*armapimanagement.ServiceResource)
sku := string(*a.SKU.Name)
return strings.Contains(sku, "Developer"), sku
},
LearnMoreUrl: "https://learn.microsoft.com/en-us/azure/api-management/api-management-features",
},
"apim-006": {
RecommendationID: "apim-006",
ResourceType: "Microsoft.ApiManagement/service",
Expand Down
Loading

0 comments on commit 69673f6

Please sign in to comment.