oc-lib/models/resources/compute.go
2024-12-16 12:17:20 +01:00

168 lines
6.4 KiB
Go

package resources
import (
"errors"
"strings"
"time"
"cloud.o-forge.io/core/oc-lib/models/common"
"cloud.o-forge.io/core/oc-lib/models/common/pricing"
"cloud.o-forge.io/core/oc-lib/models/utils"
"cloud.o-forge.io/core/oc-lib/tools"
)
/*
* ComputeResource is a struct that represents a compute resource
* it defines the resource compute
*/
type ComputeResource struct {
AbstractResource[*ComputeResourceInstance]
Architecture string `json:"architecture,omitempty" bson:"architecture,omitempty"` // Architecture is the architecture
Infrastructure common.InfrastructureType `json:"infrastructure,omitempty" bson:"infrastructure,omitempty"`
}
func (d *ComputeResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
return NewAccessor[*ComputeResource](tools.COMPUTE_RESOURCE, request, func() utils.DBObject { return &ComputeResource{} })
}
type ComputeResourceInstance struct {
ResourceInstance[*ComputeResourcePartnership]
SecurityLevel string `json:"security_level,omitempty" bson:"security_level,omitempty"`
PowerSource string `json:"power_source,omitempty" bson:"power_source,omitempty"`
CPUs map[string]*common.CPU `bson:"cpus,omitempty" json:"cpus,omitempty"` // CPUs is the list of CPUs key is model
GPUs map[string]*common.GPU `bson:"gpus,omitempty" json:"gpus,omitempty"` // GPUs is the list of GPUs key is model
RAM *common.RAM `bson:"ram,omitempty" json:"ram,omitempty"` // RAM is the RAM
}
type ComputeResourcePartnership struct {
ResourcePartnerShip[*ComputeResourcePricingProfile]
MaxAllowedCPUsCores map[string]int `json:"allowed_cpus,omitempty" bson:"allowed_cpus,omitempty"`
MaxAllowedGPUsMemoryGB map[string]float64 `json:"allowed_gpus,omitempty" bson:"allowed_gpus,omitempty"`
MaxAllowedRAMSize float64 `json:"allowed_ram,omitempty" bson:"allowed_ram,omitempty"`
}
type ComputeResourcePricingProfileOptions struct {
CPUCore int `json:"cpu_core" bson:"cpu_core" default:"1"`
GPUMemoryGB float64 `json:"gpu_memory_gb" bson:"gpu_memory_gb" default:"1"`
RAMSizeGB float64 `json:"ram_size_gb" bson:"ram_size_gb" default:"1"`
}
type ComputeResourcePricingProfile struct {
pricing.ExploitPricingProfile[pricing.TimePricingStrategy]
Options ComputeResourcePricingProfileOptions `json:"options,omitempty" bson:"options,omitempty"` // Options is the options of the pricing profile
// ExploitPricingProfile is the pricing profile of a compute it means that we exploit the resource for an amount of continuous time
OverrideCPUsPrices map[string]float64 `json:"cpus_prices,omitempty" bson:"cpus_prices,omitempty"` // CPUsPrices is the prices of the CPUs
OverrideGPUsPrices map[string]float64 `json:"gpus_prices,omitempty" bson:"gpus_prices,omitempty"` // GPUsPrices is the prices of the GPUs
OverrideRAMPrice float64 `json:"ram_price" bson:"ram_price" default:"-1"` // RAMPrice is the price of the RAM
}
// PROBLEM
func (p *ComputeResourcePricingProfile) IsBuying() bool {
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
}
func (p *ComputeResourcePricingProfile) GetOverrideStrategyValue() int {
return -1
}
// NOT A PROPER QUANTITY
// amountOfData is the number of CPUs, GPUs or RAM dependings on the params
func (p *ComputeResourcePricingProfile) GetPrice(amountOfData float64, explicitDuration float64, start time.Time, end time.Time, request *tools.APIRequest, params ...string) (float64, error) {
if len(params) < 1 {
return 0, errors.New("params must be set")
}
pp := float64(0)
model := params[1]
if strings.Contains(params[0], "cpus") && len(params) > 1 {
if _, ok := p.OverrideCPUsPrices[model]; ok {
p.Pricing.Price = p.OverrideCPUsPrices[model]
}
r, err := p.Pricing.GetPrice(amountOfData/float64(p.Options.CPUCore), explicitDuration, start, &end)
if err != nil {
return 0, err
}
pp += r
}
if strings.Contains(params[0], "gpus") && len(params) > 1 {
if _, ok := p.OverrideGPUsPrices[model]; ok {
p.Pricing.Price = p.OverrideGPUsPrices[model]
}
r, err := p.Pricing.GetPrice(amountOfData/float64(p.Options.GPUMemoryGB), explicitDuration, start, &end)
if err != nil {
return 0, err
}
pp += r
}
if strings.Contains(params[0], "ram") {
if p.OverrideRAMPrice >= 0 {
p.Pricing.Price = p.OverrideRAMPrice
}
r, err := p.Pricing.GetPrice(float64(amountOfData)/p.Options.RAMSizeGB, explicitDuration, start, &end)
if err != nil {
return 0, err
}
pp += r
}
return pp, nil
}
type CustomizedComputeResource struct {
AbstractCustomizedResource[*ComputeResourceInstance]
CPUsLocated map[string]float64 `json:"cpus_in_use" bson:"cpus_in_use"` // CPUsInUse is the list of CPUs in use
GPUsLocated map[string]float64 `json:"gpus_in_use" bson:"gpus_in_use"` // GPUsInUse is the list of GPUs in use
RAMLocated float64 `json:"ram_in_use" bson:"ram_in_use"` // RAMInUse is the RAM in use
}
func (r *CustomizedComputeResource) GetType() tools.DataType {
return tools.COMPUTE_RESOURCE
}
func (r *CustomizedComputeResource) GetPrice(request *tools.APIRequest) (float64, error) {
if r.UsageStart == nil || r.UsageEnd == nil {
return 0, errors.New("Usage start and end must be set")
}
partner := r.GetPartnership(request)
if partner != nil && partner.GetPricing(r.SelectedPricing) != nil {
return 0, errors.New("Pricing strategy not found")
}
pricing := partner.GetPricing(r.SelectedPricing)
price := float64(0)
for _, l := range []map[string]float64{r.CPUsLocated, r.GPUsLocated} {
for model, amountOfData := range l {
cpus, err := pricing.GetPrice(float64(amountOfData), r.ExplicitBookingDurationS, *r.UsageStart, *r.UsageEnd, request, "cpus", model)
if err != nil {
return 0, err
}
price += cpus
}
}
ram, err := pricing.GetPrice(r.RAMLocated, r.ExplicitBookingDurationS, *r.UsageStart, *r.UsageEnd, request, "ram")
if err != nil {
return 0, err
}
price += ram
return price, nil
}
/*
* FillWithDefaultProcessingUsage fills the order item with the default processing usage
* it depends on the processing usage only if nothing is set, during order
*/
func (i *CustomizedComputeResource) FillWithDefaultProcessingUsage(usage *ProcessingUsage) {
for _, cpu := range usage.CPUs {
if _, ok := i.CPUsLocated[cpu.Model]; !ok {
i.CPUsLocated[cpu.Model] = 0
}
if i.CPUsLocated[cpu.Model] < float64(cpu.Cores) {
i.CPUsLocated[cpu.Model] = float64(cpu.Cores)
}
}
for _, cpu := range usage.GPUs {
i.GPUsLocated[cpu.Model] = 1
}
i.RAMLocated = usage.RAM.SizeGb
}