diff --git a/pkg/apis/internal.admin.acorn.io/v1/default.go b/pkg/apis/internal.admin.acorn.io/v1/default.go index 4ddc9707d..90b803fe3 100644 --- a/pkg/apis/internal.admin.acorn.io/v1/default.go +++ b/pkg/apis/internal.admin.acorn.io/v1/default.go @@ -5,10 +5,12 @@ import ( "fmt" "sort" + internalv1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" + "github.com/acorn-io/z" "sigs.k8s.io/controller-runtime/pkg/client" ) -func getCurrentClusterComputeClassDefault(ctx context.Context, c client.Client) (*ClusterComputeClassInstance, error) { +func getCurrentClusterComputeClassDefault(ctx context.Context, c client.Client, projectDefaultComputeClass string) (*ClusterComputeClassInstance, error) { clusterComputeClasses := ClusterComputeClassInstanceList{} if err := c.List(ctx, &clusterComputeClasses, &client.ListOptions{}); err != nil { return nil, err @@ -18,7 +20,7 @@ func getCurrentClusterComputeClassDefault(ctx context.Context, c client.Client) return clusterComputeClasses.Items[i].Name < clusterComputeClasses.Items[j].Name }) - var defaultCCC *ClusterComputeClassInstance + var defaultCCC, projectDefaultCCC *ClusterComputeClassInstance for _, clusterComputeClass := range clusterComputeClasses.Items { if clusterComputeClass.Default { if defaultCCC != nil { @@ -26,15 +28,26 @@ func getCurrentClusterComputeClassDefault(ctx context.Context, c client.Client) "cannot establish defaults because two default computeclasses exist: %v and %v", defaultCCC.Name, clusterComputeClass.Name) } - t := clusterComputeClass // Create a new variable that isn't being iterated on to get a pointer - defaultCCC = &t + + // Create a new variable that isn't being iterated on to get a pointer + if projectDefaultComputeClass != "" { + defaultCCC = z.Pointer(clusterComputeClass) + } + } + + if clusterComputeClass.Name == projectDefaultComputeClass { + projectDefaultCCC = z.Pointer(clusterComputeClass) } } + if projectDefaultCCC != nil { + return projectDefaultCCC, nil + } + return defaultCCC, nil } -func getCurrentProjectComputeClassDefault(ctx context.Context, c client.Client, namespace string) (*ProjectComputeClassInstance, error) { +func getCurrentProjectComputeClassDefault(ctx context.Context, c client.Client, projectDefaultComputeClass, namespace string) (*ProjectComputeClassInstance, error) { projectComputeClasses := ProjectComputeClassInstanceList{} if err := c.List(ctx, &projectComputeClasses, &client.ListOptions{Namespace: namespace}); err != nil { return nil, err @@ -44,7 +57,7 @@ func getCurrentProjectComputeClassDefault(ctx context.Context, c client.Client, return projectComputeClasses.Items[i].Name < projectComputeClasses.Items[j].Name }) - var defaultPCC *ProjectComputeClassInstance + var defaultPCC, projectDefaultPCC *ProjectComputeClassInstance for _, projectComputeClass := range projectComputeClasses.Items { if projectComputeClass.Default { if defaultPCC != nil { @@ -52,23 +65,40 @@ func getCurrentProjectComputeClassDefault(ctx context.Context, c client.Client, "cannot establish defaults because two default computeclasses exist: %v and %v", defaultPCC.Name, projectComputeClass.Name) } - t := projectComputeClass // Create a new variable that isn't being iterated on to get a pointer - defaultPCC = &t + + // Create a new variable that isn't being iterated on to get a pointer + if projectDefaultComputeClass != "" { + defaultPCC = z.Pointer(projectComputeClass) + } + } + + if projectComputeClass.Name == projectDefaultComputeClass { + projectDefaultPCC = z.Pointer(projectComputeClass) } } + if projectDefaultPCC != nil { + return projectDefaultPCC, nil + } + return defaultPCC, nil } func GetDefaultComputeClass(ctx context.Context, c client.Client, namespace string) (string, error) { - pcc, err := getCurrentProjectComputeClassDefault(ctx, c, namespace) + var project internalv1.ProjectInstance + if err := c.Get(ctx, client.ObjectKey{Name: namespace}, &project); err != nil { + return "", fmt.Errorf("failed to get projectinstance to determine default compute class: %w", err) + } + projectDefault := project.Status.DefaultComputeClass + + pcc, err := getCurrentProjectComputeClassDefault(ctx, c, projectDefault, namespace) if err != nil { return "", err } else if pcc != nil { return pcc.Name, nil } - ccc, err := getCurrentClusterComputeClassDefault(ctx, c) + ccc, err := getCurrentClusterComputeClassDefault(ctx, c, projectDefault) if err != nil { return "", err } else if ccc != nil { diff --git a/pkg/computeclasses/computeclasses.go b/pkg/computeclasses/computeclasses.go index ddd74470b..a25aef998 100644 --- a/pkg/computeclasses/computeclasses.go +++ b/pkg/computeclasses/computeclasses.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "math" - "sort" "github.com/acorn-io/baaah/pkg/router" apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1" @@ -145,13 +144,12 @@ func GetComputeClassNameForWorkload(workload string, container internalv1.Contai return cc } -// GetClassForWorkload determines what ComputeClass should be used for the given appInstance, container and -// workload. +// GetClassForWorkload determines what ComputeClass should be used for the given appInstance, container, and workload. func GetClassForWorkload(ctx context.Context, c client.Client, computeClasses internalv1.ComputeClassMap, container internalv1.Container, workload, namespace string) (*internaladminv1.ProjectComputeClassInstance, error) { - var err error ccName := GetComputeClassNameForWorkload(workload, container, computeClasses) if ccName == "" { - ccName, err = GetDefaultComputeClass(ctx, c, namespace) + var err error + ccName, err = internaladminv1.GetDefaultComputeClass(ctx, c, namespace) if err != nil { return nil, err } @@ -171,90 +169,19 @@ func GetAsProjectComputeClassInstance(ctx context.Context, c client.Client, name return nil, nil } - projectComputeClass := internaladminv1.ProjectComputeClassInstance{} - err := c.Get(ctx, router.Key(namespace, computeClass), &projectComputeClass) - if err != nil { + var projectComputeClass internaladminv1.ProjectComputeClassInstance + if err := c.Get(ctx, router.Key(namespace, computeClass), &projectComputeClass); err != nil { if !apierrors.IsNotFound(err) { return nil, err } - clusterComputeClass := internaladminv1.ClusterComputeClassInstance{} - err = c.Get(ctx, router.Key("", computeClass), &clusterComputeClass) - if err != nil { + var clusterComputeClass internaladminv1.ClusterComputeClassInstance + if err := c.Get(ctx, router.Key("", computeClass), &clusterComputeClass); err != nil { return nil, err } - cc := internaladminv1.ProjectComputeClassInstance(clusterComputeClass) - return &cc, nil - } - return &projectComputeClass, nil -} - -func getCurrentClusterComputeClassDefault(ctx context.Context, c client.Client) (*internaladminv1.ClusterComputeClassInstance, error) { - clusterComputeClasses := internaladminv1.ClusterComputeClassInstanceList{} - if err := c.List(ctx, &clusterComputeClasses, &client.ListOptions{}); err != nil { - return nil, err - } - - sort.Slice(clusterComputeClasses.Items, func(i, j int) bool { - return clusterComputeClasses.Items[i].Name < clusterComputeClasses.Items[j].Name - }) - - var defaultCCC *internaladminv1.ClusterComputeClassInstance - for _, clusterComputeClass := range clusterComputeClasses.Items { - if clusterComputeClass.Default { - if defaultCCC != nil { - return nil, fmt.Errorf( - "cannot establish defaults because two default computeclasses exist: %v and %v", - defaultCCC.Name, clusterComputeClass.Name) - } - t := clusterComputeClass // Create a new variable that isn't being iterated on to get a pointer - defaultCCC = &t - } - } - - return defaultCCC, nil -} - -func getCurrentProjectComputeClassDefault(ctx context.Context, c client.Client, namespace string) (*internaladminv1.ProjectComputeClassInstance, error) { - projectComputeClasses := internaladminv1.ProjectComputeClassInstanceList{} - if err := c.List(ctx, &projectComputeClasses, &client.ListOptions{Namespace: namespace}); err != nil { - return nil, err - } - - sort.Slice(projectComputeClasses.Items, func(i, j int) bool { - return projectComputeClasses.Items[i].Name < projectComputeClasses.Items[j].Name - }) - - var defaultPCC *internaladminv1.ProjectComputeClassInstance - for _, projectComputeClass := range projectComputeClasses.Items { - if projectComputeClass.Default { - if defaultPCC != nil { - return nil, fmt.Errorf( - "cannot establish defaults because two default computeclasses exist: %v and %v", - defaultPCC.Name, projectComputeClass.Name) - } - t := projectComputeClass // Create a new variable that isn't being iterated on to get a pointer - defaultPCC = &t - } - } - - return defaultPCC, nil -} - -func GetDefaultComputeClass(ctx context.Context, c client.Client, namespace string) (string, error) { - pcc, err := getCurrentProjectComputeClassDefault(ctx, c, namespace) - if err != nil { - return "", err - } else if pcc != nil { - return pcc.Name, nil + projectComputeClass = internaladminv1.ProjectComputeClassInstance(clusterComputeClass) } - ccc, err := getCurrentClusterComputeClassDefault(ctx, c) - if err != nil { - return "", err - } else if ccc != nil { - return ccc.Name, nil - } - return "", nil + return &projectComputeClass, nil } diff --git a/pkg/controller/resolvedofferings/testdata/computeclass/acornfile-override-compute-class/expected.golden b/pkg/controller/resolvedofferings/testdata/computeclass/acornfile-override-compute-class/expected.golden index 40315968a..8a9683ce7 100644 --- a/pkg/controller/resolvedofferings/testdata/computeclass/acornfile-override-compute-class/expected.golden +++ b/pkg/controller/resolvedofferings/testdata/computeclass/acornfile-override-compute-class/expected.golden @@ -49,7 +49,6 @@ status: resolvedOfferings: containers: "": - class: sample-compute-class memory: 0 left: class: sample-compute-class diff --git a/pkg/controller/resolvedofferings/testdata/computeclass/compute-class-default/expected.golden b/pkg/controller/resolvedofferings/testdata/computeclass/compute-class-default/expected.golden index 3b46bd188..cfa85853d 100644 --- a/pkg/controller/resolvedofferings/testdata/computeclass/compute-class-default/expected.golden +++ b/pkg/controller/resolvedofferings/testdata/computeclass/compute-class-default/expected.golden @@ -48,7 +48,6 @@ status: resolvedOfferings: containers: "": - class: sample-compute-class memory: 0 left: class: sample-compute-class diff --git a/pkg/controller/resolvedofferings/testdata/computeclass/user-override-compute-class/expected.golden b/pkg/controller/resolvedofferings/testdata/computeclass/user-override-compute-class/expected.golden index bcb2ab7b6..389cdb743 100644 --- a/pkg/controller/resolvedofferings/testdata/computeclass/user-override-compute-class/expected.golden +++ b/pkg/controller/resolvedofferings/testdata/computeclass/user-override-compute-class/expected.golden @@ -51,7 +51,6 @@ status: resolvedOfferings: containers: "": - class: sample-compute-class memory: 0 left: class: sample-compute-class diff --git a/pkg/project/handlers.go b/pkg/project/handlers.go index 7ff4f7c5d..8a4edcebe 100644 --- a/pkg/project/handlers.go +++ b/pkg/project/handlers.go @@ -1,11 +1,13 @@ package project import ( + "fmt" "time" "github.com/acorn-io/baaah/pkg/router" apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1" v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" + "github.com/acorn-io/runtime/pkg/computeclasses" "github.com/acorn-io/runtime/pkg/labels" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -20,9 +22,23 @@ func SetDefaultComputeClass(req router.Request, resp router.Response) error { project := req.Object.(*v1.ProjectInstance) if cc := project.Spec.DefaultComputeClass; cc != "" && project.Status.DefaultComputeClass != cc { + // The spec has been changed, update the status field to match. project.Status.DefaultComputeClass = cc } + // Check if the given compute class exists + if project.Status.DefaultComputeClass != "" { + if _, err := computeclasses.GetAsProjectComputeClassInstance(req.Ctx, req.Client, project.Status.Namespace, project.Status.DefaultComputeClass); err != nil { + if !apierrors.IsNotFound(err) { + return fmt.Errorf("failed to check existence of default compute class on project [%s] status: %w", project.Name, err) + } + + // The compute class does not exist, clear the status field. + project.Status.DefaultComputeClass = "" + } + // TODO(njhale): Unset the status field if the project does not support the same regions as the compute class? + } + resp.Objects(req.Object) return nil }