feature: Add "network_interfaces" field to server resource (#628)
* Add network_interfaces field to server resource * Update docs * Update description of stackit_server_network_interface_attach Co-authored-by: João Palet <joao.palet@outlook.com> --------- Co-authored-by: João Palet <joao.palet@outlook.com>
This commit is contained in:
parent
9b969ae583
commit
4d6f860b26
6 changed files with 132 additions and 49 deletions
|
|
@ -36,6 +36,7 @@ Server datasource schema. Must have a `region` specified in the provider configu
|
||||||
- `launched_at` (String) Date-time when the server was launched
|
- `launched_at` (String) Date-time when the server was launched
|
||||||
- `machine_type` (String) Name of the type of the machine for the server. Possible values are documented in [Virtual machine flavors](https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html)
|
- `machine_type` (String) Name of the type of the machine for the server. Possible values are documented in [Virtual machine flavors](https://docs.stackit.cloud/stackit/en/virtual-machine-flavors-75137231.html)
|
||||||
- `name` (String) The name of the server.
|
- `name` (String) The name of the server.
|
||||||
|
- `network_interfaces` (List of String) The IDs of network interfaces which should be attached to the server. Updating it will recreate the server.
|
||||||
- `updated_at` (String) Date-time when the server was updated
|
- `updated_at` (String) Date-time when the server was updated
|
||||||
- `user_data` (String) User data that is passed via cloud-init to the server.
|
- `user_data` (String) User data that is passed via cloud-init to the server.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -388,6 +388,7 @@ resource "stackit_server" "user-data-from-file" {
|
||||||
- `image_id` (String) The image ID to be used for an ephemeral disk on the server.
|
- `image_id` (String) The image ID to be used for an ephemeral disk on the server.
|
||||||
- `keypair_name` (String) The name of the keypair used during server creation.
|
- `keypair_name` (String) The name of the keypair used during server creation.
|
||||||
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container
|
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container
|
||||||
|
- `network_interfaces` (List of String) The IDs of network interfaces which should be attached to the server. Updating it will recreate the server.
|
||||||
- `user_data` (String) User data that is passed via cloud-init to the server.
|
- `user_data` (String) User data that is passed via cloud-init to the server.
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@
|
||||||
page_title: "stackit_server_network_interface_attach Resource - stackit"
|
page_title: "stackit_server_network_interface_attach Resource - stackit"
|
||||||
subcategory: ""
|
subcategory: ""
|
||||||
description: |-
|
description: |-
|
||||||
Network interface attachment resource schema. Attaches a network interface to a server. Must have a region specified in the provider configuration.
|
Network interface attachment resource schema. Attaches a network interface to a server. Must have a region specified in the provider configuration. The attachment takes only effect after server reboot.
|
||||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
|
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
|
||||||
---
|
---
|
||||||
|
|
||||||
# stackit_server_network_interface_attach (Resource)
|
# stackit_server_network_interface_attach (Resource)
|
||||||
|
|
||||||
Network interface attachment resource schema. Attaches a network interface to a server. Must have a `region` specified in the provider configuration.
|
Network interface attachment resource schema. Attaches a network interface to a server. Must have a `region` specified in the provider configuration. The attachment takes only effect after server reboot.
|
||||||
|
|
||||||
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
|
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,11 @@ func (r *serverDataSource) Schema(_ context.Context, _ datasource.SchemaRequest,
|
||||||
Description: "The image ID to be used for an ephemeral disk on the server.",
|
Description: "The image ID to be used for an ephemeral disk on the server.",
|
||||||
Computed: true,
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
"network_interfaces": schema.ListAttribute{
|
||||||
|
Description: "The IDs of network interfaces which should be attached to the server. Updating it will recreate the server.",
|
||||||
|
Computed: true,
|
||||||
|
ElementType: types.StringType,
|
||||||
|
},
|
||||||
"keypair_name": schema.StringAttribute{
|
"keypair_name": schema.StringAttribute{
|
||||||
Description: "The name of the keypair used during server creation.",
|
Description: "The name of the keypair used during server creation.",
|
||||||
Computed: true,
|
Computed: true,
|
||||||
|
|
@ -201,7 +206,9 @@ func (r *serverDataSource) Read(ctx context.Context, req datasource.ReadRequest,
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectId)
|
||||||
ctx = tflog.SetField(ctx, "server_id", serverId)
|
ctx = tflog.SetField(ctx, "server_id", serverId)
|
||||||
|
|
||||||
serverResp, err := r.client.GetServer(ctx, projectId, serverId).Execute()
|
serverReq := r.client.GetServer(ctx, projectId, serverId)
|
||||||
|
serverReq = serverReq.Details(true)
|
||||||
|
serverResp, err := serverReq.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
||||||
if ok && oapiErr.StatusCode == http.StatusNotFound {
|
if ok && oapiErr.StatusCode == http.StatusNotFound {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
|
"github.com/hashicorp/terraform-plugin-framework-validators/resourcevalidator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/attr"
|
"github.com/hashicorp/terraform-plugin-framework/attr"
|
||||||
|
|
@ -17,6 +18,7 @@ import (
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||||
|
|
@ -57,22 +59,23 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
Id types.String `tfsdk:"id"` // needed by TF
|
Id types.String `tfsdk:"id"` // needed by TF
|
||||||
ProjectId types.String `tfsdk:"project_id"`
|
ProjectId types.String `tfsdk:"project_id"`
|
||||||
ServerId types.String `tfsdk:"server_id"`
|
ServerId types.String `tfsdk:"server_id"`
|
||||||
MachineType types.String `tfsdk:"machine_type"`
|
MachineType types.String `tfsdk:"machine_type"`
|
||||||
Name types.String `tfsdk:"name"`
|
Name types.String `tfsdk:"name"`
|
||||||
AvailabilityZone types.String `tfsdk:"availability_zone"`
|
AvailabilityZone types.String `tfsdk:"availability_zone"`
|
||||||
BootVolume types.Object `tfsdk:"boot_volume"`
|
BootVolume types.Object `tfsdk:"boot_volume"`
|
||||||
ImageId types.String `tfsdk:"image_id"`
|
ImageId types.String `tfsdk:"image_id"`
|
||||||
KeypairName types.String `tfsdk:"keypair_name"`
|
NetworkInterfaces types.List `tfsdk:"network_interfaces"`
|
||||||
Labels types.Map `tfsdk:"labels"`
|
KeypairName types.String `tfsdk:"keypair_name"`
|
||||||
AffinityGroup types.String `tfsdk:"affinity_group"`
|
Labels types.Map `tfsdk:"labels"`
|
||||||
UserData types.String `tfsdk:"user_data"`
|
AffinityGroup types.String `tfsdk:"affinity_group"`
|
||||||
CreatedAt types.String `tfsdk:"created_at"`
|
UserData types.String `tfsdk:"user_data"`
|
||||||
LaunchedAt types.String `tfsdk:"launched_at"`
|
CreatedAt types.String `tfsdk:"created_at"`
|
||||||
UpdatedAt types.String `tfsdk:"updated_at"`
|
LaunchedAt types.String `tfsdk:"launched_at"`
|
||||||
DesiredStatus types.String `tfsdk:"desired_status"`
|
UpdatedAt types.String `tfsdk:"updated_at"`
|
||||||
|
DesiredStatus types.String `tfsdk:"desired_status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Struct corresponding to Model.BootVolume
|
// Struct corresponding to Model.BootVolume
|
||||||
|
|
@ -286,6 +289,20 @@ func (r *serverResource) Schema(_ context.Context, _ resource.SchemaRequest, res
|
||||||
stringplanmodifier.RequiresReplace(),
|
stringplanmodifier.RequiresReplace(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"network_interfaces": schema.ListAttribute{
|
||||||
|
Description: "The IDs of network interfaces which should be attached to the server. Updating it will recreate the server.",
|
||||||
|
Optional: true,
|
||||||
|
ElementType: types.StringType,
|
||||||
|
Validators: []validator.List{
|
||||||
|
listvalidator.ValueStringsAre(
|
||||||
|
validate.UUID(),
|
||||||
|
validate.NoSeparator(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
PlanModifiers: []planmodifier.List{
|
||||||
|
listplanmodifier.RequiresReplace(),
|
||||||
|
},
|
||||||
|
},
|
||||||
"keypair_name": schema.StringAttribute{
|
"keypair_name": schema.StringAttribute{
|
||||||
Description: "The name of the keypair used during server creation.",
|
Description: "The name of the keypair used during server creation.",
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
|
@ -422,13 +439,21 @@ func (r *serverResource) Create(ctx context.Context, req resource.CreateRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
serverId := *server.Id
|
serverId := *server.Id
|
||||||
server, err = wait.CreateServerWaitHandler(ctx, r.client, projectId, serverId).WaitWithContext(ctx)
|
_, err = wait.CreateServerWaitHandler(ctx, r.client, projectId, serverId).WaitWithContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating server", fmt.Sprintf("server creation waiting: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating server", fmt.Sprintf("server creation waiting: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx = tflog.SetField(ctx, "server_id", serverId)
|
ctx = tflog.SetField(ctx, "server_id", serverId)
|
||||||
|
|
||||||
|
// Get Server with details
|
||||||
|
serverReq := r.client.GetServer(ctx, projectId, serverId)
|
||||||
|
serverReq = serverReq.Details(true)
|
||||||
|
server, err = serverReq.Execute()
|
||||||
|
if err != nil {
|
||||||
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating server", fmt.Sprintf("get server details: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
// Map response body to schema
|
// Map response body to schema
|
||||||
err = mapFields(ctx, server, &model)
|
err = mapFields(ctx, server, &model)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -574,7 +599,9 @@ func (r *serverResource) Read(ctx context.Context, req resource.ReadRequest, res
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectId)
|
||||||
ctx = tflog.SetField(ctx, "server_id", serverId)
|
ctx = tflog.SetField(ctx, "server_id", serverId)
|
||||||
|
|
||||||
serverResp, err := r.client.GetServer(ctx, projectId, serverId).Execute()
|
serverReq := r.client.GetServer(ctx, projectId, serverId)
|
||||||
|
serverReq = serverReq.Details(true)
|
||||||
|
serverResp, err := serverReq.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
|
||||||
if ok && oapiErr.StatusCode == http.StatusNotFound {
|
if ok && oapiErr.StatusCode == http.StatusNotFound {
|
||||||
|
|
@ -815,6 +842,20 @@ func mapFields(ctx context.Context, serverResp *iaas.Server, model *Model) error
|
||||||
launchedAtValue := *serverResp.LaunchedAt
|
launchedAtValue := *serverResp.LaunchedAt
|
||||||
launchedAt = types.StringValue(launchedAtValue.Format(time.RFC3339))
|
launchedAt = types.StringValue(launchedAtValue.Format(time.RFC3339))
|
||||||
}
|
}
|
||||||
|
if serverResp.Nics != nil {
|
||||||
|
var respNics []string
|
||||||
|
for _, nic := range *serverResp.Nics {
|
||||||
|
respNics = append(respNics, *nic.NicId)
|
||||||
|
}
|
||||||
|
nicTF, diags := types.ListValueFrom(ctx, types.StringType, respNics)
|
||||||
|
if diags.HasError() {
|
||||||
|
return fmt.Errorf("failed to map networkInterfaces: %w", core.DiagsToError(diags))
|
||||||
|
}
|
||||||
|
|
||||||
|
model.NetworkInterfaces = nicTF
|
||||||
|
} else {
|
||||||
|
model.NetworkInterfaces = types.ListNull(types.StringType)
|
||||||
|
}
|
||||||
|
|
||||||
model.ServerId = types.StringValue(serverId)
|
model.ServerId = types.StringValue(serverId)
|
||||||
model.MachineType = types.StringPointerValue(serverResp.MachineType)
|
model.MachineType = types.StringPointerValue(serverResp.MachineType)
|
||||||
|
|
@ -875,6 +916,24 @@ func toCreatePayload(ctx context.Context, model *Model) (*iaas.CreateServerPaylo
|
||||||
userData = &encodedUserData
|
userData = &encodedUserData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var network *iaas.CreateServerPayloadNetworking
|
||||||
|
if !model.NetworkInterfaces.IsNull() && !model.NetworkInterfaces.IsUnknown() {
|
||||||
|
var nicIds []string
|
||||||
|
for _, nic := range model.NetworkInterfaces.Elements() {
|
||||||
|
nicString, ok := nic.(types.String)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("type assertion failed")
|
||||||
|
}
|
||||||
|
nicIds = append(nicIds, nicString.ValueString())
|
||||||
|
}
|
||||||
|
|
||||||
|
network = &iaas.CreateServerPayloadNetworking{
|
||||||
|
CreateServerNetworkingWithNics: &iaas.CreateServerNetworkingWithNics{
|
||||||
|
NicIds: &nicIds,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &iaas.CreateServerPayload{
|
return &iaas.CreateServerPayload{
|
||||||
AvailabilityZone: conversion.StringValueToPointer(model.AvailabilityZone),
|
AvailabilityZone: conversion.StringValueToPointer(model.AvailabilityZone),
|
||||||
BootVolume: bootVolumePayload,
|
BootVolume: bootVolumePayload,
|
||||||
|
|
@ -882,6 +941,7 @@ func toCreatePayload(ctx context.Context, model *Model) (*iaas.CreateServerPaylo
|
||||||
KeypairName: conversion.StringValueToPointer(model.KeypairName),
|
KeypairName: conversion.StringValueToPointer(model.KeypairName),
|
||||||
Labels: &labels,
|
Labels: &labels,
|
||||||
Name: conversion.StringValueToPointer(model.Name),
|
Name: conversion.StringValueToPointer(model.Name),
|
||||||
|
Networking: network,
|
||||||
MachineType: conversion.StringValueToPointer(model.MachineType),
|
MachineType: conversion.StringValueToPointer(model.MachineType),
|
||||||
UserData: userData,
|
UserData: userData,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,20 @@ func TestMapFields(t *testing.T) {
|
||||||
Id: utils.Ptr("sid"),
|
Id: utils.Ptr("sid"),
|
||||||
},
|
},
|
||||||
Model{
|
Model{
|
||||||
Id: types.StringValue("pid,sid"),
|
Id: types.StringValue("pid,sid"),
|
||||||
ProjectId: types.StringValue("pid"),
|
ProjectId: types.StringValue("pid"),
|
||||||
ServerId: types.StringValue("sid"),
|
ServerId: types.StringValue("sid"),
|
||||||
Name: types.StringNull(),
|
Name: types.StringNull(),
|
||||||
AvailabilityZone: types.StringNull(),
|
AvailabilityZone: types.StringNull(),
|
||||||
Labels: types.MapNull(types.StringType),
|
Labels: types.MapNull(types.StringType),
|
||||||
ImageId: types.StringNull(),
|
ImageId: types.StringNull(),
|
||||||
KeypairName: types.StringNull(),
|
NetworkInterfaces: types.ListNull(types.StringType),
|
||||||
AffinityGroup: types.StringNull(),
|
KeypairName: types.StringNull(),
|
||||||
UserData: types.StringNull(),
|
AffinityGroup: types.StringNull(),
|
||||||
CreatedAt: types.StringNull(),
|
UserData: types.StringNull(),
|
||||||
UpdatedAt: types.StringNull(),
|
CreatedAt: types.StringNull(),
|
||||||
LaunchedAt: types.StringNull(),
|
UpdatedAt: types.StringNull(),
|
||||||
|
LaunchedAt: types.StringNull(),
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
|
@ -72,7 +73,15 @@ func TestMapFields(t *testing.T) {
|
||||||
Labels: &map[string]interface{}{
|
Labels: &map[string]interface{}{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
ImageId: utils.Ptr("image_id"),
|
ImageId: utils.Ptr("image_id"),
|
||||||
|
Nics: &[]iaas.ServerNetwork{
|
||||||
|
{
|
||||||
|
NicId: utils.Ptr("nic1"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NicId: utils.Ptr("nic2"),
|
||||||
|
},
|
||||||
|
},
|
||||||
KeypairName: utils.Ptr("keypair_name"),
|
KeypairName: utils.Ptr("keypair_name"),
|
||||||
AffinityGroup: utils.Ptr("group_id"),
|
AffinityGroup: utils.Ptr("group_id"),
|
||||||
CreatedAt: utils.Ptr(testTimestamp()),
|
CreatedAt: utils.Ptr(testTimestamp()),
|
||||||
|
|
@ -89,7 +98,11 @@ func TestMapFields(t *testing.T) {
|
||||||
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
|
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{
|
||||||
"key": types.StringValue("value"),
|
"key": types.StringValue("value"),
|
||||||
}),
|
}),
|
||||||
ImageId: types.StringValue("image_id"),
|
ImageId: types.StringValue("image_id"),
|
||||||
|
NetworkInterfaces: types.ListValueMust(types.StringType, []attr.Value{
|
||||||
|
types.StringValue("nic1"),
|
||||||
|
types.StringValue("nic2"),
|
||||||
|
}),
|
||||||
KeypairName: types.StringValue("keypair_name"),
|
KeypairName: types.StringValue("keypair_name"),
|
||||||
AffinityGroup: types.StringValue("group_id"),
|
AffinityGroup: types.StringValue("group_id"),
|
||||||
CreatedAt: types.StringValue(testTimestampValue),
|
CreatedAt: types.StringValue(testTimestampValue),
|
||||||
|
|
@ -109,19 +122,20 @@ func TestMapFields(t *testing.T) {
|
||||||
Id: utils.Ptr("sid"),
|
Id: utils.Ptr("sid"),
|
||||||
},
|
},
|
||||||
Model{
|
Model{
|
||||||
Id: types.StringValue("pid,sid"),
|
Id: types.StringValue("pid,sid"),
|
||||||
ProjectId: types.StringValue("pid"),
|
ProjectId: types.StringValue("pid"),
|
||||||
ServerId: types.StringValue("sid"),
|
ServerId: types.StringValue("sid"),
|
||||||
Name: types.StringNull(),
|
Name: types.StringNull(),
|
||||||
AvailabilityZone: types.StringNull(),
|
AvailabilityZone: types.StringNull(),
|
||||||
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{}),
|
Labels: types.MapValueMust(types.StringType, map[string]attr.Value{}),
|
||||||
ImageId: types.StringNull(),
|
ImageId: types.StringNull(),
|
||||||
KeypairName: types.StringNull(),
|
NetworkInterfaces: types.ListNull(types.StringType),
|
||||||
AffinityGroup: types.StringNull(),
|
KeypairName: types.StringNull(),
|
||||||
UserData: types.StringNull(),
|
AffinityGroup: types.StringNull(),
|
||||||
CreatedAt: types.StringNull(),
|
UserData: types.StringNull(),
|
||||||
UpdatedAt: types.StringNull(),
|
CreatedAt: types.StringNull(),
|
||||||
LaunchedAt: types.StringNull(),
|
UpdatedAt: types.StringNull(),
|
||||||
|
LaunchedAt: types.StringNull(),
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue