This is an automated email from the ASF dual-hosted git repository.
pbacsko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-core.git
The following commit(s) were added to refs/heads/master by this push:
new d765f3a4 [YUNIKORN-1801] add allocation events (#571)
d765f3a4 is described below
commit d765f3a4e1fff8607a27b2206be76e43df0cee2b
Author: Frank Yang <[email protected]>
AuthorDate: Thu Jun 22 15:40:22 2023 +0200
[YUNIKORN-1801] add allocation events (#571)
Signed-off-by: Frank Yang <[email protected]>
Closes: #571
Signed-off-by: Peter Bacsko <[email protected]>
---
pkg/scheduler/objects/application.go | 28 ++
pkg/scheduler/objects/application_events.go | 122 ++++++++
pkg/scheduler/objects/application_events_test.go | 345 +++++++++++++++++++++++
pkg/scheduler/objects/application_test.go | 123 +++++++-
pkg/scheduler/objects/events.go | 59 ----
pkg/scheduler/objects/events_test.go | 91 ------
pkg/scheduler/objects/utilities_test.go | 1 +
pkg/scheduler/partition_test.go | 183 +++++++++++-
8 files changed, 792 insertions(+), 160 deletions(-)
diff --git a/pkg/scheduler/objects/application.go
b/pkg/scheduler/objects/application.go
index 961f46cb..4de1764c 100644
--- a/pkg/scheduler/objects/application.go
+++ b/pkg/scheduler/objects/application.go
@@ -536,6 +536,7 @@ func (sa *Application) GetPendingResource()
*resources.Resource {
func (sa *Application) RemoveAllocationAsk(allocKey string) int {
sa.Lock()
defer sa.Unlock()
+ sa.sendRemoveAskEvent(allocKey)
return sa.removeAsksInternal(allocKey)
}
@@ -675,6 +676,7 @@ func (sa *Application) AddAllocationAsk(ask *AllocationAsk)
error {
zap.Stringer("pendingDelta", delta))
sa.sortedRequests.insert(ask)
+ sa.appEvents.sendNewAskEvent(ask)
return nil
}
@@ -1145,6 +1147,7 @@ func (sa *Application)
tryPlaceholderAllocate(nodeIterator func() NodeIterator,
log.Log(log.SchedApplication).Warn("ask
repeat update failed unexpectedly",
zap.Error(err))
}
+ sa.appEvents.sendRemoveAllocationEvent(ph,
si.TerminationType_PLACEHOLDER_REPLACED)
return alloc
}
}
@@ -1200,6 +1203,7 @@ func (sa *Application)
tryPlaceholderAllocate(nodeIterator func() NodeIterator,
log.Log(log.SchedApplication).Warn("ask repeat
update failed unexpectedly",
zap.Error(err))
}
+ sa.appEvents.sendRemoveAllocationEvent(phFit,
si.TerminationType_PLACEHOLDER_REPLACED)
return alloc
}
}
@@ -1476,6 +1480,8 @@ func (sa *Application) tryNode(node *Node, ask
*AllocationAsk) *Allocation {
}
// all is OK, last update for the app
sa.addAllocationInternal(alloc)
+
+ sa.appEvents.sendNewAllocationEvent(alloc)
// return allocation
return alloc
}
@@ -1770,6 +1776,11 @@ func (sa *Application) removeAllocationInternal(uuid
string, releaseType si.Term
}
}
delete(sa.allocations, uuid)
+ // If release count of placeholder is 0 and termination type is
PLACEHOLDER_REPLACED,
+ // the placeholder has already been replaced. No need to send remove
event.
+ if !(alloc.IsPlaceholder() && alloc.GetReleaseCount() == 0 &&
releaseType == si.TerminationType_PLACEHOLDER_REPLACED) {
+ sa.appEvents.sendRemoveAllocationEvent(alloc, releaseType)
+ }
return alloc
}
@@ -1900,6 +1911,7 @@ func (sa *Application) notifyRMAllocationReleased(rmID
string, released []*Alloc
TerminationType: terminationType,
Message: message,
})
+ sa.appEvents.sendRemoveAllocationEvent(alloc, terminationType)
}
sa.rmEventHandler.HandleEvent(releaseEvent)
// Wait from channel
@@ -1931,6 +1943,7 @@ func (sa *Application) notifyRMAllocationAskReleased(rmID
string, released []*Al
TerminationType: terminationType,
Message: message,
})
+ sa.appEvents.sendRemoveAskEvent(alloc, terminationType, false)
}
sa.rmEventHandler.HandleEvent(releaseEvent)
}
@@ -2009,3 +2022,18 @@ func (sa *Application)
SetTimedOutPlaceholder(taskGroupName string, timedOut int
sa.placeholderData[taskGroupName].TimedOut = timedOut
}
}
+
+func (sa *Application) sendRemoveAskEvent(allocKey string) {
+ if allocKey != "" {
+ // if allocKey is not empty, it means a specific ask is being
terminated
+ if ask := sa.requests[allocKey]; ask != nil {
+ sa.appEvents.sendRemoveAskEvent(ask,
si.TerminationType_STOPPED_BY_RM, false)
+ }
+ return
+ }
+
+ // if allocKey is empty, it means application is terminated
+ for _, ask := range sa.requests {
+ sa.appEvents.sendRemoveAskEvent(ask,
si.TerminationType_STOPPED_BY_RM, true)
+ }
+}
diff --git a/pkg/scheduler/objects/application_events.go
b/pkg/scheduler/objects/application_events.go
new file mode 100644
index 00000000..049ee626
--- /dev/null
+++ b/pkg/scheduler/objects/application_events.go
@@ -0,0 +1,122 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package objects
+
+import (
+ "fmt"
+
+ "github.com/apache/yunikorn-core/pkg/events"
+ "github.com/apache/yunikorn-scheduler-interface/lib/go/si"
+)
+
+type applicationEvents struct {
+ enabled bool
+ eventSystem events.EventSystem
+ app *Application
+}
+
+func (evt *applicationEvents) sendAppDoesNotFitEvent(request *AllocationAsk) {
+ if !evt.enabled {
+ return
+ }
+
+ message := fmt.Sprintf("Application %s does not fit into %s queue",
request.GetApplicationID(), evt.app.queuePath)
+ event := events.CreateRequestEventRecord(request.GetAllocationKey(),
request.GetApplicationID(), message, request.GetAllocatedResource())
+ evt.eventSystem.AddEvent(event)
+}
+
+func (evt *applicationEvents) sendPlaceholderLargerEvent(ph *Allocation,
request *AllocationAsk) {
+ if !evt.enabled {
+ return
+ }
+
+ message := fmt.Sprintf("Task group '%s' in application '%s': allocation
resources '%s' are not matching placeholder '%s' allocation with ID '%s'",
ph.GetTaskGroup(), evt.app.ApplicationID,
request.GetAllocatedResource().String(), ph.GetAllocatedResource().String(),
ph.GetAllocationKey())
+ event := events.CreateRequestEventRecord(ph.GetAllocationKey(),
evt.app.ApplicationID, message, request.GetAllocatedResource())
+ evt.eventSystem.AddEvent(event)
+}
+
+func (evt *applicationEvents) sendNewAllocationEvent(alloc *Allocation) {
+ if !evt.enabled {
+ return
+ }
+
+ event := events.CreateAppEventRecord(evt.app.ApplicationID, "",
alloc.GetUUID(), si.EventRecord_ADD, si.EventRecord_APP_ALLOC,
alloc.GetAllocatedResource())
+ evt.eventSystem.AddEvent(event)
+}
+
+func (evt *applicationEvents) sendNewAskEvent(request *AllocationAsk) {
+ if !evt.enabled {
+ return
+ }
+
+ event := events.CreateAppEventRecord(evt.app.ApplicationID, "",
request.GetAllocationKey(), si.EventRecord_ADD, si.EventRecord_APP_REQUEST,
request.GetAllocatedResource())
+ evt.eventSystem.AddEvent(event)
+}
+
+func (evt *applicationEvents) sendRemoveAllocationEvent(alloc *Allocation,
terminationType si.TerminationType) {
+ if !evt.enabled {
+ return
+ }
+
+ var eventChangeDetail si.EventRecord_ChangeDetail
+ switch terminationType {
+ case si.TerminationType_UNKNOWN_TERMINATION_TYPE:
+ eventChangeDetail = si.EventRecord_ALLOC_NODEREMOVED
+ case si.TerminationType_STOPPED_BY_RM:
+ eventChangeDetail = si.EventRecord_ALLOC_CANCEL
+ case si.TerminationType_TIMEOUT:
+ eventChangeDetail = si.EventRecord_ALLOC_TIMEOUT
+ case si.TerminationType_PREEMPTED_BY_SCHEDULER:
+ eventChangeDetail = si.EventRecord_ALLOC_PREEMPT
+ case si.TerminationType_PLACEHOLDER_REPLACED:
+ eventChangeDetail = si.EventRecord_ALLOC_REPLACED
+ }
+
+ event := events.CreateAppEventRecord(evt.app.ApplicationID, "",
alloc.GetUUID(), si.EventRecord_REMOVE, eventChangeDetail,
alloc.GetAllocatedResource())
+ evt.eventSystem.AddEvent(event)
+}
+
+func (evt *applicationEvents) sendRemoveAskEvent(request *AllocationAsk,
terminationType si.TerminationType, appRemoved bool) {
+ if !evt.enabled {
+ return
+ }
+
+ var eventChangeDetail si.EventRecord_ChangeDetail
+ switch terminationType {
+ case si.TerminationType_TIMEOUT:
+ eventChangeDetail = si.EventRecord_REQUEST_TIMEOUT
+ case si.TerminationType_STOPPED_BY_RM:
+ if appRemoved {
+ eventChangeDetail = si.EventRecord_REQUEST_CANCEL
+ } else {
+ eventChangeDetail = si.EventRecord_APP_REQUEST
+ }
+ }
+
+ event := events.CreateAppEventRecord(evt.app.ApplicationID, "",
request.GetAllocationKey(), si.EventRecord_REMOVE, eventChangeDetail,
request.GetAllocatedResource())
+ evt.eventSystem.AddEvent(event)
+}
+
+func newApplicationEvents(app *Application, evt events.EventSystem)
*applicationEvents {
+ return &applicationEvents{
+ eventSystem: evt,
+ enabled: evt != nil,
+ app: app,
+ }
+}
diff --git a/pkg/scheduler/objects/application_events_test.go
b/pkg/scheduler/objects/application_events_test.go
new file mode 100644
index 00000000..e8a284bb
--- /dev/null
+++ b/pkg/scheduler/objects/application_events_test.go
@@ -0,0 +1,345 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package objects
+
+import (
+ "testing"
+
+ "gotest.tools/v3/assert"
+
+ "github.com/apache/yunikorn-scheduler-interface/lib/go/si"
+)
+
+type EventSystemMock struct {
+ events []*si.EventRecord
+}
+
+func (m *EventSystemMock) AddEvent(event *si.EventRecord) {
+ m.events = append(m.events, event)
+}
+
+func (m *EventSystemMock) StartService() {}
+
+func (m *EventSystemMock) Stop() {}
+
+func newEventSystemMock() *EventSystemMock {
+ return &EventSystemMock{events: make([]*si.EventRecord, 0)}
+}
+
+func TestSendAppDoesNotFitEvent(t *testing.T) {
+ app := &Application{
+ queuePath: "root.test",
+ }
+
+ // not enabled
+ evt := newApplicationEvents(app, nil)
+ assert.Assert(t, evt.eventSystem == nil, "event system should be nil")
+ assert.Assert(t, !evt.enabled, "event system should be disabled")
+ evt.sendAppDoesNotFitEvent(&AllocationAsk{})
+
+ // enabled
+ mock := newEventSystemMock()
+ evt = newApplicationEvents(app, mock)
+ assert.Assert(t, evt.eventSystem != nil, "event system should not be
nil")
+ assert.Assert(t, evt.enabled, "event system should be enabled")
+ evt.sendAppDoesNotFitEvent(&AllocationAsk{
+ applicationID: appID0,
+ allocationKey: aKey,
+ })
+ assert.Equal(t, 1, len(mock.events), "event was not generated")
+}
+
+func TestSendPlaceholderLargerEvent(t *testing.T) {
+ app := &Application{
+ queuePath: "root.test",
+ }
+
+ // not enabled
+ evt := newApplicationEvents(app, nil)
+ assert.Assert(t, evt.eventSystem == nil, "event system should be nil")
+ assert.Assert(t, !evt.enabled, "event system should be disabled")
+ evt.sendPlaceholderLargerEvent(&Allocation{}, &AllocationAsk{})
+
+ // enabled
+ mock := newEventSystemMock()
+ evt = newApplicationEvents(app, mock)
+ assert.Assert(t, evt.eventSystem != nil, "event system should not be
nil")
+ assert.Assert(t, evt.enabled, "event system should be enabled")
+ evt.sendPlaceholderLargerEvent(&Allocation{
+ allocationKey: aKey,
+ }, &AllocationAsk{
+ applicationID: appID0,
+ allocationKey: aKey,
+ })
+ assert.Equal(t, 1, len(mock.events), "event was not generated")
+}
+
+func TestSendNewAllocationEvent(t *testing.T) {
+ app := &Application{
+ ApplicationID: appID0,
+ queuePath: "root.test",
+ }
+
+ // not enabled
+ evt := newApplicationEvents(app, nil)
+ assert.Assert(t, evt.eventSystem == nil, "event system should be nil")
+ assert.Assert(t, !evt.enabled, "event system should be disabled")
+ evt.sendNewAllocationEvent(&Allocation{})
+
+ // enabled
+ mock := newEventSystemMock()
+ evt = newApplicationEvents(app, mock)
+ assert.Assert(t, evt.eventSystem != nil, "event system should not be
nil")
+ assert.Assert(t, evt.enabled, "event system should be enabled")
+ evt.sendNewAllocationEvent(&Allocation{
+ applicationID: appID0,
+ allocationKey: aKey,
+ uuid: aUUID,
+ })
+ assert.Equal(t, 1, len(mock.events), "event was not generated")
+ assert.Equal(t, si.EventRecord_APP, mock.events[0].Type, "event type is
not expected")
+ assert.Equal(t, si.EventRecord_ADD, mock.events[0].EventChangeType,
"event change type is not expected")
+ assert.Equal(t, si.EventRecord_APP_ALLOC,
mock.events[0].EventChangeDetail, "event change detail is not expected")
+ assert.Equal(t, appID0, mock.events[0].ObjectID, "event object id is
not expected")
+ assert.Equal(t, aUUID, mock.events[0].ReferenceID, "event reference id
is not expected")
+}
+
+func TestSendNewAskEvent(t *testing.T) {
+ app := &Application{
+ ApplicationID: appID0,
+ queuePath: "root.test",
+ }
+
+ // not enabled
+ evt := newApplicationEvents(app, nil)
+ assert.Assert(t, evt.eventSystem == nil, "event system should be nil")
+ assert.Assert(t, !evt.enabled, "event system should be disabled")
+ evt.sendNewAskEvent(&AllocationAsk{})
+
+ // enabled
+ mock := newEventSystemMock()
+ evt = newApplicationEvents(app, mock)
+ assert.Assert(t, evt.eventSystem != nil, "event system should not be
nil")
+ assert.Assert(t, evt.enabled, "event system should be enabled")
+ evt.sendNewAskEvent(&AllocationAsk{
+ applicationID: appID0,
+ allocationKey: aKey,
+ })
+ assert.Equal(t, 1, len(mock.events), "event was not generated")
+ assert.Equal(t, si.EventRecord_APP, mock.events[0].Type, "event type is
not expected")
+ assert.Equal(t, si.EventRecord_ADD, mock.events[0].EventChangeType,
"event change type is not expected")
+ assert.Equal(t, si.EventRecord_APP_REQUEST,
mock.events[0].EventChangeDetail, "event change detail is not expected")
+ assert.Equal(t, appID0, mock.events[0].ObjectID, "event object id is
not expected")
+ assert.Equal(t, aKey, mock.events[0].ReferenceID, "event reference id
is not expected")
+}
+
+func TestSendRemoveAllocationEvent(t *testing.T) {
+ app := &Application{
+ ApplicationID: appID0,
+ queuePath: "root.test",
+ }
+
+ testCases := []struct {
+ name string
+ eventSystemMock *EventSystemMock
+ terminationType si.TerminationType
+ allocation *Allocation
+ expectedEventCnt int
+ expectedType si.EventRecord_Type
+ expectedChangeType si.EventRecord_ChangeType
+ expectedChangeDetail si.EventRecord_ChangeDetail
+ expectedObjectID string
+ expectedReferenceID string
+ }{
+ {
+ name: "disabled event system",
+ eventSystemMock: nil,
+ terminationType:
si.TerminationType_UNKNOWN_TERMINATION_TYPE,
+ allocation: &Allocation{},
+ },
+ {
+ name: "remove allocation cause of node
removal",
+ eventSystemMock: newEventSystemMock(),
+ terminationType:
si.TerminationType_UNKNOWN_TERMINATION_TYPE,
+ allocation: &Allocation{applicationID:
appID0, allocationKey: aKey, uuid: aUUID},
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_ALLOC_NODEREMOVED,
+ expectedObjectID: appID0,
+ expectedReferenceID: aUUID,
+ },
+ {
+ name: "remove allocation cause of
resource manager cancel",
+ eventSystemMock: newEventSystemMock(),
+ terminationType: si.TerminationType_STOPPED_BY_RM,
+ allocation: &Allocation{applicationID:
appID0, allocationKey: aKey, uuid: aUUID},
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_ALLOC_CANCEL,
+ expectedObjectID: appID0,
+ expectedReferenceID: aUUID,
+ },
+ {
+ name: "remove allocation cause of
timeout",
+ eventSystemMock: newEventSystemMock(),
+ terminationType: si.TerminationType_TIMEOUT,
+ allocation: &Allocation{applicationID:
appID0, allocationKey: aKey, uuid: aUUID},
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_ALLOC_TIMEOUT,
+ expectedObjectID: appID0,
+ expectedReferenceID: aUUID,
+ },
+ {
+ name: "remove allocation cause of
preemption",
+ eventSystemMock: newEventSystemMock(),
+ terminationType:
si.TerminationType_PREEMPTED_BY_SCHEDULER,
+ allocation: &Allocation{applicationID:
appID0, allocationKey: aKey, uuid: aUUID},
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_ALLOC_PREEMPT,
+ expectedObjectID: appID0,
+ expectedReferenceID: aUUID,
+ },
+ {
+ name: "remove allocation cause of
replacement",
+ eventSystemMock: newEventSystemMock(),
+ terminationType:
si.TerminationType_PLACEHOLDER_REPLACED,
+ allocation: &Allocation{applicationID:
appID0, allocationKey: aKey, uuid: aUUID},
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_ALLOC_REPLACED,
+ expectedObjectID: appID0,
+ expectedReferenceID: aUUID,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ if testCase.eventSystemMock == nil {
+ evt := newApplicationEvents(app, nil)
+ assert.Assert(t, evt.eventSystem == nil, "event
system should be nil")
+ assert.Assert(t, !evt.enabled, "event system
should be disabled")
+
evt.sendRemoveAllocationEvent(testCase.allocation, testCase.terminationType)
+ } else {
+ evt := newApplicationEvents(app,
testCase.eventSystemMock)
+ assert.Assert(t, evt.eventSystem != nil, "event
system should not be nil")
+ assert.Assert(t, evt.enabled, "event system
should be enabled")
+
evt.sendRemoveAllocationEvent(testCase.allocation, testCase.terminationType)
+ assert.Equal(t, testCase.expectedEventCnt,
len(testCase.eventSystemMock.events), "event was not generated")
+ assert.Equal(t, testCase.expectedType,
testCase.eventSystemMock.events[0].Type, "event type is not expected")
+ assert.Equal(t, testCase.expectedChangeType,
testCase.eventSystemMock.events[0].EventChangeType, "event change type is not
expected")
+ assert.Equal(t, testCase.expectedChangeDetail,
testCase.eventSystemMock.events[0].EventChangeDetail, "event change detail is
not expected")
+ assert.Equal(t, testCase.expectedObjectID,
testCase.eventSystemMock.events[0].ObjectID, "event object id is not expected")
+ assert.Equal(t, testCase.expectedReferenceID,
testCase.eventSystemMock.events[0].ReferenceID, "event reference id is not
expected")
+ }
+ })
+ }
+}
+
+func TestSendRemoveAskEvent(t *testing.T) {
+ app := &Application{
+ ApplicationID: appID0,
+ queuePath: "root.test",
+ }
+
+ testCases := []struct {
+ name string
+ eventSystemMock *EventSystemMock
+ terminationType si.TerminationType
+ appRemoved bool
+ allocationAsk *AllocationAsk
+ expectedEventCnt int
+ expectedType si.EventRecord_Type
+ expectedChangeType si.EventRecord_ChangeType
+ expectedChangeDetail si.EventRecord_ChangeDetail
+ expectedObjectID string
+ expectedReferenceID string
+ }{
+ {
+ name: "disabled event system",
+ eventSystemMock: nil,
+ terminationType:
si.TerminationType_UNKNOWN_TERMINATION_TYPE,
+ allocationAsk: &AllocationAsk{},
+ },
+ {
+ name: "remove allocation ask cause of
resource manager cancel",
+ eventSystemMock: newEventSystemMock(),
+ terminationType: si.TerminationType_STOPPED_BY_RM,
+ allocationAsk: &AllocationAsk{applicationID:
appID0, allocationKey: aKey},
+ appRemoved: false,
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_APP_REQUEST,
+ expectedObjectID: appID0,
+ expectedReferenceID: aKey,
+ },
+ {
+ name: "remove allocation ask cause of
timeout",
+ eventSystemMock: newEventSystemMock(),
+ terminationType: si.TerminationType_TIMEOUT,
+ allocationAsk: &AllocationAsk{applicationID:
appID0, allocationKey: aKey},
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_REQUEST_TIMEOUT,
+ expectedObjectID: appID0,
+ expectedReferenceID: aKey,
+ },
+ {
+ name: "remove allocation cause of
application removal",
+ eventSystemMock: newEventSystemMock(),
+ terminationType: si.TerminationType_STOPPED_BY_RM,
+ allocationAsk: &AllocationAsk{applicationID:
appID0, allocationKey: aKey},
+ appRemoved: true,
+ expectedEventCnt: 1,
+ expectedType: si.EventRecord_APP,
+ expectedChangeType: si.EventRecord_REMOVE,
+ expectedChangeDetail: si.EventRecord_REQUEST_CANCEL,
+ expectedObjectID: appID0,
+ expectedReferenceID: aKey,
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ if testCase.eventSystemMock == nil {
+ evt := newApplicationEvents(app, nil)
+ assert.Assert(t, evt.eventSystem == nil, "event
system should be nil")
+ assert.Assert(t, !evt.enabled, "event system
should be disabled")
+ evt.sendRemoveAskEvent(testCase.allocationAsk,
testCase.terminationType, testCase.appRemoved)
+ } else {
+ evt := newApplicationEvents(app,
testCase.eventSystemMock)
+ assert.Assert(t, evt.eventSystem != nil, "event
system should not be nil")
+ assert.Assert(t, evt.enabled, "event system
should be enabled")
+ evt.sendRemoveAskEvent(testCase.allocationAsk,
testCase.terminationType, testCase.appRemoved)
+ assert.Equal(t, testCase.expectedEventCnt,
len(testCase.eventSystemMock.events), "event was not generated")
+ assert.Equal(t, testCase.expectedType,
testCase.eventSystemMock.events[0].Type, "event type is not expected")
+ assert.Equal(t, testCase.expectedChangeType,
testCase.eventSystemMock.events[0].EventChangeType, "event change type is not
expected")
+ assert.Equal(t, testCase.expectedChangeDetail,
testCase.eventSystemMock.events[0].EventChangeDetail, "event change detail is
not expected")
+ assert.Equal(t, testCase.expectedObjectID,
testCase.eventSystemMock.events[0].ObjectID, "event object id is not expected")
+ assert.Equal(t, testCase.expectedReferenceID,
testCase.eventSystemMock.events[0].ReferenceID, "event reference id is not
expected")
+ }
+ })
+ }
+}
diff --git a/pkg/scheduler/objects/application_test.go
b/pkg/scheduler/objects/application_test.go
index e01f0856..a7aead35 100644
--- a/pkg/scheduler/objects/application_test.go
+++ b/pkg/scheduler/objects/application_test.go
@@ -30,6 +30,7 @@ import (
"github.com/apache/yunikorn-core/pkg/common/configs"
"github.com/apache/yunikorn-core/pkg/common/resources"
"github.com/apache/yunikorn-core/pkg/common/security"
+ "github.com/apache/yunikorn-core/pkg/events"
"github.com/apache/yunikorn-core/pkg/handler"
"github.com/apache/yunikorn-core/pkg/rmproxy"
"github.com/apache/yunikorn-core/pkg/rmproxy/rmevent"
@@ -199,6 +200,10 @@ func TestAppReservation(t *testing.T) {
// test multiple reservations from one allocation
func TestAppAllocReservation(t *testing.T) {
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
app := newApplication(appID1, "default", "root.unknown")
if app == nil || app.ApplicationID != appID1 {
t.Fatalf("app create failed which should not have %v", app)
@@ -260,6 +265,30 @@ func TestAppAllocReservation(t *testing.T) {
if app.HasReserved() || node1.IsReserved() || node2.IsReserved() ||
reservedAsks != 2 {
t.Errorf("ask removal did not clean up all reservations,
reserved released = %d", reservedAsks)
}
+
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 2
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 2, len(records), "expecting 2 events: 1 new alloc ask
and 1 alloc ask cancel")
+ allocAskRecord := records[0]
+ assert.Equal(t, si.EventRecord_APP, allocAskRecord.Type, "incorrect
event type, expect app")
+ assert.Equal(t, ask.applicationID, allocAskRecord.ObjectID, "incorrect
object ID, expected application ID")
+ assert.Equal(t, ask.allocationKey, allocAskRecord.ReferenceID,
"incorrect reference ID, expected alloc ask ID")
+ assert.Equal(t, si.EventRecord_ADD, allocAskRecord.EventChangeType,
"incorrect change type, expected add")
+ assert.Equal(t, si.EventRecord_APP_REQUEST,
allocAskRecord.EventChangeDetail, "incorrect change detail, expected new alloc
ask")
+ allocAskCancelRecord := records[1]
+ assert.Equal(t, si.EventRecord_APP, allocAskCancelRecord.Type,
"incorrect event type, expect app")
+ assert.Equal(t, ask.applicationID, allocAskCancelRecord.ObjectID,
"incorrect object ID, expected application ID")
+ assert.Equal(t, ask.allocationKey, allocAskCancelRecord.ReferenceID,
"incorrect reference ID, expected alloc ask ID")
+ assert.Equal(t, si.EventRecord_REMOVE,
allocAskCancelRecord.EventChangeType, "incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_REQUEST_CANCEL,
allocAskCancelRecord.EventChangeDetail, "incorrect change detail, expected new
alloc ask")
}
// test update allocation repeat
@@ -311,6 +340,10 @@ func TestUpdateRepeat(t *testing.T) {
// test pending calculation and ask addition
func TestAddAllocAsk(t *testing.T) {
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
app := newApplication(appID1, "default", "root.unknown")
if app == nil || app.ApplicationID != appID1 {
t.Fatalf("app create failed which should not have %v", app)
@@ -338,7 +371,7 @@ func TestAddAllocAsk(t *testing.T) {
t.Errorf("ask with zero repeat should not have been added to
app")
}
- // working cases
+ // add alloc ask
res =
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 5})
ask = newAllocationAskRepeat(aKey, appID1, res, 1)
err = app.AddAllocationAsk(ask)
@@ -348,6 +381,26 @@ func TestAddAllocAsk(t *testing.T) {
if !resources.Equals(res, pending) {
t.Errorf("pending resource not updated correctly, expected %v
but was: %v", res, pending)
}
+
+ // test add alloc ask event
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 1
+ })
+ assert.NilError(t, err, "the events should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 1, len(records), "expecting add alloc ask event")
+ record := records[0]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, appID1, record.ObjectID, "incorrect object ID, expected
application ID")
+ assert.Equal(t, aKey, record.ReferenceID, "incorrect reference ID,
expected placeholder alloc ID")
+ assert.Equal(t, si.EventRecord_ADD, record.EventChangeType, "incorrect
change type, expected add")
+ assert.Equal(t, si.EventRecord_APP_REQUEST, record.EventChangeDetail,
"incorrect change detail, expected app request")
+ eventSystem.Stop()
+
ask = newAllocationAskRepeat(aKey, appID1, res, 2)
err = app.AddAllocationAsk(ask)
assert.NilError(t, err, "ask should have been updated on app")
@@ -1178,6 +1231,10 @@ func TestOnStatusChangeCalled(t *testing.T) {
func TestReplaceAllocation(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
app := newApplication(appID1, "default", "root.a")
assert.Equal(t, New.String(), app.CurrentState(), "new app not in New
state")
// state changes are not important
@@ -1234,6 +1291,25 @@ func TestReplaceAllocation(t *testing.T) {
assert.Equal(t, realAlloc.GetPlaceholderCreateTime(),
ph.GetCreateTime(), "real allocation's placeholder create time not updated as
expected: got %s, expected %s", realAlloc.GetPlaceholderCreateTime(),
ph.GetCreateTime())
assertUserGroupResource(t, getTestUserGroup(), res)
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 1
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 1, len(records), "expecting alloc replaced event")
+ record := records[0]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, alloc.applicationID, record.ObjectID, "incorrect object
ID, expected application ID")
+ assert.Equal(t, alloc.GetUUID(), record.ReferenceID, "incorrect
reference ID, expected placeholder alloc ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_ALLOC_REPLACED,
record.EventChangeDetail, "incorrect change detail, expected alloc replaced")
+ eventSystem.Stop()
+
// add the placeholder back to the app, the failure test above changed
state and removed the ph
app.SetState(Running.String())
ph.ClearReleases()
@@ -1274,6 +1350,10 @@ func TestTimeoutPlaceholderAllocAsk(t *testing.T) {
func runTimeoutPlaceholderTest(t *testing.T, expectedState string,
gangSchedulingStyle string) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
// create a fake queue
queue, err := createRootQueue(nil)
assert.NilError(t, err, "queue create failed")
@@ -1352,10 +1432,33 @@ func runTimeoutPlaceholderTest(t *testing.T,
expectedState string, gangSchedulin
assert.Equal(t, len(log), 2, "wrong number of app events")
assert.Equal(t, log[0].ApplicationState, Accepted.String())
assert.Equal(t, log[1].ApplicationState, expectedState)
+
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 4
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 4, len(records), "expecting 4 events: 1 new alloc ask,
1 alloc ask timeout, and 2 alloc timeout")
+ // new alloc sak and alloc timeout are tested in other cases, we only
test the alloc ask timeout
+ record := records[1]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, phAsk.GetApplicationID(), record.ObjectID, "incorrect
object ID, expected application ID")
+ assert.Equal(t, phAsk.GetAllocationKey(), record.ReferenceID,
"incorrect reference ID, expected alloc ask ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_REQUEST_TIMEOUT,
record.EventChangeDetail, "incorrect change detail, expected alloc ask timeout")
}
func TestTimeoutPlaceholderAllocReleased(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
originalPhTimeout := defaultPlaceholderTimeout
defaultPlaceholderTimeout = 5 * time.Millisecond
defer func() { defaultPlaceholderTimeout = originalPhTimeout }()
@@ -1417,6 +1520,24 @@ func TestTimeoutPlaceholderAllocReleased(t *testing.T) {
assert.Equal(t, app.placeholderData[""].Replaced, int64(0))
assert.Equal(t, app.placeholderData[""].TimedOut, int64(1))
assertUserGroupResource(t, getTestUserGroup(), resources.Multiply(res,
3))
+
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 1
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 1, len(records), "expecting alloc timeout event")
+ record := records[0]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, ph.applicationID, record.ObjectID, "incorrect object
ID, expected application ID")
+ assert.Equal(t, ph.GetUUID(), record.ReferenceID, "incorrect reference
ID, expected alloc ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_ALLOC_TIMEOUT, record.EventChangeDetail,
"incorrect change detail, expected alloc timeout")
}
func TestTimeoutPlaceholderCompleting(t *testing.T) {
diff --git a/pkg/scheduler/objects/events.go b/pkg/scheduler/objects/events.go
deleted file mode 100644
index 60dcadf7..00000000
--- a/pkg/scheduler/objects/events.go
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package objects
-
-import (
- "fmt"
-
- "github.com/apache/yunikorn-core/pkg/events"
-)
-
-type applicationEvents struct {
- enabled bool
- eventSystem events.EventSystem
- app *Application
-}
-
-func (evt *applicationEvents) sendAppDoesNotFitEvent(request *AllocationAsk) {
- if !evt.enabled {
- return
- }
-
- message := fmt.Sprintf("Application %s does not fit into %s queue",
request.GetApplicationID(), evt.app.queuePath)
- event := events.CreateRequestEventRecord(request.GetAllocationKey(),
request.GetApplicationID(), message, request.GetAllocatedResource())
- evt.eventSystem.AddEvent(event)
-}
-
-func (evt *applicationEvents) sendPlaceholderLargerEvent(ph *Allocation,
request *AllocationAsk) {
- if !evt.enabled {
- return
- }
-
- message := fmt.Sprintf("Task group '%s' in application '%s': allocation
resources '%s' are not matching placeholder '%s' allocation with ID '%s'",
ph.GetTaskGroup(), evt.app.ApplicationID,
request.GetAllocatedResource().String(), ph.GetAllocatedResource().String(),
ph.GetAllocationKey())
- event := events.CreateRequestEventRecord(ph.GetAllocationKey(),
evt.app.ApplicationID, message, request.GetAllocatedResource())
- evt.eventSystem.AddEvent(event)
-}
-
-func newApplicationEvents(app *Application, evt events.EventSystem)
*applicationEvents {
- return &applicationEvents{
- eventSystem: evt,
- enabled: evt != nil,
- app: app,
- }
-}
diff --git a/pkg/scheduler/objects/events_test.go
b/pkg/scheduler/objects/events_test.go
deleted file mode 100644
index 84ae5364..00000000
--- a/pkg/scheduler/objects/events_test.go
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package objects
-
-import (
- "testing"
-
- "gotest.tools/v3/assert"
-
- "github.com/apache/yunikorn-scheduler-interface/lib/go/si"
-)
-
-type EventSystemMock struct {
- events []*si.EventRecord
-}
-
-func (m *EventSystemMock) AddEvent(event *si.EventRecord) {
- m.events = append(m.events, event)
-}
-
-func (m *EventSystemMock) StartService() {}
-
-func (m *EventSystemMock) Stop() {}
-
-func TestSendAppDoesNotFitEvent(t *testing.T) {
- app := &Application{
- queuePath: "root.test",
- }
-
- // not enabled
- evt := newApplicationEvents(app, nil)
- assert.Assert(t, evt.eventSystem == nil, "event system should be nil")
- assert.Assert(t, !evt.enabled, "event system should be disabled")
- evt.sendAppDoesNotFitEvent(&AllocationAsk{})
-
- // enabled
- mock := newEventSystemMock()
- evt = newApplicationEvents(app, mock)
- assert.Assert(t, evt.eventSystem != nil, "event system should not be
nil")
- assert.Assert(t, evt.enabled, "event system should be enabled")
- evt.sendAppDoesNotFitEvent(&AllocationAsk{
- applicationID: appID0,
- allocationKey: aKey,
- })
- assert.Equal(t, 1, len(mock.events), "event was not generated")
-}
-
-func TestSendPlaceholderLargerEvent(t *testing.T) {
- app := &Application{
- queuePath: "root.test",
- }
-
- // not enabled
- evt := newApplicationEvents(app, nil)
- assert.Assert(t, evt.eventSystem == nil, "event system should be nil")
- assert.Assert(t, !evt.enabled, "event system should be disabled")
- evt.sendPlaceholderLargerEvent(&Allocation{}, &AllocationAsk{})
-
- // enabled
- mock := newEventSystemMock()
- evt = newApplicationEvents(app, mock)
- assert.Assert(t, evt.eventSystem != nil, "event system should not be
nil")
- assert.Assert(t, evt.enabled, "event system should be enabled")
- evt.sendPlaceholderLargerEvent(&Allocation{
- allocationKey: aKey,
- }, &AllocationAsk{
- applicationID: appID0,
- allocationKey: aKey,
- })
- assert.Equal(t, 1, len(mock.events), "event was not generated")
-}
-
-func newEventSystemMock() *EventSystemMock {
- return &EventSystemMock{events: make([]*si.EventRecord, 0)}
-}
diff --git a/pkg/scheduler/objects/utilities_test.go
b/pkg/scheduler/objects/utilities_test.go
index 025989b1..8b391cdc 100644
--- a/pkg/scheduler/objects/utilities_test.go
+++ b/pkg/scheduler/objects/utilities_test.go
@@ -38,6 +38,7 @@ const (
appID1 = "app-1"
appID2 = "app-2"
aKey = "alloc-1"
+ aUUID = "alloc-uuid-1"
nodeID1 = "node-1"
instType1 = "itype-1"
)
diff --git a/pkg/scheduler/partition_test.go b/pkg/scheduler/partition_test.go
index 665acc1d..99210f11 100644
--- a/pkg/scheduler/partition_test.go
+++ b/pkg/scheduler/partition_test.go
@@ -308,6 +308,10 @@ func TestRemoveNode(t *testing.T) {
func TestRemoveNodeWithAllocations(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
partition, err := newBasePartition()
assert.NilError(t, err, "partition create failed")
@@ -347,6 +351,24 @@ func TestRemoveNodeWithAllocations(t *testing.T) {
assert.Equal(t, 0, len(confirmed), "node did not confirm correct
allocation")
assert.Equal(t, released[0].GetUUID(), allocUUID, "uuid returned by
release not the same as on allocation")
assertLimits(t, getTestUserGroup(), nil)
+
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 1
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 1, len(records), "expecting alloc timeout event")
+ record := records[0]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, appID1, record.ObjectID, "incorrect object ID, expected
application ID")
+ assert.Equal(t, allocUUID, record.ReferenceID, "incorrect reference ID,
expected alloc ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_ALLOC_NODEREMOVED,
record.EventChangeDetail, "incorrect change detail, expected alloc node
removed")
}
// test with a replacement of a placeholder: placeholder and real on the same
node that gets removed
@@ -662,6 +684,10 @@ func TestPlaceholderDataWithNodeRemoval(t *testing.T) {
// ensure removed placeholders has been accounted under timed out in gang app
placeholder data
func TestPlaceholderDataWithRemoval(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
partition, err := newBasePartition()
assert.NilError(t, err, "partition create failed")
@@ -740,6 +766,25 @@ func TestPlaceholderDataWithRemoval(t *testing.T) {
releases, _ := partition.removeAllocation(release)
assert.Equal(t, 1, len(releases), "unexpected number of allocations
released")
assertPlaceholderData(t, gangApp, 7, 1)
+
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 15
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 15, len(records), "expecting 15 events: 7 new alloc
ask, 7 new alloc, and 1 stopped by rm")
+ // new alloc ask and alloc events are tested in other cases, we only
want to test the stopped by rm event
+ record := records[14]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, release.ApplicationID, record.ObjectID, "incorrect
object ID, expected application ID")
+ assert.Equal(t, release.UUID, record.ReferenceID, "incorrect reference
ID, expected alloc ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_ALLOC_CANCEL, record.EventChangeDetail,
"incorrect change detail, expected alloc stopped by rm")
}
// check PlaceHolderData
@@ -1676,6 +1721,10 @@ func TestRequiredNodeAllocation(t *testing.T) {
func TestPreemption(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
partition, _, app2, alloc1, alloc2 := setupPreemption(t)
res, err := resources.NewResourceFromConf(map[string]string{"vcore":
"5"})
@@ -1699,6 +1748,26 @@ func TestPreemption(t *testing.T) {
assert.Assert(t, !alloc1.IsPreempted(), "alloc-1 is preempted")
assert.Assert(t, alloc2.IsPreempted(), "alloc-2 is not preempted")
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 6
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 6, len(records), "expecting 6 events: 3 new alloc ask,
2 new alloc, and 1 alloc preempted event")
+ // new alloc ask and new alloc events are tested in other cases, we
only want to test the alloc preempted event
+ record := records[5]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, ask3.GetApplicationID(), record.ObjectID, "incorrect
object ID, expected application ID")
+ assert.Equal(t, alloc2.GetUUID(), record.ReferenceID, "incorrect
reference ID, expected alloc ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_ALLOC_PREEMPT, record.EventChangeDetail,
"incorrect change detail, expected alloc preempted")
+ eventSystem.Stop()
+
// allocation should still not do anything as we have not yet released
the preempted allocation
alloc = partition.tryAllocate()
if alloc != nil {
@@ -2626,7 +2695,8 @@ func TestPlaceholderSmallerThanReal(t *testing.T) {
// wait for events to be processed
err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
- return eventSystem.Store.CountStoredEvents() == 1
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 4
})
assert.NilError(t, err, "the event should have been processed")
@@ -2634,12 +2704,30 @@ func TestPlaceholderSmallerThanReal(t *testing.T) {
if records == nil {
t.Fatal("collecting eventChannel should return something")
}
- assert.Equal(t, 1, len(records), "expecting one event for placeholder
mismatch")
- record := records[0]
- assert.Equal(t, si.EventRecord_REQUEST, record.Type, "incorrect event
type")
- assert.Equal(t, phID, record.ObjectID, "incorrect allocation ID,
expected placeholder alloc ID")
- assert.Equal(t, appID1, record.ReferenceID, "event should reference
application ID")
- assert.Assert(t, strings.Contains(record.Message, "Task group 'tg-1' in
application 'app-1'"), "unexpected message in record")
+ assert.Equal(t, 4, len(records), "expecting four events: ph-1 ask, ph-1
allocation, alloc-1 ask and placeholder mismatch")
+ phAskRecord := records[0]
+ assert.Equal(t, si.EventRecord_APP, phAskRecord.Type, "incorrect event
type, expect app")
+ assert.Equal(t, appID1, phAskRecord.ObjectID, "incorrect object ID,
expected application ID")
+ assert.Equal(t, phID, phAskRecord.ReferenceID, "incorrect reference ID,
expected placeholder alloc ID")
+ assert.Equal(t, si.EventRecord_ADD, phAskRecord.EventChangeType,
"incorrect change type, expected add")
+ assert.Equal(t, si.EventRecord_APP_REQUEST,
phAskRecord.EventChangeDetail, "incorrect change detail, expected app request")
+ phAllocRecord := records[1]
+ assert.Equal(t, si.EventRecord_APP, phAllocRecord.Type, "incorrect
event type, expect app")
+ assert.Equal(t, appID1, phAllocRecord.ObjectID, "incorrect object ID,
expected application ID")
+ assert.Equal(t, ph.GetUUID(), phAllocRecord.ReferenceID, "incorrect
reference ID, expected placeholder alloc UUID")
+ assert.Equal(t, si.EventRecord_ADD, phAllocRecord.EventChangeType,
"incorrect change type, expected add")
+ assert.Equal(t, si.EventRecord_APP_ALLOC,
phAllocRecord.EventChangeDetail, "incorrect change detail, expected app alloc")
+ allocAskRecord := records[2]
+ assert.Equal(t, si.EventRecord_APP, allocAskRecord.Type, "incorrect
event type, expect app")
+ assert.Equal(t, appID1, allocAskRecord.ObjectID, "incorrect object ID,
expected application ID")
+ assert.Equal(t, allocID, allocAskRecord.ReferenceID, "incorrect
reference ID, expected alloc ID")
+ assert.Equal(t, si.EventRecord_ADD, allocAskRecord.EventChangeType,
"incorrect change type, expected add")
+ assert.Equal(t, si.EventRecord_APP_REQUEST,
allocAskRecord.EventChangeDetail, "incorrect change detail, expected app alloc")
+ placeholderMismatchRecord := records[3]
+ assert.Equal(t, si.EventRecord_REQUEST, placeholderMismatchRecord.Type,
"incorrect event type")
+ assert.Equal(t, phID, placeholderMismatchRecord.ObjectID, "incorrect
allocation ID, expected placeholder alloc ID")
+ assert.Equal(t, appID1, placeholderMismatchRecord.ReferenceID, "event
should reference application ID")
+ assert.Assert(t, strings.Contains(placeholderMismatchRecord.Message,
"Task group 'tg-1' in application 'app-1'"), "unexpected message in record")
assertLimits(t, getTestUserGroup(), phRes)
// release placeholder: do what the context would do after the shim
processing
@@ -2713,7 +2801,7 @@ func TestPlaceholderSmallerMulti(t *testing.T) {
// wait for events to be processed
err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
- return eventSystem.Store.CountStoredEvents() == phCount
+ return eventSystem.Store.CountStoredEvents() == 16
})
assert.NilError(t, err, "the events should have been processed")
@@ -2721,7 +2809,7 @@ func TestPlaceholderSmallerMulti(t *testing.T) {
if records == nil {
t.Fatal("collecting eventChannel should return something")
}
- assert.Equal(t, phCount, len(records), "expecting %d events for
placeholder mismatch", phCount)
+ assert.Equal(t, 16, len(records), "expecting 16 events: 6 alloc ask, 5
alloc, and 5 placeholder mismatch")
assertLimits(t, getTestUserGroup(), tgRes)
// release placeholders: do what the context would do after the shim
processing
@@ -2811,6 +2899,10 @@ func TestPlaceholderBiggerThanReal(t *testing.T) {
func TestPlaceholderMatch(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
partition, err := newBasePartition()
assert.NilError(t, err, "partition create failed")
tgRes :=
resources.NewResourceFromMap(map[string]resources.Quantity{"first": 10,
"second": 10})
@@ -2872,6 +2964,27 @@ func TestPlaceholderMatch(t *testing.T) {
assert.Equal(t, allocID2, alloc.GetAllocationKey(), "expected
allocation of alloc-2 to be returned")
assert.Equal(t, int64(1), app.GetAllPlaceholderData()[0].Count,
"placeholder data should show 1 available placeholder")
assert.Equal(t, int64(0), app.GetAllPlaceholderData()[0].Replaced,
"placeholder data should show no replacements yet")
+
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 6
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 6, len(records), "expecting 6 events: 3 new alloc ask,
2 new alloc , and 1 alloc replaced")
+ // new alloc sak and new alloc are tested in other cases, we only test
the alloc replaced
+ record := records[5]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, alloc.GetApplicationID(), record.ObjectID, "incorrect
object ID, expected application ID")
+ assert.Equal(t, phUUID, record.ReferenceID, "incorrect reference ID,
expected alloc ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_ALLOC_REPLACED,
record.EventChangeDetail, "incorrect change detail, expected alloc replaced")
+ eventSystem.Stop()
+
// release placeholder: do what the context would do after the shim
processing
release := &si.AllocationRelease{
PartitionName: "test",
@@ -3019,6 +3132,10 @@ func TestTryPlaceholderAllocate(t *testing.T) {
// The failure is triggered by the predicate plugin and is hidden in the alloc
handling
func TestFailReplacePlaceholder(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
partition, err := newBasePartition()
assert.NilError(t, err, "partition create failed")
if alloc := partition.tryPlaceholderAllocate(); alloc != nil {
@@ -3084,6 +3201,26 @@ func TestFailReplacePlaceholder(t *testing.T) {
t.Fatalf("node-2 allocation not updated as expected: got %s,
expected %s", node2.GetAllocatedResource(), res)
}
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 4
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 4, len(records), "expecting 4 events: 2 new alloc ask,
1 new alloc, and 1 alloc replaced")
+ // new alloc ask and new alloc are tested in other cases, we only test
alloc replaced here
+ record := records[3]
+ assert.Equal(t, si.EventRecord_APP, record.Type, "incorrect event type,
expect app")
+ assert.Equal(t, alloc.GetApplicationID(), record.ObjectID, "incorrect
object ID, expected application ID")
+ assert.Equal(t, alloc.GetFirstRelease().GetUUID(), record.ReferenceID,
"incorrect reference ID, expected alloc ID")
+ assert.Equal(t, si.EventRecord_REMOVE, record.EventChangeType,
"incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_ALLOC_REPLACED,
record.EventChangeDetail, "incorrect change detail, expected alloc replaced")
+ eventSystem.Stop()
+
phUUID := alloc.GetFirstRelease().GetUUID()
// placeholder is not released until confirmed by the shim
if !resources.Equals(app.GetPlaceholderResource(), res) {
@@ -3159,6 +3296,10 @@ func TestAddAllocationAsk(t *testing.T) {
func TestRemoveAllocationAsk(t *testing.T) {
setupUGM()
+ events.CreateAndSetEventSystem()
+ eventSystem := events.GetEventSystem().(*events.EventSystemImpl)
//nolint:errcheck
+ eventSystem.StartServiceWithPublisher(false)
+
partition, err := newBasePartition()
assert.NilError(t, err, "partition create failed")
// add the app
@@ -3208,6 +3349,30 @@ func TestRemoveAllocationAsk(t *testing.T) {
partition.removeAllocationAsk(release)
assert.Assert(t, resources.IsZero(app.GetPendingResource()), "app
should not have pending asks")
assertLimits(t, getTestUserGroup(), nil)
+
+ // wait for events to be processed
+ err = common.WaitFor(10*time.Millisecond, time.Second, func() bool {
+ fmt.Printf("checking event length: %d\n",
eventSystem.Store.CountStoredEvents())
+ return eventSystem.Store.CountStoredEvents() == 2
+ })
+ assert.NilError(t, err, "the event should have been processed")
+ records := eventSystem.Store.CollectEvents()
+ if records == nil {
+ t.Fatal("collecting eventChannel should return something")
+ }
+ assert.Equal(t, 2, len(records), "expecting 2 events: 1 new alloc ask
and 1 alloc ask removal")
+ allocAskRecord := records[0]
+ assert.Equal(t, si.EventRecord_APP, allocAskRecord.Type, "incorrect
event type, expect app")
+ assert.Equal(t, ask.GetApplicationID(), allocAskRecord.ObjectID,
"incorrect object ID, expected application ID")
+ assert.Equal(t, ask.GetAllocationKey(), allocAskRecord.ReferenceID,
"incorrect reference ID, expected alloc ask ID")
+ assert.Equal(t, si.EventRecord_ADD, allocAskRecord.EventChangeType,
"incorrect change type, expected add")
+ assert.Equal(t, si.EventRecord_APP_REQUEST,
allocAskRecord.EventChangeDetail, "incorrect change detail, expected new alloc
ask")
+ allocAskCancelRecord := records[1]
+ assert.Equal(t, si.EventRecord_APP, allocAskCancelRecord.Type,
"incorrect event type, expect app")
+ assert.Equal(t, release.ApplicationID, allocAskCancelRecord.ObjectID,
"incorrect object ID, expected application ID")
+ assert.Equal(t, release.AllocationKey,
allocAskCancelRecord.ReferenceID, "incorrect reference ID, expected alloc ask
ID")
+ assert.Equal(t, si.EventRecord_REMOVE,
allocAskCancelRecord.EventChangeType, "incorrect change type, expected remove")
+ assert.Equal(t, si.EventRecord_APP_REQUEST,
allocAskCancelRecord.EventChangeDetail, "incorrect change detail, expected
alloc cancel")
}
func TestUpdateNodeSortingPolicy(t *testing.T) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]