Skip to content

Commit

Permalink
Add apps data source, docs, & acceptance test.
Browse files Browse the repository at this point in the history
  • Loading branch information
steveAG authored and exitcode0 committed Sep 4, 2024
1 parent 4932705 commit 90af3bc
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 0 deletions.
14 changes: 14 additions & 0 deletions okta/app_filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,17 @@ func getAppFilters(d *schema.ResourceData) (*appFilters, error) {
}
return filters, nil
}

func getAppsFilters(d *schema.ResourceData) (*appFilters, error) {
label := d.Get("label").(string)
labelPrefix := d.Get("label_prefix").(string)

filters := &appFilters{
Label: label,
LabelPrefix: labelPrefix,
}
if d.Get("active_only").(bool) {
filters.Status = fmt.Sprintf(`status eq "%s"`, statusActive)
}
return filters, nil
}
104 changes: 104 additions & 0 deletions okta/data_source_okta_apps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package okta

import (
"context"
"encoding/json"
"fmt"
"hash/crc32"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceApps() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceAppsRead,
Schema: map[string]*schema.Schema{
"active_only": {
Type: schema.TypeBool,
Optional: true,
Default: true,
Description: "Search only active applications.",
},
"label": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"label_prefix"},
Description: "Searches for applications whose label or name property matches this value exactly",
},
"label_prefix": {
Type: schema.TypeString,
Optional: true,
ConflictsWith: []string{"label"},
Description: "Searches for applications whose label or name property begins with this value",
},
"apps": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Computed: true,
},
"name": {
Type: schema.TypeString,
Computed: true,
},
"label": {
Type: schema.TypeString,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"links": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
}
}

func dataSourceAppsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
filters, err := getAppsFilters(d)
if err != nil {
return diag.Errorf("invalid apps filters: %v", err)
}

appsResponse, err := listApps(ctx, getOktaClientFromMetadata(m), filters, 200)
if err != nil {
return diag.Errorf("failed to list apps: %v", err)
}
d.SetId(fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(filters.String()))))

if len(appsResponse) > 0 {
appsArr := []map[string]interface{}{}
for _, app := range appsResponse {
// Okta API for list apps uses a starts with query on label and name.
// This can yield unexpected results if an exact match is desired.
// If requested, drop apps that don't match the exact value.
if filters.Label != "" && app.Label != filters.Label && app.Name != filters.Label {
continue
}
links, _ := json.Marshal(app.Links)
app := map[string]interface{}{
"id": app.Id,
"name": app.Name,
"label": app.Label,
"status": app.Status,
"links": string(links),
}
appsArr = append(appsArr, app)
}
_ = d.Set("apps", appsArr)
} else {
_ = d.Set("apps", make([]map[string]interface{}, 0))
}

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

import (
"fmt"
"testing"

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

func TestAccDataSourceOktaApps_read(t *testing.T) {
mgr := newFixtureManager("datasources", apps, t.Name())
appsCreate := appsResources
appsRead := fmt.Sprintf("%s%s", appsResources, appsDataSources)

oktaResourceTest(t, resource.TestCase{
PreCheck: testAccPreCheck(t),
ErrorCheck: testAccErrorChecks(t),
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: mgr.ConfigReplace(appsCreate),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("okta_app_oauth.test1", "id"),
resource.TestCheckResourceAttrSet("okta_app_oauth.test2", "id"),
resource.TestCheckResourceAttrSet("okta_app_oauth.test3", "id"),
),
},
{
Config: mgr.ConfigReplace(appsRead),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.okta_apps.test_by_exact_match", "apps.#", "1"),
resource.TestCheckResourceAttrSet("data.okta_apps.test_by_exact_match", "apps.#.id"),
resource.TestCheckResourceAttr("data.okta_apps.test_by_exact_match", "apps.#.label", fmt.Sprintf("testApp_%s_one", buildResourceName(mgr.Seed))),
resource.TestCheckResourceAttr("data.okta_apps.test_by_exact_match", "apps.#.status", statusActive),

resource.TestCheckResourceAttr("data.okta_apps.test_by_prefix", "apps.#", "2"),

resource.TestCheckResourceAttr("data.okta_apps.test_by_no_match", "apps.#", "0"),
),
},
},
})
}

const appsResources = `
resource "okta_app_oauth" "test1" {
label = "testApp_testAcc_replace_with_uuid_one"
type = "web"
grant_types = ["implicit", "authorization_code"]
redirect_uris = ["http://a.com/"]
response_types = ["code", "token", "id_token"]
issuer_mode = "ORG_URL"
consent_method = "TRUSTED"
}
resource "okta_app_oauth" "test2" {
label = "testApp_testAcc_replace_with_uuid_two"
type = "web"
grant_types = ["implicit", "authorization_code"]
redirect_uris = ["http://b.com/"]
response_types = ["code", "token", "id_token"]
issuer_mode = "ORG_URL"
consent_method = "TRUSTED"
}
resource "okta_app_oauth" "test3" {
label = "testAppInvalid_testAcc_replace_with_uuid"
type = "web"
grant_types = ["implicit", "authorization_code"]
redirect_uris = ["http://c.com/"]
response_types = ["code", "token", "id_token"]
issuer_mode = "ORG_URL"
consent_method = "TRUSTED"
}
`

const appsDataSources = `
data "okta_apps" "test_by_exact_match" {
label = "testApp_testAcc_replace_with_uuid_one"
}
data "okta_apps" "test_by_prefix" {
label_prefix = "testApp_testAcc_replace_with_uuid_"
}
data "okta_apps" "test_by_no_match" {
label = "invalidApp_replace_with_uuid"
}
`
2 changes: 2 additions & 0 deletions okta/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
adminRoleCustomAssignments = "okta_admin_role_custom_assignments"
adminRoleTargets = "okta_admin_role_targets"
app = "okta_app"
apps = "okta_apps"
appAutoLogin = "okta_app_auto_login"
appBasicAuth = "okta_app_basic_auth"
appBookmark = "okta_app_bookmark"
Expand Down Expand Up @@ -331,6 +332,7 @@ func Provider() *schema.Provider {
},
DataSourcesMap: map[string]*schema.Resource{
app: dataSourceApp(),
apps: dataSourceApps(),
appGroupAssignments: dataSourceAppGroupAssignments(),
appMetadataSaml: dataSourceAppMetadataSaml(),
appOAuth: dataSourceAppOauth(),
Expand Down
46 changes: 46 additions & 0 deletions website/docs/d/app.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
layout: 'okta'
page_title: 'Okta: okta_app'
sidebar_current: 'docs-okta-datasource-app'
description: |-
Get an application of any kind from Okta.
---

# okta_app

Use this data source to retrieve an application from Okta.

## Example Usage

```hcl
data "okta_app" "example" {
label = "Example App"
}
```

## Arguments Reference

- `label` - (Optional) The label or name of the app to retrieve, conflicts with `label_prefix` and `id`. Label uses
the `?q=<label>` query parameter exposed by Okta's API. It should be noted that at this time the API searches both `name`
and `label` with a [starts with query](https://developer.okta.com/docs/reference/api/apps/#list-applications) which
may result in multiple apps being returned for the query. The data source further inspects the labels looking for
an exact match.

- `label_prefix` - (Optional) The label or name prefix of the app to retrieve, conflicts with `label` and `id`.
This will tell the provider to do a `starts with` query as opposed to an `equals` query.

- `id` - (Optional) `id` of application to retrieve, conflicts with `label` and `label_prefix`.

- `active_only` - (Optional) tells the provider to query for only `ACTIVE` applications.

## Attributes Reference

- `id` - Application ID.

- `label` - Application label.

- `name` - Application name.

- `status` - Application status.

- `links` - Generic JSON containing discoverable resources related to the app.
45 changes: 45 additions & 0 deletions website/docs/d/apps.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
layout: 'okta'
page_title: 'Okta: okta_apps'
sidebar_current: 'docs-okta-datasource-apps'
description: |-
List applications of any kind from Okta.
---

# okta_app

Use this data source to list applications from Okta.

## Example Usage

```hcl
data "okta_apps" "example" {
label_prefix = "Example App"
}
```

## Arguments Reference

- `label` - (Optional) The label or name of the apps to retrieve, conflicts with `label_prefix`. Both `label` and `label_prefix`
use the `?q=<label>` query parameter exposed by Okta's API. It should be noted that at this time the API searches both `name`
and `label` with a [starts with query](https://developer.okta.com/docs/reference/api/apps/#list-applications).
The data source further inspects the labels looking for an exact match when the `label` parameter is set.

- `label_prefix` - (Optional) The label or name prefix of the apps to retrieve, conflicts with `label`. It should be noted that
Okta's API searches both the `label` and `name` application properties.

- `active_only` - (Optional) tells the provider to query for only `ACTIVE` applications.

## Attributes Reference

- `apps` - collection of applications retrieved from Okta with the following properties.

- `id` - Application ID.

- `label` - Application label.

- `name` - Application name.

- `status` - Application status.

- `links` - Generic JSON containing discoverable resources related to the app.

0 comments on commit 90af3bc

Please sign in to comment.