2019-10-31 14:32:46 -04:00
// Copyright (C) 2018 spdfg
2018-10-06 20:03:14 -07:00
//
// This file is part of Elektron.
//
// Elektron is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Elektron is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Elektron. If not, see <http://www.gnu.org/licenses/>.
//
2018-01-26 17:29:43 -05:00
package utilities
import (
"errors"
"sync"
2018-09-30 18:23:38 -07:00
mesos "github.com/mesos/mesos-go/api/v0/mesosproto"
2019-10-31 14:32:46 -04:00
"github.com/spdfg/elektron/def"
"github.com/spdfg/elektron/utilities/offerUtils"
2018-01-26 17:29:43 -05:00
)
type TrackResourceUsage struct {
2018-01-29 18:03:46 -05:00
perHostResourceAvailability map [ string ] * ResourceCount
2018-01-26 17:29:43 -05:00
sync . Mutex
}
// Maintain information regarding the usage of the cluster resources.
// This information is maintained for each node in the cluster.
type ResourceCount struct {
// Total resources available.
2018-01-29 18:19:44 -05:00
TotalCPU float64
TotalRAM float64
TotalWatts float64
2018-01-26 17:29:43 -05:00
// Resources currently unused.
2018-01-29 18:03:46 -05:00
UnusedCPU float64
UnusedRAM float64
UnusedWatts float64
2018-01-26 17:29:43 -05:00
}
// Increment unused resources.
func ( rc * ResourceCount ) IncrUnusedResources ( tr def . TaskResources ) {
2018-01-29 18:03:46 -05:00
rc . UnusedCPU += tr . CPU
rc . UnusedRAM += tr . Ram
rc . UnusedWatts += tr . Watts
2018-01-26 17:29:43 -05:00
}
// Decrement unused resources.
func ( rc * ResourceCount ) DecrUnusedResources ( tr def . TaskResources ) {
2018-01-29 18:03:46 -05:00
rc . UnusedCPU -= tr . CPU
rc . UnusedRAM -= tr . Ram
rc . UnusedWatts -= tr . Watts
2018-01-26 17:29:43 -05:00
}
var truInstance * TrackResourceUsage
func getTRUInstance ( ) * TrackResourceUsage {
if truInstance == nil {
truInstance = newResourceUsageTracker ( )
}
return truInstance
}
func newResourceUsageTracker ( ) * TrackResourceUsage {
return & TrackResourceUsage {
2018-01-29 18:03:46 -05:00
perHostResourceAvailability : make ( map [ string ] * ResourceCount ) ,
2018-01-26 17:29:43 -05:00
}
}
// Determine the total available resources from the first round of mesos resource offers.
func RecordTotalResourceAvailability ( offers [ ] * mesos . Offer ) {
tru := getTRUInstance ( )
tru . Lock ( )
defer tru . Unlock ( )
for _ , offer := range offers {
// If first offer received from Mesos Agent.
if _ , ok := tru . perHostResourceAvailability [ * offer . SlaveId . Value ] ; ! ok {
cpu , mem , watts := offerUtils . OfferAgg ( offer )
2018-01-29 18:03:46 -05:00
tru . perHostResourceAvailability [ * offer . SlaveId . Value ] = & ResourceCount {
TotalCPU : cpu ,
TotalRAM : mem ,
TotalWatts : watts ,
2018-01-26 17:29:43 -05:00
// Initially, all resources are used.
2018-01-29 18:03:46 -05:00
UnusedCPU : cpu ,
UnusedRAM : mem ,
UnusedWatts : watts ,
2018-01-26 17:29:43 -05:00
}
}
}
}
// Resource availability update scenarios.
var resourceAvailabilityUpdateScenario = map [ string ] func ( mesos . TaskID , mesos . SlaveID ) error {
"ON_TASK_TERMINAL_STATE" : func ( taskID mesos . TaskID , slaveID mesos . SlaveID ) error {
tru := getTRUInstance ( )
tru . Lock ( )
defer tru . Unlock ( )
if taskResources , err := def . GetResourceRequirement ( * taskID . Value ) ; err != nil {
return err
} else {
// Checking if first resource offer already recorded for slaveID.
if resCount , ok := tru . perHostResourceAvailability [ * slaveID . Value ] ; ok {
resCount . IncrUnusedResources ( taskResources )
} else {
// Shouldn't be here.
// First round of mesos resource offers not recorded.
return errors . New ( "Recource Availability not recorded for " + * slaveID . Value )
}
return nil
}
} ,
"ON_TASK_ACTIVE_STATE" : func ( taskID mesos . TaskID , slaveID mesos . SlaveID ) error {
tru := getTRUInstance ( )
tru . Lock ( )
defer tru . Unlock ( )
if taskResources , err := def . GetResourceRequirement ( * taskID . Value ) ; err != nil {
return err
} else {
2018-01-29 18:19:44 -05:00
// Checking if first resource offer already recorded for slaveID.
2018-01-26 17:29:43 -05:00
if resCount , ok := tru . perHostResourceAvailability [ * slaveID . Value ] ; ok {
resCount . DecrUnusedResources ( taskResources )
} else {
// Shouldn't be here.
// First round of mesos resource offers not recorded.
return errors . New ( "Resource Availability not recorded for " + * slaveID . Value )
}
return nil
}
} ,
}
// Updating cluster resource availability based on the given scenario.
func ResourceAvailabilityUpdate ( scenario string , taskID mesos . TaskID , slaveID mesos . SlaveID ) error {
if updateFunc , ok := resourceAvailabilityUpdateScenario [ scenario ] ; ok {
// Applying the update function
updateFunc ( taskID , slaveID )
return nil
} else {
// Incorrect scenario specified.
return errors . New ( "Incorrect scenario specified for resource availability update: " + scenario )
}
}
// Retrieve clusterwide resource availability.
func GetClusterwideResourceAvailability ( ) ResourceCount {
tru := getTRUInstance ( )
tru . Lock ( )
defer tru . Unlock ( )
clusterwideResourceCount := ResourceCount { }
for _ , resCount := range tru . perHostResourceAvailability {
// Aggregating the total CPU, RAM and Watts.
2018-01-29 18:03:46 -05:00
clusterwideResourceCount . TotalCPU += resCount . TotalCPU
clusterwideResourceCount . TotalRAM += resCount . TotalRAM
clusterwideResourceCount . TotalWatts += resCount . TotalWatts
2018-01-26 17:29:43 -05:00
// Aggregating the total unused CPU, RAM and Watts.
2018-01-29 18:03:46 -05:00
clusterwideResourceCount . UnusedCPU += resCount . UnusedCPU
clusterwideResourceCount . UnusedRAM += resCount . UnusedRAM
clusterwideResourceCount . UnusedWatts += resCount . UnusedWatts
2018-01-26 17:29:43 -05:00
}
return clusterwideResourceCount
}
// Retrieve resource availability for each host in the cluster.
2018-01-29 18:03:46 -05:00
func GetPerHostResourceAvailability ( ) map [ string ] * ResourceCount {
2018-01-26 17:29:43 -05:00
tru := getTRUInstance ( )
tru . Lock ( )
defer tru . Unlock ( )
return tru . perHostResourceAvailability
}