From 5369643f68b23d2961793d52e547195f337b59d8 Mon Sep 17 00:00:00 2001 From: Lena Garber <114949949+lgarber-akamai@users.noreply.github.com> Date: Thu, 23 Jan 2025 10:11:10 -0500 Subject: [PATCH] Implement `linode_database_mysql_v2` data source (#1717) * Implement linode_database_mysql_v2 data source * Add trailing newline to docs * fix lint * Address docs feedback * Fix test * oops * g6-standard-1 -> g6-nanode-1 * Fix other test oversights --- docs/data-sources/database_mysql_v2.md | 102 +++++++++++++ docs/data-sources/database_postgresql_v2.md | 2 +- linode/databasemysqlv2/datasource_test.go | 77 ++++++++++ .../databasemysqlv2/framework_datasource.go | 54 +++++++ .../framework_datasource_schema.go | 135 ++++++++++++++++++ linode/databasemysqlv2/framework_models.go | 5 +- linode/databasemysqlv2/framework_resource.go | 12 +- linode/databasemysqlv2/tmpl/data.gotf | 9 ++ linode/databasemysqlv2/tmpl/template.go | 11 ++ linode/framework_provider.go | 4 +- 10 files changed, 401 insertions(+), 10 deletions(-) create mode 100644 docs/data-sources/database_mysql_v2.md create mode 100644 linode/databasemysqlv2/datasource_test.go create mode 100644 linode/databasemysqlv2/framework_datasource.go create mode 100644 linode/databasemysqlv2/framework_datasource_schema.go create mode 100644 linode/databasemysqlv2/tmpl/data.gotf diff --git a/docs/data-sources/database_mysql_v2.md b/docs/data-sources/database_mysql_v2.md new file mode 100644 index 000000000..aa05c37ad --- /dev/null +++ b/docs/data-sources/database_mysql_v2.md @@ -0,0 +1,102 @@ +--- +page_title: "Linode: linode_database_mysql_v2" +description: |- + Provides information about a Linode MySQL Database. +--- + +# Data Source: linode\_database\_mysql\_v2 + +Provides information about a Linode MySQL Database. +For more information, see the [Linode APIv4 docs](https://techdocs.akamai.com/linode-api/reference/get-databases-mysql-instance). + +## Example Usage + +Get information about a MySQL database: + +```hcl +data "linode_database_mysql_v2" "my-db" { + id = 12345 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `id` - The ID of the MySQL database. + +## Attributes Reference + +The `linode_database_mysql_v2` data source exports the following attributes: + +* `allow_list` - A list of IP addresses that can access the Managed Database. Each item can be a single IP address or a range in CIDR format. Use `linode_database_access_controls` to manage your allow list separately. + +* `ca_cert` - The base64-encoded SSL CA certificate for the Managed Database. + +* `cluster_size` - The number of Linode Instance nodes deployed to the Managed Database. (default `1`) + +* `created` - When this Managed Database was created. + +* `encrypted` - Whether the Managed Databases is encrypted. + +* `engine` - The Managed Database engine. (e.g. `mysql`) + +* `engine_id` - The Managed Database engine in engine/version format. (e.g. `mysql`) + +* `fork_restore_time` - The database timestamp from which it was restored. + +* `fork_source` - The ID of the database that was forked from. + +* `host_primary` - The primary host for the Managed Database. + +* `host_secondary` - The secondary/private host for the managed database. + +* `label` - A unique, user-defined string referring to the Managed Database. + +* [`pending_updates`](#pending_updates) - A set of pending updates. + +* `platform` - The back-end platform for relational databases used by the service. + +* `port` - The access port for this Managed Database. + +* `region` - The region to use for the Managed Database. + +* `root_password` - The randomly-generated root password for the Managed Database instance. + +* `root_username` - The root username for the Managed Database instance. + +* `ssl_connection` - Whether to require SSL credentials to establish a connection to the Managed Database. + +* `status` - The operating status of the Managed Database. + +* `type` - The Linode Instance type used for the nodes of the Managed Database. + +* `updated` - When this Managed Database was last updated. + +* [`updates`](#updates) - Configuration settings for automated patch update maintenance for the Managed Database. + +* `version` - The Managed Database engine version. (e.g. `13.2`) + +## pending_updates + +The following arguments are exposed by each entry in the `pending_updates` attribute: + +* `deadline` - The time when a mandatory update needs to be applied. + +* `description` - A description of the update. + +* `planned_for` - The date and time a maintenance update will be applied. + +## updates + +The following arguments are supported in the `updates` specification block: + +* `day_of_week` - The day to perform maintenance. (`monday`, `tuesday`, ...) + +* `duration` - The maximum maintenance window time in hours. (`1`..`3`) + +* `frequency` - Whether maintenance occurs on a weekly or monthly basis. (`weekly`, `monthly`) + +* `hour_of_day` - The hour to begin maintenance based in UTC time. (`0`..`23`) + +* `week_of_month` - The week of the month to perform monthly frequency updates. Required for `monthly` frequency updates. (`1`..`4`) diff --git a/docs/data-sources/database_postgresql_v2.md b/docs/data-sources/database_postgresql_v2.md index ccd4659c8..8386aa745 100644 --- a/docs/data-sources/database_postgresql_v2.md +++ b/docs/data-sources/database_postgresql_v2.md @@ -53,7 +53,7 @@ The `linode_database_postgresql_v2` data source exports the following attributes * `label` - A unique, user-defined string referring to the Managed Database. -* `pending_updates` - A set of pending updates. +* [`pending_updates`](#pending_updates) - A set of pending updates. * `platform` - The back-end platform for relational databases used by the service. diff --git a/linode/databasemysqlv2/datasource_test.go b/linode/databasemysqlv2/datasource_test.go new file mode 100644 index 000000000..0d7944f6c --- /dev/null +++ b/linode/databasemysqlv2/datasource_test.go @@ -0,0 +1,77 @@ +//go:build integration || databasemysqlv2 + +package databasemysqlv2_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" + "github.com/linode/terraform-provider-linode/v2/linode/databasemysqlv2/tmpl" +) + +func TestAccDataSource_basic(t *testing.T) { + t.Parallel() + + label := acctest.RandomWithPrefix("tf_test") + dataSourceName := "data.linode_database_mysql_v2.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + ProtoV5ProviderFactories: acceptance.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: tmpl.Data(t, tmpl.TemplateData{ + Label: label, + Region: testRegion, + EngineID: testEngine, + Type: "g6-nanode-1", + AllowedIP: "10.0.0.3/32", + ClusterSize: 1, + Updates: tmpl.TemplateDataUpdates{ + HourOfDay: 3, + DayOfWeek: 2, + Duration: 4, + Frequency: "weekly", + }, + }), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "id"), + + resource.TestCheckResourceAttrSet(dataSourceName, "ca_cert"), + resource.TestCheckResourceAttr(dataSourceName, "cluster_size", "1"), + resource.TestCheckResourceAttrSet(dataSourceName, "created"), + resource.TestCheckResourceAttr(dataSourceName, "encrypted", "true"), + resource.TestCheckResourceAttr(dataSourceName, "engine", "mysql"), + resource.TestCheckResourceAttr(dataSourceName, "engine_id", testEngine), + resource.TestCheckNoResourceAttr(dataSourceName, "fork_restore_time"), + resource.TestCheckNoResourceAttr(dataSourceName, "fork_source"), + resource.TestCheckResourceAttrSet(dataSourceName, "host_primary"), + resource.TestCheckResourceAttr(dataSourceName, "label", label), + resource.TestCheckResourceAttrSet(dataSourceName, "members.%"), + resource.TestCheckResourceAttrSet(dataSourceName, "root_password"), + resource.TestCheckResourceAttrSet(dataSourceName, "root_username"), + resource.TestCheckResourceAttr(dataSourceName, "platform", "rdbms-default"), + resource.TestCheckResourceAttrSet(dataSourceName, "port"), + resource.TestCheckResourceAttr(dataSourceName, "region", testRegion), + resource.TestCheckResourceAttr(dataSourceName, "ssl_connection", "true"), + resource.TestCheckResourceAttr(dataSourceName, "status", "active"), + resource.TestCheckResourceAttr(dataSourceName, "type", "g6-nanode-1"), + resource.TestCheckResourceAttrSet(dataSourceName, "updated"), + resource.TestCheckResourceAttrSet(dataSourceName, "version"), + + resource.TestCheckResourceAttr(dataSourceName, "allow_list.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "allow_list.0", "10.0.0.3/32"), + + resource.TestCheckResourceAttr(dataSourceName, "updates.hour_of_day", "3"), + resource.TestCheckResourceAttr(dataSourceName, "updates.day_of_week", "2"), + resource.TestCheckResourceAttr(dataSourceName, "updates.duration", "4"), + resource.TestCheckResourceAttr(dataSourceName, "updates.frequency", "weekly"), + + resource.TestCheckResourceAttr(dataSourceName, "pending_updates.#", "0"), + ), + }, + }, + }) +} diff --git a/linode/databasemysqlv2/framework_datasource.go b/linode/databasemysqlv2/framework_datasource.go new file mode 100644 index 000000000..2ccdcfe88 --- /dev/null +++ b/linode/databasemysqlv2/framework_datasource.go @@ -0,0 +1,54 @@ +package databasemysqlv2 + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/linode/terraform-provider-linode/v2/linode/helper" +) + +type DataSource struct { + helper.BaseDataSource +} + +func NewDataSource() datasource.DataSource { + return &DataSource{ + BaseDataSource: helper.NewBaseDataSource( + helper.BaseDataSourceConfig{ + Name: "linode_database_mysql_v2", + Schema: &frameworkDatasourceSchema, + }, + ), + } +} + +func (d *DataSource) Read( + ctx context.Context, + req datasource.ReadRequest, + resp *datasource.ReadResponse, +) { + tflog.Debug(ctx, "Read data.linode_database_mysql_v2") + + client := d.Meta.Client + var data Model + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + id := helper.FrameworkSafeStringToInt(data.ID.ValueString(), &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + + ctx = tflog.SetField(ctx, "id", id) + + resp.Diagnostics.Append(data.Refresh(ctx, client, id, false)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/linode/databasemysqlv2/framework_datasource_schema.go b/linode/databasemysqlv2/framework_datasource_schema.go new file mode 100644 index 000000000..b00c1e179 --- /dev/null +++ b/linode/databasemysqlv2/framework_datasource_schema.go @@ -0,0 +1,135 @@ +package databasemysqlv2 + +import ( + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var frameworkDatasourceSchema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The id of the VPC.", + Required: true, + }, + + "engine_id": schema.StringAttribute{ + Description: "The unique ID of the database engine and version to use. (e.g. mysql/8)", + Computed: true, + }, + "label": schema.StringAttribute{ + Description: "A unique, user-defined string referring to the Managed Database.", + Computed: true, + }, + "region": schema.StringAttribute{ + Description: "The Region ID for the Managed Database.", + Computed: true, + }, + "type": schema.StringAttribute{ + Description: "The Linode Instance type used by the Managed Database for its nodes.", + Computed: true, + }, + + "allow_list": schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + Description: "A list of IP addresses that can access the Managed Database. " + + "Each item can be a single IP address or a range in CIDR format.", + }, + "ca_cert": schema.StringAttribute{ + Description: "The base64-encoded SSL CA certificate for the Managed Database.", + Computed: true, + Sensitive: true, + }, + "cluster_size": schema.Int64Attribute{ + Computed: true, + Description: "The number of Linode instance nodes deployed to the Managed Database.", + }, + "fork_restore_time": schema.StringAttribute{ + Description: "The database timestamp from which it was restored.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "fork_source": schema.Int64Attribute{ + Description: "The ID of the database that was forked from.", + Computed: true, + }, + "updates": schema.ObjectAttribute{ + Description: "Configuration settings for automated patch update maintenance for the Managed Database.", + AttributeTypes: updatesAttributes, + Computed: true, + }, + + "created": schema.StringAttribute{ + Description: "When this Managed Database was created.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "encrypted": schema.BoolAttribute{ + Description: "Whether the Managed Databases is encrypted.", + Computed: true, + }, + "engine": schema.StringAttribute{ + Description: "The Managed Database engine in engine/version format.", + Computed: true, + }, + "host_primary": schema.StringAttribute{ + Description: "The primary host for the Managed Database.", + Computed: true, + }, + "host_secondary": schema.StringAttribute{ + Description: "The secondary/private host for the Managed Database.", + Computed: true, + }, + "members": schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, + Description: "A mapping between IP addresses and strings designating them as primary or failover.", + }, + "oldest_restore_time": schema.StringAttribute{ + Description: "The oldest time to which a database can be restored.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "pending_updates": schema.SetAttribute{ + Description: "A set of pending updates.", + Computed: true, + ElementType: types.ObjectType{AttrTypes: pendingUpdateAttributes}, + }, + "platform": schema.StringAttribute{ + Computed: true, + Description: "The back-end platform for relational databases used by the service.", + }, + "port": schema.Int64Attribute{ + Description: "The access port for this Managed Database.", + Computed: true, + }, + "root_password": schema.StringAttribute{ + Description: "The randomly generated root password for the Managed Database instance.", + Computed: true, + Sensitive: true, + }, + "root_username": schema.StringAttribute{ + Description: "The root username for the Managed Database instance.", + Computed: true, + Sensitive: true, + }, + "ssl_connection": schema.BoolAttribute{ + Computed: true, + Description: "Whether to require SSL credentials to establish a connection to the Managed Database.", + }, + "status": schema.StringAttribute{ + Computed: true, + Description: "The operating status of the Managed Database.", + }, + "updated": schema.StringAttribute{ + Description: "When this Managed Database was last updated.", + Computed: true, + CustomType: timetypes.RFC3339Type{}, + }, + "version": schema.StringAttribute{ + Description: "The Managed Database engine version.", + Computed: true, + }, + }, +} diff --git a/linode/databasemysqlv2/framework_models.go b/linode/databasemysqlv2/framework_models.go index 79904e758..22025cca7 100644 --- a/linode/databasemysqlv2/framework_models.go +++ b/linode/databasemysqlv2/framework_models.go @@ -41,9 +41,12 @@ type ModelPendingUpdate struct { PlannedFor timetypes.RFC3339 `tfsdk:"planned_for"` } -type Model struct { +type ResourceModel struct { + Model Timeouts timeouts.Value `tfsdk:"timeouts"` +} +type Model struct { ID types.String `tfsdk:"id"` AllowList types.Set `tfsdk:"allow_list"` diff --git a/linode/databasemysqlv2/framework_resource.go b/linode/databasemysqlv2/framework_resource.go index 68dbd01c8..3f817825f 100644 --- a/linode/databasemysqlv2/framework_resource.go +++ b/linode/databasemysqlv2/framework_resource.go @@ -50,7 +50,7 @@ func (r *Resource) Create( ) { tflog.Debug(ctx, "Create linode_database_mysql_v2") - var data Model + var data ResourceModel client := r.Meta.Client resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) @@ -185,7 +185,7 @@ func (r *Resource) Read( ) { tflog.Debug(ctx, "Read linode_database_mysql_v2") - var data Model + var data ResourceModel client := r.Meta.Client resp.Diagnostics.Append(req.State.Get(ctx, &data)...) @@ -242,7 +242,7 @@ func (r *Resource) Update( tflog.Debug(ctx, "Update linode_database_mysql_v2") client := r.Meta.Client - var plan, state Model + var plan, state ResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) resp.Diagnostics.Append(req.State.Get(ctx, &state)...) @@ -378,7 +378,7 @@ func (r *Resource) Update( } } - plan.CopyFrom(&state, true) + plan.CopyFrom(&state.Model, true) // Workaround for Crossplane issue where ID is not // properly populated in plan @@ -398,7 +398,7 @@ func (r *Resource) Delete( tflog.Debug(ctx, "Delete linode_database_mysql_v2") client := r.Meta.Client - var data Model + var data ResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) if resp.Diagnostics.HasError() { @@ -434,6 +434,6 @@ func (r *Resource) Delete( } } -func populateLogAttributes(ctx context.Context, data Model) context.Context { +func populateLogAttributes(ctx context.Context, data ResourceModel) context.Context { return tflog.SetField(ctx, "id", data.ID) } diff --git a/linode/databasemysqlv2/tmpl/data.gotf b/linode/databasemysqlv2/tmpl/data.gotf new file mode 100644 index 000000000..702c80176 --- /dev/null +++ b/linode/databasemysqlv2/tmpl/data.gotf @@ -0,0 +1,9 @@ +{{ define "database_mysql_v2_data" }} + +{{ template "database_mysql_v2_complex" . }} + +data "linode_database_mysql_v2" "foobar" { + id = linode_database_mysql_v2.foobar.id +} + +{{ end }} \ No newline at end of file diff --git a/linode/databasemysqlv2/tmpl/template.go b/linode/databasemysqlv2/tmpl/template.go index fd1e8d98d..969b207e5 100644 --- a/linode/databasemysqlv2/tmpl/template.go +++ b/linode/databasemysqlv2/tmpl/template.go @@ -57,3 +57,14 @@ func Fork(t testing.TB, label, region, engine, nodeType string) string { }, ) } + +func Data( + t testing.TB, + data TemplateData, +) string { + return acceptance.ExecuteTemplate( + t, + "database_mysql_v2_data", + data, + ) +} diff --git a/linode/framework_provider.go b/linode/framework_provider.go index a7f530f0d..4cc22077f 100644 --- a/linode/framework_provider.go +++ b/linode/framework_provider.go @@ -3,8 +3,6 @@ package linode import ( "context" - "github.com/linode/terraform-provider-linode/v2/linode/databasemysqlv2" - "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" @@ -21,6 +19,7 @@ import ( "github.com/linode/terraform-provider-linode/v2/linode/databasebackups" "github.com/linode/terraform-provider-linode/v2/linode/databaseengines" "github.com/linode/terraform-provider-linode/v2/linode/databasemysql" + "github.com/linode/terraform-provider-linode/v2/linode/databasemysqlv2" "github.com/linode/terraform-provider-linode/v2/linode/databasepostgresql" "github.com/linode/terraform-provider-linode/v2/linode/databasepostgresqlv2" "github.com/linode/terraform-provider-linode/v2/linode/databases" @@ -313,6 +312,7 @@ func (p *FrameworkProvider) DataSources(ctx context.Context) []func() datasource childaccount.NewDataSource, childaccounts.NewDataSource, networkingips.NewDataSource, + databasemysqlv2.NewDataSource, databasepostgresqlv2.NewDataSource, } }