Skip to content

Commit f978872

Browse files
committed
[3.1.4] Service Tags support added
1 parent 636a66c commit f978872

File tree

9 files changed

+1016
-8
lines changed

9 files changed

+1016
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## [3.1.4] - 2025-07-17
4+
### Features
5+
- service `tags` support added.
6+
37
## [3.1.3] - 2024-07-25
48
### Package Updates
59
- upgraded go 1.19 => 1.21

docs/resources/skysql_service.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ resource "skysql_service" "default" {
2929
volume_type = "gp3"
3030
volume_iops = 3000
3131
volume_throughput = 125
32+
tags = {
33+
name = "production-database"
34+
}
3235
# The service create is an asynchronous operation.
3336
# if you want to wait for the service to be created set wait_for_creation to true
3437
wait_for_creation = true
@@ -65,6 +68,7 @@ resource "skysql_service" "default" {
6568
- `size` (String) The size of the service. Valid values are: sky-2x4, sky-2x8 etc
6669
- `ssl_enabled` (Boolean) Whether to enable SSL. Valid values are: true or false
6770
- `storage` (Number) The storage size in GB. Valid values are: 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000
71+
- `tags` (Map of String) Tags associated with the service
6872
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
6973
- `version` (String) The software version
7074
- `volume_iops` (Number) The volume IOPS. This is only applicable for AWS

examples/main.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ resource "skysql_service" "default" {
2929
volume_type = "gp3"
3030
volume_iops = 3000
3131
volume_throughput = 125
32+
tags = {
33+
name = "production-database"
34+
}
3235
allow_list = [
3336
{
3437
"ip" : "127.0.0.1/32",

examples/resources/skysql_service.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ resource "skysql_service" "default" {
1515
volume_type = "gp3"
1616
volume_iops = 3000
1717
volume_throughput = 125
18+
tags = {
19+
name = "production-database"
20+
}
1821
# The service create is an asynchronous operation.
1922
# if you want to wait for the service to be created set wait_for_creation to true
2023
wait_for_creation = true

internal/provider/service_resource.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ type ServiceResourceModel struct {
9898
MaxscaleSize types.String `tfsdk:"maxscale_size"`
9999
FQDN types.String `tfsdk:"fqdn"`
100100
AvailabilityZone types.String `tfsdk:"availability_zone"`
101+
Tags types.Map `tfsdk:"tags"`
101102
}
102103

103104
// ServiceResourceNamedPortModel is an endpoint port
@@ -403,6 +404,12 @@ var serviceResourceSchemaV0 = schema.Schema{
403404
stringplanmodifier.RequiresReplace(),
404405
},
405406
},
407+
"tags": schema.MapAttribute{
408+
Optional: true,
409+
Computed: true,
410+
ElementType: types.StringType,
411+
Description: "Tags associated with the service",
412+
},
406413
},
407414
Blocks: map[string]schema.Block{
408415
"timeouts": timeouts.Block(context.Background(), timeouts.Opts{
@@ -721,6 +728,11 @@ func (r *ServiceResource) readServiceState(ctx context.Context, data *ServiceRes
721728
if !(data.MaxscaleNodes.IsUnknown() || data.MaxscaleSize.IsNull()) {
722729
data.MaxscaleNodes = types.Int64Value(int64(service.MaxscaleNodes))
723730
}
731+
if service.Tags != nil {
732+
data.Tags, _ = types.MapValueFrom(ctx, types.StringType, service.Tags)
733+
} else {
734+
data.Tags = types.MapNull(types.StringType)
735+
}
724736
return nil
725737
}
726738

@@ -783,6 +795,11 @@ func (r *ServiceResource) Update(ctx context.Context, req resource.UpdateRequest
783795
return
784796
}
785797

798+
r.updateServiceTags(ctx, plan, state, resp)
799+
if resp.Diagnostics.HasError() {
800+
return
801+
}
802+
786803
err := r.readServiceState(ctx, state)
787804
if err != nil {
788805
if errors.Is(err, skysql.ErrorServiceNotFound) {
@@ -1035,6 +1052,63 @@ func (r *ServiceResource) updateServicePowerState(ctx context.Context, plan *Ser
10351052
}
10361053
}
10371054

1055+
func (r *ServiceResource) updateServiceTags(ctx context.Context, plan *ServiceResourceModel, state *ServiceResourceModel, resp *resource.UpdateResponse) {
1056+
if !plan.Tags.IsUnknown() {
1057+
var planTags map[string]string
1058+
diags := plan.Tags.ElementsAs(ctx, &planTags, false)
1059+
if diags.HasError() {
1060+
// Log warning but don't fail the update to protect against state incompatibility
1061+
tflog.Warn(ctx, "Failed to parse plan tags, skipping tag update", map[string]interface{}{
1062+
"id": state.ID.ValueString(),
1063+
"error": diags.Errors(),
1064+
})
1065+
return
1066+
}
1067+
1068+
var stateTags map[string]string
1069+
diags = state.Tags.ElementsAs(ctx, &stateTags, false)
1070+
if diags.HasError() {
1071+
// For backward compatibility, if state tags can't be parsed (e.g., from older provider version),
1072+
// treat as empty map and continue with the update
1073+
tflog.Warn(ctx, "Failed to parse state tags, treating as empty", map[string]interface{}{
1074+
"id": state.ID.ValueString(),
1075+
"error": diags.Errors(),
1076+
})
1077+
stateTags = make(map[string]string)
1078+
}
1079+
1080+
if !reflect.DeepEqual(planTags, stateTags) {
1081+
tflog.Info(ctx, "Updating service tags", map[string]interface{}{
1082+
"id": state.ID.ValueString(),
1083+
})
1084+
1085+
err := r.client.UpdateServiceTags(ctx, state.ID.ValueString(), planTags)
1086+
if err != nil {
1087+
if errors.Is(err, skysql.ErrorServiceNotFound) {
1088+
tflog.Warn(ctx, "SkySQL service not found, removing from state", map[string]interface{}{
1089+
"id": state.ID.ValueString(),
1090+
})
1091+
resp.State.RemoveResource(ctx)
1092+
return
1093+
}
1094+
// Log warning but don't fail the update to protect against tag API errors
1095+
tflog.Warn(ctx, "Failed to update service tags, continuing with other updates", map[string]interface{}{
1096+
"id": state.ID.ValueString(),
1097+
"error": err.Error(),
1098+
})
1099+
return
1100+
}
1101+
1102+
state.Tags = plan.Tags
1103+
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
1104+
if resp.Diagnostics.HasError() {
1105+
return
1106+
}
1107+
r.waitForUpdate(ctx, state, resp)
1108+
}
1109+
}
1110+
}
1111+
10381112
var serviceUpdateWaitStates = []string{"ready", "failed", "stopped"}
10391113

10401114
func (r *ServiceResource) waitForUpdate(ctx context.Context, state *ServiceResourceModel, resp *resource.UpdateResponse) {

0 commit comments

Comments
 (0)