Skip to content
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
20 changes: 14 additions & 6 deletions .github/workflows/acctest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

name: Tests
on: [ pull_request ]
on: [pull_request]
jobs:
acctest:
name: Run acceptance tests
Expand Down Expand Up @@ -53,11 +53,19 @@ jobs:
sudo mv terraform-provider-streamnative $HOME/.terraform.d/plugins/linux_amd64/
echo "The terraform-provider-streamnative location:" `readlink -f $HOME/.terraform.d/plugins/linux_amd64/`

# - name: Setup tmate session
# uses: mxschmitt/action-tmate@v3
# - name: Setup tmate session
# uses: mxschmitt/action-tmate@v3

- name: Run Acceptance Tests for the Provider
- name: Ready the environment
run: |
echo $ACC_TEST_SERVICE_ACCOUNT > $HOME/service_account.json
export KEY_FILE_PATH=$HOME/service_account.json
make testacc

- name: Run Acceptance Tests for the Provider
uses: nick-fields/retry@v2
with:
timeout_minutes: 120
max_attempts: 3
retry_on: error
command: |
export KEY_FILE_PATH=$HOME/service_account.json
make testacc
111 changes: 111 additions & 0 deletions cloud/data_source_secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright 2024 StreamNative, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cloud

import (
"context"
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func dataSourceSecret() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceSecretRead,
Importer: &schema.ResourceImporter{
StateContext: func(
ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), "/")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid import id %q, expected <organization>/<name>", d.Id())
}
_ = d.Set("organization", parts[0])
_ = d.Set("name", parts[1])
if diags := dataSourceSecretRead(ctx, d, meta); diags.HasError() {
return nil, fmt.Errorf("import %q: %s", d.Id(), diags[0].Summary)
}
return []*schema.ResourceData{d}, nil
},
},
Comment on lines +31 to +45
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Data sources should not have an Importer field. The Importer is only applicable to resources, not data sources. Data sources are read-only and don't maintain state that needs to be imported. Other data sources in the codebase (e.g., cloud/data_source_volume.go) do not define an Importer.

Suggested change
Importer: &schema.ResourceImporter{
StateContext: func(
ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), "/")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid import id %q, expected <organization>/<name>", d.Id())
}
_ = d.Set("organization", parts[0])
_ = d.Set("name", parts[1])
if diags := dataSourceSecretRead(ctx, d, meta); diags.HasError() {
return nil, fmt.Errorf("import %q: %s", d.Id(), diags[0].Summary)
}
return []*schema.ResourceData{d}, nil
},
},

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

we have multiple existing data sources have Importer blocks, so we may remove such in future PRs, this PR will not cover such changes.

Schema: map[string]*schema.Schema{
"organization": {
Type: schema.TypeString,
Required: true,
Description: descriptions["organization"],
ValidateFunc: validateNotBlank,
},
"name": {
Type: schema.TypeString,
Required: true,
Description: descriptions["secret_name"],
ValidateFunc: validateNotBlank,
},
"instance_name": {
Type: schema.TypeString,
Computed: true,
Description: descriptions["instance_name"],
},
"location": {
Type: schema.TypeString,
Computed: true,
Description: descriptions["location"],
},
"pool_member_name": {
Type: schema.TypeString,
Computed: true,
Description: descriptions["pool_member_name"],
},
"type": {
Type: schema.TypeString,
Computed: true,
Description: descriptions["secret_type"],
},
"data": {
Type: schema.TypeMap,
Computed: true,
Sensitive: true,
Description: descriptions["secret_data"],
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func dataSourceSecretRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
namespace := d.Get("organization").(string)
name := d.Get("name").(string)

clientSet, err := getClientSet(getFactoryFromMeta(meta))
if err != nil {
return diag.FromErr(fmt.Errorf("ERROR_INIT_CLIENT_ON_READ_SECRET: %w", err))
}

secret, err := clientSet.CloudV1alpha1().Secrets(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
if apierrors.IsNotFound(err) {
d.SetId("")
return nil
}
return diag.FromErr(fmt.Errorf("ERROR_READ_SECRET: %w", err))
}

return setSecretState(d, secret)
}
6 changes: 6 additions & 0 deletions cloud/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ func init() {
"cluster_display_name": "The pulsar cluster display name",
"admin": "Whether the service account is admin",
"private_key_data": "The private key data",
"secret_name": "The secret name",
"secret_data": "The secret data map",
"secret_string_data": "Write-only string data that will be stored encrypted by the API server",
"secret_type": "The Kubernetes secret type",
"availability-mode": "The availability mode, supporting 'zonal' and 'regional'",
"pool_name": "The infrastructure pool name",
"pool_namespace": "The infrastructure pool namespace",
Expand Down Expand Up @@ -249,6 +253,7 @@ func Provider() *schema.Provider {
"streamnative_rolebinding": resourceRoleBinding(),
"streamnative_volume": resourceVolume(),
"streamnative_catalog": resourceCatalog(),
"streamnative_secret": resourceSecret(),
},
DataSourcesMap: map[string]*schema.Resource{
"streamnative_service_account": dataSourceServiceAccount(),
Expand All @@ -265,6 +270,7 @@ func Provider() *schema.Provider {
"streamnative_rolebinding": dataSourceRoleBinding(),
"streamnative_volume": dataSourceVolume(),
"streamnative_catalog": dataSourceCatalog(),
"streamnative_secret": dataSourceSecret(),
},
}
provider.ConfigureContextFunc = func(_ context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
Expand Down
4 changes: 4 additions & 0 deletions cloud/resource_pulsar_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func resourcePulsarCluster() *schema.Resource {
return []*schema.ResourceData{d}, nil
},
},
Timeouts: &schema.ResourceTimeout{
// Pulsar clusters can take time to tear down; allow 30m to avoid spurious test failures.
Delete: schema.DefaultTimeout(30 * time.Minute),
},
Comment on lines +70 to +73
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

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

[nitpick] This timeout configuration change appears unrelated to the PR's stated purpose of adding SN Cloud secrets support. Consider moving this change to a separate PR or adding context to the PR description explaining why this is included.

Suggested change
Timeouts: &schema.ResourceTimeout{
// Pulsar clusters can take time to tear down; allow 30m to avoid spurious test failures.
Delete: schema.DefaultTimeout(30 * time.Minute),
},

Copilot uses AI. Check for mistakes.
Schema: map[string]*schema.Schema{
"organization": {
Type: schema.TypeString,
Expand Down
Loading
Loading