Skip to content

Commit

Permalink
Added policy wizards API. Note! not including the listing of wizards,…
Browse files Browse the repository at this point in the history
… but only management of policy sets.
  • Loading branch information
gengdahlCyral committed Nov 25, 2024
1 parent 6f73352 commit d56ad7f
Show file tree
Hide file tree
Showing 18 changed files with 851 additions and 20 deletions.
7 changes: 7 additions & 0 deletions cyral/internal/policywizard/v1/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package policywizardv1

const (
resourceName = "cyral_policy_wizard_v1"
dataSourceName = resourceName
apiPathPolicySet = "v1/policyWizards/policySets"
)
111 changes: 111 additions & 0 deletions cyral/internal/policywizard/v1/datasource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package policywizardv1

import (
"fmt"

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

"github.com/cyralinc/terraform-provider-cyral/cyral/client"
"github.com/cyralinc/terraform-provider-cyral/cyral/core"
"github.com/cyralinc/terraform-provider-cyral/cyral/core/types/resourcetype"
)

var dsContextHandler = core.DefaultContextHandler{
ResourceName: dataSourceName,
ResourceType: resourcetype.DataSource,
SchemaWriterFactoryGetMethod: func(_ *schema.ResourceData) core.SchemaWriter { return &PolicySet{} },
ReadUpdateDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
return fmt.Sprintf("https://%s/%s/%s", c.ControlPlane, apiPathPolicySet, d.Get("id").(string))
},
}

func dataSourceSchema() *schema.Resource {
return &schema.Resource{
Description: "This data source provides information about a policy set.",
ReadContext: dsContextHandler.ReadContext(),
Schema: map[string]*schema.Schema{
"id": {
Description: "Identifier for the policy set.",
Type: schema.TypeString,
Required: true,
},
"wizard_id": {
Description: "The ID of the policy wizard used to create this policy set.",
Type: schema.TypeString,
Computed: true,
},
"name": {
Description: "Name of the policy set.",
Type: schema.TypeString,
Computed: true,
},
"description": {
Description: "Description of the policy set.",
Type: schema.TypeString,
Computed: true,
},
"tags": {
Description: "Tags associated with the policy set.",
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"scope": {
Description: "Scope of the policy set.",
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"repo_ids": {
Description: "List of repository IDs that are in scope. Empty list means all repositories are in scope.",
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Computed: true,
},
},
},
},
"wizard_parameters": {
Description: "Parameters passed to the wizard while creating the policy set.",
Type: schema.TypeString,
Computed: true,
},
"enabled": {
Description: "Indicates if the policy set is enabled.",
Type: schema.TypeBool,
Computed: true,
},
"policies": {
Description: "List of policies that comprise the policy set.",
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Description: "Type of the policy.",
Type: schema.TypeString,
Computed: true,
},
"id": {
Description: "ID of the policy.",
Type: schema.TypeString,
Computed: true,
},
},
},
},
"last_updated": {
Description: "Information about when and by whom the policy set was last updated.",
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"created": {
Description: "Information about when and by whom the policy set was created.",
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}
147 changes: 147 additions & 0 deletions cyral/internal/policywizard/v1/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package policywizardv1

import (
"fmt"

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

"github.com/cyralinc/terraform-provider-cyral/cyral/utils"
)

// ChangeInfo represents information about changes to the policy set
type ChangeInfo struct {
Actor string `json:"actor,omitempty"`
ActorType string `json:"actorType,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
}

// ToMap converts ChangeInfo to a map
func (c ChangeInfo) ToMap() map[string]interface{} {
return map[string]interface{}{
"actor": c.Actor,
"actor_type": c.ActorType,
"timestamp": c.Timestamp,
}
}

// PolicySetPolicy represents a policy in the policy set
type PolicySetPolicy struct {
Type string `json:"type,omitempty"`
ID string `json:"id,omitempty"`
}

// ToMap converts PolicySetPolicy to a map
func (p PolicySetPolicy) ToMap() map[string]interface{} {
return map[string]interface{}{
"type": p.Type,
"id": p.ID,
}
}

// Scope represents the scope of the policy set
type Scope struct {
RepoIds []string `json:"repoIds,omitempty"`
}

// ToMap converts Scope to a list of maps
func (s *Scope) ToMap() []map[string]interface{} {
return []map[string]interface{}{
{
"repo_ids": s.RepoIds,
},
}
}

// PolicySet represents the policy set details
type PolicySet struct {
ID string `json:"id,omitempty"`
WizardID string `json:"wizardId,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Tags []string `json:"tags,omitempty"`
Scope *Scope `json:"scope,omitempty"`
WizardParameters string `json:"wizardParameters,omitempty"`
Enabled bool `json:"enabled,omitempty"`
Policies []PolicySetPolicy `json:"policies,omitempty"`
LastUpdated ChangeInfo `json:"lastUpdated,omitempty"`
Created ChangeInfo `json:"created,omitempty"`
}

// WriteToSchema writes the policy set data to the schema
func (r *PolicySet) WriteToSchema(d *schema.ResourceData) error {
if err := d.Set("id", r.ID); err != nil {
return fmt.Errorf("error setting 'id' field: %w", err)
}
if err := d.Set("wizard_id", r.WizardID); err != nil {
return fmt.Errorf("error setting 'wizard_id' field: %w", err)
}
if err := d.Set("name", r.Name); err != nil {
return fmt.Errorf("error setting 'name' field: %w", err)
}
if err := d.Set("description", r.Description); err != nil {
return fmt.Errorf("error setting 'description' field: %w", err)
}
if err := d.Set("tags", r.Tags); err != nil {
return fmt.Errorf("error setting 'tags' field: %w", err)
}
if err := d.Set("wizard_parameters", r.WizardParameters); err != nil {
return fmt.Errorf("error setting 'wizard_parameters' field: %w", err)
}
if err := d.Set("enabled", r.Enabled); err != nil {
return fmt.Errorf("error setting 'enabled' field: %w", err)
}
if err := d.Set("policies", policiesToMaps(r.Policies)); err != nil {
return fmt.Errorf("error setting 'policies' field: %w", err)
}
if err := d.Set("last_updated", r.LastUpdated.ToMap()); err != nil {
return fmt.Errorf("error setting 'last_updated' field: %w", err)
}
if err := d.Set("created", r.Created.ToMap()); err != nil {
return fmt.Errorf("error setting 'created' field: %w", err)
}
if r.Scope != nil {
if err := d.Set("scope", r.Scope.ToMap()); err != nil {
return fmt.Errorf("error setting 'scope' field: %w", err)
}
}
d.SetId(r.ID)
return nil
}

func policiesToMaps(policies []PolicySetPolicy) []map[string]interface{} {
var result []map[string]interface{}
for _, policy := range policies {
result = append(result, policy.ToMap())
}
return result
}

// ReadFromSchema reads the policy set data from the schema
func (r *PolicySet) ReadFromSchema(d *schema.ResourceData) error {
r.ID = d.Get("id").(string)
r.WizardID = d.Get("wizard_id").(string)
r.Name = d.Get("name").(string)
r.Description = d.Get("description").(string)
r.Tags = utils.ConvertFromInterfaceList[string](d.Get("tags").([]interface{}))
r.WizardParameters = d.Get("wizard_parameters").(string)
r.Enabled = d.Get("enabled").(bool)
if v, ok := d.GetOk("scope"); ok {
r.Scope = scopeFromInterface(v.([]interface{}))
}
return nil
}

// scopeFromInterface converts the map to a Scope struct
func scopeFromInterface(s []interface{}) *Scope {
if len(s) == 0 || s[0] == nil {
// return an empty scope (ie a scope with a repo ids array of length 0)
return &Scope{
RepoIds: []string{},
}
}
m := s[0].(map[string]interface{})
scope := Scope{
RepoIds: utils.ConvertFromInterfaceList[string](m["repo_ids"].([]interface{})),
}
return &scope
}
130 changes: 130 additions & 0 deletions cyral/internal/policywizard/v1/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package policywizardv1

import (
"context"
"fmt"

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

"github.com/cyralinc/terraform-provider-cyral/cyral/client"
"github.com/cyralinc/terraform-provider-cyral/cyral/core"
"github.com/cyralinc/terraform-provider-cyral/cyral/core/types/resourcetype"
)

var resourceContextHandler = core.DefaultContextHandler{
ResourceName: resourceName,
ResourceType: resourcetype.Resource,
SchemaReaderFactory: func() core.SchemaReader { return &PolicySet{} },
SchemaWriterFactoryGetMethod: func(_ *schema.ResourceData) core.SchemaWriter { return &PolicySet{} },
BaseURLFactory: func(d *schema.ResourceData, c *client.Client) string {
return fmt.Sprintf("https://%s/%s", c.ControlPlane, apiPathPolicySet)
},
ReadUpdateDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
return fmt.Sprintf("https://%s/%s/%s",
c.ControlPlane,
apiPathPolicySet,
d.Id(),
)
},
}

func resourceSchema() *schema.Resource {
return &schema.Resource{
Description: "This resource allows management of policy sets in the Cyral platform.",
CreateContext: resourceContextHandler.CreateContext(),
ReadContext: resourceContextHandler.ReadContext(),
UpdateContext: resourceContextHandler.UpdateContext(),
DeleteContext: resourceContextHandler.DeleteContext(),
Importer: &schema.ResourceImporter{
StateContext: importPolicySetStateContext,
},
Schema: map[string]*schema.Schema{
"id": {
Description: "Identifier for the policy set.",
Type: schema.TypeString,
Computed: true,
},
"wizard_id": {
Description: "The ID of the policy wizard used to create this policy set.",
Type: schema.TypeString,
Required: true,
},
"name": {
Description: "Name of the policy set.",
Type: schema.TypeString,
Required: true,
},
"description": {
Description: "Description of the policy set.",
Type: schema.TypeString,
Optional: true,
},
"tags": {
Description: "Tags associated with the policy set.",
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"scope": {
Description: "Scope of the policy set.",
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"repo_ids": {
Description: "List of repository IDs that are in scope. Empty list means all repositories are in scope.",
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
},
},
},
},
"wizard_parameters": {
Description: "Parameters passed to the wizard while creating the policy set.",
Type: schema.TypeString,
Required: true,
},
"enabled": {
Description: "Indicates if the policy set is enabled.",
Type: schema.TypeBool,
Optional: true,
},
"policies": {
Description: "List of policies that comprise the policy set.",
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Description: "Type of the policy.",
Type: schema.TypeString,
Computed: true,
},
"id": {
Description: "ID of the policy.",
Type: schema.TypeString,
Computed: true,
},
},
},
},
"last_updated": {
Description: "Information about when and by whom the policy set was last updated.",
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"created": {
Description: "Information about when and by whom the policy set was created.",
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
}
}

func importPolicySetStateContext(_ context.Context, d *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
return []*schema.ResourceData{d}, nil
}
Loading

0 comments on commit d56ad7f

Please sign in to comment.