Skip to content

Commit

Permalink
Add terraform resource and data source changes to support infrastruct…
Browse files Browse the repository at this point in the history
…ure application
  • Loading branch information
SaiDadireddy committed Sep 26, 2024
1 parent 4e12a27 commit 3b495bc
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 1 deletion.
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/cloudflare/terraform-provider-cloudflare

go 1.21
go 1.22.0

toolchain go1.22.5

require (
Expand Down Expand Up @@ -32,6 +33,8 @@ require (
golang.org/x/time v0.6.0 // indirect
)

replace github.com/cloudflare/cloudflare-go => ../cloudflare-go

require (
github.com/MakeNowJust/heredoc/v2 v2.0.1
github.com/aws/aws-sdk-go-v2 v1.30.5
Expand Down
21 changes: 21 additions & 0 deletions internal/sdkv2provider/resource_cloudflare_access_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ func resourceCloudflareAccessApplicationCreate(ctx context.Context, d *schema.Re
newAccessApplication.SaasApplication = convertSaasSchemaToStruct(d)
}

if _, ok := d.GetOk("target_criteria"); ok {
target_contexts, err := convertTargetContextsToStruct(d)
if err != nil {
return diag.FromErr(err)
}
newAccessApplication.TargetContexts = target_contexts
}

if value, ok := d.GetOk("tags"); ok {
newAccessApplication.Tags = expandInterfaceToStringList(value.(*schema.Set).List())
}
Expand Down Expand Up @@ -244,6 +252,11 @@ func resourceCloudflareAccessApplicationRead(ctx context.Context, d *schema.Reso
return diag.FromErr(fmt.Errorf("error setting Access Application SaaS app configuration: %w", saasConfigErr))
}

targetContexts := convertTargetContextsToSchema(accessApplication.TargetContexts)
if targetContextsErr := d.Set("target_criteria", targetContexts); targetContextsErr != nil {
return diag.FromErr(fmt.Errorf("error setting Access Application Infrastructure app configuration: %w", targetContextsErr))
}

if _, ok := d.GetOk("self_hosted_domains"); ok {
d.Set("self_hosted_domains", accessApplication.SelfHostedDomains)
}
Expand Down Expand Up @@ -328,6 +341,14 @@ func resourceCloudflareAccessApplicationUpdate(ctx context.Context, d *schema.Re
updatedAccessApplication.SaasApplication = saasConfig
}

if _, ok := d.GetOk("target_criteria"); ok {
target_contexts, err := convertTargetContextsToStruct(d)
if err != nil {
return diag.FromErr(err)
}
updatedAccessApplication.TargetContexts = target_contexts
}

if value, ok := d.GetOk("tags"); ok {
updatedAccessApplication.Tags = expandInterfaceToStringList(value.(*schema.Set).List())
}
Expand Down
48 changes: 48 additions & 0 deletions internal/sdkv2provider/resource_cloudflare_access_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,32 @@ func apiAccessPolicyApprovalGroupToSchema(approvalGroup cloudflare.AccessApprova
return data
}

func apiAccessPolicyConnectionRulesToAPI(connectionRules map[string]interface{}) (*cloudflare.InfraConnectionRules, error) {
sshData, ok := connectionRules["ssh"].(cloudflare.InfraConnectionRulesSSH)
if !ok {
return &cloudflare.InfraConnectionRules{}, fmt.Errorf("failed to parse connection_rules: supported connection rule types: [SSH]")
}

return &cloudflare.InfraConnectionRules{
SSH: &cloudflare.InfraConnectionRulesSSH{
Usernames: sshData.Usernames,
},
}, nil
}

func apiAccessPolicyConnectionRulesToSchema(connectionRules *cloudflare.InfraConnectionRules) map[string]interface{} {
if connectionRules == nil {
return map[string]interface{}{}
}

targetContextsSchema := make(map[string]interface{})
targetContextsSchema["ssh"] = map[string]interface{}{
"usernames": connectionRules.SSH.Usernames,
}

return targetContextsSchema
}

func schemaAccessPolicyApprovalGroupToAPI(data map[string]interface{}) cloudflare.AccessApprovalGroup {
var approvalGroup cloudflare.AccessApprovalGroup

Expand All @@ -87,6 +113,10 @@ func apiCloudflareAccessPolicyToResource(ctx context.Context, d *schema.Resource
d.Set("name", accessPolicy.Name)
d.Set("decision", accessPolicy.Decision)

if err := d.Set("connection_rules", apiAccessPolicyConnectionRulesToSchema(accessPolicy.InfraConnectionRules)); err != nil {
return diag.FromErr(fmt.Errorf("failed to set connection_rules attribute: %w", err))
}

if err := d.Set("require", TransformAccessGroupForSchema(ctx, accessPolicy.Require)); err != nil {
return diag.FromErr(fmt.Errorf("failed to set require attribute: %w", err))
}
Expand Down Expand Up @@ -166,6 +196,15 @@ func resourceCloudflareAccessPolicyCreate(ctx context.Context, d *schema.Resourc
return diag.FromErr(fmt.Errorf("application_id is required for non-account level Access Policies"))
}

connectionRulesSchema, ok := d.Get("connection_rules").(map[string]interface{})
if ok {
connectionRules, err := apiAccessPolicyConnectionRulesToAPI(connectionRulesSchema)
if err != nil {
return diag.FromErr(err)
}
newAccessPolicy.InfraConnectionRules = connectionRules
}

exclude := d.Get("exclude").([]interface{})
for _, value := range exclude {
if value != nil {
Expand Down Expand Up @@ -230,6 +269,15 @@ func resourceCloudflareAccessPolicyUpdate(ctx context.Context, d *schema.Resourc
SessionDuration: cloudflare.StringPtr(d.Get("session_duration").(string)),
}

connectionRulesSchema, ok := d.Get("connection_rules").(map[string]interface{})
if ok {
connectionRules, err := apiAccessPolicyConnectionRulesToAPI(connectionRulesSchema)
if err != nil {
return diag.FromErr(err)
}
updateReq.InfraConnectionRules = connectionRules
}

exclude := d.Get("exclude").([]interface{})
for _, value := range exclude {
if value != nil {
Expand Down
96 changes: 96 additions & 0 deletions internal/sdkv2provider/schema_cloudflare_access_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,36 @@ func resourceCloudflareAccessApplicationSchema() map[string]*schema.Schema {
},
},
},
"target_criteria": {
Type: schema.TypeList,
Optional: true,
Description: "A list of mappings to apply to SCIM resources before provisioning them in this application. These can transform or filter the resources to be provisioned.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"port": {
Type: schema.TypeInt,
Required: true,
Description: "Which SCIM resource type this mapping applies to.",
ValidateFunc: validation.StringMatch(regexp.MustCompile(`urn:.*`), "schema must begin with \"urn:\""),
},
"protocol": {
Type: schema.TypeString,
Required: true,
Description: "Whether or not this mapping is enabled.",
},
"target_attributes": {
Type: schema.TypeMap,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
},
"auto_redirect_to_identity": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -933,6 +963,49 @@ func convertSaasSchemaToStruct(d *schema.ResourceData) *cloudflare.SaasApplicati
return &SaasConfig
}

func convertTargetContextsToStruct(d *schema.ResourceData) (*[]cloudflare.InfraTargetContext, error) {
TargetContexts := []cloudflare.InfraTargetContext{}
if value, ok := d.GetOk("target_criteria"); ok {
targetCriteria := value.([]interface{})
targetContext := cloudflare.InfraTargetContext{}
for _, item := range targetCriteria {
itemMap := item.(map[string]interface{})

if port, ok := itemMap["port"].(int); ok {
targetContext.Port = port
}
if protocol, ok := itemMap["protocol"].(string); ok {
switch protocol {
case "SSH":
targetContext.Protocol = cloudflare.InfraSSH
case "RDP":
targetContext.Protocol = cloudflare.RDP
default:
return &[]cloudflare.InfraTargetContext{}, fmt.Errorf("failed to parse protocol: value must be one of SSH or RDP")
}
}

if targetAttributes, ok := itemMap["target_attributes"].(map[string]interface{}); ok {
attributes := make(map[string][]string)
for key, value := range targetAttributes {
valueList := value.([]interface{})
var stringValues []string
for _, val := range valueList {
stringValues = append(stringValues, val.(string))
}
attributes[key] = stringValues
}

targetContext.TargetAttributes = attributes
}

TargetContexts = append(TargetContexts, targetContext)
}

}
return &TargetContexts, nil
}

func convertLandingPageDesignSchemaToStruct(d *schema.ResourceData) *cloudflare.AccessLandingPageDesign {
LandingPageDesign := cloudflare.AccessLandingPageDesign{}
if _, ok := d.GetOk("landing_page_design"); ok {
Expand Down Expand Up @@ -1234,6 +1307,29 @@ func convertSaasStructToSchema(d *schema.ResourceData, app *cloudflare.SaasAppli
}
}

func convertTargetContextsToSchema(targetContexts *[]cloudflare.InfraTargetContext) []interface{} {
if targetContexts == nil {
return []interface{}{}
}

var targetContextsSchema []interface{}
for _, targetContext := range *targetContexts {
targetContextSchema := make(map[string]interface{})

targetContextSchema["port"] = targetContext.Port
targetContextSchema["protocol"] = targetContext.Protocol

attributeMap := make(map[string]interface{})
for key, values := range targetContext.TargetAttributes {
attributeMap[key] = values
}
targetContextSchema["target_attributes"] = attributeMap

targetContextsSchema = append(targetContextsSchema, targetContextSchema)
}
return targetContextsSchema
}

func convertScimConfigStructToSchema(scimConfig *cloudflare.AccessApplicationSCIMConfig) []interface{} {
if scimConfig == nil {
return []interface{}{}
Expand Down
15 changes: 15 additions & 0 deletions internal/sdkv2provider/schema_cloudflare_access_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,21 @@ func resourceCloudflareAccessPolicySchema() map[string]*schema.Schema {
},
Description: "How often a user will be forced to re-authorise. Must be in the format `48h` or `2h45m`",
},
"connection_rules": {
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"ssh": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
}
}

Expand Down

0 comments on commit 3b495bc

Please sign in to comment.