Skip to content

Commit 03cea82

Browse files
nika-qubitNing Kang
andauthored
Added a magic modules resource definition for IcebergCatalog resource (#15924)
Co-authored-by: Ning Kang <[email protected]>
1 parent 554b907 commit 03cea82

File tree

7 files changed

+357
-0
lines changed

7 files changed

+357
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright 2025 Google Inc.
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
---
15+
name: 'IcebergCatalog'
16+
description: |
17+
IcebergCatalogs are top-level containers for Apache Iceberg REST Catalog served Namespaces and Tables.
18+
references:
19+
guides:
20+
'Use the BigLake metastore Iceberg REST catalog': 'https://docs.cloud.google.com/biglake/docs/blms-rest-catalog'
21+
base_url: 'restcatalog/extensions/projects/{{project}}/catalogs'
22+
self_link: 'restcatalog/extensions/projects/{{project}}/catalogs/{{name}}'
23+
immutable: false
24+
create_url: 'restcatalog/extensions/projects/{{project}}/catalogs?iceberg-catalog-id={{name}}'
25+
custom_code:
26+
custom_update:
27+
templates/terraform/custom_update/biglake_iceberg_catalog_update.go.tmpl
28+
examples:
29+
- name: 'biglake_iceberg_catalog'
30+
primary_resource_id: 'my_iceberg_catalog'
31+
vars:
32+
name: 'my_iceberg_catalog'
33+
parameters:
34+
- name: 'name'
35+
type: String
36+
required: true
37+
immutable: true
38+
url_param_only: true
39+
description: |
40+
The name of the IcebergCatalog. Format:
41+
projects/{project_id_or_number}/catalogs/{iceberg_catalog_id}
42+
properties:
43+
- name: 'credential_mode'
44+
api_name: 'credential-mode'
45+
type: Enum
46+
description: The credential mode used for the catalog.
47+
CREDENTIAL_MODE_END_USER - End user credentials, default. The authenticating
48+
user must have access to the catalog resources and the corresponding Google
49+
Cloud Storage files. CREDENTIAL_MODE_VENDED_CREDENTIALS - Use credential
50+
vending. The authenticating user must have access to the catalog resources
51+
and the system will provide the caller with downscoped credentials to access
52+
the Google Cloud Storage files. All table operations in this mode would
53+
require `X-Iceberg-Access-Delegation` header with `vended-credentials` value
54+
included. System will generate a service account and the catalog
55+
administrator must grant the service account appropriate permissions.
56+
required: false
57+
immutable: false
58+
output: false
59+
enum_values:
60+
- 'CREDENTIAL_MODE_END_USER'
61+
- 'CREDENTIAL_MODE_VENDED_CREDENTIALS'
62+
default_from_api: true
63+
- name: 'biglake_service_account'
64+
api_name: 'biglake-service-account'
65+
type: String
66+
description: Output only. The service account used for credential vending. It
67+
might be empty if credential vending was never enabled for the catalog.
68+
output: true
69+
- name: 'catalog_type'
70+
api_name: 'catalog-type'
71+
type: Enum
72+
description: The catalog type of the IcebergCatalog. Currently only supports
73+
the type for Google Cloud Storage Buckets.
74+
required: true
75+
immutable: true
76+
output: false
77+
enum_values:
78+
- 'CATALOG_TYPE_GCS_BUCKET'
79+
- name: 'default_location'
80+
api_name: 'default-location'
81+
type: String
82+
description: Output only. The default storage location for the catalog, e.g.,
83+
`gs://my-bucket`.
84+
output: true
85+
- name: 'storage_regions'
86+
api_name: 'storage-regions'
87+
type: Array
88+
item_type:
89+
type: String
90+
description: Output only. The GCP region(s) where the physical metadata for
91+
the tables is stored, e.g. `us-central1`, `nam4` or `us`. This will contain
92+
one value for all locations, except for the catalogs that are configured to
93+
use custom dual region buckets.
94+
output: true
95+
- name: 'create_time'
96+
api_name: 'create-time'
97+
type: String
98+
description: Output only. The creation time of the IcebergCatalog.
99+
output: true
100+
- name: 'update_time'
101+
api_name: 'update-time'
102+
type: String
103+
description: Output only. The last modification time of the IcebergCatalog.
104+
output: true
105+
- name: 'replicas'
106+
type: Array
107+
item_type:
108+
type: NestedObject
109+
properties:
110+
- name: 'region'
111+
type: String
112+
description: The region of the replica, e.g., `us-east1`.
113+
output: true
114+
- name: 'state'
115+
type: Enum
116+
description: If the IcebergCatalog is replicated to multiple regions, this
117+
describes the current state of the replica. STATE_UNKNOWN - The replica
118+
state is unknown. STATE_PRIMARY - The replica is the writable primary.
119+
STATE_PRIMARY_IN_PROGRESS - The replica has been recently assigned as
120+
the primary, but not all namespaces are writeable yet. STATE_SECONDARY -
121+
The replica is a read-only secondary replica.
122+
output: true
123+
enum_values:
124+
- 'STATE_UNKNOWN'
125+
- 'STATE_PRIMARY'
126+
- 'STATE_PRIMARY_IN_PROGRESS'
127+
- 'STATE_SECONDARY'
128+
description: Output only. The replicas for the catalog metadata.
129+
output: true
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2025 Google Inc.
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
---
15+
name: 'BiglakeIceberg'
16+
legacy_name: 'biglake'
17+
display_name: 'Biglake'
18+
versions:
19+
- name: 'ga'
20+
base_url: 'https://biglake.googleapis.com/iceberg/v1/'
21+
scopes:
22+
- 'https://www.googleapis.com/auth/bigquery'
23+
- 'https://www.googleapis.com/auth/cloud-platform'
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
2+
if err != nil {
3+
return err
4+
}
5+
6+
billingProject := ""
7+
8+
project, err := tpgresource.GetProject(d, config)
9+
if err != nil {
10+
return fmt.Errorf("Error fetching project for IcebergCatalog: %s", err)
11+
}
12+
billingProject = project
13+
14+
obj := make(map[string]interface{})
15+
credentialModeProp, err := expandBiglakeIcebergIcebergCatalogCredentialMode(d.Get("credential_mode"), d, config)
16+
if err != nil {
17+
return err
18+
} else if v, ok := d.GetOkExists("credential_mode"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, credentialModeProp)) {
19+
obj["credential-mode"] = credentialModeProp
20+
}
21+
22+
url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}BiglakeIcebergBasePath{{"}}"}}restcatalog/extensions/projects/{{"{{"}}project{{"}}"}}/catalogs/{{"{{"}}name{{"}}"}}")
23+
if err != nil {
24+
return err
25+
}
26+
27+
log.Printf("[DEBUG] Updating IcebergCatalog %q: %#v", d.Id(), obj)
28+
headers := make(http.Header)
29+
updateMask := []string{}
30+
31+
// The custom logic is that server only respects property name not the json name for updateMask.
32+
// This will apply to all future updateable fields if they have a kebab-case json name override.
33+
// This does not apply to any field with a camelCase or snake_case name.
34+
if d.HasChange("credential_mode") {
35+
updateMask = append(updateMask, "credential_mode")
36+
}
37+
// updateMask is a URL parameter but not present in the schema, so ReplaceVars
38+
// won't set it
39+
url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")})
40+
if err != nil {
41+
return err
42+
}
43+
44+
// err == nil indicates that the billing_project value was found
45+
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
46+
billingProject = bp
47+
}
48+
49+
// if updateMask is empty we are not updating anything so skip the post
50+
if len(updateMask) > 0 {
51+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
52+
Config: config,
53+
Method: "PATCH",
54+
Project: billingProject,
55+
RawURL: url,
56+
UserAgent: userAgent,
57+
Body: obj,
58+
Timeout: d.Timeout(schema.TimeoutUpdate),
59+
Headers: headers,
60+
})
61+
62+
if err != nil {
63+
return fmt.Errorf("Error updating IcebergCatalog %q: %s", d.Id(), err)
64+
} else {
65+
log.Printf("[DEBUG] Finished updating IcebergCatalog %q: %#v", d.Id(), res)
66+
}
67+
68+
}
69+
70+
return resourceBiglakeIcebergIcebergCatalogRead(d, meta)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
resource "google_storage_bucket" "bucket_for_{{$.PrimaryResourceId}}" {
2+
name = "{{index $.Vars "name"}}"
3+
location = "us-central1"
4+
force_destroy = true
5+
uniform_bucket_level_access = true
6+
}
7+
8+
resource "google_biglake_iceberg_catalog" "{{$.PrimaryResourceId}}" {
9+
name = "{{index $.Vars "name"}}"
10+
catalog_type = "CATALOG_TYPE_GCS_BUCKET"
11+
depends_on = [
12+
google_storage_bucket.bucket_for_{{$.PrimaryResourceId}}
13+
]
14+
}

mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ var ServicesListBeta = mapOf(
9191
"displayName" to "Biglake",
9292
"path" to "./google-beta/services/biglake"
9393
),
94+
"biglakeiceberg" to mapOf(
95+
"name" to "biglakeiceberg",
96+
"displayName" to "BiglakeIceberg",
97+
"path" to "./google-beta/services/biglakeiceberg"
98+
),
9499
"bigquery" to mapOf(
95100
"name" to "bigquery",
96101
"displayName" to "Bigquery",

mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ var ServicesListGa = mapOf(
9191
"displayName" to "Biglake",
9292
"path" to "./google/services/biglake"
9393
),
94+
"biglakeiceberg" to mapOf(
95+
"name" to "biglakeiceberg",
96+
"displayName" to "BiglakeIceberg",
97+
"path" to "./google/services/biglakeiceberg"
98+
),
9499
"bigquery" to mapOf(
95100
"name" to "bigquery",
96101
"displayName" to "Bigquery",
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
// ----------------------------------------------------------------------------
5+
//
6+
// *** AUTO GENERATED CODE *** Type: MMv1 ***
7+
//
8+
// ----------------------------------------------------------------------------
9+
//
10+
// This file is automatically generated by Magic Modules and manual
11+
// changes will be clobbered when the file is regenerated.
12+
//
13+
// Please read more about how to change this file in
14+
// .github/CONTRIBUTING.md.
15+
//
16+
// ----------------------------------------------------------------------------
17+
18+
package biglakeiceberg_test
19+
20+
import (
21+
"fmt"
22+
"log"
23+
"strconv"
24+
"strings"
25+
"testing"
26+
"time"
27+
28+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
29+
"github.com/hashicorp/terraform-plugin-testing/plancheck"
30+
"github.com/hashicorp/terraform-plugin-testing/terraform"
31+
32+
"github.com/hashicorp/terraform-provider-google/google/acctest"
33+
"github.com/hashicorp/terraform-provider-google/google/envvar"
34+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
35+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
36+
37+
"google.golang.org/api/googleapi"
38+
)
39+
40+
var (
41+
_ = fmt.Sprintf
42+
_ = log.Print
43+
_ = strconv.Atoi
44+
_ = strings.Trim
45+
_ = time.Now
46+
_ = resource.TestMain
47+
_ = terraform.NewState
48+
_ = envvar.TestEnvVar
49+
_ = tpgresource.SetLabels
50+
_ = transport_tpg.Config{}
51+
_ = googleapi.Error{}
52+
)
53+
54+
func TestAccBiglakeIcebergIcebergCatalog_biglakeIcebergCatalog_update(t *testing.T) {
55+
t.Parallel()
56+
57+
context := map[string]interface{}{
58+
"random_suffix": acctest.RandString(t, 10),
59+
}
60+
61+
acctest.VcrTest(t, resource.TestCase{
62+
PreCheck: func() { acctest.AccTestPreCheck(t) },
63+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
64+
CheckDestroy: testAccCheckBiglakeIcebergIcebergCatalogDestroyProducer(t),
65+
Steps: []resource.TestStep{
66+
{
67+
Config: testAccBiglakeIcebergIcebergCatalog_biglakeIcebergCatalogExample(context),
68+
},
69+
{
70+
ResourceName: "google_biglake_iceberg_catalog.my_iceberg_catalog",
71+
ImportState: true,
72+
ImportStateVerify: true,
73+
ImportStateVerifyIgnore: []string{"name"},
74+
},
75+
{
76+
Config: testAccBiglakeIcebergIcebergCatalog_biglakeIcebergCatalog_update(context),
77+
ConfigPlanChecks: resource.ConfigPlanChecks{
78+
PreApply: []plancheck.PlanCheck{
79+
plancheck.ExpectResourceAction("google_biglake_iceberg_catalog.my_iceberg_catalog", plancheck.ResourceActionUpdate),
80+
},
81+
},
82+
},
83+
{
84+
ResourceName: "google_biglake_iceberg_catalog.my_iceberg_catalog",
85+
ImportState: true,
86+
ImportStateVerify: true,
87+
ImportStateVerifyIgnore: []string{"name"},
88+
},
89+
},
90+
})
91+
}
92+
93+
func testAccBiglakeIcebergIcebergCatalog_biglakeIcebergCatalog_update(context map[string]interface{}) string {
94+
return acctest.Nprintf(`
95+
resource "google_storage_bucket" "bucket_for_my_iceberg_catalog" {
96+
name = "tf_test_my_iceberg_catalog%{random_suffix}"
97+
location = "us-central1"
98+
force_destroy = true
99+
uniform_bucket_level_access = true
100+
}
101+
102+
resource "google_biglake_iceberg_catalog" "my_iceberg_catalog" {
103+
name = "tf_test_my_iceberg_catalog%{random_suffix}"
104+
catalog_type = "CATALOG_TYPE_GCS_BUCKET"
105+
credential_mode = "CREDENTIAL_MODE_VENDED_CREDENTIALS"
106+
depends_on = [
107+
google_storage_bucket.bucket_for_my_iceberg_catalog
108+
]
109+
}
110+
`, context)
111+
}

0 commit comments

Comments
 (0)