PricedItem evolved

This commit is contained in:
mr
2026-03-20 13:07:06 +01:00
parent 2abc035ec0
commit 1508cc3611
16 changed files with 162 additions and 96 deletions

View File

@@ -7,6 +7,7 @@ import (
"cloud.o-forge.io/core/oc-lib/dbs" "cloud.o-forge.io/core/oc-lib/dbs"
"cloud.o-forge.io/core/oc-lib/models/common/enum" "cloud.o-forge.io/core/oc-lib/models/common/enum"
"cloud.o-forge.io/core/oc-lib/models/common/pricing"
"cloud.o-forge.io/core/oc-lib/models/order" "cloud.o-forge.io/core/oc-lib/models/order"
"cloud.o-forge.io/core/oc-lib/models/peer" "cloud.o-forge.io/core/oc-lib/models/peer"
"cloud.o-forge.io/core/oc-lib/models/resources" "cloud.o-forge.io/core/oc-lib/models/resources"
@@ -48,6 +49,7 @@ func DraftFirstBill(order *order.Order, request *tools.APIRequest) (*Bill, error
peers[p.DestPeerID] = []*PeerItemOrder{} peers[p.DestPeerID] = []*PeerItemOrder{}
} }
peers[p.DestPeerID] = append(peers[p.DestPeerID], &PeerItemOrder{ peers[p.DestPeerID] = append(peers[p.DestPeerID], &PeerItemOrder{
ResourceType: p.ResourceType,
Purchase: p, Purchase: p,
Item: p.PricedItem, Item: p.PricedItem,
Quantity: 1, Quantity: 1,
@@ -69,6 +71,8 @@ func DraftFirstBill(order *order.Order, request *tools.APIRequest) (*Bill, error
peers[b.DestPeerID] = []*PeerItemOrder{} peers[b.DestPeerID] = []*PeerItemOrder{}
} }
peers[b.DestPeerID] = append(peers[b.DestPeerID], &PeerItemOrder{ peers[b.DestPeerID] = append(peers[b.DestPeerID], &PeerItemOrder{
ResourceType: b.ResourceType,
Quantity: 1,
Item: b.PricedItem, Item: b.PricedItem,
}) })
} }
@@ -135,6 +139,22 @@ type PeerOrder struct {
Total float64 `json:"total,omitempty" bson:"total,omitempty"` Total float64 `json:"total,omitempty" bson:"total,omitempty"`
} }
func PricedByType(dt tools.DataType) pricing.PricedItemITF {
switch dt {
case tools.PROCESSING_RESOURCE:
return &resources.PricedProcessingResource{}
case tools.STORAGE_RESOURCE:
return &resources.PricedStorageResource{}
case tools.DATA_RESOURCE:
return &resources.PricedDataResource{}
case tools.COMPUTE_RESOURCE:
return &resources.PricedComputeResource{}
case tools.WORKFLOW_RESOURCE:
return &resources.PricedResource[*pricing.ExploitPricingProfile[pricing.TimePricingStrategy]]{}
}
return nil
}
func (d *PeerOrder) Pay(request *tools.APIRequest, response chan *PeerOrder, wg *sync.WaitGroup) { func (d *PeerOrder) Pay(request *tools.APIRequest, response chan *PeerOrder, wg *sync.WaitGroup) {
d.Status = enum.PENDING d.Status = enum.PENDING
@@ -144,7 +164,7 @@ func (d *PeerOrder) Pay(request *tools.APIRequest, response chan *PeerOrder, wg
d.Status = enum.PAID // TO REMOVE LATER IT'S A MOCK d.Status = enum.PAID // TO REMOVE LATER IT'S A MOCK
if d.Status == enum.PAID { if d.Status == enum.PAID {
for _, b := range d.Items { for _, b := range d.Items {
var priced *resources.PricedResource priced := PricedByType(b.ResourceType)
bb, _ := json.Marshal(b.Item) bb, _ := json.Marshal(b.Item)
json.Unmarshal(bb, priced) json.Unmarshal(bb, priced)
if !priced.IsPurchasable() { if !priced.IsPurchasable() {
@@ -178,6 +198,7 @@ func (d *PeerOrder) SumUpBill(request *tools.APIRequest) error {
} }
type PeerItemOrder struct { type PeerItemOrder struct {
ResourceType tools.DataType `json:"datatype,omitempty" bson:"datatype,omitempty"`
Quantity int `json:"quantity,omitempty" bson:"quantity,omitempty"` Quantity int `json:"quantity,omitempty" bson:"quantity,omitempty"`
Purchase *purchase_resource.PurchaseResource `json:"purchase,omitempty" bson:"purchase,omitempty"` Purchase *purchase_resource.PurchaseResource `json:"purchase,omitempty" bson:"purchase,omitempty"`
Item map[string]interface{} `json:"item,omitempty" bson:"item,omitempty"` Item map[string]interface{} `json:"item,omitempty" bson:"item,omitempty"`
@@ -189,7 +210,7 @@ func (d *PeerItemOrder) GetPriceHT(request *tools.APIRequest) (float64, error) {
return 0, nil return 0, nil
} }
/////////// ///////////
var priced *resources.PricedResource priced := PricedByType(d.ResourceType)
b, _ := json.Marshal(d.Item) b, _ := json.Marshal(d.Item)
err := json.Unmarshal(b, priced) err := json.Unmarshal(b, priced)
if err != nil { if err != nil {

View File

@@ -36,11 +36,11 @@ func (abs *ComputeResource) ConvertToPricedResource(t tools.DataType, selectedIn
if t != tools.COMPUTE_RESOURCE { if t != tools.COMPUTE_RESOURCE {
return nil, errors.New("not the proper type expected : cannot convert to priced resource : have " + t.String() + " wait Compute") return nil, errors.New("not the proper type expected : cannot convert to priced resource : have " + t.String() + " wait Compute")
} }
p, err := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, selectedInstance, selectedPartnership, selectedBuyingStrategy, selectedStrategy, selectedBookingModeIndex, request) p, err := ConvertToPricedResource[*ComputeResourcePricingProfile](t, selectedInstance, selectedPartnership, selectedBuyingStrategy, selectedStrategy, selectedBookingModeIndex, abs, request)
if err != nil { if err != nil {
return nil, err return nil, err
} }
priced := p.(*PricedResource) priced := p.(*PricedResource[*ComputeResourcePricingProfile])
return &PricedComputeResource{ return &PricedComputeResource{
PricedResource: *priced, PricedResource: *priced,
}, nil }, nil
@@ -122,7 +122,10 @@ func (p *ComputeResourcePricingProfile) GetPriceHT(amountOfData float64, explici
return 0, errors.New("params must be set") return 0, errors.New("params must be set")
} }
pp := float64(0) pp := float64(0)
model := params[1] model := ""
if len(params) > 1 {
model = params[1]
}
if strings.Contains(params[0], "cpus") && len(params) > 1 { if strings.Contains(params[0], "cpus") && len(params) > 1 {
if _, ok := p.CPUsPrices[model]; ok { if _, ok := p.CPUsPrices[model]; ok {
p.Pricing.Price = p.CPUsPrices[model] p.Pricing.Price = p.CPUsPrices[model]
@@ -158,7 +161,7 @@ func (p *ComputeResourcePricingProfile) GetPriceHT(amountOfData float64, explici
} }
type PricedComputeResource struct { type PricedComputeResource struct {
PricedResource PricedResource[*ComputeResourcePricingProfile]
CPUsLocated map[string]float64 `json:"cpus_in_use" bson:"cpus_in_use"` // CPUsInUse is the list of CPUs in use 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 GPUsLocated map[string]float64 `json:"gpus_in_use" bson:"gpus_in_use"` // GPUsInUse is the list of GPUs in use

View File

@@ -41,11 +41,11 @@ func (abs *DataResource) ConvertToPricedResource(t tools.DataType, selectedInsta
if t != tools.DATA_RESOURCE { if t != tools.DATA_RESOURCE {
return nil, errors.New("not the proper type expected : cannot convert to priced resource : have " + t.String() + " wait Data") return nil, errors.New("not the proper type expected : cannot convert to priced resource : have " + t.String() + " wait Data")
} }
p, err := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, selectedInstance, selectedPartnership, selectedBuyingStrategy, selectedStrategy, selectedBookingModeIndex, request) p, err := ConvertToPricedResource[*DataResourcePricingProfile](t, selectedInstance, selectedPartnership, selectedBuyingStrategy, selectedStrategy, selectedBookingModeIndex, abs, request)
if err != nil { if err != nil {
return nil, err return nil, err
} }
priced := p.(*PricedResource) priced := p.(*PricedResource[*DataResourcePricingProfile])
return &PricedDataResource{ return &PricedDataResource{
PricedResource: *priced, PricedResource: *priced,
}, nil }, nil
@@ -160,7 +160,7 @@ func (p *DataResourcePricingProfile) IsBooked() bool {
} }
type PricedDataResource struct { type PricedDataResource struct {
PricedResource PricedResource[*DataResourcePricingProfile]
UsageStorageGB float64 `json:"storage_gb,omitempty" bson:"storage_gb,omitempty"` UsageStorageGB float64 `json:"storage_gb,omitempty" bson:"storage_gb,omitempty"`
} }

View File

@@ -8,6 +8,10 @@ import (
"cloud.o-forge.io/core/oc-lib/tools" "cloud.o-forge.io/core/oc-lib/tools"
) )
type PricedResourceITF interface {
pricing.PricedItemITF
}
type ResourceInterface interface { type ResourceInterface interface {
utils.DBObject utils.DBObject
FilterPeer(peerID string) *dbs.Filters FilterPeer(peerID string) *dbs.Filters
@@ -15,7 +19,7 @@ type ResourceInterface interface {
ConvertToPricedResource(t tools.DataType, a *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, b *int, request *tools.APIRequest) (pricing.PricedItemITF, error) ConvertToPricedResource(t tools.DataType, a *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, b *int, request *tools.APIRequest) (pricing.PricedItemITF, error)
GetType() string GetType() string
ClearEnv() utils.DBObject ClearEnv() utils.DBObject
SetAllowedInstances(request *tools.APIRequest, instance_id ...string) SetAllowedInstances(request *tools.APIRequest, instance_id ...string) []ResourceInstanceITF
AddInstances(instance ResourceInstanceITF) AddInstances(instance ResourceInstanceITF)
GetSelectedInstance(index *int) ResourceInstanceITF GetSelectedInstance(index *int) ResourceInstanceITF
} }

View File

@@ -37,12 +37,13 @@ func (d *NativeTool) ClearEnv() utils.DBObject {
return d return d
} }
func (w *NativeTool) SetAllowedInstances(request *tools.APIRequest, ids ...string) { func (w *NativeTool) SetAllowedInstances(request *tools.APIRequest, ids ...string) []ResourceInstanceITF {
/* EMPTY */ /* EMPTY */
return []ResourceInstanceITF{}
} }
func (w *NativeTool) ConvertToPricedResource(t tools.DataType, selectedInstance *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, selectedBookingModeIndex *int, request *tools.APIRequest) (pricing.PricedItemITF, error) { func (w *NativeTool) ConvertToPricedResource(t tools.DataType, selectedInstance *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, selectedBookingModeIndex *int, request *tools.APIRequest) (pricing.PricedItemITF, error) {
return &PricedResource{ return &PricedResource[*pricing.ExploitPricingProfile[pricing.TimePricingStrategy]]{
Name: w.Name, Name: w.Name,
Logo: w.Logo, Logo: w.Logo,
ResourceID: w.UUID, ResourceID: w.UUID,

View File

@@ -16,11 +16,11 @@ type BookingConfiguration struct {
Mode booking.BookingMode `json:"mode,omitempty" bson:"mode,omitempty"` Mode booking.BookingMode `json:"mode,omitempty" bson:"mode,omitempty"`
} }
type PricedResource struct { type PricedResource[T pricing.PricingProfileITF] struct {
Name string `json:"name,omitempty" bson:"name,omitempty"` Name string `json:"name,omitempty" bson:"name,omitempty"`
Logo string `json:"logo,omitempty" bson:"logo,omitempty"` Logo string `json:"logo,omitempty" bson:"logo,omitempty"`
InstancesRefs map[string]string `json:"instances_refs,omitempty" bson:"instances_refs,omitempty"` InstancesRefs map[string]string `json:"instances_refs,omitempty" bson:"instances_refs,omitempty"`
SelectedPricing pricing.PricingProfileITF `json:"selected_pricing,omitempty" bson:"selected_pricing,omitempty"` SelectedPricing T `json:"selected_pricing,omitempty" bson:"selected_pricing,omitempty"`
Quantity int `json:"quantity,omitempty" bson:"quantity,omitempty"` Quantity int `json:"quantity,omitempty" bson:"quantity,omitempty"`
BookingConfiguration *BookingConfiguration `json:"booking_configuration,omitempty" bson:"booking_configuration,omitempty"` BookingConfiguration *BookingConfiguration `json:"booking_configuration,omitempty" bson:"booking_configuration,omitempty"`
Variations []*pricing.PricingVariation `json:"pricing_variations" bson:"pricing_variations"` Variations []*pricing.PricingVariation `json:"pricing_variations" bson:"pricing_variations"`
@@ -31,56 +31,56 @@ type PricedResource struct {
ResourceType tools.DataType `json:"resource_type,omitempty" bson:"resource_type,omitempty"` ResourceType tools.DataType `json:"resource_type,omitempty" bson:"resource_type,omitempty"`
} }
func (abs *PricedResource) GetQuantity() int { func (abs *PricedResource[T]) GetQuantity() int {
return abs.Quantity return abs.Quantity
} }
func (abs *PricedResource) AddQuantity(amount int) { func (abs *PricedResource[T]) AddQuantity(amount int) {
abs.Quantity += amount abs.Quantity += amount
} }
func (abs *PricedResource) SelectPricing() pricing.PricingProfileITF { func (abs *PricedResource[T]) SelectPricing() pricing.PricingProfileITF {
return abs.SelectedPricing return abs.SelectedPricing
} }
func (abs *PricedResource) GetID() string { func (abs *PricedResource[T]) GetID() string {
return abs.ResourceID return abs.ResourceID
} }
func (abs *PricedResource) GetInstanceID() string { func (abs *PricedResource[T]) GetInstanceID() string {
return abs.InstanceID return abs.InstanceID
} }
func (abs *PricedResource) GetType() tools.DataType { func (abs *PricedResource[T]) GetType() tools.DataType {
return abs.ResourceType return abs.ResourceType
} }
func (abs *PricedResource) GetCreatorID() string { func (abs *PricedResource[T]) GetCreatorID() string {
return abs.CreatorID return abs.CreatorID
} }
func (abs *PricedResource) IsPurchasable() bool { func (abs *PricedResource[T]) IsPurchasable() bool {
if abs.SelectedPricing == nil { if any(abs.SelectedPricing) == nil {
return false return false
} }
return (abs.SelectedPricing).IsPurchasable() return abs.SelectedPricing.IsPurchasable()
} }
func (abs *PricedResource) IsBooked() bool { func (abs *PricedResource[T]) IsBooked() bool {
if abs.SelectedPricing == nil { if any(abs.SelectedPricing) == nil {
return false return false
} }
return (abs.SelectedPricing).IsBooked() return abs.SelectedPricing.IsBooked()
} }
func (abs *PricedResource) GetLocationEnd() *time.Time { func (abs *PricedResource[T]) GetLocationEnd() *time.Time {
if abs.BookingConfiguration == nil { if abs.BookingConfiguration == nil {
return nil return nil
} }
return abs.BookingConfiguration.UsageEnd return abs.BookingConfiguration.UsageEnd
} }
func (abs *PricedResource) GetLocationStart() *time.Time { func (abs *PricedResource[T]) GetLocationStart() *time.Time {
if abs.BookingConfiguration == nil { if abs.BookingConfiguration == nil {
now := time.Now().Add(2 * time.Minute) now := time.Now().Add(2 * time.Minute)
return &now return &now
@@ -88,34 +88,34 @@ func (abs *PricedResource) GetLocationStart() *time.Time {
return abs.BookingConfiguration.UsageStart return abs.BookingConfiguration.UsageStart
} }
func (abs *PricedResource) SetLocationStart(start time.Time) { func (abs *PricedResource[T]) SetLocationStart(start time.Time) {
if abs.BookingConfiguration == nil { if abs.BookingConfiguration == nil {
abs.BookingConfiguration = &BookingConfiguration{} abs.BookingConfiguration = &BookingConfiguration{}
} }
abs.BookingConfiguration.UsageStart = &start abs.BookingConfiguration.UsageStart = &start
} }
func (abs *PricedResource) SetLocationEnd(end time.Time) { func (abs *PricedResource[T]) SetLocationEnd(end time.Time) {
if abs.BookingConfiguration == nil { if abs.BookingConfiguration == nil {
abs.BookingConfiguration = &BookingConfiguration{} abs.BookingConfiguration = &BookingConfiguration{}
} }
abs.BookingConfiguration.UsageEnd = &end abs.BookingConfiguration.UsageEnd = &end
} }
func (abs *PricedResource) GetBookingMode() booking.BookingMode { func (abs *PricedResource[T]) GetBookingMode() booking.BookingMode {
if abs.BookingConfiguration == nil { if abs.BookingConfiguration == nil {
return booking.WHEN_POSSIBLE return booking.WHEN_POSSIBLE
} }
return abs.BookingConfiguration.Mode return abs.BookingConfiguration.Mode
} }
func (abs *PricedResource) GetExplicitDurationInS() float64 { func (abs *PricedResource[T]) GetExplicitDurationInS() float64 {
if abs.BookingConfiguration == nil { if abs.BookingConfiguration == nil {
abs.BookingConfiguration = &BookingConfiguration{} abs.BookingConfiguration = &BookingConfiguration{}
} }
if abs.BookingConfiguration.ExplicitBookingDurationS == 0 { if abs.BookingConfiguration.ExplicitBookingDurationS == 0 {
if abs.BookingConfiguration.UsageEnd == nil && abs.BookingConfiguration.UsageStart == nil { if abs.BookingConfiguration.UsageEnd == nil && abs.BookingConfiguration.UsageStart == nil {
return (5 * time.Minute).Seconds() return (1 * time.Hour).Seconds()
} }
if abs.BookingConfiguration.UsageEnd == nil { if abs.BookingConfiguration.UsageEnd == nil {
add := abs.BookingConfiguration.UsageStart.Add(5 * time.Minute) add := abs.BookingConfiguration.UsageStart.Add(5 * time.Minute)
@@ -126,7 +126,7 @@ func (abs *PricedResource) GetExplicitDurationInS() float64 {
return abs.BookingConfiguration.ExplicitBookingDurationS return abs.BookingConfiguration.ExplicitBookingDurationS
} }
func (r *PricedResource) GetPriceHT() (float64, error) { func (r *PricedResource[T]) GetPriceHT() (float64, error) {
now := time.Now() now := time.Now()
if r.BookingConfiguration == nil { if r.BookingConfiguration == nil {
r.BookingConfiguration = &BookingConfiguration{} r.BookingConfiguration = &BookingConfiguration{}
@@ -138,8 +138,8 @@ func (r *PricedResource) GetPriceHT() (float64, error) {
add := r.BookingConfiguration.UsageStart.Add(time.Duration(1 * time.Hour)) add := r.BookingConfiguration.UsageStart.Add(time.Duration(1 * time.Hour))
r.BookingConfiguration.UsageEnd = &add r.BookingConfiguration.UsageEnd = &add
} }
if r.SelectedPricing == nil { if any(r.SelectedPricing) == nil {
return 0, errors.New("pricing profile must be set on Priced Resource " + r.ResourceID) return 0, errors.New("pricing profile must be set for resource " + r.ResourceID)
} }
pricing := r.SelectedPricing pricing := r.SelectedPricing
return pricing.GetPriceHT(1, 0, *r.BookingConfiguration.UsageStart, *r.BookingConfiguration.UsageEnd, r.Variations) return pricing.GetPriceHT(1, 0, *r.BookingConfiguration.UsageStart, *r.BookingConfiguration.UsageEnd, r.Variations)

View File

@@ -1,6 +1,7 @@
package resources package resources
import ( import (
"errors"
"time" "time"
"cloud.o-forge.io/core/oc-lib/models/common/enum" "cloud.o-forge.io/core/oc-lib/models/common/enum"
@@ -65,7 +66,7 @@ type ProcessingResourcePartnership struct {
} }
type PricedProcessingResource struct { type PricedProcessingResource struct {
PricedResource PricedResource[*ProcessingResourcePricingProfile]
IsService bool IsService bool
} }
@@ -82,7 +83,7 @@ func (a *PricedProcessingResource) GetExplicitDurationInS() float64 {
if a.IsService { if a.IsService {
return -1 return -1
} }
return (5 * time.Minute).Seconds() return (1 * time.Hour).Seconds()
} }
return a.BookingConfiguration.UsageEnd.Sub(*a.BookingConfiguration.UsageStart).Seconds() return a.BookingConfiguration.UsageEnd.Sub(*a.BookingConfiguration.UsageStart).Seconds()
} }
@@ -93,6 +94,20 @@ func (d *ProcessingResource) GetAccessor(request *tools.APIRequest) utils.Access
return NewAccessor[*ProcessingResource](tools.PROCESSING_RESOURCE, request, func() utils.DBObject { return &ProcessingResource{} }) // Create a new instance of the accessor return NewAccessor[*ProcessingResource](tools.PROCESSING_RESOURCE, request, func() utils.DBObject { return &ProcessingResource{} }) // Create a new instance of the accessor
} }
func (abs *ProcessingResource) ConvertToPricedResource(t tools.DataType, selectedInstance *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, selectedBookingModeIndex *int, request *tools.APIRequest) (pricing.PricedItemITF, error) {
if t != tools.PROCESSING_RESOURCE {
return nil, errors.New("not the proper type expected : cannot convert to priced resource : have " + t.String() + " wait Data")
}
p, err := ConvertToPricedResource[*DataResourcePricingProfile](t, selectedInstance, selectedPartnership, selectedBuyingStrategy, selectedStrategy, selectedBookingModeIndex, abs, request)
if err != nil {
return nil, err
}
priced := p.(*PricedResource[*DataResourcePricingProfile])
return &PricedDataResource{
PricedResource: *priced,
}, nil
}
type ProcessingResourcePricingProfile struct { type ProcessingResourcePricingProfile struct {
pricing.AccessPricingProfile[pricing.TimePricingStrategy] // AccessPricingProfile is the pricing profile of a data it means that we can access the data for an amount of time pricing.AccessPricingProfile[pricing.TimePricingStrategy] // AccessPricingProfile is the pricing profile of a data it means that we can access the data for an amount of time
} }

View File

@@ -73,9 +73,9 @@ func (abs *AbstractInstanciatedResource[T]) AddInstances(instance ResourceInstan
abs.Instances = append(abs.Instances, instance.(T)) abs.Instances = append(abs.Instances, instance.(T))
} }
func (abs *AbstractInstanciatedResource[T]) ConvertToPricedResource(t tools.DataType, func ConvertToPricedResource[T pricing.PricingProfileITF](t tools.DataType,
selectedInstance *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, selectedInstance *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int,
selectedBookingModeIndex *int, request *tools.APIRequest) (pricing.PricedItemITF, error) { selectedBookingModeIndex *int, abs ResourceInterface, request *tools.APIRequest) (pricing.PricedItemITF, error) {
instances := map[string]string{} instances := map[string]string{}
var profile pricing.PricingProfileITF var profile pricing.PricingProfileITF
var inst ResourceInstanceITF var inst ResourceInstanceITF
@@ -84,7 +84,7 @@ func (abs *AbstractInstanciatedResource[T]) ConvertToPricedResource(t tools.Data
instances[t.GetID()] = t.GetName() instances[t.GetID()] = t.GetName()
profile = t.GetProfile(request.PeerID, selectedPartnership, selectedBuyingStrategy, selectedStrategy) profile = t.GetProfile(request.PeerID, selectedPartnership, selectedBuyingStrategy, selectedStrategy)
} else { } else {
for i, instance := range abs.Instances { // TODO why it crush before ? for i, instance := range abs.SetAllowedInstances(request) { // TODO why it crush before ?
if i == 0 { if i == 0 {
inst = instance inst = instance
} }
@@ -106,8 +106,8 @@ func (abs *AbstractInstanciatedResource[T]) ConvertToPricedResource(t tools.Data
}*/ }*/
} }
variations := []*pricing.PricingVariation{} variations := []*pricing.PricingVariation{}
if selectedBookingModeIndex != nil && abs.AllowedBookingModes[booking.BookingMode(*selectedBookingModeIndex)] != nil { if selectedBookingModeIndex != nil && abs.GetBookingModes()[booking.BookingMode(*selectedBookingModeIndex)] != nil {
variations = append(variations, abs.AllowedBookingModes[booking.BookingMode(*selectedBookingModeIndex)]) variations = append(variations, abs.GetBookingModes()[booking.BookingMode(*selectedBookingModeIndex)])
} }
// Seed the booking configuration with the instance's historical average duration // Seed the booking configuration with the instance's historical average duration
// so GetExplicitDurationInS() returns a realistic default out of the box. // so GetExplicitDurationInS() returns a realistic default out of the box.
@@ -117,17 +117,21 @@ func (abs *AbstractInstanciatedResource[T]) ConvertToPricedResource(t tools.Data
bc = &BookingConfiguration{ExplicitBookingDurationS: avg} bc = &BookingConfiguration{ExplicitBookingDurationS: avg}
} }
} }
return &PricedResource{ instanceID := ""
Name: abs.Name, if inst != nil {
Logo: abs.Logo, instanceID = inst.GetID()
ResourceID: abs.UUID, }
InstanceID: inst.GetID(), selectedPricing, _ := profile.(T)
return &PricedResource[T]{
Name: abs.GetName(),
ResourceID: abs.GetID(),
InstanceID: instanceID,
ResourceType: t, ResourceType: t,
Quantity: 1, Quantity: 1,
InstancesRefs: instances, InstancesRefs: instances,
SelectedPricing: profile, SelectedPricing: selectedPricing,
Variations: variations, Variations: variations,
CreatorID: abs.CreatorID, CreatorID: abs.GetCreatorID(),
BookingConfiguration: bc, BookingConfiguration: bc,
}, nil }, nil
} }
@@ -149,12 +153,17 @@ func (r *AbstractInstanciatedResource[T]) GetSelectedInstance(selected *int) Res
return nil return nil
} }
func (abs *AbstractInstanciatedResource[T]) SetAllowedInstances(request *tools.APIRequest, instanceID ...string) { func (abs *AbstractInstanciatedResource[T]) SetAllowedInstances(request *tools.APIRequest, instanceID ...string) []ResourceInstanceITF {
if (request != nil && request.PeerID == abs.CreatorID && request.PeerID != "") || request.Admin { if !((request != nil && request.PeerID == abs.CreatorID && request.PeerID != "") || request.Admin) {
return
}
abs.Instances = VerifyAuthAction(abs.Instances, request, instanceID...) abs.Instances = VerifyAuthAction(abs.Instances, request, instanceID...)
} }
inst := []ResourceInstanceITF{}
for _, i := range abs.Instances {
inst = append(inst, i)
}
return inst
}
func (abs *AbstractInstanciatedResource[T]) VerifyAuth(callName string, request *tools.APIRequest) bool { func (abs *AbstractInstanciatedResource[T]) VerifyAuth(callName string, request *tools.APIRequest) bool {
return len(VerifyAuthAction(abs.Instances, request)) > 0 || abs.AbstractObject.VerifyAuth(callName, request) return len(VerifyAuthAction(abs.Instances, request)) > 0 || abs.AbstractObject.VerifyAuth(callName, request)

View File

@@ -35,11 +35,11 @@ func (abs *StorageResource) ConvertToPricedResource(t tools.DataType, selectedIn
if t != tools.STORAGE_RESOURCE { if t != tools.STORAGE_RESOURCE {
return nil, errors.New("not the proper type expected : cannot convert to priced resource : have " + t.String() + " wait Storage") return nil, errors.New("not the proper type expected : cannot convert to priced resource : have " + t.String() + " wait Storage")
} }
p, err := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, selectedInstance, selectedPartnership, selectedBuyingStrategy, selectedStrategy, selectedBookingModeIndex, request) p, err := ConvertToPricedResource[*StorageResourcePricingProfile](t, selectedInstance, selectedPartnership, selectedBuyingStrategy, selectedStrategy, selectedBookingModeIndex, abs, request)
if err != nil { if err != nil {
return nil, err return nil, err
} }
priced := p.(*PricedResource) priced := p.(*PricedResource[*StorageResourcePricingProfile])
return &PricedStorageResource{ return &PricedStorageResource{
PricedResource: *priced, PricedResource: *priced,
}, nil }, nil
@@ -181,7 +181,7 @@ func (p *StorageResourcePricingProfile) IsBooked() bool {
} }
type PricedStorageResource struct { type PricedStorageResource struct {
PricedResource PricedResource[*StorageResourcePricingProfile]
UsageStorageGB float64 `json:"storage_gb,omitempty" bson:"storage_gb,omitempty"` UsageStorageGB float64 `json:"storage_gb,omitempty" bson:"storage_gb,omitempty"`
} }

View File

@@ -63,9 +63,16 @@ func TestPricedComputeResource_GetPriceHT(t *testing.T) {
start := time.Now() start := time.Now()
end := start.Add(1 * time.Hour) end := start.Add(1 * time.Hour)
r := resources.PricedComputeResource{ r := resources.PricedComputeResource{
PricedResource: resources.PricedResource{ PricedResource: resources.PricedResource[*resources.ComputeResourcePricingProfile]{
ResourceID: "comp456", ResourceID: "comp456",
SelectedPricing: &MockPricingProfile{ReturnCost: 1.0}, SelectedPricing: &resources.ComputeResourcePricingProfile{
CPUsPrices: map[string]float64{"Xeon": 2.0},
ExploitPricingProfile: pricing.ExploitPricingProfile[pricing.TimePricingStrategy]{
AccessPricingProfile: pricing.AccessPricingProfile[pricing.TimePricingStrategy]{
Pricing: pricing.PricingStrategy[pricing.TimePricingStrategy]{Price: 1.0},
},
},
},
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
UsageStart: &start, UsageStart: &start,
UsageEnd: &end, UsageEnd: &end,
@@ -73,8 +80,8 @@ func TestPricedComputeResource_GetPriceHT(t *testing.T) {
}, },
}, },
CPUsLocated: map[string]float64{"Xeon": 2}, CPUsLocated: map[string]float64{"Xeon": 2},
GPUsLocated: map[string]float64{"Tesla": 1}, GPUsLocated: map[string]float64{},
RAMLocated: 4, RAMLocated: 0,
} }
price, err := r.GetPriceHT() price, err := r.GetPriceHT()
@@ -84,7 +91,7 @@ func TestPricedComputeResource_GetPriceHT(t *testing.T) {
func TestPricedComputeResource_GetPriceHT_MissingProfile(t *testing.T) { func TestPricedComputeResource_GetPriceHT_MissingProfile(t *testing.T) {
r := resources.PricedComputeResource{ r := resources.PricedComputeResource{
PricedResource: resources.PricedResource{ PricedResource: resources.PricedResource[*resources.ComputeResourcePricingProfile]{
ResourceID: "comp789", ResourceID: "comp789",
}, },
} }

View File

@@ -76,7 +76,7 @@ func TestDataResourcePricingStrategy_GetQuantity(t *testing.T) {
func TestDataResourcePricingProfile_IsPurchased(t *testing.T) { func TestDataResourcePricingProfile_IsPurchased(t *testing.T) {
profile := &resources.DataResourcePricingProfile{} profile := &resources.DataResourcePricingProfile{}
profile.Pricing.BuyingStrategy = pricing.SUBSCRIPTION profile.Pricing.BuyingStrategy = pricing.PERMANENT
assert.True(t, profile.IsPurchasable()) assert.True(t, profile.IsPurchasable())
} }
@@ -91,7 +91,7 @@ func TestPricedDataResource_GetPriceHT(t *testing.T) {
pricingProfile.Pricing.OverrideStrategy = resources.PER_GB_DOWNLOADED pricingProfile.Pricing.OverrideStrategy = resources.PER_GB_DOWNLOADED
r := &resources.PricedDataResource{ r := &resources.PricedDataResource{
PricedResource: resources.PricedResource{ PricedResource: resources.PricedResource[*resources.DataResourcePricingProfile]{
SelectedPricing: pricingProfile, SelectedPricing: pricingProfile,
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
UsageStart: &now, UsageStart: &now,
@@ -107,7 +107,7 @@ func TestPricedDataResource_GetPriceHT(t *testing.T) {
func TestPricedDataResource_GetPriceHT_NoProfiles(t *testing.T) { func TestPricedDataResource_GetPriceHT_NoProfiles(t *testing.T) {
r := &resources.PricedDataResource{ r := &resources.PricedDataResource{
PricedResource: resources.PricedResource{ PricedResource: resources.PricedResource[*resources.DataResourcePricingProfile]{
ResourceID: "test-resource", ResourceID: "test-resource",
}, },
} }

View File

@@ -36,7 +36,7 @@ func (m *MockPricingProfile) GetPriceHT(amount float64, explicitDuration float64
// ---- Tests ---- // ---- Tests ----
func TestGetIDAndCreatorAndType(t *testing.T) { func TestGetIDAndCreatorAndType(t *testing.T) {
r := resources.PricedResource{ r := resources.PricedResource[pricing.PricingProfileITF]{
ResourceID: "res-123", ResourceID: "res-123",
CreatorID: "user-abc", CreatorID: "user-abc",
ResourceType: tools.DATA_RESOURCE, ResourceType: tools.DATA_RESOURCE,
@@ -48,19 +48,19 @@ func TestGetIDAndCreatorAndType(t *testing.T) {
func TestIsPurchased(t *testing.T) { func TestIsPurchased(t *testing.T) {
t.Run("nil selected pricing returns false", func(t *testing.T) { t.Run("nil selected pricing returns false", func(t *testing.T) {
r := &resources.PricedResource{} r := &resources.PricedResource[pricing.PricingProfileITF]{}
assert.False(t, r.IsPurchasable()) assert.False(t, r.IsPurchasable())
}) })
t.Run("returns true if pricing profile is purchased", func(t *testing.T) { t.Run("returns true if pricing profile is purchased", func(t *testing.T) {
mock := &MockPricingProfile{Purchased: true} mock := &MockPricingProfile{Purchased: true}
r := &resources.PricedResource{SelectedPricing: mock} r := &resources.PricedResource[pricing.PricingProfileITF]{SelectedPricing: mock}
assert.True(t, r.IsPurchasable()) assert.True(t, r.IsPurchasable())
}) })
} }
func TestGetAndSetLocationStartEnd(t *testing.T) { func TestGetAndSetLocationStartEnd(t *testing.T) {
r := &resources.PricedResource{} r := &resources.PricedResource[pricing.PricingProfileITF]{}
now := time.Now() now := time.Now()
r.SetLocationStart(now) r.SetLocationStart(now)
@@ -72,7 +72,7 @@ func TestGetAndSetLocationStartEnd(t *testing.T) {
func TestGetExplicitDurationInS(t *testing.T) { func TestGetExplicitDurationInS(t *testing.T) {
t.Run("uses explicit duration if set", func(t *testing.T) { t.Run("uses explicit duration if set", func(t *testing.T) {
r := &resources.PricedResource{BookingConfiguration: &resources.BookingConfiguration{ r := &resources.PricedResource[pricing.PricingProfileITF]{BookingConfiguration: &resources.BookingConfiguration{
ExplicitBookingDurationS: 3600, ExplicitBookingDurationS: 3600,
}, },
} }
@@ -82,7 +82,7 @@ func TestGetExplicitDurationInS(t *testing.T) {
t.Run("computes duration from start and end", func(t *testing.T) { t.Run("computes duration from start and end", func(t *testing.T) {
start := time.Now() start := time.Now()
end := start.Add(2 * time.Hour) end := start.Add(2 * time.Hour)
r := &resources.PricedResource{ r := &resources.PricedResource[pricing.PricingProfileITF]{
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
UsageStart: &start, UsageEnd: &end, UsageStart: &start, UsageEnd: &end,
}, },
@@ -91,14 +91,14 @@ func TestGetExplicitDurationInS(t *testing.T) {
}) })
t.Run("defaults to 1 hour when times not set", func(t *testing.T) { t.Run("defaults to 1 hour when times not set", func(t *testing.T) {
r := &resources.PricedResource{} r := &resources.PricedResource[pricing.PricingProfileITF]{}
assert.InDelta(t, 3600.0, r.GetExplicitDurationInS(), 0.1) assert.InDelta(t, 3600.0, r.GetExplicitDurationInS(), 0.1)
}) })
} }
func TestGetPriceHT(t *testing.T) { func TestGetPriceHT(t *testing.T) {
t.Run("returns error if no pricing profile", func(t *testing.T) { t.Run("returns error if no pricing profile", func(t *testing.T) {
r := &resources.PricedResource{ResourceID: "no-profile"} r := &resources.PricedResource[pricing.PricingProfileITF]{ResourceID: "no-profile"}
price, err := r.GetPriceHT() price, err := r.GetPriceHT()
require.Error(t, err) require.Error(t, err)
assert.Contains(t, err.Error(), "pricing profile must be set") assert.Contains(t, err.Error(), "pricing profile must be set")
@@ -107,7 +107,7 @@ func TestGetPriceHT(t *testing.T) {
t.Run("defaults BookingConfiguration when nil", func(t *testing.T) { t.Run("defaults BookingConfiguration when nil", func(t *testing.T) {
mock := &MockPricingProfile{ReturnCost: 42.0} mock := &MockPricingProfile{ReturnCost: 42.0}
r := &resources.PricedResource{ r := &resources.PricedResource[pricing.PricingProfileITF]{
SelectedPricing: mock, SelectedPricing: mock,
} }
price, err := r.GetPriceHT() price, err := r.GetPriceHT()
@@ -119,7 +119,7 @@ func TestGetPriceHT(t *testing.T) {
start := time.Now() start := time.Now()
end := start.Add(1 * time.Hour) end := start.Add(1 * time.Hour)
mock := &MockPricingProfile{ReturnErr: true} mock := &MockPricingProfile{ReturnErr: true}
r := &resources.PricedResource{ r := &resources.PricedResource[pricing.PricingProfileITF]{
SelectedPricing: mock, SelectedPricing: mock,
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
UsageStart: &start, UsageStart: &start,
@@ -135,7 +135,7 @@ func TestGetPriceHT(t *testing.T) {
start := time.Now() start := time.Now()
end := start.Add(1 * time.Hour) end := start.Add(1 * time.Hour)
mock := &MockPricingProfile{ReturnCost: 10.0} mock := &MockPricingProfile{ReturnCost: 10.0}
r := &resources.PricedResource{ r := &resources.PricedResource[pricing.PricingProfileITF]{
SelectedPricing: mock, SelectedPricing: mock,
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
UsageStart: &start, UsageStart: &start,

View File

@@ -40,7 +40,7 @@ func TestPricedProcessingResource_GetExplicitDurationInS(t *testing.T) {
{ {
name: "Nil start time, non-service", name: "Nil start time, non-service",
input: PricedProcessingResource{ input: PricedProcessingResource{
PricedResource: PricedResource{ PricedResource: PricedResource[*ProcessingResourcePricingProfile]{
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
UsageStart: nil, UsageStart: nil,
}, },
@@ -51,7 +51,7 @@ func TestPricedProcessingResource_GetExplicitDurationInS(t *testing.T) {
{ {
name: "Duration computed from start and end", name: "Duration computed from start and end",
input: PricedProcessingResource{ input: PricedProcessingResource{
PricedResource: PricedResource{ PricedResource: PricedResource[*ProcessingResourcePricingProfile]{
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
UsageStart: &now, UsageStart: &now,
UsageEnd: &after, UsageEnd: &after,
@@ -63,7 +63,7 @@ func TestPricedProcessingResource_GetExplicitDurationInS(t *testing.T) {
{ {
name: "Explicit duration takes precedence", name: "Explicit duration takes precedence",
input: PricedProcessingResource{ input: PricedProcessingResource{
PricedResource: PricedResource{ PricedResource: PricedResource[*ProcessingResourcePricingProfile]{
BookingConfiguration: &resources.BookingConfiguration{ BookingConfiguration: &resources.BookingConfiguration{
ExplicitBookingDurationS: 1337, ExplicitBookingDurationS: 1337,
}, },
@@ -96,7 +96,7 @@ func TestProcessingResourcePricingProfile_GetPriceHT(t *testing.T) {
}, },
} }
profile := &ProcessingResourcePricingProfile{AccessPricingProfile: mockPricing} profile := &ProcessingResourcePricingProfile{AccessPricingProfile: mockPricing}
price, err := profile.GetPriceHT(0, 0, start, end, []*pricing.PricingVariation{}) price, err := profile.GetPriceHT(1, 0, start, end, []*pricing.PricingVariation{})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 100.0, price) assert.Equal(t, 100.0, price)
} }

View File

@@ -81,8 +81,8 @@ func TestGetSelectedInstance_NoIndex(t *testing.T) {
} }
func TestCanUpdate_WhenOnlyStateDiffers(t *testing.T) { func TestCanUpdate_WhenOnlyStateDiffers(t *testing.T) {
resource := &resources.AbstractResource{AbstractObject: utils.AbstractObject{IsDraft: false}} resource := &resources.AbstractResource{AbstractObject: utils.AbstractObject{IsDraft: true}}
set := &MockDBObject{isDraft: true} set := &MockDBObject{isDraft: false}
canUpdate, updated := resource.CanUpdate(set) canUpdate, updated := resource.CanUpdate(set)
assert.True(t, canUpdate) assert.True(t, canUpdate)
assert.Equal(t, set, updated) assert.Equal(t, set, updated)
@@ -105,7 +105,12 @@ type FakeResource struct {
resources.AbstractInstanciatedResource[*MockInstance] resources.AbstractInstanciatedResource[*MockInstance]
} }
func (f *FakeResource) SetAllowedInstances(*tools.APIRequest, ...string) {} func (f *FakeResource) SetAllowedInstances(req *tools.APIRequest, instance_id ...string) []resources.ResourceInstanceITF {
return nil
}
func (f *FakeResource) ConvertToPricedResource(t tools.DataType, a *int, b *int, c *int, d *int, e *int, req *tools.APIRequest) (pricing.PricedItemITF, error) {
return nil, nil
}
func (f *FakeResource) VerifyAuth(string, *tools.APIRequest) bool { return true } func (f *FakeResource) VerifyAuth(string, *tools.APIRequest) bool { return true }
func TestNewAccessor_ReturnsValid(t *testing.T) { func TestNewAccessor_ReturnsValid(t *testing.T) {

View File

@@ -96,7 +96,7 @@ func TestStorageResourcePricingStrategy_GetQuantity_Invalid(t *testing.T) {
func TestPricedStorageResource_GetPriceHT_NoProfiles(t *testing.T) { func TestPricedStorageResource_GetPriceHT_NoProfiles(t *testing.T) {
res := &resources.PricedStorageResource{ res := &resources.PricedStorageResource{
PricedResource: resources.PricedResource{ PricedResource: resources.PricedResource[*resources.StorageResourcePricingProfile]{
ResourceID: "res-id", ResourceID: "res-id",
}, },
} }

View File

@@ -30,8 +30,9 @@ func (d *WorkflowResource) ClearEnv() utils.DBObject {
return d return d
} }
func (w *WorkflowResource) SetAllowedInstances(request *tools.APIRequest, ids ...string) { func (w *WorkflowResource) SetAllowedInstances(request *tools.APIRequest, ids ...string) []ResourceInstanceITF {
/* EMPTY */ /* EMPTY */
return []ResourceInstanceITF{}
} }
func (r *WorkflowResource) GetSelectedInstance(selected *int) ResourceInstanceITF { func (r *WorkflowResource) GetSelectedInstance(selected *int) ResourceInstanceITF {
@@ -39,7 +40,7 @@ func (r *WorkflowResource) GetSelectedInstance(selected *int) ResourceInstanceIT
} }
func (w *WorkflowResource) ConvertToPricedResource(t tools.DataType, selectedInstance *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, selectedBookingModeIndex *int, request *tools.APIRequest) (pricing.PricedItemITF, error) { func (w *WorkflowResource) ConvertToPricedResource(t tools.DataType, selectedInstance *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, selectedBookingModeIndex *int, request *tools.APIRequest) (pricing.PricedItemITF, error) {
return &PricedResource{ return &PricedResource[*pricing.ExploitPricingProfile[pricing.TimePricingStrategy]]{
Name: w.Name, Name: w.Name,
Logo: w.Logo, Logo: w.Logo,
ResourceID: w.UUID, ResourceID: w.UUID,