Skip to content

Commit

Permalink
use gRPC to implement policy sets
Browse files Browse the repository at this point in the history
  • Loading branch information
yoursnerdly committed Dec 9, 2024
1 parent 486d873 commit 375715e
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 141 deletions.
7 changes: 0 additions & 7 deletions cyral/internal/policy/v2/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ import (
"github.com/cyralinc/terraform-provider-cyral/cyral/utils"
)

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

// changeInfoToMap converts ChangeInfo to a map
func changeInfoToMap(c *msg.ChangeInfo) map[string]interface{} {
return map[string]interface{}{
Expand Down
22 changes: 5 additions & 17 deletions cyral/internal/policyset/datasource.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
package policyset

import (
"fmt"
"net/url"

"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.HTTPContextHandler{
ResourceName: dataSourceName,
ResourceType: resourcetype.DataSource,
SchemaWriterFactoryGetMethod: func(_ *schema.ResourceData) core.SchemaWriter { return &PolicySet{} },
ReadUpdateDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
baseURL := &url.URL{
Scheme: "https",
Host: c.ControlPlane,
Path: fmt.Sprintf("%s/%s", apiPathPolicySet, d.Get("id").(string)),
}
return baseURL.String()
},
var dsContextHandler = core.ContextHandler{
ResourceName: dataSourceName,
ResourceType: resourcetype.DataSource,
Read: readPolicySet,
}

func dataSourceSchema() *schema.Resource {
return &schema.Resource{
Description: "This data source provides information about a policy set.",
ReadContext: dsContextHandler.ReadContext(),
ReadContext: dsContextHandler.ReadContext,
Schema: map[string]*schema.Schema{
"id": {
Description: "Identifier for the policy set.",
Expand Down
199 changes: 110 additions & 89 deletions cyral/internal/policyset/model.go
Original file line number Diff line number Diff line change
@@ -1,147 +1,168 @@
package policyset

import (
"context"
"fmt"
"time"

methods "buf.build/gen/go/cyral/policy/grpc/go/policy/v1/policyv1grpc"
msg "buf.build/gen/go/cyral/policy/protocolbuffers/go/policy/v1"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

"github.com/cyralinc/terraform-provider-cyral/cyral/client"
"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{} {
// ToMap converts PolicySetPolicy to a map
func policySetPolicyToMap(p *msg.PolicySetPolicy) map[string]interface{} {
return map[string]interface{}{
"actor": c.Actor,
"actor_type": c.ActorType,
"timestamp": c.Timestamp,
"type": p.GetType().String(),
"id": p.GetId(),
}
}

// PolicySetPolicy represents a policy in the policy set
type PolicySetPolicy struct {
Type string `json:"type,omitempty"`
ID string `json:"id,omitempty"`
func policiesToMaps(policies []*msg.PolicySetPolicy) []map[string]interface{} {
var result []map[string]interface{}
for _, policy := range policies {
result = append(result, policySetPolicyToMap(policy))
}
return result
}

// ToMap converts PolicySetPolicy to a map
func (p PolicySetPolicy) ToMap() map[string]interface{} {
// changeInfoToMap converts ChangeInfo to a map
func changeInfoToMap(c *msg.ChangeInfo) map[string]interface{} {
return map[string]interface{}{
"type": p.Type,
"id": p.ID,
"actor": c.GetActor(),
"actor_type": c.GetActorType().String(),
"timestamp": c.GetTimestamp().AsTime().Format(time.RFC3339),
}
}

// 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{} {
// scopeToMap converts Scope to a list of maps
func scopeToMap(s *msg.Scope) []map[string]interface{} {
return []map[string]interface{}{
{
"repo_ids": s.RepoIds,
"repo_ids": s.GetRepoIds(),
},
}
}

// 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 {
// updateSchema writes the policy set data to the schema
func updateSchema(ps *msg.PolicySet, d *schema.ResourceData) error {
if err := d.Set("id", ps.GetId()); 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("wizard_id", ps.GetWizardId()); err != nil {
return fmt.Errorf("error setting 'id' field: %w", err)
}
if err := d.Set("name", r.Name); err != nil {
if err := d.Set("name", ps.GetName()); err != nil {
return fmt.Errorf("error setting 'name' field: %w", err)
}
if err := d.Set("description", r.Description); err != nil {
if err := d.Set("description", ps.GetDescription()); 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("enabled", ps.GetEnabled()); err != nil {
return fmt.Errorf("error setting 'enabled' 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("tags", ps.GetTags()); err != nil {
return fmt.Errorf("error setting 'tags' 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("wizard_parameters", ps.GetWizardParameters()); err != nil {
return fmt.Errorf("error setting 'document' field: %w", err)
}
if err := d.Set("policies", policiesToMaps(r.Policies)); err != nil {

if err := d.Set("policies", policiesToMaps(ps.GetPolicies())); err != nil {
return fmt.Errorf("error setting 'policies' field: %w", err)
}
if err := d.Set("last_updated", r.LastUpdated.ToMap()); err != nil {
if ps.GetScope() != nil {
if err := d.Set("scope", scopeToMap(ps.GetScope())); err != nil {
return fmt.Errorf("error setting 'scope' field: %w", err)
}
}
// Use the changeInfoToMap method to set the last_updated and created fields
if err := d.Set("last_updated", changeInfoToMap(ps.GetLastUpdated())); err != nil {
return fmt.Errorf("error setting 'last_updated' field: %w", err)
}
if err := d.Set("created", r.Created.ToMap()); err != nil {
if err := d.Set("created", changeInfoToMap(ps.GetCreated())); 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)
d.SetId(ps.GetId())
return nil
}

func policiesToMaps(policies []PolicySetPolicy) []map[string]interface{} {
var result []map[string]interface{}
for _, policy := range policies {
result = append(result, policy.ToMap())
func policySetFromSchema(d *schema.ResourceData) *msg.PolicySet {
p := &msg.PolicySet{
Id: d.Get("id").(string),
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Enabled: d.Get("enabled").(bool),
Tags: utils.ConvertFromInterfaceList[string](d.Get("tags").([]interface{})),
WizardId: d.Get("wizard_id").(string),
WizardParameters: d.Get("wizard_parameters").(string),
}
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{}))
p.Scope = scopeFromInterface(v.([]interface{}))
}
return nil
return p
}

// scopeFromInterface converts the map to a Scope struct
func scopeFromInterface(s []interface{}) *Scope {
func scopeFromInterface(s []interface{}) *msg.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{},
}
return nil
}
m := s[0].(map[string]interface{})
scope := Scope{
return &msg.Scope{
RepoIds: utils.ConvertFromInterfaceList[string](m["repo_ids"].([]interface{})),
}
return &scope
}

func createPolicySet(ctx context.Context, cl *client.Client, rd *schema.ResourceData) error {
ps := policySetFromSchema(rd)
req := &msg.CreatePolicySetRequest{
PolicySet: ps,
}
grpcClient := methods.NewPolicyWizardServiceClient(cl.GRPCClient())
resp, err := grpcClient.CreatePolicySet(ctx, req)
if err != nil {
return err
}
rd.SetId(resp.GetPolicySet().GetId())
return nil
}

func readPolicySet(ctx context.Context, cl *client.Client, rd *schema.ResourceData) error {
req := &msg.ReadPolicySetRequest{
Id: rd.Get("id").(string),
}
grpcClient := methods.NewPolicyWizardServiceClient(cl.GRPCClient())
resp, err := grpcClient.ReadPolicySet(ctx, req)
if err != nil {
return err
}
return updateSchema(resp.GetPolicySet(), rd)
}

func updatePolicySet(ctx context.Context, cl *client.Client, rd *schema.ResourceData) error {
ps := policySetFromSchema(rd)
req := &msg.UpdatePolicySetRequest{
Id: ps.GetId(),
PolicySet: ps,
}
grpcClient := methods.NewPolicyWizardServiceClient(cl.GRPCClient())
resp, err := grpcClient.UpdatePolicySet(ctx, req)
if err != nil {
return err
}
return updateSchema(resp.GetPolicySet(), rd)
}

func deletePolicySet(ctx context.Context, cl *client.Client, rd *schema.ResourceData) error {
req := &msg.DeletePolicySetRequest{
Id: rd.Get("id").(string),
}
grpcClient := methods.NewPolicyWizardServiceClient(cl.GRPCClient())
_, err := grpcClient.DeletePolicySet(ctx, req)
return err
}
39 changes: 11 additions & 28 deletions cyral/internal/policyset/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,29 @@ package policyset

import (
"context"
"fmt"
"net/url"

"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.HTTPContextHandler{
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 {
baseURL := &url.URL{
Scheme: "https",
Host: c.ControlPlane,
Path: apiPathPolicySet,
}
return baseURL.String()
},
ReadUpdateDeleteURLFactory: func(d *schema.ResourceData, c *client.Client) string {
baseURL := &url.URL{
Scheme: "https",
Host: c.ControlPlane,
Path: fmt.Sprintf("%s/%s", apiPathPolicySet, d.Id()),
}
return baseURL.String()
},
var resourceContextHandler = core.ContextHandler{
ResourceName: resourceName,
ResourceType: resourcetype.Resource,
Create: createPolicySet,
Read: readPolicySet,
Update: updatePolicySet,
Delete: deletePolicySet,
}

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(),
CreateContext: resourceContextHandler.CreateContext,
ReadContext: resourceContextHandler.ReadContext,
UpdateContext: resourceContextHandler.UpdateContext,
DeleteContext: resourceContextHandler.DeleteContext,
Importer: &schema.ResourceImporter{
StateContext: importPolicySetStateContext,
},
Expand Down

0 comments on commit 375715e

Please sign in to comment.