Skip to content

Commit 43fa093

Browse files
Add headers to Hosting Version (#12527) (#8887)
[upstream:93c2b6e54aed3c54aed94e92875dd06b863d49f2] Signed-off-by: Modular Magician <[email protected]>
1 parent 136d283 commit 43fa093

File tree

4 files changed

+347
-31
lines changed

4 files changed

+347
-31
lines changed

Diff for: .changelog/12527.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
firebasehosting: added `headers` field in `google_firebase_hosting_version` resource (beta)
3+
```

Diff for: google-beta/services/firebasehosting/resource_firebase_hosting_version.go

+150-31
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,36 @@ func ResourceFirebaseHostingVersion() *schema.Resource {
6161
MaxItems: 1,
6262
Elem: &schema.Resource{
6363
Schema: map[string]*schema.Schema{
64+
"headers": {
65+
Type: schema.TypeList,
66+
Optional: true,
67+
ForceNew: true,
68+
Description: `An array of objects, where each object specifies a URL pattern that, if matched to the request URL path,
69+
triggers Hosting to apply the specified custom response headers.`,
70+
Elem: &schema.Resource{
71+
Schema: map[string]*schema.Schema{
72+
"headers": {
73+
Type: schema.TypeMap,
74+
Required: true,
75+
ForceNew: true,
76+
Description: `The additional headers to add to the response. Example: { "name": "wrench", "mass": "1.3kg", "count": "3" }.`,
77+
Elem: &schema.Schema{Type: schema.TypeString},
78+
},
79+
"glob": {
80+
Type: schema.TypeString,
81+
Optional: true,
82+
ForceNew: true,
83+
Description: `The user-supplied glob to match against the request URL path.`,
84+
},
85+
"regex": {
86+
Type: schema.TypeString,
87+
Optional: true,
88+
ForceNew: true,
89+
Description: `The user-supplied RE2 regular expression to match against the request URL path.`,
90+
},
91+
},
92+
},
93+
},
6494
"redirects": {
6595
Type: schema.TypeList,
6696
Optional: true,
@@ -92,18 +122,16 @@ redirects {
92122
Description: `The status HTTP code to return in the response. It must be a valid 3xx status code.`,
93123
},
94124
"glob": {
95-
Type: schema.TypeString,
96-
Optional: true,
97-
ForceNew: true,
98-
Description: `The user-supplied glob to match against the request URL path.`,
99-
ExactlyOneOf: []string{},
125+
Type: schema.TypeString,
126+
Optional: true,
127+
ForceNew: true,
128+
Description: `The user-supplied glob to match against the request URL path.`,
100129
},
101130
"regex": {
102-
Type: schema.TypeString,
103-
Optional: true,
104-
ForceNew: true,
105-
Description: `The user-supplied RE2 regular expression to match against the request URL path.`,
106-
ExactlyOneOf: []string{},
131+
Type: schema.TypeString,
132+
Optional: true,
133+
ForceNew: true,
134+
Description: `The user-supplied RE2 regular expression to match against the request URL path.`,
107135
},
108136
},
109137
},
@@ -117,32 +145,28 @@ request URL path, triggers Hosting to respond as if the service were given the s
117145
Elem: &schema.Resource{
118146
Schema: map[string]*schema.Schema{
119147
"function": {
120-
Type: schema.TypeString,
121-
Optional: true,
122-
ForceNew: true,
123-
Description: `The function to proxy requests to. Must match the exported function name exactly.`,
124-
ExactlyOneOf: []string{},
148+
Type: schema.TypeString,
149+
Optional: true,
150+
ForceNew: true,
151+
Description: `The function to proxy requests to. Must match the exported function name exactly.`,
125152
},
126153
"glob": {
127-
Type: schema.TypeString,
128-
Optional: true,
129-
ForceNew: true,
130-
Description: `The user-supplied glob to match against the request URL path.`,
131-
ExactlyOneOf: []string{},
154+
Type: schema.TypeString,
155+
Optional: true,
156+
ForceNew: true,
157+
Description: `The user-supplied glob to match against the request URL path.`,
132158
},
133159
"path": {
134-
Type: schema.TypeString,
135-
Optional: true,
136-
ForceNew: true,
137-
Description: `The URL path to rewrite the request to.`,
138-
ExactlyOneOf: []string{},
160+
Type: schema.TypeString,
161+
Optional: true,
162+
ForceNew: true,
163+
Description: `The URL path to rewrite the request to.`,
139164
},
140165
"regex": {
141-
Type: schema.TypeString,
142-
Optional: true,
143-
ForceNew: true,
144-
Description: `The user-supplied RE2 regular expression to match against the request URL path.`,
145-
ExactlyOneOf: []string{},
166+
Type: schema.TypeString,
167+
Optional: true,
168+
ForceNew: true,
169+
Description: `The user-supplied RE2 regular expression to match against the request URL path.`,
146170
},
147171
"run": {
148172
Type: schema.TypeList,
@@ -166,7 +190,6 @@ request URL path, triggers Hosting to respond as if the service were given the s
166190
},
167191
},
168192
},
169-
ExactlyOneOf: []string{},
170193
},
171194
},
172195
},
@@ -387,6 +410,8 @@ func flattenFirebaseHostingVersionConfig(v interface{}, d *schema.ResourceData,
387410
flattenFirebaseHostingVersionConfigRewrites(original["rewrites"], d, config)
388411
transformed["redirects"] =
389412
flattenFirebaseHostingVersionConfigRedirects(original["redirects"], d, config)
413+
transformed["headers"] =
414+
flattenFirebaseHostingVersionConfigHeaders(original["headers"], d, config)
390415
return []interface{}{transformed}
391416
}
392417
func flattenFirebaseHostingVersionConfigRewrites(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
@@ -500,6 +525,38 @@ func flattenFirebaseHostingVersionConfigRedirectsLocation(v interface{}, d *sche
500525
return v
501526
}
502527

528+
func flattenFirebaseHostingVersionConfigHeaders(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
529+
if v == nil {
530+
return v
531+
}
532+
l := v.([]interface{})
533+
transformed := make([]interface{}, 0, len(l))
534+
for _, raw := range l {
535+
original := raw.(map[string]interface{})
536+
if len(original) < 1 {
537+
// Do not include empty json objects coming back from the api
538+
continue
539+
}
540+
transformed = append(transformed, map[string]interface{}{
541+
"glob": flattenFirebaseHostingVersionConfigHeadersGlob(original["glob"], d, config),
542+
"regex": flattenFirebaseHostingVersionConfigHeadersRegex(original["regex"], d, config),
543+
"headers": flattenFirebaseHostingVersionConfigHeadersHeaders(original["headers"], d, config),
544+
})
545+
}
546+
return transformed
547+
}
548+
func flattenFirebaseHostingVersionConfigHeadersGlob(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
549+
return v
550+
}
551+
552+
func flattenFirebaseHostingVersionConfigHeadersRegex(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
553+
return v
554+
}
555+
556+
func flattenFirebaseHostingVersionConfigHeadersHeaders(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
557+
return v
558+
}
559+
503560
func expandFirebaseHostingVersionConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
504561
l := v.([]interface{})
505562
if len(l) == 0 || l[0] == nil {
@@ -523,6 +580,13 @@ func expandFirebaseHostingVersionConfig(v interface{}, d tpgresource.TerraformRe
523580
transformed["redirects"] = transformedRedirects
524581
}
525582

583+
transformedHeaders, err := expandFirebaseHostingVersionConfigHeaders(original["headers"], d, config)
584+
if err != nil {
585+
return nil, err
586+
} else if val := reflect.ValueOf(transformedHeaders); val.IsValid() && !tpgresource.IsEmptyValue(val) {
587+
transformed["headers"] = transformedHeaders
588+
}
589+
526590
return transformed, nil
527591
}
528592

@@ -685,6 +749,61 @@ func expandFirebaseHostingVersionConfigRedirectsLocation(v interface{}, d tpgres
685749
return v, nil
686750
}
687751

752+
func expandFirebaseHostingVersionConfigHeaders(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
753+
l := v.([]interface{})
754+
req := make([]interface{}, 0, len(l))
755+
for _, raw := range l {
756+
if raw == nil {
757+
continue
758+
}
759+
original := raw.(map[string]interface{})
760+
transformed := make(map[string]interface{})
761+
762+
transformedGlob, err := expandFirebaseHostingVersionConfigHeadersGlob(original["glob"], d, config)
763+
if err != nil {
764+
return nil, err
765+
} else if val := reflect.ValueOf(transformedGlob); val.IsValid() && !tpgresource.IsEmptyValue(val) {
766+
transformed["glob"] = transformedGlob
767+
}
768+
769+
transformedRegex, err := expandFirebaseHostingVersionConfigHeadersRegex(original["regex"], d, config)
770+
if err != nil {
771+
return nil, err
772+
} else if val := reflect.ValueOf(transformedRegex); val.IsValid() && !tpgresource.IsEmptyValue(val) {
773+
transformed["regex"] = transformedRegex
774+
}
775+
776+
transformedHeaders, err := expandFirebaseHostingVersionConfigHeadersHeaders(original["headers"], d, config)
777+
if err != nil {
778+
return nil, err
779+
} else if val := reflect.ValueOf(transformedHeaders); val.IsValid() && !tpgresource.IsEmptyValue(val) {
780+
transformed["headers"] = transformedHeaders
781+
}
782+
783+
req = append(req, transformed)
784+
}
785+
return req, nil
786+
}
787+
788+
func expandFirebaseHostingVersionConfigHeadersGlob(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
789+
return v, nil
790+
}
791+
792+
func expandFirebaseHostingVersionConfigHeadersRegex(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
793+
return v, nil
794+
}
795+
796+
func expandFirebaseHostingVersionConfigHeadersHeaders(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
797+
if v == nil {
798+
return map[string]string{}, nil
799+
}
800+
m := make(map[string]string)
801+
for k, val := range v.(map[string]interface{}) {
802+
m[k] = val.(string)
803+
}
804+
return m, nil
805+
}
806+
688807
func resourceFirebaseHostingVersionDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
689808
if err := d.Set("version_id", tpgresource.GetResourceNameFromSelfLink(res["name"].(string))); err != nil {
690809
return nil, err

Diff for: google-beta/services/firebasehosting/resource_firebase_hosting_version_generated_test.go

+112
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,118 @@ resource "google_firebase_hosting_release" "default" {
8080
`, context)
8181
}
8282

83+
func TestAccFirebaseHostingVersion_firebasehostingVersionHeadersExample(t *testing.T) {
84+
t.Parallel()
85+
86+
context := map[string]interface{}{
87+
"project_id": envvar.GetTestProjectFromEnv(),
88+
"random_suffix": acctest.RandString(t, 10),
89+
}
90+
91+
acctest.VcrTest(t, resource.TestCase{
92+
PreCheck: func() { acctest.AccTestPreCheck(t) },
93+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t),
94+
Steps: []resource.TestStep{
95+
{
96+
Config: testAccFirebaseHostingVersion_firebasehostingVersionHeadersExample(context),
97+
},
98+
{
99+
ResourceName: "google_firebase_hosting_version.default",
100+
ImportState: true,
101+
ImportStateVerify: true,
102+
ImportStateVerifyIgnore: []string{"site_id", "version_id"},
103+
},
104+
},
105+
})
106+
}
107+
108+
func testAccFirebaseHostingVersion_firebasehostingVersionHeadersExample(context map[string]interface{}) string {
109+
return acctest.Nprintf(`
110+
resource "google_firebase_hosting_site" "default" {
111+
provider = google-beta
112+
project = "%{project_id}"
113+
site_id = "tf-test-site-id%{random_suffix}"
114+
}
115+
116+
resource "google_firebase_hosting_version" "default" {
117+
provider = google-beta
118+
site_id = google_firebase_hosting_site.default.site_id
119+
config {
120+
headers {
121+
# Also okay to use regex
122+
glob = "/headers/**"
123+
headers = {
124+
my-header = "my-value"
125+
}
126+
}
127+
}
128+
}
129+
130+
resource "google_firebase_hosting_release" "default" {
131+
provider = google-beta
132+
site_id = google_firebase_hosting_site.default.site_id
133+
version_name = google_firebase_hosting_version.default.name
134+
message = "With custom headers"
135+
}
136+
`, context)
137+
}
138+
139+
func TestAccFirebaseHostingVersion_firebasehostingVersionHeadersRegexExample(t *testing.T) {
140+
t.Parallel()
141+
142+
context := map[string]interface{}{
143+
"project_id": envvar.GetTestProjectFromEnv(),
144+
"random_suffix": acctest.RandString(t, 10),
145+
}
146+
147+
acctest.VcrTest(t, resource.TestCase{
148+
PreCheck: func() { acctest.AccTestPreCheck(t) },
149+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t),
150+
Steps: []resource.TestStep{
151+
{
152+
Config: testAccFirebaseHostingVersion_firebasehostingVersionHeadersRegexExample(context),
153+
},
154+
{
155+
ResourceName: "google_firebase_hosting_version.default",
156+
ImportState: true,
157+
ImportStateVerify: true,
158+
ImportStateVerifyIgnore: []string{"site_id", "version_id"},
159+
},
160+
},
161+
})
162+
}
163+
164+
func testAccFirebaseHostingVersion_firebasehostingVersionHeadersRegexExample(context map[string]interface{}) string {
165+
return acctest.Nprintf(`
166+
resource "google_firebase_hosting_site" "default" {
167+
provider = google-beta
168+
project = "%{project_id}"
169+
site_id = "tf-test-site-id%{random_suffix}"
170+
}
171+
172+
resource "google_firebase_hosting_version" "default" {
173+
provider = google-beta
174+
site_id = google_firebase_hosting_site.default.site_id
175+
config {
176+
headers {
177+
# Also okay to use glob
178+
regex = "^~/headers$"
179+
headers = {
180+
my-header = "my-value"
181+
}
182+
}
183+
}
184+
}
185+
186+
resource "google_firebase_hosting_release" "default" {
187+
provider = google-beta
188+
site_id = google_firebase_hosting_site.default.site_id
189+
version_name = google_firebase_hosting_version.default.name
190+
message = "With custom headers"
191+
}
192+
`, context)
193+
}
194+
83195
func TestAccFirebaseHostingVersion_firebasehostingVersionPathExample(t *testing.T) {
84196
t.Parallel()
85197

0 commit comments

Comments
 (0)