diff --git a/cmd/ateapi/internal/apivalidation/actor.go b/cmd/ateapi/internal/apivalidation/actor.go index 77c0d27a5b..2fdaa78cb2 100644 --- a/cmd/ateapi/internal/apivalidation/actor.go +++ b/cmd/ateapi/internal/apivalidation/actor.go @@ -134,9 +134,9 @@ func ValidateCustom_WorkerAssignment_WorkerPodIps(_ context.Context, _ operation return validateDualStackIPs(fldPath, value) } -// ValidateCustom_ExternalVolume_VolumeType checks that a volume type string is well-formed. +// ValidateCustom_ActorVolumeStatus_VolumeType checks that a volume type string is well-formed. // It allows an optional "substrate.io/" prefix, followed by a valid DNS-1123 subdomain. -func ValidateCustom_ExternalVolume_VolumeType(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { +func ValidateCustom_ActorVolumeStatus_VolumeType(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { if value == nil || *value == "" { return nil } @@ -148,9 +148,9 @@ func ValidateCustom_ExternalVolume_VolumeType(_ context.Context, _ operation.Ope return errs } -// ValidateCustom_ExternalVolume_StorageVolumeId checks that an external volume's storage ID does not +// ValidateCustom_ActorVolumeStatus_StorageVolumeId checks that an external volume's storage ID does not // contain control characters (U+0000-U+0008, U+000B, U+000C, U+000E-U+001F, U+007F-U+009F). -func ValidateCustom_ExternalVolume_StorageVolumeId(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { +func ValidateCustom_ActorVolumeStatus_StorageVolumeId(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { if value == nil || *value == "" { return nil } diff --git a/cmd/ateapi/internal/apivalidation/actor_test.go b/cmd/ateapi/internal/apivalidation/actor_test.go index 7b2a2cafbd..b8f6cfee5c 100644 --- a/cmd/ateapi/internal/apivalidation/actor_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_test.go @@ -643,9 +643,9 @@ func TestValidateActorUpdate(t *testing.T) { "too many external_volumes", validInput(), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - vols := make([]*ateapipb.ExternalVolume, 33) + vols := make([]*ateapipb.ActorVolumeStatus, 33) for i := range vols { - vols[i] = &ateapipb.ExternalVolume{Name: fmt.Sprintf("vol-%d", i), VolumeType: "substrate.io/mock"} + vols[i] = &ateapipb.ActorVolumeStatus{Name: fmt.Sprintf("vol-%d", i), VolumeType: "substrate.io/mock"} } s.ExternalVolumes = vols })), @@ -656,14 +656,14 @@ func TestValidateActorUpdate(t *testing.T) { "adding a volume on update is allowed", validInput(withStatus()), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{{Name: "vol-a", VolumeType: "substrate.io/mock"}} + s.ExternalVolumes = []*ateapipb.ActorVolumeStatus{{Name: "vol-a", VolumeType: "substrate.io/mock"}} })), nil, }, { "duplicate external_volumes name", validInput(withStatus()), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{ + s.ExternalVolumes = []*ateapipb.ActorVolumeStatus{ {Name: "vol-a", VolumeType: "substrate.io/mock"}, {Name: "vol-a", VolumeType: "substrate.io/mock"}, } @@ -672,14 +672,14 @@ func TestValidateActorUpdate(t *testing.T) { }, { "provisioning transition on an existing volume is valid", validInput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{{Name: "vol-a", VolumeType: "substrate.io/mock", Status: ateapipb.ExternalVolume_STATUS_PENDING}} + s.ExternalVolumes = []*ateapipb.ActorVolumeStatus{{Name: "vol-a", VolumeType: "substrate.io/mock", Status: ateapipb.ActorVolumeStatus_STATUS_PENDING}} })), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{{ + s.ExternalVolumes = []*ateapipb.ActorVolumeStatus{{ Name: "vol-a", VolumeType: "substrate.io/mock", StorageVolumeId: "csi-426d29b7", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, VolumeContext: map[string]string{"attachment": "iqn.2026-08.io.ate:vol-a"}, }} })), diff --git a/cmd/ateapi/internal/apivalidation/validation_test.go b/cmd/ateapi/internal/apivalidation/validation_test.go index f5ed650b13..d272b3a7c0 100644 --- a/cmd/ateapi/internal/apivalidation/validation_test.go +++ b/cmd/ateapi/internal/apivalidation/validation_test.go @@ -911,12 +911,12 @@ func TestValidateTrustBundleDataSource(t *testing.T) { } } -func validExternalVolume(mutate ...func(*ateapipb.ExternalVolume)) *ateapipb.ExternalVolume { - v := &ateapipb.ExternalVolume{ +func validExternalVolume(mutate ...func(*ateapipb.ActorVolumeStatus)) *ateapipb.ActorVolumeStatus { + v := &ateapipb.ActorVolumeStatus{ Name: "my-vol", StorageVolumeId: "valid-storage-id", VolumeType: "mock", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, } for _, m := range mutate { m(v) @@ -929,96 +929,96 @@ func TestValidateExternalVolume(t *testing.T) { tests := []struct { name string - obj *ateapipb.ExternalVolume + obj *ateapipb.ActorVolumeStatus want field.ErrorList }{{ name: "valid external volume", obj: valid(), }, { name: "missing volume name", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.Name = "" }), want: field.ErrorList{field.Required(field.NewPath("name"), "")}, }, { name: "invalid volume name", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "NOT A VOLUME" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.Name = "NOT A VOLUME" }), want: field.ErrorList{field.Invalid(field.NewPath("name"), nil, "").WithOrigin("format=k8s-short-name")}, }, { name: "valid external volume with empty storage volume id", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "" }), }, { name: "invalid storage volume id with null U+0000", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol\x00id" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol\x00id" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "")}, }, { name: "invalid storage volume id with unit separator U+001F", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol\x1fid" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol\x1fid" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "")}, }, { name: "invalid storage volume id with DEL U+007F", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol\x7fid" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol\x7fid" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "")}, }, { name: "invalid storage volume id with C1 control U+0080", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol\u0080id" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol\u0080id" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "")}, }, { name: "invalid storage volume id with C1 control U+009F", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol\u009fid" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol\u009fid" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "")}, }, { name: "storage volume id too long", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = strings.Repeat("x", 257) }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = strings.Repeat("x", 257) }), want: field.ErrorList{field.TooLong(field.NewPath("storage_volume_id"), nil, 256).WithOrigin("maxLength")}, }, { name: "valid csi volume type", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "pd.csi.storage.gke.io" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "pd.csi.storage.gke.io" }), }, { name: "missing volume type", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "" }), want: field.ErrorList{field.Required(field.NewPath("volume_type"), "")}, }, { name: "invalid volume type with uppercase", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "MockPlugin" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "MockPlugin" }), want: field.ErrorList{field.Invalid(field.NewPath("volume_type"), nil, "")}, }, { name: "valid volume type with 253 characters", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = strings.Repeat("a", 253) }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = strings.Repeat("a", 253) }), }, { name: "invalid volume type exceeding 253 characters", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = strings.Repeat("a", 254) }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = strings.Repeat("a", 254) }), want: field.ErrorList{ field.Invalid(field.NewPath("volume_type"), nil, ""), field.TooLong(field.NewPath("volume_type"), nil, 253).WithOrigin("maxLength"), }, }, { name: "valid volume with substrate.io prefixed volume type", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "substrate.io/mock" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "substrate.io/mock" }), }, { name: "invalid volume type with empty plugin after substrate.io prefix", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "substrate.io/" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "substrate.io/" }), want: field.ErrorList{field.Invalid(field.NewPath("volume_type"), nil, "")}, }, { name: "invalid volume type with invalid plugin name after substrate.io prefix", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "substrate.io/Mock_Plugin" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "substrate.io/Mock_Plugin" }), want: field.ErrorList{field.Invalid(field.NewPath("volume_type"), nil, "")}, }, { name: "invalid volume type with non-substrate prefix", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "other.io/mock" }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "other.io/mock" }), want: field.ErrorList{field.Invalid(field.NewPath("volume_type"), nil, "")}, }, { name: "negative status", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Status = ateapipb.ExternalVolume_Status(-1) }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.Status = ateapipb.ActorVolumeStatus_Status(-1) }), want: field.ErrorList{field.Invalid(field.NewPath("status"), nil, "").WithOrigin("minimum")}, }, { name: "status outside the enum", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Status = ateapipb.ExternalVolume_Status(4) }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.Status = ateapipb.ActorVolumeStatus_Status(4) }), want: field.ErrorList{field.Invalid(field.NewPath("status"), nil, "").WithOrigin("maximum")}, }, { name: "storage volume id at the bound", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = strings.Repeat("x", 256) }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = strings.Repeat("x", 256) }), }, { name: "too many volume_context entries", - obj: valid(func(v *ateapipb.ExternalVolume) { + obj: valid(func(v *ateapipb.ActorVolumeStatus) { ctxMap := make(map[string]string, 33) for i := 0; i < 33; i++ { ctxMap[fmt.Sprintf("key-%d", i)] = "v" @@ -1028,11 +1028,13 @@ func TestValidateExternalVolume(t *testing.T) { want: field.ErrorList{field.TooMany(field.NewPath("volume_context"), 33, 32).WithOrigin("maxProperties")}, }, { name: "volume_context key too long", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeContext = map[string]string{strings.Repeat("k", 129): "v"} }), + obj: valid(func(v *ateapipb.ActorVolumeStatus) { + v.VolumeContext = map[string]string{strings.Repeat("k", 129): "v"} + }), want: field.ErrorList{field.TooLong(field.NewPath("volume_context"), nil, 128).WithOrigin("maxLength")}, }, { name: "volume_context value too long", - obj: valid(func(v *ateapipb.ExternalVolume) { + obj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeContext = map[string]string{"attachment": strings.Repeat("v", 257)} }), want: field.ErrorList{field.TooLong(field.NewPath("volume_context").Key("attachment"), nil, 256).WithOrigin("maxLength")}, @@ -1040,18 +1042,18 @@ func TestValidateExternalVolume(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { op := operation.Operation{Type: operation.Create} - assertValidateErr(t, Validate_ExternalVolume(context.Background(), op, nil, tt.obj, nil), tt.want) + assertValidateErr(t, Validate_ActorVolumeStatus(context.Background(), op, nil, tt.obj, nil), tt.want) }) } } -func TestValidateExternalVolume_Update(t *testing.T) { +func TestValidateActorVolumeStatus_Update(t *testing.T) { valid := validExternalVolume tests := []struct { name string - oldObj *ateapipb.ExternalVolume - newObj *ateapipb.ExternalVolume + oldObj *ateapipb.ActorVolumeStatus + newObj *ateapipb.ActorVolumeStatus want field.ErrorList }{{ name: "unchanged volume is valid", @@ -1059,43 +1061,43 @@ func TestValidateExternalVolume_Update(t *testing.T) { newObj: valid(), }, { name: "name changed is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "vol1" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "vol2" }), + oldObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.Name = "vol1" }), + newObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.Name = "vol2" }), want: field.ErrorList{field.Invalid(field.NewPath("name"), nil, "").WithOrigin("update")}, }, { name: "storage_volume_id transition from empty to non-empty is valid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-1" }), + oldObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "" }), + newObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol-id-1" }), }, { name: "storage_volume_id changed once set is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-1" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-2" }), + oldObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol-id-1" }), + newObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol-id-2" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "").WithOrigin("update")}, }, { name: "storage_volume_id unset once set is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-1" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "" }), + oldObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "vol-id-1" }), + newObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.StorageVolumeId = "" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "").WithOrigin("update")}, }, { name: "volume_type changed is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "mock" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "pd.csi.storage.gke.io" }), + oldObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "mock" }), + newObj: valid(func(v *ateapipb.ActorVolumeStatus) { v.VolumeType = "pd.csi.storage.gke.io" }), want: field.ErrorList{field.Invalid(field.NewPath("volume_type"), nil, "").WithOrigin("update")}, }, { name: "status and volume_context changed is valid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { - v.Status = ateapipb.ExternalVolume_STATUS_PENDING + oldObj: valid(func(v *ateapipb.ActorVolumeStatus) { + v.Status = ateapipb.ActorVolumeStatus_STATUS_PENDING v.VolumeContext = nil }), - newObj: valid(func(v *ateapipb.ExternalVolume) { - v.Status = ateapipb.ExternalVolume_STATUS_CREATED + newObj: valid(func(v *ateapipb.ActorVolumeStatus) { + v.Status = ateapipb.ActorVolumeStatus_STATUS_CREATED v.VolumeContext = map[string]string{"foo": "bar"} }), }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { op := operation.Operation{Type: operation.Update} - assertValidateErr(t, Validate_ExternalVolume(context.Background(), op, nil, tt.newObj, tt.oldObj), tt.want) + assertValidateErr(t, Validate_ActorVolumeStatus(context.Background(), op, nil, tt.newObj, tt.oldObj), tt.want) }) } } diff --git a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go index 69c505dd3c..ec7348a780 100644 --- a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go +++ b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go @@ -709,7 +709,7 @@ func Validate_ActorStatus( { // field ateapipb.ActorStatus.ExternalVolumes fn := func( fldPath *field.Path, - obj, oldObj []*ateapipb.ExternalVolume, + obj, oldObj []*ateapipb.ActorVolumeStatus, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -719,7 +719,7 @@ func Validate_ActorStatus( } // call field-attached validations earlyReturn := false - if e := validate.PtrSliceNoNils[ateapipb.ExternalVolume](ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + if e := validate.PtrSliceNoNils[ateapipb.ActorVolumeStatus](ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { errs = append(errs, e...) earlyReturn = true } @@ -735,18 +735,18 @@ func Validate_ActorStatus( } // lists with map semantics require unique keys if e := validate.PtrSliceUnique(ctx, op, fldPath, obj, oldObj, - func(a *ateapipb.ExternalVolume, b *ateapipb.ExternalVolume) bool { return a.Name == b.Name }); len(e) != 0 { + func(a *ateapipb.ActorVolumeStatus, b *ateapipb.ActorVolumeStatus) bool { return a.Name == b.Name }); len(e) != 0 { errs = append(errs, e...) } // iterate the list and call the type's validation function if e := validate.EachPtrSliceVal(ctx, op, fldPath, obj, oldObj, - func(a *ateapipb.ExternalVolume, b *ateapipb.ExternalVolume) bool { return a.Name == b.Name }, ateDeepEqual, Validate_ExternalVolume); len(e) != 0 { + func(a *ateapipb.ActorVolumeStatus, b *ateapipb.ActorVolumeStatus) bool { return a.Name == b.Name }, ateDeepEqual, Validate_ActorVolumeStatus); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ActorStatus) []*ateapipb.ExternalVolume { + func(oldObj *ateapipb.ActorStatus) []*ateapipb.ActorVolumeStatus { return oldObj.ExternalVolumes }) errs = append(errs, fn(fldPath.Child("external_volumes"), obj.ExternalVolumes, oldVal, oldObj != nil)...) @@ -1244,6 +1244,211 @@ func Validate_ActorTemplateStatus( return errs } +// Validate_ActorVolumeStatus validates an instance of ActorVolumeStatus according +// to declarative validation rules in the API schema. +func Validate_ActorVolumeStatus( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.ActorVolumeStatus) (errs field.ErrorList) { + + { // field ateapipb.ActorVolumeStatus.Name + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.ShortName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ActorVolumeStatus) *string { + return &oldObj.Name + }) + errs = append(errs, fn(fldPath.Child("name"), &obj.Name, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ActorVolumeStatus.StorageVolumeId + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // custom validation + if e := ValidateCustom_ActorVolumeStatus_StorageVolumeId(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 256); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ActorVolumeStatus) *string { + return &oldObj.StorageVolumeId + }) + errs = append(errs, fn(fldPath.Child("storage_volume_id"), &obj.StorageVolumeId, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ActorVolumeStatus.VolumeType + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // custom validation + if e := ValidateCustom_ActorVolumeStatus_VolumeType(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 253); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ActorVolumeStatus) *string { + return &oldObj.VolumeType + }) + errs = append(errs, fn(fldPath.Child("volume_type"), &obj.VolumeType, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ActorVolumeStatus.Status + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.ActorVolumeStatus_Status, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 3); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ActorVolumeStatus) *ateapipb.ActorVolumeStatus_Status { + return &oldObj.Status + }) + errs = append(errs, fn(fldPath.Child("status"), &obj.Status, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ActorVolumeStatus.VolumeContext + fn := func( + fldPath *field.Path, + obj, oldObj map[string]string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if ateDeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.MaxProperties(ctx, op, fldPath, obj, oldObj, 32).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalMap(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.EachMapKey(ctx, op, fldPath, obj, oldObj, + func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList { + return validate.MaxLength(ctx, op, fldPath, obj, oldObj, 128) + }); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.EachMapVal(ctx, op, fldPath, obj, oldObj, validate.DirectEqual, + func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList { + return validate.MaxLength(ctx, op, fldPath, obj, oldObj, 256) + }); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ActorVolumeStatus) map[string]string { + return oldObj.VolumeContext + }) + errs = append(errs, fn(fldPath.Child("volume_context"), obj.VolumeContext, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_Atespace validates an instance of Atespace according // to declarative validation rules in the API schema. func Validate_Atespace( @@ -3550,211 +3755,6 @@ func Validate_EnvVar( return errs } -// Validate_ExternalVolume validates an instance of ExternalVolume according -// to declarative validation rules in the API schema. -func Validate_ExternalVolume( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *ateapipb.ExternalVolume) (errs field.ErrorList) { - - { // field ateapipb.ExternalVolume.Name - fn := func( - fldPath *field.Path, - obj, oldObj *string, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, - func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - if e := validate.ShortName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *string { - return &oldObj.Name - }) - errs = append(errs, fn(fldPath.Child("name"), &obj.Name, oldVal, oldObj != nil)...) - } - - { // field ateapipb.ExternalVolume.StorageVolumeId - fn := func( - fldPath *field.Path, - obj, oldObj *string, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, - func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // custom validation - if e := ValidateCustom_ExternalVolume_StorageVolumeId(ctx, op, fldPath, obj, oldObj); len(e) != 0 { - errs = append(errs, e...) - } - if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 256); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *string { - return &oldObj.StorageVolumeId - }) - errs = append(errs, fn(fldPath.Child("storage_volume_id"), &obj.StorageVolumeId, oldVal, oldObj != nil)...) - } - - { // field ateapipb.ExternalVolume.VolumeType - fn := func( - fldPath *field.Path, - obj, oldObj *string, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, - func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // custom validation - if e := ValidateCustom_ExternalVolume_VolumeType(ctx, op, fldPath, obj, oldObj); len(e) != 0 { - errs = append(errs, e...) - } - if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 253); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *string { - return &oldObj.VolumeType - }) - errs = append(errs, fn(fldPath.Child("volume_type"), &obj.VolumeType, oldVal, oldObj != nil)...) - } - - { // field ateapipb.ExternalVolume.Status - fn := func( - fldPath *field.Path, - obj, oldObj *ateapipb.ExternalVolume_Status, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 3); len(e) != 0 { - errs = append(errs, e...) - } - if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *ateapipb.ExternalVolume_Status { - return &oldObj.Status - }) - errs = append(errs, fn(fldPath.Child("status"), &obj.Status, oldVal, oldObj != nil)...) - } - - { // field ateapipb.ExternalVolume.VolumeContext - fn := func( - fldPath *field.Path, - obj, oldObj map[string]string, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if ateDeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.MaxProperties(ctx, op, fldPath, obj, oldObj, 32).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if e := validate.OptionalMap(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - if e := validate.EachMapKey(ctx, op, fldPath, obj, oldObj, - func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList { - return validate.MaxLength(ctx, op, fldPath, obj, oldObj, 128) - }); len(e) != 0 { - errs = append(errs, e...) - } - if e := validate.EachMapVal(ctx, op, fldPath, obj, oldObj, validate.DirectEqual, - func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList { - return validate.MaxLength(ctx, op, fldPath, obj, oldObj, 256) - }); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) map[string]string { - return oldObj.VolumeContext - }) - errs = append(errs, fn(fldPath.Child("volume_context"), obj.VolumeContext, oldVal, oldObj != nil)...) - } - - return errs -} - // Validate_ExternalVolumeTemplate validates an instance of ExternalVolumeTemplate according // to declarative validation rules in the API schema. func Validate_ExternalVolumeTemplate( diff --git a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go index 25cb9e1f41..eccf0bbc5e 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go @@ -148,8 +148,8 @@ func TestCreateActor_WithExternalVolumes(t *testing.T) { if vol.GetName() != "ext-vol-1" { t.Errorf("volume name = %q, want %q", vol.GetName(), "ext-vol-1") } - if vol.GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { - t.Errorf("volume status = %v, want %v", vol.GetStatus(), ateapipb.ExternalVolume_STATUS_PENDING) + if vol.GetStatus() != ateapipb.ActorVolumeStatus_STATUS_PENDING { + t.Errorf("volume status = %v, want %v", vol.GetStatus(), ateapipb.ActorVolumeStatus_STATUS_PENDING) } if vol.GetStorageVolumeId() != "" { t.Errorf("expected empty storageVolumeId before resume, got %q", vol.GetStorageVolumeId()) @@ -165,8 +165,8 @@ func TestCreateActor_WithExternalVolumes(t *testing.T) { if len(getResp.GetStatus().GetExternalVolumes()) != 1 { t.Fatalf("expected 1 volume in GetActor response, got %d", len(getResp.GetStatus().GetExternalVolumes())) } - if getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { - t.Errorf("GetActor status = %v, want %v", getResp.GetStatus().GetExternalVolumes()[0].GetStatus(), ateapipb.ExternalVolume_STATUS_PENDING) + if getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ActorVolumeStatus_STATUS_PENDING { + t.Errorf("GetActor status = %v, want %v", getResp.GetStatus().GetExternalVolumes()[0].GetStatus(), ateapipb.ActorVolumeStatus_STATUS_PENDING) } } @@ -1372,9 +1372,9 @@ func TestDeleteActor_MultipleVolumeDeletionFailures(t *testing.T) { ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, Status: &ateapipb.ActorStatus{ State: ateapipb.ActorState_ACTOR_STATE_SUSPENDED, - ExternalVolumes: []*ateapipb.ExternalVolume{ - {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "substrate.io/mock"}, - {Name: "vol2", StorageVolumeId: "storage-vol-2", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "substrate.io/mock"}, + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ + {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, VolumeType: "substrate.io/mock"}, + {Name: "vol2", StorageVolumeId: "storage-vol-2", Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, VolumeType: "substrate.io/mock"}, }, }, } @@ -1421,7 +1421,7 @@ func (r *retryDeleteVolumePlugin) DeleteVolume(ctx context.Context, volumeID str // TestDeleteActor_VolumeDeletionFailure_RetrySuccess tests that when volume deletion fails // during DeleteActor, the actor transitions to ACTOR_STATE_DELETING and its volumes to -// ExternalVolume_STATUS_DELETING, and a subsequent retry of DeleteActor cleanly finalizes deletion. +// ActorVolumeStatus_STATUS_DELETING, and a subsequent retry of DeleteActor cleanly finalizes deletion. // // Workflow: // 1. Creates a suspended actor with a provisioned external volume. @@ -1448,8 +1448,8 @@ func TestDeleteActor_VolumeDeletionFailure_RetrySuccess(t *testing.T) { ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, Status: &ateapipb.ActorStatus{ State: ateapipb.ActorState_ACTOR_STATE_SUSPENDED, - ExternalVolumes: []*ateapipb.ExternalVolume{ - {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "substrate.io/mock"}, + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ + {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, VolumeType: "substrate.io/mock"}, }, }, } @@ -1465,7 +1465,7 @@ func TestDeleteActor_VolumeDeletionFailure_RetrySuccess(t *testing.T) { t.Fatalf("expected DeleteActor to fail, but got nil") } - // 3. Verify actor is persisted in ACTOR_STATE_DELETING with volume in ExternalVolume_STATUS_DELETING. + // 3. Verify actor is persisted in ACTOR_STATE_DELETING with volume in ActorVolumeStatus_STATUS_DELETING. getResp, err := tc.service.GetActor(context.Background(), &ateapipb.GetActorRequest{ Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "delete-retry-actor"}, }) @@ -1475,7 +1475,7 @@ func TestDeleteActor_VolumeDeletionFailure_RetrySuccess(t *testing.T) { if getResp.GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_DELETING { t.Errorf("actor state = %v, want ACTOR_STATE_DELETING", getResp.GetStatus().GetState()) } - if len(getResp.GetStatus().GetExternalVolumes()) != 1 || getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_DELETING { + if len(getResp.GetStatus().GetExternalVolumes()) != 1 || getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ActorVolumeStatus_STATUS_DELETING { t.Errorf("actor volume status = %v, want STATUS_DELETING", getResp.GetStatus().GetExternalVolumes()) } @@ -1608,7 +1608,7 @@ func TestActorLifecycle_WithExternalVolumes(t *testing.T) { if createResp.GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { t.Fatalf("expected initial state ACTOR_STATE_SUSPENDED, got %v", createResp.GetStatus().GetState()) } - if len(createResp.GetStatus().GetExternalVolumes()) != 1 || createResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { + if len(createResp.GetStatus().GetExternalVolumes()) != 1 || createResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ActorVolumeStatus_STATUS_PENDING { t.Fatalf("expected 1 pending volume after CreateActor, got %v", createResp.GetStatus().GetExternalVolumes()) } @@ -1622,7 +1622,7 @@ func TestActorLifecycle_WithExternalVolumes(t *testing.T) { if resumeResp.GetActor().GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_RUNNING { t.Fatalf("expected state ACTOR_STATE_RUNNING after resume, got %v", resumeResp.GetActor().GetStatus().GetState()) } - if len(resumeResp.GetActor().GetStatus().GetExternalVolumes()) != 1 || resumeResp.GetActor().GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED { + if len(resumeResp.GetActor().GetStatus().GetExternalVolumes()) != 1 || resumeResp.GetActor().GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ActorVolumeStatus_STATUS_CREATED { t.Fatalf("expected 1 created volume after ResumeActor, got %v", resumeResp.GetActor().GetStatus().GetExternalVolumes()) } if resumeResp.GetActor().GetStatus().GetExternalVolumes()[0].GetStorageVolumeId() == "" { @@ -1781,14 +1781,14 @@ func TestResumeActor_VolumeCreationFailure(t *testing.T) { if len(getResp.GetStatus().GetExternalVolumes()) != 2 { t.Fatalf("expected 2 volumes on actor, got %d", len(getResp.GetStatus().GetExternalVolumes())) } - volsByName := make(map[string]*ateapipb.ExternalVolume) + volsByName := make(map[string]*ateapipb.ActorVolumeStatus) for _, v := range getResp.GetStatus().GetExternalVolumes() { volsByName[v.GetName()] = v } - if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || v1.GetStorageVolumeId() == "" { + if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ActorVolumeStatus_STATUS_CREATED || v1.GetStorageVolumeId() == "" { t.Errorf("succ-vol1 unexpected state: %v", v1) } - if v2, ok := volsByName["fail-vol2"]; !ok || v2.GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { + if v2, ok := volsByName["fail-vol2"]; !ok || v2.GetStatus() != ateapipb.ActorVolumeStatus_STATUS_PENDING { t.Errorf("fail-vol2 unexpected state: %v", v2) } @@ -1915,14 +1915,14 @@ func TestResumeActor_VolumeCreationRetrySuccess(t *testing.T) { t.Errorf("actor state after first resume = %v, want %v", getResp.GetStatus().GetState(), ateapipb.ActorState_ACTOR_STATE_SUSPENDED) } - volsByName := make(map[string]*ateapipb.ExternalVolume) + volsByName := make(map[string]*ateapipb.ActorVolumeStatus) for _, v := range getResp.GetStatus().GetExternalVolumes() { volsByName[v.GetName()] = v } - if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || v1.GetStorageVolumeId() == "" { + if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ActorVolumeStatus_STATUS_CREATED || v1.GetStorageVolumeId() == "" { t.Errorf("succ-vol1 unexpected state after first resume: %v", v1) } - if v2, ok := volsByName["retry-vol2"]; !ok || v2.GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { + if v2, ok := volsByName["retry-vol2"]; !ok || v2.GetStatus() != ateapipb.ActorVolumeStatus_STATUS_PENDING { t.Errorf("retry-vol2 unexpected state after first resume: %v", v2) } @@ -1945,7 +1945,7 @@ func TestResumeActor_VolumeCreationRetrySuccess(t *testing.T) { t.Errorf("actor state after second resume = %v, want %v", getResp.GetStatus().GetState(), ateapipb.ActorState_ACTOR_STATE_RUNNING) } for _, v := range getResp.GetStatus().GetExternalVolumes() { - if v.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || v.GetStorageVolumeId() == "" { + if v.GetStatus() != ateapipb.ActorVolumeStatus_STATUS_CREATED || v.GetStorageVolumeId() == "" { t.Errorf("volume %s unexpected state after second resume: %v", v.GetName(), v) } } @@ -2070,7 +2070,7 @@ func TestResumeActor_VolumeAttachFailureAndRetry(t *testing.T) { t.Fatalf("expected 1 volume on actor, got %d", len(getResp.GetStatus().GetExternalVolumes())) } vol := getResp.GetStatus().GetExternalVolumes()[0] - if vol.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || vol.GetStorageVolumeId() == "" { + if vol.GetStatus() != ateapipb.ActorVolumeStatus_STATUS_CREATED || vol.GetStorageVolumeId() == "" { t.Errorf("vol1 unexpected state after failed attach: %v", vol) } diff --git a/cmd/ateapi/internal/controlapi/volumes.go b/cmd/ateapi/internal/controlapi/volumes.go index b2f8292599..2460b522b3 100644 --- a/cmd/ateapi/internal/controlapi/volumes.go +++ b/cmd/ateapi/internal/controlapi/volumes.go @@ -30,11 +30,11 @@ import ( ) // initialActorVolumes constructs initial volume objects in PENDING state before volume creation. -func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageClassLister, template *ateapipb.ActorTemplate) ([]*ateapipb.ExternalVolume, error) { +func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageClassLister, template *ateapipb.ActorTemplate) ([]*ateapipb.ActorVolumeStatus, error) { if template == nil { return nil, apierror.InvalidArgument("template is required") } - var volumes []*ateapipb.ExternalVolume + var volumes []*ateapipb.ActorVolumeStatus for _, vol := range template.GetVolumes() { if vol.GetExternalVolumeTemplate() != nil { scName := vol.GetExternalVolumeTemplate().GetStorageClassName() @@ -46,10 +46,10 @@ func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageC return nil, apierror.Internal("failed to get StorageClass %q: %v", scName, err) } - volumes = append(volumes, &ateapipb.ExternalVolume{ + volumes = append(volumes, &ateapipb.ActorVolumeStatus{ Name: vol.GetName(), VolumeType: sc.Provisioner, - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }) } } @@ -59,8 +59,8 @@ func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageC // createActorVolumes provisions external volumes specified in volumesToCreate using the provided volume plugin. // It returns the list of external volumes (with updated status and storage IDs), or an error if any creation fails. // Any volumes processed before or during a failure are returned alongside the error so they can be persisted on the actor. -func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLister storagev1listers.StorageClassLister, actorUID string, template *ateapipb.ActorTemplate, volumesToCreate []*ateapipb.ExternalVolume) (resultVolumes []*ateapipb.ExternalVolume, err error) { - resultVolumes = make([]*ateapipb.ExternalVolume, 0, len(volumesToCreate)) +func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLister storagev1listers.StorageClassLister, actorUID string, template *ateapipb.ActorTemplate, volumesToCreate []*ateapipb.ActorVolumeStatus) (resultVolumes []*ateapipb.ActorVolumeStatus, err error) { + resultVolumes = make([]*ateapipb.ActorVolumeStatus, 0, len(volumesToCreate)) var currentIdx int defer func() { @@ -87,12 +87,12 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi } switch vol.GetStatus() { - case ateapipb.ExternalVolume_STATUS_PENDING: + case ateapipb.ActorVolumeStatus_STATUS_PENDING: // proceed with volume creation - case ateapipb.ExternalVolume_STATUS_CREATED: + case ateapipb.ActorVolumeStatus_STATUS_CREATED: resultVolumes = append(resultVolumes, vol) continue - case ateapipb.ExternalVolume_STATUS_DELETING: + case ateapipb.ActorVolumeStatus_STATUS_DELETING: return resultVolumes, apierror.FailedPrecondition("cannot create volume %q in DELETING status", volName) default: return resultVolumes, apierror.Internal("unexpected status %s for volume %q", vol.GetStatus(), volName) @@ -127,11 +127,11 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi return resultVolumes, apierror.Internal("failed to create volume %q: %v", specVol.GetName(), volErr) } - resultVolumes = append(resultVolumes, &ateapipb.ExternalVolume{ + resultVolumes = append(resultVolumes, &ateapipb.ActorVolumeStatus{ Name: volName, StorageVolumeId: resp.VolumeID, VolumeType: sc.Provisioner, - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, VolumeContext: resp.VolumeContext, }) } @@ -139,7 +139,7 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi } // deleteActorVolumes deletes all external volumes in the list. -func deleteActorVolumes(ctx context.Context, registry VolumePluginRegistry, actorUID string, volumes []*ateapipb.ExternalVolume) error { +func deleteActorVolumes(ctx context.Context, registry VolumePluginRegistry, actorUID string, volumes []*ateapipb.ActorVolumeStatus) error { if actorUID == "" { return errors.New("actorUID is required") } @@ -171,8 +171,8 @@ func deleteActorVolumes(ctx context.Context, registry VolumePluginRegistry, acto } // getMountedActorVolumes filters the actor's volumes and returns only those that are declared and mounted in the ActorTemplate. -func getMountedActorVolumes(ctx context.Context, ref *ateapipb.ObjectRef, volumes []*ateapipb.ExternalVolume, template *ateapipb.ActorTemplate) []*ateapipb.ExternalVolume { - var mounted []*ateapipb.ExternalVolume +func getMountedActorVolumes(ctx context.Context, ref *ateapipb.ObjectRef, volumes []*ateapipb.ActorVolumeStatus, template *ateapipb.ActorTemplate) []*ateapipb.ActorVolumeStatus { + var mounted []*ateapipb.ActorVolumeStatus for _, vol := range volumes { // Find the corresponding volume in the ActorTemplate to check if it's mounted var matchedTemplateVol *ateapipb.Volume diff --git a/cmd/ateapi/internal/controlapi/volumes_test.go b/cmd/ateapi/internal/controlapi/volumes_test.go index 5fb207c11d..52d8eb6fb5 100644 --- a/cmd/ateapi/internal/controlapi/volumes_test.go +++ b/cmd/ateapi/internal/controlapi/volumes_test.go @@ -68,10 +68,10 @@ func TestActorVolumesStorageClassErrors(t *testing.T) { }, }}, } - volumes := []*ateapipb.ExternalVolume{{ + volumes := []*ateapipb.ActorVolumeStatus{{ Name: "data-vol", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }} for _, tt := range []struct { @@ -141,16 +141,16 @@ func TestInitialActorVolumes_PendingState(t *testing.T) { }, } - want := []*ateapipb.ExternalVolume{ + want := []*ateapipb.ActorVolumeStatus{ { Name: "data-vol-1", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, { Name: "data-vol-2", VolumeType: "mock-fast", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, } @@ -215,108 +215,108 @@ func TestCreateActorVolumes(t *testing.T) { tests := []struct { name string tmpl *ateapipb.ActorTemplate - inputVolumes []*ateapipb.ExternalVolume + inputVolumes []*ateapipb.ActorVolumeStatus storageClasses map[string]*storagev1.StorageClass wantErr bool - wantRes []*ateapipb.ExternalVolume + wantRes []*ateapipb.ActorVolumeStatus }{ { name: "partial failure returns error and preserves succeeded, failed, and remaining volumes", tmpl: multiVolTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ActorVolumeStatus{ { Name: "vol1", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, { Name: "vol2", - Status: ateapipb.ExternalVolume_STATUS_DELETING, + Status: ateapipb.ActorVolumeStatus_STATUS_DELETING, }, { Name: "vol3", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, }, wantErr: true, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ActorVolumeStatus{ { Name: "vol1", StorageVolumeId: "mock-vol-substrate-actor-uid-123-vol1", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, }, { Name: "vol2", - Status: ateapipb.ExternalVolume_STATUS_DELETING, + Status: ateapipb.ActorVolumeStatus_STATUS_DELETING, }, { Name: "vol3", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, }, }, { name: "created volume status succeeds", tmpl: standardTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ActorVolumeStatus{ { Name: "data-vol", StorageVolumeId: "existing-vol-id", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, }, }, wantErr: false, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ActorVolumeStatus{ { Name: "data-vol", StorageVolumeId: "existing-vol-id", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, }, }, }, { name: "unspecified volume status returns error", tmpl: standardTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ActorVolumeStatus{ { Name: "data-vol", - Status: ateapipb.ExternalVolume_STATUS_UNSPECIFIED, + Status: ateapipb.ActorVolumeStatus_STATUS_UNSPECIFIED, }, }, wantErr: true, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ActorVolumeStatus{ { Name: "data-vol", - Status: ateapipb.ExternalVolume_STATUS_UNSPECIFIED, + Status: ateapipb.ActorVolumeStatus_STATUS_UNSPECIFIED, }, }, }, { name: "volume not found in template returns error", tmpl: &ateapipb.ActorTemplate{}, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ActorVolumeStatus{ { Name: "missing-vol", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, }, wantErr: true, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ActorVolumeStatus{ { Name: "missing-vol", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, }, }, { name: "storage class parameters are propagated to volume context", tmpl: standardTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ActorVolumeStatus{ { Name: "data-vol", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ActorVolumeStatus_STATUS_PENDING, }, }, storageClasses: map[string]*storagev1.StorageClass{ @@ -330,12 +330,12 @@ func TestCreateActorVolumes(t *testing.T) { }, }, wantErr: false, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ActorVolumeStatus{ { Name: "data-vol", StorageVolumeId: "mock-vol-substrate-actor-uid-123-data-vol", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, VolumeContext: map[string]string{ "type": "pd-ssd", "csi.storage.k8s.io/fstype": "ext4", @@ -395,14 +395,14 @@ func TestDeleteActorVolumes(t *testing.T) { tests := []struct { name string actorUID string - volumes []*ateapipb.ExternalVolume + volumes []*ateapipb.ActorVolumeStatus wantDeleted []string wantErr bool }{ { name: "uses storage volume ID when present", actorUID: "uid-abc", - volumes: []*ateapipb.ExternalVolume{ + volumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "storage-vol-123", VolumeType: "mock"}, }, wantDeleted: []string{"storage-vol-123"}, @@ -411,8 +411,8 @@ func TestDeleteActorVolumes(t *testing.T) { { name: "falls back to actorVolumeID when storage volume ID is empty regardless of status", actorUID: "uid-abc", - volumes: []*ateapipb.ExternalVolume{ - {Name: "vol1", StorageVolumeId: "", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "mock"}, + volumes: []*ateapipb.ActorVolumeStatus{ + {Name: "vol1", StorageVolumeId: "", Status: ateapipb.ActorVolumeStatus_STATUS_CREATED, VolumeType: "mock"}, }, wantDeleted: []string{"substrate-uid-abc-vol1"}, wantErr: false, @@ -491,7 +491,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -522,7 +522,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "mounted-vol", StorageVolumeId: "storage-vol-mounted", VolumeType: "mock"}, {Name: "unmounted-vol", StorageVolumeId: "storage-vol-unmounted", VolumeType: "mock"}, }, @@ -551,7 +551,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -581,7 +581,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -599,7 +599,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, }, }, @@ -620,7 +620,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -644,7 +644,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "unknown-plugin"}, }, }, @@ -658,7 +658,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, }, }, diff --git a/cmd/ateapi/internal/controlapi/workflow_delete.go b/cmd/ateapi/internal/controlapi/workflow_delete.go index 759facf0c4..ea98140354 100644 --- a/cmd/ateapi/internal/controlapi/workflow_delete.go +++ b/cmd/ateapi/internal/controlapi/workflow_delete.go @@ -334,7 +334,7 @@ func (w *ActorWorkflow) ensureMarkedDeleting(ctx context.Context, actorRef resou storedActor, err := w.store.UpdateActor(ctx, actorRef, store.PreconditionFrom(actor), func(toUpdate *ateapipb.Actor) error { toUpdate.Status.State = ateapipb.ActorState_ACTOR_STATE_DELETING for _, vol := range toUpdate.GetStatus().GetExternalVolumes() { - vol.Status = ateapipb.ExternalVolume_STATUS_DELETING + vol.Status = ateapipb.ActorVolumeStatus_STATUS_DELETING } return nil }) diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index f9bd159582..2a8e649ddf 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -194,7 +194,7 @@ func (w *ActorWorkflow) ensureVolumesCreated(ctx context.Context, actorRef resou pending := false for _, vol := range actor.GetStatus().GetExternalVolumes() { - if vol.GetStatus() == ateapipb.ExternalVolume_STATUS_PENDING { + if vol.GetStatus() == ateapipb.ActorVolumeStatus_STATUS_PENDING { pending = true break } diff --git a/cmd/ateapi/internal/controlapi/workflow_resume_test.go b/cmd/ateapi/internal/controlapi/workflow_resume_test.go index 02a6030fa5..0f1f0a95f9 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume_test.go @@ -1549,9 +1549,9 @@ func TestEnsureVolumesAttached_ReturnsPublishContext(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "id1"}, Status: &ateapipb.ActorStatus{ State: ateapipb.ActorState_ACTOR_STATE_RESUMING, - ExternalVolumes: []*ateapipb.ExternalVolume{ - {Name: "mounted", StorageVolumeId: "storage-mounted", VolumeType: "mock", Status: ateapipb.ExternalVolume_STATUS_CREATED}, - {Name: "unmounted", StorageVolumeId: "storage-unmounted", VolumeType: "mock", Status: ateapipb.ExternalVolume_STATUS_CREATED}, + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ + {Name: "mounted", StorageVolumeId: "storage-mounted", VolumeType: "mock", Status: ateapipb.ActorVolumeStatus_STATUS_CREATED}, + {Name: "unmounted", StorageVolumeId: "storage-unmounted", VolumeType: "mock", Status: ateapipb.ActorVolumeStatus_STATUS_CREATED}, }, }, }) diff --git a/cmd/ateapi/internal/controlapi/workload_spec_test.go b/cmd/ateapi/internal/controlapi/workload_spec_test.go index b39a90bbfd..66cc175771 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec_test.go +++ b/cmd/ateapi/internal/controlapi/workload_spec_test.go @@ -421,7 +421,7 @@ func TestAppendExternalVolumes(t *testing.T) { Name: "actor-123", }, Status: &ateapipb.ActorStatus{ - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ActorVolumeStatus{ { Name: "vol-1", StorageVolumeId: "vol-gce-pd-123", @@ -480,7 +480,7 @@ func TestAppendExternalVolumes(t *testing.T) { Atespace: "space-abc", Name: "actor-123", }, - Status: &ateapipb.ActorStatus{ExternalVolumes: []*ateapipb.ExternalVolume{}}, + Status: &ateapipb.ActorStatus{ExternalVolumes: []*ateapipb.ActorVolumeStatus{}}, } if err := appendExternalVolumes(&ateletpb.WorkloadSpec{}, template, missingActor, nil); err == nil { t.Errorf("appendExternalVolumes expected error for missing volume, got nil") diff --git a/internal/e2e/suites/demo/demo_test.go b/internal/e2e/suites/demo/demo_test.go index 2900689c6c..e1b2c63d1a 100644 --- a/internal/e2e/suites/demo/demo_test.go +++ b/internal/e2e/suites/demo/demo_test.go @@ -388,7 +388,7 @@ func TestDeleteActorAnyStateWithExternalVolume(t *testing.T) { t.Fatalf("expected actor to have volumes, got 0") } for _, vol := range actor.GetStatus().GetExternalVolumes() { - if vol.Status != ateapipb.ExternalVolume_STATUS_CREATED { + if vol.Status != ateapipb.ActorVolumeStatus_STATUS_CREATED { t.Fatalf("expected volume %q to be CREATED, got %s", vol.Name, vol.Status) } } diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index 02e7410462..d9de88106f 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -533,27 +533,28 @@ func (WorkerState) EnumDescriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{8} } -type ExternalVolume_Status int32 +// Status is the volume's lifecycle state in the storage system. +type ActorVolumeStatus_Status int32 const ( - ExternalVolume_STATUS_UNSPECIFIED ExternalVolume_Status = 0 + ActorVolumeStatus_STATUS_UNSPECIFIED ActorVolumeStatus_Status = 0 // Volume creation pending in the storage system. - ExternalVolume_STATUS_PENDING ExternalVolume_Status = 1 + ActorVolumeStatus_STATUS_PENDING ActorVolumeStatus_Status = 1 // Volume successfully created in the storage system. - ExternalVolume_STATUS_CREATED ExternalVolume_Status = 2 + ActorVolumeStatus_STATUS_CREATED ActorVolumeStatus_Status = 2 // Volume being deleted from the storage system. - ExternalVolume_STATUS_DELETING ExternalVolume_Status = 3 // Keep this in sync with ExternalVolume.status's maximum. + ActorVolumeStatus_STATUS_DELETING ActorVolumeStatus_Status = 3 // Keep this in sync with ActorVolumeStatus.status's maximum. ) -// Enum value maps for ExternalVolume_Status. +// Enum value maps for ActorVolumeStatus_Status. var ( - ExternalVolume_Status_name = map[int32]string{ + ActorVolumeStatus_Status_name = map[int32]string{ 0: "STATUS_UNSPECIFIED", 1: "STATUS_PENDING", 2: "STATUS_CREATED", 3: "STATUS_DELETING", } - ExternalVolume_Status_value = map[string]int32{ + ActorVolumeStatus_Status_value = map[string]int32{ "STATUS_UNSPECIFIED": 0, "STATUS_PENDING": 1, "STATUS_CREATED": 2, @@ -561,30 +562,30 @@ var ( } ) -func (x ExternalVolume_Status) Enum() *ExternalVolume_Status { - p := new(ExternalVolume_Status) +func (x ActorVolumeStatus_Status) Enum() *ActorVolumeStatus_Status { + p := new(ActorVolumeStatus_Status) *p = x return p } -func (x ExternalVolume_Status) String() string { +func (x ActorVolumeStatus_Status) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (ExternalVolume_Status) Descriptor() protoreflect.EnumDescriptor { +func (ActorVolumeStatus_Status) Descriptor() protoreflect.EnumDescriptor { return file_ateapi_proto_enumTypes[9].Descriptor() } -func (ExternalVolume_Status) Type() protoreflect.EnumType { +func (ActorVolumeStatus_Status) Type() protoreflect.EnumType { return &file_ateapi_proto_enumTypes[9] } -func (x ExternalVolume_Status) Number() protoreflect.EnumNumber { +func (x ActorVolumeStatus_Status) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use ExternalVolume_Status.Descriptor instead. -func (ExternalVolume_Status) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use ActorVolumeStatus_Status.Descriptor instead. +func (ActorVolumeStatus_Status) EnumDescriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{6, 0} } @@ -1068,7 +1069,8 @@ func (x *ResourceMetadata) GetUpdateTime() *timestamppb.Timestamp { return nil } -type ExternalVolume struct { +// ActorVolumeStatus is one actor's view of an external volume it mounts. +type ActorVolumeStatus struct { state protoimpl.MessageState `protogen:"open.v1"` // Name of the volume specified in the actor template. Template volume // names are DNS labels. @@ -1102,10 +1104,12 @@ type ExternalVolume struct { // +k8s:update=NoUnset # set-once, like name above // +k8s:customValidation VolumeType string `protobuf:"bytes,3,opt,name=volume_type,json=volumeType,proto3" json:"volume_type,omitempty"` + // status is the volume's lifecycle state in the storage system. + // // +k8s:optional // +k8s:minimum=1 // +k8s:maximum=3 # keep this in sync with the Status enum - Status ExternalVolume_Status `protobuf:"varint,4,opt,name=status,proto3,enum=ateapi.ExternalVolume_Status" json:"status,omitempty"` + Status ActorVolumeStatus_Status `protobuf:"varint,4,opt,name=status,proto3,enum=ateapi.ActorVolumeStatus_Status" json:"status,omitempty"` // volume_context contains metadata returned by the CSI driver during volume // provisioning, needed by the node plugin for mounting (e.g. attachment // info). Keys and values are the driver's own, so they are only bounded, @@ -1120,20 +1124,20 @@ type ExternalVolume struct { sizeCache protoimpl.SizeCache } -func (x *ExternalVolume) Reset() { - *x = ExternalVolume{} +func (x *ActorVolumeStatus) Reset() { + *x = ActorVolumeStatus{} mi := &file_ateapi_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ExternalVolume) String() string { +func (x *ActorVolumeStatus) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ExternalVolume) ProtoMessage() {} +func (*ActorVolumeStatus) ProtoMessage() {} -func (x *ExternalVolume) ProtoReflect() protoreflect.Message { +func (x *ActorVolumeStatus) ProtoReflect() protoreflect.Message { mi := &file_ateapi_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1145,40 +1149,40 @@ func (x *ExternalVolume) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ExternalVolume.ProtoReflect.Descriptor instead. -func (*ExternalVolume) Descriptor() ([]byte, []int) { +// Deprecated: Use ActorVolumeStatus.ProtoReflect.Descriptor instead. +func (*ActorVolumeStatus) Descriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{6} } -func (x *ExternalVolume) GetName() string { +func (x *ActorVolumeStatus) GetName() string { if x != nil { return x.Name } return "" } -func (x *ExternalVolume) GetStorageVolumeId() string { +func (x *ActorVolumeStatus) GetStorageVolumeId() string { if x != nil { return x.StorageVolumeId } return "" } -func (x *ExternalVolume) GetVolumeType() string { +func (x *ActorVolumeStatus) GetVolumeType() string { if x != nil { return x.VolumeType } return "" } -func (x *ExternalVolume) GetStatus() ExternalVolume_Status { +func (x *ActorVolumeStatus) GetStatus() ActorVolumeStatus_Status { if x != nil { return x.Status } - return ExternalVolume_STATUS_UNSPECIFIED + return ActorVolumeStatus_STATUS_UNSPECIFIED } -func (x *ExternalVolume) GetVolumeContext() map[string]string { +func (x *ActorVolumeStatus) GetVolumeContext() map[string]string { if x != nil { return x.VolumeContext } @@ -2052,7 +2056,7 @@ type ActorStatus struct { // +k8s:maxItems=32 # matches the template's volumes bound // +k8s:listType=map // +k8s:listMapKey=name - ExternalVolumes []*ExternalVolume `protobuf:"bytes,7,rep,name=external_volumes,json=externalVolumes,proto3" json:"external_volumes,omitempty"` + ExternalVolumes []*ActorVolumeStatus `protobuf:"bytes,7,rep,name=external_volumes,json=externalVolumes,proto3" json:"external_volumes,omitempty"` // crash records why and when the Actor entered CRASHED. It is set with the // CRASHED state and cleared when a revert returns the Actor to SUSPENDED. // @@ -2131,7 +2135,7 @@ func (x *ActorStatus) GetWorkerAssignment() *WorkerAssignment { return nil } -func (x *ActorStatus) GetExternalVolumes() []*ExternalVolume { +func (x *ActorStatus) GetExternalVolumes() []*ActorVolumeStatus { if x != nil { return x.ExternalVolumes } @@ -8351,14 +8355,14 @@ const file_ateapi_proto_rawDesc = "" + "\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\n" + "createTime\x12;\n" + "\vupdate_time\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\n" + - "updateTime\"\x9b\x03\n" + - "\x0eExternalVolume\x12\x12\n" + + "updateTime\"\xa4\x03\n" + + "\x11ActorVolumeStatus\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12*\n" + "\x11storage_volume_id\x18\x02 \x01(\tR\x0fstorageVolumeId\x12\x1f\n" + "\vvolume_type\x18\x03 \x01(\tR\n" + - "volumeType\x125\n" + - "\x06status\x18\x04 \x01(\x0e2\x1d.ateapi.ExternalVolume.StatusR\x06status\x12P\n" + - "\x0evolume_context\x18\x05 \x03(\v2).ateapi.ExternalVolume.VolumeContextEntryR\rvolumeContext\x1a@\n" + + "volumeType\x128\n" + + "\x06status\x18\x04 \x01(\x0e2 .ateapi.ActorVolumeStatus.StatusR\x06status\x12S\n" + + "\x0evolume_context\x18\x05 \x03(\v2,.ateapi.ActorVolumeStatus.VolumeContextEntryR\rvolumeContext\x1a@\n" + "\x12VolumeContextEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"]\n" + @@ -8407,11 +8411,11 @@ const file_ateapi_proto_rawDesc = "" + "\tactor_jwt\x18\x04 \x01(\v2\x16.ateapi.ActorJWTSourceR\bactorJwt\"]\n" + "\x0eActorJWTSource\x12\x1c\n" + "\taudiences\x18\x01 \x03(\tR\taudiences\x12-\n" + - "\x12expiration_seconds\x18\x02 \x01(\x03R\x11expirationSeconds\"\xfa\x02\n" + + "\x12expiration_seconds\x18\x02 \x01(\x03R\x11expirationSeconds\"\xfd\x02\n" + "\vActorStatus\x12(\n" + "\x05state\x18\x01 \x01(\x0e2\x12.ateapi.ActorStateR\x05state\x12E\n" + - "\x11worker_assignment\x18\x02 \x01(\v2\x18.ateapi.WorkerAssignmentR\x10workerAssignment\x12A\n" + - "\x10external_volumes\x18\a \x03(\v2\x16.ateapi.ExternalVolumeR\x0fexternalVolumes\x12(\n" + + "\x11worker_assignment\x18\x02 \x01(\v2\x18.ateapi.WorkerAssignmentR\x10workerAssignment\x12D\n" + + "\x10external_volumes\x18\a \x03(\v2\x19.ateapi.ActorVolumeStatusR\x0fexternalVolumes\x12(\n" + "\x05crash\x18\t \x01(\v2\x12.ateapi.ActorCrashR\x05crash\x12#\n" + "\rassigned_node\x18\n" + " \x01(\tR\fassignedNode\x12.\n" + @@ -8865,14 +8869,14 @@ var file_ateapi_proto_goTypes = []any{ (SandboxClass)(0), // 6: ateapi.SandboxClass (ActorMetadataField)(0), // 7: ateapi.ActorMetadataField (WorkerState)(0), // 8: ateapi.WorkerState - (ExternalVolume_Status)(0), // 9: ateapi.ExternalVolume.Status + (ActorVolumeStatus_Status)(0), // 9: ateapi.ActorVolumeStatus.Status (*ObjectSnapshot)(nil), // 10: ateapi.ObjectSnapshot (*LocalSnapshot)(nil), // 11: ateapi.LocalSnapshot (*SnapshotStorage)(nil), // 12: ateapi.SnapshotStorage (*Snapshot)(nil), // 13: ateapi.Snapshot (*Selector)(nil), // 14: ateapi.Selector (*ResourceMetadata)(nil), // 15: ateapi.ResourceMetadata - (*ExternalVolume)(nil), // 16: ateapi.ExternalVolume + (*ActorVolumeStatus)(nil), // 16: ateapi.ActorVolumeStatus (*Actor)(nil), // 17: ateapi.Actor (*EgressPolicy)(nil), // 18: ateapi.EgressPolicy (*EgressRule)(nil), // 19: ateapi.EgressRule @@ -8983,7 +8987,7 @@ var file_ateapi_proto_goTypes = []any{ (*UpdateAtespaceAccessPolicyRequest)(nil), // 124: ateapi.UpdateAtespaceAccessPolicyRequest (*DeleteAtespaceAccessPolicyRequest)(nil), // 125: ateapi.DeleteAtespaceAccessPolicyRequest nil, // 126: ateapi.Selector.MatchLabelsEntry - nil, // 127: ateapi.ExternalVolume.VolumeContextEntry + nil, // 127: ateapi.ActorVolumeStatus.VolumeContextEntry nil, // 128: ateapi.Worker.LabelsEntry nil, // 129: ateapi.HardwareIdentity.AttributesEntry (*timestamppb.Timestamp)(nil), // 130: google.protobuf.Timestamp @@ -8999,8 +9003,8 @@ var file_ateapi_proto_depIdxs = []int32{ 126, // 7: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry 130, // 8: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp 130, // 9: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp - 9, // 10: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status - 127, // 11: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry + 9, // 10: ateapi.ActorVolumeStatus.status:type_name -> ateapi.ActorVolumeStatus.Status + 127, // 11: ateapi.ActorVolumeStatus.volume_context:type_name -> ateapi.ActorVolumeStatus.VolumeContextEntry 15, // 12: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata 34, // 13: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef 14, // 14: ateapi.Actor.worker_selector:type_name -> ateapi.Selector @@ -9021,7 +9025,7 @@ var file_ateapi_proto_depIdxs = []int32{ 27, // 29: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJWTSource 5, // 30: ateapi.ActorStatus.state:type_name -> ateapi.ActorState 30, // 31: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment - 16, // 32: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ExternalVolume + 16, // 32: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ActorVolumeStatus 29, // 33: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash 13, // 34: ateapi.ActorStatus.snapshots:type_name -> ateapi.Snapshot 130, // 35: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index ca0195c8d7..28bc6bae54 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -398,7 +398,8 @@ message ResourceMetadata { google.protobuf.Timestamp update_time = 6; } -message ExternalVolume { +// ActorVolumeStatus is one actor's view of an external volume it mounts. +message ActorVolumeStatus { // Name of the volume specified in the actor template. Template volume // names are DNS labels. // @@ -434,6 +435,7 @@ message ExternalVolume { // +k8s:customValidation string volume_type = 3; + // Status is the volume's lifecycle state in the storage system. enum Status { STATUS_UNSPECIFIED = 0; // Volume creation pending in the storage system. @@ -442,9 +444,11 @@ message ExternalVolume { STATUS_CREATED = 2; // Volume being deleted from the storage system. STATUS_DELETING = 3; - // Keep this in sync with ExternalVolume.status's maximum. + // Keep this in sync with ActorVolumeStatus.status's maximum. } + // status is the volume's lifecycle state in the storage system. + // // +k8s:optional // +k8s:minimum=1 // +k8s:maximum=3 # keep this in sync with the Status enum @@ -809,7 +813,7 @@ message ActorStatus { // +k8s:maxItems=32 # matches the template's volumes bound // +k8s:listType=map // +k8s:listMapKey=name - repeated ExternalVolume external_volumes = 7; + repeated ActorVolumeStatus external_volumes = 7; // crash records why and when the Actor entered CRASHED. It is set with the // CRASHED state and cleared when a revert returns the Actor to SUSPENDED. diff --git a/tools/apitool/exemptions.json b/tools/apitool/exemptions.json index 804256c62f..9bf946e52d 100644 --- a/tools/apitool/exemptions.json +++ b/tools/apitool/exemptions.json @@ -149,21 +149,6 @@ "subject": "ateapi.DrainWorkerRequest", "message": "message has no doc comment" }, - { - "rule": "documented", - "subject": "ateapi.ExternalVolume", - "message": "message has no doc comment" - }, - { - "rule": "documented", - "subject": "ateapi.ExternalVolume.Status", - "message": "enum has no doc comment" - }, - { - "rule": "documented", - "subject": "ateapi.ExternalVolume.status", - "message": "field has no doc comment" - }, { "rule": "documented", "subject": "ateapi.GetActorRequest", diff --git a/tools/apitool/internal/model/model.go b/tools/apitool/internal/model/model.go index 7a664e341e..bc299ef4b9 100644 --- a/tools/apitool/internal/model/model.go +++ b/tools/apitool/internal/model/model.go @@ -41,7 +41,7 @@ type API struct { Messages []Message // Enums lists every enum declared in the file, top-level and nested, // flattened the same way as Messages. For example, both the top-level - // "ateapi.ActorState" and the nested "ateapi.ExternalVolume.Status" + // "ateapi.ActorState" and the nested "ateapi.ActorVolumeStatus.Status" // appear here. Enums []Enum } @@ -101,7 +101,7 @@ type Message struct { // Name is the message's short name, with its enclosing message's name // dotted in front for a nested type. For example, "ResourceMetadata" // for a top-level message. ateapi.proto has no nested message today - // (only a nested enum, ExternalVolume.Status - see Enum.Name for that + // (only a nested enum, ActorVolumeStatus.Status - see Enum.Name for that // shape); a nested message named "Child" inside "Parent" would read // "Parent.Child" here. Name string @@ -132,13 +132,13 @@ type Field struct { // Repeated is true for a `repeated` field, not a map - see // MapValueKind for those. For example, true for - // `repeated ExternalVolume external_volumes = 7;` on ActorStatus; false + // `repeated ActorVolumeStatus external_volumes = 7;` on ActorStatus; false // for ResourceMetadata.atespace. Repeated bool // TypeDisplay is always a ready-to-render string. For example, "string" // for ResourceMetadata.name, "int64" for ResourceMetadata.version, - // "repeated ExternalVolume" for ActorStatus.external_volumes, + // "repeated ActorVolumeStatus" for ActorStatus.external_volumes, // "map" for SandboxAssets.assets, "ActorState" for // ActorStatus.state, or "google.protobuf.Timestamp" for // ResourceMetadata.create_time. @@ -184,25 +184,25 @@ type Field struct { // Enum is one enum declared in the file, top-level or nested. type Enum struct { // FullName is the enum's proto full name. For example, "ateapi.ActorState" - // for a top-level enum, or "ateapi.ExternalVolume.Status" for one - // nested inside the ExternalVolume message. + // for a top-level enum, or "ateapi.ActorVolumeStatus.Status" for one + // nested inside the ActorVolumeStatus message. FullName string // Name is the enum's short name, with its enclosing message's name // dotted in front for a nested enum. For example, "ActorState" for - // the top-level enum, or "ExternalVolume.Status" for the one nested - // inside ExternalVolume. + // the top-level enum, or "ActorVolumeStatus.Status" for the one nested + // inside ActorVolumeStatus. Name string // ParentFullName is the enclosing message's full name, or "" for a // top-level enum. For example, "" for "ateapi.ActorState", or - // "ateapi.ExternalVolume" for "ateapi.ExternalVolume.Status". + // "ateapi.ActorVolumeStatus" for "ateapi.ActorVolumeStatus.Status". ParentFullName string // Comment is the enum's leading doc comment. ateapi.proto's ActorState - // and ExternalVolume.Status have none today, so this is often "" in + // and ActorVolumeStatus.Status have none today, so this is often "" in // practice even though the field is populated the same way as for a // message or field. Comment string // Values lists the enum's values, in declaration order. For example, - // ExternalVolume.Status's STATUS_UNSPECIFIED, STATUS_PENDING, + // ActorVolumeStatus.Status's STATUS_UNSPECIFIED, STATUS_PENDING, // STATUS_CREATED, STATUS_DELETING. Values []EnumValue } @@ -221,13 +221,13 @@ func (e Enum) ValueByNumber(number int32) *EnumValue { // EnumValue is one value declared on an Enum. type EnumValue struct { // Name is the value's proto name. For example, "STATUS_PENDING" for - // ExternalVolume.Status. + // ActorVolumeStatus.Status. Name string // Number is the value's proto number. For example, 1 for // `STATUS_PENDING = 1;`. Number int32 // Comment is the value's leading doc comment. For example, "Volume - // creation pending in the storage system." for ExternalVolume.Status's + // creation pending in the storage system." for ActorVolumeStatus.Status's // STATUS_PENDING. Comment string }