Orga + Consent

This commit is contained in:
mr
2026-06-05 15:56:50 +02:00
parent 6ee169f444
commit 1425a31494
8 changed files with 79 additions and 5 deletions
+11
View File
@@ -0,0 +1,11 @@
package organization
// Organization holds descriptive data about a peer's organization.
// It is optional — a peer without an organization has a nil Organization field.
type Organization struct {
Name string `json:"name,omitempty" bson:"name,omitempty"`
Description string `json:"description,omitempty" bson:"description,omitempty"`
Website string `json:"website,omitempty" bson:"website,omitempty"`
Sector string `json:"sector,omitempty" bson:"sector,omitempty"`
Country string `json:"country,omitempty" bson:"country,omitempty"`
}
+21 -1
View File
@@ -5,6 +5,7 @@ import (
"strings" "strings"
"time" "time"
"cloud.o-forge.io/core/oc-lib/models/organization"
"cloud.o-forge.io/core/oc-lib/models/utils" "cloud.o-forge.io/core/oc-lib/models/utils"
"cloud.o-forge.io/core/oc-lib/tools" "cloud.o-forge.io/core/oc-lib/tools"
"github.com/biter777/countries" "github.com/biter777/countries"
@@ -30,9 +31,19 @@ const (
NANO NANO
PENDING_NANO PENDING_NANO
PENDING_MASTER PENDING_MASTER
ORGANIZATION_MASTER
ORGANIZATION_MEMBER
ORGANIZATION_PARTNER
ORGANIZATION_MASTER_PENDING
ORGANIZATION_MEMBER_PENDING
) )
var path = []string{"known", "self", "partner", "blacklist", "pending_partner", "master", "nano", "pending_nano", "pending_master"} var path = []string{
"known", "self", "partner", "blacklist", "pending_partner",
"master", "nano", "pending_nano", "pending_master",
"organization_master", "organization_member", "organization_partner",
"organization_master_pending", "organization_member_pending",
}
func GetRelationPath(str string) int { func GetRelationPath(str string) int {
for i, p := range path { for i, p := range path {
@@ -121,6 +132,15 @@ type Peer struct {
// When oc-discovery fails to reach a NANO, it routes the booking to MasterID instead. // When oc-discovery fails to reach a NANO, it routes the booking to MasterID instead.
MasterID string `json:"master_id,omitempty" bson:"master_id,omitempty"` MasterID string `json:"master_id,omitempty" bson:"master_id,omitempty"`
// OrganizationMasterID is the MongoDB _id of the peer acting as this node's
// organization master. Set automatically when an ORGANIZATION_MASTER relation
// is validated (equivalent of MasterID for the Nano/Master hierarchy).
OrganizationMasterID string `json:"organization_master_id,omitempty" bson:"organization_master_id,omitempty"`
// Organization holds optional descriptive data about the peer's organization.
// Null when the peer has not registered any organization data.
Organization *organization.Organization `json:"organization,omitempty" bson:"organization,omitempty"`
// Volatile connectivity state — never persisted to DB (bson:"-"). // Volatile connectivity state — never persisted to DB (bson:"-").
// Set in-memory by oc-peer when it receives a PEER_OBSERVE_RESPONSE_EVENT. // Set in-memory by oc-peer when it receives a PEER_OBSERVE_RESPONSE_EVENT.
// Considered offline when LastHeartbeat is older than 60 s (30 s interval + 30 s grace). // Considered offline when LastHeartbeat is older than 60 s (30 s interval + 30 s grace).
+14
View File
@@ -0,0 +1,14 @@
package resources
// Consent represents a consent request attached to a resource.
// ConsentString is the question displayed to the user.
// Optional, when true, means the user may decline without blocking scheduling.
// A nil Optional is treated as required (false).
type Consent struct {
ConsentString string `json:"consent_string" bson:"consent_string"`
Optional *bool `json:"optional,omitempty" bson:"optional,omitempty"`
}
func (c Consent) IsOptional() bool {
return c.Optional != nil && *c.Optional
}
+1
View File
@@ -30,6 +30,7 @@ type ResourceInterface interface {
GetInputs() []models.Param GetInputs() []models.Param
GetOutputs() []models.Param GetOutputs() []models.Param
GetExploitationAuthorizations() []ExploitationAuthorization GetExploitationAuthorizations() []ExploitationAuthorization
GetConsents() []Consent
} }
type ResourceInstanceITF interface { type ResourceInstanceITF interface {
+9
View File
@@ -50,6 +50,10 @@ type AbstractResource struct {
// NOT in a separate collection. // NOT in a separate collection.
// Visibility-filtered per requesting peer before any response is sent. // Visibility-filtered per requesting peer before any response is sent.
ExploitationAuthorizations []ExploitationAuthorization `json:"exploitation_authorizations,omitempty" bson:"exploitation_authorizations,omitempty"` ExploitationAuthorizations []ExploitationAuthorization `json:"exploitation_authorizations,omitempty" bson:"exploitation_authorizations,omitempty"`
// Consents lists the consent questions the user must acknowledge before
// scheduling this resource. Consents with Optional=true may be skipped.
Consents []Consent `json:"consents,omitempty" bson:"consents,omitempty"`
} }
func (ri *AbstractResource) Extend(typ ...string) map[string][]tools.DataType { func (ri *AbstractResource) Extend(typ ...string) map[string][]tools.DataType {
@@ -100,6 +104,11 @@ func (r *AbstractResource) GetExploitationAuthorizations() []ExploitationAuthori
return r.ExploitationAuthorizations return r.ExploitationAuthorizations
} }
// GetConsents returns the consent questions declared by this resource.
func (r *AbstractResource) GetConsents() []Consent {
return r.Consents
}
// FilterExploitationAuthorizations removes AEs that are not visible to peerID. // FilterExploitationAuthorizations removes AEs that are not visible to peerID.
// Must be called before serializing the resource for a consumer peer. // Must be called before serializing the resource for a consumer peer.
// The resource owner (CreatorID) always sees all AEs unfiltered. // The resource owner (CreatorID) always sees all AEs unfiltered.
@@ -48,6 +48,10 @@ type WorkflowExecution struct {
BookingsState map[string]BookingState `json:"bookings_state" bson:"bookings_state,omitempty"` // booking_id → reservation+completion status BookingsState map[string]BookingState `json:"bookings_state" bson:"bookings_state,omitempty"` // booking_id → reservation+completion status
PurchasesState map[string]bool `json:"purchases_state" bson:"purchases_state,omitempty"` // purchase_id → confirmed PurchasesState map[string]bool `json:"purchases_state" bson:"purchases_state,omitempty"` // purchase_id → confirmed
// ResourceConsents records which consent strings the user acknowledged per resource
// (resource_id → list of acknowledged ConsentString values) at scheduling time.
ResourceConsents map[string][]string `json:"resource_consents,omitempty" bson:"resource_consents,omitempty"`
// Graph is a lightweight, real-time summary of the workflow execution graph. // Graph is a lightweight, real-time summary of the workflow execution graph.
// Keyed by workflow graph item ID; updated by oc-scheduler on each step-done event. // Keyed by workflow graph item ID; updated by oc-scheduler on each step-done event.
// Consumed by oc-front to render the live execution panel via websocket updates. // Consumed by oc-front to render the live execution panel via websocket updates.
+13 -2
View File
@@ -208,6 +208,14 @@ const (
// for a private source resource (isReachable=false, Phase 4). // for a private source resource (isReachable=false, Phase 4).
// oc-discovery routes it to the resource owner peer via ProtocolSourcePresignResource. // oc-discovery routes it to the resource owner peer via ProtocolSourcePresignResource.
PB_SOURCE_PRESIGN PB_SOURCE_PRESIGN
// PB_ORG_PARTNER is propagated via PB_PROPAGATE through oc-discovery to the
// organization master's oc-discovery, which notifies its oc-peer via
// ORG_PARTNER_EVENT. The master's oc-peer confirms or rejects by emitting a
// PROPALGATION_EVENT back, which oc-discovery routes to the originating
// oc-discovery, which in turn notifies our oc-peer via ORG_PARTNER_EVENT to
// finalize the relation.
PB_ORG_PARTNER
) )
func GetActionString(ss string) PubSubAction { func GetActionString(ss string) PubSubAction {
@@ -242,6 +250,8 @@ func GetActionString(ss string) PubSubAction {
return PB_PROPAGATE return PB_PROPAGATE
case "source_presign": case "source_presign":
return PB_SOURCE_PRESIGN return PB_SOURCE_PRESIGN
case "org_partner":
return PB_ORG_PARTNER
default: default:
return NONE return NONE
} }
@@ -264,8 +274,9 @@ var path = []string{
"none", // 12 NONE "none", // 12 NONE
"observe", // 13 PB_OBSERVE "observe", // 13 PB_OBSERVE
"observe_close", // 14 PB_OBSERVE_CLOSE "observe_close", // 14 PB_OBSERVE_CLOSE
"propagate", // 15 PB_PROPAGATE "propagate", // 15 PB_PROPAGATE
"source_presign", // 16 PB_SOURCE_PRESIGN "source_presign", // 16 PB_SOURCE_PRESIGN
"org_partner", // 17 PB_ORG_PARTNER
} }
func (m PubSubAction) String() string { func (m PubSubAction) String() string {
+6 -2
View File
@@ -32,7 +32,7 @@ var meths = []string{"remove execution", "create execution", "planner execution"
"considers event", "admiralty config event", "minio config event", "pvc config event", "considers event", "admiralty config event", "minio config event", "pvc config event",
"workflow started event", "workflow step done event", "workflow done event", "workflow started event", "workflow step done event", "workflow done event",
"peer behavior event", "peer observe response event", "peer observe event", "peer behavior event", "peer observe response event", "peer observe event",
"source presign event", "source presign event", "org partner event",
} }
const ( const (
@@ -85,6 +85,10 @@ const (
// oc-datacenter listens to it to generate a pre-signed Minio URL and reply // oc-datacenter listens to it to generate a pre-signed Minio URL and reply
// via PB_CONSIDERS (Phase 4 — isReachable=false). // via PB_CONSIDERS (Phase 4 — isReachable=false).
SOURCE_PRESIGN_EVENT SOURCE_PRESIGN_EVENT
// ORG_PARTNER_EVENT is emitted by a peer to its OrganizationMaster to ask:
// "is peer X one of your members?". The master replies via the same channel.
ORG_PARTNER_EVENT
) )
func (n NATSMethod) String() string { func (n NATSMethod) String() string {
@@ -98,7 +102,7 @@ func NameToMethod(name string) NATSMethod {
CONSIDERS_EVENT, ADMIRALTY_CONFIG_EVENT, MINIO_CONFIG_EVENT, PVC_CONFIG_EVENT, CONSIDERS_EVENT, ADMIRALTY_CONFIG_EVENT, MINIO_CONFIG_EVENT, PVC_CONFIG_EVENT,
WORKFLOW_STARTED_EVENT, WORKFLOW_STEP_DONE_EVENT, WORKFLOW_DONE_EVENT, WORKFLOW_STARTED_EVENT, WORKFLOW_STEP_DONE_EVENT, WORKFLOW_DONE_EVENT,
PEER_BEHAVIOR_EVENT, PEER_OBSERVE_RESPONSE_EVENT, PEER_OBSERVE_EVENT, PEER_BEHAVIOR_EVENT, PEER_OBSERVE_RESPONSE_EVENT, PEER_OBSERVE_EVENT,
SOURCE_PRESIGN_EVENT} { SOURCE_PRESIGN_EVENT, ORG_PARTNER_EVENT} {
if strings.Contains(strings.ToLower(v.String()), strings.ToLower(name)) { if strings.Contains(strings.ToLower(v.String()), strings.ToLower(name)) {
return v return v
} }