Skip to content
Open
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
2 changes: 1 addition & 1 deletion .go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.22.9
1.23.5
37 changes: 37 additions & 0 deletions docs/data-sources/ai_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "launchdarkly_ai_config Data Source - launchdarkly"
subcategory: ""
description: |-
Provides a LaunchDarkly AI Config data source.
This data source allows you to retrieve AI Config information from your LaunchDarkly project.
-> Note: AI Configs are currently in beta.
---

# launchdarkly_ai_config (Data Source)

Provides a LaunchDarkly AI Config data source.

This data source allows you to retrieve AI Config information from your LaunchDarkly project.

-> **Note:** AI Configs are currently in beta.



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

### Required

- `key` (String) The unique key of the AI Config.
- `project_key` (String) The project key.

### Read-Only

- `description` (String) The description of the AI Config.
- `id` (String) The ID of this resource.
- `maintainer_id` (String) The ID of the member who maintains this AI Config.
- `maintainer_team_key` (String) The key of the team that maintains this AI Config.
- `name` (String) The human-readable name of the AI Config.
- `tags` (Set of String) Tags associated with the AI Config.
- `version` (Number) The version of the AI Config.
40 changes: 40 additions & 0 deletions docs/resources/ai_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "launchdarkly_ai_config Resource - launchdarkly"
subcategory: ""
description: |-
Provides a LaunchDarkly AI Config resource.
This resource allows you to create and manage AI Configs within your LaunchDarkly project.
-> Note: AI Configs are currently in beta.
---

# launchdarkly_ai_config (Resource)

Provides a LaunchDarkly AI Config resource.

This resource allows you to create and manage AI Configs within your LaunchDarkly project.

-> **Note:** AI Configs are currently in beta.



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

### Required

- `key` (String) The unique key of the AI Config.
- `name` (String) The human-readable name of the AI Config.
- `project_key` (String) The project key.

### Optional

- `description` (String) The description of the AI Config.
- `maintainer_id` (String) The ID of the member who maintains this AI Config.
- `maintainer_team_key` (String) The key of the team that maintains this AI Config.
- `tags` (Set of String) Tags associated with the AI Config.

### Read-Only

- `id` (String) The ID of this resource.
- `version` (Number) The version of the AI Config.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
)

require (
github.com/launchdarkly/api-client-go/v17 v17.1.0
github.com/launchdarkly/api-client-go/v17 v17.2.0
golang.org/x/sync v0.16.0
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+
github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg=
github.com/launchdarkly/api-client-go/v17 v17.1.0 h1:IbR5UDLKBmff0eRBSD3UgVDfgnifOepBIe4gqivMaec=
github.com/launchdarkly/api-client-go/v17 v17.1.0/go.mod h1:lMTmhEjepXfam8xm8b0ERBJbV9g8vdu9nbKueDXcB5o=
github.com/launchdarkly/api-client-go/v17 v17.2.0 h1:5CJxDaL7ZgqALAcohNUMlV7hfXR65s2czZ4XmZjW/qI=
github.com/launchdarkly/api-client-go/v17 v17.2.0/go.mod h1:lMTmhEjepXfam8xm8b0ERBJbV9g8vdu9nbKueDXcB5o=
github.com/ldez/gomoddirectives v0.2.2/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0=
github.com/ldez/tagliatelle v0.3.0/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88=
github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY=
Expand Down
14 changes: 14 additions & 0 deletions launchdarkly/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type Client struct {
// ld is the standard API client that we use in most cases to interact with LaunchDarkly's APIs.
ld *ldapi.APIClient

ldBeta *ldapi.APIClient

// ld404Retry is the same as ld except that it will also retry 404s with an exponential backoff. In most cases `ld` should be used instead. sc-218015
ld404Retry *ldapi.APIClient
ctx context.Context
Expand Down Expand Up @@ -73,12 +75,23 @@ func newLDClientConfig(apiHost string, httpTimeoutSeconds int, apiVersion string
return cfg
}

func newLDClientConfigNoVersion(apiHost string, httpTimeoutSeconds int, retryPolicy retryablehttp.CheckRetry) *ldapi.Configuration {
cfg := ldapi.NewConfiguration()
cfg.Host = apiHost
cfg.DefaultHeader = make(map[string]string)
cfg.UserAgent = fmt.Sprintf("launchdarkly-terraform-provider/%s", version)
cfg.HTTPClient = newRetryableClient(retryPolicy)
cfg.HTTPClient.Timeout = time.Duration(httpTimeoutSeconds) * time.Second
return cfg
}

func baseNewClient(token string, apiHost string, oauth bool, httpTimeoutSeconds int, apiVersion string, maxConcurrent int) (*Client, error) {
if token == "" {
return nil, errors.New("token cannot be empty")
}

standardConfig := newLDClientConfig(apiHost, httpTimeoutSeconds, apiVersion, standardRetryPolicy)
betaConfigNoVersion := newLDClientConfigNoVersion(apiHost, httpTimeoutSeconds, standardRetryPolicy)
configWith404Retries := newLDClientConfig(apiHost, httpTimeoutSeconds, apiVersion, retryPolicyWith404Retries)

ctx := context.WithValue(context.Background(), ldapi.ContextAPIKeys, map[string]ldapi.APIKey{
Expand All @@ -97,6 +110,7 @@ func baseNewClient(token string, apiHost string, oauth bool, httpTimeoutSeconds
apiKey: token,
apiHost: apiHost,
ld: ldapi.NewAPIClient(standardConfig),
ldBeta: ldapi.NewAPIClient(betaConfigNoVersion),
ld404Retry: ldapi.NewAPIClient(configWith404Retries),
ctx: ctx,
fallbackClient: fallbackClient,
Expand Down
69 changes: 69 additions & 0 deletions launchdarkly/data_source_launchdarkly_ai_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package launchdarkly

import (
"context"

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

func dataSourceAIConfig() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceAIConfigRead,
Schema: map[string]*schema.Schema{
PROJECT_KEY: {
Type: schema.TypeString,
Required: true,
Description: "The project key.",
},
KEY: {
Type: schema.TypeString,
Required: true,
Description: "The unique key of the AI Config.",
},
NAME: {
Type: schema.TypeString,
Computed: true,
Description: "The human-readable name of the AI Config.",
},
DESCRIPTION: {
Type: schema.TypeString,
Computed: true,
Description: "The description of the AI Config.",
},
TAGS: {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "Tags associated with the AI Config.",
},
MAINTAINER_ID: {
Type: schema.TypeString,
Computed: true,
Description: "The ID of the member who maintains this AI Config.",
},
MAINTAINER_TEAM_KEY: {
Type: schema.TypeString,
Computed: true,
Description: "The key of the team that maintains this AI Config.",
},
VERSION: {
Type: schema.TypeInt,
Computed: true,
Description: "The version of the AI Config.",
},
},
Description: `Provides a LaunchDarkly AI Config data source.

This data source allows you to retrieve AI Config information from your LaunchDarkly project.

-> **Note:** AI Configs are currently in beta.`,
}
}

func dataSourceAIConfigRead(ctx context.Context, d *schema.ResourceData, metaRaw interface{}) diag.Diagnostics {
projectKey := d.Get(PROJECT_KEY).(string)
key := d.Get(KEY).(string)
d.SetId(projectKey + "/" + key)
return resourceAIConfigRead(ctx, d, metaRaw)
}
118 changes: 118 additions & 0 deletions launchdarkly/data_source_launchdarkly_ai_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package launchdarkly

import (
"fmt"
"regexp"
"testing"

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

const (
testAccDataSourceAIConfig = `
resource "launchdarkly_ai_config" "test" {
project_key = launchdarkly_project.test.key
key = "test-ai-config"
name = "Test AI Config"
description = "Test description"
tags = ["terraform", "test"]
}

data "launchdarkly_ai_config" "test" {
project_key = launchdarkly_ai_config.test.project_key
key = launchdarkly_ai_config.test.key
}
`

testAccDataSourceAIConfigWithTeamFmt = `
resource "launchdarkly_team" "test" {
key = "%s"
name = "Test Team"
}

resource "launchdarkly_ai_config" "test" {
project_key = launchdarkly_project.test.key
key = "test-ai-config"
name = "Test AI Config"
maintainer_team_key = launchdarkly_team.test.key
}

data "launchdarkly_ai_config" "test" {
project_key = launchdarkly_ai_config.test.project_key
key = launchdarkly_ai_config.test.key
}
`
)

func TestAccDataSourceAIConfig_exists(t *testing.T) {
projectKey := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
resourceName := "data.launchdarkly_ai_config.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: withRandomProject(projectKey, testAccDataSourceAIConfig),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(resourceName, ID),
resource.TestCheckResourceAttr(resourceName, NAME, "Test AI Config"),
resource.TestCheckResourceAttr(resourceName, KEY, "test-ai-config"),
resource.TestCheckResourceAttr(resourceName, PROJECT_KEY, projectKey),
resource.TestCheckResourceAttr(resourceName, DESCRIPTION, "Test description"),
resource.TestCheckResourceAttr(resourceName, "tags.#", "2"),
resource.TestCheckResourceAttrSet(resourceName, VERSION),
),
},
},
})
}

func TestAccDataSourceAIConfig_existsWithTeamMaintainer(t *testing.T) {
projectKey := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
teamKey := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
resourceName := "data.launchdarkly_ai_config.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: withRandomProject(projectKey, fmt.Sprintf(testAccDataSourceAIConfigWithTeamFmt, teamKey)),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(resourceName, ID),
resource.TestCheckResourceAttr(resourceName, NAME, "Test AI Config"),
resource.TestCheckResourceAttr(resourceName, KEY, "test-ai-config"),
resource.TestCheckResourceAttr(resourceName, PROJECT_KEY, projectKey),
resource.TestCheckResourceAttr(resourceName, MAINTAINER_TEAM_KEY, teamKey),
resource.TestCheckResourceAttrSet(resourceName, VERSION),
),
},
},
})
}

func TestAccDataSourceAIConfig_noMatchReturnsError(t *testing.T) {
projectKey := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
aiConfigKey := acctest.RandStringFromCharSet(24, acctest.CharSetAlphaNum)
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: withRandomProject(projectKey, fmt.Sprintf(`
data "launchdarkly_ai_config" "test" {
project_key = launchdarkly_project.test.key
key = "%s"
}
`, aiConfigKey)),
ExpectError: regexp.MustCompile(`failed to get AI config`),
},
},
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ func TestAccDataSourceFeatureFlagEnvironment_exists(t *testing.T) {
require.NoError(t, err)
}()

thisConfig := flag.Environments[envKey]
otherConfig := flag.Environments["production"]
thisConfig := (*flag.Environments)[envKey]
otherConfig := (*flag.Environments)["production"]

flagId := projectKey + "/" + flagKey
resourceName := "data.launchdarkly_feature_flag_environment.test"
Expand Down Expand Up @@ -283,8 +283,8 @@ func TestAccDataSourceFeatureFlagEnvironment_WithContextFields(t *testing.T) {
require.NoError(t, err)
}()

thisConfig := flag.Environments[envKey]
otherConfig := flag.Environments["production"]
thisConfig := (*flag.Environments)[envKey]
otherConfig := (*flag.Environments)["production"]

flagId := projectKey + "/" + flagKey
resourceName := "data.launchdarkly_feature_flag_environment.test"
Expand Down
12 changes: 11 additions & 1 deletion launchdarkly/feature_flag_environment_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,17 @@ func featureFlagEnvironmentRead(ctx context.Context, d *schema.ResourceData, raw
return diag.Errorf("failed to get flag %q of project %q: %s", flagKey, projectKey, handleLdapiErr(err))
}

environment, ok := flag.Environments[envKey]
if flag.Environments == nil {
log.Printf("[WARN] failed to find environments for flag %q, removing from state", flagKey)
diags = append(diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: fmt.Sprintf("[WARN] failed to find environments for flag %q, removing from state", flagKey),
})
d.SetId("")
return diags
}

environment, ok := (*flag.Environments)[envKey]
if !ok {
log.Printf("[WARN] failed to find environment %q for flag %q, removing from state", envKey, flagKey)
diags = append(diags, diag.Diagnostic{
Expand Down
2 changes: 2 additions & 0 deletions launchdarkly/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func Provider() *schema.Provider {
"launchdarkly_audit_log_subscription": resourceAuditLogSubscription(),
"launchdarkly_relay_proxy_configuration": resourceRelayProxyConfig(),
"launchdarkly_metric": resourceMetric(),
"launchdarkly_ai_config": resourceAIConfig(),
},
DataSourcesMap: map[string]*schema.Resource{
"launchdarkly_team": dataSourceTeam(),
Expand All @@ -92,6 +93,7 @@ func Provider() *schema.Provider {
"launchdarkly_audit_log_subscription": dataSourceAuditLogSubscription(),
"launchdarkly_relay_proxy_configuration": dataSourceRelayProxyConfig(),
"launchdarkly_metric": dataSourceMetric(),
"launchdarkly_ai_config": dataSourceAIConfig(),
},
ConfigureContextFunc: providerConfigure,
}
Expand Down
Loading
Loading