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 roles resource and permissions datasource #753

Merged
merged 22 commits into from
Nov 23, 2020
Merged
Show file tree
Hide file tree
Changes from 11 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
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Install pre-commit
run: python -m pip install pre-commit
- name: set PY
run: echo "::set-env name=PY::$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')"
run: echo "PY=$(python -c 'import hashlib, sys;print(hashlib.sha256(sys.version.encode()+sys.executable.encode()).hexdigest())')" >> $GITHUB_ENV
- uses: actions/cache@v1
with:
path: ~/.cache/pre-commit
Expand All @@ -38,7 +38,7 @@ jobs:
git config --global core.autocrlf false
git config --global core.eol lf
- name: Install Go
uses: actions/setup-go@v2-beta
uses: actions/setup-go@v2
with:
go-version: 1.15
- name: Checkout code
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2020-11-19T10:30:31.704789+01:00
451 changes: 451 additions & 0 deletions datadog/cassettes/TestAccDatadogPermissionsDatasource.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2020-11-19T12:00:56.078914+01:00
1,309 changes: 1,309 additions & 0 deletions datadog/cassettes/TestAccDatadogRoleDatasourceExactMatch.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions datadog/cassettes/TestAccDatadogRole_CreateUpdate.freeze
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2020-11-19T11:21:35.461993+01:00
2,486 changes: 2,486 additions & 0 deletions datadog/cassettes/TestAccDatadogRole_CreateUpdate.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions datadog/cassettes/TestAccDatadogRole_RestrictedPerm.freeze
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2020-11-19T11:43:43.053221+01:00
115 changes: 115 additions & 0 deletions datadog/cassettes/TestAccDatadogRole_RestrictedPerm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
version: 1
interactions:
- request:
body: ""
form: {}
headers:
Accept:
- application/json
Dd-Operation-Id:
- ListPermissions
User-Agent:
- terraform-provider-datadog/dev (terraform 1.15.0; terraform-cli 0.12.7-sdk)
datadog-api-client-go/1.0.0-beta.11 (go go1.15.4; os darwin; arch amd64)
X-Datadog-Parent-Id:
- "7165266347497469612"
X-Datadog-Sampling-Priority:
- "1"
X-Datadog-Trace-Id:
- "5872402547522963203"
url: https://api.datadoghq.com/api/v2/permissions
method: GET
response:
body: '{"data":[{"type":"permissions","id":"984a2bd4-d3b4-11e8-a1ff-a7f660d43029","attributes":{"name":"admin","display_name":"Privileged
Access","description":"This permission gives you the ability to view and edit
everything in your Datadog organization that does not have an explicitly defined
permission. This includes billing and usage, user, key, and organization management.
This permission is inclusive of all Standard access permissions.","created":"2018-10-19T15:35:23.734317+00:00","group_name":"General","display_type":"other","restricted":false}},{"type":"permissions","id":"984d2f00-d3b4-11e8-a200-bb47109e9987","attributes":{"name":"standard","display_name":"Standard
Access","description":"This permission gives you the ability to view and edit
components in your Datadog organization that do not have explicitly defined
permissions. This includes APM, Events, and other non-Account Management functionality.","created":"2018-10-19T15:35:23.756736+00:00","group_name":"General","display_type":"other","restricted":false}},{"type":"permissions","id":"5e605652-dd12-11e8-9e53-375565b8970e","attributes":{"name":"logs_read_index_data","display_name":"Logs
Read Index Data","description":"The ability to read all or some log indexes.
Can be granted in a limited capacity per index from the Logs interface or APIs.
If granted via the Roles interface or API the permission has global scope.","created":"2018-10-31T13:39:19.727450+00:00","group_name":"Logs","display_type":"read","restricted":false}},{"type":"permissions","id":"62cc036c-dd12-11e8-9e54-db9995643092","attributes":{"name":"logs_modify_indexes","display_name":"Logs
Modify Indexes","description":"The ability to read and modify all indexes in
your account. This includes the ability to grant the Logs Read Index Data and
Logs Write Exclusion Filter permission to other roles, for some or all indexes.
This permission also grants global Log Index Read and Log Exclusion Filter Write
implicitly.","created":"2018-10-31T13:39:27.148615+00:00","group_name":"Logs","display_type":"other","restricted":false}},{"type":"permissions","id":"6f66600e-dd12-11e8-9e55-7f30fbb45e73","attributes":{"name":"logs_live_tail","display_name":"Logs
Live Tail Access","description":"The ability to view the live tail feed for
all log indexes, even if otherwise specifically restricted.","created":"2018-10-31T13:39:48.292879+00:00","group_name":"Logs","display_type":"read","restricted":false}},{"type":"permissions","id":"7d7c98ac-dd12-11e8-9e56-93700598622d","attributes":{"name":"logs_write_exclusion_filters","display_name":"Logs
Write Exclusion Filters","description":"The ability to add and change exclusion
filters for all or some log indexes. Can be granted in a limited capacity per
index to specific roles via the Logs interface or API. If granted from the Roles
interface or API, the permission has global scope.","created":"2018-10-31T13:40:11.926613+00:00","group_name":"Logs","display_type":"write","restricted":false}},{"type":"permissions","id":"811ac4ca-dd12-11e8-9e57-676a7f0beef9","attributes":{"name":"logs_write_pipelines","display_name":"Logs
Write Pipelines","description":"The ability to add and change log pipeline configurations,
including the ability to grant the Logs Write Processors permission to other
roles, for some or all pipelines. This permission also grants global Log Processor
Write implicitly.","created":"2018-10-31T13:40:17.996379+00:00","group_name":"Logs","display_type":"other","restricted":false}},{"type":"permissions","id":"84aa3ae4-dd12-11e8-9e58-a373a514ccd0","attributes":{"name":"logs_write_processors","display_name":"Log
Write Processors","description":"The ability to add and change some or all log
processor configurations. Can be granted in a limited capacity per pipeline
to specific roles via the Logs interface or API. If granted via the Roles interface
or API the permission has global scope.","created":"2018-10-31T13:40:23.969725+00:00","group_name":"Logs","display_type":"write","restricted":false}},{"type":"permissions","id":"87b00304-dd12-11e8-9e59-cbeb5f71f72f","attributes":{"name":"logs_write_archives","display_name":"Logs
Archives","description":"The ability to add and edit log archive locations.","created":"2018-10-31T13:40:29.040786+00:00","group_name":"Logs","display_type":"write","restricted":false}},{"type":"permissions","id":"1a92ede2-6cb2-11e9-99c6-2b3a4a0cdf0a","attributes":{"name":"logs_public_config_api","display_name":"Logs
Public Config API","description":"The ability to access and edit logs configurations
via the API.","created":"2019-05-02T08:13:01.731092+00:00","group_name":"Logs","display_type":"other","restricted":false}},{"type":"permissions","id":"979df720-aed7-11e9-99c6-a7eb8373165a","attributes":{"name":"logs_generate_metrics","display_name":"Log
Generate Metrics","description":"The ability to create custom metrics from logs.","created":"2019-07-25T12:27:39.640758+00:00","group_name":"Logs","display_type":"other","restricted":false}},{"type":"permissions","id":"d90f6830-d3d8-11e9-a77a-b3404e5e9ee2","attributes":{"name":"dashboards_read","display_name":"Dashboards","description":"The
ability to view dashboards.","created":"2019-09-10T14:39:51.955175+00:00","group_name":"Dashboards","display_type":"read","restricted":true}},{"type":"permissions","id":"d90f6831-d3d8-11e9-a77a-4fd230ddbc6a","attributes":{"name":"dashboards_write","display_name":"Dashboards","description":"The
ability to create and change dashboards.","created":"2019-09-10T14:39:51.962944+00:00","group_name":"Dashboards","display_type":"write","restricted":false}},{"type":"permissions","id":"d90f6832-d3d8-11e9-a77a-bf8a2607f864","attributes":{"name":"dashboards_public_share","display_name":"Dashboards
Share","description":"The ability to share dashboards externally.","created":"2019-09-10T14:39:51.967094+00:00","group_name":"Dashboards","display_type":"other","restricted":false}},{"type":"permissions","id":"4441648c-d8b1-11e9-a77a-1b899a04b304","attributes":{"name":"monitors_read","display_name":"Monitors","description":"The
ability to view monitors.","created":"2019-09-16T18:39:07.744297+00:00","group_name":"Monitors","display_type":"read","restricted":true}},{"type":"permissions","id":"48ef71ea-d8b1-11e9-a77a-93f408470ad0","attributes":{"name":"monitors_write","display_name":"Monitors","description":"The
ability to change, mute, and delete individual monitors.","created":"2019-09-16T18:39:15.597109+00:00","group_name":"Monitors","display_type":"write","restricted":false}},{"type":"permissions","id":"4d87d5f8-d8b1-11e9-a77a-eb9c8350d04f","attributes":{"name":"monitors_downtime","display_name":"Monitors
Manage Downtimes","description":"The ability to set downtimes for your organization.
A user with this permission can suppress alerts from any monitor using a downtime,
even if they do not have permission to edit those monitors explicitly.","created":"2019-09-16T18:39:23.306702+00:00","group_name":"Monitors","display_type":"other","restricted":false}},{"type":"permissions","id":"1af86ce4-7823-11ea-93dc-d7cad1b1c6cb","attributes":{"name":"logs_read_data","display_name":"Logs
Read Data","description":"The ability to read log data. Can be restricted with
restriction queries.","created":"2020-04-06T16:24:35.989108+00:00","group_name":"Logs","display_type":"read","restricted":false}},{"type":"permissions","id":"b382b982-8535-11ea-93de-2bf1bdf20798","attributes":{"name":"logs_read_archives","display_name":"Logs
Archives","description":"The ability to read logs archives location and use
it for rehydration.","created":"2020-04-23T07:40:27.966133+00:00","group_name":"Logs","display_type":"read","restricted":false}},{"type":"permissions","id":"7314eb20-aa58-11ea-95e2-6fb6e4a451d5","attributes":{"name":"security_monitoring_rules_read","display_name":"Detection
Rules","description":"The ability to read Detection rules.","created":"2020-06-09T13:52:25.279909+00:00","group_name":"Security
Monitoring","display_type":"read","restricted":false}},{"type":"permissions","id":"7b516476-aa58-11ea-95e2-93718cd56369","attributes":{"name":"security_monitoring_rules_write","display_name":"Detection
Rules","description":"The ability to create and edit Detection rules.","created":"2020-06-09T13:52:39.099413+00:00","group_name":"Security
Monitoring","display_type":"write","restricted":false}},{"type":"permissions","id":"80de1ec0-aa58-11ea-95e2-aff381626d5d","attributes":{"name":"security_monitoring_signals_read","display_name":"Security
Signals","description":"The ability to view Security signals.","created":"2020-06-09T13:52:48.410398+00:00","group_name":"Security
Monitoring","display_type":"read","restricted":false}},{"type":"permissions","id":"9ac1d8cc-e707-11ea-aa2d-73d37e989a9d","attributes":{"name":"user_access_invite","display_name":"Invite
User","description":"Allows users to invite other users to your organization.","created":"2020-08-25T19:17:23.539701+00:00","group_name":"User
Access","display_type":"other","restricted":false}},{"type":"permissions","id":"9de604d8-e707-11ea-aa2d-93f1a783b3a3","attributes":{"name":"user_access_manage","display_name":"Access
Management","description":"Grants the permission to disable users, manage user
roles and SAML-to-role mappings.","created":"2020-08-25T19:17:28.810412+00:00","group_name":"User
Access","display_type":"other","restricted":false}},{"type":"permissions","id":"07c3c146-f7f8-11ea-acf6-0bd62b9ae60e","attributes":{"name":"logs_write_historical_view","display_name":"Logs
Historical View","description":"The capability to rehydrate logs from Archives.","created":"2020-09-16T08:38:44.242076+00:00","group_name":"Logs","display_type":"write","restricted":false}},{"type":"permissions","id":"6ba32d22-0e1a-11eb-ba44-bf9a5aafaa39","attributes":{"name":"logs_write_facets","display_name":"Logs
Facets","description":"The capability to create or edit logs facets.","created":"2020-10-14T12:40:20.271908+00:00","group_name":"Logs","display_type":"write","restricted":false}}]}'
headers:
Cache-Control:
- no-cache
Connection:
- keep-alive
Content-Security-Policy:
- frame-ancestors 'self'; report-uri https://api.datadoghq.com/csp-report
Content-Type:
- application/json
Date:
- Thu, 19 Nov 2020 10:43:43 GMT
Dd-Pool:
- dogweb
Pragma:
- no-cache
Set-Cookie:
- DD-PSHARD=233; Max-Age=604800; Path=/; expires=Thu, 26-Nov-2020 10:43:43 GMT;
secure; HttpOnly
Strict-Transport-Security:
- max-age=15724800;
Vary:
- Accept-Encoding
X-Content-Type-Options:
- nosniff
X-Dd-Debug:
- xRBFY2Rp8NHDG9Rp4RaGjcqlKnbzhHpETMjn37ZNtmzdKqGU6DeuhyyL4o7jfpVZ
X-Dd-Version:
- "35.3397059"
X-Frame-Options:
- SAMEORIGIN
status: 200 OK
code: 200
duration: ""
47 changes: 47 additions & 0 deletions datadog/data_source_datadog_permissions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package datadog

import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func dataSourceDatadogPermissions() *schema.Resource {
return &schema.Resource{
Read: dataSourceDatadogPermissionsRead,

Schema: map[string]*schema.Schema{
// Computed values
"permissions": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think we'd want to add additional fields to this later? I'm wondering if it'd be useful to use schema like:

permissions: [
    {
        "name": <name>
         "id": <id>
    }
]

but that may be a bit of overkill here, wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Honestly, I don't know. And I do need this mapping so that it's practical for user to reference in other resources. A list wouldn't allow that

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah you're right, we don't want users to have to care about the order of the list...

I just want to make sure will be able to add new fields in the future without compatibility issues if needed. (But maybe we won't need it) Another possibility may be this, though I'm unsure if that means you'd need to know the hash

    {
        "name": {
            "id": <id>,
            "future_fields": ....,
         }
    }
]```

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So in a map I can only have primitive types though
Elem represents the element type. For a TypeMap, it must be a *Schema with a Type that is one of the primitives: TypeString, TypeBool, TypeInt, or TypeFloat

Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func dataSourceDatadogPermissionsRead(d *schema.ResourceData, meta interface{}) error {
providerConf := meta.(*ProviderConfiguration)
datadogClientV2 := providerConf.DatadogClientV2
authV2 := providerConf.AuthV2

res, _, err := datadogClientV2.RolesApi.ListPermissions(authV2).Execute()
if err != nil {
return translateClientError(err, "error listing permissions")
}
perms := res.GetData()
permsNameToID := make(map[string]string, len(perms))
for _, perm := range perms {
// Don't list restricted permissions, as they cannot be granted/revoked to/from a role
if !perm.Attributes.GetRestricted() {
permsNameToID[perm.Attributes.GetName()] = perm.GetId()
}
zippolyte marked this conversation as resolved.
Show resolved Hide resolved
}
d.SetId("datadog-permissions")
zippolyte marked this conversation as resolved.
Show resolved Hide resolved
if err := d.Set("permissions", permsNameToID); err != nil {
return err
}

return nil
}
28 changes: 28 additions & 0 deletions datadog/data_source_datadog_permissions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package datadog

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

func TestAccDatadogPermissionsDatasource(t *testing.T) {
accProviders, _, cleanup := testAccProviders(t, initRecorder(t))
defer cleanup(t)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: accProviders,
Steps: []resource.TestStep{
{
Config: `data "datadog_permissions" "foo" {}`,
// Check at least one permission exists
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.datadog_permissions.foo", "id", "datadog-permissions"),
resource.TestCheckResourceAttrSet("data.datadog_permissions.foo", "permissions.admin"),
resource.TestCheckNoResourceAttr("data.datadog_permissions.foo", "permissions.dashboards_read"),
zippolyte marked this conversation as resolved.
Show resolved Hide resolved
),
},
},
})
}
10 changes: 7 additions & 3 deletions datadog/data_source_datadog_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func dataSourceDatadogRole() *schema.Resource {
Computed: true,
},
"user_count": {
Type: schema.TypeString,
Type: schema.TypeInt,
Computed: true,
},
},
Expand Down Expand Up @@ -68,8 +68,12 @@ func dataSourceDatadogRoleRead(d *schema.ResourceData, meta interface{}) error {

r := roles[roleIndex]
d.SetId(r.GetId())
d.Set("name", r.Attributes.GetName())
d.Set("user_count", r.Attributes.GetUserCount())
if err := d.Set("name", r.Attributes.GetName()); err != nil {
return err
}
if err := d.Set("user_count", r.Attributes.GetUserCount()); err != nil {
return err
}

return nil
}
57 changes: 57 additions & 0 deletions datadog/data_source_datadog_role_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package datadog

import (
"fmt"
"regexp"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
Expand All @@ -22,9 +25,63 @@ func TestAccDatadogRoleDatasource(t *testing.T) {
})
}

func TestAccDatadogRoleDatasourceExactMatch(t *testing.T) {
accProviders, clock, cleanup := testAccProviders(t, initRecorder(t))
rolename := strings.ToLower(uniqueEntityName(clock, t))
defer cleanup(t)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: accProviders,
Steps: []resource.TestStep{
{
Config: testAccDatasourceRoleCreateConfig(rolename),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("datadog_role.main", "name", rolename+" main"),
resource.TestCheckResourceAttr("datadog_role.cloned", "name", rolename+" main cloned"),
),
},
{
Config: testAccDatasourceRoleErrorConfig(rolename),
ExpectError: regexp.MustCompile("no exact match for name .* were found"),
},
{
Config: testAccDatasourceRoleExactMatchConfig(rolename),
Check: resource.TestCheckResourceAttr("data.datadog_role.exact_match", "name", rolename+" main"),
},
},
})
}

func testAccDatasourceRoleConfig() string {
return `
data "datadog_role" "foo" {
filter = "Datadog Standard Role"
}`
}

func testAccDatasourceRoleCreateConfig(uniq string) string {
return fmt.Sprintf(`
resource "datadog_role" "main" {
name = "%s main"
}

resource "datadog_role" "cloned" {
name = "%s main cloned"
}`, uniq, uniq)

}

func testAccDatasourceRoleErrorConfig(uniq string) string {
return fmt.Sprintf(`
data "datadog_role" "error" {
filter = "%s"
}`, uniq)
}

func testAccDatasourceRoleExactMatchConfig(uniq string) string {
return fmt.Sprintf(`
data "datadog_role" "exact_match" {
filter = "%s main"
}`, uniq)
}
2 changes: 2 additions & 0 deletions datadog/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func Provider() terraform.ResourceProvider {
"datadog_logs_pipeline_order": resourceDatadogLogsPipelineOrder(),
"datadog_metric_metadata": resourceDatadogMetricMetadata(),
"datadog_monitor": resourceDatadogMonitor(),
"datadog_role": resourceDatadogRole(),
"datadog_screenboard": resourceDatadogScreenboard(),
"datadog_service_level_objective": resourceDatadogServiceLevelObjective(),
"datadog_synthetics_test": resourceDatadogSyntheticsTest(),
Expand All @@ -83,6 +84,7 @@ func Provider() terraform.ResourceProvider {
"datadog_dashboard_list": dataSourceDatadogDashboardList(),
"datadog_ip_ranges": dataSourceDatadogIpRanges(),
"datadog_monitor": dataSourceDatadogMonitor(),
"datadog_permissions": dataSourceDatadogPermissions(),
"datadog_role": dataSourceDatadogRole(),
"datadog_synthetics_locations": dataSourceDatadogSyntheticsLocations(),
},
Expand Down
2 changes: 2 additions & 0 deletions datadog/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var testFiles2EndpointTags = map[string]string{
"data_source_datadog_dashboard_list_test": "dashboard-lists",
"data_source_datadog_ip_ranges_test": "ip-ranges",
"data_source_datadog_monitor_test": "monitors",
"data_source_datadog_permissions_test": "permissions",
"data_source_datadog_role_test": "roles",
"data_source_datadog_synthetics_locations_test": "synthetics",
"import_datadog_downtime_test": "downtimes",
Expand Down Expand Up @@ -83,6 +84,7 @@ var testFiles2EndpointTags = map[string]string{
"resource_datadog_logs_custom_pipeline_test": "logs-pipelines",
"resource_datadog_metric_metadata_test": "metrics",
"resource_datadog_monitor_test": "monitors",
"resource_datadog_role_test": "roles",
"resource_datadog_screenboard_test": "dashboards",
"resource_datadog_service_level_objective_test": "service-level-objectives",
"resource_datadog_synthetics_test_test": "synthetics",
Expand Down
Loading