2024-07-18 11:51:12 +02:00
package resources
2024-07-19 10:54:58 +02:00
import (
2024-12-12 16:25:47 +01:00
"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"
2024-11-28 11:05:54 +01:00
"cloud.o-forge.io/core/oc-lib/models/resources/resource_model"
"cloud.o-forge.io/core/oc-lib/models/utils"
2024-12-12 16:25:47 +01:00
"cloud.o-forge.io/core/oc-lib/tools"
"github.com/biter777/countries"
"github.com/marcinwyszynski/geopoint"
2024-07-19 10:54:58 +02:00
)
2024-07-18 11:51:12 +02:00
// AbstractResource is the struct containing all of the attributes commons to all ressources
// Resource is the interface to be implemented by all classes inheriting from Resource to have the same behavior
2024-07-23 11:22:50 +02:00
// http://www.inanzzz.com/index.php/post/wqbs/a-basic-usage-of-int-and-string-enum-types-in-golang
2024-12-12 16:25:47 +01:00
/ *
* 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" `
}
func ( r * abstractResource ) StoreDraftDefault ( ) {
r . IsDraft = true
}
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 * 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 ]
2024-11-28 11:05:54 +01:00
}
}
}
2024-12-12 16:25:47 +01:00
return nil
2024-11-28 11:05:54 +01:00
}
2024-12-16 12:17:20 +01:00
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 )
}
2024-12-12 16:25:47 +01:00
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" `
2024-07-30 12:08:13 +02:00
}
2024-08-01 16:50:16 +02:00
2024-12-12 16:25:47 +01:00
func ( abs * AbstractCustomizedResource [ T ] ) SetStartUsage ( start time . Time ) {
if abs . UsageStart == nil {
abs . UsageStart = & start
}
}
2024-11-28 11:05:54 +01:00
2024-12-12 16:25:47 +01:00
func ( abs * AbstractCustomizedResource [ T ] ) SetEndUsage ( end time . Time ) {
if abs . UsageEnd == nil {
abs . UsageEnd = & end
2024-08-01 16:50:16 +02:00
}
2024-12-12 16:25:47 +01:00
}
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 ( )
2024-08-01 16:50:16 +02:00
}
2024-12-12 16:25:47 +01:00
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" )
2024-08-01 16:50:16 +02:00
}
2024-12-12 16:25:47 +01:00
partner := r . GetPartnership ( request )
if partner != nil && partner . GetPricing ( r . SelectedPricing ) != nil {
return 0 , errors . New ( "Pricing strategy not found" )
2024-08-01 16:50:16 +02:00
}
2024-12-12 16:25:47 +01:00
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 ]
}
2024-08-01 16:50:16 +02:00
}
return nil
2024-11-28 11:05:54 +01:00
}
2024-12-12 16:25:47 +01:00
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 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 '
* /