diff --git a/doc/model.puml b/doc/model.puml index 50a4c72..1e29d0b 100644 --- a/doc/model.puml +++ b/doc/model.puml @@ -7,7 +7,7 @@ abstract Resource{ +icon: string +description: string +graphic: GraphicElement - +element: DataResource/ProcessingResource/StorageResource/Workflow/DatacenterResource + +element: DataResource/ProcessingResource/StorageResource/Workflow/ComputeResource } class DataResource { @@ -31,7 +31,7 @@ class StorageResource { +capacity: int } -class DatacenterResource { +class ComputeResource { +UUID: int +name: string @@ -96,7 +96,7 @@ class UserWorkflows { class DatacenterWorkflows { +UUID: int - +datacenter: DatacenterResource + +compute: ComputeResource +workflows: Workflow[] } @@ -159,7 +159,7 @@ DatacenterWorkflows "1" o-- "0..*" Workflow Resource<|-- DataResource Resource<|-- ProcessingResource Resource<|-- StorageResource -Resource<|-- DatacenterResource +Resource<|-- ComputeResource Resource<|-- Workflow ResourceSet "1" o-- "0..*" Ressource diff --git a/doc/order_model.puml b/doc/order_model.puml new file mode 100644 index 0000000..f79715d --- /dev/null +++ b/doc/order_model.puml @@ -0,0 +1,325 @@ +@startuml + +class AbstractObject { + ID string + Name string + IsDraft bool // is consider as a draft + UpdateDate date + LastPeerWriter string + CreatorID string + AccessMode int // public or private +} + +AbstractObject ^-- AbstractResource +AbstractObject ^-- Order +AbstractObject ^-- Booking +AbstractObject ^-- BuyingStatus +AbstractObject ^-- WorkflowExecution +AbstractObject ^-- Workflow + +class AbstractResource { + Logo string + Description string + ShortDescription string + Owners []string + UsageRestrictions string + + VerifyAuth(request) bool +} + +AbstractResource "1 " --* "many " InstanceITF +AbstractCustomizedResource "1 " --* "1 " InstanceITF + +AbstractResource ^-- ComputeResource +AbstractResource ^-- DataResource +AbstractResource ^-- ProcessingResource +AbstractResource ^-- StorageResource +AbstractResource ^-- WorkflowResource +class ComputeResource { + Architecture string + Infrastructure string +} +class DataResource { + Type string + Quality string + OpenData bool + Static bool + UpdatePeriod date + PersonalData bool + AnonymizedPersonalData bool + SizeGB float64 + Licence string + Example string +} +ProcessingResource "1 " *-- "1 " ProcessingUsage +class ProcessingUsage { + CPUs map[string]CPU + GPUs map[string]GPU + RAM RAM + StorageGB float64 + Hypothesis string + ScalingModel string +} + +class ProcessingResource { + Infrastructure string + Service bool + Usage ProcessingUsage + OpenSource bool + License string + Maturity string +} +class StorageResource { + Type string + Accronym string +} +WorkflowResource "1 " --* "many " ComputeResource +WorkflowResource "1 " --* "many " DataResource +WorkflowResource "1 " --* "many " ProcessingResource +WorkflowResource "1 " --* "many " StorageResource +class WorkflowResource { + WorkflowID string +} + +class ExploitResourceSet {} + +AbstractCustomizedResource --^ AbstractResource +AbstractCustomizedResource --* ExploitResourceSet +ExploitResourceSet ^-- CustomizedComputeResource +ExploitResourceSet ^-- CustomizedDataResource +ExploitResourceSet ^-- CustomizedProcessingResource +ExploitResourceSet ^-- CustomizedStorageResource +ExploitResourceSet ^-- CustomizedWorkflowResource +class AbstractCustomizedResource { +// A customized resource is an +// extended abstract resource not use in catalog + ExplicitBookingDurationS float64 + UsageStart date + UsageEnd date + SelectedPricing string +} +class CustomizedComputeResource { + CPUsLocated map[string]float64 + GPUsLocated map[string]float64 + RAMLocated float64 +} +class CustomizedDataResource { + StorageGB float64 +} +class CustomizedProcessingResource { + Container Container +} +class CustomizedStorageResource { + StorageGB bool +} +class CustomizedWorkflowResource {} + +interface InstanceITF { + GetID() string + VerifyPartnership() bool // eval if there is one partnership per peer groups in every instance + GetPeerGroups() []ResourcePartnerITF, []map[string][]string + ClearPeerGroups() +} + +InstanceITF -- ResourceInstance +ResourceInstance ^-- ComputeResourceInstance +ResourceInstance ^-- StorageResourceInstance +ResourceInstance "many " --* "1 " ResourcePartnerITF +class ResourceInstance { + ID string + Location Geopoint + Country CountryCode + AccessProtocol string +} +class ComputeResourceInstance { + SecurityLevel string + PowerSource string + CPUs map[string]CPU + GPUs map[string]GPU + RAM RAM +} +class StorageResourceInstance { + Local bool + SecurityLevel string + SizeType string + SizeGB int + Encryption bool + Redundancy string + Throughput string +} + +ResourcePartnerITF -- ResourcePartnership +ResourcePartnership ^-- ComputeResourcePartnership +ResourcePartnership ^-- DataResourcePartnership +ResourcePartnership ^-- StorageResourcePartnership + +interface ResourcePartnerITF { + GetPricing(id string) PricingProfileITF + GetPeerGroups() []ResourcePartnerITF, []map[string][]string + ClearPeerGroups() +} + +ResourcePartnership "many " --* "1 " PricingProfileITF +class ResourcePartnership{ + Namespace string + PeerGroups map[string][]string +} +class ComputeResourcePartnership { + MaxAllowedCPUsCores map[string]int + MaxAllowedGPUsMemoryGB map[string]float64 + RAMSizeGB float64 +} +class DataResourcePartnership { + MaxDownloadableGBAllowed float64 + PersonalDataAllowed bool + AnonymizedPersonalDataAllowed bool +} +class StorageResourcePartnership { + MaxSizeGBAllowed float64 + OnlyEncryptedAllowed bool +} + + +RefundType -- AccessPricingProfile +enum RefundType { + REFUND_DEAD_END + REFUND_ON_ERROR + REFUND_ON_EARLY_END +} +PricingProfileITF -- AccessPricingProfile +PricingProfileITF -- ExploitPricingProfile +PricingProfileITF -- WorkflowResourcePricingProfile +AccessPricingProfile ^-- DataResourcePricingProfile +AccessPricingProfile ^-- ProcessingResourcePricingProfile +ExploitPricingProfile ^-- ComputeResourcePricingProfile +ExploitPricingProfile ^-- StorageResourcePricingProfile +interface PricingProfileITF { + GetPrice(quantity float64, val float64, start date, end date, request) float64 + IsBuying() bool +} +class AccessPricingProfile { + ID string + Pricing PricingStrategy + DefaultRefundType RefundType + RefundRatio int // percentage of refund on price +} +class DataResourcePricingProfile {} +class ProcessingResourcePricingProfile {} + +ExploitPrivilegeStrategy -- ExploitPricingProfile +enum ExploitPrivilegeStrategy { + BASIC + GARANTED_ON_DELAY + GARANTED +} + +AccessPricingProfile --* PricingStrategy +AccessPricingProfile ^-- ExploitPricingProfile +class ExploitPricingProfile { + AdditionnalRefundTypes RefundTypeint + PrivilegeStrategy ExploitPrivilegeStrategy + GarantedDelaySecond int + Exceeding bool + ExceedingRatio int // percentage of Exceeding based on price +} +class ComputeResourcePricingProfile { + OverrideCPUsPrices map[string]float64 + OverrideGPUsPrices map[string]float64 + OverrideRAMPrice float64 +} +class StorageResourcePricingProfile {} +WorkflowResourcePricingProfile "1 " --* "many " ExploitResourceSet + +class WorkflowResourcePricingProfile { + ID string +} + +BuyingStrategy -- PricingStrategy +enum BuyingStrategy { + UNLIMITED + SUBSCRIPTION + PAY_PER_USE +} +Strategy -- TimePricingStrategy +Strategy "0-1 " *-- " " PricingStrategy +interface Strategy { + GetStrategy () string + GetStrategyValue() int +} +enum TimePricingStrategy { + ONCE + PER_SECOND + PER_MINUTE + PER_HOUR + PER_DAY + PER_WEEK + PER_MONTH +} + +class PricingStrategy { + Price float64 + BuyingStrategy + TimePricingStrategy TimePricingStrategy + OverrideStrategy Strategy +} + + +PeerOrder "many " *-- "1 " Order +PeerItemOrder "many " *-- "1 " PeerOrder +PricedItemITF "many " *-- "1 " PeerItemOrder + +PricedItemITF -- AbstractCustomizedResource + +class Order { + OrderBy string + WorkflowExecutionIDs []string + Status string + Total float64 +} +class PeerOrder { + PeerID string + Error string + Status string + BillingAddress string + Total float64 +} +class PeerItemOrder { + Quantity int + BuyingStatus string +} + +class BuyingStatus {} + +WorkflowExecution "many " --* "1 " Workflow +Workflow "1 " --* "many " WorkflowScheduler +WorkflowScheduler "1 " --* "many " WorkflowExecution + +class WorkflowExecution { + ExecDate date + EndDate date + State string + WorkflowID string + + ToBookings() []Booking +} +class WorkflowScheduler* { + Message string + Warning string + Start date + End date + DurationS float64 + Cron string + + Schedules(workflowID string, request) []WorkflowExecution +} + + +Workflow "1 " --* "many " ExploitResourceSet + +class Workflow {} + +interface PricedItemITF { + getPrice(request) float64, error +} + +@enduml \ No newline at end of file diff --git a/models/common/pricing/pricing_profile.go b/models/common/pricing/pricing_profile.go index 89fbb58..87accf7 100644 --- a/models/common/pricing/pricing_profile.go +++ b/models/common/pricing/pricing_profile.go @@ -3,7 +3,6 @@ package pricing import ( "time" - "cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/tools" ) @@ -22,33 +21,38 @@ const ( REFUND_ON_EARLY_END ) -type AccessPricingProfile struct { // only use for acces such as : DATA && PROCESSING - utils.DBObject - DefaultRefund RefundType `json:"default_refund" bson:"default_refund"` // DefaultRefund is the default refund type of the pricing - RefundRatio int32 `json:"refund_ratio" bson:"refund_ratio" default:"0"` // RefundRatio is the refund ratio if missing +type AccessPricingProfile[T Strategy] struct { // only use for acces such as : DATA && PROCESSING + ID string `json:"id,omitempty" bson:"id,omitempty"` // ID is the ID of the pricing + Pricing PricingStrategy[T] `json:"price,omitempty" bson:"price,omitempty"` // Price is the price of the resource + DefaultRefund RefundType `json:"default_refund" bson:"default_refund"` // DefaultRefund is the default refund type of the pricing + RefundRatio int32 `json:"refund_ratio" bson:"refund_ratio" default:"0"` // RefundRatio is the refund ratio if missing } -func (b *AccessPricingProfile) GetOverrideStrategyValue() int { +func (b *AccessPricingProfile[T]) GetID() string { + return b.ID +} + +func (b *AccessPricingProfile[T]) GetOverrideStrategyValue() int { return -1 } -type ExploitPricingStrategy int +type ExploitPrivilegeStrategy int const ( - BASIC ExploitPricingStrategy = iota + BASIC ExploitPrivilegeStrategy = iota GARANTED_ON_DELAY GARANTED ) -func (t ExploitPricingStrategy) String() string { +func (t ExploitPrivilegeStrategy) String() string { return [...]string{"BASIC", "GARANTED_ON_DELAY", "GARANTED"}[t] } -type ExploitPricingProfile struct { // only use for exploit such as : STORAGE, COMPUTE, WORKFLOW - AccessPricingProfile +type ExploitPricingProfile[T Strategy] struct { // only use for exploit such as : STORAGE, COMPUTE, WORKFLOW + AccessPricingProfile[T] AdditionnalRefundTypes []RefundType `json:"refund_types" bson:"refund_types"` // RefundTypes is the refund types of the pricing - PrivilegeStrategy ExploitPricingStrategy `json:"privilege_strategy,omitempty" bson:"privilege_strategy,omitempty"` // Strategy is the strategy of the pricing + PrivilegeStrategy ExploitPrivilegeStrategy `json:"privilege_strategy,omitempty" bson:"privilege_strategy,omitempty"` // Strategy is the strategy of the pricing GarantedDelaySecond uint Exceeding bool diff --git a/models/resources/compute.go b/models/resources/compute.go index a3a7981..8248a16 100644 --- a/models/resources/compute.go +++ b/models/resources/compute.go @@ -41,24 +41,6 @@ type ComputeResourcePartnership struct { MaxAllowedRAMSize float64 `json:"allowed_ram,omitempty" bson:"allowed_ram,omitempty"` } -func (r *ComputeResourceInstance) VerifyPartnerships() bool { - peersMultiple := map[string]int{} - for _, p := range r.Partnerships { - for k, g := range p.PeerGroups { - for _, v := range g { - if _, ok := peersMultiple[k+"_"+v]; !ok { - peersMultiple[k + "_" + v] = 0 - } - peersMultiple[k+"_"+v]++ - } - } - for k, p := range peersMultiple { - if p > 1 { - return false - } - } -} - type ComputeResourcePricingProfileOptions struct { CPUCore int `json:"cpu_core" bson:"cpu_core" default:"1"` GPUMemoryGB float64 `json:"gpu_memory_gb" bson:"gpu_memory_gb" default:"1"` @@ -66,9 +48,8 @@ type ComputeResourcePricingProfileOptions struct { } type ComputeResourcePricingProfile struct { - pricing.ExploitPricingProfile - Pricing pricing.PricingStrategy[pricing.TimePricingStrategy] `json:"price,omitempty" bson:"price,omitempty"` // Price is the price of the resource - Options ComputeResourcePricingProfileOptions `json:"options,omitempty" bson:"options,omitempty"` // Options is the options of the pricing profile + pricing.ExploitPricingProfile[pricing.TimePricingStrategy] + Options ComputeResourcePricingProfileOptions `json:"options,omitempty" bson:"options,omitempty"` // Options is the options of the pricing profile // ExploitPricingProfile is the pricing profile of a compute it means that we exploit the resource for an amount of continuous time OverrideCPUsPrices map[string]float64 `json:"cpus_prices,omitempty" bson:"cpus_prices,omitempty"` // CPUsPrices is the prices of the CPUs OverrideGPUsPrices map[string]float64 `json:"gpus_prices,omitempty" bson:"gpus_prices,omitempty"` // GPUsPrices is the prices of the GPUs diff --git a/models/resources/data.go b/models/resources/data.go index d65570f..30443d9 100644 --- a/models/resources/data.go +++ b/models/resources/data.go @@ -91,8 +91,7 @@ func (t DataResourcePricingStrategy) GetQuantity(amountOfDataGB float64) (float6 } type DataResourcePricingProfile struct { - Pricing *pricing.PricingStrategy[DataResourcePricingStrategy] `json:"cpus_prices,omitempty" bson:"cpus_prices,omitempty"` // CPUsPrices is the prices of the CPUs - pricing.AccessPricingProfile // AccessPricingProfile is the pricing profile of a data it means that we can access the data for an amount of time + pricing.AccessPricingProfile[DataResourcePricingStrategy] // AccessPricingProfile is the pricing profile of a data it means that we can access the data for an amount of time } func (p *DataResourcePricingProfile) GetOverrideStrategyValue() int { diff --git a/models/resources/processing.go b/models/resources/processing.go index 4985e3d..752882e 100644 --- a/models/resources/processing.go +++ b/models/resources/processing.go @@ -65,8 +65,7 @@ func (d *ProcessingResource) GetAccessor(request *tools.APIRequest) utils.Access } type ProcessingResourcePricingProfile struct { - Pricing *pricing.PricingStrategy[pricing.TimePricingStrategy] `json:"cpus_prices,omitempty" bson:"cpus_prices,omitempty"` // CPUsPrices is the prices of the CPUs - pricing.AccessPricingProfile // 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 } func (p *ProcessingResourcePricingProfile) IsBuying() bool { diff --git a/models/resources/resource.go b/models/resources/resource.go index f9d8f91..0e6d60b 100644 --- a/models/resources/resource.go +++ b/models/resources/resource.go @@ -85,6 +85,30 @@ func (abs *AbstractResource[T]) GetPartnership(request *tools.APIRequest) Resour return nil } +func (abs *AbstractResource[T]) VerifyPartnerships() bool { + // a peer can be part of only one partnership by instance + // may we need to define partnership in a different DB + for _, instance := range abs.Instances { + if !instance.VerifyPartnerships() { + return false + } + } + return true +} + +func (d *AbstractResource[T]) Trim() { + if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: d.CreatorID}}).IsMySelf(); !ok { + // TODO clean up the peer groups that are not in the allowed peers group + for _, instance := range d.Instances { + instance.ClearPeerGroups() + } + } +} + +func (abs *AbstractResource[T]) VerifyAuth(request *tools.APIRequest) bool { + return len(verifyAuthAction[T](abs.Instances, request)) > 0 || abs.AbstractObject.VerifyAuth(request) +} + type AbstractCustomizedResource[T InstanceITF] struct { abstractResource ExplicitBookingDurationS float64 `json:"explicit_location_duration_s,omitempty" bson:"explicit_location_duration_s,omitempty"` @@ -179,35 +203,6 @@ func verifyAuthAction[T InstanceITF](baseInstance []T, request *tools.APIRequest return instances } -/* -* VerifyPartnerships is a function that verifies the partnerships of the resource -* an instance can only have one partnership available for a peer -* it returns a boolean - */ -func (abs *AbstractResource[T]) VerifyPartnerships() bool { - // a peer can be part of only one partnership by instance - // may we need to define partnership in a different DB - for _, instance := range abs.Instances { - if !instance.VerifyPartnerships() { - return false - } - } - return true -} - -func (d *AbstractResource[T]) Trim() { - if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: d.CreatorID}}).IsMySelf(); !ok { - // TODO clean up the peer groups that are not in the allowed peers group - for _, instance := range d.Instances { - instance.ClearPeerGroups() - } - } -} - -func (abs *AbstractResource[T]) VerifyAuth(request *tools.APIRequest) bool { - return len(verifyAuthAction[T](abs.Instances, request)) > 0 || abs.AbstractObject.VerifyAuth(request) -} - type ResourceInstance[T ResourcePartnerITF] struct { UUID string `json:"id,omitempty" bson:"id,omitempty"` Location geopoint.GeoPoint `json:"location,omitempty" bson:"location,omitempty"` diff --git a/models/resources/storage.go b/models/resources/storage.go index 7ae511d..90cc422 100644 --- a/models/resources/storage.go +++ b/models/resources/storage.go @@ -96,8 +96,7 @@ func (t StorageResourcePricingStrategy) GetQuantity(amountOfDataGB float64) (flo } type StorageResourcePricingProfile struct { - Pricing *pricing.PricingStrategy[StorageResourcePricingStrategy] `json:"cpus_prices,omitempty" bson:"cpus_prices,omitempty"` // CPUsPrices is the prices of the CPUs - pricing.ExploitPricingProfile // ExploitPricingProfile is the pricing profile of a storage it means that we exploit the resource for an amount of continuous time + 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) IsBuying() bool { diff --git a/models/resources/workflow.go b/models/resources/workflow.go index 31d9fb0..e3065dd 100644 --- a/models/resources/workflow.go +++ b/models/resources/workflow.go @@ -3,7 +3,6 @@ package resources import ( "time" - "cloud.o-forge.io/core/oc-lib/models/common/pricing" "cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/tools" ) @@ -36,8 +35,16 @@ func (d *WorkflowResource) GetAccessor(request *tools.APIRequest) utils.Accessor } type WorkflowResourcePricingProfile struct { + ID string `json:"id,omitempty" bson:"id,omitempty"` ExploitedResourceSet - pricing.ExploitPricingProfile // ExploitPricingProfile is the pricing profile of a workflow it means that we exploit the resource for an amount of continuous time +} + +func (p *WorkflowResourcePricingProfile) GetOverrideStrategyValue() int { + return -1 +} + +func (p *WorkflowResourcePricingProfile) GetID() string { + return p.ID } func (p *WorkflowResourcePricingProfile) IsBuying() bool {