From a548eaf90376570ef89a0cb5727f317fb4a9c0b3 Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Thu, 8 Aug 2024 13:14:25 +0200 Subject: [PATCH] Allow provider to start without credentials (#195) Without RSC credentials the provider still support CDM bootstrapping. --- go.mod | 2 +- go.sum | 4 +-- internal/provider/provider.go | 48 +++++++++++++++++------------- internal/provider/provider_test.go | 45 +++++++++++++++++++++------- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index 13892c2..ad70967 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/terraform-plugin-docs v0.16.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.0 - github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.11.0-beta.1 + github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.11.0-beta.2 ) require ( diff --git a/go.sum b/go.sum index d9063d6..65ab3b7 100644 --- a/go.sum +++ b/go.sum @@ -412,8 +412,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.11.0-beta.1 h1:9yIQxW8d2outzWALXSuxDrcYGryy/7RQJ7d6ZCZbaeI= -github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.11.0-beta.1/go.mod h1:ryJGDKlbaCvozY3Wvt+TPSN2OZRChQedHUNsnVfCbXE= +github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.11.0-beta.2 h1:JQlwbV6KsgEJ9CczJAWYvKS5cCc9ozuB0wV7lKQBrDI= +github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.11.0-beta.2/go.mod h1:ryJGDKlbaCvozY3Wvt+TPSN2OZRChQedHUNsnVfCbXE= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= diff --git a/internal/provider/provider.go b/internal/provider/provider.go index bb2abd8..9937541 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -23,6 +23,7 @@ package provider import ( "context" "errors" + "fmt" "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -116,23 +117,12 @@ func Provider() *schema.Provider { type client struct { cdmClient *cdm.BootstrapClient polarisClient *polaris.Client -} - -func newClient(account polaris.Account, params polaris.CacheParams, logger log.Logger) (*client, diag.Diagnostics) { - polarisClient, err := polaris.NewClientWithLoggerAndCacheParams(account, params, logger) - if err != nil { - return nil, diag.FromErr(err) - } - - return &client{ - cdmClient: cdm.NewBootstrapClientWithLogger(true, logger), - polarisClient: polarisClient, - }, nil + polarisErr error } func (c *client) cdm() (*cdm.BootstrapClient, error) { if c.cdmClient == nil { - return nil, errors.New("cdm functionality has not been configured in the provider block") + return nil, errors.New("CDM functionality has not been configured in the provider block") } return c.cdmClient, nil @@ -140,7 +130,11 @@ func (c *client) cdm() (*cdm.BootstrapClient, error) { func (c *client) polaris() (*polaris.Client, error) { if c.polarisClient == nil { - return nil, errors.New("polaris functionality has not been configured in the provider block") + err := errors.New("RSC functionality has not been configured in the provider block") + if c.polarisErr != nil { + err = fmt.Errorf("%s: %s", err, c.polarisErr) + } + return nil, err } return c.polarisClient, nil @@ -153,17 +147,29 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData) (any, diag.D return nil, diag.FromErr(err) } + client := &client{ + cdmClient: cdm.NewBootstrapClientWithLogger(true, logger), + } + account, err := polaris.FindAccount(d.Get("credentials").(string), true) - if err != nil { + switch { + case errors.Is(err, polaris.ErrAccountNotFound): + client.polarisErr = err + case err != nil: return nil, diag.FromErr(err) + default: + cacheParams := polaris.CacheParams{ + Enable: d.Get("token_cache").(bool), + Dir: d.Get("token_cache_dir").(string), + Secret: d.Get("token_cache_secret").(string), + } + client.polarisClient, err = polaris.NewClientWithLoggerAndCacheParams(account, cacheParams, logger) + if err != nil { + return nil, diag.FromErr(err) + } } - cacheParams := polaris.CacheParams{ - Enable: d.Get("token_cache").(bool), - Dir: d.Get("token_cache_dir").(string), - Secret: d.Get("token_cache_secret").(string), - } - return newClient(account, cacheParams, logger) + return client, nil } // description returns the description string with all acute accents replaced diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index cbdc82d..55490b9 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -56,8 +56,7 @@ func TestAccProviderCredentialsInEnv_basic(t *testing.T) { t.Fatal(err) } - // Valid service account in env. - t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS", credentials) + // Valid service account in RUBRIK_POLARIS_SERVICEACCOUNT_FILE. resource.Test(t, resource.TestCase{ ProviderFactories: providerFactories, Steps: []resource.TestStep{{ @@ -69,31 +68,43 @@ func TestAccProviderCredentialsInEnv_basic(t *testing.T) { }}, }) - // Invalid service account in env. - t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS", "invalid") + // Non-existing service account in RUBRIK_POLARIS_SERVICEACCOUNT_FILE. + t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_FILE", "03147711-359c-40fd-b635-69619fcf374d") resource.Test(t, resource.TestCase{ ProviderFactories: providerFactories, Steps: []resource.TestStep{{ Config: credentialsFromEnv, - ExpectError: regexp.MustCompile("failed to unmarshal RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS: invalid character 'i' looking for beginning of value"), + ExpectError: regexp.MustCompile("RSC functionality has not been configured in the provider block: account not found, searched: default service account file and env"), }}, }) -} -func TestAccProviderMissingCredentialsInEnv_basic(t *testing.T) { - // No service account in env. This could happen if the provider is used to - // bootstrap a CDM cluster without RSC credentials, but an RSC resource is - // used. + // Valid service account in RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS. + t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_FILE", "") + t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS", credentials) + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories, + Steps: []resource.TestStep{{ + Config: credentialsFromEnv, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.polaris_role.admin", "id", "00000000-0000-0000-0000-000000000000"), + resource.TestCheckResourceAttr("data.polaris_role.admin", "name", "Administrator"), + ), + }}, + }) + + // Invalid service account in RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS. + t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS", "invalid") resource.Test(t, resource.TestCase{ ProviderFactories: providerFactories, Steps: []resource.TestStep{{ Config: credentialsFromEnv, - ExpectError: regexp.MustCompile("polaris functionality has not been configured in the provider block"), + ExpectError: regexp.MustCompile("RSC functionality has not been configured in the provider block: account not found, searched: default service account file and env"), }}, }) // Partial service account in env. This could happen if the service account // is given in parts and one of the parts is missing. + t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_CREDENTIALS", "") t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_NAME", "name") resource.Test(t, resource.TestCase{ ProviderFactories: providerFactories, @@ -102,6 +113,18 @@ func TestAccProviderMissingCredentialsInEnv_basic(t *testing.T) { ExpectError: regexp.MustCompile("invalid service account client id"), }}, }) + + // No service account in env. This could happen if the provider is used to + // bootstrap a CDM cluster without RSC credentials, but an RSC resource is + // used. + t.Setenv("RUBRIK_POLARIS_SERVICEACCOUNT_NAME", "") + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories, + Steps: []resource.TestStep{{ + Config: credentialsFromEnv, + ExpectError: regexp.MustCompile("RSC functionality has not been configured in the provider block: account not found, searched: default service account file and env"), + }}, + }) } // loadTestCredentials returns the content of the file pointed to by the