diff --git a/README.md b/README.md index 9f8c2d3..90c1692 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -[![Build Status](https://dev.azure.com/dariuszdwornikowski0297/azure-tag-manager/_apis/build/status/nordcloud.azure-tag-manager?branchName=master)](https://dev.azure.com/dariuszdwornikowski0297/azure-tag-manager/_build/latest?definitionId=1&branchName=master) +[![Build Status](https://dev.azure.com/dariuszdwornikowski0297/azure-tag-manager/_apis/build/status/nordcloud.azure-tag-manager?branchName=master)](https://dev.azure.com/dariuszdwornikowski0297/azure-tag-manager/_build/latest?definitionId=1&branchName=master) +[![Go Report Card](https://goreportcard.com/badge/github.com/nordcloud/azure-tag-manager)](https://goreportcard.com/report/github.com/nordcloud/azure-tag-manager) # Azure Tag manager diff --git a/cmd/cli/commands/restore.go b/cmd/cli/commands/restore.go index 1ad9de2..027f731 100644 --- a/cmd/cli/commands/restore.go +++ b/cmd/cli/commands/restore.go @@ -35,7 +35,7 @@ var restoreCommand = &cobra.Command{ fmt.Printf("Restoring tags from: [%s]\n", restoreFile) - restorer := azure.NewRestorerFromFile(restoreFile, sess, false) + restorer := azure.NewRestorerFromFile(restoreFile, sess) err = restorer.Restore() if err != nil { diff --git a/internal/azure/backup.go b/internal/azure/backup.go index f3491fb..accc37f 100644 --- a/internal/azure/backup.go +++ b/internal/azure/backup.go @@ -7,29 +7,31 @@ import ( log "github.com/sirupsen/logrus" - "github.com/nordcloud/azure-tag-manager/internal/azure/session" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources/resourcesapi" + "github.com/nordcloud/azure-tag-manager/internal/azure/session" "github.com/pkg/errors" ) +// BackupEntry represents one resource tags backup type BackupEntry struct { ID string `json:"id"` Tags map[string]*string `json:"tags"` } +// Restorer provides interface for restorers type Restorer interface { Restore() error } +// TagRestorer represents a restorer of Azure tags from backup type TagRestorer struct { - Session *session.AzureSession - ResourcesClient resourcesapi.ClientAPI - ReplaceTags bool - Backup []BackupEntry + Session *session.AzureSession // session to connect to Azure + ResourcesClient resourcesapi.ClientAPI // client to the resources API + Backup []BackupEntry // list of backup entries } -//NewBackupFromMatched make a file backup from the matching resources +//NewBackupFromMatched makes a file backup from the resources in matched to a json file in directory func NewBackupFromMatched(matched map[string]Matched, directory string) string { var backup []BackupEntry @@ -56,6 +58,7 @@ func NewBackupFromMatched(matched map[string]Matched, directory string) string { return tmpfile.Name() } +// Restore restores tags from a backup file provided in TagRestorer func (t TagRestorer) Restore() error { for _, backupEntry := range t.Backup { log.Infof("Restoring tags for [%s]\n", backupEntry.ID) @@ -76,7 +79,8 @@ func (t TagRestorer) Restore() error { return nil } -func NewRestorerFromFile(filename string, s *session.AzureSession, replace bool) *TagRestorer { +// NewRestorerFromFile creates a TagRestorer, which will restore tag backup from filename +func NewRestorerFromFile(filename string, s *session.AzureSession) *TagRestorer { resClient := resources.NewClient(s.SubscriptionID) resClient.Authorizer = s.Authorizer @@ -94,7 +98,6 @@ func NewRestorerFromFile(filename string, s *session.AzureSession, replace bool) Session: s, ResourcesClient: &resClient, Backup: backup, - ReplaceTags: replace, } return restorer } diff --git a/internal/azure/checker.go b/internal/azure/checker.go index 6070604..3239272 100644 --- a/internal/azure/checker.go +++ b/internal/azure/checker.go @@ -4,15 +4,19 @@ import ( "github.com/nordcloud/azure-tag-manager/internal/azure/session" ) +// TagChecker represents an Azure checker type TagChecker struct { Session *session.AzureSession } +// SameTagDifferentValue reprents a resource with a tag's value type SameTagDifferentValue struct { Resource Resource Value string } +// CheckSameTagDifferentValue checks if resources in resources are tagged with the same tag but with different values. It returns a map of lists of such resources. The key to the list is tag key. +//TODO: make this differently func (t TagChecker) CheckSameTagDifferentValue(resources []Resource) map[string][]SameTagDifferentValue { var ( @@ -43,7 +47,8 @@ func (t TagChecker) CheckSameTagDifferentValue(resources []Resource) map[string] return nonCompliant } -//NewTagChecker +// NewTagChecker creates new checker with AzureSession +//TODO: get rid of this func NewTagChecker(s *session.AzureSession) *TagChecker { checker := TagChecker{ Session: s, diff --git a/internal/azure/scanner.go b/internal/azure/scanner.go index eb1ca51..090de13 100644 --- a/internal/azure/scanner.go +++ b/internal/azure/scanner.go @@ -6,17 +6,19 @@ import ( log "github.com/sirupsen/logrus" - "github.com/nordcloud/azure-tag-manager/internal/azure/session" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" + "github.com/nordcloud/azure-tag-manager/internal/azure/session" "github.com/pkg/errors" ) +// ResourceGroupScanner represents resource group scanner that scans all resources in a resource group type ResourceGroupScanner struct { Session *session.AzureSession ResourcesClient *resources.Client GroupsClient *resources.GroupsClient } +// Scanner represents generic scanner of Azure resource groups type Scanner interface { GetResources() ([]Resource, error) GetResourcesByResourceGroup(string) ([]Resource, error) @@ -24,10 +26,12 @@ type Scanner interface { GetResourceGroupTags(string) (map[string]*string, error) } +// String converts string v to the string pointer func String(v string) *string { return &v } +// GetResourceGroupTags returns a map of key value tags of a reource group rg func (r ResourceGroupScanner) GetResourceGroupTags(rg string) (map[string]*string, error) { result, err := r.GroupsClient.Get(context.Background(), rg) if err != nil { @@ -36,6 +40,7 @@ func (r ResourceGroupScanner) GetResourceGroupTags(rg string) (map[string]*strin return result.Tags, nil } +// NewResourceGroupScanner creates ResourceGroupScanner with Azure Serssion s func NewResourceGroupScanner(s *session.AzureSession) *ResourceGroupScanner { resClient := resources.NewClient(s.SubscriptionID) resClient.Authorizer = s.Authorizer @@ -52,6 +57,7 @@ func NewResourceGroupScanner(s *session.AzureSession) *ResourceGroupScanner { return scanner } +// ScanResourceGroup returns a list of resources and their tags from a resource group rg func (r ResourceGroupScanner) ScanResourceGroup(rg string) []Resource { tab := make([]Resource, 0) for list, err := r.ResourcesClient.ListByResourceGroupComplete(context.Background(), rg, "", "", nil); list.NotDone(); err = list.NextWithContext(context.Background()) { @@ -71,6 +77,7 @@ func (r ResourceGroupScanner) ScanResourceGroup(rg string) []Resource { return tab } +// GetResources retruns list of resources in resource group func (r ResourceGroupScanner) GetResources() ([]Resource, error) { var wg sync.WaitGroup @@ -99,6 +106,7 @@ func (r ResourceGroupScanner) GetResources() ([]Resource, error) { return tab, nil } +// GetGroups returns list of resource groups in a subscription func (r ResourceGroupScanner) GetGroups() ([]string, error) { tab := make([]string, 0) for list, err := r.GroupsClient.ListComplete(context.Background(), "", nil); list.NotDone(); err = list.NextWithContext(context.Background()) { @@ -111,6 +119,7 @@ func (r ResourceGroupScanner) GetGroups() ([]string, error) { return tab, nil } +// GetResourcesByResourceGroup returns resources in a resource group rg func (r ResourceGroupScanner) GetResourcesByResourceGroup(rg string) ([]Resource, error) { tab := make([]Resource, 0) for list, err := r.ResourcesClient.ListByResourceGroupComplete(context.Background(), rg, "", "", nil); list.NotDone(); err = list.NextWithContext(context.Background()) { diff --git a/internal/azure/tagger.go b/internal/azure/tagger.go index 5cd804a..3f04b33 100644 --- a/internal/azure/tagger.go +++ b/internal/azure/tagger.go @@ -4,25 +4,26 @@ import ( "context" "fmt" - "github.com/nordcloud/azure-tag-manager/internal/azure/rules" - "github.com/nordcloud/azure-tag-manager/internal/azure/session" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources" "github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources/resourcesapi" + "github.com/nordcloud/azure-tag-manager/internal/azure/rules" + "github.com/nordcloud/azure-tag-manager/internal/azure/session" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) +// Tagger reprents the maing tagging element type Tagger struct { Session *session.AzureSession Matched map[string]Matched - Rules rules.TagRules - condMap condFuncMap - actionMap actionFuncMap - dryRun bool + Rules rules.TagRules // list of rules + condMap condFuncMap // map of implementation of conditions + actionMap actionFuncMap // map of implementation of actions + dryRun bool // if true, actions will not be executed ResourcesClient resourcesapi.ClientAPI } -// Matched stores +// Matched represents rules that mathc for a resource type Matched struct { Resource Resource TagRules []rules.Rule @@ -53,10 +54,12 @@ func NewTagger(ruleDef rules.TagRules, session *session.AzureSession) *Tagger { return &tagger } +// DryRun returns true if the check should be simulated func (t *Tagger) DryRun() { t.dryRun = true } +// InitActionMap initializes action map with supported actions func (t *Tagger) InitActionMap() { t.actionMap = actionFuncMap{} t.actionMap["addTag"] = func(p map[string]string, data *Resource) error { @@ -86,6 +89,7 @@ func (t *Tagger) InitActionMap() { } +// InitCondMap initializes conditions map with supported conditions func (t *Tagger) InitCondMap() { t.condMap = condFuncMap{} t.condMap["noTags"] = func(p map[string]string, data *Resource) bool { @@ -180,6 +184,7 @@ func (t *Tagger) InitCondMap() { } } +// ExecuteActions executes all actions based on definitions of rules. It resturns list of executed actions func (t *Tagger) ExecuteActions() ([]ActionExecution, error) { ael := make([]ActionExecution, 0) for resID, matched := range t.Matched { @@ -295,6 +300,7 @@ func (t Tagger) createOrUpdateTag(id, tag, value string) error { return err } +// Execute executes action from p in resource data func (t *Tagger) Execute(data *Resource, p rules.ActionItem) error { if val, ok := t.actionMap[p.GetType()]; ok { err := val(p, data) @@ -308,6 +314,7 @@ func (t *Tagger) Execute(data *Resource, p rules.ActionItem) error { return nil } +// Eval checks if condition p is satisfied on resource data func (t *Tagger) Eval(data *Resource, p rules.ConditionItem) bool { if val, ok := t.condMap[p.GetType()]; ok { return val(p, data)