From 68fb1eb48683d211c5b13d22ed8c0caa53518cac Mon Sep 17 00:00:00 2001 From: Wilson de Carvalho <796900+wcmjunior@users.noreply.github.com> Date: Thu, 3 Aug 2023 09:04:13 -0700 Subject: [PATCH] Fix error handling in case of state file out of sync (#430) * Add 404 handler on read operations * Add 404 handler on read operations --- cyral/error_handlers.go | 18 ++++++++++++++++++ cyral/resource_cyral_integration_datadog.go | 3 ++- cyral/resource_cyral_integration_elk.go | 3 ++- cyral/resource_cyral_integration_hcvault.go | 3 ++- cyral/resource_cyral_integration_idp_saml.go | 3 ++- cyral/resource_cyral_integration_logging.go | 3 ++- .../resource_cyral_integration_slack_alerts.go | 3 ++- cyral/resource_cyral_integration_teams.go | 3 ++- cyral/resource_cyral_repository.go | 1 + ...resource_cyral_repository_access_gateway.go | 1 + .../resource_cyral_repository_access_rules.go | 1 + cyral/resource_cyral_repository_binding.go | 1 + cyral/resource_cyral_repository_conf_auth.go | 3 ++- ...e_cyral_repository_network_access_policy.go | 3 ++- .../resource_cyral_repository_user_account.go | 1 + cyral/resource_cyral_role_sso_groups.go | 3 ++- cyral/resource_cyral_sidecar_listener.go | 3 ++- 17 files changed, 45 insertions(+), 11 deletions(-) diff --git a/cyral/error_handlers.go b/cyral/error_handlers.go index 37ea4515..d28c1f29 100644 --- a/cyral/error_handlers.go +++ b/cyral/error_handlers.go @@ -25,3 +25,21 @@ func (h *DeleteIgnoreHttpNotFound) HandleError( log.Printf("[DEBUG] %s not found. Skipping deletion.", h.resName) return nil } + +type ReadIgnoreHttpNotFound struct { + resName string +} + +func (h *ReadIgnoreHttpNotFound) HandleError( + r *schema.ResourceData, + _ *client.Client, + err error, +) error { + httpError, ok := err.(*client.HttpError) + if !ok || httpError.StatusCode != http.StatusNotFound { + return err + } + r.SetId("") + log.Printf("[DEBUG] %s not found. Marking resource for recreation.", h.resName) + return nil +} diff --git a/cyral/resource_cyral_integration_datadog.go b/cyral/resource_cyral_integration_datadog.go index d6fb5fea..75e7b089 100644 --- a/cyral/resource_cyral_integration_datadog.go +++ b/cyral/resource_cyral_integration_datadog.go @@ -33,7 +33,8 @@ var ReadDatadogConfig = ResourceOperationConfig{ CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf("https://%s/v1/integrations/datadog/%s", c.ControlPlane, d.Id()) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &DatadogIntegration{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &DatadogIntegration{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Integration datadog"}, } func resourceIntegrationDatadog() *schema.Resource { diff --git a/cyral/resource_cyral_integration_elk.go b/cyral/resource_cyral_integration_elk.go index 2893a61f..e4e7ba55 100644 --- a/cyral/resource_cyral_integration_elk.go +++ b/cyral/resource_cyral_integration_elk.go @@ -36,7 +36,8 @@ var ReadELKConfig = ResourceOperationConfig{ CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf("https://%s/v1/integrations/elk/%s", c.ControlPlane, d.Id()) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ELKIntegration{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ELKIntegration{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Integration elk"}, } func resourceIntegrationELK() *schema.Resource { diff --git a/cyral/resource_cyral_integration_hcvault.go b/cyral/resource_cyral_integration_hcvault.go index cca866af..7d772999 100644 --- a/cyral/resource_cyral_integration_hcvault.go +++ b/cyral/resource_cyral_integration_hcvault.go @@ -32,7 +32,8 @@ var ReadHCVaultIntegrationConfig = ResourceOperationConfig{ CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf("https://%s/v1/integrations/secretProviders/hcvault/%s", c.ControlPlane, d.Id()) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &HCVaultIntegration{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &HCVaultIntegration{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Integration hcvault"}, } func resourceIntegrationHCVault() *schema.Resource { diff --git a/cyral/resource_cyral_integration_idp_saml.go b/cyral/resource_cyral_integration_idp_saml.go index 52807ce8..e9cc6cdd 100644 --- a/cyral/resource_cyral_integration_idp_saml.go +++ b/cyral/resource_cyral_integration_idp_saml.go @@ -86,7 +86,8 @@ func ReadGenericSAMLConfig() ResourceOperationConfig { CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf("https://%s/v1/integrations/generic-saml/sso/%s", c.ControlPlane, d.Id()) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ReadGenericSAMLResponse{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ReadGenericSAMLResponse{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Generic SAML"}, } } diff --git a/cyral/resource_cyral_integration_logging.go b/cyral/resource_cyral_integration_logging.go index 85b45615..040a8a34 100644 --- a/cyral/resource_cyral_integration_logging.go +++ b/cyral/resource_cyral_integration_logging.go @@ -186,7 +186,8 @@ var ReadLoggingIntegration = ResourceOperationConfig{ CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf(loggingApiUrl, c.ControlPlane, d.Id()) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &LoggingIntegration{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &LoggingIntegration{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Integration logging"}, } func UpdateLoggingIntegration() ResourceOperationConfig { diff --git a/cyral/resource_cyral_integration_slack_alerts.go b/cyral/resource_cyral_integration_slack_alerts.go index 5792c666..48a4e514 100644 --- a/cyral/resource_cyral_integration_slack_alerts.go +++ b/cyral/resource_cyral_integration_slack_alerts.go @@ -31,7 +31,8 @@ var ReadSlackAlertsConfig = ResourceOperationConfig{ CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf("https://%s/v1/integrations/notifications/slack/%s", c.ControlPlane, d.Id()) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &SlackAlertsIntegration{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &SlackAlertsIntegration{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Integration Slack"}, } func resourceIntegrationSlackAlerts() *schema.Resource { diff --git a/cyral/resource_cyral_integration_teams.go b/cyral/resource_cyral_integration_teams.go index 7f55f2e9..7a2a3760 100644 --- a/cyral/resource_cyral_integration_teams.go +++ b/cyral/resource_cyral_integration_teams.go @@ -31,7 +31,8 @@ var ReadMsTeamsConfig = ResourceOperationConfig{ CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf("https://%s/v1/integrations/notifications/teams/%s", c.ControlPlane, d.Id()) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &MsTeamsIntegration{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &MsTeamsIntegration{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Integration Teams"}, } func resourceIntegrationMsTeams() *schema.Resource { diff --git a/cyral/resource_cyral_repository.go b/cyral/resource_cyral_repository.go index f154664a..7be80dfb 100644 --- a/cyral/resource_cyral_repository.go +++ b/cyral/resource_cyral_repository.go @@ -281,6 +281,7 @@ var ReadRepositoryConfig = ResourceOperationConfig{ NewResponseData: func(_ *schema.ResourceData) ResponseData { return &GetRepoByIDResponse{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Repository"}, } func resourceRepository() *schema.Resource { diff --git a/cyral/resource_cyral_repository_access_gateway.go b/cyral/resource_cyral_repository_access_gateway.go index 0d7f5c38..511aff77 100644 --- a/cyral/resource_cyral_repository_access_gateway.go +++ b/cyral/resource_cyral_repository_access_gateway.go @@ -46,6 +46,7 @@ var ReadRepositoryAccessGatewayConfig = ResourceOperationConfig{ NewResponseData: func(_ *schema.ResourceData) ResponseData { return &GetOrUpdateAccessGateway{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Repository access gateway"}, } func resourceRepositoryAccessGateway() *schema.Resource { diff --git a/cyral/resource_cyral_repository_access_rules.go b/cyral/resource_cyral_repository_access_rules.go index 40ed420c..eff6af49 100644 --- a/cyral/resource_cyral_repository_access_rules.go +++ b/cyral/resource_cyral_repository_access_rules.go @@ -139,6 +139,7 @@ var ReadRepositoryAccessRulesConfig = ResourceOperationConfig{ NewResponseData: func(_ *schema.ResourceData) ResponseData { return &AccessRulesResponse{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Repository access rule"}, } func resourceRepositoryAccessRules() *schema.Resource { diff --git a/cyral/resource_cyral_repository_binding.go b/cyral/resource_cyral_repository_binding.go index 746212db..d2ea3c66 100644 --- a/cyral/resource_cyral_repository_binding.go +++ b/cyral/resource_cyral_repository_binding.go @@ -117,6 +117,7 @@ var ReadRepositoryBindingConfig = ResourceOperationConfig{ NewResponseData: func(_ *schema.ResourceData) ResponseData { return &GetBindingResponse{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Repository binding"}, } func resourceRepositoryBinding() *schema.Resource { diff --git a/cyral/resource_cyral_repository_conf_auth.go b/cyral/resource_cyral_repository_conf_auth.go index 90393308..ef4065de 100644 --- a/cyral/resource_cyral_repository_conf_auth.go +++ b/cyral/resource_cyral_repository_conf_auth.go @@ -143,7 +143,8 @@ func ReadConfAuthConfig() ResourceOperationConfig { CreateURL: func(d *schema.ResourceData, c *client.Client) string { return fmt.Sprintf(repositoryConfAuthURLFormat, c.ControlPlane, d.Get("repository_id")) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ReadRepositoryConfAuthResponse{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ReadRepositoryConfAuthResponse{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Repository conf auth"}, } } diff --git a/cyral/resource_cyral_repository_network_access_policy.go b/cyral/resource_cyral_repository_network_access_policy.go index 84db8229..27dc81c7 100644 --- a/cyral/resource_cyral_repository_network_access_policy.go +++ b/cyral/resource_cyral_repository_network_access_policy.go @@ -117,7 +117,8 @@ func readRepositoryNetworkAccessPolicy() ResourceOperationConfig { return fmt.Sprintf(repositoryNetworkAccessPolicyURLFormat, c.ControlPlane, d.Get("repository_id")) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &NetworkAccessPolicy{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &NetworkAccessPolicy{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Repository network access policy"}, } } diff --git a/cyral/resource_cyral_repository_user_account.go b/cyral/resource_cyral_repository_user_account.go index aa35b975..73b01f58 100644 --- a/cyral/resource_cyral_repository_user_account.go +++ b/cyral/resource_cyral_repository_user_account.go @@ -318,6 +318,7 @@ var ReadRepositoryUserAccountConfig = ResourceOperationConfig{ NewResponseData: func(_ *schema.ResourceData) ResponseData { return &UserAccountResource{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "User account"}, } func resourceRepositoryUserAccount() *schema.Resource { diff --git a/cyral/resource_cyral_role_sso_groups.go b/cyral/resource_cyral_role_sso_groups.go index e159f394..d8d4d6ed 100644 --- a/cyral/resource_cyral_role_sso_groups.go +++ b/cyral/resource_cyral_role_sso_groups.go @@ -138,7 +138,8 @@ var readRoleSSOGroupsConfig = ResourceOperationConfig{ return fmt.Sprintf("https://%s/v1/users/groups/%s/mappings", c.ControlPlane, d.Get("role_id").(string)) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &RoleSSOGroupsReadResponse{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &RoleSSOGroupsReadResponse{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Role SSO groups"}, } var deleteRoleSSOGroupsConfig = ResourceOperationConfig{ diff --git a/cyral/resource_cyral_sidecar_listener.go b/cyral/resource_cyral_sidecar_listener.go index 28062374..b094ebca 100644 --- a/cyral/resource_cyral_sidecar_listener.go +++ b/cyral/resource_cyral_sidecar_listener.go @@ -58,7 +58,8 @@ var ReadSidecarListenersConfig = ResourceOperationConfig{ d.Get(SidecarIDKey).(string), d.Get(ListenerIDKey).(string)) }, - NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ReadSidecarListenerAPIResponse{} }, + NewResponseData: func(_ *schema.ResourceData) ResponseData { return &ReadSidecarListenerAPIResponse{} }, + RequestErrorHandler: &ReadIgnoreHttpNotFound{resName: "Sidecar listener"}, } type ReadSidecarListenerAPIResponse struct {