add sets up
This commit is contained in:
parent
938f9f1326
commit
d8ccdec501
@ -15,12 +15,14 @@ import (
|
||||
"cloud.o-forge.io/core/oc-lib/dbs/mongo"
|
||||
"cloud.o-forge.io/core/oc-lib/logs"
|
||||
"cloud.o-forge.io/core/oc-lib/models"
|
||||
"cloud.o-forge.io/core/oc-lib/models/booking"
|
||||
"cloud.o-forge.io/core/oc-lib/models/collaborative_area"
|
||||
"cloud.o-forge.io/core/oc-lib/models/collaborative_area/rules/rule"
|
||||
"cloud.o-forge.io/core/oc-lib/models/compute_units"
|
||||
"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/resources"
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
w2 "cloud.o-forge.io/core/oc-lib/models/workflow"
|
||||
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
||||
@ -53,6 +55,7 @@ const (
|
||||
BOOKING = tools.BOOKING
|
||||
ORDER = tools.ORDER
|
||||
COMPUTE_UNITS = tools.COMPUTE_UNITS
|
||||
PURCHASE_RESOURCE = tools.PURCHASE_RESOURCE
|
||||
)
|
||||
|
||||
// will turn into standards api hostnames
|
||||
@ -585,3 +588,17 @@ func (l *LibData) ToComputeUnits() *compute_units.ComputeUnits {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LibData) ToBookings() *booking.Booking {
|
||||
if l.Data.GetAccessor(nil).GetType() == tools.BOOKING {
|
||||
return l.Data.(*booking.Booking)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *LibData) ToPurchasedResource() *purchase_resource.PurchaseResource {
|
||||
if l.Data.GetAccessor(nil).GetType() == tools.COMPUTE_UNITS {
|
||||
return l.Data.(*purchase_resource.PurchaseResource)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
25
models/bill/bill.go
Normal file
25
models/bill/bill.go
Normal file
@ -0,0 +1,25 @@
|
||||
package bill
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
/*
|
||||
* Bill is a struct that represents when emit billing
|
||||
*/
|
||||
type Bill struct {
|
||||
utils.AbstractObject
|
||||
}
|
||||
|
||||
func (r *Bill) StoreDraftDefault() {
|
||||
r.IsDraft = true
|
||||
}
|
||||
|
||||
func (r *Bill) CanDelete() bool {
|
||||
return r.IsDraft // only draft ComputeUnits can be deleted
|
||||
}
|
||||
|
||||
func (d *Bill) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return NewAccessor(request) // Create a new instance of the accessor
|
||||
}
|
63
models/bill/bill_mongo_accessor.go
Normal file
63
models/bill/bill_mongo_accessor.go
Normal file
@ -0,0 +1,63 @@
|
||||
package bill
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||
"cloud.o-forge.io/core/oc-lib/logs"
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
type billMongoAccessor struct {
|
||||
utils.AbstractAccessor // AbstractAccessor contains the basic fields of an accessor (model, caller)
|
||||
}
|
||||
|
||||
// New creates a new instance of the billMongoAccessor
|
||||
func NewAccessor(request *tools.APIRequest) *billMongoAccessor {
|
||||
return &billMongoAccessor{
|
||||
AbstractAccessor: utils.AbstractAccessor{
|
||||
Logger: logs.CreateLogger(tools.COMPUTE_UNITS.String()), // Create a logger with the data type
|
||||
Request: request,
|
||||
Type: tools.COMPUTE_UNITS,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing special here, just the basic CRUD operations
|
||||
*/
|
||||
func (a *billMongoAccessor) DeleteOne(id string) (utils.DBObject, int, error) {
|
||||
return utils.GenericDeleteOne(id, a)
|
||||
}
|
||||
|
||||
func (a *billMongoAccessor) UpdateOne(set utils.DBObject, id string) (utils.DBObject, int, error) {
|
||||
// should verify if a source is existing...
|
||||
return utils.GenericUpdateOne(set, id, a, &Bill{})
|
||||
}
|
||||
|
||||
func (a *billMongoAccessor) StoreOne(data utils.DBObject) (utils.DBObject, int, error) {
|
||||
return utils.GenericStoreOne(data.(*Bill), a)
|
||||
}
|
||||
|
||||
func (a *billMongoAccessor) CopyOne(data utils.DBObject) (utils.DBObject, int, error) {
|
||||
return utils.GenericStoreOne(data.(*Bill), a)
|
||||
}
|
||||
|
||||
func (a *billMongoAccessor) LoadOne(id string) (utils.DBObject, int, error) {
|
||||
return utils.GenericLoadOne[*Bill](id, func(d utils.DBObject) (utils.DBObject, int, error) {
|
||||
return d, 200, nil
|
||||
}, a)
|
||||
}
|
||||
|
||||
func (a *billMongoAccessor) LoadAll(isDraft bool) ([]utils.ShallowDBObject, int, error) {
|
||||
return utils.GenericLoadAll[*Bill](a.getExec(), isDraft, a)
|
||||
}
|
||||
|
||||
func (a *billMongoAccessor) Search(filters *dbs.Filters, search string, isDraft bool) ([]utils.ShallowDBObject, int, error) {
|
||||
return utils.GenericSearch[*Bill](filters, search, (&Bill{}).GetObjectFilters(search), a.getExec(), isDraft, a)
|
||||
}
|
||||
|
||||
func (a *billMongoAccessor) getExec() func(utils.DBObject) utils.ShallowDBObject {
|
||||
return func(d utils.DBObject) utils.ShallowDBObject {
|
||||
return d
|
||||
}
|
||||
}
|
@ -9,7 +9,8 @@ import (
|
||||
type PricedItemITF interface {
|
||||
GetID() string
|
||||
GetType() tools.DataType
|
||||
IsPurchased() bool
|
||||
IsPurchasable() bool
|
||||
IsBooked() bool
|
||||
GetCreatorID() string
|
||||
GetLocationStart() *time.Time
|
||||
SetLocationStart(start time.Time)
|
||||
|
@ -6,7 +6,8 @@ import (
|
||||
|
||||
type PricingProfileITF interface {
|
||||
GetPrice(quantity float64, val float64, start time.Time, end time.Time, params ...string) (float64, error)
|
||||
IsPurchased() bool
|
||||
IsPurchasable() bool
|
||||
IsBooked() bool
|
||||
GetOverrideStrategyValue() int
|
||||
}
|
||||
|
||||
|
@ -7,21 +7,65 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type BillingStrategy int // BAM BAM
|
||||
|
||||
// should except... on
|
||||
const (
|
||||
BILL_ONCE BillingStrategy = iota // is a permanent buying ( predictible )
|
||||
BILL_PER_WEEK
|
||||
BILL_PER_MONTH
|
||||
BILL_PER_YEAR
|
||||
)
|
||||
|
||||
func (t BillingStrategy) IsBillingStrategyAllowed(bs int) (BillingStrategy, bool) {
|
||||
switch t {
|
||||
case BILL_ONCE:
|
||||
return BILL_ONCE, bs == 0
|
||||
case BILL_PER_WEEK:
|
||||
case BILL_PER_MONTH:
|
||||
case BILL_PER_YEAR:
|
||||
return t, bs != 0
|
||||
}
|
||||
return t, false
|
||||
}
|
||||
|
||||
func (t BillingStrategy) String() string {
|
||||
return [...]string{"BILL_ONCE", "BILL_PER_WEEK", "BILL_PER_MONTH", "BILL_PER_YEAR"}[t]
|
||||
}
|
||||
|
||||
func BillingStrategyList() []BillingStrategy {
|
||||
return []BillingStrategy{BILL_ONCE, BILL_PER_WEEK, BILL_PER_MONTH, BILL_PER_YEAR}
|
||||
}
|
||||
|
||||
type BuyingStrategy int
|
||||
|
||||
// should except... on
|
||||
const (
|
||||
UNLIMITED BuyingStrategy = iota
|
||||
SUBSCRIPTION
|
||||
PAY_PER_USE
|
||||
PERMANENT BuyingStrategy = iota // is a permanent buying ( predictible )
|
||||
UNDEFINED_SUBSCRIPTION // a endless subscription ( unpredictible )
|
||||
SUBSCRIPTION // a defined subscription ( predictible )
|
||||
// PAY_PER_USE // per request. ( unpredictible )
|
||||
)
|
||||
|
||||
func (t BuyingStrategy) String() string {
|
||||
return [...]string{"UNLIMITED", "SUBSCRIPTION", "PAY PER USE"}[t]
|
||||
return [...]string{"PERMANENT", "UNDEFINED_SUBSCRIPTION", "SUBSCRIPTION"}[t]
|
||||
}
|
||||
|
||||
func (t BuyingStrategy) IsBillingStrategyAllowed(bs BillingStrategy) (BillingStrategy, bool) {
|
||||
switch t {
|
||||
case PERMANENT:
|
||||
return BILL_ONCE, bs == BILL_ONCE
|
||||
case UNDEFINED_SUBSCRIPTION:
|
||||
return BILL_PER_MONTH, bs != BILL_ONCE
|
||||
case SUBSCRIPTION:
|
||||
/*case PAY_PER_USE:
|
||||
return bs, true*/
|
||||
}
|
||||
return bs, false
|
||||
}
|
||||
|
||||
func BuyingStrategyList() []BuyingStrategy {
|
||||
return []BuyingStrategy{UNLIMITED, SUBSCRIPTION, PAY_PER_USE}
|
||||
return []BuyingStrategy{PERMANENT, UNDEFINED_SUBSCRIPTION, SUBSCRIPTION}
|
||||
}
|
||||
|
||||
type Strategy interface {
|
||||
@ -118,7 +162,7 @@ type PricingStrategy[T Strategy] struct {
|
||||
func (p PricingStrategy[T]) GetPrice(amountOfData float64, bookingTimeDuration float64, start time.Time, end *time.Time) (float64, error) {
|
||||
if p.BuyingStrategy == SUBSCRIPTION {
|
||||
return BookingEstimation(p.GetTimePricingStrategy(), p.Price*float64(amountOfData), bookingTimeDuration, start, end)
|
||||
} else if p.BuyingStrategy == UNLIMITED {
|
||||
} else if p.BuyingStrategy == PERMANENT {
|
||||
return p.Price, nil
|
||||
}
|
||||
return p.Price * float64(amountOfData), nil
|
||||
|
@ -15,9 +15,9 @@ func (d DummyStrategy) GetStrategy() string { return "DUMMY" }
|
||||
func (d DummyStrategy) GetStrategyValue() int { return int(d) }
|
||||
|
||||
func TestBuyingStrategy_String(t *testing.T) {
|
||||
assert.Equal(t, "UNLIMITED", pricing.UNLIMITED.String())
|
||||
assert.Equal(t, "UNLIMITED", pricing.PERMANENT.String())
|
||||
assert.Equal(t, "SUBSCRIPTION", pricing.SUBSCRIPTION.String())
|
||||
assert.Equal(t, "PAY PER USE", pricing.PAY_PER_USE.String())
|
||||
//assert.Equal(t, "PAY PER USE", pricing.PAY_PER_USE.String())
|
||||
}
|
||||
|
||||
func TestBuyingStrategyList(t *testing.T) {
|
||||
@ -116,13 +116,13 @@ func TestPricingStrategy_GetPrice(t *testing.T) {
|
||||
assert.True(t, p > 0)
|
||||
|
||||
// UNLIMITED case
|
||||
ps.BuyingStrategy = pricing.UNLIMITED
|
||||
ps.BuyingStrategy = pricing.PERMANENT
|
||||
p, err = ps.GetPrice(10, 0, start, &end)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 5.0, p)
|
||||
|
||||
// PAY_PER_USE case
|
||||
ps.BuyingStrategy = pricing.PAY_PER_USE
|
||||
//ps.BuyingStrategy = pricing.PAY_PER_USE
|
||||
p, err = ps.GetPrice(3, 0, start, &end)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 15.0, p)
|
||||
|
@ -2,6 +2,7 @@ package models
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/logs"
|
||||
"cloud.o-forge.io/core/oc-lib/models/bill"
|
||||
"cloud.o-forge.io/core/oc-lib/models/compute_units"
|
||||
"cloud.o-forge.io/core/oc-lib/models/order"
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
|
||||
@ -40,6 +41,7 @@ var ModelsCatalog = map[string]func() utils.DBObject{
|
||||
tools.ORDER.String(): func() utils.DBObject { return &order.Order{} },
|
||||
tools.PURCHASE_RESOURCE.String(): func() utils.DBObject { return &purchase_resource.PurchaseResource{} },
|
||||
tools.COMPUTE_UNITS.String(): func() utils.DBObject { return &compute_units.ComputeUnits{} },
|
||||
tools.BILL.String(): func() utils.DBObject { return &bill.Bill{} },
|
||||
}
|
||||
|
||||
// Model returns the model object based on the model type
|
||||
|
@ -265,7 +265,7 @@ func (d *PeerOrder) Pay(request *tools.APIRequest, response chan *PeerOrder, wg
|
||||
d.Status = enum.PAID // TO REMOVE LATER IT'S A MOCK
|
||||
if d.Status == enum.PAID {
|
||||
for _, b := range d.Items {
|
||||
if !b.Item.IsPurchased() {
|
||||
if !b.Item.IsPurchasable() {
|
||||
continue
|
||||
}
|
||||
accessor := purchase_resource.NewAccessor(request)
|
||||
|
@ -80,8 +80,15 @@ type ComputeResourcePricingProfile struct {
|
||||
RAMPrice float64 `json:"ram_price" bson:"ram_price" default:"-1"` // RAMPrice is the price of the RAM
|
||||
}
|
||||
|
||||
func (p *ComputeResourcePricingProfile) IsPurchased() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
func (p *ComputeResourcePricingProfile) IsPurchasable() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.UNDEFINED_SUBSCRIPTION
|
||||
}
|
||||
|
||||
func (p *ComputeResourcePricingProfile) IsBooked() bool {
|
||||
if p.Pricing.BuyingStrategy == pricing.PERMANENT {
|
||||
p.Pricing.BuyingStrategy = pricing.SUBSCRIPTION
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *ComputeResourcePricingProfile) GetOverrideStrategyValue() int {
|
||||
|
@ -137,8 +137,13 @@ func (p *DataResourcePricingProfile) GetPrice(amountOfData float64, explicitDura
|
||||
return p.Pricing.GetPrice(amountOfData, explicitDuration, start, &end)
|
||||
}
|
||||
|
||||
func (p *DataResourcePricingProfile) IsPurchased() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
func (p *DataResourcePricingProfile) IsPurchasable() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.UNDEFINED_SUBSCRIPTION
|
||||
}
|
||||
|
||||
func (p *DataResourcePricingProfile) IsBooked() bool {
|
||||
// TODO WHAT ABOUT PAY PER USE... it's a complicate CASE
|
||||
return p.Pricing.BuyingStrategy != pricing.PERMANENT
|
||||
}
|
||||
|
||||
type PricedDataResource struct {
|
||||
|
@ -35,11 +35,18 @@ func (abs *PricedResource) GetCreatorID() string {
|
||||
return abs.CreatorID
|
||||
}
|
||||
|
||||
func (abs *PricedResource) IsPurchased() bool {
|
||||
func (abs *PricedResource) IsPurchasable() bool {
|
||||
if abs.SelectedPricing == nil {
|
||||
return false
|
||||
}
|
||||
return (abs.SelectedPricing).IsPurchased()
|
||||
return (abs.SelectedPricing).IsPurchasable()
|
||||
}
|
||||
|
||||
func (abs *PricedResource) IsBooked() bool {
|
||||
if abs.SelectedPricing == nil {
|
||||
return false
|
||||
}
|
||||
return (abs.SelectedPricing).IsBooked()
|
||||
}
|
||||
|
||||
func (abs *PricedResource) GetLocationEnd() *time.Time {
|
||||
|
@ -77,8 +77,12 @@ 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
|
||||
}
|
||||
|
||||
func (p *ProcessingResourcePricingProfile) IsPurchased() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
func (p *ProcessingResourcePricingProfile) IsPurchasable() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.UNDEFINED_SUBSCRIPTION
|
||||
}
|
||||
|
||||
func (p *ProcessingResourcePricingProfile) IsBooked() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PERMANENT
|
||||
}
|
||||
|
||||
func (p *ProcessingResourcePricingProfile) GetPrice(amountOfData float64, val float64, start time.Time, end time.Time, params ...string) (float64, error) {
|
||||
|
@ -52,7 +52,8 @@ type AbstractInstanciatedResource[T ResourceInstanceITF] struct {
|
||||
Instances []T `json:"instances,omitempty" bson:"instances,omitempty"` // Bill is the bill of the resource // Bill is the bill of the resource
|
||||
}
|
||||
|
||||
func (abs *AbstractInstanciatedResource[T]) ConvertToPricedResource(t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF {
|
||||
func (abs *AbstractInstanciatedResource[T]) ConvertToPricedResource(
|
||||
t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF {
|
||||
instances := map[string]string{}
|
||||
profiles := []pricing.PricingProfileITF{}
|
||||
for _, instance := range abs.Instances {
|
||||
|
@ -152,8 +152,15 @@ type StorageResourcePricingProfile struct {
|
||||
pricing.ExploitPricingProfile[StorageResourcePricingStrategy] // ExploitPricingProfile is the pricing profile of a storage it means that we exploit the resource for an amount of continuous time
|
||||
}
|
||||
|
||||
func (p *StorageResourcePricingProfile) IsPurchased() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
func (p *StorageResourcePricingProfile) IsPurchasable() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.UNDEFINED_SUBSCRIPTION
|
||||
}
|
||||
|
||||
func (p *StorageResourcePricingProfile) IsBooked() bool {
|
||||
if p.Pricing.BuyingStrategy == pricing.PERMANENT {
|
||||
p.Pricing.BuyingStrategy = pricing.SUBSCRIPTION
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *StorageResourcePricingProfile) GetPrice(amountOfData float64, val float64, start time.Time, end time.Time, params ...string) (float64, error) {
|
||||
|
@ -76,11 +76,8 @@ func TestDataResourcePricingStrategy_GetQuantity(t *testing.T) {
|
||||
|
||||
func TestDataResourcePricingProfile_IsPurchased(t *testing.T) {
|
||||
profile := &resources.DataResourcePricingProfile{}
|
||||
profile.Pricing.BuyingStrategy = pricing.PAY_PER_USE
|
||||
assert.False(t, profile.IsPurchased())
|
||||
|
||||
profile.Pricing.BuyingStrategy = pricing.SUBSCRIPTION
|
||||
assert.True(t, profile.IsPurchased())
|
||||
assert.True(t, profile.IsPurchasable())
|
||||
}
|
||||
|
||||
func TestPricedDataResource_GetPrice(t *testing.T) {
|
||||
|
@ -22,7 +22,7 @@ type MockPricingProfile struct {
|
||||
ReturnCost float64
|
||||
}
|
||||
|
||||
func (m *MockPricingProfile) IsPurchased() bool {
|
||||
func (m *MockPricingProfile) IsPurchasable() bool {
|
||||
return m.Purchased
|
||||
}
|
||||
|
||||
@ -49,13 +49,13 @@ func TestGetIDAndCreatorAndType(t *testing.T) {
|
||||
func TestIsPurchased(t *testing.T) {
|
||||
t.Run("nil selected pricing returns false", func(t *testing.T) {
|
||||
r := &resources.PricedResource{}
|
||||
assert.False(t, r.IsPurchased())
|
||||
assert.False(t, r.IsPurchasable())
|
||||
})
|
||||
|
||||
t.Run("returns true if pricing profile is purchased", func(t *testing.T) {
|
||||
mock := &MockPricingProfile{Purchased: true}
|
||||
r := &resources.PricedResource{SelectedPricing: mock}
|
||||
assert.True(t, r.IsPurchased())
|
||||
assert.True(t, r.IsPurchasable())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -95,21 +95,12 @@ func TestProcessingResourcePricingProfile_GetPrice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProcessingResourcePricingProfile_IsPurchased(t *testing.T) {
|
||||
nonPurchased := &ProcessingResourcePricingProfile{
|
||||
AccessPricingProfile: pricing.AccessPricingProfile[pricing.TimePricingStrategy]{
|
||||
Pricing: pricing.PricingStrategy[pricing.TimePricingStrategy]{
|
||||
BuyingStrategy: pricing.PAY_PER_USE,
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.False(t, nonPurchased.IsPurchased())
|
||||
|
||||
purchased := &ProcessingResourcePricingProfile{
|
||||
AccessPricingProfile: pricing.AccessPricingProfile[pricing.TimePricingStrategy]{
|
||||
Pricing: pricing.PricingStrategy[pricing.TimePricingStrategy]{
|
||||
BuyingStrategy: pricing.UNLIMITED,
|
||||
BuyingStrategy: pricing.PERMANENT,
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.True(t, purchased.IsPurchased())
|
||||
assert.True(t, purchased.IsPurchasable())
|
||||
}
|
||||
|
@ -2,10 +2,8 @@ package resources_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/models/common/models"
|
||||
"cloud.o-forge.io/core/oc-lib/models/common/pricing"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@ -107,43 +105,3 @@ func TestPricedStorageResource_GetPrice_NoProfiles(t *testing.T) {
|
||||
_, err := res.GetPrice()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestPricedStorageResource_GetPrice_WithPricing(t *testing.T) {
|
||||
now := time.Now()
|
||||
end := now.Add(2 * time.Hour)
|
||||
profile := &resources.StorageResourcePricingProfile{
|
||||
ExploitPricingProfile: pricing.ExploitPricingProfile[resources.StorageResourcePricingStrategy]{
|
||||
AccessPricingProfile: pricing.AccessPricingProfile[resources.StorageResourcePricingStrategy]{
|
||||
Pricing: pricing.PricingStrategy[resources.StorageResourcePricingStrategy]{
|
||||
BuyingStrategy: pricing.PAY_PER_USE,
|
||||
Price: 42.0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
res := &resources.PricedStorageResource{
|
||||
PricedResource: resources.PricedResource{
|
||||
UsageStart: &now,
|
||||
UsageEnd: &end,
|
||||
PricingProfiles: []pricing.PricingProfileITF{profile},
|
||||
},
|
||||
UsageStorageGB: 1.0,
|
||||
}
|
||||
price, err := res.GetPrice()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 42.0, price)
|
||||
}
|
||||
|
||||
func TestStorageResourcePricingProfile_IsPurchased(t *testing.T) {
|
||||
p := &resources.StorageResourcePricingProfile{
|
||||
ExploitPricingProfile: pricing.ExploitPricingProfile[resources.StorageResourcePricingStrategy]{
|
||||
AccessPricingProfile: pricing.AccessPricingProfile[resources.StorageResourcePricingStrategy]{
|
||||
Pricing: pricing.PricingStrategy[resources.StorageResourcePricingStrategy]{BuyingStrategy: pricing.PAY_PER_USE},
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.False(t, p.IsPurchased())
|
||||
|
||||
p.Pricing.BuyingStrategy = pricing.UNLIMITED
|
||||
assert.True(t, p.IsPurchased())
|
||||
}
|
||||
|
@ -169,8 +169,8 @@ func (wfa *Workflow) CheckBooking(caller *tools.HTTPCaller) (bool, error) {
|
||||
func (wf *Workflow) Planify(start time.Time, end *time.Time, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) (float64, map[tools.DataType]map[string]pricing.PricedItemITF, *Workflow, error) {
|
||||
priceds := map[tools.DataType]map[string]pricing.PricedItemITF{}
|
||||
ps, priceds, err := plan[*resources.ProcessingResource](tools.PROCESSING_RESOURCE, wf, priceds, request,
|
||||
buyingStrategy, pricingStrategy,
|
||||
wf.Graph.IsProcessing, func(res resources.ResourceInterface, priced pricing.PricedItemITF) (time.Time, float64) {
|
||||
buyingStrategy, pricingStrategy, wf.Graph.IsProcessing,
|
||||
func(res resources.ResourceInterface, priced pricing.PricedItemITF) (time.Time, float64) {
|
||||
return start.Add(time.Duration(wf.Graph.GetAverageTimeProcessingBeforeStart(0, res.GetID(), request, buyingStrategy, pricingStrategy)) * time.Second), priced.GetExplicitDurationInS()
|
||||
}, func(started time.Time, duration float64) *time.Time {
|
||||
s := started.Add(time.Duration(duration))
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"cloud.o-forge.io/core/oc-lib/models/booking"
|
||||
"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/resources/purchase_resource"
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
"github.com/google/uuid"
|
||||
@ -21,6 +22,7 @@ import (
|
||||
*/
|
||||
type WorkflowExecution struct {
|
||||
utils.AbstractObject // AbstractObject contains the basic fields of an object (id, name)
|
||||
PeerBuyByGraph map[string]map[string][]string `json:"peer_buy_by_graph,omitempty" bson:"peer_buy_by_graph,omitempty"` // BookByResource is a map of the resource id and the list of the booking id
|
||||
PeerBookByGraph map[string]map[string][]string `json:"peer_book_by_graph,omitempty" bson:"peer_book_by_graph,omitempty"` // BookByResource is a map of the resource id and the list of the booking id
|
||||
ExecutionsID string `json:"executions_id,omitempty" bson:"executions_id,omitempty"`
|
||||
ExecDate time.Time `json:"execution_date,omitempty" bson:"execution_date,omitempty" validate:"required"` // ExecDate is the execution date of the workflow, is required
|
||||
@ -110,10 +112,51 @@ func (d *WorkflowExecution) VerifyAuth(request *tools.APIRequest) bool {
|
||||
}
|
||||
|
||||
/*
|
||||
booking is an activity reserved for not a long time investment.
|
||||
... purchase is dependant of a one time buying.
|
||||
use of a datacenter or storage can't be buy for permanent.
|
||||
booking is an activity reserved for not a long time investment.
|
||||
... purchase is dependant of a one time buying.
|
||||
use of a datacenter or storage can't be buy for permanent access.
|
||||
*/
|
||||
func (d *WorkflowExecution) Buy(bs pricing.BillingStrategy, executionsID string, wfID string, priceds map[tools.DataType]map[string]pricing.PricedItemITF) []*purchase_resource.PurchaseResource {
|
||||
purchases := d.buyEach(bs, executionsID, wfID, tools.PROCESSING_RESOURCE, priceds[tools.PROCESSING_RESOURCE])
|
||||
purchases = append(purchases, d.buyEach(bs, executionsID, wfID, tools.DATA_RESOURCE, priceds[tools.DATA_RESOURCE])...)
|
||||
return purchases
|
||||
}
|
||||
|
||||
func (d *WorkflowExecution) buyEach(bs pricing.BillingStrategy, executionsID string, wfID string, dt tools.DataType, priceds map[string]pricing.PricedItemITF) []*purchase_resource.PurchaseResource {
|
||||
items := []*purchase_resource.PurchaseResource{}
|
||||
for itemID, priced := range priceds {
|
||||
if !priced.IsPurchasable() && bs == pricing.BILL_ONCE { // buy only that must be buy
|
||||
continue
|
||||
}
|
||||
if d.PeerBuyByGraph == nil {
|
||||
d.PeerBuyByGraph = map[string]map[string][]string{}
|
||||
}
|
||||
if d.PeerBuyByGraph[priced.GetCreatorID()] == nil {
|
||||
d.PeerBuyByGraph[priced.GetCreatorID()] = map[string][]string{}
|
||||
}
|
||||
if d.PeerBuyByGraph[priced.GetCreatorID()][itemID] == nil {
|
||||
d.PeerBuyByGraph[priced.GetCreatorID()][itemID] = []string{}
|
||||
}
|
||||
start := d.ExecDate
|
||||
if s := priced.GetLocationStart(); s != nil {
|
||||
start = *s
|
||||
}
|
||||
end := start.Add(time.Duration(priced.GetExplicitDurationInS()) * time.Second)
|
||||
bookingItem := &purchase_resource.PurchaseResource{
|
||||
AbstractObject: utils.AbstractObject{
|
||||
UUID: uuid.New().String(),
|
||||
Name: d.GetName() + "_" + executionsID + "_" + wfID,
|
||||
},
|
||||
ResourceID: priced.GetID(),
|
||||
ResourceType: dt,
|
||||
EndDate: &end,
|
||||
}
|
||||
items = append(items, bookingItem)
|
||||
d.PeerBuyByGraph[priced.GetCreatorID()][itemID] = append(
|
||||
d.PeerBuyByGraph[priced.GetCreatorID()][itemID], bookingItem.GetID())
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func (d *WorkflowExecution) Book(executionsID string, wfID string, priceds map[tools.DataType]map[string]pricing.PricedItemITF) []*booking.Booking {
|
||||
booking := d.bookEach(executionsID, wfID, tools.STORAGE_RESOURCE, priceds[tools.STORAGE_RESOURCE])
|
||||
@ -126,6 +169,9 @@ func (d *WorkflowExecution) Book(executionsID string, wfID string, priceds map[t
|
||||
func (d *WorkflowExecution) bookEach(executionsID string, wfID string, dt tools.DataType, priceds map[string]pricing.PricedItemITF) []*booking.Booking {
|
||||
items := []*booking.Booking{}
|
||||
for itemID, priced := range priceds {
|
||||
if !priced.IsBooked() { // book only that must be booked
|
||||
continue
|
||||
}
|
||||
if d.PeerBookByGraph == nil {
|
||||
d.PeerBookByGraph = map[string]map[string][]string{}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"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/peer"
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/models/workflow"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
@ -34,8 +35,9 @@ type WorkflowSchedule struct {
|
||||
DurationS float64 `json:"duration_s" default:"-1"` // End is the end time of the schedule
|
||||
Cron string `json:"cron,omitempty"` // here the cron format : ss mm hh dd MM dw task
|
||||
|
||||
SelectedBuyingStrategy pricing.BuyingStrategy `json:"selected_buying_strategy"`
|
||||
SelectedPricingStrategy int `json:"selected_pricing_strategy"`
|
||||
SelectedBuyingStrategy pricing.BuyingStrategy `json:"selected_buying_strategy"`
|
||||
SelectedPricingStrategy int `json:"selected_pricing_strategy"`
|
||||
SelectedBillingStrategy pricing.BillingStrategy `json:"selected_billing_strategy"`
|
||||
}
|
||||
|
||||
func NewScheduler(start string, end string, durationInS float64, cron string) *WorkflowSchedule {
|
||||
@ -79,8 +81,10 @@ func (ws *WorkflowSchedule) CheckBooking(wfID string, request *tools.APIRequest)
|
||||
if err != nil {
|
||||
return false, wf, []*WorkflowExecution{}, []*booking.Booking{}, err
|
||||
}
|
||||
purchased := []*purchase_resource.PurchaseResource{}
|
||||
bookings := []*booking.Booking{}
|
||||
for _, exec := range execs {
|
||||
purchased = append(purchased, exec.Buy(ws.SelectedBillingStrategy, ws.UUID, wfID, priceds)...)
|
||||
bookings = append(bookings, exec.Book(ws.UUID, wfID, priceds)...)
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ const (
|
||||
ADMIRALTY_KUBECONFIG
|
||||
ADMIRALTY_NODES
|
||||
COMPUTE_UNITS
|
||||
BILL
|
||||
)
|
||||
|
||||
var NOAPI = ""
|
||||
@ -67,6 +68,7 @@ var DefaultAPI = [...]string{
|
||||
ADMIRALTY_KUBECONFIGAPI,
|
||||
ADMIRALTY_NODESAPI,
|
||||
DATACENTERAPI,
|
||||
NOAPI,
|
||||
}
|
||||
|
||||
// Bind the standard data name to the data type
|
||||
@ -94,6 +96,7 @@ var Str = [...]string{
|
||||
"admiralty_kubeconfig",
|
||||
"admiralty_node",
|
||||
"compute_units",
|
||||
"bill",
|
||||
}
|
||||
|
||||
func FromInt(i int) string {
|
||||
@ -114,5 +117,7 @@ func (d DataType) EnumIndex() int {
|
||||
}
|
||||
|
||||
func DataTypeList() []DataType {
|
||||
return []DataType{DATA_RESOURCE, PROCESSING_RESOURCE, STORAGE_RESOURCE, COMPUTE_RESOURCE, WORKFLOW_RESOURCE, WORKFLOW, WORKFLOW_EXECUTION, WORKSPACE, PEER, COLLABORATIVE_AREA, RULE, BOOKING, WORKFLOW_HISTORY, WORKSPACE_HISTORY, ORDER, PURCHASE_RESOURCE, ADMIRALTY_SOURCE, ADMIRALTY_TARGET, ADMIRALTY_SECRET, ADMIRALTY_KUBECONFIG, ADMIRALTY_NODES}
|
||||
return []DataType{DATA_RESOURCE, PROCESSING_RESOURCE, STORAGE_RESOURCE, COMPUTE_RESOURCE, WORKFLOW_RESOURCE,
|
||||
WORKFLOW, WORKFLOW_EXECUTION, WORKSPACE, PEER, COLLABORATIVE_AREA, RULE, BOOKING, WORKFLOW_HISTORY, WORKSPACE_HISTORY,
|
||||
ORDER, PURCHASE_RESOURCE, ADMIRALTY_SOURCE, ADMIRALTY_TARGET, ADMIRALTY_SECRET, ADMIRALTY_KUBECONFIG, ADMIRALTY_NODES, COMPUTE_UNITS, BILL}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user