Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Data Source: wiz_subscription_resource_groups #64

Merged
merged 1 commit into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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