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

fix: remove resolvedOfferings, defaults, and scheduling for containers not defined in app #2468

Merged
merged 2 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions pkg/apis/internal.acorn.io/v1/appinstance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package v1
import (
"strings"

"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -122,6 +124,19 @@ func (in *AppInstance) GetStopped() bool {
return in.Spec.Stop != nil && *in.Spec.Stop && in.DeletionTimestamp.IsZero()
}

// GetAllContainerNames returns a string slice containing the name of every container, job, and sidecar defined in Status.AppSpec.
func (in *AppInstance) GetAllContainerNames() []string {
allContainers := append(maps.Keys(in.Status.AppSpec.Containers), maps.Keys(in.Status.AppSpec.Jobs)...)
for _, container := range in.Status.AppSpec.Containers {
allContainers = append(allContainers, maps.Keys(container.Sidecars)...)
}
for _, job := range in.Status.AppSpec.Jobs {
allContainers = append(allContainers, maps.Keys(job.Sidecars)...)
}
slices.Sort[[]string](allContainers)
return allContainers
}

func (in *AppInstanceSpec) GetAutoUpgrade() bool {
return in.AutoUpgrade != nil && *in.AutoUpgrade
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/controller/defaults/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
adminv1 "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1"
"github.com/acorn-io/runtime/pkg/computeclasses"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/utils/strings/slices"
)

// defaultMemory calculates the default that should be used and considers the defaults from the Config, ComputeClass, and
Expand Down Expand Up @@ -54,6 +55,17 @@ func addDefaultMemory(req router.Request, cfg *apiv1.Config, appInstance *v1.App
return err
}

// Remove any memory defaults for containers that are no longer defined in the app.
allContainers := appInstance.GetAllContainerNames()
for containerName := range appInstance.Status.Defaults.Memory {
if containerName == "" {
continue
}
if !slices.Contains(allContainers, containerName) {
delete(appInstance.Status.Defaults.Memory, containerName)
}
}

return nil
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/controller/defaults/memory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@ func TestTwoPCCDefaultsShouldError(t *testing.T) {

assert.True(t, resp.NoPrune, "NoPrune should be true when error occurs")
}

func TestRemovedContainer(t *testing.T) {
tester.DefaultTest(t, scheme.Scheme, "testdata/memory/removed-container", Calculate)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
kind: ProjectInstance
apiVersion: internal.acorn.io/v1
metadata:
name: app-namespace
spec: {}
status:
defaultRegion: local
supportedRegions:
- local
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
`apiVersion: internal.acorn.io/v1
kind: AppInstance
metadata:
creationTimestamp: null
name: app-name
namespace: app-namespace
uid: 1234567890abcdef
spec:
image: test
memory:
oneimage: 1048576
status:
appImage:
buildContext: {}
id: test
imageData: {}
vcs: {}
appSpec:
containers:
oneimage:
build:
context: .
dockerfile: Dockerfile
image: image-name
metrics: {}
ports:
- port: 80
protocol: http
targetPort: 81
probes: null
sidecars:
left:
image: foo
metrics: {}
ports:
- port: 90
protocol: tcp
targetPort: 91
probes: null
appStatus: {}
columns: {}
conditions:
reason: Success
status: "True"
success: true
type: defaults
defaults:
memory:
"": 0
left: 0
oneimage: 0
region: local
namespace: app-created-namespace
observedGeneration: 1
resolvedOfferings: {}
staged:
appImage:
buildContext: {}
imageData: {}
vcs: {}
summary: {}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
kind: AppInstance
apiVersion: internal.acorn.io/v1
metadata:
name: app-name
namespace: app-namespace
uid: 1234567890abcdef
spec:
image: test
memory:
oneimage: 1048576 # 1Mi
status:
observedGeneration: 1
namespace: app-created-namespace
appImage:
id: test
appSpec:
containers:
oneimage:
sidecars:
left:
image: "foo"
ports:
- port: 90
targetPort: 91
protocol: tcp
ports:
- port: 80
targetPort: 81
protocol: http
image: "image-name"
build:
dockerfile: "Dockerfile"
context: "."
defaults:
memory:
twoimage: 0
12 changes: 12 additions & 0 deletions pkg/controller/resolvedofferings/computeclass.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
adminv1 "github.com/acorn-io/runtime/pkg/apis/internal.admin.acorn.io/v1"
"github.com/acorn-io/runtime/pkg/computeclasses"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/utils/strings/slices"
)

// resolveComputeClasses resolves the compute class information for each container in the AppInstance
Expand Down Expand Up @@ -69,6 +70,17 @@ func resolveComputeClasses(req router.Request, cfg *apiv1.Config, appInstance *v
return err
}

// Remove any resolved offerings for containers that are no longer defined in the app.
allContainers := appInstance.GetAllContainerNames()
for containerName := range appInstance.Status.ResolvedOfferings.Containers {
if containerName == "" {
continue
}
if !slices.Contains(allContainers, containerName) {
delete(appInstance.Status.ResolvedOfferings.Containers, containerName)
}
}

return nil
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/controller/resolvedofferings/computeclass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@ func TestUserOverrideComputeClass(t *testing.T) {
func TestWithAcornfileMemoryAndSpecOverride(t *testing.T) {
tester.DefaultTest(t, scheme.Scheme, "testdata/computeclass/with-acornfile-memory-and-spec-override", Calculate)
}

func TestRemovedContainer(t *testing.T) {
tester.DefaultTest(t, scheme.Scheme, "testdata/computeclass/removed-container", Calculate)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
kind: ProjectInstance
apiVersion: internal.acorn.io/v1
metadata:
name: app-namespace
spec: {}
status:
defaultRegion: local
supportedRegions:
- local
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
`apiVersion: internal.acorn.io/v1
kind: AppInstance
metadata:
creationTimestamp: null
name: app-name
namespace: app-namespace
uid: 1234567890abcdef
spec:
image: test
memory:
oneimage: 1048576
status:
appImage:
buildContext: {}
id: test
imageData: {}
vcs: {}
appSpec:
containers:
oneimage:
build:
context: .
dockerfile: Dockerfile
image: image-name
metrics: {}
ports:
- port: 80
protocol: http
targetPort: 81
probes: null
sidecars:
left:
image: foo
metrics: {}
ports:
- port: 90
protocol: tcp
targetPort: 91
probes: null
appStatus: {}
columns: {}
conditions:
reason: Success
status: "True"
success: true
type: resolved-offerings
defaults: {}
namespace: app-created-namespace
observedGeneration: 1
resolvedOfferings:
containers:
"":
memory: 0
left:
memory: 0
oneimage:
memory: 1048576
region: local
staged:
appImage:
buildContext: {}
imageData: {}
vcs: {}
summary: {}
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
kind: AppInstance
apiVersion: internal.acorn.io/v1
metadata:
name: app-name
namespace: app-namespace
uid: 1234567890abcdef
spec:
image: test
memory:
oneimage: 1048576 # 1Mi
status:
observedGeneration: 1
namespace: app-created-namespace
appImage:
id: test
appSpec:
containers:
oneimage:
sidecars:
left:
image: "foo"
ports:
- port: 90
targetPort: 91
protocol: tcp
ports:
- port: 80
targetPort: 81
protocol: http
image: "image-name"
build:
dockerfile: "Dockerfile"
context: "."
resolvedOfferings:
containers:
twoimage:
memory: 0
4 changes: 4 additions & 0 deletions pkg/controller/scheduling/computeclass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,7 @@ func TestInvalidPriorityClassShouldError(t *testing.T) {

assert.True(t, resp.NoPrune, "NoPrune should be true when error occurs")
}

func TestRemovedContainerComputeClass(t *testing.T) {
tester.DefaultTest(t, scheme.Scheme, "testdata/computeclass/removed-container", Calculate)
}
4 changes: 4 additions & 0 deletions pkg/controller/scheduling/memory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ func TestAllSetOverwrite(t *testing.T) {
func TestSameGenerationMemory(t *testing.T) {
tester.DefaultTest(t, scheme.Scheme, "testdata/memory/same-generation", Calculate)
}

func TestRemovedContainerMemory(t *testing.T) {
tester.DefaultTest(t, scheme.Scheme, "testdata/memory/removed-container", Calculate)
}
10 changes: 10 additions & 0 deletions pkg/controller/scheduling/scheduling.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
nodev1 "k8s.io/api/node/v1"
schedulingv1 "k8s.io/api/scheduling/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/utils/strings/slices"
)

// Calculate is a handler that sets the scheduling rules for an AppInstance to its
Expand Down Expand Up @@ -49,6 +50,15 @@ func calculate(req router.Request, appInstance *v1.AppInstance) error {
if err := addScheduling(req, appInstance, appInstance.Status.AppSpec.Jobs); err != nil {
return err
}

// Remove any scheduling information for containers that are no longer defined in the app.
allContainers := appInstance.GetAllContainerNames()
for containerName := range appInstance.Status.Scheduling {
if !slices.Contains(allContainers, containerName) {
delete(appInstance.Status.Scheduling, containerName)
}
}

return nil
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
kind: ClusterComputeClassInstance
apiVersion: internal.admin.acorn.io/v1
metadata:
name: sample-compute-class
description: Simple description for a simple ComputeClass
cpuScaler: 0.25
memory:
min: 1Mi # 1Mi
max: 2Mi # 2Mi
default: 1Mi # 1Mi
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: foo
operator: In
values:
- bar
Loading
Loading