massive draft for payment process (UNCOMPLETE)
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/models/common"
|
||||
"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"
|
||||
)
|
||||
@@ -11,68 +16,171 @@ import (
|
||||
* it defines the resource compute
|
||||
*/
|
||||
type ComputeResource struct {
|
||||
resource_model.AbstractResource
|
||||
Technology TechnologyEnum `json:"technology" bson:"technology" default:"0"` // Technology is the technology
|
||||
Architecture string `json:"architecture,omitempty" bson:"architecture,omitempty"` // Architecture is the architecture
|
||||
Access AccessEnum `json:"access" bson:"access" default:"0"` // Access is the access
|
||||
|
||||
Localisation string `json:"localisation,omitempty" bson:"localisation,omitempty"` // Localisation is the localisation
|
||||
|
||||
CPUs []*CPU `bson:"cpus,omitempty" json:"cpus,omitempty"` // CPUs is the list of CPUs
|
||||
RAM *RAM `bson:"ram,omitempty" json:"ram,omitempty"` // RAM is the RAM
|
||||
GPUs []*GPU `bson:"gpus,omitempty" json:"gpus,omitempty"` // GPUs is the list of GPUs
|
||||
AbstractResource[*ComputeResourceInstance]
|
||||
Architecture string `json:"architecture,omitempty" bson:"architecture,omitempty"` // Architecture is the architecture
|
||||
Infrastructure common.InfrastructureType `json:"infrastructure,omitempty" bson:"infrastructure,omitempty"`
|
||||
}
|
||||
|
||||
func (d *ComputeResource) GetAccessor(username string, peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
|
||||
return New[*ComputeResource](tools.COMPUTE_RESOURCE, username, peerID, groups, caller, func() utils.DBObject { return &ComputeResource{} })
|
||||
func (d *ComputeResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return NewAccessor[*ComputeResource](tools.COMPUTE_RESOURCE, request, func() utils.DBObject { return &ComputeResource{} })
|
||||
}
|
||||
|
||||
// CPU is a struct that represents a CPU
|
||||
type CPU struct {
|
||||
Cores uint `bson:"cores,omitempty" json:"cores,omitempty"` //TODO: validate
|
||||
Architecture string `bson:"architecture,omitempty" json:"architecture,omitempty"` //TOOD: enum
|
||||
Shared bool `bson:"shared,omitempty" json:"shared,omitempty"`
|
||||
MinimumMemory uint `bson:"minimum_memory,omitempty" json:"minimum_memory,omitempty"`
|
||||
Platform string `bson:"platform,omitempty" json:"platform,omitempty"`
|
||||
type ComputeResourceInstance struct {
|
||||
ResourceInstance[*ComputeResourcePartnership]
|
||||
SecurityLevel string `json:"security_level,omitempty" bson:"security_level,omitempty"`
|
||||
PowerSource string `json:"power_source,omitempty" bson:"power_source,omitempty"`
|
||||
CPUs map[string]*common.CPU `bson:"cpus,omitempty" json:"cpus,omitempty"` // CPUs is the list of CPUs key is model
|
||||
GPUs map[string]*common.GPU `bson:"gpus,omitempty" json:"gpus,omitempty"` // GPUs is the list of GPUs key is model
|
||||
RAM *common.RAM `bson:"ram,omitempty" json:"ram,omitempty"` // RAM is the RAM
|
||||
}
|
||||
|
||||
type RAM struct {
|
||||
Size uint `bson:"size,omitempty" json:"size,omitempty" description:"Units in MB"`
|
||||
Ecc bool `bson:"ecc,omitempty" json:"ecc,omitempty"`
|
||||
type ComputeResourcePartnership struct {
|
||||
ResourcePartnerShip[*ComputeResourcePricingProfile]
|
||||
MaxAllowedCPUsCores map[string]int `json:"allowed_cpus,omitempty" bson:"allowed_cpus,omitempty"`
|
||||
MaxAllowedGPUsMemoryGB map[string]float64 `json:"allowed_gpus,omitempty" bson:"allowed_gpus,omitempty"`
|
||||
MaxAllowedRAMSize float64 `json:"allowed_ram,omitempty" bson:"allowed_ram,omitempty"`
|
||||
}
|
||||
|
||||
type GPU struct {
|
||||
CudaCores uint `bson:"cuda_cores,omitempty" json:"cuda_cores,omitempty"`
|
||||
Model string `bson:"model,omitempty" json:"model,omitempty"`
|
||||
Memory uint `bson:"memory,omitempty" json:"memory,omitempty" description:"Units in MB"`
|
||||
TensorCores uint `bson:"tensor_cores,omitempty" json:"tensor_cores,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 TechnologyEnum int
|
||||
|
||||
const (
|
||||
DOCKER TechnologyEnum = iota
|
||||
KUBERNETES
|
||||
SLURM
|
||||
HW
|
||||
CONDOR
|
||||
)
|
||||
|
||||
func (t TechnologyEnum) String() string {
|
||||
return [...]string{"DOCKER", "KUBERNETES", "SLURM", "HW", "CONDOR"}[t]
|
||||
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"`
|
||||
RAMSizeGB float64 `json:"ram_size_gb" bson:"ram_size_gb" default:"1"`
|
||||
}
|
||||
|
||||
type AccessEnum int
|
||||
|
||||
const (
|
||||
SSH AccessEnum = iota
|
||||
SSH_KUBE_API
|
||||
SSH_SLURM
|
||||
SSH_DOCKER
|
||||
OPENCLOUD
|
||||
VPN
|
||||
)
|
||||
|
||||
func (a AccessEnum) String() string {
|
||||
return [...]string{"SSH", "SSH_KUBE_API", "SSH_SLURM", "SSH_DOCKER", "OPENCLOUD", "VPN"}[a]
|
||||
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
|
||||
// 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
|
||||
OverrideRAMPrice float64 `json:"ram_price" bson:"ram_price" default:"-1"` // RAMPrice is the price of the RAM
|
||||
}
|
||||
|
||||
// PROBLEM
|
||||
|
||||
func (p *ComputeResourcePricingProfile) IsBuying() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
}
|
||||
|
||||
func (p *ComputeResourcePricingProfile) GetOverrideStrategyValue() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// NOT A PROPER QUANTITY
|
||||
// amountOfData is the number of CPUs, GPUs or RAM dependings on the params
|
||||
func (p *ComputeResourcePricingProfile) GetPrice(amountOfData float64, explicitDuration float64, start time.Time, end time.Time, request *tools.APIRequest, params ...string) (float64, error) {
|
||||
if len(params) < 1 {
|
||||
return 0, errors.New("params must be set")
|
||||
}
|
||||
pp := float64(0)
|
||||
model := params[1]
|
||||
if strings.Contains(params[0], "cpus") && len(params) > 1 {
|
||||
if _, ok := p.OverrideCPUsPrices[model]; ok {
|
||||
p.Pricing.Price = p.OverrideCPUsPrices[model]
|
||||
}
|
||||
r, err := p.Pricing.GetPrice(amountOfData/float64(p.Options.CPUCore), explicitDuration, start, &end)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
pp += r
|
||||
|
||||
}
|
||||
if strings.Contains(params[0], "gpus") && len(params) > 1 {
|
||||
if _, ok := p.OverrideGPUsPrices[model]; ok {
|
||||
p.Pricing.Price = p.OverrideGPUsPrices[model]
|
||||
}
|
||||
r, err := p.Pricing.GetPrice(amountOfData/float64(p.Options.GPUMemoryGB), explicitDuration, start, &end)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
pp += r
|
||||
}
|
||||
if strings.Contains(params[0], "ram") {
|
||||
if p.OverrideRAMPrice >= 0 {
|
||||
p.Pricing.Price = p.OverrideRAMPrice
|
||||
}
|
||||
r, err := p.Pricing.GetPrice(float64(amountOfData)/p.Options.RAMSizeGB, explicitDuration, start, &end)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
pp += r
|
||||
}
|
||||
return pp, nil
|
||||
}
|
||||
|
||||
type CustomizedComputeResource struct {
|
||||
AbstractCustomizedResource[*ComputeResourceInstance]
|
||||
|
||||
CPUsLocated map[string]float64 `json:"cpus_in_use" bson:"cpus_in_use"` // CPUsInUse is the list of CPUs in use
|
||||
GPUsLocated map[string]float64 `json:"gpus_in_use" bson:"gpus_in_use"` // GPUsInUse is the list of GPUs in use
|
||||
RAMLocated float64 `json:"ram_in_use" bson:"ram_in_use"` // RAMInUse is the RAM in use
|
||||
}
|
||||
|
||||
func (r *CustomizedComputeResource) GetType() tools.DataType {
|
||||
return tools.COMPUTE_RESOURCE
|
||||
}
|
||||
|
||||
func (r *CustomizedComputeResource) GetPrice(request *tools.APIRequest) (float64, error) {
|
||||
if r.UsageStart == nil || r.UsageEnd == nil {
|
||||
return 0, errors.New("Usage start and end must be set")
|
||||
}
|
||||
partner := r.GetPartnership(request)
|
||||
if partner != nil && partner.GetPricing(r.SelectedPricing) != nil {
|
||||
return 0, errors.New("Pricing strategy not found")
|
||||
}
|
||||
pricing := partner.GetPricing(r.SelectedPricing)
|
||||
price := float64(0)
|
||||
for _, l := range []map[string]float64{r.CPUsLocated, r.GPUsLocated} {
|
||||
for model, amountOfData := range l {
|
||||
cpus, err := pricing.GetPrice(float64(amountOfData), r.ExplicitBookingDurationS, *r.UsageStart, *r.UsageEnd, request, "cpus", model)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += cpus
|
||||
}
|
||||
}
|
||||
ram, err := pricing.GetPrice(r.RAMLocated, r.ExplicitBookingDurationS, *r.UsageStart, *r.UsageEnd, request, "ram")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += ram
|
||||
return price, nil
|
||||
}
|
||||
|
||||
/*
|
||||
* FillWithDefaultProcessingUsage fills the order item with the default processing usage
|
||||
* it depends on the processing usage only if nothing is set, during order
|
||||
*/
|
||||
func (i *CustomizedComputeResource) FillWithDefaultProcessingUsage(usage *ProcessingUsage) {
|
||||
for _, cpu := range usage.CPUs {
|
||||
if _, ok := i.CPUsLocated[cpu.Model]; !ok {
|
||||
i.CPUsLocated[cpu.Model] = 0
|
||||
}
|
||||
if i.CPUsLocated[cpu.Model] < float64(cpu.Cores) {
|
||||
i.CPUsLocated[cpu.Model] = float64(cpu.Cores)
|
||||
}
|
||||
}
|
||||
for _, cpu := range usage.GPUs {
|
||||
i.GPUsLocated[cpu.Model] = 1
|
||||
}
|
||||
i.RAMLocated = usage.RAM.SizeGb
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
|
||||
"errors"
|
||||
"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"
|
||||
)
|
||||
@@ -15,12 +18,15 @@ const (
|
||||
LICENCED
|
||||
)
|
||||
|
||||
/*
|
||||
* Struct of Usage Conditions
|
||||
*/
|
||||
type UsageConditions struct {
|
||||
Usage string `json:"usage,omitempty" bson:"usage,omitempty" description:"usage of the data"` // Usage is the usage of the data
|
||||
Actors []string `json:"actors,omitempty" bson:"actors,omitempty" description:"actors of the data"` // Actors is the actors of the data
|
||||
type abstractDataResource struct {
|
||||
Type string `bson:"type,omitempty" json:"type,omitempty"`
|
||||
Quality string `bson:"quality,omitempty" json:"quality,omitempty"`
|
||||
OpenData bool `bson:"open_data" json:"open_data" default:"false"` // Type is the type of the storage
|
||||
Static bool `bson:"static" json:"static" default:"false"`
|
||||
UpdatePeriod time.Time `bson:"update_period,omitempty" json:"update_period,omitempty"`
|
||||
PersonalData bool `bson:"personal_data,omitempty" json:"personal_data,omitempty"`
|
||||
AnonymizedPersonalData bool `bson:"anonymized_personal_data,omitempty" json:"anonymized_personal_data,omitempty"`
|
||||
SizeGB float64 `json:"size_gb,omitempty" bson:"size_gb,omitempty"` // SizeGB is the size of the data
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -28,15 +34,105 @@ type UsageConditions struct {
|
||||
* it defines the resource data
|
||||
*/
|
||||
type DataResource struct {
|
||||
resource_model.AbstractResource // AbstractResource contains the basic fields of an object (id, name)
|
||||
resource_model.WebResource
|
||||
Type string `bson:"type,omitempty" json:"type,omitempty"` // Type is the type of the storage
|
||||
UsageConditions UsageConditions `json:"usage_conditions,omitempty" bson:"usage_conditions,omitempty" description:"usage conditions of the data"` // UsageConditions is the usage conditions of the data
|
||||
License DataLicense `json:"license" bson:"license" description:"license of the data" default:"0"` // License is the license of the data
|
||||
Interest DataLicense `json:"interest" bson:"interest" description:"interest of the data" default:"0"` // Interest is the interest of the data
|
||||
Example string `json:"example,omitempty" bson:"example,omitempty" description:"base64 encoded data"` // Example is an example of the data
|
||||
AbstractResource[*ResourceInstance[*DataResourcePartnership]]
|
||||
abstractDataResource // AbstractResource contains the basic fields of an object (id, name)
|
||||
License DataLicense `json:"license" bson:"license" description:"license of the data" default:"0"` // License is the license of the data
|
||||
// ? Interest DataLicense `json:"interest" bson:"interest" description:"interest of the data" default:"0"` // Interest is the interest of the data
|
||||
Example string `json:"example,omitempty" bson:"example,omitempty" description:"base64 encoded data"` // Example is an example of the data
|
||||
}
|
||||
|
||||
func (d *DataResource) GetAccessor(username string, peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
|
||||
return New[*DataResource](tools.DATA_RESOURCE, username, peerID, groups, caller, func() utils.DBObject { return &DataResource{} }) // Create a new instance of the accessor
|
||||
func (d *DataResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return NewAccessor[*DataResource](tools.DATA_RESOURCE, request, func() utils.DBObject { return &DataResource{} }) // Create a new instance of the accessor
|
||||
}
|
||||
|
||||
type DataResourcePartnership struct {
|
||||
ResourcePartnerShip[*DataResourcePricingProfile]
|
||||
MaxDownloadableGbAllowed float64 `json:"allowed_gb,omitempty" bson:"allowed_gb,omitempty"`
|
||||
PersonalDataAllowed bool `json:"personal_data_allowed,omitempty" bson:"personal_data_allowed,omitempty"`
|
||||
AnonymizedPersonalDataAllowed bool `json:"anonymized_personal_data_allowed,omitempty" bson:"anonymized_personal_data_allowed,omitempty"`
|
||||
}
|
||||
|
||||
type DataResourcePricingStrategy int
|
||||
|
||||
const (
|
||||
PER_DOWNLOAD DataResourcePricingStrategy = iota
|
||||
PER_TB_DOWNLOADED
|
||||
PER_GB_DOWNLOADED
|
||||
PER_MB_DOWNLOADED
|
||||
PER_KB_DOWNLOADED
|
||||
)
|
||||
|
||||
func ToDataResourcePricingStrategy(i int) DataResourcePricingStrategy {
|
||||
return DataResourcePricingStrategy(i)
|
||||
}
|
||||
|
||||
func (t DataResourcePricingStrategy) GetStrategy() string {
|
||||
return [...]string{"PER_DOWNLOAD", "PER_GB", "PER_MB", "PER_KB"}[t]
|
||||
}
|
||||
|
||||
func (t DataResourcePricingStrategy) GetStrategyValue() int {
|
||||
return int(t)
|
||||
}
|
||||
|
||||
func (t DataResourcePricingStrategy) GetQuantity(amountOfDataGB float64) (float64, error) {
|
||||
switch t {
|
||||
case PER_DOWNLOAD:
|
||||
return 1, nil
|
||||
case PER_TB_DOWNLOADED:
|
||||
return amountOfDataGB * 1000, nil
|
||||
case PER_GB_DOWNLOADED:
|
||||
return amountOfDataGB, nil
|
||||
case PER_MB_DOWNLOADED:
|
||||
return amountOfDataGB / 1000, nil
|
||||
case PER_KB_DOWNLOADED:
|
||||
return amountOfDataGB / 1000000, nil
|
||||
}
|
||||
return 0, errors.New("Pricing strategy not found")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (p *DataResourcePricingProfile) GetOverrideStrategyValue() int {
|
||||
return p.Pricing.OverrideStrategy.GetStrategyValue()
|
||||
}
|
||||
|
||||
func (p *DataResourcePricingProfile) GetPrice(amountOfData float64, explicitDuration float64, start time.Time, end time.Time, request *tools.APIRequest, params ...string) (float64, error) {
|
||||
return p.Pricing.GetPrice(amountOfData, explicitDuration, start, &end)
|
||||
}
|
||||
|
||||
func (p *DataResourcePricingProfile) IsBuying() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
}
|
||||
|
||||
type CustomizedDataResource struct {
|
||||
AbstractCustomizedResource[*ResourceInstance[*DataResourcePartnership]]
|
||||
abstractDataResource
|
||||
StorageGB float64 `json:"storage_gb,omitempty" bson:"storage_gb,omitempty"`
|
||||
}
|
||||
|
||||
func (r *CustomizedDataResource) GetType() tools.DataType {
|
||||
return tools.DATA_RESOURCE
|
||||
}
|
||||
|
||||
func (r *CustomizedDataResource) GetPrice(request *tools.APIRequest) (float64, error) {
|
||||
if r.UsageStart == nil || r.UsageEnd == nil {
|
||||
return 0, errors.New("Usage start and end must be set")
|
||||
}
|
||||
partner := r.GetPartnership(request)
|
||||
if partner != nil && partner.GetPricing(r.SelectedPricing) != nil {
|
||||
return 0, errors.New("Pricing strategy not found")
|
||||
}
|
||||
pricing := partner.GetPricing(r.SelectedPricing)
|
||||
var err error
|
||||
amountOfData := float64(1)
|
||||
if pricing.GetOverrideStrategyValue() >= 0 {
|
||||
amountOfData, err = ToDataResourcePricingStrategy(pricing.GetOverrideStrategyValue()).GetQuantity(r.StorageGB)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return pricing.GetPrice(amountOfData, r.ExplicitBookingDurationS, *r.UsageStart, *r.UsageEnd, request)
|
||||
}
|
||||
|
||||
47
models/resources/interfaces.go
Normal file
47
models/resources/interfaces.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/models/common/pricing"
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
type ShallowResourceInterface interface {
|
||||
utils.DBObject
|
||||
GetType() tools.DataType
|
||||
GetCreatorID() string
|
||||
GetPricingID() string
|
||||
GetLocationStart() *time.Time
|
||||
GetLocationEnd() *time.Time
|
||||
GetExplicitDurationInS() float64
|
||||
SetStartUsage(start time.Time)
|
||||
SetEndUsage(end time.Time)
|
||||
GetPartnership(request *tools.APIRequest) ResourcePartnerITF
|
||||
SetResourceModel(model *resource_model.ResourceModel)
|
||||
}
|
||||
|
||||
type ResourceInterface interface {
|
||||
utils.DBObject
|
||||
Trim()
|
||||
GetCreatorID() string
|
||||
VerifyPartnerships() bool
|
||||
GetPartnership(request *tools.APIRequest) ResourcePartnerITF
|
||||
SetAllowedInstances(request *tools.APIRequest)
|
||||
SetResourceModel(model *resource_model.ResourceModel)
|
||||
}
|
||||
|
||||
type InstanceITF interface {
|
||||
GetID() string
|
||||
VerifyPartnerships() bool
|
||||
GetPeerGroups() ([]ResourcePartnerITF, []map[string][]string)
|
||||
ClearPeerGroups()
|
||||
}
|
||||
|
||||
type ResourcePartnerITF interface {
|
||||
GetPricing(id string) pricing.PricingProfileITF
|
||||
GetPeerGroups() map[string][]string
|
||||
ClearPeerGroups()
|
||||
}
|
||||
92
models/resources/models.go
Normal file
92
models/resources/models.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
)
|
||||
|
||||
type ExploitedResourceSet struct {
|
||||
DataResources []*CustomizedDataResource `bson:"-" json:"data_resources,omitempty"`
|
||||
StorageResources []*CustomizedStorageResource `bson:"-" json:"storage_resources,omitempty"`
|
||||
ProcessingResources []*CustomizedProcessingResource `bson:"-" json:"processing_resources,omitempty"`
|
||||
ComputeResources []*CustomizedComputeResource `bson:"-" json:"compute_resources,omitempty"`
|
||||
WorkflowResources []*CustomizedWorkflowResource `bson:"-" json:"workflow_resources,omitempty"`
|
||||
}
|
||||
|
||||
type ResourceSet struct {
|
||||
Datas []string `bson:"datas,omitempty" json:"datas,omitempty"`
|
||||
Storages []string `bson:"storages,omitempty" json:"storages,omitempty"`
|
||||
Processings []string `bson:"processings,omitempty" json:"processings,omitempty"`
|
||||
Computes []string `bson:"computes,omitempty" json:"computes,omitempty"`
|
||||
Workflows []string `bson:"workflows,omitempty" json:"workflows,omitempty"`
|
||||
|
||||
DataResources []*DataResource `bson:"-" json:"data_resources,omitempty"`
|
||||
StorageResources []*StorageResource `bson:"-" json:"storage_resources,omitempty"`
|
||||
ProcessingResources []*ProcessingResource `bson:"-" json:"processing_resources,omitempty"`
|
||||
ComputeResources []*ComputeResource `bson:"-" json:"compute_resources,omitempty"`
|
||||
WorkflowResources []*WorkflowResource `bson:"-" json:"workflow_resources,omitempty"`
|
||||
}
|
||||
|
||||
func (r *ResourceSet) Clear() {
|
||||
r.DataResources = nil
|
||||
r.StorageResources = nil
|
||||
r.ProcessingResources = nil
|
||||
r.ComputeResources = nil
|
||||
r.WorkflowResources = nil
|
||||
}
|
||||
|
||||
func (r *ResourceSet) Fill(request *tools.APIRequest) {
|
||||
for k, v := range map[utils.DBObject][]string{
|
||||
(&DataResource{}): r.Datas,
|
||||
(&ComputeResource{}): r.Computes,
|
||||
(&StorageResource{}): r.Storages,
|
||||
(&ProcessingResource{}): r.Processings,
|
||||
(&WorkflowResource{}): r.Workflows,
|
||||
} {
|
||||
for _, id := range v {
|
||||
d, _, e := k.GetAccessor(request).LoadOne(id)
|
||||
if e == nil {
|
||||
switch k.(type) {
|
||||
case *DataResource:
|
||||
r.DataResources = append(r.DataResources, d.(*DataResource))
|
||||
case *ComputeResource:
|
||||
r.ComputeResources = append(r.ComputeResources, d.(*ComputeResource))
|
||||
case *StorageResource:
|
||||
r.StorageResources = append(r.StorageResources, d.(*StorageResource))
|
||||
case *ProcessingResource:
|
||||
r.ProcessingResources = append(r.ProcessingResources, d.(*ProcessingResource))
|
||||
case *WorkflowResource:
|
||||
r.WorkflowResources = append(r.WorkflowResources, d.(*WorkflowResource))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ItemExploitedResource struct {
|
||||
Data *CustomizedDataResource `bson:"data,omitempty" json:"data,omitempty"`
|
||||
Processing *CustomizedProcessingResource `bson:"processing,omitempty" json:"processing,omitempty"`
|
||||
Storage *CustomizedStorageResource `bson:"storage,omitempty" json:"storage,omitempty"`
|
||||
Compute *CustomizedComputeResource `bson:"compute,omitempty" json:"compute,omitempty"`
|
||||
Workflow *CustomizedWorkflowResource `bson:"workflow,omitempty" json:"workflow,omitempty"`
|
||||
}
|
||||
|
||||
func (w *ItemExploitedResource) SetItemEndUsage(end time.Time) {
|
||||
for _, item := range []ShallowResourceInterface{w.Data, w.Processing, w.Storage, w.Compute, w.Workflow} {
|
||||
if item != nil {
|
||||
item.SetItemEndUsage(end)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (w *ItemExploitedResource) SetItemStartUsage(start time.Time) {
|
||||
for _, item := range []ShallowResourceInterface{w.Data, w.Processing, w.Storage, w.Compute, w.Workflow} {
|
||||
if item != nil {
|
||||
item.SetItemStartUsage(start)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,28 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/models/common"
|
||||
"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"
|
||||
)
|
||||
|
||||
type Container struct {
|
||||
Image string `json:"image,omitempty" bson:"image,omitempty"` // Image is the container image
|
||||
Command string `json:"command,omitempty" bson:"command,omitempty"` // Command is the container command
|
||||
Args string `json:"args,omitempty" bson:"args,omitempty"` // Args is the container arguments
|
||||
Env map[string]string `json:"env,omitempty" bson:"env,omitempty"` // Env is the container environment variables
|
||||
Volumes map[string]string `json:"volumes,omitempty" bson:"volumes,omitempty"` // Volumes is the container volumes
|
||||
type ProcessingUsage struct {
|
||||
CPUs map[string]*common.CPU `bson:"cpus,omitempty" json:"cpus,omitempty"` // CPUs is the list of CPUs key is model
|
||||
GPUs map[string]*common.GPU `bson:"gpus,omitempty" json:"gpus,omitempty"` // GPUs is the list of GPUs key is model
|
||||
RAM *common.RAM `bson:"ram,omitempty" json:"ram,omitempty"` // RAM is the RAM
|
||||
|
||||
StorageGb float64 `bson:"storage,omitempty" json:"storage,omitempty"` // Storage is the storage
|
||||
Hypothesis string `bson:"hypothesis,omitempty" json:"hypothesis,omitempty"`
|
||||
ScalingModel string `bson:"scaling_model,omitempty" json:"scaling_model,omitempty"` // ScalingModel is the scaling model
|
||||
}
|
||||
|
||||
type Expose struct {
|
||||
Port int `json:"port,omitempty" bson:"port,omitempty"` // Port is the port
|
||||
Reverse string `json:"reverse,omitempty" bson:"reverse,omitempty"` // Reverse is the reverse
|
||||
PAT int `json:"pat,omitempty" bson:"pat,omitempty"` // PAT is the PAT
|
||||
type abstractProcessingResource struct {
|
||||
Infrastructure common.InfrastructureType `json:"infrastructure,omitempty" bson:"infrastructure,omitempty"`
|
||||
Service bool `json:"is_service,omitempty" bson:"is_service,omitempty"` // IsService is a flag that indicates if the processing is a service
|
||||
Usage *ProcessingUsage `bson:"usage,omitempty" json:"usage,omitempty"` // Usage is the usage of the processing
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -25,19 +30,49 @@ type Expose struct {
|
||||
* it defines the resource processing
|
||||
*/
|
||||
type ProcessingResource struct {
|
||||
resource_model.AbstractResource
|
||||
IsService bool `json:"is_service,omitempty" bson:"is_service,omitempty"` // IsService is a flag that indicates if the processing is a service
|
||||
CPUs []*CPU `bson:"cpus,omitempty" json:"cp_us,omitempty"` // CPUs is the list of CPUs
|
||||
GPUs []*GPU `bson:"gpus,omitempty" json:"gp_us,omitempty"` // GPUs is the list of GPUs
|
||||
RAM *RAM `bson:"ram,omitempty" json:"ram,omitempty"` // RAM is the RAM
|
||||
Storage uint `bson:"storage,omitempty" json:"storage,omitempty"` // Storage is the storage
|
||||
Parallel bool `bson:"parallel,omitempty" json:"parallel,omitempty"` // Parallel is a flag that indicates if the processing is parallel
|
||||
ScalingModel uint `bson:"scaling_model,omitempty" json:"scaling_model,omitempty"` // ScalingModel is the scaling model
|
||||
DiskIO string `bson:"disk_io,omitempty" json:"disk_io,omitempty"` // DiskIO is the disk IO
|
||||
Container *Container `bson:"container,omitempty" json:"container,omitempty"` // Container is the container
|
||||
Expose []Expose `bson:"expose,omitempty" json:"expose,omitempty"` // Expose is the execution
|
||||
AbstractResource[*ResourceInstance[*ResourcePartnerShip[*ProcessingResourcePricingProfile]]]
|
||||
abstractProcessingResource
|
||||
OpenSource bool `json:"open_source" bson:"open_source" default:"false"`
|
||||
License string `json:"license,omitempty" bson:"license,omitempty"`
|
||||
Maturity string `json:"maturity,omitempty" bson:"maturity,omitempty"`
|
||||
}
|
||||
|
||||
func (d *ProcessingResource) GetAccessor(username string, peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
|
||||
return New[*ProcessingResource](tools.PROCESSING_RESOURCE, username, peerID, groups, caller, func() utils.DBObject { return &ProcessingResource{} }) // Create a new instance of the accessor
|
||||
type CustomizedProcessingResource struct {
|
||||
AbstractCustomizedResource[*ResourceInstance[*ResourcePartnerShip[*ProcessingResourcePricingProfile]]]
|
||||
abstractProcessingResource
|
||||
Container common.Container `json:"container,omitempty" bson:"container,omitempty"` // Container is the container
|
||||
}
|
||||
|
||||
func (r *CustomizedProcessingResource) GetType() tools.DataType {
|
||||
return tools.PROCESSING_RESOURCE
|
||||
}
|
||||
|
||||
func (a *CustomizedProcessingResource) GetExplicitDurationInS() float64 {
|
||||
if a.ExplicitBookingDurationS == 0 {
|
||||
if a.UsageEnd == nil || a.UsageStart == nil {
|
||||
if a.Service {
|
||||
return -1
|
||||
}
|
||||
return time.Duration(1 * time.Hour).Seconds()
|
||||
}
|
||||
return a.UsageEnd.Sub(*a.UsageStart).Seconds()
|
||||
}
|
||||
return a.ExplicitBookingDurationS
|
||||
}
|
||||
|
||||
func (d *ProcessingResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return NewAccessor[*ProcessingResource](tools.PROCESSING_RESOURCE, request, func() utils.DBObject { return &ProcessingResource{} }) // Create a new instance of the accessor
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (p *ProcessingResourcePricingProfile) IsBuying() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
}
|
||||
|
||||
func (p *ProcessingResourcePricingProfile) GetPrice(amountOfData float64, val float64, start time.Time, end time.Time, request *tools.APIRequest, params ...string) (float64, error) {
|
||||
return p.Pricing.GetPrice(amountOfData, val, start, &end)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/config"
|
||||
"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/resource_model"
|
||||
"cloud.o-forge.io/core/oc-lib/models/utils"
|
||||
"cloud.o-forge.io/core/oc-lib/tools"
|
||||
"github.com/biter777/countries"
|
||||
"github.com/marcinwyszynski/geopoint"
|
||||
)
|
||||
|
||||
// AbstractResource is the struct containing all of the attributes commons to all ressources
|
||||
@@ -10,86 +20,265 @@ import (
|
||||
// Resource is the interface to be implemented by all classes inheriting from Resource to have the same behavior
|
||||
|
||||
// http://www.inanzzz.com/index.php/post/wqbs/a-basic-usage-of-int-and-string-enum-types-in-golang
|
||||
type ResourceInterface interface {
|
||||
utils.DBObject
|
||||
Trim() *resource_model.AbstractResource
|
||||
SetResourceModel(model *resource_model.ResourceModel)
|
||||
/*
|
||||
* AbstractResource is a struct that represents a resource
|
||||
* it defines the resource data
|
||||
*/
|
||||
type abstractResource struct {
|
||||
utils.AbstractObject // AbstractObject contains the basic fields of an object (id, name)
|
||||
Logo string `json:"logo,omitempty" bson:"logo,omitempty" validate:"required"` // Logo is the logo of the resource
|
||||
Description string `json:"description,omitempty" bson:"description,omitempty"` // Description is the description of the resource
|
||||
ShortDescription string `json:"short_description,omitempty" bson:"short_description,omitempty" validate:"required"` // ShortDescription is the short description of the resource
|
||||
Owners []utils.Owner `json:"owners,omitempty" bson:"owners,omitempty"` // Owners is the list of owners of the resource
|
||||
ResourceModel *resource_model.ResourceModel `json:"resource_model,omitempty" bson:"resource_model,omitempty"` // ResourceModel is the model of the resource
|
||||
UsageRestrictions string `bson:"usage_restrictions,omitempty" json:"usage_restrictions,omitempty"`
|
||||
}
|
||||
|
||||
type ResourceSet struct {
|
||||
Datas []string `bson:"datas,omitempty" json:"datas,omitempty"`
|
||||
Storages []string `bson:"storages,omitempty" json:"storages,omitempty"`
|
||||
Processings []string `bson:"processings,omitempty" json:"processings,omitempty"`
|
||||
Computes []string `bson:"computes,omitempty" json:"computes,omitempty"`
|
||||
Workflows []string `bson:"workflows,omitempty" json:"workflows,omitempty"`
|
||||
|
||||
DataResources []*DataResource `bson:"-" json:"data_resources,omitempty"`
|
||||
StorageResources []*StorageResource `bson:"-" json:"storage_resources,omitempty"`
|
||||
ProcessingResources []*ProcessingResource `bson:"-" json:"processing_resources,omitempty"`
|
||||
ComputeResources []*ComputeResource `bson:"-" json:"compute_resources,omitempty"`
|
||||
WorkflowResources []*WorkflowResource `bson:"-" json:"workflow_resources,omitempty"`
|
||||
func (r *abstractResource) StoreDraftDefault() {
|
||||
r.IsDraft = true
|
||||
}
|
||||
|
||||
func (r *ResourceSet) Clear() {
|
||||
r.DataResources = nil
|
||||
r.StorageResources = nil
|
||||
r.ProcessingResources = nil
|
||||
r.ComputeResources = nil
|
||||
r.WorkflowResources = nil
|
||||
func (r *AbstractCustomizedResource[T]) CanUpdate(set utils.DBObject) (bool, utils.DBObject) {
|
||||
if r.IsDraft != set.IsDrafted() && set.IsDrafted() {
|
||||
return true, set // only state can be updated
|
||||
}
|
||||
return r.IsDraft != set.IsDrafted() && set.IsDrafted(), set
|
||||
}
|
||||
|
||||
func (r *ResourceSet) Fill(username string, peerID string, groups []string) {
|
||||
for k, v := range map[utils.DBObject][]string{
|
||||
(&DataResource{}): r.Datas,
|
||||
(&ComputeResource{}): r.Computes,
|
||||
(&StorageResource{}): r.Storages,
|
||||
(&ProcessingResource{}): r.Processings,
|
||||
(&WorkflowResource{}): r.Workflows,
|
||||
} {
|
||||
for _, id := range v {
|
||||
d, _, e := k.GetAccessor(username, peerID, groups, nil).LoadOne(id)
|
||||
if e == nil {
|
||||
switch k.(type) {
|
||||
case *DataResource:
|
||||
r.DataResources = append(r.DataResources, d.(*DataResource))
|
||||
case *ComputeResource:
|
||||
r.ComputeResources = append(r.ComputeResources, d.(*ComputeResource))
|
||||
case *StorageResource:
|
||||
r.StorageResources = append(r.StorageResources, d.(*StorageResource))
|
||||
case *ProcessingResource:
|
||||
r.ProcessingResources = append(r.ProcessingResources, d.(*ProcessingResource))
|
||||
case *WorkflowResource:
|
||||
r.WorkflowResources = append(r.WorkflowResources, d.(*WorkflowResource))
|
||||
func (r *abstractResource) CanDelete() bool {
|
||||
return r.IsDraft // only draft bookings can be deleted
|
||||
}
|
||||
|
||||
func (ao *abstractResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ao *abstractResource) GetCreatorID() string {
|
||||
return ao.CreatorID
|
||||
}
|
||||
|
||||
func (abs *abstractResource) SetResourceModel(model *resource_model.ResourceModel) {
|
||||
abs.ResourceModel = model
|
||||
}
|
||||
|
||||
type AbstractResource[T InstanceITF] struct {
|
||||
abstractResource
|
||||
Instances []T `json:"instances,omitempty" bson:"instances,omitempty"` // Bill is the bill of the resource // Bill is the bill of the resource
|
||||
}
|
||||
|
||||
func (abs *AbstractResource[T]) SetAllowedInstances(request *tools.APIRequest) {
|
||||
abs.Instances = verifyAuthAction[T](abs.Instances, request)
|
||||
}
|
||||
|
||||
func (abs *AbstractResource[T]) GetPartnership(request *tools.APIRequest) ResourcePartnerITF {
|
||||
for _, instance := range abs.Instances {
|
||||
partners, grps := instance.GetPeerGroups()
|
||||
for i, p := range grps {
|
||||
if request == nil {
|
||||
continue
|
||||
}
|
||||
if _, ok := p[request.PeerID]; ok {
|
||||
return partners[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AbstractCustomizedResource[T InstanceITF] struct {
|
||||
abstractResource
|
||||
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"`
|
||||
SelectedInstance T `json:"selected_instance,omitempty" bson:"selected_instance,omitempty"`
|
||||
SelectedPricing string `json:"selected_pricing,omitempty" bson:"selected_pricing,omitempty"`
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) SetStartUsage(start time.Time) {
|
||||
if abs.UsageStart == nil {
|
||||
abs.UsageStart = &start
|
||||
}
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) SetEndUsage(end time.Time) {
|
||||
if abs.UsageEnd == nil {
|
||||
abs.UsageEnd = &end
|
||||
}
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) IsBuying(request *tools.APIRequest) bool {
|
||||
return abs.GetPartnership(request).GetPricing(abs.SelectedPricing).IsBuying()
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) GetLocationEnd() *time.Time {
|
||||
return abs.UsageEnd
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) GetLocationStart() *time.Time {
|
||||
return abs.UsageStart
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) GetExplicitDurationInS() float64 {
|
||||
if abs.ExplicitBookingDurationS == 0 {
|
||||
if abs.UsageEnd == nil || abs.UsageStart == nil {
|
||||
return time.Duration(1 * time.Hour).Seconds()
|
||||
}
|
||||
return abs.UsageEnd.Sub(*abs.UsageStart).Seconds()
|
||||
}
|
||||
return abs.ExplicitBookingDurationS
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) GetPricingID() string {
|
||||
return abs.SelectedPricing
|
||||
}
|
||||
|
||||
func (r *AbstractCustomizedResource[T]) GetPrice(request *tools.APIRequest) (float64, error) {
|
||||
if r.UsageStart == nil || r.UsageEnd == nil {
|
||||
return 0, errors.New("Usage start and end must be set")
|
||||
}
|
||||
partner := r.GetPartnership(request)
|
||||
if partner != nil && partner.GetPricing(r.SelectedPricing) != nil {
|
||||
return 0, errors.New("Pricing strategy not found")
|
||||
}
|
||||
return partner.GetPricing(r.SelectedPricing).GetPrice(1, 0, *r.UsageStart, *r.UsageEnd, request)
|
||||
}
|
||||
|
||||
func (abs *AbstractCustomizedResource[T]) GetPartnership(request *tools.APIRequest) ResourcePartnerITF {
|
||||
partners, grps := abs.SelectedInstance.GetPeerGroups()
|
||||
for i, p := range grps {
|
||||
if request == nil {
|
||||
continue
|
||||
}
|
||||
if _, ok := p[request.PeerID]; ok {
|
||||
return partners[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyAuthAction[T InstanceITF](baseInstance []T, request *tools.APIRequest) []T {
|
||||
instances := []T{}
|
||||
for _, instance := range baseInstance {
|
||||
_, peerGroups := instance.GetPeerGroups()
|
||||
for _, peers := range peerGroups {
|
||||
if request == nil {
|
||||
continue
|
||||
}
|
||||
if grps, ok := peers[request.PeerID]; ok || config.GetConfig().Whitelist {
|
||||
if (ok && slices.Contains(grps, "*")) || (!ok && config.GetConfig().Whitelist) {
|
||||
instances = append(instances, instance)
|
||||
}
|
||||
for _, grp := range grps {
|
||||
if slices.Contains(request.Groups, grp) {
|
||||
instances = append(instances, instance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return instances
|
||||
}
|
||||
|
||||
type ItemResource struct {
|
||||
Data *DataResource `bson:"data,omitempty" json:"data,omitempty"`
|
||||
Processing *ProcessingResource `bson:"processing,omitempty" json:"processing,omitempty"`
|
||||
Storage *StorageResource `bson:"storage,omitempty" json:"storage,omitempty"`
|
||||
Compute *ComputeResource `bson:"compute,omitempty" json:"compute,omitempty"`
|
||||
Workflow *WorkflowResource `bson:"workflow,omitempty" json:"workflow,omitempty"`
|
||||
/*
|
||||
* 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 (i *ItemResource) GetAbstractRessource() *resource_model.AbstractResource {
|
||||
|
||||
if i.Data != nil {
|
||||
return &i.Data.AbstractResource
|
||||
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()
|
||||
}
|
||||
}
|
||||
if i.Processing != nil {
|
||||
return &i.Processing.AbstractResource
|
||||
}
|
||||
if i.Storage != nil {
|
||||
return &i.Storage.AbstractResource
|
||||
}
|
||||
if i.Compute != nil {
|
||||
return &i.Compute.AbstractResource
|
||||
}
|
||||
if i.Workflow != nil {
|
||||
return &i.Workflow.AbstractResource
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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"`
|
||||
Country countries.CountryCode `json:"country,omitempty" bson:"country,omitempty"`
|
||||
// Url string `json:"url,omitempty" bson:"url,omitempty"`
|
||||
AccessProtocol string `json:"access_protocol,omitempty" bson:"access_protocol,omitempty"`
|
||||
Partnerships []T `json:"partner_resource,omitempty" bson:"partner_resource,omitempty"`
|
||||
}
|
||||
|
||||
func (ri *ResourceInstance[T]) GetID() string {
|
||||
return ri.UUID
|
||||
}
|
||||
|
||||
func (r *ResourceInstance[T]) VerifyPartnerships() bool {
|
||||
peersMultiple := map[string]int{}
|
||||
for _, p := range r.Partnerships {
|
||||
for k, g := range p.GetPeerGroups() {
|
||||
for _, v := range g {
|
||||
if _, ok := peersMultiple[k+"_"+v]; !ok {
|
||||
peersMultiple[k+"_"+v] = 0
|
||||
}
|
||||
peersMultiple[k+"_"+v]++
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, p := range peersMultiple {
|
||||
if p > 1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (ri *ResourceInstance[T]) GetPeerGroups() ([]ResourcePartnerITF, []map[string][]string) {
|
||||
groups := []map[string][]string{}
|
||||
partners := []ResourcePartnerITF{}
|
||||
for _, p := range ri.Partnerships {
|
||||
partners = append(partners, p)
|
||||
groups = append(groups, p.GetPeerGroups())
|
||||
}
|
||||
return partners, groups
|
||||
}
|
||||
|
||||
func (ri *ResourceInstance[T]) ClearPeerGroups() {
|
||||
for _, p := range ri.Partnerships {
|
||||
p.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 map[string]T `json:"pricing,omitempty" bson:"pricing,omitempty"`
|
||||
}
|
||||
|
||||
func (rp *ResourcePartnerShip[T]) GetPricing(id string) pricing.PricingProfileITF {
|
||||
return rp.PricingProfiles[id]
|
||||
}
|
||||
|
||||
func (rp *ResourcePartnerShip[T]) GetPeerGroups() map[string][]string {
|
||||
return rp.PeerGroups
|
||||
}
|
||||
|
||||
func (rp *ResourcePartnerShip[T]) ClearPeerGroups() {
|
||||
rp.PeerGroups = map[string][]string{}
|
||||
}
|
||||
|
||||
/*
|
||||
-> when a workflow should book a resource
|
||||
-> it must be able to book a resource for a particular time
|
||||
-> the resource should be available for the time
|
||||
-> we must be able to parameter the resource for the time
|
||||
-> before bookin'
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/dbs"
|
||||
"cloud.o-forge.io/core/oc-lib/logs"
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
|
||||
@@ -14,15 +16,15 @@ type resourceMongoAccessor[T ResourceInterface] struct {
|
||||
}
|
||||
|
||||
// New creates a new instance of the computeMongoAccessor
|
||||
func New[T ResourceInterface](t tools.DataType, username string, peerID string, groups []string, caller *tools.HTTPCaller, g func() utils.DBObject) *resourceMongoAccessor[T] {
|
||||
func NewAccessor[T ResourceInterface](t tools.DataType, request *tools.APIRequest, g func() utils.DBObject) *resourceMongoAccessor[T] {
|
||||
if !slices.Contains([]tools.DataType{tools.COMPUTE_RESOURCE, tools.STORAGE_RESOURCE, tools.PROCESSING_RESOURCE, tools.WORKFLOW_RESOURCE, tools.DATA_RESOURCE}, t) {
|
||||
return nil
|
||||
}
|
||||
return &resourceMongoAccessor[T]{
|
||||
AbstractAccessor: utils.AbstractAccessor{
|
||||
ResourceModelAccessor: resource_model.New(),
|
||||
ResourceModelAccessor: resource_model.NewAccessor(),
|
||||
Logger: logs.CreateLogger(t.String()), // Create a logger with the data type
|
||||
Caller: caller,
|
||||
PeerID: peerID,
|
||||
User: username, // Set the caller
|
||||
Groups: groups, // Set the caller
|
||||
Request: request,
|
||||
Type: t,
|
||||
},
|
||||
generateData: g,
|
||||
@@ -39,12 +41,14 @@ func (dca *resourceMongoAccessor[T]) DeleteOne(id string) (utils.DBObject, int,
|
||||
|
||||
func (dca *resourceMongoAccessor[T]) UpdateOne(set utils.DBObject, id string) (utils.DBObject, int, error) {
|
||||
set.(T).SetResourceModel(nil)
|
||||
return utils.GenericUpdateOne(set.(T).Trim(), id, dca, dca.generateData()) // TODO CHANGE
|
||||
set.(T).Trim()
|
||||
return utils.GenericUpdateOne(set, id, dca, dca.generateData())
|
||||
}
|
||||
|
||||
func (dca *resourceMongoAccessor[T]) StoreOne(data utils.DBObject) (utils.DBObject, int, error) {
|
||||
data.(T).SetResourceModel(nil)
|
||||
return utils.GenericStoreOne(data.(T).Trim(), dca)
|
||||
data.(T).Trim()
|
||||
return utils.GenericStoreOne(data, dca)
|
||||
}
|
||||
|
||||
func (dca *resourceMongoAccessor[T]) CopyOne(data utils.DBObject) (utils.DBObject, int, error) {
|
||||
@@ -53,33 +57,36 @@ func (dca *resourceMongoAccessor[T]) CopyOne(data utils.DBObject) (utils.DBObjec
|
||||
|
||||
func (dca *resourceMongoAccessor[T]) LoadOne(id string) (utils.DBObject, int, error) {
|
||||
return utils.GenericLoadOne[T](id, func(d utils.DBObject) (utils.DBObject, int, error) {
|
||||
resources, _, err := dca.ResourceModelAccessor.Search(nil, dca.GetType().String())
|
||||
resources, _, err := dca.ResourceModelAccessor.Search(nil, dca.GetType().String(), false)
|
||||
if err == nil && len(resources) > 0 {
|
||||
d.(T).SetResourceModel(resources[0].(*resource_model.ResourceModel))
|
||||
}
|
||||
d.(T).SetAllowedInstances(dca.Request)
|
||||
return d, 200, nil
|
||||
}, dca)
|
||||
}
|
||||
|
||||
func (wfa *resourceMongoAccessor[T]) LoadAll() ([]utils.ShallowDBObject, int, error) {
|
||||
resources, _, err := wfa.ResourceModelAccessor.Search(nil, wfa.GetType().String())
|
||||
func (wfa *resourceMongoAccessor[T]) LoadAll(isDraft bool) ([]utils.ShallowDBObject, int, error) {
|
||||
resources, _, err := wfa.ResourceModelAccessor.Search(nil, wfa.GetType().String(), isDraft)
|
||||
return utils.GenericLoadAll[T](func(d utils.DBObject) utils.ShallowDBObject {
|
||||
if err == nil && len(resources) > 0 {
|
||||
d.(T).SetResourceModel(resources[0].(*resource_model.ResourceModel))
|
||||
}
|
||||
d.(T).SetAllowedInstances(wfa.Request)
|
||||
return d
|
||||
}, wfa)
|
||||
}, isDraft, wfa)
|
||||
}
|
||||
|
||||
func (wfa *resourceMongoAccessor[T]) Search(filters *dbs.Filters, search string) ([]utils.ShallowDBObject, int, error) {
|
||||
resources, _, err := wfa.ResourceModelAccessor.Search(nil, wfa.GetType().String())
|
||||
func (wfa *resourceMongoAccessor[T]) Search(filters *dbs.Filters, search string, isDraft bool) ([]utils.ShallowDBObject, int, error) {
|
||||
resources, _, err := wfa.ResourceModelAccessor.Search(nil, wfa.GetType().String(), false)
|
||||
return utils.GenericSearch[T](filters, search, wfa.getResourceFilter(search),
|
||||
func(d utils.DBObject) utils.ShallowDBObject {
|
||||
if err == nil && len(resources) > 0 {
|
||||
d.(T).SetResourceModel(resources[0].(*resource_model.ResourceModel))
|
||||
}
|
||||
d.(T).SetAllowedInstances(wfa.Request)
|
||||
return d
|
||||
}, wfa)
|
||||
}, isDraft, wfa)
|
||||
}
|
||||
|
||||
func (abs *resourceMongoAccessor[T]) getResourceFilter(search string) *dbs.Filters {
|
||||
|
||||
@@ -2,13 +2,9 @@ package resource_model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/config"
|
||||
"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/tools"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type WebResource struct {
|
||||
@@ -16,94 +12,6 @@ type WebResource struct {
|
||||
Path string `bson:"path,omitempty" json:"path,omitempty"` // Path is the path of the URL
|
||||
}
|
||||
|
||||
/*
|
||||
* AbstractResource is a struct that represents a resource
|
||||
* it defines the resource data
|
||||
*/
|
||||
type AbstractResource struct {
|
||||
utils.AbstractObject // AbstractObject contains the basic fields of an object (id, name)
|
||||
ShortDescription string `json:"short_description,omitempty" bson:"short_description,omitempty" validate:"required"` // ShortDescription is the short description of the resource
|
||||
Description string `json:"description,omitempty" bson:"description,omitempty"` // Description is the description of the resource
|
||||
Logo string `json:"logo,omitempty" bson:"logo,omitempty" validate:"required"` // Logo is the logo of the resource
|
||||
Owner string `json:"owner,omitempty" bson:"owner,omitempty" validate:"required"` // Owner is the owner of the resource
|
||||
OwnerLogo string `json:"owner_logo,omitempty" bson:"owner_logo,omitempty"` // OwnerLogo is the owner logo of the resource
|
||||
SourceUrl string `json:"source_url,omitempty" bson:"source_url,omitempty" validate:"required"` // SourceUrl is the source URL of the resource
|
||||
PeerID string `json:"peer_id,omitempty" bson:"peer_id,omitempty" validate:"required"` // PeerID is the ID of the peer getting this resource
|
||||
License string `json:"license,omitempty" bson:"license,omitempty"` // License is the license of the resource
|
||||
ResourceModel *ResourceModel `json:"resource_model,omitempty" bson:"resource_model,omitempty"` // ResourceModel is the model of the resource
|
||||
|
||||
AllowedPeersGroup map[string][]string `json:"allowed_peers_group,omitempty" bson:"allowed_peers_group,omitempty"` // AllowedPeersGroup is the group of allowed peers
|
||||
|
||||
Price string `json:"price,omitempty" bson:"price,omitempty"` // Price is the price of access to the resource
|
||||
Currency string `json:"currency,omitempty" bson:"currency,omitempty"` // Currency is the currency of the price
|
||||
}
|
||||
|
||||
func (ao *AbstractResource) GetAccessor(username string, peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (abs *AbstractResource) SetResourceModel(model *ResourceModel) {
|
||||
abs.ResourceModel = model
|
||||
}
|
||||
|
||||
func (abs *AbstractResource) VerifyAuth(username string, peerID string, groups []string) bool {
|
||||
if grps, ok := abs.AllowedPeersGroup[peerID]; ok || config.GetConfig().Whitelist {
|
||||
if (ok && slices.Contains(grps, "*")) || (!ok && config.GetConfig().Whitelist) {
|
||||
return true
|
||||
}
|
||||
for _, grp := range grps {
|
||||
if slices.Contains(groups, grp) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return abs.AbstractObject.VerifyAuth(username, peerID, groups)
|
||||
}
|
||||
|
||||
/*
|
||||
* GetModelType returns the type of the model key
|
||||
*/
|
||||
func (abs *AbstractResource) GetModelType(cat string, key string) interface{} {
|
||||
if abs.ResourceModel == nil || abs.ResourceModel.Model == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := abs.ResourceModel.Model[key]; !ok {
|
||||
return nil
|
||||
}
|
||||
return abs.ResourceModel.Model[cat][key].Type
|
||||
}
|
||||
|
||||
/*
|
||||
* GetModelKeys returns the keys of the model
|
||||
*/
|
||||
func (abs *AbstractResource) GetModelKeys() []string {
|
||||
keys := make([]string, 0)
|
||||
for k := range abs.ResourceModel.Model {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
/*
|
||||
* GetModelReadOnly returns the readonly of the model key
|
||||
*/
|
||||
func (abs *AbstractResource) GetModelReadOnly(cat string, key string) interface{} {
|
||||
if abs.ResourceModel == nil || abs.ResourceModel.Model == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := abs.ResourceModel.Model[key]; !ok {
|
||||
return nil
|
||||
}
|
||||
return abs.ResourceModel.Model[cat][key].ReadOnly
|
||||
}
|
||||
|
||||
func (d *AbstractResource) Trim() *AbstractResource {
|
||||
if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: d.PeerID}}).IsMySelf(); !ok {
|
||||
d.AllowedPeersGroup = map[string][]string{}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type Model struct {
|
||||
Type string `json:"type,omitempty" bson:"type,omitempty"` // Type is the type of the model
|
||||
ReadOnly bool `json:"readonly,omitempty" bson:"readonly,omitempty"` // ReadOnly is the readonly of the model
|
||||
@@ -115,38 +23,26 @@ type Model struct {
|
||||
* Warning: This struct is not user available, it is only used by the system
|
||||
*/
|
||||
type ResourceModel struct {
|
||||
UUID string `json:"id,omitempty" bson:"id,omitempty" validate:"required"`
|
||||
utils.AbstractObject
|
||||
ResourceType string `json:"resource_type,omitempty" bson:"resource_type,omitempty" validate:"required"`
|
||||
VarRefs map[string]string `json:"var_refs,omitempty" bson:"var_refs,omitempty"` // VarRefs is the variable references of the model
|
||||
Model map[string]map[string]Model `json:"model,omitempty" bson:"model,omitempty"`
|
||||
}
|
||||
|
||||
func (ao *ResourceModel) GetID() string {
|
||||
return ao.UUID
|
||||
func (d *ResourceModel) StoreDraftDefault() {
|
||||
d.Name = d.ResourceType + " Resource Model"
|
||||
d.IsDraft = false
|
||||
}
|
||||
|
||||
func (ao *ResourceModel) UpToDate(user string, create bool) {}
|
||||
|
||||
func (r *ResourceModel) GenerateID() {
|
||||
r.UUID = uuid.New().String()
|
||||
}
|
||||
|
||||
func (d *ResourceModel) GetName() string {
|
||||
return d.UUID
|
||||
}
|
||||
|
||||
func (abs *ResourceModel) VerifyAuth(username string, peerID string, groups []string) bool {
|
||||
func (abs *ResourceModel) VerifyAuth(request *tools.APIRequest) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *ResourceModel) GetAccessor(username string, peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
|
||||
func (d *ResourceModel) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return &ResourceModelMongoAccessor{
|
||||
utils.AbstractAccessor{
|
||||
Type: tools.RESOURCE_MODEL,
|
||||
PeerID: peerID,
|
||||
Groups: groups,
|
||||
User: username,
|
||||
Caller: caller,
|
||||
Type: tools.RESOURCE_MODEL,
|
||||
Request: request,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type ResourceModelMongoAccessor struct {
|
||||
* Nothing special here, just the basic CRUD operations
|
||||
*/
|
||||
|
||||
func New() *ResourceModelMongoAccessor {
|
||||
func NewAccessor() *ResourceModelMongoAccessor {
|
||||
return &ResourceModelMongoAccessor{
|
||||
utils.AbstractAccessor{
|
||||
Type: tools.RESOURCE_MODEL,
|
||||
@@ -46,17 +46,17 @@ func (a *ResourceModelMongoAccessor) LoadOne(id string) (utils.DBObject, int, er
|
||||
}, a)
|
||||
}
|
||||
|
||||
func (a *ResourceModelMongoAccessor) LoadAll() ([]utils.ShallowDBObject, int, error) {
|
||||
func (a *ResourceModelMongoAccessor) LoadAll(isDraft bool) ([]utils.ShallowDBObject, int, error) {
|
||||
return utils.GenericLoadAll[*ResourceModel](func(d utils.DBObject) utils.ShallowDBObject {
|
||||
return d
|
||||
}, a)
|
||||
}, isDraft, a)
|
||||
}
|
||||
|
||||
func (a *ResourceModelMongoAccessor) Search(filters *dbs.Filters, search string) ([]utils.ShallowDBObject, int, error) {
|
||||
func (a *ResourceModelMongoAccessor) Search(filters *dbs.Filters, search string, isDraft bool) ([]utils.ShallowDBObject, int, error) {
|
||||
return utils.GenericSearch[*ResourceModel](filters, search,
|
||||
&dbs.Filters{
|
||||
Or: map[string][]dbs.Filter{
|
||||
"resource_type": {{Operator: dbs.LIKE.String(), Value: search}},
|
||||
},
|
||||
}, func(d utils.DBObject) utils.ShallowDBObject { return d }, a)
|
||||
}, func(d utils.DBObject) utils.ShallowDBObject { return d }, isDraft, a)
|
||||
}
|
||||
|
||||
@@ -1,61 +1,138 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"cloud.o-forge.io/core/oc-lib/models/common"
|
||||
"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"
|
||||
)
|
||||
|
||||
type StorageSize int
|
||||
|
||||
// StorageType - Enum that defines the type of storage
|
||||
const (
|
||||
GB StorageSize = iota
|
||||
MB
|
||||
KB
|
||||
)
|
||||
|
||||
var argoType = [...]string{
|
||||
"Gi",
|
||||
"Mi",
|
||||
"Ki",
|
||||
}
|
||||
|
||||
// New creates a new instance of the StorageResource struct
|
||||
func (dma StorageSize) ToArgo() string {
|
||||
return argoType[dma]
|
||||
}
|
||||
|
||||
// enum of a data type
|
||||
type StorageType int
|
||||
|
||||
const (
|
||||
FILE = iota
|
||||
STREAM
|
||||
API
|
||||
DATABASE
|
||||
S3
|
||||
MEMORY
|
||||
HARDWARE
|
||||
)
|
||||
|
||||
/*
|
||||
* StorageResource is a struct that represents a storage resource
|
||||
* it defines the resource storage
|
||||
*/
|
||||
type StorageResource struct {
|
||||
resource_model.AbstractResource // AbstractResource contains the basic fields of an object (id, name)
|
||||
resource_model.WebResource
|
||||
Type StorageType `bson:"type,omitempty" json:"type,omitempty"` // Type is the type of the storage
|
||||
Acronym string `bson:"acronym,omitempty" json:"acronym,omitempty"` // Acronym is the acronym of the storage
|
||||
SizeType StorageSize `bson:"size_type" json:"size_type" default:"0"` // SizeType is the type of the storage size
|
||||
Size uint `bson:"size,omitempty" json:"size,omitempty"` // Size is the size of the storage
|
||||
Local bool `bson:"local" json:"local"` // Local is a flag that indicates if the storage is local
|
||||
Encryption bool `bson:"encryption,omitempty" json:"encryption,omitempty"` // Encryption is a flag that indicates if the storage is encrypted
|
||||
Redundancy string `bson:"redundancy,omitempty" json:"redundancy,omitempty"` // Redundancy is the redundancy of the storage
|
||||
Throughput string `bson:"throughput,omitempty" json:"throughput,omitempty"` // Throughput is the throughput of the storage
|
||||
AbstractResource[*StorageResourceInstance] // AbstractResource contains the basic fields of an object (id, name)
|
||||
Type common.StorageType `bson:"type,omitempty" json:"type,omitempty"` // Type is the type of the storage
|
||||
Acronym string `bson:"acronym,omitempty" json:"acronym,omitempty"` // Acronym is the acronym of the storage
|
||||
}
|
||||
|
||||
func (d *StorageResource) GetAccessor(username string, peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
|
||||
return New[*StorageResource](tools.STORAGE_RESOURCE, username, peerID, groups, caller, func() utils.DBObject { return &StorageResource{} }) // Create a new instance of the accessor
|
||||
func (d *StorageResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return NewAccessor[*StorageResource](tools.STORAGE_RESOURCE, request, func() utils.DBObject { return &StorageResource{} }) // Create a new instance of the accessor
|
||||
}
|
||||
|
||||
type StorageResourceInstance struct {
|
||||
ResourceInstance[*StorageResourcePartnership]
|
||||
Local bool `bson:"local" json:"local"`
|
||||
SecurityLevel string `bson:"security_level,omitempty" json:"security_level,omitempty"`
|
||||
SizeType common.StorageSize `bson:"size_type" json:"size_type" default:"0"` // SizeType is the type of the storage size
|
||||
SizeGB uint `bson:"size,omitempty" json:"size,omitempty"` // Size is the size of the storage
|
||||
Encryption bool `bson:"encryption,omitempty" json:"encryption,omitempty"` // Encryption is a flag that indicates if the storage is encrypted
|
||||
Redundancy string `bson:"redundancy,omitempty" json:"redundancy,omitempty"` // Redundancy is the redundancy of the storage
|
||||
Throughput string `bson:"throughput,omitempty" json:"throughput,omitempty"` // Throughput is the throughput of the storage
|
||||
}
|
||||
|
||||
func (i *StorageResourceInstance) GetID() string {
|
||||
return i.UUID
|
||||
}
|
||||
|
||||
type StorageResourcePartnership struct {
|
||||
ResourcePartnerShip[*StorageResourcePricingProfile]
|
||||
MaxSizeGBAllowed float64 `json:"allowed_gb,omitempty" bson:"allowed_gb,omitempty"`
|
||||
OnlyEncryptedAllowed bool `json:"personal_data_allowed,omitempty" bson:"personal_data_allowed,omitempty"`
|
||||
}
|
||||
|
||||
type PrivilegeStoragePricingStrategy int
|
||||
|
||||
const (
|
||||
BASIC_STORAGE PrivilegeStoragePricingStrategy = iota
|
||||
GARANTED_ON_DELAY_STORAGE
|
||||
GARANTED_STORAGE
|
||||
)
|
||||
|
||||
func (t PrivilegeStoragePricingStrategy) String() string {
|
||||
return [...]string{"BASIC_STORAGE", "GARANTED_ON_DELAY_STORAGE", "GARANTED_STORAGE"}[t]
|
||||
}
|
||||
|
||||
type StorageResourcePricingStrategy int
|
||||
|
||||
const (
|
||||
PER_DATA_STORED StorageResourcePricingStrategy = iota
|
||||
PER_TB_STORED
|
||||
PER_GB_STORED
|
||||
PER_MB_STORED
|
||||
PER_KB_STORED
|
||||
)
|
||||
|
||||
func (t StorageResourcePricingStrategy) GetStrategy() string {
|
||||
return [...]string{"PER_DATA_STORED", "PER_GB_STORED", "PER_MB_STORED", "PER_KB_STORED"}[t]
|
||||
}
|
||||
|
||||
func (t StorageResourcePricingStrategy) GetStrategyValue() int {
|
||||
return int(t)
|
||||
}
|
||||
|
||||
func ToStorageResourcePricingStrategy(i int) StorageResourcePricingStrategy {
|
||||
return StorageResourcePricingStrategy(i)
|
||||
}
|
||||
|
||||
func (t StorageResourcePricingStrategy) GetQuantity(amountOfDataGB float64) (float64, error) {
|
||||
switch t {
|
||||
case PER_DATA_STORED:
|
||||
return amountOfDataGB, nil
|
||||
case PER_TB_STORED:
|
||||
return amountOfDataGB * 1000, nil
|
||||
case PER_GB_STORED:
|
||||
return amountOfDataGB, nil
|
||||
case PER_MB_STORED:
|
||||
return (amountOfDataGB * 1000), nil
|
||||
case PER_KB_STORED:
|
||||
return amountOfDataGB * 1000000, nil
|
||||
}
|
||||
return 0, errors.New("Pricing strategy not found")
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (p *StorageResourcePricingProfile) IsBuying() bool {
|
||||
return p.Pricing.BuyingStrategy != pricing.PAY_PER_USE
|
||||
}
|
||||
|
||||
func (p *StorageResourcePricingProfile) GetPrice(amountOfData float64, val float64, start time.Time, end time.Time, request *tools.APIRequest, params ...string) (float64, error) {
|
||||
return p.Pricing.GetPrice(amountOfData, val, start, &end)
|
||||
}
|
||||
|
||||
type CustomizedStorageResource struct {
|
||||
AbstractCustomizedResource[*StorageResourceInstance]
|
||||
StorageGB float64 `json:"storage_gb,omitempty" bson:"storage_gb,omitempty"`
|
||||
}
|
||||
|
||||
func (r *CustomizedStorageResource) GetType() tools.DataType {
|
||||
return tools.STORAGE_RESOURCE
|
||||
}
|
||||
|
||||
func (r *CustomizedStorageResource) GetPrice(request *tools.APIRequest) (float64, error) {
|
||||
if r.UsageStart == nil || r.UsageEnd == nil {
|
||||
return 0, errors.New("Usage start and end must be set")
|
||||
}
|
||||
partner := r.GetPartnership(request)
|
||||
if partner != nil && partner.GetPricing(r.SelectedPricing) != nil {
|
||||
return 0, errors.New("Pricing strategy not found")
|
||||
}
|
||||
pricing := partner.GetPricing(r.SelectedPricing)
|
||||
var err error
|
||||
amountOfData := float64(1)
|
||||
if pricing.GetOverrideStrategyValue() >= 0 {
|
||||
amountOfData, err = ToStorageResourcePricingStrategy(pricing.GetOverrideStrategyValue()).GetQuantity(r.StorageGB)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return pricing.GetPrice(amountOfData, r.ExplicitBookingDurationS, *r.UsageStart, *r.UsageEnd, request)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,96 @@
|
||||
package resources
|
||||
|
||||
import (
|
||||
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
|
||||
"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"
|
||||
)
|
||||
|
||||
// WorkflowResource is a struct that represents a workflow resource
|
||||
// it defines the resource workflow
|
||||
type WorkflowResource struct {
|
||||
resource_model.AbstractResource
|
||||
// COMPLEX SHOULD BE REFACTORED
|
||||
// we don't have any information about the accessor
|
||||
type abstractWorkflowResource struct {
|
||||
ExploitedResourceSet
|
||||
WorkflowID string `bson:"workflow_id,omitempty" json:"workflow_id,omitempty"` // WorkflowID is the ID of the native workflow
|
||||
}
|
||||
|
||||
func (d *WorkflowResource) GetAccessor(username string, peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
|
||||
return New[*WorkflowResource](tools.WORKFLOW_RESOURCE, username, peerID, groups, caller, func() utils.DBObject { return &WorkflowResource{} }) // Create a new instance of the accessor
|
||||
// WorkflowResource is a struct that represents a workflow resource
|
||||
// it defines the resource workflow
|
||||
type WorkflowResource struct {
|
||||
AbstractResource[*ResourceInstance[*ResourcePartnerShip[*WorkflowResourcePricingProfile]]]
|
||||
abstractWorkflowResource
|
||||
}
|
||||
|
||||
type CustomizedWorkflowResource struct {
|
||||
AbstractCustomizedResource[*ResourceInstance[*ResourcePartnerShip[*WorkflowResourcePricingProfile]]]
|
||||
abstractWorkflowResource
|
||||
}
|
||||
|
||||
func (r *CustomizedWorkflowResource) GetType() tools.DataType {
|
||||
return tools.WORKFLOW_RESOURCE
|
||||
}
|
||||
|
||||
func (d *WorkflowResource) GetAccessor(request *tools.APIRequest) utils.Accessor {
|
||||
return NewAccessor[*WorkflowResource](tools.WORKFLOW_RESOURCE, request, func() utils.DBObject { return &WorkflowResource{} }) // Create a new instance of the accessor
|
||||
}
|
||||
|
||||
type WorkflowResourcePricingProfile struct {
|
||||
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) IsBuying() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
* Missing wich Instance is selected
|
||||
*
|
||||
*/
|
||||
|
||||
func (p *WorkflowResourcePricingProfile) GetPrice(amountOfData float64, val float64, start time.Time, end time.Time, request *tools.APIRequest, params ...string) (float64, error) {
|
||||
// load workflow
|
||||
price := float64(0)
|
||||
pp, err := getPrice[*CustomizedDataResource](p.DataResources, amountOfData, val, start, end, request, params...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += pp
|
||||
pp, err = getPrice[*CustomizedStorageResource](p.StorageResources, amountOfData, val, start, end, request, params...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += pp
|
||||
pp, err = getPrice[*CustomizedProcessingResource](p.ProcessingResources, amountOfData, val, start, end, request, params...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += pp
|
||||
pp, err = getPrice[*CustomizedComputeResource](p.ComputeResources, amountOfData, val, start, end, request, params...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += pp
|
||||
pp, err = getPrice[*CustomizedWorkflowResource](p.WorkflowResources, amountOfData, val, start, end, request, params...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += pp
|
||||
return price, nil
|
||||
}
|
||||
|
||||
func getPrice[T ShallowResourceInterface](arr []T, amountOfData float64, val float64, start time.Time, end time.Time, request *tools.APIRequest, params ...string) (float64, error) {
|
||||
// load workflow
|
||||
price := float64(0)
|
||||
for _, data := range arr {
|
||||
partner := data.GetPartnership(request)
|
||||
pricing := partner.GetPricing(data.GetPricingID())
|
||||
pp, err := pricing.GetPrice(amountOfData, val, start, end, request)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
price += pp
|
||||
}
|
||||
return price, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user