@@ -55,6 +55,39 @@ func resourceServiceV1() *schema.Resource {
5555 },
5656 },
5757
58+ "condition" : & schema.Schema {
59+ Type : schema .TypeSet ,
60+ Optional : true ,
61+ Elem : & schema.Resource {
62+ Schema : map [string ]* schema.Schema {
63+ "name" : & schema.Schema {
64+ Type : schema .TypeString ,
65+ Required : true ,
66+ },
67+ "statement" : & schema.Schema {
68+ Type : schema .TypeString ,
69+ Required : true ,
70+ Description : "The statement used to determine if the condition is met" ,
71+ StateFunc : func (v interface {}) string {
72+ value := v .(string )
73+ // Trim newlines and spaces, to match Fastly API
74+ return strings .TrimSpace (value )
75+ },
76+ },
77+ "priority" : & schema.Schema {
78+ Type : schema .TypeInt ,
79+ Required : true ,
80+ Description : "A number used to determine the order in which multiple conditions execute. Lower numbers execute first" ,
81+ },
82+ "type" : & schema.Schema {
83+ Type : schema .TypeString ,
84+ Required : true ,
85+ Description : "Type of the condition, either `REQUEST`, `RESPONSE`, or `CACHE`" ,
86+ },
87+ },
88+ },
89+ },
90+
5891 "default_ttl" : & schema.Schema {
5992 Type : schema .TypeInt ,
6093 Optional : true ,
@@ -409,6 +442,7 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
409442 "header" ,
410443 "gzip" ,
411444 "s3logging" ,
445+ "condition" ,
412446 } {
413447 if d .HasChange (v ) {
414448 needsChange = true
@@ -463,13 +497,70 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
463497 }
464498 }
465499
500+ // Conditions need to be updated first, as they can be referenced by other
501+ // configuraiton objects (Backends, Request Headers, etc)
502+
503+ // Find difference in Conditions
504+ if d .HasChange ("condition" ) {
505+ // Note: we don't utilize the PUT endpoint to update these objects, we simply
506+ // destroy any that have changed, and create new ones with the updated
507+ // values. This is how Terraform works with nested sub resources, we only
508+ // get the full diff not a partial set item diff. Because this is done
509+ // on a new version of the Fastly Service configuration, this is considered safe
510+
511+ oc , nc := d .GetChange ("condition" )
512+ if oc == nil {
513+ oc = new (schema.Set )
514+ }
515+ if nc == nil {
516+ nc = new (schema.Set )
517+ }
518+
519+ ocs := oc .(* schema.Set )
520+ ncs := nc .(* schema.Set )
521+ removeConditions := ocs .Difference (ncs ).List ()
522+ addConditions := ncs .Difference (ocs ).List ()
523+
524+ // DELETE old Conditions
525+ for _ , cRaw := range removeConditions {
526+ cf := cRaw .(map [string ]interface {})
527+ opts := gofastly.DeleteConditionInput {
528+ Service : d .Id (),
529+ Version : latestVersion ,
530+ Name : cf ["name" ].(string ),
531+ }
532+
533+ log .Printf ("[DEBUG] Fastly Conditions Removal opts: %#v" , opts )
534+ err := conn .DeleteCondition (& opts )
535+ if err != nil {
536+ return err
537+ }
538+ }
539+
540+ // POST new Conditions
541+ for _ , cRaw := range addConditions {
542+ cf := cRaw .(map [string ]interface {})
543+ opts := gofastly.CreateConditionInput {
544+ Service : d .Id (),
545+ Version : latestVersion ,
546+ Name : cf ["name" ].(string ),
547+ Type : cf ["type" ].(string ),
548+ // need to trim leading/tailing spaces, incase the config has HEREDOC
549+ // formatting and contains a trailing new line
550+ Statement : strings .TrimSpace (cf ["statement" ].(string )),
551+ Priority : cf ["priority" ].(int ),
552+ }
553+
554+ log .Printf ("[DEBUG] Create Conditions Opts: %#v" , opts )
555+ _ , err := conn .CreateCondition (& opts )
556+ if err != nil {
557+ return err
558+ }
559+ }
560+ }
561+
466562 // Find differences in domains
467563 if d .HasChange ("domain" ) {
468- // Note: we don't utilize the PUT endpoint to update a Domain, we simply
469- // destroy it and create a new one. This is how Terraform works with nested
470- // sub resources, we only get the full diff not a partial set item diff.
471- // Because this is done on a new version of the configuration, this is
472- // considered safe
473564 od , nd := d .GetChange ("domain" )
474565 if od == nil {
475566 od = new (schema.Set )
@@ -523,12 +614,6 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
523614
524615 // find difference in backends
525616 if d .HasChange ("backend" ) {
526- // POST new Backends
527- // Note: we don't utilize the PUT endpoint to update a Backend, we simply
528- // destroy it and create a new one. This is how Terraform works with nested
529- // sub resources, we only get the full diff not a partial set item diff.
530- // Because this is done on a new version of the configuration, this is
531- // considered safe
532617 ob , nb := d .GetChange ("backend" )
533618 if ob == nil {
534619 ob = new (schema.Set )
@@ -558,6 +643,7 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
558643 }
559644 }
560645
646+ // Find and post new Backends
561647 for _ , dRaw := range addBackends {
562648 df := dRaw .(map [string ]interface {})
563649 opts := gofastly.CreateBackendInput {
@@ -585,11 +671,6 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
585671 }
586672
587673 if d .HasChange ("header" ) {
588- // Note: we don't utilize the PUT endpoint to update a Header, we simply
589- // destroy it and create a new one. This is how Terraform works with nested
590- // sub resources, we only get the full diff not a partial set item diff.
591- // Because this is done on a new version of the configuration, this is
592- // considered safe
593674 oh , nh := d .GetChange ("header" )
594675 if oh == nil {
595676 oh = new (schema.Set )
@@ -640,11 +721,6 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
640721
641722 // Find differences in Gzips
642723 if d .HasChange ("gzip" ) {
643- // Note: we don't utilize the PUT endpoint to update a Gzip rule, we simply
644- // destroy it and create a new one. This is how Terraform works with nested
645- // sub resources, we only get the full diff not a partial set item diff.
646- // Because this is done on a new version of the configuration, this is
647- // considered safe
648724 og , ng := d .GetChange ("gzip" )
649725 if og == nil {
650726 og = new (schema.Set )
@@ -714,12 +790,6 @@ func resourceServiceV1Update(d *schema.ResourceData, meta interface{}) error {
714790
715791 // find difference in s3logging
716792 if d .HasChange ("s3logging" ) {
717- // POST new Logging
718- // Note: we don't utilize the PUT endpoint to update a S3 Logs, we simply
719- // destroy it and create a new one. This is how Terraform works with nested
720- // sub resources, we only get the full diff not a partial set item diff.
721- // Because this is done on a new version of the configuration, this is
722- // considered safe
723793 os , ns := d .GetChange ("s3logging" )
724794 if os == nil {
725795 os = new (schema.Set )
@@ -947,6 +1017,23 @@ func resourceServiceV1Read(d *schema.ResourceData, meta interface{}) error {
9471017 log .Printf ("[WARN] Error setting S3 Logging for (%s): %s" , d .Id (), err )
9481018 }
9491019
1020+ // refresh Conditions
1021+ log .Printf ("[DEBUG] Refreshing Conditions for (%s)" , d .Id ())
1022+ conditionList , err := conn .ListConditions (& gofastly.ListConditionsInput {
1023+ Service : d .Id (),
1024+ Version : s .ActiveVersion .Number ,
1025+ })
1026+
1027+ if err != nil {
1028+ return fmt .Errorf ("[ERR] Error looking up Conditions for (%s), version (%s): %s" , d .Id (), s .ActiveVersion .Number , err )
1029+ }
1030+
1031+ cl := flattenConditions (conditionList )
1032+
1033+ if err := d .Set ("condition" , cl ); err != nil {
1034+ log .Printf ("[WARN] Error setting Conditions for (%s): %s" , d .Id (), err )
1035+ }
1036+
9501037 } else {
9511038 log .Printf ("[DEBUG] Active Version for Service (%s) is empty, no state to refresh" , d .Id ())
9521039 }
@@ -1215,3 +1302,27 @@ func flattenS3s(s3List []*gofastly.S3) []map[string]interface{} {
12151302
12161303 return sl
12171304}
1305+
1306+ func flattenConditions (conditionList []* gofastly.Condition ) []map [string ]interface {} {
1307+ var cl []map [string ]interface {}
1308+ for _ , c := range conditionList {
1309+ // Convert Conditions to a map for saving to state.
1310+ nc := map [string ]interface {}{
1311+ "name" : c .Name ,
1312+ "statement" : c .Statement ,
1313+ "type" : c .Type ,
1314+ "priority" : c .Priority ,
1315+ }
1316+
1317+ // prune any empty values that come from the default string value in structs
1318+ for k , v := range nc {
1319+ if v == "" {
1320+ delete (nc , k )
1321+ }
1322+ }
1323+
1324+ cl = append (cl , nc )
1325+ }
1326+
1327+ return cl
1328+ }
0 commit comments