Skip to content

Commit a114a7d

Browse files
Fix for unique name in OS Resource (#148)
Co-authored-by: Daniele Moro <9449199+daniele-moro@users.noreply.github.com> Co-authored-by: Daniele Moro <daniele.moro@intel.com>
1 parent 8a62ff9 commit a114a7d

14 files changed

Lines changed: 188 additions & 204 deletions

inventory/api/os/v1/os.proto

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ message OperatingSystemResource {
3939
option (ent.schema) = {gen: true};
4040
option (infrainv.schemaExtension) = {
4141
indexes: [
42+
{
43+
unique: true
44+
fields: [
45+
"name",
46+
"tenant_id"
47+
]
48+
},
4249
{
4350
unique: false
4451
fields: ["tenant_id"]
@@ -55,7 +62,10 @@ message OperatingSystemResource {
5562
(buf.validate.field).ignore = IGNORE_IF_UNPOPULATED
5663
]; // Resource ID of this OperatingSystemResource
5764

58-
string name = 2 [(ent.field) = {optional: true}]; // user-provided, human-readable name of OS
65+
string name = 2 [(ent.field) = {
66+
optional: true
67+
immutable: true
68+
}]; // user-provided, human-readable name of OS
5969
string architecture = 3 [(ent.field) = {optional: true}]; // CPU architecture supported
6070
string kernel_command = 4 [(ent.field) = {optional: true}]; // Kernel Command Line Options. Deprecated in EMF-v3.1, use OSUpdatePolicy.
6171

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- First ensure that we won't have any duplicate names for the same tenant.
2+
UPDATE "operating_system_resources"
3+
SET "name" = "name" || '-' || substr(md5(random()::text), 1, 5)
4+
WHERE ("name", "tenant_id") IN (
5+
SELECT "name", "tenant_id"
6+
FROM "operating_system_resources"
7+
GROUP BY "name", "tenant_id"
8+
HAVING COUNT(*) > 1
9+
);
10+
-- atlas:nolint MF101 the above data migration ensure that there won't be any duplicated.
11+
-- Create index "operatingsystemresource_name_tenant_id" to table: "operating_system_resources"
12+
CREATE UNIQUE INDEX "operatingsystemresource_name_tenant_id" ON "operating_system_resources" ("name", "tenant_id");

inventory/internal/ent/migrate/migrations/atlas.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
h1:7nG5HeBq3h/fzIFcnOkKvitj6V9Ca3NcSMTgoTVurss=
1+
h1:W4uB08mRdcstBe1WlAGlwUxrsFB3xvDR+YCw69FpjIg=
22
20230600000000_empty.sql h1:WTkYlwWwrdJjax+pXqrJYBNu1BIdqqnF9WoasjlGLUk=
33
20250324165719_all.sql h1:YEGDRbDPwxh5fBkoaGAwXpPu3nDCsCDdrvTt2EzBekk=
44
20250520125803_add_osprof_desc.sql h1:RQBqrgNfdTJlElMRdsizeMIRLsfw2Dq1LzzdiIV/JmE=
@@ -8,3 +8,4 @@ h1:7nG5HeBq3h/fzIFcnOkKvitj6V9Ca3NcSMTgoTVurss=
88
20250605155657_add_osupdatepolicy.sql h1:Q1CJe+b8PV6k7icmIDaBMbfVn7rZLwhuZTeeFmSegCU=
99
20250606153212_instance_update.sql h1:xmZLkFyu8Kaumkj9W10czTP+54Fb3sqF7RB90O7dtzE=
1010
20250610144827_add_customconfig.sql h1:AEZjZR5G0WSxeuyVDuc7LzIYHDnSX7ALaMGaQIRZYeo=
11+
20250611162552_modify_OSResource_name_tenantId_uniqueness.sql h1:EbpWIWxka0/ozWlnfWiEKvpM7o88+uyYOxGYq/Uwhf0=

inventory/internal/ent/migrate/schema.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inventory/internal/ent/operatingsystemresource_update.go

Lines changed: 0 additions & 46 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inventory/internal/ent/schema/operating_system_resource.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type OperatingSystemResource struct {
1414
}
1515

1616
func (OperatingSystemResource) Fields() []ent.Field {
17-
return []ent.Field{field.String("resource_id").Unique(), field.String("name").Optional(), field.String("architecture").Optional(), field.String("kernel_command").Optional(), field.String("update_sources").Optional(), field.String("image_url").Optional().Immutable(), field.String("image_id").Optional().Immutable(), field.String("sha256").Optional().Immutable(), field.String("profile_name").Optional().Immutable(), field.String("profile_version").Optional().Immutable(), field.String("installed_packages").Optional(), field.Enum("security_feature").Optional().Immutable().Values("SECURITY_FEATURE_UNSPECIFIED", "SECURITY_FEATURE_NONE", "SECURITY_FEATURE_SECURE_BOOT_AND_FULL_DISK_ENCRYPTION"), field.Enum("os_type").Optional().Immutable().Values("OS_TYPE_UNSPECIFIED", "OS_TYPE_MUTABLE", "OS_TYPE_IMMUTABLE"), field.Enum("os_provider").Immutable().Values("OS_PROVIDER_KIND_UNSPECIFIED", "OS_PROVIDER_KIND_INFRA", "OS_PROVIDER_KIND_LENOVO"), field.String("platform_bundle").Optional().Immutable(), field.String("description").Optional().Immutable(), field.String("metadata").Optional(), field.String("existing_cves_url").Optional().Immutable(), field.String("existing_cves").Optional(), field.String("fixed_cves_url").Optional().Immutable(), field.String("fixed_cves").Optional(), field.String("tenant_id").Immutable(), field.String("created_at").Immutable().SchemaType(map[string]string{"postgres": "TIMESTAMP"}), field.String("updated_at").SchemaType(map[string]string{"postgres": "TIMESTAMP"})}
17+
return []ent.Field{field.String("resource_id").Unique(), field.String("name").Optional().Immutable(), field.String("architecture").Optional(), field.String("kernel_command").Optional(), field.String("update_sources").Optional(), field.String("image_url").Optional().Immutable(), field.String("image_id").Optional().Immutable(), field.String("sha256").Optional().Immutable(), field.String("profile_name").Optional().Immutable(), field.String("profile_version").Optional().Immutable(), field.String("installed_packages").Optional(), field.Enum("security_feature").Optional().Immutable().Values("SECURITY_FEATURE_UNSPECIFIED", "SECURITY_FEATURE_NONE", "SECURITY_FEATURE_SECURE_BOOT_AND_FULL_DISK_ENCRYPTION"), field.Enum("os_type").Optional().Immutable().Values("OS_TYPE_UNSPECIFIED", "OS_TYPE_MUTABLE", "OS_TYPE_IMMUTABLE"), field.Enum("os_provider").Immutable().Values("OS_PROVIDER_KIND_UNSPECIFIED", "OS_PROVIDER_KIND_INFRA", "OS_PROVIDER_KIND_LENOVO"), field.String("platform_bundle").Optional().Immutable(), field.String("description").Optional().Immutable(), field.String("metadata").Optional(), field.String("existing_cves_url").Optional().Immutable(), field.String("existing_cves").Optional(), field.String("fixed_cves_url").Optional().Immutable(), field.String("fixed_cves").Optional(), field.String("tenant_id").Immutable(), field.String("created_at").Immutable().SchemaType(map[string]string{"postgres": "TIMESTAMP"}), field.String("updated_at").SchemaType(map[string]string{"postgres": "TIMESTAMP"})}
1818
}
1919
func (OperatingSystemResource) Edges() []ent.Edge {
2020
return nil
@@ -23,5 +23,5 @@ func (OperatingSystemResource) Annotations() []schema.Annotation {
2323
return nil
2424
}
2525
func (OperatingSystemResource) Indexes() []ent.Index {
26-
return []ent.Index{index.Fields("tenant_id")}
26+
return []ent.Index{index.Fields("name", "tenant_id").Unique(), index.Fields("tenant_id")}
2727
}

inventory/internal/store/instance_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,8 +1417,7 @@ func Test_NestedFilterInstances(t *testing.T) {
14171417
instanceresource.EdgeDesiredOs, operatingsystemresource.FieldName, os1.GetName()),
14181418
},
14191419
resources: []*computev1.InstanceResource{
1420-
instance1, instance2, instance3, instance4,
1421-
instanceWithProvider, instanceWithLocalAccount,
1420+
instance1, instance2,
14221421
},
14231422
valid: true,
14241423
},

inventory/internal/store/os_test.go

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ func Test_Create_Get_Delete_Update_Os(t *testing.T) {
254254
},
255255
}
256256
fieldMask := &fieldmaskpb.FieldMask{
257-
Paths: []string{oss.FieldName, oss.FieldInstalledPackages},
257+
Paths: []string{oss.FieldUpdateSources, oss.FieldInstalledPackages},
258258
}
259259
upRes, err := inv_testing.TestClients[inv_testing.APIClient].Update(
260260
ctx,
@@ -289,19 +289,10 @@ func Test_Create_Get_Delete_Update_Os(t *testing.T) {
289289
}
290290

291291
func Test_FilterOss(t *testing.T) {
292-
dao := inv_testing.NewInvResourceDAOOrFail(t)
293-
tenantID := uuid.NewString()
294-
cupdatesourceResp1 := dao.CreateOsWithOpts(t, tenantID, true,
295-
inv_testing.Sha256(inv_testing.RandomSha256v1),
296-
inv_testing.ProfileName("Test OS profile name 1"),
297-
inv_testing.Metadata(`{"key1": "value1", "key2": "value2"}`),
298-
inv_testing.SecurityFeature(os_v1.SecurityFeature_SECURITY_FEATURE_SECURE_BOOT_AND_FULL_DISK_ENCRYPTION),
299-
inv_testing.OsType(os_v1.OsType_OS_TYPE_MUTABLE))
300-
cupdatesourceResp2 := dao.CreateOsWithOpts(t, tenantID, true,
301-
inv_testing.Sha256(inv_testing.RandomSha256v2),
302-
inv_testing.ProfileName("Test OS profile name 2"),
303-
inv_testing.SecurityFeature(os_v1.SecurityFeature_SECURITY_FEATURE_NONE),
304-
inv_testing.OsType(os_v1.OsType_OS_TYPE_MUTABLE))
292+
cupdatesourceResp1 := inv_testing.CreateOsWithArgs(t, inv_testing.RandomSha256v1, "Test OS 1", "Test OS profile name 1",
293+
os_v1.SecurityFeature_SECURITY_FEATURE_SECURE_BOOT_AND_FULL_DISK_ENCRYPTION, os_v1.OsType_OS_TYPE_MUTABLE)
294+
cupdatesourceResp2 := inv_testing.CreateOsWithArgs(t, inv_testing.RandomSha256v2, "Test OS 2", "Test OS profile name 2",
295+
os_v1.SecurityFeature_SECURITY_FEATURE_NONE, os_v1.OsType_OS_TYPE_MUTABLE)
305296

306297
testcases := map[string]struct {
307298
in *inv_v1.ResourceFilter
@@ -521,28 +512,16 @@ func Test_UpdateOs(t *testing.T) {
521512
valid bool
522513
expErrorCode codes.Code
523514
}{
524-
"UpdateName": {
525-
in: &os_v1.OperatingSystemResource{
526-
Name: "Updated Name",
527-
Sha256: inv_testing.RandomSha256v3,
528-
ProfileName: "Test OS profile name 3",
529-
},
530-
resourceID: osResID,
531-
fieldMask: &fieldmaskpb.FieldMask{
532-
Paths: []string{oss.FieldName},
533-
},
534-
valid: true,
535-
},
536515
"UpdateMultipleFields": {
537516
in: &os_v1.OperatingSystemResource{
538-
Name: "Updated Name 2",
517+
Name: "Updated Name",
539518
KernelCommand: "linux",
540519
UpdateSources: []string{"update 2"},
541520
},
542521
resourceID: osResID,
543522
fieldMask: &fieldmaskpb.FieldMask{
544523
Paths: []string{
545-
oss.FieldKernelCommand, oss.FieldName, oss.FieldUpdateSources,
524+
oss.FieldKernelCommand, oss.FieldUpdateSources,
546525
},
547526
},
548527
valid: true,
@@ -560,6 +539,19 @@ func Test_UpdateOs(t *testing.T) {
560539
valid: false,
561540
expErrorCode: codes.InvalidArgument,
562541
},
542+
"UpdateImmutableNameFail": {
543+
in: &os_v1.OperatingSystemResource{
544+
Name: "Updated Name",
545+
},
546+
resourceID: osResID,
547+
fieldMask: &fieldmaskpb.FieldMask{
548+
Paths: []string{
549+
oss.FieldName,
550+
},
551+
},
552+
valid: false,
553+
expErrorCode: codes.InvalidArgument,
554+
},
563555
"UpdateImmutablePlatformBundleFail": {
564556
in: &os_v1.OperatingSystemResource{
565557
PlatformBundle: "some platform bundle",
@@ -690,7 +682,7 @@ func Test_ImmutableFieldsOnUpdate(t *testing.T) {
690682
osResID := inv_testing.GetResourceIDOrFail(t, cosResp)
691683
t.Cleanup(func() { inv_testing.DeleteResource(t, osResID) })
692684

693-
os1 := inv_testing.CreateOsWithArgs(t, inv_testing.RandomSha256v2, "Test OS profile name 2",
685+
os1 := inv_testing.CreateOsWithArgs(t, inv_testing.RandomSha256v2, "Test OS 2", "Test OS profile name 2",
694686
os_v1.SecurityFeature_SECURITY_FEATURE_UNSPECIFIED, os_v1.OsType_OS_TYPE_MUTABLE)
695687

696688
getresp, err := inv_testing.TestClients[inv_testing.APIClient].Get(ctx, os1.ResourceId)
@@ -972,14 +964,13 @@ func Test_Create_Get_Delete_Update_Os_Install_Packages(t *testing.T) {
972964
updateresreq := &inv_v1.Resource{
973965
Resource: &inv_v1.Resource_Os{
974966
Os: &os_v1.OperatingSystemResource{
975-
Name: "Updated Name",
976967
InstalledPackages: "intel-opencl-icd-updated\nintel-level-zero-gpu-updated\nlevel-zero-updated",
977968
},
978969
},
979970
}
980971

981972
fieldMask := &fieldmaskpb.FieldMask{
982-
Paths: []string{oss.FieldName, oss.FieldInstalledPackages},
973+
Paths: []string{oss.FieldInstalledPackages},
983974
}
984975

985976
upRes, err := inv_testing.TestClients[inv_testing.APIClient].Update(

inventory/internal/store/timestamp_suite_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ func (tts *TimestampTestSuite) TestUpdateTimestamps() {
112112
// Other special cases are handled via the updateResource func.
113113
case "HostgpuResource", "HostnicResource", "HoststorageResource", "HostusbResource":
114114
fieldName = "device_name"
115+
case "OperatingSystemResource":
116+
fieldName = "kernel_command"
115117
default:
116118
fieldName = "name"
117119
}

0 commit comments

Comments
 (0)