From 7dc5eb540fe1410a2e7ed46c107bc06c7732d833 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 18:38:14 +0200 Subject: [PATCH 01/11] add flavor field for instance --- api/instance/v1alpha1/types.pb.go | 29 +++- api/instance/v1alpha1/types.proto | 2 + controlplane/postgres/instance.go | 63 ++++---- controlplane/postgres/query.sql | 13 +- controlplane/postgres/query/batch.go | 2 +- controlplane/postgres/query/db.go | 2 +- controlplane/postgres/query/models.go | 2 +- controlplane/postgres/query/query.sql.go | 153 ++++++++---------- internal/resource/codec/instance.go | 1 + internal/resource/resources.go | 1 + platformd/workload/service.go | 5 +- .../database/instance_repository_test.go | 4 + 12 files changed, 145 insertions(+), 132 deletions(-) diff --git a/api/instance/v1alpha1/types.pb.go b/api/instance/v1alpha1/types.pb.go index 56fb4d5b..ecf43dfb 100644 --- a/api/instance/v1alpha1/types.pb.go +++ b/api/instance/v1alpha1/types.pb.go @@ -123,7 +123,8 @@ type Instance struct { // contains an opaque identifier representing the player // that ordered the creation this instance. ordered_by and // owner of the instance are not necessarily the same. - OrderedBy string `protobuf:"bytes,8,opt,name=ordered_by,json=orderedBy,proto3" json:"ordered_by,omitempty"` + OrderedBy string `protobuf:"bytes,8,opt,name=ordered_by,json=orderedBy,proto3" json:"ordered_by,omitempty"` + Flavor *v1alpha1.Flavor `protobuf:"bytes,9,opt,name=flavor,proto3" json:"flavor,omitempty"` } func (x *Instance) Reset() { @@ -212,6 +213,13 @@ func (x *Instance) GetOrderedBy() string { return "" } +func (x *Instance) GetFlavor() *v1alpha1.Flavor { + if x != nil { + return x.Flavor + } + return nil +} + type InstanceStatusReport struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -284,7 +292,7 @@ var file_instance_v1alpha1_types_proto_rawDesc = []byte{ 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x02, 0x0a, 0x08, 0x49, + 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe3, 0x02, 0x0a, 0x08, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x2e, 0x76, @@ -304,6 +312,9 @@ var file_instance_v1alpha1_types_proto_rawDesc = []byte{ 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x42, 0x79, + 0x12, 0x2e, 0x0a, 0x06, 0x66, 0x6c, 0x61, 0x76, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x16, 0x2e, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, + 0x31, 0x2e, 0x46, 0x6c, 0x61, 0x76, 0x6f, 0x72, 0x52, 0x06, 0x66, 0x6c, 0x61, 0x76, 0x6f, 0x72, 0x22, 0x83, 0x01, 0x0a, 0x14, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, @@ -349,18 +360,20 @@ var file_instance_v1alpha1_types_proto_goTypes = []any{ (*v1alpha1.Chunk)(nil), // 3: chunk.v1alpha1.Chunk (*v1alpha1.FlavorVersion)(nil), // 4: chunk.v1alpha1.FlavorVersion (*v1alpha11.User)(nil), // 5: user.v1alpha1.User + (*v1alpha1.Flavor)(nil), // 6: chunk.v1alpha1.Flavor } var file_instance_v1alpha1_types_proto_depIdxs = []int32{ 3, // 0: instance.v1alpha1.Instance.chunk:type_name -> chunk.v1alpha1.Chunk 4, // 1: instance.v1alpha1.Instance.flavor_version:type_name -> chunk.v1alpha1.FlavorVersion 0, // 2: instance.v1alpha1.Instance.state:type_name -> instance.v1alpha1.InstanceState 5, // 3: instance.v1alpha1.Instance.owner:type_name -> user.v1alpha1.User - 0, // 4: instance.v1alpha1.InstanceStatusReport.state:type_name -> instance.v1alpha1.InstanceState - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 6, // 4: instance.v1alpha1.Instance.flavor:type_name -> chunk.v1alpha1.Flavor + 0, // 5: instance.v1alpha1.InstanceStatusReport.state:type_name -> instance.v1alpha1.InstanceState + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_instance_v1alpha1_types_proto_init() } diff --git a/api/instance/v1alpha1/types.proto b/api/instance/v1alpha1/types.proto index 7bc614e5..9909df82 100644 --- a/api/instance/v1alpha1/types.proto +++ b/api/instance/v1alpha1/types.proto @@ -69,6 +69,8 @@ message Instance { // that ordered the creation this instance. ordered_by and // owner of the instance are not necessarily the same. string ordered_by = 8; + + chunk.v1alpha1.Flavor flavor = 9; } message InstanceStatusReport { diff --git a/controlplane/postgres/instance.go b/controlplane/postgres/instance.go index 9f46187b..1b8d737e 100644 --- a/controlplane/postgres/instance.go +++ b/controlplane/postgres/instance.go @@ -199,44 +199,53 @@ func (db *DB) GetInstancesByNodeID(ctx context.Context, nodeID string) ([]resour for _, row := range rows { var port *uint16 - if row.Port != nil { - port = ptr.Pointer(uint16(*row.Port)) + if row.Instance.Port != nil { + port = ptr.Pointer(uint16(*row.Instance.Port)) } ret = append(ret, resource.Instance{ - ID: row.ID, + ID: row.Instance.ID, Chunk: resource.Chunk{ - ID: row.ID_3, - Name: row.Name, - Description: row.Description, - Tags: row.Tags, - CreatedAt: row.CreatedAt_3.UTC(), - UpdatedAt: row.UpdatedAt_2.UTC(), + ID: row.Chunk.ID, + Name: row.Chunk.Name, + Description: row.Chunk.Description, + Tags: row.Chunk.Tags, + CreatedAt: row.Chunk.CreatedAt.UTC(), + UpdatedAt: row.Chunk.UpdatedAt.UTC(), + DeletedAt: nil, // not needed atm + }, + Flavor: resource.Flavor{ + ID: row.Flavor.ID, + Name: row.Flavor.Name, + Versions: nil, // not needed atm + CreatedAt: row.Flavor.CreatedAt.UTC(), + UpdatedAt: row.Flavor.UpdatedAt.UTC(), + DeletedAt: nil, // not needed atm }, FlavorVersion: resource.FlavorVersion{ - ID: row.ID_2, - Version: row.Version, - MinecraftVersion: row.MinecraftVersion, - Hash: row.Hash, - ChangeHash: row.ChangeHash, + ID: row.FlavorVersion.ID, + Version: row.FlavorVersion.Version, + MinecraftVersion: row.FlavorVersion.MinecraftVersion, + Hash: row.FlavorVersion.Hash, + ChangeHash: row.FlavorVersion.ChangeHash, FileHashes: nil, - FilesUploaded: row.FilesUploaded, - BuildStatus: resource.FlavorVersionBuildStatus(row.BuildStatus), - CreatedAt: row.CreatedAt_2.UTC(), + FilesUploaded: row.FlavorVersion.FilesUploaded, + BuildStatus: resource.FlavorVersionBuildStatus(row.FlavorVersion.BuildStatus), + CreatedAt: row.FlavorVersion.CreatedAt.UTC(), }, Owner: resource.User{ - ID: row.ID_5, - Nickname: row.Nickname, - Email: row.Email, - CreatedAt: row.CreatedAt_5, - UpdatedAt: row.UpdatedAt_3, + ID: row.User.ID, + Nickname: row.User.Nickname, + Email: "", // we don't want to leak emails in calls everyone can do + CreatedAt: row.User.CreatedAt, + UpdatedAt: row.User.UpdatedAt, }, - Address: row.Address, - State: resource.InstanceState(row.State), + Address: row.Node.Address, + State: resource.InstanceState(row.Instance.State), Port: port, - CreatedAt: row.CreatedAt.UTC(), - UpdatedAt: row.UpdatedAt.UTC(), - OrderedBy: row.OrderedBy, + CreatedAt: row.Instance.CreatedAt.UTC(), + UpdatedAt: row.Instance.UpdatedAt.UTC(), + OrderedBy: row.Instance.OrderedBy, }) } diff --git a/controlplane/postgres/query.sql b/controlplane/postgres/query.sql index f7344805..4a737f35 100644 --- a/controlplane/postgres/query.sql +++ b/controlplane/postgres/query.sql @@ -229,8 +229,7 @@ SELECT i.*, v.*, c.*, f.*, n.*, u.* FROM instances i JOIN flavors f ON f.chunk_id = c.id JOIN nodes n ON i.node_id = n.id JOIN users u ON u.id = i.owner_id -ORDER BY i.id -; +ORDER BY i.id; -- name: GetInstance :many SELECT * FROM instances i @@ -242,9 +241,17 @@ SELECT * FROM instances i WHERE i.id = $1; -- name: GetInstancesByNodeID :many -SELECT * FROM instances i +SELECT + sqlc.embed(v), + sqlc.embed(c), + sqlc.embed(f), + sqlc.embed(n), + sqlc.embed(u), + sqlc.embed(i) +FROM instances i JOIN flavor_versions v ON i.flavor_version_id = v.id JOIN chunks c ON i.chunk_id = c.id + JOIN flavors f ON f.id = v.flavor_id JOIN nodes n ON i.node_id = n.id JOIN users u ON u.id = i.owner_id WHERE i.node_id = $1; diff --git a/controlplane/postgres/query/batch.go b/controlplane/postgres/query/batch.go index 90a36187..28150bc6 100644 --- a/controlplane/postgres/query/batch.go +++ b/controlplane/postgres/query/batch.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.0 +// sqlc v1.31.1 // source: batch.go package query diff --git a/controlplane/postgres/query/db.go b/controlplane/postgres/query/db.go index 9ba90fad..ee2bb0b2 100644 --- a/controlplane/postgres/query/db.go +++ b/controlplane/postgres/query/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.0 +// sqlc v1.31.1 package query diff --git a/controlplane/postgres/query/models.go b/controlplane/postgres/query/models.go index 587c70f3..317107f4 100644 --- a/controlplane/postgres/query/models.go +++ b/controlplane/postgres/query/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.0 +// sqlc v1.31.1 package query diff --git a/controlplane/postgres/query/query.sql.go b/controlplane/postgres/query/query.sql.go index 96b06f40..9dee2c50 100644 --- a/controlplane/postgres/query/query.sql.go +++ b/controlplane/postgres/query/query.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.31.0 +// sqlc v1.31.1 // source: query.sql package query @@ -929,58 +929,29 @@ func (q *Queries) GetInstance(ctx context.Context, id string) ([]GetInstanceRow, } const getInstancesByNodeID = `-- name: GetInstancesByNodeID :many -SELECT i.id, chunk_id, flavor_version_id, node_id, port, state, i.created_at, i.updated_at, i.owner_id, ordered_by, v.id, flavor_id, hash, change_hash, build_status, version, files_uploaded, prev_version_id, v.created_at, presigned_url_expiry_date, presigned_url, minecraft_version, c.id, c.name, description, tags, c.created_at, c.updated_at, c.owner_id, thumbnail_hash, thumbnail_updated_at, deleted_at, n.id, n.name, address, checkpoint_api_endpoint, n.created_at, slots, u.id, nickname, email, u.created_at, u.updated_at FROM instances i +SELECT + v.id, v.flavor_id, v.hash, v.change_hash, v.build_status, v.version, v.files_uploaded, v.prev_version_id, v.created_at, v.presigned_url_expiry_date, v.presigned_url, v.minecraft_version, + c.id, c.name, c.description, c.tags, c.created_at, c.updated_at, c.owner_id, c.thumbnail_hash, c.thumbnail_updated_at, c.deleted_at, + f.id, f.chunk_id, f.name, f.created_at, f.updated_at, f.deleted_at, + n.id, n.name, n.address, n.checkpoint_api_endpoint, n.created_at, n.slots, + u.id, u.nickname, u.email, u.created_at, u.updated_at, + i.id, i.chunk_id, i.flavor_version_id, i.node_id, i.port, i.state, i.created_at, i.updated_at, i.owner_id, i.ordered_by +FROM instances i JOIN flavor_versions v ON i.flavor_version_id = v.id JOIN chunks c ON i.chunk_id = c.id + JOIN flavors f ON f.id = v.flavor_id JOIN nodes n ON i.node_id = n.id JOIN users u ON u.id = i.owner_id WHERE i.node_id = $1 ` type GetInstancesByNodeIDRow struct { - ID string - ChunkID string - FlavorVersionID string - NodeID string - Port *int32 - State InstanceState - CreatedAt time.Time - UpdatedAt time.Time - OwnerID string - OrderedBy string - ID_2 string - FlavorID string - Hash string - ChangeHash string - BuildStatus BuildStatus - Version string - FilesUploaded bool - PrevVersionID *string - CreatedAt_2 time.Time - PresignedUrlExpiryDate pgtype.Timestamptz - PresignedUrl pgtype.Text - MinecraftVersion string - ID_3 string - Name string - Description string - Tags []string - CreatedAt_3 time.Time - UpdatedAt_2 time.Time - OwnerID_2 string - ThumbnailHash pgtype.Text - ThumbnailUpdatedAt time.Time - DeletedAt pgtype.Timestamptz - ID_4 string - Name_2 string - Address netip.Addr - CheckpointApiEndpoint string - CreatedAt_4 time.Time - Slots int32 - ID_5 string - Nickname string - Email string - CreatedAt_5 time.Time - UpdatedAt_3 time.Time + FlavorVersion FlavorVersion + Chunk Chunk + Flavor Flavor + Node Node + User User + Instance Instance } func (q *Queries) GetInstancesByNodeID(ctx context.Context, nodeID string) ([]GetInstancesByNodeIDRow, error) { @@ -993,49 +964,55 @@ func (q *Queries) GetInstancesByNodeID(ctx context.Context, nodeID string) ([]Ge for rows.Next() { var i GetInstancesByNodeIDRow if err := rows.Scan( - &i.ID, - &i.ChunkID, - &i.FlavorVersionID, - &i.NodeID, - &i.Port, - &i.State, - &i.CreatedAt, - &i.UpdatedAt, - &i.OwnerID, - &i.OrderedBy, - &i.ID_2, - &i.FlavorID, - &i.Hash, - &i.ChangeHash, - &i.BuildStatus, - &i.Version, - &i.FilesUploaded, - &i.PrevVersionID, - &i.CreatedAt_2, - &i.PresignedUrlExpiryDate, - &i.PresignedUrl, - &i.MinecraftVersion, - &i.ID_3, - &i.Name, - &i.Description, - &i.Tags, - &i.CreatedAt_3, - &i.UpdatedAt_2, - &i.OwnerID_2, - &i.ThumbnailHash, - &i.ThumbnailUpdatedAt, - &i.DeletedAt, - &i.ID_4, - &i.Name_2, - &i.Address, - &i.CheckpointApiEndpoint, - &i.CreatedAt_4, - &i.Slots, - &i.ID_5, - &i.Nickname, - &i.Email, - &i.CreatedAt_5, - &i.UpdatedAt_3, + &i.FlavorVersion.ID, + &i.FlavorVersion.FlavorID, + &i.FlavorVersion.Hash, + &i.FlavorVersion.ChangeHash, + &i.FlavorVersion.BuildStatus, + &i.FlavorVersion.Version, + &i.FlavorVersion.FilesUploaded, + &i.FlavorVersion.PrevVersionID, + &i.FlavorVersion.CreatedAt, + &i.FlavorVersion.PresignedUrlExpiryDate, + &i.FlavorVersion.PresignedUrl, + &i.FlavorVersion.MinecraftVersion, + &i.Chunk.ID, + &i.Chunk.Name, + &i.Chunk.Description, + &i.Chunk.Tags, + &i.Chunk.CreatedAt, + &i.Chunk.UpdatedAt, + &i.Chunk.OwnerID, + &i.Chunk.ThumbnailHash, + &i.Chunk.ThumbnailUpdatedAt, + &i.Chunk.DeletedAt, + &i.Flavor.ID, + &i.Flavor.ChunkID, + &i.Flavor.Name, + &i.Flavor.CreatedAt, + &i.Flavor.UpdatedAt, + &i.Flavor.DeletedAt, + &i.Node.ID, + &i.Node.Name, + &i.Node.Address, + &i.Node.CheckpointApiEndpoint, + &i.Node.CreatedAt, + &i.Node.Slots, + &i.User.ID, + &i.User.Nickname, + &i.User.Email, + &i.User.CreatedAt, + &i.User.UpdatedAt, + &i.Instance.ID, + &i.Instance.ChunkID, + &i.Instance.FlavorVersionID, + &i.Instance.NodeID, + &i.Instance.Port, + &i.Instance.State, + &i.Instance.CreatedAt, + &i.Instance.UpdatedAt, + &i.Instance.OwnerID, + &i.Instance.OrderedBy, ); err != nil { return nil, err } diff --git a/internal/resource/codec/instance.go b/internal/resource/codec/instance.go index 0611336b..91193045 100644 --- a/internal/resource/codec/instance.go +++ b/internal/resource/codec/instance.go @@ -47,6 +47,7 @@ func InstanceToTransport(ins resource.Instance) *instancev1alpha1.Instance { CreatedAt: timestamppb.New(ins.Chunk.CreatedAt), UpdatedAt: timestamppb.New(ins.Chunk.UpdatedAt), }, + Flavor: FlavorToTransport(ins.Flavor), FlavorVersion: &chunkv1alpha1.FlavorVersion{ Id: ins.FlavorVersion.ID, Version: ins.FlavorVersion.Version, diff --git a/internal/resource/resources.go b/internal/resource/resources.go index e54fc33a..5e9c6160 100644 --- a/internal/resource/resources.go +++ b/internal/resource/resources.go @@ -117,6 +117,7 @@ type Instance struct { ID string Chunk Chunk FlavorVersion FlavorVersion + Flavor Flavor Address netip.Addr State InstanceState Port *uint16 diff --git a/platformd/workload/service.go b/platformd/workload/service.go index 90c36b37..4508998a 100644 --- a/platformd/workload/service.go +++ b/platformd/workload/service.go @@ -66,9 +66,8 @@ func (s *svc) RunWorkload(ctx context.Context, w Workload, attempt uint) error { Annotations: map[string]string{ AnnotationInstance: string(data), }, - Hostname: w.Hostname, // TODO: explore if we can use the id as the hostname - LogDirectory: cri.PodLogDir, - Labels: w.Labels, + Hostname: w.Hostname, // TODO: explore if we can use the id as the hostname + Labels: w.Labels, DnsConfig: &runtimev1.DNSConfig{ Servers: []string{"10.0.0.53"}, // TODO: make configurable Options: []string{"edns0", "trust-ad"}, diff --git a/test/functional/database/instance_repository_test.go b/test/functional/database/instance_repository_test.go index a601a329..3c0fbc52 100644 --- a/test/functional/database/instance_repository_test.go +++ b/test/functional/database/instance_repository_test.go @@ -297,6 +297,7 @@ func TestGetInstancesByNodeID(t *testing.T) { ins := resource.Instance{ ID: test.NewUUIDv7(t), Chunk: chunks[i], + Flavor: chunks[i].Flavors[0], FlavorVersion: v, Address: fixture.Node().Addr, State: resource.InstanceStatePending, @@ -307,6 +308,9 @@ func TestGetInstancesByNodeID(t *testing.T) { ins.Chunk.Owner = resource.User{} // will not be returned atm ins.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm + ins.Chunk.DeletedAt = nil // will not be returned atm + ins.Owner.Email = "" // will not be returned atm + ins.Flavor.Versions = nil // will not be returned atm // see FIXME in GetInstancesByNodeID ins.Chunk.Flavors = nil From b87535b19a477a5f3604c30bd8f331d711fca39b Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 18:39:45 +0200 Subject: [PATCH 02/11] fmt --- test/functional/database/instance_repository_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/functional/database/instance_repository_test.go b/test/functional/database/instance_repository_test.go index 3c0fbc52..39f0bc44 100644 --- a/test/functional/database/instance_repository_test.go +++ b/test/functional/database/instance_repository_test.go @@ -308,9 +308,9 @@ func TestGetInstancesByNodeID(t *testing.T) { ins.Chunk.Owner = resource.User{} // will not be returned atm ins.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm - ins.Chunk.DeletedAt = nil // will not be returned atm - ins.Owner.Email = "" // will not be returned atm - ins.Flavor.Versions = nil // will not be returned atm + ins.Chunk.DeletedAt = nil // will not be returned atm + ins.Owner.Email = "" // will not be returned atm + ins.Flavor.Versions = nil // will not be returned atm // see FIXME in GetInstancesByNodeID ins.Chunk.Flavors = nil From c37fdaec822b6629f307ea327cf464301b2eeb30 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 18:40:46 +0200 Subject: [PATCH 03/11] add ordered by --- test/functional/database/instance_repository_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/functional/database/instance_repository_test.go b/test/functional/database/instance_repository_test.go index 39f0bc44..2fc8e344 100644 --- a/test/functional/database/instance_repository_test.go +++ b/test/functional/database/instance_repository_test.go @@ -304,6 +304,7 @@ func TestGetInstancesByNodeID(t *testing.T) { CreatedAt: chunks[i].CreatedAt, UpdatedAt: chunks[i].UpdatedAt, Owner: chunks[i].Owner, + OrderedBy: "ordered_by", } ins.Chunk.Owner = resource.User{} // will not be returned atm From 6a78586ac598b757646e6167037dc21690d83624 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 18:42:38 +0200 Subject: [PATCH 04/11] add flavor to instance fixture --- test/fixture/chunk.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/fixture/chunk.go b/test/fixture/chunk.go index f5dca715..f919418f 100644 --- a/test/fixture/chunk.go +++ b/test/fixture/chunk.go @@ -170,6 +170,7 @@ func Instance(mod ...func(i *resource.Instance)) resource.Instance { ins := resource.Instance{ ID: "019533f6-a770-7903-8f99-88ae6b271663", Chunk: c, + Flavor: c.Flavors[0], FlavorVersion: c.Flavors[0].Versions[0], Address: netip.MustParseAddr("198.51.100.1"), State: resource.InstanceStatePending, From 47047e8f60fdfc2a31d081b270b70a0ed8db3418 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 18:55:27 +0200 Subject: [PATCH 05/11] add pod log dir again --- platformd/reconciler_test.go | 4 ++++ platformd/workload/service.go | 1 + 2 files changed, 5 insertions(+) diff --git a/platformd/reconciler_test.go b/platformd/reconciler_test.go index bb2edd6e..a1bb59a6 100644 --- a/platformd/reconciler_test.go +++ b/platformd/reconciler_test.go @@ -527,6 +527,10 @@ func discoverInstance( Chunk: &chunkv1alpha1.Chunk{ Name: "test-chunk", }, + Flavor: &chunkv1alpha1.Flavor{ + Id: "test-flavor-id", + Name: "test-flavor", + }, FlavorVersion: &chunkv1alpha1.FlavorVersion{ Id: "flavor-version-id", }, diff --git a/platformd/workload/service.go b/platformd/workload/service.go index 4508998a..aa21dfe2 100644 --- a/platformd/workload/service.go +++ b/platformd/workload/service.go @@ -68,6 +68,7 @@ func (s *svc) RunWorkload(ctx context.Context, w Workload, attempt uint) error { }, Hostname: w.Hostname, // TODO: explore if we can use the id as the hostname Labels: w.Labels, + LogDirectory: cri.PodLogDir, DnsConfig: &runtimev1.DNSConfig{ Servers: []string{"10.0.0.53"}, // TODO: make configurable Options: []string{"edns0", "trust-ad"}, From d656b72bce68e8a36296f629c36c5cf4a690cc71 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 18:59:35 +0200 Subject: [PATCH 06/11] also return flavors for other calls --- controlplane/postgres/instance.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/controlplane/postgres/instance.go b/controlplane/postgres/instance.go index 1b8d737e..31a74352 100644 --- a/controlplane/postgres/instance.go +++ b/controlplane/postgres/instance.go @@ -150,6 +150,10 @@ func (db *DB) ListInstances(ctx context.Context, pageSize int, afterID *string) UpdatedAt: instanceRow.UpdatedAt_3.UTC(), } flavors = append(flavors, f) + + if f.ID == instanceRow.FlavorID { + i.Flavor = f + } } sort.Slice(flavors, func(i, j int) bool { @@ -388,8 +392,10 @@ func (db *DB) getInstanceByID(ctx context.Context, q *query.Queries, id string) CreatedAt: instanceRow.CreatedAt_2.UTC(), UpdatedAt: instanceRow.UpdatedAt_2.UTC(), } - flavors = append(flavors, f) + if f.ID == instanceRow.FlavorID { + ret.Flavor = f + } } sort.Slice(flavors, func(i, j int) bool { From 48f12662f9315601e5b81b24112172d1de76bf0c Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 19:04:04 +0200 Subject: [PATCH 07/11] adjust tests --- test/functional/controlplane/instance_api_test.go | 8 ++++++++ test/functional/database/instance_repository_test.go | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/test/functional/controlplane/instance_api_test.go b/test/functional/controlplane/instance_api_test.go index 8ae81f59..6134db72 100644 --- a/test/functional/controlplane/instance_api_test.go +++ b/test/functional/controlplane/instance_api_test.go @@ -131,6 +131,7 @@ func TestAPIListInstances(t *testing.T) { i.FlavorVersion = i.Chunk.Flavors[0].Versions[0] i.Port = nil // port will not be saved when creating i.FlavorVersion.FileHashes = nil // not returned atm + i.Flavor.Versions = nil // not returned atm })) } @@ -227,6 +228,7 @@ func TestRunFlavorVersion(t *testing.T) { cp.Postgres.InsertNode(t) cp.Postgres.CreateChunk(t, &c, fixture.CreateOptionsAll) + f := c.Flavors[0] v := c.Flavors[0].Versions[0] expected := &instancev1alpha1.Instance{ @@ -239,6 +241,12 @@ func TestRunFlavorVersion(t *testing.T) { CreatedAt: timestamppb.New(c.CreatedAt), UpdatedAt: timestamppb.New(c.UpdatedAt), }, + Flavor: &chunkv1alpha1.Flavor{ + Name: f.Name, + CreatedAt: timestamppb.New(f.CreatedAt), + UpdatedAt: timestamppb.New(f.UpdatedAt), + Versions: nil, // not returned atm + }, FlavorVersion: &chunkv1alpha1.FlavorVersion{ Id: v.ID, Version: v.Version, diff --git a/test/functional/database/instance_repository_test.go b/test/functional/database/instance_repository_test.go index 2fc8e344..1a762757 100644 --- a/test/functional/database/instance_repository_test.go +++ b/test/functional/database/instance_repository_test.go @@ -93,6 +93,7 @@ func TestCreateInstance(t *testing.T) { expected.FlavorVersion.FileHashes = nil // will not be returned atm expected.Chunk.Owner = resource.User{} // will not be returned atm expected.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm + expected.Flavor.Versions = nil // will not be returned atm expected.Owner = c.Owner actual, err := pg.DB.CreateInstance(ctx, expected, fixture.Node().ID) @@ -136,6 +137,7 @@ func TestDBListInstances(t *testing.T) { i.FlavorVersion.FileHashes = nil // will not be returned atm i.Chunk.Owner = resource.User{} // will not be returned atm i.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm + i.Flavor.Versions = nil // will not be returned atm i.Owner = c.Owner }), fixture.Instance(func(i *resource.Instance) { @@ -146,6 +148,7 @@ func TestDBListInstances(t *testing.T) { i.FlavorVersion.FileHashes = nil // will not be returned atm i.Chunk.Owner = resource.User{} // will not be returned atm i.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm + i.Flavor.Versions = nil // will not be returned atm i.Owner = c.Owner }), } @@ -209,6 +212,7 @@ func TestGetInstanceByID(t *testing.T) { tt.expected.Owner = tt.expected.Chunk.Owner tt.expected.Chunk.Owner = resource.User{} // will not be returned atm tt.expected.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm + tt.expected.Flavor.Versions = nil // will not be returned atm v := tt.expected.Chunk.Flavors[0].Versions[0] v.FileHashes = nil // not returned atm From f3626a9f5fdc54c9c0e1ac39a8f7140d03ac3cf9 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 19:30:12 +0200 Subject: [PATCH 08/11] fix db tests --- controlplane/postgres/instance.go | 65 +++---- controlplane/postgres/query.sql | 9 +- controlplane/postgres/query/query.sql.go | 162 +++++++----------- .../database/instance_repository_test.go | 14 +- 4 files changed, 113 insertions(+), 137 deletions(-) diff --git a/controlplane/postgres/instance.go b/controlplane/postgres/instance.go index 31a74352..ab7e5524 100644 --- a/controlplane/postgres/instance.go +++ b/controlplane/postgres/instance.go @@ -343,43 +343,43 @@ func (db *DB) getInstanceByID(ctx context.Context, q *query.Queries, id string) // instance port is intentionally left out, because it will not be // known beforehand atm, thus it will always be nil when creating. ret := resource.Instance{ - ID: row.ID, - Address: row.Address, - State: resource.InstanceState(row.State), - CreatedAt: row.CreatedAt.UTC(), - UpdatedAt: row.UpdatedAt.UTC(), - OrderedBy: row.OrderedBy, + ID: row.Instance.ID, + Address: row.Node.Address, + State: resource.InstanceState(row.Instance.State), + CreatedAt: row.Instance.CreatedAt.UTC(), + UpdatedAt: row.Instance.UpdatedAt.UTC(), + OrderedBy: row.Instance.OrderedBy, Chunk: resource.Chunk{ - ID: row.ID_3, - Name: row.Name, - Description: row.Description, - Tags: row.Tags, - CreatedAt: row.CreatedAt_3.UTC(), - UpdatedAt: row.UpdatedAt_2.UTC(), + ID: row.Chunk.ID, + Name: row.Chunk.Name, + Description: row.Chunk.Description, + Tags: row.Chunk.Tags, + CreatedAt: row.Chunk.CreatedAt.UTC(), + UpdatedAt: row.Chunk.UpdatedAt.UTC(), }, FlavorVersion: resource.FlavorVersion{ - ID: row.ID_2, - Version: row.Version, - MinecraftVersion: row.MinecraftVersion, - Hash: row.Hash, - ChangeHash: row.ChangeHash, + ID: row.FlavorVersion.ID, + Version: row.FlavorVersion.Version, + MinecraftVersion: row.FlavorVersion.MinecraftVersion, + Hash: row.FlavorVersion.Hash, + ChangeHash: row.FlavorVersion.ChangeHash, FileHashes: nil, - FilesUploaded: row.FilesUploaded, - BuildStatus: resource.FlavorVersionBuildStatus(row.BuildStatus), - CreatedAt: row.CreatedAt_2.UTC(), + FilesUploaded: row.FlavorVersion.FilesUploaded, + BuildStatus: resource.FlavorVersionBuildStatus(row.FlavorVersion.BuildStatus), + CreatedAt: row.FlavorVersion.CreatedAt.UTC(), }, Owner: resource.User{ - ID: row.ID_6, - Nickname: row.Nickname, - Email: row.Email, - CreatedAt: row.CreatedAt_5, - UpdatedAt: row.UpdatedAt_3, + ID: row.User.ID, + Nickname: row.User.Nickname, + Email: "", // dont return email + CreatedAt: row.User.CreatedAt, + UpdatedAt: row.User.UpdatedAt, }, } var port *uint16 - if row.Port != nil { - port = ptr.Pointer(uint16(*row.Port)) + if row.Instance.Port != nil { + port = ptr.Pointer(uint16(*row.Instance.Port)) } ret.Port = port @@ -387,13 +387,14 @@ func (db *DB) getInstanceByID(ctx context.Context, q *query.Queries, id string) flavors := make([]resource.Flavor, 0, len(rows)) for _, instanceRow := range rows { f := resource.Flavor{ - ID: instanceRow.ID_2, - Name: instanceRow.Name_2, - CreatedAt: instanceRow.CreatedAt_2.UTC(), - UpdatedAt: instanceRow.UpdatedAt_2.UTC(), + ID: instanceRow.Flavor.ID, + Name: instanceRow.Flavor.Name, + CreatedAt: instanceRow.Flavor.CreatedAt.UTC(), + UpdatedAt: instanceRow.Flavor.UpdatedAt.UTC(), } flavors = append(flavors, f) - if f.ID == instanceRow.FlavorID { + + if f.ID == instanceRow.FlavorVersion.FlavorID { ret.Flavor = f } } diff --git a/controlplane/postgres/query.sql b/controlplane/postgres/query.sql index 4a737f35..387062a6 100644 --- a/controlplane/postgres/query.sql +++ b/controlplane/postgres/query.sql @@ -232,7 +232,14 @@ SELECT i.*, v.*, c.*, f.*, n.*, u.* FROM instances i ORDER BY i.id; -- name: GetInstance :many -SELECT * FROM instances i +SELECT + sqlc.embed(v), + sqlc.embed(c), + sqlc.embed(f), + sqlc.embed(n), + sqlc.embed(u), + sqlc.embed(i) +FROM instances i JOIN flavor_versions v ON i.flavor_version_id = v.id JOIN chunks c ON i.chunk_id = c.id JOIN flavors f ON f.chunk_id = c.id diff --git a/controlplane/postgres/query/query.sql.go b/controlplane/postgres/query/query.sql.go index 9dee2c50..7d3695d3 100644 --- a/controlplane/postgres/query/query.sql.go +++ b/controlplane/postgres/query/query.sql.go @@ -797,7 +797,14 @@ func (q *Queries) GetFlavorByID(ctx context.Context, flavorID string) ([]GetFlav } const getInstance = `-- name: GetInstance :many -SELECT i.id, i.chunk_id, flavor_version_id, node_id, port, state, i.created_at, i.updated_at, i.owner_id, ordered_by, v.id, flavor_id, hash, change_hash, build_status, version, files_uploaded, prev_version_id, v.created_at, presigned_url_expiry_date, presigned_url, minecraft_version, c.id, c.name, description, tags, c.created_at, c.updated_at, c.owner_id, thumbnail_hash, thumbnail_updated_at, c.deleted_at, f.id, f.chunk_id, f.name, f.created_at, f.updated_at, f.deleted_at, n.id, n.name, address, checkpoint_api_endpoint, n.created_at, slots, u.id, nickname, email, u.created_at, u.updated_at FROM instances i +SELECT + v.id, v.flavor_id, v.hash, v.change_hash, v.build_status, v.version, v.files_uploaded, v.prev_version_id, v.created_at, v.presigned_url_expiry_date, v.presigned_url, v.minecraft_version, + c.id, c.name, c.description, c.tags, c.created_at, c.updated_at, c.owner_id, c.thumbnail_hash, c.thumbnail_updated_at, c.deleted_at, + f.id, f.chunk_id, f.name, f.created_at, f.updated_at, f.deleted_at, + n.id, n.name, n.address, n.checkpoint_api_endpoint, n.created_at, n.slots, + u.id, u.nickname, u.email, u.created_at, u.updated_at, + i.id, i.chunk_id, i.flavor_version_id, i.node_id, i.port, i.state, i.created_at, i.updated_at, i.owner_id, i.ordered_by +FROM instances i JOIN flavor_versions v ON i.flavor_version_id = v.id JOIN chunks c ON i.chunk_id = c.id JOIN flavors f ON f.chunk_id = c.id @@ -807,55 +814,12 @@ WHERE i.id = $1 ` type GetInstanceRow struct { - ID string - ChunkID string - FlavorVersionID string - NodeID string - Port *int32 - State InstanceState - CreatedAt time.Time - UpdatedAt time.Time - OwnerID string - OrderedBy string - ID_2 string - FlavorID string - Hash string - ChangeHash string - BuildStatus BuildStatus - Version string - FilesUploaded bool - PrevVersionID *string - CreatedAt_2 time.Time - PresignedUrlExpiryDate pgtype.Timestamptz - PresignedUrl pgtype.Text - MinecraftVersion string - ID_3 string - Name string - Description string - Tags []string - CreatedAt_3 time.Time - UpdatedAt_2 time.Time - OwnerID_2 string - ThumbnailHash pgtype.Text - ThumbnailUpdatedAt time.Time - DeletedAt pgtype.Timestamptz - ID_4 string - ChunkID_2 string - Name_2 string - CreatedAt_4 time.Time - UpdatedAt_3 time.Time - DeletedAt_2 pgtype.Timestamptz - ID_5 string - Name_3 string - Address netip.Addr - CheckpointApiEndpoint string - CreatedAt_5 time.Time - Slots int32 - ID_6 string - Nickname string - Email string - CreatedAt_6 time.Time - UpdatedAt_4 time.Time + FlavorVersion FlavorVersion + Chunk Chunk + Flavor Flavor + Node Node + User User + Instance Instance } func (q *Queries) GetInstance(ctx context.Context, id string) ([]GetInstanceRow, error) { @@ -868,55 +832,55 @@ func (q *Queries) GetInstance(ctx context.Context, id string) ([]GetInstanceRow, for rows.Next() { var i GetInstanceRow if err := rows.Scan( - &i.ID, - &i.ChunkID, - &i.FlavorVersionID, - &i.NodeID, - &i.Port, - &i.State, - &i.CreatedAt, - &i.UpdatedAt, - &i.OwnerID, - &i.OrderedBy, - &i.ID_2, - &i.FlavorID, - &i.Hash, - &i.ChangeHash, - &i.BuildStatus, - &i.Version, - &i.FilesUploaded, - &i.PrevVersionID, - &i.CreatedAt_2, - &i.PresignedUrlExpiryDate, - &i.PresignedUrl, - &i.MinecraftVersion, - &i.ID_3, - &i.Name, - &i.Description, - &i.Tags, - &i.CreatedAt_3, - &i.UpdatedAt_2, - &i.OwnerID_2, - &i.ThumbnailHash, - &i.ThumbnailUpdatedAt, - &i.DeletedAt, - &i.ID_4, - &i.ChunkID_2, - &i.Name_2, - &i.CreatedAt_4, - &i.UpdatedAt_3, - &i.DeletedAt_2, - &i.ID_5, - &i.Name_3, - &i.Address, - &i.CheckpointApiEndpoint, - &i.CreatedAt_5, - &i.Slots, - &i.ID_6, - &i.Nickname, - &i.Email, - &i.CreatedAt_6, - &i.UpdatedAt_4, + &i.FlavorVersion.ID, + &i.FlavorVersion.FlavorID, + &i.FlavorVersion.Hash, + &i.FlavorVersion.ChangeHash, + &i.FlavorVersion.BuildStatus, + &i.FlavorVersion.Version, + &i.FlavorVersion.FilesUploaded, + &i.FlavorVersion.PrevVersionID, + &i.FlavorVersion.CreatedAt, + &i.FlavorVersion.PresignedUrlExpiryDate, + &i.FlavorVersion.PresignedUrl, + &i.FlavorVersion.MinecraftVersion, + &i.Chunk.ID, + &i.Chunk.Name, + &i.Chunk.Description, + &i.Chunk.Tags, + &i.Chunk.CreatedAt, + &i.Chunk.UpdatedAt, + &i.Chunk.OwnerID, + &i.Chunk.ThumbnailHash, + &i.Chunk.ThumbnailUpdatedAt, + &i.Chunk.DeletedAt, + &i.Flavor.ID, + &i.Flavor.ChunkID, + &i.Flavor.Name, + &i.Flavor.CreatedAt, + &i.Flavor.UpdatedAt, + &i.Flavor.DeletedAt, + &i.Node.ID, + &i.Node.Name, + &i.Node.Address, + &i.Node.CheckpointApiEndpoint, + &i.Node.CreatedAt, + &i.Node.Slots, + &i.User.ID, + &i.User.Nickname, + &i.User.Email, + &i.User.CreatedAt, + &i.User.UpdatedAt, + &i.Instance.ID, + &i.Instance.ChunkID, + &i.Instance.FlavorVersionID, + &i.Instance.NodeID, + &i.Instance.Port, + &i.Instance.State, + &i.Instance.CreatedAt, + &i.Instance.UpdatedAt, + &i.Instance.OwnerID, + &i.Instance.OrderedBy, ); err != nil { return nil, err } diff --git a/test/functional/database/instance_repository_test.go b/test/functional/database/instance_repository_test.go index 1a762757..cc0b6236 100644 --- a/test/functional/database/instance_repository_test.go +++ b/test/functional/database/instance_repository_test.go @@ -20,6 +20,7 @@ package database import ( "context" + "fmt" "net/netip" "sort" "strings" @@ -84,17 +85,23 @@ func TestCreateInstance(t *testing.T) { pg.InsertMinecraftVersion(t) c.Flavors = []resource.Flavor{c.Flavors[0]} + fmt.Println("gef", c.Flavors[0].ID) + pg.CreateChunk(t, &c, fixture.CreateOptionsAll) + fmt.Println("af", c.Flavors[0].ID) + expected := fixture.Instance() expected.Chunk = c expected.FlavorVersion = c.Flavors[0].Versions[0] + expected.Flavor = c.Flavors[0] expected.Port = nil // port will not be saved when creating expected.FlavorVersion.FileHashes = nil // will not be returned atm expected.Chunk.Owner = resource.User{} // will not be returned atm expected.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm expected.Flavor.Versions = nil // will not be returned atm expected.Owner = c.Owner + expected.Owner.Email = "" // will not be returned atm actual, err := pg.DB.CreateInstance(ctx, expected, fixture.Node().ID) require.NoError(t, err) @@ -207,8 +214,6 @@ func TestGetInstanceByID(t *testing.T) { pg.InsertMinecraftVersion(t) if tt.create { - pg.CreateChunk(t, &tt.expected.Chunk, fixture.CreateOptionsAll) - tt.expected.Owner = tt.expected.Chunk.Owner tt.expected.Chunk.Owner = resource.User{} // will not be returned atm tt.expected.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm @@ -219,10 +224,9 @@ func TestGetInstanceByID(t *testing.T) { tt.expected.FlavorVersion = v - _, err := pg.DB.CreateInstance(ctx, tt.expected, fixture.Node().ID) - require.NoError(t, err) + pg.CreateInstance(t, fixture.Node().ID, &tt.expected) - _, err = pg.Pool.Exec( + _, err := pg.Pool.Exec( ctx, `UPDATE instances SET port = $1 WHERE id = $2`, tt.expected.Port, From ac6ac7b05d3c2c2e8a09655fbc1e529ef5aeaf7d Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 19:30:57 +0200 Subject: [PATCH 09/11] fmt --- platformd/workload/service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformd/workload/service.go b/platformd/workload/service.go index aa21dfe2..a3d6b7ee 100644 --- a/platformd/workload/service.go +++ b/platformd/workload/service.go @@ -66,8 +66,8 @@ func (s *svc) RunWorkload(ctx context.Context, w Workload, attempt uint) error { Annotations: map[string]string{ AnnotationInstance: string(data), }, - Hostname: w.Hostname, // TODO: explore if we can use the id as the hostname - Labels: w.Labels, + Hostname: w.Hostname, // TODO: explore if we can use the id as the hostname + Labels: w.Labels, LogDirectory: cri.PodLogDir, DnsConfig: &runtimev1.DNSConfig{ Servers: []string{"10.0.0.53"}, // TODO: make configurable From 2ca75c598084ad109811b320317f57abc80edc05 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 19:51:36 +0200 Subject: [PATCH 10/11] adjsut --- controlplane/postgres/instance.go | 66 +++---- controlplane/postgres/query.sql | 9 +- controlplane/postgres/query/query.sql.go | 162 +++++++----------- .../database/instance_repository_test.go | 22 ++- 4 files changed, 119 insertions(+), 140 deletions(-) diff --git a/controlplane/postgres/instance.go b/controlplane/postgres/instance.go index ab7e5524..45be44ae 100644 --- a/controlplane/postgres/instance.go +++ b/controlplane/postgres/instance.go @@ -77,10 +77,10 @@ func (db *DB) ListInstances(ctx context.Context, pageSize int, afterID *string) m := make(map[string][]query.ListInstancesWithPaginationRow) order := make([]string, 0) for _, r := range rows { - if _, ok := m[r.ID]; !ok { - order = append(order, r.ID) + if _, ok := m[r.Instance.ID]; !ok { + order = append(order, r.Instance.ID) } - m[r.ID] = append(m[r.ID], r) + m[r.Instance.ID] = append(m[r.Instance.ID], r) } ret = make([]resource.Instance, 0, len(m)) @@ -99,19 +99,19 @@ func (db *DB) ListInstances(ctx context.Context, pageSize int, afterID *string) // instance port is intentionally left out, because it will not be // known beforehand atm, thus it will always be nil when creating. i := resource.Instance{ - ID: row.ID, - Address: row.Address, - State: resource.InstanceState(row.State), - CreatedAt: row.CreatedAt.UTC(), - UpdatedAt: row.UpdatedAt.UTC(), - OrderedBy: row.OrderedBy, + ID: row.Instance.ID, + Address: row.Node.Address, + State: resource.InstanceState(row.Instance.State), + CreatedAt: row.Instance.CreatedAt.UTC(), + UpdatedAt: row.Instance.UpdatedAt.UTC(), + OrderedBy: row.Instance.OrderedBy, Chunk: resource.Chunk{ - ID: row.ID_3, - Name: row.Name, - Description: row.Description, - Tags: row.Tags, - CreatedAt: row.CreatedAt_3.UTC(), - UpdatedAt: row.UpdatedAt_2.UTC(), + ID: row.Chunk.ID, + Name: row.Chunk.Name, + Description: row.Chunk.Description, + Tags: row.Chunk.Tags, + CreatedAt: row.Chunk.CreatedAt.UTC(), + UpdatedAt: row.Chunk.UpdatedAt.UTC(), // FIXME: for now this is not needed anywhere, so it is not included in the query Thumbnail: resource.Thumbnail{ @@ -119,39 +119,39 @@ func (db *DB) ListInstances(ctx context.Context, pageSize int, afterID *string) }, }, FlavorVersion: resource.FlavorVersion{ - ID: row.ID_2, - Version: row.Version, - MinecraftVersion: row.MinecraftVersion, - Hash: row.Hash, - ChangeHash: row.ChangeHash, + ID: row.FlavorVersion.ID, + Version: row.FlavorVersion.Version, + MinecraftVersion: row.FlavorVersion.MinecraftVersion, + Hash: row.FlavorVersion.Hash, + ChangeHash: row.FlavorVersion.ChangeHash, // FIXME: for now those are not needed anywhere, so they are not included in the query FileHashes: nil, - FilesUploaded: row.FilesUploaded, - BuildStatus: resource.FlavorVersionBuildStatus(row.BuildStatus), - CreatedAt: row.CreatedAt_2.UTC(), + FilesUploaded: row.FlavorVersion.FilesUploaded, + BuildStatus: resource.FlavorVersionBuildStatus(row.FlavorVersion.BuildStatus), + CreatedAt: row.FlavorVersion.CreatedAt.UTC(), }, Owner: resource.User{ - ID: row.ID_6, - Nickname: row.Nickname, - Email: row.Email, - CreatedAt: row.CreatedAt_6, - UpdatedAt: row.UpdatedAt_4, + ID: row.User.ID, + Nickname: row.User.Nickname, + Email: "", // do not return + CreatedAt: row.User.CreatedAt, + UpdatedAt: row.User.UpdatedAt, }, } flavors := make([]resource.Flavor, 0, len(rows)) for _, instanceRow := range v { f := resource.Flavor{ - ID: instanceRow.ID_4, - Name: instanceRow.Name_2, - CreatedAt: instanceRow.CreatedAt_4.UTC(), - UpdatedAt: instanceRow.UpdatedAt_3.UTC(), + ID: instanceRow.Flavor.ID, + Name: instanceRow.Flavor.Name, + CreatedAt: instanceRow.Flavor.CreatedAt.UTC(), + UpdatedAt: instanceRow.Flavor.UpdatedAt.UTC(), } flavors = append(flavors, f) - if f.ID == instanceRow.FlavorID { + if f.ID == instanceRow.FlavorVersion.FlavorID { i.Flavor = f } } diff --git a/controlplane/postgres/query.sql b/controlplane/postgres/query.sql index 387062a6..981b7304 100644 --- a/controlplane/postgres/query.sql +++ b/controlplane/postgres/query.sql @@ -222,7 +222,14 @@ WITH paged_instances AS ( ORDER BY id LIMIT sqlc.arg('limit') ) -SELECT i.*, v.*, c.*, f.*, n.*, u.* FROM instances i +SELECT + sqlc.embed(v), + sqlc.embed(c), + sqlc.embed(f), + sqlc.embed(n), + sqlc.embed(u), + sqlc.embed(i) +FROM instances i JOIN paged_instances pi ON pi.id = i.id JOIN flavor_versions v ON i.flavor_version_id = v.id JOIN chunks c ON i.chunk_id = c.id diff --git a/controlplane/postgres/query/query.sql.go b/controlplane/postgres/query/query.sql.go index 7d3695d3..4964613d 100644 --- a/controlplane/postgres/query/query.sql.go +++ b/controlplane/postgres/query/query.sql.go @@ -1388,7 +1388,14 @@ WITH paged_instances AS ( ORDER BY id LIMIT $2 ) -SELECT i.id, i.chunk_id, i.flavor_version_id, i.node_id, i.port, i.state, i.created_at, i.updated_at, i.owner_id, i.ordered_by, v.id, v.flavor_id, v.hash, v.change_hash, v.build_status, v.version, v.files_uploaded, v.prev_version_id, v.created_at, v.presigned_url_expiry_date, v.presigned_url, v.minecraft_version, c.id, c.name, c.description, c.tags, c.created_at, c.updated_at, c.owner_id, c.thumbnail_hash, c.thumbnail_updated_at, c.deleted_at, f.id, f.chunk_id, f.name, f.created_at, f.updated_at, f.deleted_at, n.id, n.name, n.address, n.checkpoint_api_endpoint, n.created_at, n.slots, u.id, u.nickname, u.email, u.created_at, u.updated_at FROM instances i +SELECT + v.id, v.flavor_id, v.hash, v.change_hash, v.build_status, v.version, v.files_uploaded, v.prev_version_id, v.created_at, v.presigned_url_expiry_date, v.presigned_url, v.minecraft_version, + c.id, c.name, c.description, c.tags, c.created_at, c.updated_at, c.owner_id, c.thumbnail_hash, c.thumbnail_updated_at, c.deleted_at, + f.id, f.chunk_id, f.name, f.created_at, f.updated_at, f.deleted_at, + n.id, n.name, n.address, n.checkpoint_api_endpoint, n.created_at, n.slots, + u.id, u.nickname, u.email, u.created_at, u.updated_at, + i.id, i.chunk_id, i.flavor_version_id, i.node_id, i.port, i.state, i.created_at, i.updated_at, i.owner_id, i.ordered_by +FROM instances i JOIN paged_instances pi ON pi.id = i.id JOIN flavor_versions v ON i.flavor_version_id = v.id JOIN chunks c ON i.chunk_id = c.id @@ -1404,55 +1411,12 @@ type ListInstancesWithPaginationParams struct { } type ListInstancesWithPaginationRow struct { - ID string - ChunkID string - FlavorVersionID string - NodeID string - Port *int32 - State InstanceState - CreatedAt time.Time - UpdatedAt time.Time - OwnerID string - OrderedBy string - ID_2 string - FlavorID string - Hash string - ChangeHash string - BuildStatus BuildStatus - Version string - FilesUploaded bool - PrevVersionID *string - CreatedAt_2 time.Time - PresignedUrlExpiryDate pgtype.Timestamptz - PresignedUrl pgtype.Text - MinecraftVersion string - ID_3 string - Name string - Description string - Tags []string - CreatedAt_3 time.Time - UpdatedAt_2 time.Time - OwnerID_2 string - ThumbnailHash pgtype.Text - ThumbnailUpdatedAt time.Time - DeletedAt pgtype.Timestamptz - ID_4 string - ChunkID_2 string - Name_2 string - CreatedAt_4 time.Time - UpdatedAt_3 time.Time - DeletedAt_2 pgtype.Timestamptz - ID_5 string - Name_3 string - Address netip.Addr - CheckpointApiEndpoint string - CreatedAt_5 time.Time - Slots int32 - ID_6 string - Nickname string - Email string - CreatedAt_6 time.Time - UpdatedAt_4 time.Time + FlavorVersion FlavorVersion + Chunk Chunk + Flavor Flavor + Node Node + User User + Instance Instance } func (q *Queries) ListInstancesWithPagination(ctx context.Context, arg ListInstancesWithPaginationParams) ([]ListInstancesWithPaginationRow, error) { @@ -1465,55 +1429,55 @@ func (q *Queries) ListInstancesWithPagination(ctx context.Context, arg ListInsta for rows.Next() { var i ListInstancesWithPaginationRow if err := rows.Scan( - &i.ID, - &i.ChunkID, - &i.FlavorVersionID, - &i.NodeID, - &i.Port, - &i.State, - &i.CreatedAt, - &i.UpdatedAt, - &i.OwnerID, - &i.OrderedBy, - &i.ID_2, - &i.FlavorID, - &i.Hash, - &i.ChangeHash, - &i.BuildStatus, - &i.Version, - &i.FilesUploaded, - &i.PrevVersionID, - &i.CreatedAt_2, - &i.PresignedUrlExpiryDate, - &i.PresignedUrl, - &i.MinecraftVersion, - &i.ID_3, - &i.Name, - &i.Description, - &i.Tags, - &i.CreatedAt_3, - &i.UpdatedAt_2, - &i.OwnerID_2, - &i.ThumbnailHash, - &i.ThumbnailUpdatedAt, - &i.DeletedAt, - &i.ID_4, - &i.ChunkID_2, - &i.Name_2, - &i.CreatedAt_4, - &i.UpdatedAt_3, - &i.DeletedAt_2, - &i.ID_5, - &i.Name_3, - &i.Address, - &i.CheckpointApiEndpoint, - &i.CreatedAt_5, - &i.Slots, - &i.ID_6, - &i.Nickname, - &i.Email, - &i.CreatedAt_6, - &i.UpdatedAt_4, + &i.FlavorVersion.ID, + &i.FlavorVersion.FlavorID, + &i.FlavorVersion.Hash, + &i.FlavorVersion.ChangeHash, + &i.FlavorVersion.BuildStatus, + &i.FlavorVersion.Version, + &i.FlavorVersion.FilesUploaded, + &i.FlavorVersion.PrevVersionID, + &i.FlavorVersion.CreatedAt, + &i.FlavorVersion.PresignedUrlExpiryDate, + &i.FlavorVersion.PresignedUrl, + &i.FlavorVersion.MinecraftVersion, + &i.Chunk.ID, + &i.Chunk.Name, + &i.Chunk.Description, + &i.Chunk.Tags, + &i.Chunk.CreatedAt, + &i.Chunk.UpdatedAt, + &i.Chunk.OwnerID, + &i.Chunk.ThumbnailHash, + &i.Chunk.ThumbnailUpdatedAt, + &i.Chunk.DeletedAt, + &i.Flavor.ID, + &i.Flavor.ChunkID, + &i.Flavor.Name, + &i.Flavor.CreatedAt, + &i.Flavor.UpdatedAt, + &i.Flavor.DeletedAt, + &i.Node.ID, + &i.Node.Name, + &i.Node.Address, + &i.Node.CheckpointApiEndpoint, + &i.Node.CreatedAt, + &i.Node.Slots, + &i.User.ID, + &i.User.Nickname, + &i.User.Email, + &i.User.CreatedAt, + &i.User.UpdatedAt, + &i.Instance.ID, + &i.Instance.ChunkID, + &i.Instance.FlavorVersionID, + &i.Instance.NodeID, + &i.Instance.Port, + &i.Instance.State, + &i.Instance.CreatedAt, + &i.Instance.UpdatedAt, + &i.Instance.OwnerID, + &i.Instance.OrderedBy, ); err != nil { return nil, err } diff --git a/test/functional/database/instance_repository_test.go b/test/functional/database/instance_repository_test.go index cc0b6236..a8445cf3 100644 --- a/test/functional/database/instance_repository_test.go +++ b/test/functional/database/instance_repository_test.go @@ -122,7 +122,6 @@ func TestDBListInstances(t *testing.T) { var ( ctx = context.Background() pg = fixture.NewPostgres() - c = fixture.Chunk() ) pg.Run(t, ctx) @@ -132,37 +131,46 @@ func TestDBListInstances(t *testing.T) { // make sure we only have one flavor, the fixture has 2 configured by default // but for this test we only we need one. - c.Flavors = []resource.Flavor{c.Flavors[0]} - pg.CreateChunk(t, &c, fixture.CreateOptionsAll) + //c.Flavors = []resource.Flavor{c.Flavors[0]} + //pg.CreateChunk(t, &c, fixture.CreateOptionsAll) expected := []resource.Instance{ fixture.Instance(func(i *resource.Instance) { + c := fixture.Chunk(func(tmpC *resource.Chunk) { + tmpC.ID = test.NewUUIDv7(t) + }) i.ID = test.NewUUIDv7(t) i.Chunk = c i.FlavorVersion = c.Flavors[0].Versions[0] + i.Flavor = c.Flavors[0] i.Port = nil // port will not be saved when creating i.FlavorVersion.FileHashes = nil // will not be returned atm i.Chunk.Owner = resource.User{} // will not be returned atm i.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm i.Flavor.Versions = nil // will not be returned atm i.Owner = c.Owner + i.Owner.Email = "" // will not be returned atm }), fixture.Instance(func(i *resource.Instance) { - i.ID = test.NewUUIDv7(t) + c := fixture.Chunk(func(tmpC *resource.Chunk) { + tmpC.ID = test.NewUUIDv7(t) + }) i.Chunk = c + i.ID = test.NewUUIDv7(t) i.FlavorVersion = c.Flavors[0].Versions[0] + i.Flavor = c.Flavors[0] i.Port = nil // port will not be saved when creating i.FlavorVersion.FileHashes = nil // will not be returned atm i.Chunk.Owner = resource.User{} // will not be returned atm i.Chunk.Thumbnail = resource.Thumbnail{} // will not be returned atm i.Flavor.Versions = nil // will not be returned atm i.Owner = c.Owner + i.Owner.Email = "" // will not be returned atm }), } - for _, i := range expected { - _, err := pg.DB.CreateInstance(ctx, i, fixture.Node().ID) - require.NoError(t, err) + for idx := range expected { + pg.CreateInstance(t, fixture.Node().ID, &expected[idx]) } sort.Slice(expected, func(i, j int) bool { From a63fcea1517a4bd6becb567ef25499ceee468875 Mon Sep 17 00:00:00 2001 From: yannic rieger Date: Thu, 14 May 2026 20:04:39 +0200 Subject: [PATCH 11/11] fix functests --- test/functional/controlplane/instance_api_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/controlplane/instance_api_test.go b/test/functional/controlplane/instance_api_test.go index 6134db72..f9b266ec 100644 --- a/test/functional/controlplane/instance_api_test.go +++ b/test/functional/controlplane/instance_api_test.go @@ -242,6 +242,7 @@ func TestRunFlavorVersion(t *testing.T) { UpdatedAt: timestamppb.New(c.UpdatedAt), }, Flavor: &chunkv1alpha1.Flavor{ + Id: f.ID, Name: f.Name, CreatedAt: timestamppb.New(f.CreatedAt), UpdatedAt: timestamppb.New(f.UpdatedAt), @@ -488,6 +489,7 @@ func TestReceiveInstanceStatusReports(t *testing.T) { var expected []*instancev1alpha1.Instance if !reflect.DeepEqual(tt.expected, resource.Instance{}) { tt.expected.Owner = ins.Owner + tt.expected.Flavor = ins.Flavor expected = []*instancev1alpha1.Instance{ codec.InstanceToTransport(tt.expected), }