419 lines
8.9 KiB
Go
419 lines
8.9 KiB
Go
package models
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"cloud.o-forge.io/core/oc-catalog/models/rtype"
|
|
"cloud.o-forge.io/core/oc-catalog/services"
|
|
"github.com/beego/beego/v2/core/logs"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo"
|
|
)
|
|
|
|
// Assure consistency by using a const which refers to the MongoDB entry name
|
|
// Workspace.Projects
|
|
const WorkflowDB = "workflows"
|
|
|
|
type Workspace struct {
|
|
UserID string `bson:"_id" json:"user_id"`
|
|
|
|
Workflows map[string]Workflow //WorkflowDB
|
|
|
|
// ID: rtype
|
|
Data []string `json:"data"`
|
|
Computing []string `json:"computing"`
|
|
Datacenter []string `json:"datacenter"`
|
|
Storage []string `json:"storage"`
|
|
}
|
|
|
|
type ResourceModel interface {
|
|
getRtype() rtype.Rtype
|
|
getName() string
|
|
}
|
|
|
|
func (w Workspace) getRtype(rID string) (resModel rtype.Rtype) {
|
|
|
|
for _, compVal := range w.Computing {
|
|
if compVal == rID {
|
|
return rtype.COMPUTING
|
|
}
|
|
}
|
|
|
|
for _, datVal := range w.Data {
|
|
if datVal == rID {
|
|
return rtype.DATA
|
|
}
|
|
}
|
|
|
|
for _, storVal := range w.Storage {
|
|
if storVal == rID {
|
|
return rtype.STORAGE
|
|
}
|
|
}
|
|
|
|
for _, datcentVal := range w.Datacenter {
|
|
if datcentVal == rID {
|
|
return rtype.DATACENTER
|
|
}
|
|
}
|
|
|
|
return rtype.INVALID
|
|
}
|
|
|
|
func (w *Workspace) GetResources() map[rtype.Rtype][]string {
|
|
return map[rtype.Rtype][]string{
|
|
rtype.DATA: w.Data,
|
|
rtype.COMPUTING: w.Computing,
|
|
rtype.STORAGE: w.Storage,
|
|
rtype.DATACENTER: w.Datacenter,
|
|
}
|
|
}
|
|
|
|
func (w *Workspace) GetWorkflow(workflowName string) *Workflow {
|
|
|
|
var proj Workflow
|
|
|
|
proj = w.Workflows[workflowName]
|
|
return &proj
|
|
}
|
|
|
|
func (w *Workspace) GetWorkflows() []string {
|
|
|
|
if len(w.Workflows) == 0 {
|
|
return nil
|
|
}
|
|
|
|
workflowNames := make([]string, len(w.Workflows))
|
|
|
|
i := 0
|
|
for k := range w.Workflows {
|
|
workflowNames[i] = k
|
|
i++
|
|
}
|
|
|
|
return workflowNames
|
|
}
|
|
|
|
type WorkspaceModel struct {
|
|
UserID string `bson:"_id" json:"user_id"`
|
|
|
|
Data []DataModel `json:"data"`
|
|
Computing []ComputingModel `json:"computing"`
|
|
Datacenter []DatacenterModel `json:"datacenter"`
|
|
Storage []StorageModel `json:"storage"`
|
|
}
|
|
|
|
func ListFullWorkspace(userID string) (*WorkspaceModel, error) {
|
|
ws := GetWorkspace(userID)
|
|
|
|
if ws == nil {
|
|
return nil, errors.New("Internal error")
|
|
}
|
|
|
|
fws := &WorkspaceModel{
|
|
UserID: ws.UserID,
|
|
|
|
Data: []DataModel{},
|
|
Computing: []ComputingModel{},
|
|
Datacenter: []DatacenterModel{},
|
|
Storage: []StorageModel{},
|
|
}
|
|
|
|
pipeline := []primitive.M{
|
|
{"$match": primitive.M{"_id": userID}},
|
|
{"$lookup": primitive.M{
|
|
"localField": "data",
|
|
"from": services.MngoNamesCollection.DATA,
|
|
"foreignField": "_id",
|
|
"as": "data",
|
|
}},
|
|
{"$lookup": primitive.M{
|
|
"localField": "computing",
|
|
"from": services.MngoNamesCollection.COMPUTING,
|
|
"foreignField": "_id",
|
|
"as": "computing",
|
|
}},
|
|
{"$lookup": primitive.M{
|
|
"localField": "datacenter",
|
|
"from": services.MngoNamesCollection.DATACENTER,
|
|
"foreignField": "_id",
|
|
"as": "datacenter",
|
|
}},
|
|
{"$lookup": primitive.M{
|
|
"localField": "storage",
|
|
"from": services.MngoNamesCollection.STORAGE,
|
|
"foreignField": "_id",
|
|
"as": "storage",
|
|
}},
|
|
}
|
|
|
|
ret, err := services.MngoCollWorkspace.Aggregate(services.MngoCtx, pipeline)
|
|
|
|
if err != nil {
|
|
message := "Couldn't obtain subobjects"
|
|
logs.Debug(message + "; " + err.Error())
|
|
return nil, errors.New(message)
|
|
}
|
|
|
|
if ret.RemainingBatchLength() == 1 {
|
|
ret.Next(context.Background())
|
|
ret.Decode(&fws)
|
|
}
|
|
|
|
return fws, nil
|
|
}
|
|
|
|
// Contains tells whether a contains x.
|
|
func contains(a []string, x string) bool {
|
|
for _, n := range a {
|
|
if x == n {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func RemoveResource(userID, rID, rType string) error {
|
|
|
|
rIDObj, err := primitive.ObjectIDFromHex(rID)
|
|
|
|
if err != nil {
|
|
message := "ID " + rID + " is not valid"
|
|
logs.Debug(message + "; " + err.Error())
|
|
return errors.New(message)
|
|
}
|
|
|
|
result, err := services.MngoCollWorkspace.UpdateOne(services.MngoCtx,
|
|
primitive.M{"_id": userID},
|
|
primitive.M{"$pull": primitive.M{rType: rIDObj}},
|
|
)
|
|
|
|
if err != nil {
|
|
message := err.Error()
|
|
logs.Debug(message)
|
|
return errors.New(message)
|
|
}
|
|
|
|
if result.MatchedCount == 0 {
|
|
message := "No user " + userID + " in workspace"
|
|
logs.Debug(message)
|
|
return errors.New(message)
|
|
}
|
|
|
|
if result.ModifiedCount == 0 {
|
|
message := "No rID " + rID + " in rtype " + rType
|
|
logs.Debug(message)
|
|
return errors.New(message)
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
func (w *Workspace) updateDB() (err error) {
|
|
|
|
_, err = services.MngoCollWorkspace.ReplaceOne(services.MngoCtx,
|
|
primitive.M{"_id": w.UserID},
|
|
w,
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
func (w *Workspace) NewResource(rID string, rType string) (err error) {
|
|
|
|
var targetArray *[]string
|
|
|
|
switch rType {
|
|
case rtype.DATA.String():
|
|
targetArray = &w.Data
|
|
case rtype.COMPUTING.String():
|
|
targetArray = &w.Computing
|
|
case rtype.STORAGE.String():
|
|
targetArray = &w.Storage
|
|
case rtype.DATACENTER.String():
|
|
targetArray = &w.Datacenter
|
|
default:
|
|
return errors.New("Rtype " + rType + " is not valid")
|
|
}
|
|
|
|
for _, models := range *targetArray {
|
|
if models == rID {
|
|
return errors.New("Resource " + rID + " of type " + rType +
|
|
" is already registered for user " + w.UserID)
|
|
}
|
|
}
|
|
|
|
*targetArray = append(*targetArray, rID)
|
|
|
|
w.updateDB()
|
|
|
|
return
|
|
}
|
|
|
|
func AddResource(userID, rID, rType string) (err error) {
|
|
|
|
var rIDObj *primitive.ObjectID
|
|
|
|
if rIDObj, err = IsValidResource(rID, rType); err != nil {
|
|
return err
|
|
}
|
|
|
|
//TODO: Maybe operate directly in the DB instead retriving the full object?
|
|
userWorkspace := GetWorkspace(userID)
|
|
|
|
// Exist in the DB
|
|
if userWorkspace != nil {
|
|
var targetArray []string
|
|
|
|
switch rType {
|
|
case rtype.DATA.String():
|
|
targetArray = userWorkspace.Data
|
|
case rtype.COMPUTING.String():
|
|
targetArray = userWorkspace.Computing
|
|
case rtype.STORAGE.String():
|
|
targetArray = userWorkspace.Storage
|
|
case rtype.DATACENTER.String():
|
|
targetArray = userWorkspace.Datacenter
|
|
default:
|
|
message := "Rtype " + rType + " is not valid"
|
|
logs.Debug(message)
|
|
return errors.New(message)
|
|
}
|
|
|
|
if ok := contains(targetArray, rID); ok {
|
|
// Element already registered
|
|
message := "Resource " + rID + " of type " + rType +
|
|
" is already registered for user " + userID
|
|
logs.Debug(message)
|
|
return errors.New(message)
|
|
}
|
|
|
|
// New element
|
|
// userWorkspace.ResourceList[rID] = rType
|
|
_, err := services.MngoCollWorkspace.UpdateOne(services.MngoCtx,
|
|
primitive.M{"_id": userID},
|
|
primitive.M{"$push": primitive.M{rType: rIDObj}},
|
|
)
|
|
|
|
if err != nil {
|
|
message := "Internal error when updating in DB"
|
|
logs.Debug(message + "; " + err.Error())
|
|
return errors.New(message)
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
return errors.New("Internal error")
|
|
}
|
|
|
|
func rTypeToCollection(rType string) (*mongo.Collection, error) {
|
|
switch rType {
|
|
case rtype.DATA.String():
|
|
return services.MngoCollData, nil
|
|
case rtype.COMPUTING.String():
|
|
return services.MngoCollComputing, nil
|
|
case rtype.DATACENTER.String():
|
|
return services.MngoCollDatacenter, nil
|
|
case rtype.STORAGE.String():
|
|
return services.MngoCollStorage, nil
|
|
}
|
|
|
|
message := rType + " is not a valid resource type"
|
|
logs.Debug(message)
|
|
|
|
return nil, errors.New(message)
|
|
}
|
|
|
|
func IsValidResource(rID, rType string) (*primitive.ObjectID, error) {
|
|
|
|
targetColl, err := rTypeToCollection(rType)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rIDObj, err := primitive.ObjectIDFromHex(rID)
|
|
|
|
if err != nil {
|
|
message := "ID " + rID + " is not valid"
|
|
logs.Debug(message + "; " + err.Error())
|
|
return nil, errors.New(message)
|
|
}
|
|
|
|
result := targetColl.FindOne(services.MngoCtx, primitive.M{"_id": rIDObj})
|
|
|
|
if result.Err() != nil {
|
|
message := "ID " + rID + " doesn't exist for resource type " + rType
|
|
logs.Debug(message + "; " + result.Err().Error())
|
|
return nil, errors.New(message)
|
|
}
|
|
|
|
return &rIDObj, nil
|
|
}
|
|
|
|
func GetAllWorkspaces() <-chan *Workspace {
|
|
ch := make(chan *Workspace)
|
|
go func() {
|
|
cursor, err := services.MngoCollWorkspace.Find(services.MngoCtx, primitive.M{})
|
|
if err != nil {
|
|
logs.Error(cursor.Err())
|
|
close(ch)
|
|
}
|
|
|
|
for cursor.Next(services.MngoCtx) {
|
|
var item Workspace
|
|
if err = cursor.Decode(&item); err != nil {
|
|
logs.Error(err)
|
|
close(ch)
|
|
}
|
|
ch <- &item
|
|
}
|
|
close(ch) // Remember to close or the loop never ends!
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func (w *Workspace) GetAllWorkspacesProjects() <-chan *Workflow {
|
|
ch := make(chan *Workflow)
|
|
go func() {
|
|
for _, wproj := range w.Workflows {
|
|
ch <- &wproj
|
|
}
|
|
close(ch)
|
|
}()
|
|
return ch
|
|
}
|
|
|
|
func GetWorkspace(userID string) (retObj *Workspace) {
|
|
|
|
if err := services.MngoCollWorkspace.FindOne(services.MngoCtx, primitive.M{"_id": userID}).Decode(&retObj); err != nil {
|
|
logs.Error(err.Error())
|
|
return nil
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func NewWorkspace(userID string) (*Workspace, error) {
|
|
|
|
newWsp := &Workspace{
|
|
UserID: userID,
|
|
Data: []string{},
|
|
Computing: []string{},
|
|
Datacenter: []string{},
|
|
Storage: []string{},
|
|
}
|
|
|
|
_, err := services.MngoCollWorkspace.InsertOne(services.MngoCtx, newWsp)
|
|
if err != nil {
|
|
logs.Warning(err.Error())
|
|
return nil, err
|
|
}
|
|
|
|
return newWsp, nil
|
|
|
|
}
|