You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Closes#378.
This patch updates the `oxide_instance` resource to support in-place
modifications to its `external_ips` attribute. That is, the instance
will no longer be destroyed and recreated when `external_ips` is
modified. Instead, the instance will be stopped, external IPs will be
detached and/or attached, and the instance will be started.
This patch also updates the `Read` method to refresh the external IPs
attached to the instance. Previously, since the external IPs required a
resource replacement there was no need to refresh them.
There are 2 types of external IPs, ephemeral and floating. There can be
at most 1 ephemeral external IP attached to an instance and any number
of floating external IPs. That means in order to modify ephemeral
external IPs the external IPs must be detached first and then attached.
This patch needs the following work before it can be merged.
- [x] Add tests for the new `external_ips` modification logic.
- [x] Add validation logic to `external_ips` to enforce at most 1
ephemeral external IP. This was previously "validated" during instance
creation but is not updated during instance update.
Here's the error that's returned when an instance is created with more
than 1 ephemeral external IP.
```
oxide_instance.foo: Creating...
╷
│ Error: Error creating instance
│
│ with oxide_instance.foo,
│ on main.tf line 24, in resource "oxide_instance" "foo":
│ 24: resource "oxide_instance" "foo" {
│
│ API error: POST https://oxide.example.com/v1/instances?project=5476ccc9-464d-4dc4-bfc0-5154de1c986f
│ ----------- RESPONSE -----------
│ Status: 400 InvalidRequest
│ Message: An instance may not have more than 1 ephemeral IP address
│ RequestID: fc6144e5-fa76-4583-a024-2e49ce17140e
│ ------- RESPONSE HEADERS -------
│ Content-Type: [application/json]
│ X-Request-Id: [fc6144e5-fa76-4583-a024-2e49ce17140e]
│ Date: [Thu, 09 Jan 2025 03:28:48 GMT]
│ Content-Length: [166]
│
╵
```
Description: "External IP addresses provided to this instance.",
260
+
Validators: []validator.Set{
261
+
instanceExternalIPValidator{},
262
+
},
259
263
NestedObject: schema.NestedAttributeObject{
260
264
Attributes: map[string]schema.Attribute{
265
+
// The id attribute is optional, computed, and has a default to account for the
266
+
// case where an instance created with an external IP using the default IP pool
267
+
// (i.e., id = null) would drift when read (e.g., id = "") and require updating
268
+
// in place.
261
269
"id": schema.StringAttribute{
262
270
Description: "If type is ephemeral, ID of the IP pool to retrieve addresses from, or all available pools if not specified. If type is floating, ID of the floating IP",
fmt.Sprintf("Error attaching floating external IP with ID %s", externalIPID.ValueString()),
1296
+
"API error: "+err.Error(),
1297
+
)
1298
+
1299
+
returndiags
1300
+
}
1301
+
default:
1302
+
diags.AddError(
1303
+
fmt.Sprintf("Cannot attach invalid external IP type %q", externalIPType.ValueString()),
1304
+
fmt.Sprintf("The external IP type must be one of: %q, %q", oxide.ExternalIpCreateTypeEphemeral, oxide.ExternalIpCreateTypeFloating),
1305
+
)
1306
+
returndiags
1307
+
}
1308
+
1309
+
tflog.Trace(ctx, fmt.Sprintf("successfully attached %s external IP with ID %s", externalIPType.ValueString(), externalIPID.ValueString()), map[string]any{"success": true})
1310
+
}
1311
+
1312
+
returnnil
1313
+
}
1314
+
1315
+
// detachExternalIPs detaches the external IPs specified by externalIPs from the
fmt.Sprintf("Error detaching floating external IP with ID %s", externalIPID.ValueString()),
1347
+
"API error: "+err.Error(),
1348
+
)
1349
+
1350
+
returndiags
1351
+
}
1352
+
default:
1353
+
diags.AddError(
1354
+
fmt.Sprintf("Cannot detach invalid external IP type %q", externalIPType.ValueString()),
1355
+
fmt.Sprintf("The external IP type must be one of: %q, %q", oxide.ExternalIpCreateTypeEphemeral, oxide.ExternalIpCreateTypeFloating),
1356
+
)
1357
+
returndiags
1358
+
}
1359
+
1360
+
tflog.Trace(ctx, fmt.Sprintf("successfully detached %s external IP with ID %s", externalIPType.ValueString(), externalIPID.ValueString()), map[string]any{"success": true})
0 commit comments