Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor remaining resources and data sources #522

Merged
merged 11 commits into from
Apr 9, 2024
4 changes: 2 additions & 2 deletions cyral/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (r *NewFeature) ReadFromSchema(d *schema.ResourceData) error {

### datasource.go

Use the `GetPutDeleteURLFactory` to provide the URL factory to read the data source from the API.
Use the `ReadUpdateDeleteURLFactory` to provide the URL factory to read the data source from the API.

```go
// datasource.go
Expand All @@ -75,7 +75,7 @@ var dsContextHandler = core.DefaultContextHandler{
ResourceName: dataSourceName,
ResourceType: resourcetype.DataSource,
SchemaWriterFactoryGetMethod: func(_ *schema.ResourceData) core.SchemaWriter { return &NewFeature{} },
GetPutDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
ReadUpdateDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
return fmt.Sprintf("https://%s/v1/NewFeature/%s", c.ControlPlane, d.Get("my_id_field").(string))
},
}
Expand Down
30 changes: 19 additions & 11 deletions cyral/core/default_context_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import (
// an `id` field, meaning it will use the
// `IDBasedResponse` struct in such cases.
// 3. `BaseURLFactory` must be provided for resources. It will be used to
// create the POST endpoint and others in case `GetPutDeleteURLFactory`
// create the POST endpoint and others in case `ReadUpdateDeleteURLFactory`
// is not provided.
// 4. `GetPutDeleteURLFactory` must be provided for data sources.
// 5. If `GetPutDeleteURLFactory` is NOT provided (data sources or resources),
// the endpoint to perform GET, PUT and DELETE calls are composed by the
// 4. `ReadUpdateDeleteURLFactory` must be provided for data sources.
// 5. If `ReadUpdateDeleteURLFactory` is NOT provided (data sources or resources),
// the endpoints to perform GET, PUT, PATCH and DELETE calls are composed by the
// `BaseURLFactory` endpoint plus the ID specification as follows:
// - POST: https://<CP>/<apiVersion>/<featureName>
// - GET: https://<CP>/<apiVersion>/<featureName>/<id>
// - PUT: https://<CP>/<apiVersion>/<featureName>/<id>
// - PATCH: https://<CP>/<apiVersion>/<featureName>/<id>
// - DELETE: https://<CP>/<apiVersion>/<featureName>/<id>
type DefaultContextHandler struct {
ResourceName string
Expand All @@ -41,10 +42,13 @@ type DefaultContextHandler struct {
// written in POST operations.
SchemaWriterFactoryPostMethod SchemaWriterFactoryFunc
// BaseURLFactory provides the URL used for POSTs and that
// will also be used to compose the ID URL for GET, PUT and
// DELETE in case `GetPutDeleteURLFactory` is not provided.
BaseURLFactory URLFactoryFunc
GetPutDeleteURLFactory URLFactoryFunc
// will also be used to compose the ID URL for GET, PUT/PATCH and
// DELETE in case `ReadUpdateDeleteURLFactory` is not provided.
BaseURLFactory URLFactoryFunc
ReadUpdateDeleteURLFactory URLFactoryFunc

// Http method for update operations. If not provided, assumes http.MethodPut
UpdateMethod string
}

func DefaultSchemaWriterFactory(d *schema.ResourceData) SchemaWriter {
Expand All @@ -64,8 +68,8 @@ func (dch DefaultContextHandler) defaultOperationHandler(
var url string
if httpMethod == http.MethodPost {
url = dch.BaseURLFactory(d, c)
} else if dch.GetPutDeleteURLFactory != nil {
url = dch.GetPutDeleteURLFactory(d, c)
} else if dch.ReadUpdateDeleteURLFactory != nil {
url = dch.ReadUpdateDeleteURLFactory(d, c)
} else {
url = fmt.Sprintf("%s/%s", dch.BaseURLFactory(d, c), d.Id())
}
Expand Down Expand Up @@ -122,8 +126,12 @@ func (dch DefaultContextHandler) UpdateContext() schema.UpdateContextFunc {

func (dch DefaultContextHandler) UpdateContextCustomErrorHandling(getErrorHandler RequestErrorHandler,
putErrorHandler RequestErrorHandler) schema.UpdateContextFunc {
updateMethod := http.MethodPut
if dch.UpdateMethod != "" {
updateMethod = dch.UpdateMethod
}
return UpdateResource(
dch.defaultOperationHandler(ot.Update, http.MethodPut, dch.SchemaReaderFactory, nil, putErrorHandler),
dch.defaultOperationHandler(ot.Update, updateMethod, dch.SchemaReaderFactory, nil, putErrorHandler),
dch.defaultOperationHandler(ot.Update, http.MethodGet, nil, dch.SchemaWriterFactoryGetMethod, getErrorHandler),
)
}
Expand Down
8 changes: 4 additions & 4 deletions cyral/internal/datalabel/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

var getPutDeleteURLFactory = func(d *schema.ResourceData, c *client.Client) string {
var readUpdateDeleteURLFactory = func(d *schema.ResourceData, c *client.Client) string {
return fmt.Sprintf("https://%s/v1/datalabels/%s",
c.ControlPlane,
d.Get("name").(string))
Expand All @@ -27,7 +27,7 @@ func resourceSchema() *schema.Resource {
ResourceType: resourcetype.Resource,
SchemaReaderFactory: func() core.SchemaReader { return &DataLabel{} },
SchemaWriterFactoryGetMethod: func(_ *schema.ResourceData) core.SchemaWriter { return &DataLabel{} },
GetPutDeleteURLFactory: getPutDeleteURLFactory,
ReadUpdateDeleteURLFactory: readUpdateDeleteURLFactory,
}
return &schema.Resource{
Description: "Manages data labels. Data labels are part of the Cyral [Data Map](https://cyral.com/docs/policy/datamap).",
Expand All @@ -36,7 +36,7 @@ func resourceSchema() *schema.Resource {
ResourceName: resourceName,
Type: operationtype.Create,
HttpMethod: http.MethodPut,
URLFactory: getPutDeleteURLFactory,
URLFactory: readUpdateDeleteURLFactory,
SchemaReaderFactory: func() core.SchemaReader { return &DataLabel{} },
SchemaWriterFactory: func(_ *schema.ResourceData) core.SchemaWriter { return &DataLabel{} },
}, readDataLabelConfig,
Expand Down Expand Up @@ -116,7 +116,7 @@ var readDataLabelConfig = core.ResourceOperationConfig{
ResourceName: resourceName,
Type: operationtype.Read,
HttpMethod: http.MethodGet,
URLFactory: getPutDeleteURLFactory,
URLFactory: readUpdateDeleteURLFactory,
SchemaWriterFactory: func(_ *schema.ResourceData) core.SchemaWriter { return &DataLabel{} },
RequestErrorHandler: &core.IgnoreHttpNotFound{ResName: "Data Label"},
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package samlconfiguration
package deprecated

import (
"context"
Expand All @@ -7,7 +7,6 @@ import (
"net/http"

"github.com/cyralinc/terraform-provider-cyral/cyral/client"
"github.com/cyralinc/terraform-provider-cyral/cyral/internal/deprecated"
"github.com/cyralinc/terraform-provider-cyral/cyral/utils"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-log/tflog"
Expand All @@ -21,6 +20,8 @@ var (

func DataSourceSAMLConfiguration() *schema.Resource {
return &schema.Resource{
DeprecationMessage: "This data source has been deprecated. It will be removed in the next major version of " +
"the provider.",
Description: "Parses a SAML metadata URL or a Base64 document into a SAML configuration." +
"\n\nSee also the remaining SAML-related resources and data sources.",
ReadContext: dataSourceSAMLConfigurationRead,
Expand Down Expand Up @@ -182,7 +183,7 @@ func dataSourceSAMLConfigurationRead(ctx context.Context, d *schema.ResourceData
return utils.CreateError("Unable to retrieve saml configuration", fmt.Sprintf("%v", err))
}

response := deprecated.SAMLConfiguration{}
response := SAMLConfiguration{}
if err := json.Unmarshal(body, &response); err != nil {
return utils.CreateError("Unable to unmarshall JSON", fmt.Sprintf("%v", err))
}
Expand All @@ -197,14 +198,14 @@ func dataSourceSAMLConfigurationRead(ctx context.Context, d *schema.ResourceData
return diag.Diagnostics{}
}

func getSAMLMetadataRequestFromSchema(d *schema.ResourceData) deprecated.ParseSAMLMetadataRequest {
return deprecated.ParseSAMLMetadataRequest{
func getSAMLMetadataRequestFromSchema(d *schema.ResourceData) ParseSAMLMetadataRequest {
return ParseSAMLMetadataRequest{
SamlMetadataURL: d.Get("saml_metadata_url").(string),
Base64SamlMetadataDocument: d.Get("base_64_saml_metadata_document").(string),
}
}

func setSAMLConfigurationToSchema(d *schema.ResourceData, data deprecated.SAMLConfiguration) {
func setSAMLConfigurationToSchema(d *schema.ResourceData, data SAMLConfiguration) {
if data.Config != nil {
d.Set("disable_using_jwks_url", data.Config.DisableUsingJWKSUrl)
d.Set("sync_mode", data.Config.SyncMode)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package samlconfiguration_test
package deprecated_test

import (
"fmt"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const CloudFormationDeploymentMethod = "cft-ec2"

func DataSourceSidecarCftTemplate() *schema.Resource {
return &schema.Resource{
DeprecationMessage: "This data source was deprecated. It will be removed in the next major version of " +
DeprecationMessage: "This data source has been deprecated. It will be removed in the next major version of " +
"the provider and no longer works for control planes `v4.13` and later.",
Description: "Retrieves the CloudFormation deployment template for a given sidecar. This data source only " +
"supports sidecars with `cft-ec2` deployment method. For Terraform template, use our " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type DeprecatedSidecarInstances struct {

func DataSourceSidecarInstanceIDs() *schema.Resource {
return &schema.Resource{
DeprecationMessage: "This data source was deprecated. It will be removed in the next major version of " +
DeprecationMessage: "This data source has been deprecated. It will be removed in the next major version of " +
"the provider. Use the data source `cyral_sidecar_instance` instead",
Description: "Retrieves the IDs of all the current instances of a given sidecar.",
ReadContext: dataSourceSidecarInstanceIDsRead,
Expand Down
9 changes: 9 additions & 0 deletions cyral/internal/integration/awsiam/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package awsiam

const (
resourceName = "cyral_integration_aws_iam"

AWSIAMIntegrationNameKey = "name"
AWSIAMIntegratioNDescriptionKey = "description"
AWSIAMIntegrationARNsKey = "role_arns"
)
53 changes: 53 additions & 0 deletions cyral/internal/integration/awsiam/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package awsiam

import (
"fmt"

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

type AWSIAMIntegrationWrapper struct {
Integration *AWSIAMIntegration `json:"iamIntegration"`
}

type AWSIAMIntegration struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
IAMRoleARNs []string `json:"iamRoleARNs"`
}

func (wrapper AWSIAMIntegrationWrapper) WriteToSchema(d *schema.ResourceData) error {
integration := wrapper.Integration

d.SetId(integration.ID)

if err := d.Set(AWSIAMIntegrationNameKey, integration.Name); err != nil {
return fmt.Errorf("error setting '%s': %w", AWSIAMIntegrationNameKey, err)
}

if err := d.Set(AWSIAMIntegratioNDescriptionKey, integration.Description); err != nil {
return fmt.Errorf("error setting '%s': %w", AWSIAMIntegratioNDescriptionKey, err)
}

if err := d.Set(AWSIAMIntegrationARNsKey, integration.IAMRoleARNs); err != nil {
return fmt.Errorf("error setting '%s': %w", AWSIAMIntegrationARNsKey, err)
}
return nil
}

func (wrapper *AWSIAMIntegrationWrapper) ReadFromSchema(d *schema.ResourceData) error {
wrapper.Integration = &AWSIAMIntegration{}

wrapper.Integration.Name = d.Get(AWSIAMIntegrationNameKey).(string)
wrapper.Integration.Description = d.Get(AWSIAMIntegratioNDescriptionKey).(string)

arns := d.Get(AWSIAMIntegrationARNsKey).([]interface{})
stringARNs := make([]string, 0, len(arns))
for _, arn := range arns {
stringARNs = append(stringARNs, arn.(string))
}

wrapper.Integration.IAMRoleARNs = stringARNs
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

const (
AWSIAMIntegrationNameKey = "name"
AWSIAMIntegratioNDescriptionKey = "description"
AWSIAMIntegrationARNsKey = "role_arns"
)

type AWSIAMIntegrationWrapper struct {
Integration *AWSIAMIntegration `json:"iamIntegration"`
}

type AWSIAMIntegration struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
IAMRoleARNs []string `json:"iamRoleARNs"`
}

func (wrapper *AWSIAMIntegrationWrapper) WriteToSchema(d *schema.ResourceData) error {
integration := wrapper.Integration

d.SetId(integration.ID)

if err := d.Set(AWSIAMIntegrationNameKey, integration.Name); err != nil {
return fmt.Errorf("error setting '%s': %w", AWSIAMIntegrationNameKey, err)
}

if err := d.Set(AWSIAMIntegratioNDescriptionKey, integration.Description); err != nil {
return fmt.Errorf("error setting '%s': %w", AWSIAMIntegratioNDescriptionKey, err)
}

if err := d.Set(AWSIAMIntegrationARNsKey, integration.IAMRoleARNs); err != nil {
return fmt.Errorf("error setting '%s': %w", AWSIAMIntegrationARNsKey, err)
}
return nil
}

func (wrapper *AWSIAMIntegrationWrapper) ReadFromSchema(d *schema.ResourceData) error {
wrapper.Integration = &AWSIAMIntegration{}

wrapper.Integration.Name = d.Get(AWSIAMIntegrationNameKey).(string)
wrapper.Integration.Description = d.Get(AWSIAMIntegratioNDescriptionKey).(string)

arns := d.Get(AWSIAMIntegrationARNsKey).([]interface{})
stringARNs := make([]string, 0, len(arns))
for _, arn := range arns {
stringARNs = append(stringARNs, arn.(string))
}

wrapper.Integration.IAMRoleARNs = stringARNs
return nil
}

func ResourceIntegrationAWSIAM() *schema.Resource {
func resourceSchema() *schema.Resource {
contextHandler := core.DefaultContextHandler{
ResourceName: "AWS IAM Integration",
ResourceType: resourcetype.Resource,
Expand Down
24 changes: 24 additions & 0 deletions cyral/internal/integration/awsiam/schema_loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package awsiam

import "github.com/cyralinc/terraform-provider-cyral/cyral/core"

type packageSchema struct {
}

func (p *packageSchema) Name() string {
return "integration.awsiam"
}

func (p *packageSchema) Schemas() []*core.SchemaDescriptor {
return []*core.SchemaDescriptor{
{
Name: resourceName,
Type: core.ResourceSchemaType,
Schema: resourceSchema,
},
}
}

func PackageSchema() core.PackageSchema {
return &packageSchema{}
}
9 changes: 9 additions & 0 deletions cyral/internal/integration/confextension/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package confextension

const (
authorizationPurpose = "authorization"
builtinCategory = "builtin"

PagerDutyTemplateType = "pagerduty"
DuoMFATemplateType = "duoMfa"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package mfaduo

const (
resourceName = "cyral_integration_mfa_duo"
)
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
package mfaduo

import (
"github.com/cyralinc/terraform-provider-cyral/cyral/core"
ce "github.com/cyralinc/terraform-provider-cyral/cyral/internal/integration/confextension"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func ResourceIntegrationMFADuo() *schema.Resource {
func resourceSchema() *schema.Resource {
return &schema.Resource{
Description: "Manages [integration with Duo MFA](https://cyral.com/docs/mfa/duo).",
CreateContext: core.CreateResource(
ce.ConfExtensionIntegrationCreate(ce.DuoMFATemplateType),
ce.ConfExtensionIntegrationRead(ce.DuoMFATemplateType)),
ReadContext: core.ReadResource(ce.ConfExtensionIntegrationRead(ce.DuoMFATemplateType)),
UpdateContext: core.UpdateResource(
ce.ConfExtensionIntegrationUpdate(ce.DuoMFATemplateType),
ce.ConfExtensionIntegrationRead(ce.DuoMFATemplateType)),
DeleteContext: core.DeleteResource(ce.ConfExtensionIntegrationDelete(ce.DuoMFATemplateType)),
Description: "Manages [integration with Duo MFA](https://cyral.com/docs/mfa/duo).",
CreateContext: ce.CreateResource(resourceName, ce.DuoMFATemplateType),
ReadContext: ce.ReadResource(resourceName, ce.DuoMFATemplateType),
UpdateContext: ce.UpdateResource(resourceName, ce.DuoMFATemplateType),
DeleteContext: ce.DeleteResource(resourceName, ce.DuoMFATemplateType),

Schema: map[string]*schema.Schema{
"id": {
Expand Down
Loading
Loading