|
| 1 | +package edgeservices |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + |
| 6 | + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" |
| 7 | + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" |
| 8 | + edgeservices "github.com/scaleway/scaleway-sdk-go/api/edge_services/v1beta1" |
| 9 | + "github.com/scaleway/scaleway-sdk-go/scw" |
| 10 | + "github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors" |
| 11 | + "github.com/scaleway/terraform-provider-scaleway/v2/internal/services/account" |
| 12 | + "github.com/scaleway/terraform-provider-scaleway/v2/internal/types" |
| 13 | + "github.com/scaleway/terraform-provider-scaleway/v2/internal/verify" |
| 14 | +) |
| 15 | + |
| 16 | +func ResourceRouteStage() *schema.Resource { |
| 17 | + return &schema.Resource{ |
| 18 | + CreateContext: ResourceRouteStageCreate, |
| 19 | + ReadContext: ResourceRouteStageRead, |
| 20 | + UpdateContext: ResourceRouteStageUpdate, |
| 21 | + DeleteContext: ResourceRouteStageDelete, |
| 22 | + Importer: &schema.ResourceImporter{ |
| 23 | + StateContext: schema.ImportStatePassthroughContext, |
| 24 | + }, |
| 25 | + SchemaVersion: 0, |
| 26 | + Schema: map[string]*schema.Schema{ |
| 27 | + "pipeline_id": { |
| 28 | + Type: schema.TypeString, |
| 29 | + Required: true, |
| 30 | + Description: "The ID of the pipeline", |
| 31 | + }, |
| 32 | + "waf_stage_id": { |
| 33 | + Type: schema.TypeString, |
| 34 | + Optional: true, |
| 35 | + Description: "The ID of the WAF stage HTTP requests should be forwarded to when no rules are matched", |
| 36 | + }, |
| 37 | + "rule": { |
| 38 | + Type: schema.TypeList, |
| 39 | + Optional: true, |
| 40 | + Description: "List of rules to be checked against every HTTP request. The first matching rule will forward the request to its specified backend stage. If no rules are matched, the request is forwarded to the WAF stage defined by `waf_stage_id`", |
| 41 | + Elem: &schema.Resource{ |
| 42 | + Schema: map[string]*schema.Schema{ |
| 43 | + "backend_stage_id": { |
| 44 | + Type: schema.TypeString, |
| 45 | + Required: true, |
| 46 | + Description: "ID of the backend stage that requests matching the rule should be forwarded to", |
| 47 | + }, |
| 48 | + "rule_http_match": { |
| 49 | + Type: schema.TypeList, |
| 50 | + Optional: true, |
| 51 | + Description: "Rule condition to be matched. Requests matching the condition defined here will be directly forwarded to the backend specified by the `backend_stage_id` field. Requests that do not match will be checked by the next rule's condition", |
| 52 | + MaxItems: 1, |
| 53 | + Elem: &schema.Resource{ |
| 54 | + Schema: map[string]*schema.Schema{ |
| 55 | + "method_filters": { |
| 56 | + Type: schema.TypeList, |
| 57 | + Optional: true, |
| 58 | + Computed: true, |
| 59 | + Elem: &schema.Schema{ |
| 60 | + Type: schema.TypeString, |
| 61 | + ValidateDiagFunc: verify.ValidateEnum[edgeservices.RuleHTTPMatchMethodFilter](), |
| 62 | + }, |
| 63 | + Description: "HTTP methods to filter for. A request using any of these methods will be considered to match the rule. Possible values are `get`, `post`, `put`, `patch`, `delete`, `head`, `options`. All methods will match if none is provided", |
| 64 | + }, |
| 65 | + "path_filter": { |
| 66 | + Type: schema.TypeList, |
| 67 | + Optional: true, |
| 68 | + MaxItems: 1, |
| 69 | + Description: "HTTP URL path to filter for. A request whose path matches the given filter will be considered to match the rule. All paths will match if none is provided", |
| 70 | + Elem: &schema.Resource{ |
| 71 | + Schema: map[string]*schema.Schema{ |
| 72 | + "path_filter_type": { |
| 73 | + Type: schema.TypeString, |
| 74 | + Required: true, |
| 75 | + ValidateDiagFunc: verify.ValidateEnum[edgeservices.RuleHTTPMatchPathFilterPathFilterType](), |
| 76 | + Description: "The type of filter to match for the HTTP URL path. For now, all path filters must be written in regex and use the `regex` type", |
| 77 | + }, |
| 78 | + "value": { |
| 79 | + Type: schema.TypeString, |
| 80 | + Required: true, |
| 81 | + Description: "The value to be matched for the HTTP URL path", |
| 82 | + }, |
| 83 | + }, |
| 84 | + }, |
| 85 | + }, |
| 86 | + }, |
| 87 | + }, |
| 88 | + }, |
| 89 | + }, |
| 90 | + }, |
| 91 | + }, |
| 92 | + "created_at": { |
| 93 | + Type: schema.TypeString, |
| 94 | + Computed: true, |
| 95 | + Description: "The date and time of the creation of the route stage", |
| 96 | + }, |
| 97 | + "updated_at": { |
| 98 | + Type: schema.TypeString, |
| 99 | + Computed: true, |
| 100 | + Description: "The date and time of the last update of the route stage", |
| 101 | + }, |
| 102 | + "project_id": account.ProjectIDSchema(), |
| 103 | + }, |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +func ResourceRouteStageCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { |
| 108 | + api := NewEdgeServicesAPI(m) |
| 109 | + |
| 110 | + routeStage, err := api.CreateRouteStage(&edgeservices.CreateRouteStageRequest{ |
| 111 | + PipelineID: d.Get("pipeline_id").(string), |
| 112 | + WafStageID: types.ExpandStringPtr(d.Get("waf_stage_id").(string)), |
| 113 | + }, scw.WithContext(ctx)) |
| 114 | + if err != nil { |
| 115 | + return diag.FromErr(err) |
| 116 | + } |
| 117 | + |
| 118 | + _, err = api.SetRouteRules(&edgeservices.SetRouteRulesRequest{ |
| 119 | + RouteStageID: routeStage.ID, |
| 120 | + RouteRules: expandRouteRules(d.Get("rule")), |
| 121 | + }, scw.WithContext(ctx)) |
| 122 | + if err != nil { |
| 123 | + return diag.FromErr(err) |
| 124 | + } |
| 125 | + |
| 126 | + d.SetId(routeStage.ID) |
| 127 | + |
| 128 | + return ResourceRouteStageRead(ctx, d, m) |
| 129 | +} |
| 130 | + |
| 131 | +func ResourceRouteStageRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { |
| 132 | + api := NewEdgeServicesAPI(m) |
| 133 | + |
| 134 | + routeStage, err := api.GetRouteStage(&edgeservices.GetRouteStageRequest{ |
| 135 | + RouteStageID: d.Id(), |
| 136 | + }, scw.WithContext(ctx)) |
| 137 | + if err != nil { |
| 138 | + if httperrors.Is404(err) { |
| 139 | + d.SetId("") |
| 140 | + |
| 141 | + return nil |
| 142 | + } |
| 143 | + |
| 144 | + return diag.FromErr(err) |
| 145 | + } |
| 146 | + |
| 147 | + _ = d.Set("pipeline_id", routeStage.PipelineID) |
| 148 | + _ = d.Set("waf_stage_id", types.FlattenStringPtr(routeStage.WafStageID)) |
| 149 | + _ = d.Set("created_at", types.FlattenTime(routeStage.CreatedAt)) |
| 150 | + _ = d.Set("updated_at", types.FlattenTime(routeStage.UpdatedAt)) |
| 151 | + |
| 152 | + routeRules, err := api.ListRouteRules(&edgeservices.ListRouteRulesRequest{ |
| 153 | + RouteStageID: routeStage.ID, |
| 154 | + }, scw.WithContext(ctx)) |
| 155 | + if err != nil { |
| 156 | + return diag.FromErr(err) |
| 157 | + } |
| 158 | + |
| 159 | + _ = d.Set("rule", flattenRouteRules(routeRules.RouteRules)) |
| 160 | + |
| 161 | + return nil |
| 162 | +} |
| 163 | + |
| 164 | +func ResourceRouteStageUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { |
| 165 | + api := NewEdgeServicesAPI(m) |
| 166 | + |
| 167 | + hasChanged := false |
| 168 | + |
| 169 | + updateRequest := &edgeservices.UpdateRouteStageRequest{ |
| 170 | + RouteStageID: d.Id(), |
| 171 | + } |
| 172 | + |
| 173 | + if d.HasChange("waf_stage_id") { |
| 174 | + updateRequest.WafStageID = types.ExpandStringPtr(d.Get("waf_stage_id").(string)) |
| 175 | + hasChanged = true |
| 176 | + } |
| 177 | + |
| 178 | + if hasChanged { |
| 179 | + _, err := api.UpdateRouteStage(updateRequest, scw.WithContext(ctx)) |
| 180 | + if err != nil { |
| 181 | + return diag.FromErr(err) |
| 182 | + } |
| 183 | + } |
| 184 | + |
| 185 | + if d.HasChange("rule") { |
| 186 | + _, err := api.SetRouteRules(&edgeservices.SetRouteRulesRequest{ |
| 187 | + RouteStageID: d.Id(), |
| 188 | + RouteRules: expandRouteRules(d.Get("rule")), |
| 189 | + }, scw.WithContext(ctx)) |
| 190 | + if err != nil { |
| 191 | + return diag.FromErr(err) |
| 192 | + } |
| 193 | + } |
| 194 | + |
| 195 | + return ResourceRouteStageRead(ctx, d, m) |
| 196 | +} |
| 197 | + |
| 198 | +func ResourceRouteStageDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { |
| 199 | + api := NewEdgeServicesAPI(m) |
| 200 | + |
| 201 | + err := api.DeleteRouteStage(&edgeservices.DeleteRouteStageRequest{ |
| 202 | + RouteStageID: d.Id(), |
| 203 | + }, scw.WithContext(ctx)) |
| 204 | + if err != nil && !httperrors.Is404(err) { |
| 205 | + return diag.FromErr(err) |
| 206 | + } |
| 207 | + |
| 208 | + return nil |
| 209 | +} |
0 commit comments