diff --git a/models/common/pricing/pricing_strategy.go b/models/common/pricing/pricing_strategy.go index fb8bd43..94576bb 100755 --- a/models/common/pricing/pricing_strategy.go +++ b/models/common/pricing/pricing_strategy.go @@ -9,6 +9,7 @@ import ( type BuyingStrategy int +// should except... on const ( UNLIMITED BuyingStrategy = iota SUBSCRIPTION @@ -40,6 +41,10 @@ const ( PER_MONTH ) +func IsTimeStrategy(i int) bool { + return len(TimePricingStrategyList()) < i +} + func (t TimePricingStrategy) String() string { return [...]string{"ONCE", "PER SECOND", "PER MINUTE", "PER HOUR", "PER DAY", "PER WEEK", "PER MONTH"}[t] } @@ -101,6 +106,7 @@ func BookingEstimation(t TimePricingStrategy, price float64, locationDurationInS return 0, errors.New("pricing strategy not found") } +// may suppress in pricing strategy -> to set in map type PricingStrategy[T Strategy] struct { Price float64 `json:"price" bson:"price" default:"0"` // Price is the Price of the pricing Currency string `json:"currency" bson:"currency" default:"USD"` // Currency is the currency of the pricing diff --git a/models/order/order.go b/models/order/order.go index a6c6e8b..585ce1e 100644 --- a/models/order/order.go +++ b/models/order/order.go @@ -106,10 +106,14 @@ func (o *Order) draftStoreFromModel(scheduler *workflow_execution.WorkflowSchedu // set the name of the order resourcesByPeer := map[string][]pricing.PricedItemITF{} // create a map of resources by peer - processings := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsProcessing, request) // get the processing items - datas := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsData, request) // get the data items - storages := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsStorage, request) // get the storage items - workflows := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsWorkflow, request) // get the workflow items + processings := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsProcessing, request, + int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the processing items + datas := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsData, request, + int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the data items + storages := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsStorage, request, + int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the storage items + workflows := scheduler.Workflow.GetPricedItem(scheduler.Workflow.Graph.IsWorkflow, request, + int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) // get the workflow items for _, items := range []map[string]pricing.PricedItemITF{processings, datas, storages, workflows} { for _, item := range items { if _, ok := resourcesByPeer[item.GetCreatorID()]; !ok { @@ -167,7 +171,8 @@ func (o *Order) draftBookOrder(scheduler *workflow_execution.WorkflowSchedule, r return draftedBookings, errors.New("no request found") } for _, exec := range scheduler.WorkflowExecution { - _, priceds, _, err := scheduler.Workflow.Planify(exec.ExecDate, exec.EndDate, request) + _, priceds, _, err := scheduler.Workflow.Planify(exec.ExecDate, exec.EndDate, request, + int(scheduler.SelectedBuyingStrategy), scheduler.SelectedPricingStrategy) if err != nil { return draftedBookings, errors.New("could not planify the workflow" + fmt.Sprintf("%v", err)) } diff --git a/models/resources/compute.go b/models/resources/compute.go index b71de88..d6ff81b 100755 --- a/models/resources/compute.go +++ b/models/resources/compute.go @@ -31,11 +31,11 @@ func (r *ComputeResource) GetType() string { } func (abs *ComputeResource) ConvertToPricedResource( - t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF { + t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF { if t != tools.COMPUTE_RESOURCE { return nil } - p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request) + p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request, buyingStrategy, pricingStrategy) priced := p.(*PricedResource) return &PricedComputeResource{ PricedResource: *priced, diff --git a/models/resources/data.go b/models/resources/data.go index 130b244..e9ec3df 100755 --- a/models/resources/data.go +++ b/models/resources/data.go @@ -38,11 +38,11 @@ func (r *DataResource) GetType() string { } func (abs *DataResource) ConvertToPricedResource( - t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF { + t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF { if t != tools.DATA_RESOURCE { return nil } - p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request) + p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request, buyingStrategy, pricingStrategy) priced := p.(*PricedResource) return &PricedDataResource{ PricedResource: *priced, @@ -82,7 +82,7 @@ type DataResourcePartnership struct { type DataResourcePricingStrategy int const ( - PER_DOWNLOAD DataResourcePricingStrategy = iota + PER_DOWNLOAD DataResourcePricingStrategy = iota + 6 PER_TB_DOWNLOADED PER_GB_DOWNLOADED PER_MB_DOWNLOADED diff --git a/models/resources/interfaces.go b/models/resources/interfaces.go index d4d7975..aff8cee 100755 --- a/models/resources/interfaces.go +++ b/models/resources/interfaces.go @@ -9,7 +9,7 @@ import ( type ResourceInterface interface { utils.DBObject Trim() - ConvertToPricedResource(t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF + ConvertToPricedResource(t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF GetType() string GetSelectedInstance() utils.DBObject ClearEnv() utils.DBObject @@ -22,7 +22,7 @@ type ResourceInstanceITF interface { GetName() string StoreDraftDefault() ClearEnv() - GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF + GetPricingsProfiles(peerID string, groups []string, buyingStrategy int, pricingStrategy int) []pricing.PricingProfileITF GetPeerGroups() ([]ResourcePartnerITF, []map[string][]string) ClearPeerGroups() GetSelectedPartnership() ResourcePartnerITF @@ -30,7 +30,7 @@ type ResourceInstanceITF interface { } type ResourcePartnerITF interface { - GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF + GetPricingsProfiles(peerID string, groups []string, buyingStrategy int, pricingStrategy int) []pricing.PricingProfileITF GetPeerGroups() map[string][]string ClearPeerGroups() } diff --git a/models/resources/resource.go b/models/resources/resource.go index 780544c..c57a23d 100755 --- a/models/resources/resource.go +++ b/models/resources/resource.go @@ -52,13 +52,12 @@ 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) 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 { instances[instance.GetID()] = instance.GetName() - profiles = instance.GetPricingsProfiles(request.PeerID, request.Groups) + profiles = instance.GetPricingsProfiles(request.PeerID, request.Groups, buyingStrategy, pricingStrategy) } return &PricedResource{ Name: abs.Name, @@ -184,10 +183,10 @@ func (ri *ResourceInstance[T]) GetPartnerships(peerID string, groups []string) [ return partners } -func (ri *ResourceInstance[T]) GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF { +func (ri *ResourceInstance[T]) GetPricingsProfiles(peerID string, groups []string, buyingStrategy int, pricingStrategy int) []pricing.PricingProfileITF { pricings := []pricing.PricingProfileITF{} for _, p := range ri.Partnerships { - pricings = append(pricings, p.GetPricingsProfiles(peerID, groups)...) + pricings = append(pricings, p.GetPricingsProfiles(peerID, groups, buyingStrategy, pricingStrategy)...) } return pricings } @@ -211,26 +210,31 @@ func (ri *ResourceInstance[T]) ClearPeerGroups() { type ResourcePartnerShip[T pricing.PricingProfileITF] struct { Namespace string `json:"namespace" bson:"namespace" default:"default-namespace"` PeerGroups map[string][]string `json:"peer_groups,omitempty" bson:"peer_groups,omitempty"` - PricingProfiles []T `json:"pricing_profiles,omitempty" bson:"pricing_profiles,omitempty"` + PricingProfiles map[int]map[int]T `json:"pricing_profiles,omitempty" bson:"pricing_profiles,omitempty"` + // to upgrade pricing profiles. to be a map BuyingStrategy, map of Strategy } -func (ri *ResourcePartnerShip[T]) GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF { +/* +Le pricing doit être selectionné lors d'un scheduling... +le type de paiement défini le type de stratégie de paiement +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 { profiles := []pricing.PricingProfileITF{} - if ri.PeerGroups[peerID] != nil { - if slices.Contains(groups, "*") { - for _, ri := range ri.PricingProfiles { - profiles = append(profiles, ri) + 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]) + } } return profiles } - for _, p := range ri.PeerGroups[peerID] { - if slices.Contains(groups, p) { - for _, ri := range ri.PricingProfiles { - profiles = append(profiles, ri) - } - return profiles - } - } } return profiles } diff --git a/models/resources/storage.go b/models/resources/storage.go index 5e1476b..481f326 100755 --- a/models/resources/storage.go +++ b/models/resources/storage.go @@ -31,11 +31,11 @@ func (r *StorageResource) GetType() string { } func (abs *StorageResource) ConvertToPricedResource( - t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF { + t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF { if t != tools.STORAGE_RESOURCE { return nil } - p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request) + p := abs.AbstractInstanciatedResource.ConvertToPricedResource(t, request, buyingStrategy, pricingStrategy) priced := p.(*PricedResource) return &PricedStorageResource{ PricedResource: *priced, @@ -105,7 +105,7 @@ func (t PrivilegeStoragePricingStrategy) String() string { type StorageResourcePricingStrategy int const ( - PER_DATA_STORED StorageResourcePricingStrategy = iota + PER_DATA_STORED StorageResourcePricingStrategy = iota + 6 PER_TB_STORED PER_GB_STORED PER_MB_STORED diff --git a/models/resources/tests/compute_test.go b/models/resources/tests/compute_test.go index ff33362..83cd5e8 100644 --- a/models/resources/tests/compute_test.go +++ b/models/resources/tests/compute_test.go @@ -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) + result := cr.ConvertToPricedResource(tools.COMPUTE_RESOURCE, req, 0, 0) assert.NotNil(t, result) assert.IsType(t, &resources.PricedComputeResource{}, result) } diff --git a/models/resources/tests/data_test.go b/models/resources/tests/data_test.go index bee639c..0665519 100644 --- a/models/resources/tests/data_test.go +++ b/models/resources/tests/data_test.go @@ -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{}) + res := d.ConvertToPricedResource(tools.DATA_RESOURCE, &tools.APIRequest{}, 0, 0) assert.IsType(t, &resources.PricedDataResource{}, res) - nilRes := d.ConvertToPricedResource(tools.PROCESSING_RESOURCE, &tools.APIRequest{}) + nilRes := d.ConvertToPricedResource(tools.PROCESSING_RESOURCE, &tools.APIRequest{}, 0, 0) assert.Nil(t, nilRes) } diff --git a/models/resources/tests/resource_test.go b/models/resources/tests/resource_test.go index d056713..a3fe979 100644 --- a/models/resources/tests/resource_test.go +++ b/models/resources/tests/resource_test.go @@ -16,11 +16,13 @@ type MockInstance struct { resources.ResourceInstance[*MockPartner] } -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) []pricing.PricingProfileITF { return nil } +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 { + return nil +} func (m *MockInstance) GetPeerGroups() ([]resources.ResourcePartnerITF, []map[string][]string) { return nil, []map[string][]string{ {"peer1": {"group1"}}, @@ -35,7 +37,7 @@ func (m *MockPartner) GetPeerGroups() map[string][]string { return m.groups } func (m *MockPartner) ClearPeerGroups() {} -func (m *MockPartner) GetPricingsProfiles(string, []string) []pricing.PricingProfileITF { +func (m *MockPartner) GetPricingsProfiles(string, []string, int, int) []pricing.PricingProfileITF { return nil } diff --git a/models/resources/tests/storage_test.go b/models/resources/tests/storage_test.go index 2967e06..1a42978 100644 --- a/models/resources/tests/storage_test.go +++ b/models/resources/tests/storage_test.go @@ -28,14 +28,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{}) + priced := res.ConvertToPricedResource(tools.STORAGE_RESOURCE, &tools.APIRequest{}, 0, 0) 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{}) + priced := res.ConvertToPricedResource(tools.COMPUTE_RESOURCE, &tools.APIRequest{}, 0, 0) assert.Nil(t, priced) } diff --git a/models/resources/tests/workflow_test.go b/models/resources/tests/workflow_test.go index 5d8eeb9..5c699ec 100644 --- a/models/resources/tests/workflow_test.go +++ b/models/resources/tests/workflow_test.go @@ -32,7 +32,7 @@ func TestWorkflowResource_ConvertToPricedResource(t *testing.T) { Groups: []string{"group1"}, } - pr := w.ConvertToPricedResource(tools.WORKFLOW_RESOURCE, req) + pr := w.ConvertToPricedResource(tools.WORKFLOW_RESOURCE, req, 0, 0) assert.Equal(t, "creator-id", pr.GetCreatorID()) assert.Equal(t, tools.WORKFLOW_RESOURCE, pr.GetType()) } diff --git a/models/resources/workflow.go b/models/resources/workflow.go index a80622e..9948dd4 100755 --- a/models/resources/workflow.go +++ b/models/resources/workflow.go @@ -35,7 +35,7 @@ func (w *WorkflowResource) SetAllowedInstances(request *tools.APIRequest) { } func (w *WorkflowResource) ConvertToPricedResource( - t tools.DataType, request *tools.APIRequest) pricing.PricedItemITF { + t tools.DataType, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) pricing.PricedItemITF { return &PricedResource{ Name: w.Name, Logo: w.Logo, diff --git a/models/workflow/graph/graph.go b/models/workflow/graph/graph.go index 991d321..c34f666 100644 --- a/models/workflow/graph/graph.go +++ b/models/workflow/graph/graph.go @@ -55,7 +55,7 @@ func (wf *Graph) IsWorkflow(item GraphItem) bool { } func (g *Graph) GetAverageTimeRelatedToProcessingActivity(start time.Time, processings []*resources.ProcessingResource, resource resources.ResourceInterface, - f func(GraphItem) resources.ResourceInterface, request *tools.APIRequest) (float64, float64) { + f func(GraphItem) resources.ResourceInterface, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) (float64, float64) { nearestStart := float64(10000000000) oneIsInfinite := false longestDuration := float64(0) @@ -67,7 +67,7 @@ func (g *Graph) GetAverageTimeRelatedToProcessingActivity(start time.Time, proce } else if link.Source.ID == processing.GetID() && f(g.Items[link.Source.ID]) != nil && f(g.Items[link.Source.ID]).GetID() == resource.GetID() { // if the source is the processing and the destination is not a compute source = link.Destination.ID } - priced := processing.ConvertToPricedResource(tools.PROCESSING_RESOURCE, request) + priced := processing.ConvertToPricedResource(tools.PROCESSING_RESOURCE, request, buyingStrategy, pricingStrategy) if source != "" { if priced.GetLocationStart() != nil { near := float64(priced.GetLocationStart().Sub(start).Seconds()) @@ -96,7 +96,7 @@ func (g *Graph) GetAverageTimeRelatedToProcessingActivity(start time.Time, proce /* * GetAverageTimeBeforeStart is a function that returns the average time before the start of a processing */ -func (g *Graph) GetAverageTimeProcessingBeforeStart(average float64, processingID string, request *tools.APIRequest) float64 { +func (g *Graph) GetAverageTimeProcessingBeforeStart(average float64, processingID string, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) float64 { currents := []float64{} // list of current time for _, link := range g.Links { // for each link var source string // source is the source of the link @@ -112,13 +112,13 @@ func (g *Graph) GetAverageTimeProcessingBeforeStart(average float64, processingI if r == nil { // if item is nil, continue continue } - priced := r.ConvertToPricedResource(dt, request) + priced := r.ConvertToPricedResource(dt, request, buyingStrategy, pricingStrategy) current := priced.GetExplicitDurationInS() // get the explicit duration of the item if current < 0 { // if current is negative, its means that duration of a before could be infinite continue return current } - current += g.GetAverageTimeProcessingBeforeStart(current, source, request) // get the average time before start of the source - currents = append(currents, current) // append the current to the currents + current += g.GetAverageTimeProcessingBeforeStart(current, source, request, buyingStrategy, pricingStrategy) // get the average time before start of the source + currents = append(currents, current) // append the current to the currents } var max float64 // get the max time to wait dependancies to finish for _, current := range currents { diff --git a/models/workflow/workflow.go b/models/workflow/workflow.go index 68eab0a..5c0b134 100644 --- a/models/workflow/workflow.go +++ b/models/workflow/workflow.go @@ -77,12 +77,13 @@ func (w *Workflow) GetGraphItems(f func(item graph.GraphItem) bool) (list_datas return } -func (w *Workflow) GetPricedItem(f func(item graph.GraphItem) bool, request *tools.APIRequest) map[string]pricing.PricedItemITF { +func (w *Workflow) GetPricedItem( + f func(item graph.GraphItem) bool, request *tools.APIRequest, buyingStrategy int, pricingStrategy int) map[string]pricing.PricedItemITF { list_datas := map[string]pricing.PricedItemITF{} for _, item := range w.Graph.Items { if f(item) { dt, res := item.GetResource() - ord := res.ConvertToPricedResource(dt, request) + ord := res.ConvertToPricedResource(dt, request, buyingStrategy, pricingStrategy) list_datas[res.GetID()] = ord } } @@ -165,11 +166,12 @@ func (wfa *Workflow) CheckBooking(caller *tools.HTTPCaller) (bool, error) { return true, nil } -func (wf *Workflow) Planify(start time.Time, end *time.Time, request *tools.APIRequest) (float64, map[tools.DataType]map[string]pricing.PricedItemITF, *Workflow, 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, 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)) * time.Second), priced.GetExplicitDurationInS() + 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) { + 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)) return &s @@ -177,8 +179,8 @@ func (wf *Workflow) Planify(start time.Time, end *time.Time, request *tools.APIR if err != nil { return 0, priceds, nil, err } - if _, priceds, err = plan[resources.ResourceInterface](tools.DATA_RESOURCE, wf, priceds, request, wf.Graph.IsData, - func(res resources.ResourceInterface, priced pricing.PricedItemITF) (time.Time, float64) { + if _, priceds, err = plan[resources.ResourceInterface](tools.DATA_RESOURCE, wf, priceds, request, buyingStrategy, pricingStrategy, + wf.Graph.IsData, func(res resources.ResourceInterface, priced pricing.PricedItemITF) (time.Time, float64) { return start, 0 }, func(started time.Time, duration float64) *time.Time { return end @@ -186,14 +188,14 @@ func (wf *Workflow) Planify(start time.Time, end *time.Time, request *tools.APIR return 0, priceds, nil, err } for k, f := range map[tools.DataType]func(graph.GraphItem) bool{tools.STORAGE_RESOURCE: wf.Graph.IsStorage, tools.COMPUTE_RESOURCE: wf.Graph.IsCompute} { - if _, priceds, err = plan[resources.ResourceInterface](k, wf, priceds, request, f, - func(res resources.ResourceInterface, priced pricing.PricedItemITF) (time.Time, float64) { + if _, priceds, err = plan[resources.ResourceInterface](k, wf, priceds, request, buyingStrategy, pricingStrategy, + f, func(res resources.ResourceInterface, priced pricing.PricedItemITF) (time.Time, float64) { nearestStart, longestDuration := wf.Graph.GetAverageTimeRelatedToProcessingActivity(start, ps, res, func(i graph.GraphItem) (r resources.ResourceInterface) { if f(i) { _, r = i.GetResource() } return r - }, request) + }, request, buyingStrategy, pricingStrategy) return start.Add(time.Duration(nearestStart) * time.Second), longestDuration }, func(started time.Time, duration float64) *time.Time { s := started.Add(time.Duration(duration)) @@ -203,7 +205,8 @@ func (wf *Workflow) Planify(start time.Time, end *time.Time, request *tools.APIR } } longest := common.GetPlannerLongestTime(end, priceds, request) - if _, priceds, err = plan[resources.ResourceInterface](tools.WORKFLOW_RESOURCE, wf, priceds, request, wf.Graph.IsWorkflow, + if _, priceds, err = plan[resources.ResourceInterface](tools.WORKFLOW_RESOURCE, wf, priceds, request, + buyingStrategy, pricingStrategy, wf.Graph.IsWorkflow, func(res resources.ResourceInterface, priced pricing.PricedItemITF) (time.Time, float64) { start := start.Add(time.Duration(common.GetPlannerNearestStart(start, priceds, request)) * time.Second) longest := float64(-1) @@ -211,7 +214,7 @@ func (wf *Workflow) Planify(start time.Time, end *time.Time, request *tools.APIR if code != 200 || err != nil { return start, longest } - if neoLongest, _, _, err := r.(*Workflow).Planify(start, end, request); err != nil { + if neoLongest, _, _, err := r.(*Workflow).Planify(start, end, request, buyingStrategy, pricingStrategy); err != nil { return start, longest } else if neoLongest > longest { longest = neoLongest @@ -226,7 +229,9 @@ func (wf *Workflow) Planify(start time.Time, end *time.Time, request *tools.APIR return longest, priceds, wf, nil } -func plan[T resources.ResourceInterface](dt tools.DataType, wf *Workflow, priceds map[tools.DataType]map[string]pricing.PricedItemITF, request *tools.APIRequest, +func plan[T resources.ResourceInterface]( + dt tools.DataType, wf *Workflow, priceds map[tools.DataType]map[string]pricing.PricedItemITF, request *tools.APIRequest, + buyingStrategy int, pricingStrategy int, f func(graph.GraphItem) bool, start func(resources.ResourceInterface, pricing.PricedItemITF) (time.Time, float64), end func(time.Time, float64) *time.Time) ([]T, map[tools.DataType]map[string]pricing.PricedItemITF, error) { resources := []T{} for _, item := range wf.GetGraphItems(f) { @@ -237,7 +242,7 @@ func plan[T resources.ResourceInterface](dt tools.DataType, wf *Workflow, priced if realItem == nil { return resources, priceds, errors.New("could not load the processing resource") } - priced := realItem.ConvertToPricedResource(dt, request) + priced := realItem.ConvertToPricedResource(dt, request, buyingStrategy, pricingStrategy) started, duration := start(realItem, priced) priced.SetLocationStart(started) if duration >= 0 { diff --git a/models/workflow_execution/workflow_execution.go b/models/workflow_execution/workflow_execution.go index 014bc9c..ec4c4c4 100755 --- a/models/workflow_execution/workflow_execution.go +++ b/models/workflow_execution/workflow_execution.go @@ -109,11 +109,17 @@ func (d *WorkflowExecution) VerifyAuth(request *tools.APIRequest) bool { return true } +/* + 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. +*/ + 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]) booking = append(booking, d.bookEach(executionsID, wfID, tools.PROCESSING_RESOURCE, priceds[tools.PROCESSING_RESOURCE])...) - booking = append(booking,d.bookEach(executionsID, wfID, tools.COMPUTE_RESOURCE, priceds[tools.COMPUTE_RESOURCE])...) - booking = append(booking,d.bookEach(executionsID, wfID, tools.DATA_RESOURCE, priceds[tools.DATA_RESOURCE])...) + booking = append(booking, d.bookEach(executionsID, wfID, tools.COMPUTE_RESOURCE, priceds[tools.COMPUTE_RESOURCE])...) + booking = append(booking, d.bookEach(executionsID, wfID, tools.DATA_RESOURCE, priceds[tools.DATA_RESOURCE])...) return booking } diff --git a/models/workflow_execution/workflow_scheduler.go b/models/workflow_execution/workflow_scheduler.go index 6b71cda..6156176 100755 --- a/models/workflow_execution/workflow_scheduler.go +++ b/models/workflow_execution/workflow_scheduler.go @@ -9,6 +9,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/peer" "cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/models/workflow" @@ -32,6 +33,9 @@ type WorkflowSchedule struct { End *time.Time `json:"end,omitempty"` // End is the end time of the schedule, is required and must be greater than the Start time 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"` } func NewScheduler(start string, end string, durationInS float64, cron string) *WorkflowSchedule { @@ -62,7 +66,7 @@ func (ws *WorkflowSchedule) CheckBooking(wfID string, request *tools.APIRequest) return false, nil, []*WorkflowExecution{}, []*booking.Booking{}, errors.New("could not load the workflow with id: " + err.Error()) } wf := res.(*workflow.Workflow) - longest, priceds, wf, err := wf.Planify(ws.Start, ws.End, request) + longest, priceds, wf, err := wf.Planify(ws.Start, ws.End, request, int(ws.SelectedBuyingStrategy), ws.SelectedPricingStrategy) if err != nil { return false, wf, []*WorkflowExecution{}, []*booking.Booking{}, err }