Skip to content

Commit

Permalink
Add table azure_nat_gateway closes turbot#525 (#533)
Browse files Browse the repository at this point in the history
  • Loading branch information
ParthaI authored Nov 4, 2022
1 parent ee45c11 commit 3aa5411
Show file tree
Hide file tree
Showing 14 changed files with 408 additions and 0 deletions.
Empty file.
6 changes: 6 additions & 0 deletions azure-test/tests/azure_nat_gateway/test-get-expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"id": "{{ output.resource_id.value }}",
"name": "{{ resourceName }}"
}
]
3 changes: 3 additions & 0 deletions azure-test/tests/azure_nat_gateway/test-get-query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select name, id
from azure_nat_gateway
where name = '{{resourceName}}' and resource_group = '{{resourceName}}';
6 changes: 6 additions & 0 deletions azure-test/tests/azure_nat_gateway/test-list-expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"id": "{{ output.resource_id.value }}",
"name": "{{resourceName}}"
}
]
3 changes: 3 additions & 0 deletions azure-test/tests/azure_nat_gateway/test-list-query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select id, name
from azure_nat_gateway
where name = '{{resourceName}}';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
null
3 changes: 3 additions & 0 deletions azure-test/tests/azure_nat_gateway/test-not-found-query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select name, akas, tags, title
from azure_nat_gateway
where name = 'dummy-{{resourceName}}' and resource_group = '{{resourceName}}';
13 changes: 13 additions & 0 deletions azure-test/tests/azure_nat_gateway/test-turbot-expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"akas": [
"{{ output.resource_aka.value }}",
"{{ output.resource_aka_lower.value }}"
],
"name": "{{resourceName}}",
"tags": {
"name": "{{resourceName}}"
},
"title": "{{resourceName}}"
}
]
3 changes: 3 additions & 0 deletions azure-test/tests/azure_nat_gateway/test-turbot-query.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select name, akas, title, tags
from azure_nat_gateway
where name = '{{resourceName}}' and resource_group = '{{resourceName}}';
1 change: 1 addition & 0 deletions azure-test/tests/azure_nat_gateway/variables.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
74 changes: 74 additions & 0 deletions azure-test/tests/azure_nat_gateway/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

variable "resource_name" {
type = string
default = "turbot-test-20200125-create-update"
description = "Name of the resource used throughout the test."
}

variable "azure_environment" {
type = string
default = "public"
description = "Azure environment used for the test."
}

variable "azure_subscription" {
type = string
default = "3510ae4d-530b-497d-8f30-53b9616fc6c1"
description = "Azure subscription used for the test."
}

provider "azurerm" {
# Cannot be passed as a variable
environment = var.azure_environment
subscription_id = var.azure_subscription
features {}
}

data "azurerm_client_config" "current" {}

data "null_data_source" "resource" {
inputs = {
scope = "azure:///subscriptions/${data.azurerm_client_config.current.subscription_id}"
}
}

resource "azurerm_resource_group" "named_test_resource" {
name = var.resource_name
location = "East US"
}

resource "azurerm_nat_gateway" "named_test_resource" {
name = var.resource_name
location = azurerm_resource_group.named_test_resource.location
resource_group_name = azurerm_resource_group.named_test_resource.name
sku_name = "Standard"
idle_timeout_in_minutes = 10
zones = ["1"]
tags = {
name = var.resource_name
}
}

output "resource_aka" {
value = "azure://${azurerm_nat_gateway.named_test_resource.id}"
}

output "resource_aka_lower" {
value = "azure://${lower(azurerm_nat_gateway.named_test_resource.id)}"
}

output "resource_name" {
value = var.resource_name
}

output "resource_id" {
value = azurerm_nat_gateway.named_test_resource.id
}

output "resource_guid" {
value = azurerm_nat_gateway.named_test_resource.resource_guid
}

output "subscription_id" {
value = var.azure_subscription
}
1 change: 1 addition & 0 deletions azure/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
"azure_mssql_virtual_machine": tableAzureMSSQLVirtualMachine(ctx),
"azure_mysql_flexible_server": tableAzureMySQLFlexibleServer(ctx),
"azure_mysql_server": tableAzureMySQLServer(ctx),
"azure_nat_gateway": tableAzureNatGateway(ctx),
"azure_network_interface": tableAzureNetworkInterface(ctx),
"azure_network_security_group": tableAzureNetworkSecurityGroup(ctx),
"azure_network_watcher": tableAzureNetworkWatcher(ctx),
Expand Down
243 changes: 243 additions & 0 deletions azure/table_azure_nat_gateway.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package azure

import (
"context"

"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-03-01/network"
"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 tableAzureNatGateway(_ context.Context) *plugin.Table {
return &plugin.Table{
Name: "azure_nat_gateway",
Description: "Azure NAT Gateway",
Get: &plugin.GetConfig{
KeyColumns: plugin.AllColumns([]string{"name", "resource_group"}),
Hydrate: getNatGateway,
IgnoreConfig: &plugin.IgnoreConfig{
ShouldIgnoreErrorFunc: isNotFoundError([]string{"ResourceNotFound", "ResourceGroupNotFound", "404"}),
},
},
List: &plugin.ListConfig{
Hydrate: listNatGateways,
},
Columns: azureColumns([]*plugin.Column{
{
Name: "name",
Description: "The friendly name that identifies the nat gateway.",
Type: proto.ColumnType_STRING,
},
{
Name: "id",
Description: "Contains ID to identify a nat gateway 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: "idle_timeout_in_minutes",
Description: "The idle timeout of the nat gateway.",
Type: proto.ColumnType_INT,
Transform: transform.FromP(extractNatGatewayProperties, "idleTimeoutInMinutes"),
},
{
Name: "provisioning_state",
Description: "The provisioning state of the nat gateway resource.",
Type: proto.ColumnType_STRING,
Transform: transform.FromP(extractNatGatewayProperties, "provisioningState"),
},
{
Name: "resource_guid",
Description: "The provisioning state of the nat gateway resource.",
Type: proto.ColumnType_STRING,
Transform: transform.FromP(extractNatGatewayProperties, "resourceGUID"),
},
{
Name: "sku_name",
Description: "The nat gateway SKU.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Sku.Name"),
},
{
Name: "type",
Description: "The resource type of the nat gateway.",
Type: proto.ColumnType_STRING,
},
{
Name: "public_ip_addresses",
Description: "An array of public ip addresses associated with the nat gateway resource.",
Type: proto.ColumnType_JSON,
Transform: transform.FromP(extractNatGatewayProperties, "publicIpAddresses"),
},
{
Name: "public_ip_prefixes",
Description: "An array of public ip prefixes associated with the nat gateway resource.",
Type: proto.ColumnType_JSON,
Transform: transform.FromP(extractNatGatewayProperties, "publicIpPrefixes"),
},
{
Name: "subnets",
Description: "An array of references to the subnets using this nat gateway resource.",
Type: proto.ColumnType_JSON,
Transform: transform.FromP(extractNatGatewayProperties, "subnets"),
},
{
Name: "zones",
Description: "A list of availability zones denoting the zone in which Nat Gateway should be deployed.",
Type: proto.ColumnType_JSON,
},

// 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 listNatGateways(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
session, err := GetNewSession(ctx, d, "MANAGEMENT")
if err != nil {
plugin.Logger(ctx).Error("azure_nat_gateway.listNatGateways", "session_error", err)
return nil, err
}
subscriptionID := session.SubscriptionID

networkClient := network.NewNatGatewaysClient(subscriptionID)
networkClient.Authorizer = session.Authorizer

result, err := networkClient.ListAll(ctx)
if err != nil {
plugin.Logger(ctx).Error("azure_nat_gateway.listNatGateways", "api_error", err)
return nil, err
}

for _, natGateway := range result.Values() {
d.StreamListItem(ctx, natGateway)
// 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 _, natGateWay := range result.Values() {
d.StreamListItem(ctx, natGateWay)
// 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 getNatGateway(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
name := d.KeyColumnQuals["name"].GetStringValue()
resourceGroup := d.KeyColumnQuals["resource_group"].GetStringValue()

session, err := GetNewSession(ctx, d, "MANAGEMENT")
if err != nil {
plugin.Logger(ctx).Error("azure_nat_gateway.getNatGateway", "session_error", err)
return nil, err
}
subscriptionID := session.SubscriptionID

networkClient := network.NewNatGatewaysClient(subscriptionID)
networkClient.Authorizer = session.Authorizer

op, err := networkClient.Get(ctx, resourceGroup, name, "")
if err != nil {
plugin.Logger(ctx).Error("azure_nat_gateway.getNatGateway", "api_error", err)
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
}

//// TRANSFORM FUNCTIONS

func extractNatGatewayProperties(ctx context.Context, d *transform.TransformData) (interface{}, error) {
gateway := d.HydrateItem.(network.NatGateway)
param := d.Param.(string)

objectMap := make(map[string]interface{})

if gateway.IdleTimeoutInMinutes != nil {
objectMap["idleTimeoutInMinutes"] = *gateway.IdleTimeoutInMinutes
}
if *gateway.ResourceGUID != "" {
objectMap["resourceGUID"] = gateway.ResourceGUID
}
if gateway.ProvisioningState != "" {
objectMap["provisioningState"] = gateway.ProvisioningState
}
if gateway.PublicIPAddresses != nil {
objectMap["publicIpAddresses"] = gateway.PublicIPAddresses
}
if gateway.PublicIPPrefixes != nil {
objectMap["publicIpPrefixes"] = gateway.PublicIPPrefixes
}
if gateway.Subnets != nil {
objectMap["subnets"] = gateway.Subnets
}

if val, ok := objectMap[param]; ok {
return val, nil
}
return nil, nil
}
Loading

0 comments on commit 3aa5411

Please sign in to comment.