add sets up

This commit is contained in:
mr
2025-06-20 12:10:36 +02:00
parent 583ca2fbac
commit 29b192211d
22 changed files with 136 additions and 131 deletions

View File

@@ -30,12 +30,11 @@ func (r *ComputeResource) GetType() string {
return tools.COMPUTE_RESOURCE.String()
}
func (abs *ComputeResource) ConvertToPricedResource(
t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF {
func (abs *ComputeResource) ConvertToPricedResource(t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF {
if t != tools.COMPUTE_RESOURCE {
return nil
}
p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request, buyingStrategy, pricingStrategy)
p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request)
priced := p.(*PricedResource)
return &PricedComputeResource{
PricedResource: *priced,
@@ -84,6 +83,10 @@ func (p *ComputeResourcePricingProfile) IsPurchasable() bool {
return p.Pricing.BuyingStrategy != pricing.UNDEFINED_SUBSCRIPTION
}
func (p *ComputeResourcePricingProfile) GetPurchase() pricing.BuyingStrategy {
return p.Pricing.BuyingStrategy
}
func (p *ComputeResourcePricingProfile) IsBooked() bool {
if p.Pricing.BuyingStrategy == pricing.PERMANENT {
p.Pricing.BuyingStrategy = pricing.SUBSCRIPTION
@@ -159,10 +162,7 @@ func (r *PricedComputeResource) GetPrice() (float64, error) {
r.UsageEnd = &add
}
if r.SelectedPricing == nil {
if len(r.PricingProfiles) == 0 {
return 0, errors.New("pricing profile must be set on Priced Compute" + r.ResourceID)
}
r.SelectedPricing = r.PricingProfiles[0]
return 0, errors.New("pricing profile must be set on Priced Compute" + r.ResourceID)
}
pricing := r.SelectedPricing
price := float64(0)

View File

@@ -37,12 +37,11 @@ func (r *DataResource) GetType() string {
return tools.DATA_RESOURCE.String()
}
func (abs *DataResource) ConvertToPricedResource(
t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF {
func (abs *DataResource) ConvertToPricedResource(t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF {
if t != tools.DATA_RESOURCE {
return nil
}
p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request, buyingStrategy, pricingStrategy)
p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request)
priced := p.(*PricedResource)
return &PricedDataResource{
PricedResource: *priced,
@@ -137,6 +136,10 @@ func (p *DataResourcePricingProfile) GetPrice(amountOfData float64, explicitDura
return p.Pricing.GetPrice(amountOfData, explicitDuration, start, &end)
}
func (p *DataResourcePricingProfile) GetPurchase() pricing.BuyingStrategy {
return p.Pricing.BuyingStrategy
}
func (p *DataResourcePricingProfile) IsPurchasable() bool {
return p.Pricing.BuyingStrategy != pricing.UNDEFINED_SUBSCRIPTION
}
@@ -166,10 +169,7 @@ func (r *PricedDataResource) GetPrice() (float64, error) {
r.UsageEnd = &add
}
if r.SelectedPricing == nil {
if len(r.PricingProfiles) == 0 {
return 0, errors.New("pricing profile must be set on Priced Data" + r.ResourceID)
}
r.SelectedPricing = r.PricingProfiles[0]
return 0, errors.New("pricing profile must be set on Priced Data" + r.ResourceID)
}
pricing := r.SelectedPricing
var err error

View File

@@ -9,9 +9,9 @@ import (
type ResourceInterface interface {
utils.DBObject
Trim()
ConvertToPricedResource(t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF
ConvertToPricedResource(t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF
GetType() string
GetSelectedInstance() utils.DBObject
GetSelectedInstance() ResourceInstanceITF
ClearEnv() utils.DBObject
SetAllowedInstances(request *tools.APIRequest)
}
@@ -22,15 +22,15 @@ type ResourceInstanceITF interface {
GetName() string
StoreDraftDefault()
ClearEnv()
GetPricingsProfiles(peerID string, groups []string, buyingStrategy int, pricingStrategy int) []pricing.PricingProfileITF
GetProfile() pricing.PricingProfileITF
GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF
GetPeerGroups() ([]ResourcePartnerITF, []map[string][]string)
ClearPeerGroups()
GetSelectedPartnership() ResourcePartnerITF
GetPartnerships(peerID string, groups []string) []ResourcePartnerITF
}
type ResourcePartnerITF interface {
GetPricingsProfiles(peerID string, groups []string, buyingStrategy int, pricingStrategy int) []pricing.PricingProfileITF
GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF
GetPeerGroups() map[string][]string
ClearPeerGroups()
}

View File

@@ -10,17 +10,20 @@ import (
)
type PricedResource struct {
Name string `json:"name,omitempty" bson:"name,omitempty"`
Logo string `json:"logo,omitempty" bson:"logo,omitempty"`
InstancesRefs map[string]string `json:"instances_refs,omitempty" bson:"instances_refs,omitempty"`
PricingProfiles []pricing.PricingProfileITF `json:"pricing_profiles,omitempty" bson:"pricing_profiles,omitempty"`
SelectedPricing pricing.PricingProfileITF `json:"selected_pricing,omitempty" bson:"selected_pricing,omitempty"`
ExplicitBookingDurationS float64 `json:"explicit_location_duration_s,omitempty" bson:"explicit_location_duration_s,omitempty"`
UsageStart *time.Time `json:"start,omitempty" bson:"start,omitempty"`
UsageEnd *time.Time `json:"end,omitempty" bson:"end,omitempty"`
CreatorID string `json:"peer_id,omitempty" bson:"peer_id,omitempty"`
ResourceID string `json:"resource_id,omitempty" bson:"resource_id,omitempty"`
ResourceType tools.DataType `json:"resource_type,omitempty" bson:"resource_type,omitempty"`
Name string `json:"name,omitempty" bson:"name,omitempty"`
Logo string `json:"logo,omitempty" bson:"logo,omitempty"`
InstancesRefs map[string]string `json:"instances_refs,omitempty" bson:"instances_refs,omitempty"`
SelectedPricing pricing.PricingProfileITF `json:"selected_pricing,omitempty" bson:"selected_pricing,omitempty"`
ExplicitBookingDurationS float64 `json:"explicit_location_duration_s,omitempty" bson:"explicit_location_duration_s,omitempty"`
UsageStart *time.Time `json:"start,omitempty" bson:"start,omitempty"`
UsageEnd *time.Time `json:"end,omitempty" bson:"end,omitempty"`
CreatorID string `json:"peer_id,omitempty" bson:"peer_id,omitempty"`
ResourceID string `json:"resource_id,omitempty" bson:"resource_id,omitempty"`
ResourceType tools.DataType `json:"resource_type,omitempty" bson:"resource_type,omitempty"`
}
func (abs *PricedResource) SelectPricing() pricing.PricingProfileITF {
return abs.SelectedPricing
}
func (abs *PricedResource) GetID() string {
@@ -90,10 +93,7 @@ func (r *PricedResource) GetPrice() (float64, error) {
r.UsageEnd = &add
}
if r.SelectedPricing == nil {
if len(r.PricingProfiles) == 0 {
return 0, errors.New("pricing profile must be set on Priced Resource " + r.ResourceID)
}
r.SelectedPricing = r.PricingProfiles[0]
return 0, errors.New("pricing profile must be set on Priced Resource " + r.ResourceID)
}
pricing := r.SelectedPricing
return pricing.GetPrice(1, 0, *r.UsageStart, *r.UsageEnd)

View File

@@ -85,6 +85,10 @@ func (p *ProcessingResourcePricingProfile) IsBooked() bool {
return p.Pricing.BuyingStrategy != pricing.PERMANENT
}
func (p *ProcessingResourcePricingProfile) GetPurchase() pricing.BuyingStrategy {
return p.Pricing.BuyingStrategy
}
func (p *ProcessingResourcePricingProfile) GetPrice(amountOfData float64, val float64, start time.Time, end time.Time, params ...string) (float64, error) {
return p.Pricing.GetPrice(amountOfData, val, start, &end)
}

View File

@@ -24,7 +24,7 @@ type AbstractResource struct {
SelectedInstanceIndex *int `json:"selected_instance_index,omitempty" bson:"selected_instance_index,omitempty"` // SelectedInstance is the selected instance
}
func (r *AbstractResource) GetSelectedInstance() utils.DBObject {
func (r *AbstractResource) GetSelectedInstance() ResourceInstanceITF {
return nil
}
@@ -52,13 +52,19 @@ 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) pricing.PricedItemITF {
instances := map[string]string{}
profiles := []pricing.PricingProfileITF{}
for _, instance := range abs.Instances {
instances[instance.GetID()] = instance.GetName()
profiles = instance.GetPricingsProfiles(request.PeerID, request.Groups, buyingStrategy, pricingStrategy)
profiles = instance.GetPricingsProfiles(request.PeerID, request.Groups)
}
var profile pricing.PricingProfileITF
if t := abs.GetSelectedInstance(); t != nil {
profile = t.GetProfile()
}
if profile == nil && len(profiles) > 0 {
profile = profiles[0]
}
return &PricedResource{
Name: abs.Name,
@@ -66,7 +72,7 @@ func (abs *AbstractInstanciatedResource[T]) ConvertToPricedResource(
ResourceID: abs.UUID,
ResourceType: t,
InstancesRefs: instances,
PricingProfiles: profiles,
SelectedPricing: profile,
CreatorID: abs.CreatorID,
}
}
@@ -78,7 +84,7 @@ func (abs *AbstractInstanciatedResource[T]) ClearEnv() utils.DBObject {
return abs
}
func (r *AbstractInstanciatedResource[T]) GetSelectedInstance() utils.DBObject {
func (r *AbstractInstanciatedResource[T]) GetSelectedInstance() ResourceInstanceITF {
if r.SelectedInstanceIndex != nil && len(r.Instances) > *r.SelectedInstanceIndex {
return r.Instances[*r.SelectedInstanceIndex]
}
@@ -144,24 +150,14 @@ type Credentials struct {
type ResourceInstance[T ResourcePartnerITF] struct {
utils.AbstractObject
Location GeoPoint `json:"location,omitempty" bson:"location,omitempty"`
Country countries.CountryCode `json:"country,omitempty" bson:"country,omitempty"`
AccessProtocol string `json:"access_protocol,omitempty" bson:"access_protocol,omitempty"`
Env []models.Param `json:"env,omitempty" bson:"env,omitempty"`
Inputs []models.Param `json:"inputs,omitempty" bson:"inputs,omitempty"`
Outputs []models.Param `json:"outputs,omitempty" bson:"outputs,omitempty"`
SelectedPartnershipIndex *int `json:"selected_partnership_index,omitempty" bson:"selected_partnership_index,omitempty"` // SelectedInstance is the selected instance
Partnerships []T `json:"partnerships,omitempty" bson:"partnerships,omitempty"`
}
func (r *ResourceInstance[T]) GetSelectedPartnership() ResourcePartnerITF {
if r.SelectedPartnershipIndex != nil && len(r.Partnerships) > *r.SelectedPartnershipIndex {
return r.Partnerships[*r.SelectedPartnershipIndex]
}
if len(r.Partnerships) > 0 {
return r.Partnerships[0]
}
return nil
Location GeoPoint `json:"location,omitempty" bson:"location,omitempty"`
Country countries.CountryCode `json:"country,omitempty" bson:"country,omitempty"`
AccessProtocol string `json:"access_protocol,omitempty" bson:"access_protocol,omitempty"`
Env []models.Param `json:"env,omitempty" bson:"env,omitempty"`
Inputs []models.Param `json:"inputs,omitempty" bson:"inputs,omitempty"`
Outputs []models.Param `json:"outputs,omitempty" bson:"outputs,omitempty"`
SelectedPricing pricing.PricingProfileITF `json:"selected_pricing,omitempty" bson:"selected_pricing,omitempty"`
Partnerships []T `json:"partnerships,omitempty" bson:"partnerships,omitempty"`
}
func (ri *ResourceInstance[T]) ClearEnv() {
@@ -170,6 +166,10 @@ func (ri *ResourceInstance[T]) ClearEnv() {
ri.Outputs = []models.Param{}
}
func (ri *ResourceInstance[T]) GetProfile() pricing.PricingProfileITF {
return ri.SelectedPricing
}
func (ri *ResourceInstance[T]) GetPartnerships(peerID string, groups []string) []ResourcePartnerITF {
partners := []ResourcePartnerITF{}
for _, p := range ri.Partnerships {
@@ -184,10 +184,10 @@ func (ri *ResourceInstance[T]) GetPartnerships(peerID string, groups []string) [
return partners
}
func (ri *ResourceInstance[T]) GetPricingsProfiles(peerID string, groups []string, buyingStrategy int, pricingStrategy int) []pricing.PricingProfileITF {
func (ri *ResourceInstance[T]) GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF {
pricings := []pricing.PricingProfileITF{}
for _, p := range ri.Partnerships {
pricings = append(pricings, p.GetPricingsProfiles(peerID, groups, buyingStrategy, pricingStrategy)...)
pricings = append(pricings, p.GetPricingsProfiles(peerID, groups)...)
}
return pricings
}
@@ -222,16 +222,16 @@ note : il faut rajouté - une notion de facturation
Une order est l'ensemble de la commande... un booking une réservation, une purchase un acte d'achat.
Une bill (facture) représente alors... l'emission d'une facture à un instant T en but d'être honorée, envoyée ... etc.
*/
func (ri *ResourcePartnerShip[T]) GetPricingsProfiles(peerID string, groups []string, buyingStrategy int, pricingStrategy int) []pricing.PricingProfileITF {
func (ri *ResourcePartnerShip[T]) GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF {
profiles := []pricing.PricingProfileITF{}
if ri.PeerGroups[peerID] == nil {
return profiles
}
for _, p := range ri.PeerGroups[peerID] {
if slices.Contains(groups, p) || slices.Contains(groups, "*") {
for buyingS, ri := range ri.PricingProfiles {
if _, ok := ri[pricingStrategy]; ok && buyingS == buyingStrategy {
profiles = append(profiles, ri[pricingStrategy])
for _, ri := range ri.PricingProfiles {
for _, i := range ri {
profiles = append(profiles, i)
}
}
return profiles

View File

@@ -30,12 +30,11 @@ func (r *StorageResource) GetType() string {
return tools.STORAGE_RESOURCE.String()
}
func (abs *StorageResource) ConvertToPricedResource(
t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF {
func (abs *StorageResource) ConvertToPricedResource(t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF {
if t != tools.STORAGE_RESOURCE {
return nil
}
p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request, buyingStrategy, pricingStrategy)
p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request)
priced := p.(*PricedResource)
return &PricedStorageResource{
PricedResource: *priced,
@@ -153,6 +152,10 @@ 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) GetPurchase() pricing.BuyingStrategy {
return p.Pricing.BuyingStrategy
}
func (p *StorageResourcePricingProfile) IsPurchasable() bool {
return p.Pricing.BuyingStrategy != pricing.UNDEFINED_SUBSCRIPTION
}
@@ -188,10 +191,7 @@ func (r *PricedStorageResource) GetPrice() (float64, error) {
r.UsageEnd = &add
}
if r.SelectedPricing == nil {
if len(r.PricingProfiles) == 0 {
return 0, errors.New("pricing profile must be set on Priced Storage" + r.ResourceID)
}
r.SelectedPricing = r.PricingProfiles[0]
return 0, errors.New("pricing profile must be set on Priced Storage" + r.ResourceID)
}
pricing := r.SelectedPricing
var err error

View File

@@ -30,7 +30,7 @@ func TestComputeResource_ConvertToPricedResource(t *testing.T) {
cr := &resources.ComputeResource{}
cr.UUID = "comp123"
cr.AbstractInstanciatedResource.UUID = cr.UUID
result := cr.ConvertToPricedResource(tools.COMPUTE_RESOURCE, req, 0, 0)
result := cr.ConvertToPricedResource(tools.COMPUTE_RESOURCE, req)
assert.NotNil(t, result)
assert.IsType(t, &resources.PricedComputeResource{}, result)
}
@@ -62,20 +62,9 @@ func TestComputeResourcePricingProfile_GetPrice_InvalidParams(t *testing.T) {
func TestPricedComputeResource_GetPrice(t *testing.T) {
start := time.Now()
end := start.Add(1 * time.Hour)
profile := &resources.ComputeResourcePricingProfile{
CPUsPrices: map[string]float64{"Xeon": 1.0},
GPUsPrices: map[string]float64{"Tesla": 2.0},
RAMPrice: 0.5,
ExploitPricingProfile: pricing.ExploitPricingProfile[pricing.TimePricingStrategy]{
AccessPricingProfile: pricing.AccessPricingProfile[pricing.TimePricingStrategy]{
Pricing: pricing.PricingStrategy[pricing.TimePricingStrategy]{Price: 1.0},
},
},
}
r := resources.PricedComputeResource{
PricedResource: resources.PricedResource{
ResourceID: "comp456",
PricingProfiles: []pricing.PricingProfileITF{profile},
UsageStart: &start,
UsageEnd: &end,
ExplicitBookingDurationS: 3600,

View File

@@ -27,10 +27,10 @@ func TestDataResource_GetAccessor(t *testing.T) {
func TestDataResource_ConvertToPricedResource(t *testing.T) {
d := &resources.DataResource{}
d.UUID = "123"
res := d.ConvertToPricedResource(tools.DATA_RESOURCE, &tools.APIRequest{}, 0, 0)
res := d.ConvertToPricedResource(tools.DATA_RESOURCE, &tools.APIRequest{})
assert.IsType(t, &resources.PricedDataResource{}, res)
nilRes := d.ConvertToPricedResource(tools.PROCESSING_RESOURCE, &tools.APIRequest{}, 0, 0)
nilRes := d.ConvertToPricedResource(tools.PROCESSING_RESOURCE, &tools.APIRequest{})
assert.Nil(t, nilRes)
}
@@ -94,9 +94,6 @@ func TestPricedDataResource_GetPrice(t *testing.T) {
PricedResource: resources.PricedResource{
UsageStart: &now,
UsageEnd: &later,
PricingProfiles: []pricing.PricingProfileITF{
pricingProfile,
},
},
}

View File

@@ -101,11 +101,9 @@ func TestGetPrice(t *testing.T) {
t.Run("uses first profile if selected is nil", func(t *testing.T) {
start := time.Now()
end := start.Add(30 * time.Minute)
mock := &MockPricingProfile{ReturnCost: 42.0}
r := &resources.PricedResource{
PricingProfiles: []pricing.PricingProfileITF{mock},
UsageStart: &start,
UsageEnd: &end,
UsageStart: &start,
UsageEnd: &end,
}
price, err := r.GetPrice()
require.NoError(t, err)

View File

@@ -20,7 +20,7 @@ func (m *MockInstance) GetID() string { return m.ID }
func (m *MockInstance) GetName() string { return m.Name }
func (m *MockInstance) ClearEnv() {}
func (m *MockInstance) ClearPeerGroups() {}
func (m *MockInstance) GetPricingsProfiles(string, []string, int, int) []pricing.PricingProfileITF {
func (m *MockInstance) GetPricingsProfiles(string, []string) []pricing.PricingProfileITF {
return nil
}
func (m *MockInstance) GetPeerGroups() ([]resources.ResourcePartnerITF, []map[string][]string) {
@@ -37,7 +37,7 @@ func (m *MockPartner) GetPeerGroups() map[string][]string {
return m.groups
}
func (m *MockPartner) ClearPeerGroups() {}
func (m *MockPartner) GetPricingsProfiles(string, []string, int, int) []pricing.PricingProfileITF {
func (m *MockPartner) GetPricingsProfiles(string, []string) []pricing.PricingProfileITF {
return nil
}

View File

@@ -26,14 +26,14 @@ func TestStorageResource_ConvertToPricedResource_ValidType(t *testing.T) {
res := &resources.StorageResource{}
res.AbstractInstanciatedResource.CreatorID = "creator"
res.AbstractInstanciatedResource.UUID = "res-id"
priced := res.ConvertToPricedResource(tools.STORAGE_RESOURCE, &tools.APIRequest{}, 0, 0)
priced := res.ConvertToPricedResource(tools.STORAGE_RESOURCE, &tools.APIRequest{})
assert.NotNil(t, priced)
assert.IsType(t, &resources.PricedStorageResource{}, priced)
}
func TestStorageResource_ConvertToPricedResource_InvalidType(t *testing.T) {
res := &resources.StorageResource{}
priced := res.ConvertToPricedResource(tools.COMPUTE_RESOURCE, &tools.APIRequest{}, 0, 0)
priced := res.ConvertToPricedResource(tools.COMPUTE_RESOURCE, &tools.APIRequest{})
assert.Nil(t, priced)
}

View File

@@ -32,7 +32,7 @@ func TestWorkflowResource_ConvertToPricedResource(t *testing.T) {
Groups: []string{"group1"},
}
pr := w.ConvertToPricedResource(tools.WORKFLOW_RESOURCE, req, 0, 0)
pr := w.ConvertToPricedResource(tools.WORKFLOW_RESOURCE, req)
assert.Equal(t, "creator-id", pr.GetCreatorID())
assert.Equal(t, tools.WORKFLOW_RESOURCE, pr.GetType())
}

View File

@@ -16,7 +16,7 @@ type WorkflowResource struct {
}
func (d *WorkflowResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
return NewAccessor[*ComputeResource](tools.WORKFLOW_RESOURCE, request, func() utils.DBObject { return &WorkflowResource{} })
return NewAccessor[*WorkflowResource](tools.WORKFLOW_RESOURCE, request, func() utils.DBObject { return &WorkflowResource{} })
}
func (r *WorkflowResource) GetType() string {
@@ -34,8 +34,7 @@ func (w *WorkflowResource) SetAllowedInstances(request *tools.APIRequest) {
/* EMPTY */
}
func (w *WorkflowResource) ConvertToPricedResource(
t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF {
func (w *WorkflowResource) ConvertToPricedResource(t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF {
return &PricedResource{
Name: w.Name,
Logo: w.Logo,