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

Add table gcp_project_organization_policy. closes #186 #204

Merged
merged 8 commits into from
Jun 21, 2021
Merged
Show file tree
Hide file tree
Changes from 5 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
36 changes: 36 additions & 0 deletions docs/tables/gcp_project_organization_policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Table: gcp_project_organization_policy

The Organization Policy Service gives you centralized and programmatic control over your organization's cloud resources.

## Examples

### Basic info

```sql
select
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we query specific columns, instead of *?

from
gcp_project_organization_policy;
```

### Check policy's previously updated time by server

```sql
select
id,
version,
update_time
from
gcp_project_organization_policy;
```

### Check the policy values given to constraint

```sql
select
id,
version,
list_policy ->> 'allValues' as policy_value
from
gcp_project_organization_policy;
```
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"akas": ["{{ output.project_aka.value }}"],
"project": "{{ output.project_id.value }}",
"title": "{{ output.resource_title.value }}"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select title, akas, project
from gcp.gcp_project_organization_policy
where id = '{{ output.resource_id.value }}';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"akas": ["{{ output.project_aka.value }}"],
"location": "global",
"project": "{{ output.project_id.value }}",
"title": "{{ output.resource_title.value }}"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select project, location, title, akas
from gcp.gcp_project_organization_policy
where title = '{{ output.resource_title.value }}';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select id, project, title, akas
from gcp.gcp_project_organization_policy
where title = '{{ output.resource_title.value }}:asdf';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"akas": ["{{ output.project_aka.value }}"],
"title": "{{ output.resource_title.value }}"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
select title, akas
from gcp.gcp_project_organization_policy
where title = '{{ output.resource_title.value }}';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
68 changes: 68 additions & 0 deletions gcp-test/tests/gcp_project_organization_policy/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@

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

variable "gcp_project" {
type = string
default = "pikachu-aaa"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default = "pikachu-aaa"
default = "niteowl-aaa"

description = "GCP project used for the test."
}

variable "gcp_region" {
type = string
default = "us-east1"
description = "GCP region used for the test."
}

variable "gcp_zone" {
type = string
default = "us-east1-b"
}

provider "google" {
project = var.gcp_project
region = var.gcp_region
zone = var.gcp_zone
}

data "google_client_config" "current" {}

data "null_data_source" "resource" {
inputs = {
scope = "gcp://cloudresourcemanager.googleapis.com/projects/${data.google_client_config.current.project}"
}
}

resource "google_project_organization_policy" "named_test_resource" {
project = var.gcp_project
constraint = "serviceuser.services"

list_policy {
allow {
all = true
}
}
}

output "project_aka" {
value = "gcp://cloudresourcemanager.googleapis.com/projects/${var.gcp_project}"
}

output "resource_name" {
value = var.resource_name
}

output "resource_title" {
value = google_project_organization_policy.named_test_resource.constraint
}

output "resource_id" {
value = split(":", google_project_organization_policy.named_test_resource.id)[1]
}

output "project_id" {
value = var.gcp_project
}
1 change: 1 addition & 0 deletions gcp/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func Plugin(ctx context.Context) *plugin.Plugin {
"gcp_monitoring_alert_policy": tableGcpMonitoringAlert(ctx),
"gcp_monitoring_group": tableGcpMonitoringGroup(ctx),
"gcp_monitoring_notification_channel": tableGcpMonitoringNotificationChannel(ctx),
"gcp_project_organization_policy": tableGcpProjectsOrganizationPolicy(ctx),
"gcp_project": tableGcpProject(ctx),
"gcp_project_service": tableGcpProjectService(ctx),
"gcp_pubsub_snapshot": tableGcpPubSubSnapshot(ctx),
Expand Down
181 changes: 181 additions & 0 deletions gcp/table_gcp_project_organization_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package gcp

import (
"context"
"strings"

"github.com/turbot/steampipe-plugin-sdk/grpc/proto"
"github.com/turbot/steampipe-plugin-sdk/plugin"
"github.com/turbot/steampipe-plugin-sdk/plugin/transform"

"google.golang.org/api/cloudresourcemanager/v1"
)

//// TABLE DEFINITION

func tableGcpProjectsOrganizationPolicy(ctx context.Context) *plugin.Table {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func tableGcpProjectsOrganizationPolicy(ctx context.Context) *plugin.Table {
func tableGcpProjectOrganizationPolicy(ctx context.Context) *plugin.Table {

return &plugin.Table{
Name: "gcp_project_organization_policy",
Description: "GCP Project Organization Policy",
Get: &plugin.GetConfig{
KeyColumns: plugin.SingleColumn("id"),
Hydrate: getGcpProjectOrganizationPolicy,
},
List: &plugin.ListConfig{
Hydrate: listGcpProjectOrganizationPolicies,
},
Columns: []*plugin.Column{
{
Name: "id",
Description: "The name of the Constraint the Policy is configuring.",
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Constraint").Transform(lastPathElement),
},
{
Name: "update_time",
Description: "The time stamp the Policy was previously updated.",
Type: proto.ColumnType_TIMESTAMP,
},
{
Name: "version",
Description: "Version of the Policy. Default version is 0.",
Type: proto.ColumnType_INT,
},
{
Name: "etag",
Description: "An opaque tag indicating the current version of the Policy, used for concurrency control.",
Type: proto.ColumnType_STRING,
},
{
Name: "list_policy",
Description: "List of values either allowed or disallowed.",
Type: proto.ColumnType_JSON,
},
{
Name: "boolean_policy",
Description: "For boolean Constraints, whether to enforce the Constraint or not.",
Type: proto.ColumnType_JSON,
},
{
Name: "restore_default",
Description: "Restores the default behavior of the constraint; independent of Constraint type.",
Type: proto.ColumnType_JSON,
},

// Steampipe standard columns
{
Name: "title",
Description: ColumnDescriptionTitle,
Type: proto.ColumnType_STRING,
Transform: transform.FromField("Constraint").Transform(lastPathElement),
},
{
Name: "akas",
Description: ColumnDescriptionAkas,
Type: proto.ColumnType_JSON,
Hydrate: getOrganizationPolicyTurbotData,
},

// standard gcp columns
{
Name: "location",
Description: ColumnDescriptionLocation,
Type: proto.ColumnType_STRING,
Transform: transform.FromConstant("global"),
},
{
Name: "project",
Description: ColumnDescriptionProject,
Type: proto.ColumnType_STRING,
Hydrate: getProject,
Transform: transform.FromValue(),
},
},
}
}

//// LIST FUNCTION

func listGcpProjectOrganizationPolicies(ctx context.Context, d *plugin.QueryData, _ *plugin.HydrateData) (interface{}, error) {
// Create Service Connection
service, err := CloudResourceManagerService(ctx, d)
if err != nil {
return nil, err
}

// Get project details
projectData, err := activeProject(ctx, d)
if err != nil {
return nil, err
}
project := projectData.Project
plugin.Logger(ctx).Trace("listGcpProjectOrganizationPolicies", "GCP_PROJECT: ", project)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
plugin.Logger(ctx).Trace("listGcpProjectOrganizationPolicies", "GCP_PROJECT: ", project)


rb := &cloudresourcemanager.ListOrgPoliciesRequest{}

resp := service.Projects.ListOrgPolicies("projects/"+project, rb)
if err := resp.Pages(ctx, func(page *cloudresourcemanager.ListOrgPoliciesResponse) error {
for _, orgPolicy := range page.Policies {
d.StreamListItem(ctx, orgPolicy)
}
return nil
}); err != nil {
return nil, err
}

return nil, err
}

//// HYDRATE FUNCTIONS

func getGcpProjectOrganizationPolicy(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
plugin.Logger(ctx).Trace("getGcpProjectOrganizationPolicy")

// Create Service Connection
service, err := CloudResourceManagerService(ctx, d)
if err != nil {
return nil, err
}

// Get project details
projectData, err := activeProject(ctx, d)
if err != nil {
return nil, err
}

project := projectData.Project
id := d.KeyColumnQuals["id"].GetStringValue()
rb := &cloudresourcemanager.GetOrgPolicyRequest{
Constraint: "constraints/" + id,
}

req, err := service.Projects.GetOrgPolicy("projects/" + project, rb).Do()
if err != nil {
plugin.Logger(ctx).Debug("getGcpProjectOrganizationPolicy", "ERROR", err)
return nil, err
}
return req, nil
}

func getOrganizationPolicyTurbotData(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) {
// Get project details
projectData, err := activeProject(ctx, d)
if err != nil {
return nil, err
}
project := projectData.Project

// Get the resource title
title := strings.ToUpper(project) + " Org Policy"
Copy link
Contributor

@Subhajit97 Subhajit97 May 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Priyanka585464 Is this title required?
You are not using this title value anywhere.
Currently the title is using constraint value
https://github.com/turbot/steampipe-plugin-gcp/pull/204/files#diff-90f64bc506bbef72770fec8f8ca390942b03e818c0b89357a21e3517f02b28b8R70


// Build resource aka
akas := []string{"gcp://cloudresourcemanager.googleapis.com/projects/" + project}

// Mapping all turbot defined properties
turbotData := map[string]interface{}{
"Akas": akas,
"Title": title,
}

return turbotData, nil
}