Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit 00934f4

Browse files
committed
Adjust validation for new project paradigms
It was decided that if a user doesn't specify any region information for a project, then the project supports all region by default. Additionally, it is now possible that a user can specify that a project supports all regions by using the '*' value. Signed-off-by: Donnie Adams <donnie@acorn.io>
1 parent 6db89ac commit 00934f4

File tree

10 files changed

+229
-32
lines changed

10 files changed

+229
-32
lines changed

pkg/apis/api.acorn.io/v1/region.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const (
99
RegionConditionClusterReady = "ClusterReady"
1010

1111
LocalRegion = "local"
12+
AllRegions = "*"
1213
)
1314

1415
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

pkg/apis/internal.acorn.io/v1/projectinstance.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ type ProjectInstanceSpec struct {
2020
}
2121

2222
type ProjectInstanceStatus struct {
23-
Namespace string `json:"namespace,omitempty"`
24-
DefaultRegion string `json:"defaultRegion,omitempty"`
23+
Namespace string `json:"namespace,omitempty"`
24+
DefaultRegion string `json:"defaultRegion,omitempty"`
25+
// SupportedRegions on the status field should be an explicit list of supported regions.
26+
// That is, if the user specifies "*" for supported regions, then the status value should be the list of all regions.
27+
// This is to avoid having to make another call to explicitly list all regions.
2528
SupportedRegions []string `json:"supportedRegions,omitempty"`
2629
}
2730

@@ -44,7 +47,7 @@ func (in *ProjectInstance) GetSupportedRegions() []string {
4447
func (in *ProjectInstance) SetDefaultRegion(region string) {
4548
if in.Spec.DefaultRegion == "" && len(in.Spec.SupportedRegions) == 0 {
4649
in.Status.DefaultRegion = region
47-
in.Status.SupportedRegions = []string{region}
50+
in.Status.SupportedRegions = []string{"*"}
4851
} else {
4952
// Set the status values to the provided spec values.
5053
// The idea here is that internally, we only need to check the status values.

pkg/client/project.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func (c *DefaultClient) ProjectCreate(ctx context.Context, name, defaultRegion s
3737
}
3838
if defaultRegion != "" {
3939
project.Spec.DefaultRegion = defaultRegion
40-
if !slices.Contains(supportedRegions, defaultRegion) {
40+
if !slices.Contains(supportedRegions, defaultRegion) && !slices.Contains(supportedRegions, apiv1.AllRegions) {
4141
supportedRegions = append([]string{defaultRegion}, supportedRegions...)
4242
}
4343
}
@@ -57,7 +57,7 @@ func (c *DefaultClient) ProjectUpdate(ctx context.Context, project *apiv1.Projec
5757
project.Spec.SupportedRegions = supportedRegions
5858
}
5959
}
60-
if project.Spec.DefaultRegion != "" && !slices.Contains(project.Spec.SupportedRegions, project.Spec.DefaultRegion) {
60+
if project.Spec.DefaultRegion != "" && !slices.Contains(project.Spec.SupportedRegions, project.Spec.DefaultRegion) && !slices.Contains(project.Spec.SupportedRegions, apiv1.AllRegions) {
6161
project.Spec.SupportedRegions = append(project.Spec.SupportedRegions, project.Spec.DefaultRegion)
6262
}
6363

pkg/openapi/generated/openapi_generated.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/project/handlers.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,20 @@ import (
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
klabels "k8s.io/apimachinery/pkg/labels"
1414
"k8s.io/apimachinery/pkg/selection"
15+
"k8s.io/utils/strings/slices"
1516
kclient "sigs.k8s.io/controller-runtime/pkg/client"
1617
)
1718

1819
func SetProjectSupportedRegions(req router.Request, resp router.Response) error {
19-
req.Object.(*v1.ProjectInstance).SetDefaultRegion(apiv1.LocalRegion)
20+
project := req.Object.(*v1.ProjectInstance)
21+
project.SetDefaultRegion(apiv1.LocalRegion)
22+
if slices.Contains(project.Status.SupportedRegions, apiv1.AllRegions) {
23+
// If the project supports all regions, then ensure the default region and the local region are supported regions.
24+
project.Status.SupportedRegions = []string{project.Status.DefaultRegion}
25+
if project.Status.DefaultRegion != apiv1.LocalRegion {
26+
project.Status.SupportedRegions = append(project.Status.SupportedRegions, apiv1.LocalRegion)
27+
}
28+
}
2029

2130
resp.Objects(req.Object)
2231
return nil

pkg/project/handlers_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func TestSetProjectSupportedRegions(t *testing.T) {
1818
tester.DefaultTest(t, scheme.Scheme, "testdata/setsupportedregions/no-default", SetProjectSupportedRegions)
1919
tester.DefaultTest(t, scheme.Scheme, "testdata/setsupportedregions/with-supported-regions", SetProjectSupportedRegions)
2020
tester.DefaultTest(t, scheme.Scheme, "testdata/setsupportedregions/with-default-and-supported", SetProjectSupportedRegions)
21+
tester.DefaultTest(t, scheme.Scheme, "testdata/setsupportedregions/all-supported-regions-with-default", SetProjectSupportedRegions)
2122
}
2223

2324
func TestCreateNamespace(t *testing.T) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
`apiVersion: internal.acorn.io/v1
2+
kind: ProjectInstance
3+
metadata:
4+
creationTimestamp: null
5+
name: acorn
6+
spec:
7+
defaultRegion: other-region
8+
supportedRegions:
9+
- '*'
10+
status:
11+
defaultRegion: other-region
12+
supportedRegions:
13+
- other-region
14+
- local
15+
`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: ProjectInstance
2+
apiVersion: internal.acorn.io/v1
3+
metadata:
4+
name: acorn
5+
spec:
6+
defaultRegion: other-region
7+
supportedRegions:
8+
- "*"

pkg/server/registry/apigroups/acorn/projects/validator.go

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,46 +26,42 @@ func (v *Validator) Validate(_ context.Context, obj runtime.Object) field.ErrorL
2626
var result field.ErrorList
2727
project := obj.(*apiv1.Project)
2828

29-
if project.Spec.DefaultRegion != "" && !slices.Contains(project.Spec.SupportedRegions, project.Spec.DefaultRegion) {
29+
if project.Spec.DefaultRegion != "" && !slices.Contains(project.Spec.SupportedRegions, project.Spec.DefaultRegion) && !slices.Contains(project.Spec.SupportedRegions, apiv1.AllRegions) {
3030
return append(result, field.Invalid(field.NewPath("spec", "defaultRegion"), project.Spec.DefaultRegion, "default region is not in the supported regions list"))
3131
}
3232

3333
return nil
3434
}
3535

36-
func (v *Validator) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
36+
func (v *Validator) ValidateUpdate(ctx context.Context, newObj, _ runtime.Object) field.ErrorList {
3737
// Ensure that default region and supported regions are valid.
38-
if err := v.Validate(ctx, obj); err != nil {
38+
if err := v.Validate(ctx, newObj); err != nil {
3939
return err
4040
}
4141

42-
// If the user is removing a supported region, ensure that there are no apps in that region.
43-
oldProject, newProject := old.(*apiv1.Project), obj.(*apiv1.Project)
44-
var removedRegions []string
45-
for _, region := range oldProject.Status.SupportedRegions {
46-
if !slices.Contains(newProject.Status.SupportedRegions, region) {
47-
removedRegions = append(removedRegions, region)
48-
}
49-
}
50-
51-
if len(removedRegions) > 0 {
52-
return v.ensureNoObjectsExistInRegions(ctx, newProject.Name, newProject.Status.SupportedRegions, removedRegions, &apiv1.AppList{}, &apiv1.VolumeList{})
42+
newProject := newObj.(*apiv1.Project)
43+
// If there are no supported regions given by the user (and the above validate call passed) or the user explicitly
44+
// allowed all regions, then the project supports all regions.
45+
if len(newProject.Spec.SupportedRegions) == 0 || slices.Contains(newProject.Spec.SupportedRegions, apiv1.AllRegions) {
46+
return nil
5347
}
5448

55-
return nil
49+
// If the user is removing a supported region, ensure that there are no apps in that region.
50+
return v.ensureNoObjectsExistOutsideOfRegions(ctx, newProject.Name, newProject.Spec.SupportedRegions, &apiv1.AppList{}, &apiv1.VolumeList{})
5651
}
5752

58-
func (v *Validator) ensureNoObjectsExistInRegions(ctx context.Context, namespace string, regions, removedRegions []string, objList ...kclient.ObjectList) field.ErrorList {
53+
func (v *Validator) ensureNoObjectsExistOutsideOfRegions(ctx context.Context, namespace string, regions []string, objList ...kclient.ObjectList) field.ErrorList {
5954
var result field.ErrorList
6055
for _, obj := range objList {
61-
var inRemovedRegion []string
56+
var removedRegions, inRemovedRegion []string
6257
if err := v.Client.List(ctx, obj, kclient.InNamespace(namespace)); err != nil {
6358
return field.ErrorList{field.InternalError(field.NewPath("spec", "supportedRegions"), err)}
6459
}
6560

6661
if err := meta.EachListItem(obj, func(object runtime.Object) error {
6762
regionObject, ok := object.(regionNamer)
68-
if ok && slices.Contains(removedRegions, regionObject.GetRegion()) {
63+
if ok && !slices.Contains(regions, regionObject.GetRegion()) {
64+
removedRegions = append(removedRegions, regionObject.GetRegion())
6965
inRemovedRegion = append(inRemovedRegion, regionObject.GetName())
7066
}
7167
return nil

0 commit comments

Comments
 (0)