From f6ca012d746fc415453d9cdeb6cf1f8b2043cdc6 Mon Sep 17 00:00:00 2001 From: Patrick Decat Date: Sun, 12 Mar 2023 12:14:35 +0100 Subject: [PATCH] Add azure_dns_zone table --- azure/plugin.go | 1 + azure/table_azure_dns_zone.go | 203 ++++++++++++++++++++++++++++++++++ docs/tables/azure_dns_zone.md | 43 +++++++ 3 files changed, 247 insertions(+) create mode 100644 azure/table_azure_dns_zone.go create mode 100644 docs/tables/azure_dns_zone.md diff --git a/azure/plugin.go b/azure/plugin.go index 33773d0a..47f38541 100644 --- a/azure/plugin.go +++ b/azure/plugin.go @@ -75,6 +75,7 @@ func Plugin(ctx context.Context) *plugin.Plugin { "azure_data_lake_store": tableAzureDataLakeStore(ctx), "azure_databox_edge_device": tableAzureDataBoxEdgeDevice(ctx), "azure_diagnostic_setting": tableAzureDiagnosticSetting(ctx), + "azure_dns_zone": tableAzureDNSZone(ctx), "azure_eventgrid_domain": tableAzureEventGridDomain(ctx), "azure_eventgrid_topic": tableAzureEventGridTopic(ctx), "azure_eventhub_namespace": tableAzureEventHubNamespace(ctx), diff --git a/azure/table_azure_dns_zone.go b/azure/table_azure_dns_zone.go new file mode 100644 index 00000000..7872fb7a --- /dev/null +++ b/azure/table_azure_dns_zone.go @@ -0,0 +1,203 @@ +package azure + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/services/dns/mgmt/2018-05-01/dns" + "github.com/turbot/steampipe-plugin-sdk/v4/grpc/proto" + "github.com/turbot/steampipe-plugin-sdk/v4/plugin/transform" + + "github.com/turbot/steampipe-plugin-sdk/v4/plugin" +) + +//// TABLE DEFINITION + +func tableAzureDNSZone(_ context.Context) *plugin.Table { + return &plugin.Table{ + Name: "azure_dns_zone", + Description: "Azure DNS zone", + Get: &plugin.GetConfig{ + KeyColumns: plugin.AllColumns([]string{"name", "resource_group"}), + Hydrate: getDNSZone, + IgnoreConfig: &plugin.IgnoreConfig{ + ShouldIgnoreErrorFunc: isNotFoundError([]string{"ResourceNotFound", "ResourceGroupNotFound", "404"}), + }, + }, + List: &plugin.ListConfig{ + Hydrate: listDNSZones, + }, + Columns: azureColumns([]*plugin.Column{ + { + Name: "name", + Type: proto.ColumnType_STRING, + Description: "The friendly name that identifies the DNS zone", + }, + { + Name: "id", + Description: "Contains ID to identify a DNS zone uniquely", + Type: proto.ColumnType_STRING, + Transform: transform.FromGo(), + }, + { + Name: "etag", + Description: "An unique read-only string that changes whenever the resource is updated", + Type: proto.ColumnType_STRING, + }, + { + Name: "type", + Description: "The resource type of the DNS zone", + Type: proto.ColumnType_STRING, + }, + { + Name: "max_number_of_record_sets", + Description: "The maximum number of record sets that can be created in this DNS zone", + Type: proto.ColumnType_INT, + Transform: transform.FromField("ZoneProperties.MaxNumberOfRecordSets"), + }, + { + Name: "max_number_of_records_per_record_set", + Description: "The maximum number of records per record set that can be created in this DNS zone", + Type: proto.ColumnType_INT, + Transform: transform.FromField("ZoneProperties.MaxNumberOfRecordsPerRecordSet"), + }, + { + Name: "number_of_record_sets", + Description: "The current number of record sets in this DNS zone", + Type: proto.ColumnType_INT, + Transform: transform.FromField("ZoneProperties.NumberOfRecordSets").Transform(transform.ToString), + }, + { + Name: "name_servers", + Description: "The name servers for this DNS zone", + Type: proto.ColumnType_JSON, + Transform: transform.FromField("ZoneProperties.NameServers"), + }, + { + Name: "zone_type", + Description: "The type of this DNS zone (Public or Private)", + Type: proto.ColumnType_STRING, + Transform: transform.FromField("ZoneProperties.ZoneType"), + }, + { + Name: "registration_virtual_networks", + Description: "A list of references to virtual networks that register hostnames in this DNS zone", + Type: proto.ColumnType_JSON, + Transform: transform.FromField("ZoneProperties.RegistrationVirtualNetworks"), + }, + { + Name: "resolution_virtual_networks", + Description: "A list of references to virtual networks that resolve records in this DNS zone", + Type: proto.ColumnType_JSON, + Transform: transform.FromField("ZoneProperties.ResolutionVirtualNetworks"), + }, + + // Steampipe standard columns + { + Name: "title", + Description: ColumnDescriptionTitle, + Type: proto.ColumnType_STRING, + Transform: transform.FromField("Name"), + }, + { + Name: "tags", + Description: ColumnDescriptionTags, + Type: proto.ColumnType_JSON, + }, + { + Name: "akas", + Description: ColumnDescriptionAkas, + Type: proto.ColumnType_JSON, + Transform: transform.FromField("ID").Transform(idToAkas), + }, + + // Azure standard columns + { + Name: "region", + Description: ColumnDescriptionRegion, + Type: proto.ColumnType_STRING, + Transform: transform.FromField("Location").Transform(toLower), + }, + { + Name: "resource_group", + Description: ColumnDescriptionResourceGroup, + Type: proto.ColumnType_STRING, + Transform: transform.FromField("ID").Transform(extractResourceGroupFromID), + }, + }), + } +} + +//// FETCH FUNCTIONS //// + +func listDNSZones(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + session, err := GetNewSession(ctx, d, "MANAGEMENT") + if err != nil { + return nil, err + } + subscriptionID := session.SubscriptionID + + dnsClient := dns.NewZonesClientWithBaseURI(session.ResourceManagerEndpoint, subscriptionID) + dnsClient.Authorizer = session.Authorizer + + result, err := dnsClient.List(ctx, nil) + if err != nil { + return nil, err + } + + for _, dnsZone := range result.Values() { + d.StreamListItem(ctx, dnsZone) + // Check if context has been cancelled or if the limit has been hit (if specified) + // if there is a limit, it will return the number of rows required to reach this limit + if d.QueryStatus.RowsRemaining(ctx) == 0 { + return nil, nil + } + } + + for result.NotDone() { + err = result.NextWithContext(ctx) + if err != nil { + return nil, err + } + + for _, dnsZone := range result.Values() { + d.StreamListItem(ctx, dnsZone) + // Check if context has been cancelled or if the limit has been hit (if specified) + // if there is a limit, it will return the number of rows required to reach this limit + if d.QueryStatus.RowsRemaining(ctx) == 0 { + return nil, nil + } + } + } + return nil, err +} + +//// HYDRATE FUNCTIONS //// + +func getDNSZone(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { + plugin.Logger(ctx).Trace("getDNSZone") + + name := d.KeyColumnQuals["name"].GetStringValue() + resourceGroup := d.KeyColumnQuals["resource_group"].GetStringValue() + + session, err := GetNewSession(ctx, d, "MANAGEMENT") + if err != nil { + return nil, err + } + subscriptionID := session.SubscriptionID + + dnsClient := dns.NewZonesClientWithBaseURI(session.ResourceManagerEndpoint, subscriptionID) + dnsClient.Authorizer = session.Authorizer + + op, err := dnsClient.Get(ctx, resourceGroup, name) + if err != nil { + return nil, err + } + + // In some cases resource does not give any notFound error + // instead of notFound error, it returns empty data + if op.ID != nil { + return op, nil + } + + return nil, nil +} diff --git a/docs/tables/azure_dns_zone.md b/docs/tables/azure_dns_zone.md new file mode 100644 index 00000000..96d2b2e0 --- /dev/null +++ b/docs/tables/azure_dns_zone.md @@ -0,0 +1,43 @@ +# Table: azure_dns_zone + +Azure DNS zone is used to host the DNS records for a particular domain. + +## Examples + +### Basic info + +```sql +select + name, + id, + zone_type +from + azure_dns_zone; +``` + +### List private DNS zones + +```sql +select + name, + id, + tags +from + azure_dns_zone +where + zone_type = 'Private'; +``` + +### List public DNS zones with delegated name servers + +```sql +select + name, + id, + ns +from + azure_dns_zone, jsonb_array_elements_text(name_servers) as ns +where + zone_type = 'Public' + and ns not like '%.azure-dns.%.'; +```