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

Enable setting a default ComputeClass on projects #2470

Closed
wants to merge 10 commits into from
Prev Previous commit
Next Next commit
refactor: return error when project specified cc does not exist
Signed-off-by: Nick Hale <4175918+njhale@users.noreply.github.com>
  • Loading branch information
njhale committed Feb 20, 2024
commit bff7e26963be0ec2ac41e401fb5616f81c47a907
119 changes: 54 additions & 65 deletions pkg/apis/internal.admin.acorn.io/v1/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,62 @@ import (

internalv1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1"
"github.com/acorn-io/z"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/controller-runtime/pkg/client"
apierrors "k8s.io/apimachinery/pkg/api/errors"
kclient "sigs.k8s.io/controller-runtime/pkg/client"
)

func getCurrentClusterComputeClassDefault(ctx context.Context, c client.Client, projectSpecified string) (*ClusterComputeClassInstance, error) {
// GetDefaultComputeClassName gets the name of the effective default ComputeClass for a given project namespace.
// The precedence for picking the default ComputeClass is as follows:
// 1. Any ProjectComputeClassInstance (in the project namespace) or ClusterComputeClassInstance that is specified by the
// ProjectInstance's DefaultComputeClass field
// 2. The ProjectComputeClassInstance (in the project namespace) with a Default field set to true
// 3. The ClusterComputeClassInstance with a Default field set to true
//
// If no default ComputeClass is found, an empty string is returned.
// If the project specifies a default compute class that doesn't exist, an error is returned.
func GetDefaultComputeClassName(ctx context.Context, c kclient.Client, namespace string) (string, error) {
var project internalv1.ProjectInstance
if err := c.Get(ctx, kclient.ObjectKey{Name: namespace}, &project); err != nil {
return "", fmt.Errorf("failed to get project instance to determine default compute class: %w", err)
}

if projectSpecified := project.Status.DefaultComputeClass; projectSpecified != "" {
if err := lookupComputeClass(ctx, c, namespace, projectSpecified); err != nil {
if apierrors.IsNotFound(err) {
return "", fmt.Errorf("project specified default compute class [%v] does not exist: %w", projectSpecified, err)
}
return "", fmt.Errorf("failed to get project specified default compute class [%v]: %w", projectSpecified, err)
}

return projectSpecified, nil
}

if pcc, err := getCurrentProjectComputeClassDefault(ctx, c, namespace); err != nil {
return "", err
} else if pcc != nil && pcc.Name != "" {
return pcc.Name, nil
}

if ccc, err := getCurrentClusterComputeClassDefault(ctx, c); err != nil {
return "", err
} else if ccc != nil && ccc.Name != "" {
return ccc.Name, nil
}

return "", nil
}

func getCurrentClusterComputeClassDefault(ctx context.Context, c kclient.Client) (*ClusterComputeClassInstance, error) {
var clusterComputeClasses ClusterComputeClassInstanceList
if err := c.List(ctx, &clusterComputeClasses, &client.ListOptions{}); err != nil {
if err := c.List(ctx, &clusterComputeClasses, &kclient.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, projectSpecifiedCCC *ClusterComputeClassInstance
var defaultCCC *ClusterComputeClassInstance
for _, clusterComputeClass := range clusterComputeClasses.Items {
if clusterComputeClass.Default {
if defaultCCC != nil {
Expand All @@ -30,33 +71,24 @@ func getCurrentClusterComputeClassDefault(ctx context.Context, c client.Client,
defaultCCC.Name, clusterComputeClass.Name)
}

// Create a new variable that isn't being iterated on to get a pointer
defaultCCC = z.Pointer(clusterComputeClass)
}

if projectSpecified != "" && clusterComputeClass.Name == projectSpecified {
projectSpecifiedCCC = z.Pointer(clusterComputeClass)
}
}

if projectSpecifiedCCC != nil {
return projectSpecifiedCCC, nil
}

return defaultCCC, nil
}

func getCurrentProjectComputeClassDefault(ctx context.Context, c client.Client, projectSpecified, namespace string) (*ProjectComputeClassInstance, error) {
func getCurrentProjectComputeClassDefault(ctx context.Context, c kclient.Client, namespace string) (*ProjectComputeClassInstance, error) {
var projectComputeClasses ProjectComputeClassInstanceList
if err := c.List(ctx, &projectComputeClasses, &client.ListOptions{Namespace: namespace}); err != nil {
if err := c.List(ctx, &projectComputeClasses, &kclient.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, projectSpecifiedPCC *ProjectComputeClassInstance
var defaultPCC *ProjectComputeClassInstance
for _, projectComputeClass := range projectComputeClasses.Items {
if projectComputeClass.Default {
if defaultPCC != nil {
Expand All @@ -65,61 +97,18 @@ func getCurrentProjectComputeClassDefault(ctx context.Context, c client.Client,
defaultPCC.Name, projectComputeClass.Name)
}

// Create a new variable that isn't being iterated on to get a pointer
defaultPCC = z.Pointer(projectComputeClass)
}

if projectSpecified != "" && projectComputeClass.Name == projectSpecified {
projectSpecifiedPCC = z.Pointer(projectComputeClass)
}
}

if projectSpecifiedPCC != nil {
return projectSpecifiedPCC, nil
}

return defaultPCC, nil
}

// GetDefaultComputeClassName gets the name of the effective default ComputeClass for a given project namespace.
// The precedence for picking the default ComputeClass is as follows:
// 1. Any ProjectComputeClassInstance (in the project namespace) or ClusterComputeClassInstance that is specified by the
// ProjectInstance's DefaultComputeClass field
// 2. The ProjectComputeClassInstance (in the project namespace) with a Default field set to true
// 3. The ClusterComputeClassInstance with a Default field set to true
//
// If no default ComputeClass is found, an empty string is returned.
func GetDefaultComputeClassName(ctx context.Context, c client.Client, namespace string) (string, error) {
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)
}
projectSpecified := project.Status.DefaultComputeClass

var defaultComputeClasses []string
pcc, err := getCurrentProjectComputeClassDefault(ctx, c, projectSpecified, namespace)
if err != nil {
return "", err
}
if pcc != nil {
defaultComputeClasses = append(defaultComputeClasses, pcc.Name)
}

ccc, err := getCurrentClusterComputeClassDefault(ctx, c, projectSpecified)
if err != nil {
return "", err
}
if ccc != nil {
defaultComputeClasses = append(defaultComputeClasses, ccc.Name)
}

if sets.New(defaultComputeClasses...).Has(projectSpecified) {
return projectSpecified, nil
func lookupComputeClass(ctx context.Context, c kclient.Client, namespace, name string) error {
if err := c.Get(ctx, kclient.ObjectKey{Namespace: namespace, Name: name},
new(ProjectComputeClassInstance)); kclient.IgnoreNotFound(err) != nil {
return err
}

if len(defaultComputeClasses) > 0 {
return defaultComputeClasses[0], nil
}

return "", nil
return c.Get(ctx, kclient.ObjectKey{Namespace: "", Name: name}, new(ClusterComputeClassInstance))
}
4 changes: 2 additions & 2 deletions pkg/apis/internal.admin.acorn.io/v1/default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ func TestGetDefaultComputeClass(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{
Name: "pcc-project",
},
Spec: internalv1.ProjectInstanceSpec{
Status: internalv1.ProjectInstanceStatus{
DefaultComputeClass: "project-specified-default",
},
},
Expand All @@ -185,7 +185,7 @@ func TestGetDefaultComputeClass(t *testing.T) {
).Build(),
},
expected: expected{
computeClassName: "self-specified-default",
error: true,
},
},
} {
Expand Down