Skip to content

Commit

Permalink
New Data Source: wiz_subscription_resource_groups (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
jschoombee authored Feb 13, 2023
1 parent 57d724d commit 5dc7200
Show file tree
Hide file tree
Showing 7 changed files with 692 additions and 6 deletions.
125 changes: 125 additions & 0 deletions docs/data-sources/subscription_resource_groups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "wiz_subscription_resource_groups Data Source - terraform-provider-wiz"
subcategory: ""
description: |-
Fetches the resource groups that are part of the subscription.
---

# wiz_subscription_resource_groups (Data Source)

Fetches the resource groups that are part of the subscription.

## Example Usage

```terraform
# Get the first 3 resource groups for an Azure subscription ID
data "wiz_subscription_resource_groups" "rgs" {
subscription_id = "1689bd5b-4df3-5dc8-9046-2f0a15faa62f"
first = 3
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `first` (Number) How many matches to return.
- Defaults to `50`.
- `relationship_type` (String) Relationship type, will default to `CONTAINS` if not specified.
- Allowed values:
- ANY
- ANY_OUTGOING
- ACTING_AS
- ADMINISTRATE
- ALERTED_ON
- ALLOWS
- ALLOWS_ACCESS_TO
- APPLIES_TO
- ASSIGNED_TO
- ATTACHED_TO
- BEHIND
- BOOTS
- BUILT_FROM
- CAUSES
- COLLABORATES
- CONNECTED_TO
- CONTAINS
- CONTAINS_DST_IP_RANGE
- CONTAINS_DST_PORT_RANGE
- CONTAINS_SRC_IP_RANGE
- CONTAINS_SRC_PORT_RANGE
- DENIES
- DEPENDS_ON
- DEPLOYED_TO
- ENCRYPTS
- ENCRYPTS_PARTITION
- ENTITLES
- EXCLUDES
- EXPOSES
- GOVERNS
- HAS
- HAS_BOUNDARY_POLICY
- HAS_DATA_FINDING
- HAS_DATA_INVENTORY
- HAS_DATA_SCHEMA
- HAS_DATA_STORE
- HAS_ORGANIZATION_POLICY
- HAS_PRINCIPAL_POLICY
- HAS_RESOURCE_POLICY
- HAS_SNAPSHOT
- HAS_SOURCE
- HAS_STANDARD_WEB_ACCESS_FROM
- HAS_TECH
- HOSTS
- IGNORES
- IMPLEMENTS
- INCLUDES
- INFECTS
- INSIDE
- INSTANCE_OF
- INVOKES
- LOGS_DATA_FOR
- MANAGES
- MOUNTS
- OWNS
- PART_OF
- PEERED_TO
- PERFORMED
- PERFORMED_IMPERSONATED
- PERMITS
- POINTS_TO
- PROTECTS
- READS_DATA_FROM
- REFERENCED_BY
- REPLICA_OF
- ROUTES_TRAFFIC_FROM
- ROUTES_TRAFFIC_TO
- RUNS
- SCANNED
- SEND_MESSAGES_TO
- SERVES
- STORES_DATA_IN
- TRANSIT_PEERED_TO
- USES
- VALIDATES

- Defaults to `CONTAINS`.
- `subscription_id` (String) The Wiz subscription ID to search by.

### Read-Only

- `id` (String) Internal identifier for the data.
- `resource_groups` (Set of Object) The returned subscription resource groups. (see [below for nested schema](#nestedatt--resource_groups))

<a id="nestedatt--resource_groups"></a>
### Nested Schema for `resource_groups`

Read-Only:

- `id` (String)
- `name` (String)


Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Get the first 3 resource groups for an Azure subscription ID

data "wiz_subscription_resource_groups" "rgs" {
subscription_id = "1689bd5b-4df3-5dc8-9046-2f0a15faa62f"
first = 3
}
1 change: 1 addition & 0 deletions internal/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package internal

// QueryVariables struct
type QueryVariables struct {
Query interface{} `json:"query,omitempty"`
ID string `json:"id,omitempty"`
FilterBy interface{} `json:"filterBy,omitempty"`
After string `json:"after,omitempty"`
Expand Down
221 changes: 221 additions & 0 deletions internal/provider/data_source_subscription_resource_groups.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package provider

import (
"bytes"
"context"
"crypto/sha1"
"encoding/hex"
"fmt"

"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"wiz.io/hashicorp/terraform-provider-wiz/internal"
"wiz.io/hashicorp/terraform-provider-wiz/internal/client"
"wiz.io/hashicorp/terraform-provider-wiz/internal/utils"
"wiz.io/hashicorp/terraform-provider-wiz/internal/vendor"
)

// ReadSubscriptionResourceGroups struct
type ReadSubscriptionResourceGroups struct {
SubscriptionResourceGroups vendor.GraphSearchResultConnection `json:"graphsearch"`
}

func dataSourceWizSubscriptionResourceGroups() *schema.Resource {
return &schema.Resource{
Description: "Fetches the resource groups that are part of the subscription.",
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
Description: "Internal identifier for the data.",
},
"first": {
Type: schema.TypeInt,
Optional: true,
Default: 50,
Description: "How many matches to return.",
},
"subscription_id": {
Type: schema.TypeString,
Optional: true,
Description: "The Wiz subscription ID to search by.",
},
"relationship_type": {
Type: schema.TypeString,
Optional: true,
Default: "CONTAINS",
Description: fmt.Sprintf("Relationship type, will default to `CONTAINS` if not specified.\n - Allowed values: %s",
utils.SliceOfStringToMDUList(
vendor.GraphRelationshipType,
),
),
ValidateDiagFunc: validation.ToDiagFunc(
validation.StringInSlice(
vendor.GraphRelationshipType,
false,
),
),
},
"resource_groups": {
Type: schema.TypeSet,
Computed: true,
Description: "The returned subscription resource groups.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Optional: true,
Description: "Internal Wiz ID of Resource Group.",
},
"name": {
Type: schema.TypeString,
Optional: true,
Description: "Name of the Resource Group.",
},
},
},
},
},
ReadContext: dataSourceWizSubscriptionResourceGroupsRead,
}
}

func dataSourceWizSubscriptionResourceGroupsRead(ctx context.Context, d *schema.ResourceData, m interface{}) (diags diag.Diagnostics) {
tflog.Info(ctx, "dataSourceWizSubscriptionResourceGroupsRead called...")
var identifier bytes.Buffer

a, b := d.GetOk("first")
if b {
identifier.WriteString(utils.PrettyPrint(a))
}
a, b = d.GetOk("id")
if b {
identifier.WriteString(utils.PrettyPrint(a))
}
a, b = d.GetOk("subscription_id")
if b {
identifier.WriteString(utils.PrettyPrint(a))
}
a, b = d.GetOk("relationship_type")
if b {
identifier.WriteString(utils.PrettyPrint(a))
}
h := sha1.New()
h.Write([]byte(identifier.String()))
hashID := hex.EncodeToString(h.Sum(nil))

// Set the id
d.SetId(hashID)

// We set quick to false to ensure ordering, no noticable performance trade-off detected
query := `query ResourceGroupQuery($query: GraphEntityQueryInput, $quick: Boolean = false, $first:Int) {
graphSearch(first: $first, query: $query, quick: $quick) {
nodes {
entities {
id
name
}
}
}
}`

// set the resource parameters
err := d.Set("id", d.Get("id").(string))
if err != nil {
return append(diags, diag.FromErr(err)...)
}
err = d.Set("subscription_id", d.Get("subscription_id").(string))
if err != nil {
return append(diags, diag.FromErr(err)...)
}
err = d.Set("relationship_type", d.Get("relationship_type").(string))
if err != nil {
return append(diags, diag.FromErr(err)...)
}

// populate the graphql variables
vars := &internal.QueryVariables{}
vars.First = d.Get("first").(int)

// declare main graph query
resourceGroupQuery := &vendor.GraphEntityQueryInput{}
resourceGroupQuery.Type = []string{"RESOURCE_GROUP"}

// set the relationship type
relationshipDirectedType := &vendor.GraphDirectedRelationshipTypeInput{}
a, b = d.GetOk("relationship_type")
if b {
relationshipDirectedType.Type = a.(string)
}
// reverse needs be to be true to fetch resource group subscription relationships from the edges
reverse := true
relationshipDirectedType.Reverse = &reverse

var directedRelationshipQueryInput = []vendor.GraphDirectedRelationshipTypeInput{}
directedRelationshipQueryInput = append(directedRelationshipQueryInput, *relationshipDirectedType)

entityInput := &vendor.GraphEntityQueryInput{}
entityInput.Type = []string{"SUBSCRIPTION"}

// set the where predicate for the query to the subscription id
a, b = d.GetOk("subscription_id")
if b {
wherePredicate := map[string]interface{}{
"_vertexID": map[string]interface{}{
"EQUALS": a.(string),
},
}
entityInput.Where = wherePredicate
}

var relationshipQueryInput = &vendor.GraphRelationshipQueryInput{
With: *entityInput,
Type: directedRelationshipQueryInput,
}
var relationships = []*vendor.GraphRelationshipQueryInput{}
relationships = append(relationships, relationshipQueryInput)
resourceGroupQuery.Relationships = relationships

vars.Query = resourceGroupQuery

// process the request
data := &ReadSubscriptionResourceGroups{}
requestDiags := client.ProcessRequest(ctx, m, vars, data, query, "subscriptionResourceGroups", "read")

diags = append(diags, requestDiags...)
if len(diags) > 0 {
return diags
}

resourceGroups := flattenResourceGroups(ctx, &data.SubscriptionResourceGroups.Nodes)

if err := d.Set("resource_groups", resourceGroups); err != nil {
return append(diags, diag.FromErr(err)...)
}

return diags

}

func flattenResourceGroups(ctx context.Context, resgroups *[]*vendor.GraphSearchResult) []interface{} {
tflog.Info(ctx, "flattenResourceGroups called...")
tflog.Debug(ctx, fmt.Sprintf("resourceGroups: %s", utils.PrettyPrint(resgroups)))

// walk the slice and construct the list
var output = make([]interface{}, 0, 0)
for _, b := range *resgroups {
for _, e := range b.Entities {
resourceGroups := make(map[string]interface{})
resourceGroups["id"] = e.ID
resourceGroups["name"] = e.Name
tflog.Debug(ctx, fmt.Sprintf("resourceGroups output: id: %s, name: %s", utils.PrettyPrint(e.ID), utils.PrettyPrint(e.Name)))
output = append(output, resourceGroups)
}
}

tflog.Debug(ctx, fmt.Sprintf("flattenResourceGroups output: %s", utils.PrettyPrint(output)))
return output
}
Loading

0 comments on commit 5dc7200

Please sign in to comment.