Created mongo interface and refactored the database operations [This is preparation to create mock interfaces for unit testing] (#2746)

* added mongo interface; created addtional file for switching between the collections and one for all db CRUD operations

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* modified usermanagement and projects with the new mongo structure; made logging and errors and comments consistent

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* added the changes for workflow db operations

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* added the changes for myHub db operations

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* added the changes for gitops db operations

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* minor changes for gitops db operations

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* added the changes for cluster db operations

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* added the changes for analytics db operations and added comments to the operations.go file

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* calling the initialize function and instantiating the mongo client

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>

* import order fixed

Signed-off-by: arkajyotiMukherjee <arko@chaosnative.com>
This commit is contained in:
Arkajyoti Mukherjee 2021-05-07 22:57:49 +05:30 committed by GitHub
parent 59db04e1b1
commit 91fd200783
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 714 additions and 341 deletions

View File

@ -135,12 +135,14 @@ func UpdateDataSource(datasource model.DSInput) (*model.DSResponse, error) {
query := bson.D{{"ds_id", datasource.DsID}}
update := bson.D{{"$set", bson.D{{"ds_name", datasource.DsName},
update := bson.D{{"$set", bson.D{
{"ds_name", datasource.DsName},
{"ds_url", datasource.DsURL}, {"access_type", datasource.AccessType},
{"auth_type", datasource.AuthType}, {"basic_auth_username", datasource.BasicAuthUsername},
{"basic_auth_password", datasource.BasicAuthPassword}, {"scrape_interval", datasource.ScrapeInterval},
{"query_timeout", datasource.QueryTimeout}, {"http_method", datasource.HTTPMethod},
{"updated_at", timestamp}}}}
{"updated_at", timestamp},
}}}
err := dbOperationsAnalytics.UpdateDataSource(query, update)
if err != nil {
@ -219,14 +221,20 @@ func UpdatePanel(panels []*model.Panel) (string, error) {
func DeleteDashboard(db_id *string) (bool, error) {
dashboardQuery := bson.M{"db_id": db_id, "is_removed": false}
dashboardQuery := bson.D{
{"db_id", db_id},
{"is_removed", false},
}
dashboard, err := dbOperationsAnalytics.GetDashboard(dashboardQuery)
if err != nil {
return false, fmt.Errorf("failed to list dashboard, error: %v", err)
}
for _, panelGroup := range dashboard.PanelGroups {
listPanelQuery := bson.M{"panel_group_id": panelGroup.PanelGroupID, "is_removed": false}
listPanelQuery := bson.D{
{"panel_group_id", panelGroup.PanelGroupID},
{"is_removed", false},
}
panels, err := dbOperationsAnalytics.ListPanel(listPanelQuery)
if err != nil {
return false, fmt.Errorf("failed to list Panel, error: %v", err)
@ -235,8 +243,14 @@ func DeleteDashboard(db_id *string) (bool, error) {
for _, panel := range panels {
time := strconv.FormatInt(time.Now().Unix(), 10)
query := bson.D{{"panel_id", panel.PanelID}, {"is_removed", false}}
update := bson.D{{"$set", bson.D{{"is_removed", true}, {"updated_at", time}}}}
query := bson.D{
{"panel_id", panel.PanelID},
{"is_removed", false},
}
update := bson.D{{"$set", bson.D{
{"is_removed", true},
{"updated_at", time},
}}}
err := dbOperationsAnalytics.UpdatePanel(query, update)
if err != nil {
@ -248,7 +262,10 @@ func DeleteDashboard(db_id *string) (bool, error) {
time := strconv.FormatInt(time.Now().Unix(), 10)
query := bson.D{{"db_id", db_id}}
update := bson.D{{"$set", bson.D{{"is_removed", true}, {"updated_at", time}}}}
update := bson.D{{"$set", bson.D{
{"is_removed", true},
{"updated_at", time},
}}}
err = dbOperationsAnalytics.UpdateDashboard(query, update)
if err != nil {
@ -262,7 +279,10 @@ func DeleteDataSource(input model.DeleteDSInput) (bool, error) {
time := strconv.FormatInt(time.Now().Unix(), 10)
listDBQuery := bson.M{"ds_id": input.DsID, "is_removed": false}
listDBQuery := bson.D{
{"ds_id", input.DsID},
{"is_removed", false},
}
dashboards, err := dbOperationsAnalytics.ListDashboard(listDBQuery)
if err != nil {
return false, fmt.Errorf("failed to list dashboard, error: %v", err)
@ -272,15 +292,24 @@ func DeleteDataSource(input model.DeleteDSInput) (bool, error) {
for _, dashboard := range dashboards {
for _, panelGroup := range dashboard.PanelGroups {
listPanelQuery := bson.M{"panel_group_id": panelGroup.PanelGroupID, "is_removed": false}
listPanelQuery := bson.D{
{"panel_group_id", panelGroup.PanelGroupID},
{"is_removed", false},
}
panels, err := dbOperationsAnalytics.ListPanel(listPanelQuery)
if err != nil {
return false, fmt.Errorf("failed to list Panel, error: %v", err)
}
for _, panel := range panels {
query := bson.D{{"panel_id", panel.PanelID}, {"is_removed", false}}
update := bson.D{{"$set", bson.D{{"is_removed", true}, {"updated_at", time}}}}
query := bson.D{
{"panel_id", panel.PanelID},
{"is_removed", false},
}
update := bson.D{{"$set", bson.D{
{"is_removed", true},
{"updated_at", time},
}}}
err := dbOperationsAnalytics.UpdatePanel(query, update)
if err != nil {
@ -289,7 +318,10 @@ func DeleteDataSource(input model.DeleteDSInput) (bool, error) {
}
}
updateDBQuery := bson.D{{"db_id", dashboard.DbID}}
update := bson.D{{"$set", bson.D{{"is_removed", true}, {"updated_at", time}}}}
update := bson.D{{"$set", bson.D{
{"is_removed", true},
{"updated_at", time},
}}}
err = dbOperationsAnalytics.UpdateDashboard(updateDBQuery, update)
if err != nil {
@ -298,16 +330,19 @@ func DeleteDataSource(input model.DeleteDSInput) (bool, error) {
}
} else if len(dashboards) > 0 {
var db_names []string
var dbNames []string
for _, dashboard := range dashboards {
db_names = append(db_names, dashboard.DbName)
dbNames = append(dbNames, dashboard.DbName)
}
return false, fmt.Errorf("failed to delete datasource, dashboard(s) are attached to the datasource: %v", db_names)
return false, fmt.Errorf("failed to delete datasource, dashboard(s) are attached to the datasource: %v", dbNames)
}
updateDSQuery := bson.D{{"ds_id", input.DsID}}
update := bson.D{{"$set", bson.D{{"is_removed", true}, {"updated_at", time}}}}
update := bson.D{{"$set", bson.D{
{"is_removed", true},
{"updated_at", time},
}}}
err = dbOperationsAnalytics.UpdateDataSource(updateDSQuery, update)
if err != nil {
@ -318,7 +353,10 @@ func DeleteDataSource(input model.DeleteDSInput) (bool, error) {
}
func QueryListDataSource(projectID string) ([]*model.DSResponse, error) {
query := bson.M{"project_id": projectID, "is_removed": false}
query := bson.D{
{"project_id", projectID},
{"is_removed", false},
}
datasource, err := dbOperationsAnalytics.ListDataSource(query)
if err != nil {
@ -359,7 +397,10 @@ func GetPromQuery(promInput *model.PromInput) ([]*model.PromResponse, error) {
}
func QueryListDashboard(projectID string) ([]*model.ListDashboardReponse, error) {
query := bson.M{"project_id": projectID, "is_removed": false}
query := bson.D{
{"project_id", projectID},
{"is_removed", false},
}
dashboards, err := dbOperationsAnalytics.ListDashboard(query)
if err != nil {
@ -386,7 +427,10 @@ func QueryListDashboard(projectID string) ([]*model.ListDashboardReponse, error)
dashboard.ClusterName = &cluster.ClusterName
for _, panelgroup := range dashboard.PanelGroups {
query := bson.M{"panel_group_id": panelgroup.PanelGroupID, "is_removed": false}
query := bson.D{
{"panel_group_id", panelgroup.PanelGroupID},
{"is_removed", false},
}
panels, err := dbOperationsAnalytics.ListPanel(query)
if err != nil {
return nil, fmt.Errorf("error on querying from promquery collection", err)

View File

@ -5,30 +5,19 @@ import (
"errors"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
"go.mongodb.org/mongo-driver/bson"
)
var (
dataSourceCollection *mongo.Collection
panelCollection *mongo.Collection
dashBoardCollection *mongo.Collection
backgroundContext = context.Background()
backgroundContext = context.Background()
)
func init() {
dataSourceCollection = mongodb.Database.Collection("datasource-collection")
panelCollection = mongodb.Database.Collection("panel-collection")
dashBoardCollection = mongodb.Database.Collection("dashboard-collection")
}
// InsertDataSource takes details of a data source and inserts into the database collection
func InsertDataSource(datasource DataSource) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := dataSourceCollection.InsertOne(ctx, datasource)
err := mongodb.Operator.Create(ctx, mongodb.DataSourceCollection, datasource)
if err != nil {
return err
}
@ -40,7 +29,7 @@ func InsertDataSource(datasource DataSource) error {
func InsertDashBoard(dashboard DashBoard) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := dashBoardCollection.InsertOne(ctx, dashboard)
err := mongodb.Operator.Create(ctx, mongodb.DashboardCollection, dashboard)
if err != nil {
return err
}
@ -52,12 +41,12 @@ func InsertDashBoard(dashboard DashBoard) error {
func InsertPanel(panels []*Panel) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var newInterface []interface{}
var panelList []interface{}
for _, panel := range panels {
newInterface = append(newInterface, panel)
panelList = append(panelList, panel)
}
_, err := panelCollection.InsertMany(ctx, newInterface)
err := mongodb.Operator.CreateMany(ctx, mongodb.PanelCollection, panelList)
if err != nil {
return err
}
@ -66,34 +55,34 @@ func InsertPanel(panels []*Panel) error {
}
// ListDataSource takes a query parameter to retrieve the data source details from the database
func ListDataSource(query bson.M) ([]*DataSource, error) {
func ListDataSource(query bson.D) ([]*DataSource, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var datasources []*DataSource
cursor, err := dataSourceCollection.Find(ctx, query)
var dataSources []*DataSource
results, err := mongodb.Operator.List(ctx, mongodb.DataSourceCollection, query)
if err != nil {
return []*DataSource{}, err
}
err = cursor.All(ctx, &datasources)
err = results.All(ctx, &dataSources)
if err != nil {
return []*DataSource{}, err
}
return datasources, nil
return dataSources, nil
}
// ListDashboard takes a query parameter to retrieve the dashboard details from the database
func ListDashboard(query bson.M) ([]*DashBoard, error) {
func ListDashboard(query bson.D) ([]*DashBoard, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var dashboards []*DashBoard
cursor, err := dashBoardCollection.Find(ctx, query)
results, err := mongodb.Operator.List(ctx, mongodb.DashboardCollection, query)
if err != nil {
return []*DashBoard{}, err
}
err = cursor.All(ctx, &dashboards)
err = results.All(ctx, &dashboards)
if err != nil {
return []*DashBoard{}, err
}
@ -102,16 +91,16 @@ func ListDashboard(query bson.M) ([]*DashBoard, error) {
}
// ListPanel takes a query parameter to retrieve the dashboard panel details from the database
func ListPanel(query bson.M) ([]*Panel, error) {
func ListPanel(query bson.D) ([]*Panel, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var panels []*Panel
cursor, err := panelCollection.Find(ctx, query)
results, err := mongodb.Operator.List(ctx, mongodb.PanelCollection, query)
if err != nil {
return []*Panel{}, err
}
err = cursor.All(ctx, &panels)
err = results.All(ctx, &panels)
if err != nil {
return []*Panel{}, err
}
@ -122,10 +111,11 @@ func ListPanel(query bson.M) ([]*Panel, error) {
// GetDataSourceByID takes a dsID parameter to retrieve the data source details from the database
func GetDataSourceByID(dsID string) (*DataSource, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
query := bson.M{"ds_id": dsID}
query := bson.D{{"ds_id", dsID}}
var datasource *DataSource
err := dataSourceCollection.FindOne(ctx, query).Decode(&datasource)
results, err := mongodb.Operator.Get(ctx, mongodb.DataSourceCollection, query)
err = results.Decode(&datasource)
if err != nil {
return nil, err
}
@ -137,7 +127,7 @@ func GetDataSourceByID(dsID string) (*DataSource, error) {
func UpdateDataSource(query bson.D, update bson.D) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := dataSourceCollection.UpdateOne(ctx, query, update)
_, err := mongodb.Operator.Update(ctx, mongodb.DataSourceCollection, query, update)
if err != nil {
return err
}
@ -149,7 +139,7 @@ func UpdateDataSource(query bson.D, update bson.D) error {
func UpdateDashboard(query bson.D, update bson.D) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := dashBoardCollection.UpdateOne(ctx, query, update)
_, err := mongodb.Operator.Update(ctx, mongodb.DashboardCollection, query, update)
if err != nil {
return err
}
@ -161,24 +151,25 @@ func UpdateDashboard(query bson.D, update bson.D) error {
func UpdatePanel(query bson.D, update bson.D) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
updateResult, err := panelCollection.UpdateOne(ctx, query, update)
updateResult, err := mongodb.Operator.Update(ctx, mongodb.PanelCollection, query, update)
if err != nil {
return err
}
if updateResult.MatchedCount == 0 {
return errors.New("Panel collection query didn't matched")
return errors.New("panel collection query didn't matched")
}
return nil
}
// GetDashboard takes a query parameter to retrieve the dashboard details from the database
func GetDashboard(query bson.M) (DashBoard, error) {
func GetDashboard(query bson.D) (DashBoard, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var dashboard DashBoard
err := dashBoardCollection.FindOne(ctx, query).Decode(&dashboard)
result, err := mongodb.Operator.Get(ctx, mongodb.DashboardCollection, query)
err = result.Decode(&dashboard)
if err != nil {
return DashBoard{}, err
}

View File

@ -4,26 +4,18 @@ import (
"context"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
"go.mongodb.org/mongo-driver/bson"
)
var (
clusterCollection *mongo.Collection
backgroundContext = context.Background()
err error
)
func init() {
clusterCollection = mongodb.Database.Collection("cluster-collection")
}
// InsertCluster takes details of a cluster and inserts into the database collection
func InsertCluster(cluster Cluster) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := clusterCollection.InsertOne(ctx, cluster)
err := mongodb.Operator.Create(ctx, mongodb.ClusterCollection, cluster)
if err != nil {
return err
}
@ -34,10 +26,11 @@ func InsertCluster(cluster Cluster) error {
// GetCluster takes a clusterID to retrieve the cluster details from the database
func GetCluster(clusterID string) (Cluster, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
query := bson.M{"cluster_id": clusterID}
query := bson.D{{"cluster_id", clusterID}}
var cluster Cluster
err = clusterCollection.FindOne(ctx, query).Decode(&cluster)
result, err := mongodb.Operator.Get(ctx, mongodb.ClusterCollection, query)
err = result.Decode(&cluster)
if err != nil {
return Cluster{}, err
}
@ -49,7 +42,7 @@ func GetCluster(clusterID string) (Cluster, error) {
func UpdateCluster(query bson.D, update bson.D) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := clusterCollection.UpdateOne(ctx, query, update)
_, err := mongodb.Operator.Update(ctx, mongodb.ClusterCollection, query, update)
if err != nil {
return err
}
@ -60,22 +53,29 @@ func UpdateCluster(query bson.D, update bson.D) error {
// GetClusterWithProjectID takes projectID and clusterType parameters to retrieve the cluster details from the database
func GetClusterWithProjectID(projectID string, clusterType *string) ([]*Cluster, error) {
var query bson.M
var query bson.D
if clusterType == nil {
query = bson.M{"project_id": projectID, "is_removed": false}
query = bson.D{
{"project_id", projectID},
{"is_removed", false},
}
} else {
query = bson.M{"project_id": projectID, "cluster_type": clusterType, "is_removed": false}
query = bson.D{
{"project_id", projectID},
{"cluster_type", clusterType},
{"is_removed", false},
}
}
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var clusters []*Cluster
cursor, err := clusterCollection.Find(ctx, query)
results, err := mongodb.Operator.List(ctx, mongodb.ClusterCollection, query)
if err != nil {
return []*Cluster{}, err
}
err = cursor.All(ctx, &clusters)
err = results.All(ctx, &clusters)
if err != nil {
return []*Cluster{}, err
}

View File

@ -0,0 +1,46 @@
package mongodb
import (
"errors"
"go.mongodb.org/mongo-driver/mongo"
)
type GetCollectionInterface interface {
getCollection(collectionType int) (*mongo.Collection, error)
}
type GetCollectionStruct struct{}
var (
GetCollectionClient GetCollectionInterface = &GetCollectionStruct{}
)
// getCollection function returns the appropriate DB collection based on the collection value passed
func (g *GetCollectionStruct) getCollection(collectionType int) (*mongo.Collection, error) {
mongoClient := Client
switch collectionType {
case ClusterCollection:
return mongoClient.(*MongoClient).ClusterCollection, nil
case UserCollection:
return mongoClient.(*MongoClient).UserCollection, nil
case ProjectCollection:
return mongoClient.(*MongoClient).ProjectCollection, nil
case WorkflowCollection:
return mongoClient.(*MongoClient).WorkflowCollection, nil
case WorkflowTemplateCollection:
return mongoClient.(*MongoClient).WorkflowTemplateCollection, nil
case GitOpsCollection:
return mongoClient.(*MongoClient).GitOpsCollection, nil
case MyHubCollection:
return mongoClient.(*MongoClient).MyHubCollection, nil
case DataSourceCollection:
return mongoClient.(*MongoClient).DataSourceCollection, nil
case PanelCollection:
return mongoClient.(*MongoClient).PanelCollection, nil
case DashboardCollection:
return mongoClient.(*MongoClient).DashboardCollection, nil
default:
return nil, errors.New("unknown collection name")
}
}

View File

@ -3,41 +3,15 @@ package gitops
import (
"context"
"errors"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
var (
gitOpsCollection *mongo.Collection
backgroundContext = context.Background()
)
const timeout = 15 * time.Second
func init() {
gitOpsCollection = mongodb.Database.Collection("gitops-collection")
_, err := gitOpsCollection.Indexes().CreateMany(backgroundContext, []mongo.IndexModel{
{
Keys: bson.M{
"project_id": 1,
},
Options: options.Index().SetUnique(true),
},
})
if err != nil {
log.Fatal("Error Creating Index for GitOps Collection : ", err)
}
}
// AddGitConfig inserts new git config for project
func AddGitConfig(ctx context.Context, config *GitConfigDB) error {
_, err := gitOpsCollection.InsertOne(ctx, config)
err := mongodb.Operator.Create(ctx, mongodb.GitOpsCollection, config)
if err != nil {
return err
}
@ -46,9 +20,10 @@ func AddGitConfig(ctx context.Context, config *GitConfigDB) error {
// GetGitConfig retrieves git config using project id
func GetGitConfig(ctx context.Context, projectID string) (*GitConfigDB, error) {
query := bson.M{"project_id": projectID}
query := bson.D{{"project_id", projectID}}
var res GitConfigDB
err := gitOpsCollection.FindOne(ctx, query).Decode(&res)
result, err := mongodb.Operator.Get(ctx, mongodb.GitOpsCollection, query)
err = result.Decode(&res)
if err != nil {
if err == mongo.ErrNoDocuments {
return nil, nil
@ -62,12 +37,12 @@ func GetGitConfig(ctx context.Context, projectID string) (*GitConfigDB, error) {
// GetAllGitConfig retrieves all git configs from db
func GetAllGitConfig(ctx context.Context) ([]GitConfigDB, error) {
query := bson.D{{}}
cursor, err := gitOpsCollection.Find(ctx, query)
results, err := mongodb.Operator.List(ctx, mongodb.GitOpsCollection, query)
if err != nil {
return nil, err
}
var configs []GitConfigDB
err = cursor.All(ctx, &configs)
err = results.All(ctx, &configs)
if err != nil {
return nil, err
}
@ -76,7 +51,7 @@ func GetAllGitConfig(ctx context.Context) ([]GitConfigDB, error) {
// ReplaceGitConfig updates git config matching the query
func ReplaceGitConfig(ctx context.Context, query bson.D, update *GitConfigDB) error {
updateResult, err := gitOpsCollection.ReplaceOne(ctx, query, update)
updateResult, err := mongodb.Operator.Replace(ctx, mongodb.GitOpsCollection, query, update)
if err != nil {
return err
}
@ -90,7 +65,7 @@ func ReplaceGitConfig(ctx context.Context, query bson.D, update *GitConfigDB) er
// UpdateGitConfig update git config matching the query
func UpdateGitConfig(ctx context.Context, query bson.D, update bson.D) error {
updateResult, err := gitOpsCollection.UpdateOne(ctx, query, update)
updateResult, err := mongodb.Operator.Update(ctx, mongodb.GitOpsCollection, query, update)
if err != nil {
return err
}
@ -104,7 +79,8 @@ func UpdateGitConfig(ctx context.Context, query bson.D, update bson.D) error {
// DeleteGitConfig removes git config corresponding to the given project id
func DeleteGitConfig(ctx context.Context, projectID string) error {
_, err := gitOpsCollection.DeleteOne(ctx, bson.M{"project_id": projectID})
query := bson.D{{"project_id", projectID}}
_, err := mongodb.Operator.Delete(ctx, mongodb.GitOpsCollection, query)
if err != nil {
return err

View File

@ -6,35 +6,83 @@ import (
"os"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var (
// Database ...
Database *mongo.Database
dbName = "litmus"
backgroundContext = context.Background()
err error
// Enum for Database collections
const (
ClusterCollection = iota
UserCollection
ProjectCollection
WorkflowCollection
WorkflowTemplateCollection
GitOpsCollection
MyHubCollection
DataSourceCollection
PanelCollection
DashboardCollection
)
// init initializes database connection
func init() {
// MongoInterface requires a MongoClient that implements the Initialize method to create the Mongo DB client
// and a initAllCollection method to initialize all DB Collections
type MongoInterface interface {
Initialize() *MongoClient
initAllCollection()
}
// MongoClient structure contains all the Database collections and the instance of the Database
type MongoClient struct {
Database *mongo.Database
ClusterCollection *mongo.Collection
UserCollection *mongo.Collection
ProjectCollection *mongo.Collection
WorkflowCollection *mongo.Collection
WorkflowTemplateCollection *mongo.Collection
GitOpsCollection *mongo.Collection
MyHubCollection *mongo.Collection
DataSourceCollection *mongo.Collection
PanelCollection *mongo.Collection
DashboardCollection *mongo.Collection
}
var (
Client MongoInterface = &MongoClient{}
collections = map[int]string{
ClusterCollection: "cluster-collection",
UserCollection: "user",
ProjectCollection: "project",
WorkflowCollection: "workflow-collection",
WorkflowTemplateCollection: "workflow-template",
GitOpsCollection: "gitops-collection",
MyHubCollection: "myhub",
DataSourceCollection: "datasource-collection",
PanelCollection: "panel-collection",
DashboardCollection: "dashboard-collection",
}
dbName = "litmus"
ConnectionTimeout = 20 * time.Second
backgroundContext = context.Background()
)
// Initialize initializes database connection
func (m *MongoClient) Initialize() *MongoClient {
var (
dbServer = os.Getenv("DB_SERVER")
username = os.Getenv("DB_USER")
pwd = os.Getenv("DB_PASSWORD")
dbServer = os.Getenv("DB_SERVER")
dbUser = os.Getenv("DB_USER")
dbPassword = os.Getenv("DB_PASSWORD")
)
if dbServer == "" || username == "" || pwd == "" {
if dbServer == "" || dbUser == "" || dbPassword == "" {
log.Fatal("DB configuration failed")
}
credential := options.Credential{
Username: username,
Password: pwd,
Username: dbUser,
Password: dbPassword,
}
clientOptions := options.Client().ApplyURI(dbServer).SetAuth(credential)
@ -43,7 +91,7 @@ func init() {
log.Fatal(err)
}
ctx, _ := context.WithTimeout(backgroundContext, 20*time.Second)
ctx, _ := context.WithTimeout(backgroundContext, ConnectionTimeout)
// Check the connection
err = client.Ping(ctx, nil)
@ -53,5 +101,52 @@ func init() {
log.Print("Connected To MONGODB")
}
Database = client.Database(dbName)
m.Database = client.Database(dbName)
m.initAllCollection()
return m
}
// initAllCollection initializes all the database collections
func (m *MongoClient) initAllCollection() {
m.ClusterCollection = m.Database.Collection(collections[ClusterCollection])
m.UserCollection = m.Database.Collection(collections[UserCollection])
m.ProjectCollection = m.Database.Collection(collections[ProjectCollection])
m.WorkflowCollection = m.Database.Collection(collections[WorkflowCollection])
_, err := m.WorkflowCollection.Indexes().CreateMany(backgroundContext, []mongo.IndexModel{
{
Keys: bson.M{
"workflow_id": 1,
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.M{
"workflow_name": 1,
},
Options: options.Index().SetUnique(true),
},
})
if err != nil {
log.Fatal("Error Creating Index for Workflow Collection: ", err)
}
m.WorkflowTemplateCollection = m.Database.Collection(collections[WorkflowTemplateCollection])
m.GitOpsCollection = m.Database.Collection(collections[GitOpsCollection])
_, err = m.GitOpsCollection.Indexes().CreateMany(backgroundContext, []mongo.IndexModel{
{
Keys: bson.M{
"project_id": 1,
},
Options: options.Index().SetUnique(true),
},
})
if err != nil {
log.Fatal("Error Creating Index for GitOps Collection : ", err)
}
m.MyHubCollection = m.Database.Collection(collections[MyHubCollection])
m.DataSourceCollection = m.Database.Collection(collections[DataSourceCollection])
m.PanelCollection = m.Database.Collection(collections[PanelCollection])
m.DashboardCollection = m.Database.Collection(collections[DashboardCollection])
}

View File

@ -5,21 +5,13 @@ import (
"errors"
"log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
"go.mongodb.org/mongo-driver/bson"
)
var myhubCollection *mongo.Collection
func init() {
myhubCollection = mongodb.Database.Collection("myhub")
}
// CreateMyHub ...
// CreateMyHub creates a private chaosHub for the user in the database
func CreateMyHub(ctx context.Context, myhub *MyHub) error {
_, err := myhubCollection.InsertOne(ctx, myhub)
err := mongodb.Operator.Create(ctx, mongodb.MyHubCollection, myhub)
if err != nil {
log.Print("Error creating MyHub: ", err)
return err
@ -27,45 +19,48 @@ func CreateMyHub(ctx context.Context, myhub *MyHub) error {
return nil
}
// GetMyHubByProjectID ...
// GetMyHubByProjectID returns a private Hub based on the projectID
func GetMyHubByProjectID(ctx context.Context, projectID string) ([]MyHub, error) {
query := bson.M{"project_id": projectID, "IsRemoved": false}
cursor, err := myhubCollection.Find(ctx, query)
query := bson.D{
{"project_id", projectID},
{"IsRemoved", false},
}
results, err := mongodb.Operator.List(ctx, mongodb.MyHubCollection, query)
if err != nil {
log.Print("ERROR GETTING USERS : ", err)
return []MyHub{}, err
}
var myhubs []MyHub
err = cursor.All(ctx, &myhubs)
var myHubs []MyHub
err = results.All(ctx, &myHubs)
if err != nil {
log.Print("Error deserializing myhubs in myhub object : ", err)
log.Print("Error deserializing myHubs in myHub object : ", err)
return []MyHub{}, err
}
return myhubs, nil
return myHubs, nil
}
// GetHubs ...
// GetHubs lists all the chaosHubs that are present
func GetHubs(ctx context.Context) ([]MyHub, error) {
// ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
query := bson.D{{}}
cursor, err := myhubCollection.Find(ctx, query)
results, err := mongodb.Operator.List(ctx, mongodb.MyHubCollection, query)
if err != nil {
log.Print("ERROR GETTING MYHUBS : ", err)
log.Print("Error getting myHubs: ", err)
return []MyHub{}, err
}
var MyHubs []MyHub
err = cursor.All(ctx, &MyHubs)
var myHubs []MyHub
err = results.All(ctx, &myHubs)
if err != nil {
log.Print("Error deserializing myhubs in the myhub object : ", err)
log.Print("Error deserializing myHubs in the myHub object: ", err)
return []MyHub{}, err
}
return MyHubs, nil
return myHubs, nil
}
// GetHubByID ...
// GetHubByID returns a single chaosHub based on the hubID
func GetHubByID(ctx context.Context, hubID string) (MyHub, error) {
var myHub MyHub
err := myhubCollection.FindOne(ctx, bson.M{"myhub_id": hubID}).Decode(&myHub)
result, err := mongodb.Operator.Get(ctx, mongodb.MyHubCollection, bson.D{{"myhub_id", hubID}})
err = result.Decode(&myHub)
if err != nil {
return MyHub{}, err
}
@ -73,9 +68,9 @@ func GetHubByID(ctx context.Context, hubID string) (MyHub, error) {
return myHub, nil
}
// UpdateMyHub ...
// UpdateMyHub updates the chaosHub
func UpdateMyHub(ctx context.Context, query bson.D, update bson.D) error {
updateResult, err := myhubCollection.UpdateOne(ctx, query, update)
updateResult, err := mongodb.Operator.Update(ctx, mongodb.MyHubCollection, query, update)
if err != nil {
return err
}

View File

@ -0,0 +1,177 @@
package mongodb
import (
"context"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type MongoOperator interface {
Create(ctx context.Context, collectionType int, document interface{}) error
CreateMany(ctx context.Context, collectionType int, documents []interface{}) error
Get(ctx context.Context, collectionType int, query bson.D) (*mongo.SingleResult, error)
List(ctx context.Context, collectionType int, query bson.D) (*mongo.Cursor, error)
Update(ctx context.Context, collectionType int, query, update bson.D,
opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)
UpdateMany(ctx context.Context, collectionType int, query, update bson.D,
opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)
Replace(ctx context.Context, collectionType int, query bson.D, replacement interface{}) (*mongo.UpdateResult, error)
Delete(ctx context.Context, collectionType int, query bson.D, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
CountDocuments(ctx context.Context, collectionType int, query bson.D, opts ...*options.CountOptions) (int64, error)
GetCollection(collectionType int) (*mongo.Collection, error)
}
type CollectionInterface interface {
InsertOne(ctx context.Context, document interface{},
opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
InsertMany(ctx context.Context, document interface{},
opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
FindOne(ctx context.Context, filter interface{},
opts ...*options.FindOneOptions) *mongo.SingleResult
Find(ctx context.Context, filter interface{},
opts ...*options.FindOptions) (*mongo.Cursor, error)
UpdateOne(ctx context.Context, filter interface{}, update interface{},
opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)
UpdateMany(ctx context.Context, filter interface{}, update interface{},
opts ...*options.UpdateOptions) (*mongo.UpdateResult, error)
ReplaceOne(ctx context.Context, filter interface{},
replacement interface{}, opts ...*options.ReplaceOptions) (*mongo.UpdateResult, error)
DeleteOne(ctx context.Context, filter interface{},
opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
CountDocuments(ctx context.Context, filter interface{}, opts ...*options.CountOptions) (int64, error)
}
type MongoOperations struct{}
var (
// Operator contains all the CRUD operations of the mongo database
Operator MongoOperator = &MongoOperations{}
)
// Create puts a document in the database
func (m *MongoOperations) Create(ctx context.Context, collectionType int, document interface{}) error {
collection, err := m.GetCollection(collectionType)
if err != nil {
return err
}
_, err = collection.InsertOne(ctx, document)
if err != nil {
return err
}
return nil
}
// CreateMany puts an array of documents in the database
func (m *MongoOperations) CreateMany(ctx context.Context, collectionType int, documents []interface{}) error {
collection, err := m.GetCollection(collectionType)
if err != nil {
return err
}
_, err = collection.InsertMany(ctx, documents)
if err != nil {
return err
}
return nil
}
// Get fetches a document from the database based on a query
func (m *MongoOperations) Get(ctx context.Context, collectionType int, query bson.D) (*mongo.SingleResult, error) {
collection, err := m.GetCollection(collectionType)
if err != nil {
return nil, err
}
result := collection.FindOne(ctx, query)
return result, nil
}
// List fetches a list of documents from the database based on a query
func (m *MongoOperations) List(ctx context.Context, collectionType int, query bson.D) (*mongo.Cursor, error) {
collection, err := m.GetCollection(collectionType)
if err != nil {
return nil, err
}
result, err := collection.Find(ctx, query)
if err != nil {
return nil, err
}
return result, nil
}
// Update updates a document in the database based on a query
func (m *MongoOperations) Update(ctx context.Context, collectionType int, query, update bson.D, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) {
var result *mongo.UpdateResult
collection, err := m.GetCollection(collectionType)
if err != nil {
return result, err
}
result, err = collection.UpdateOne(ctx, query, update, opts...)
if err != nil {
return result, err
}
return result, nil
}
// UpdateMany updates multiple documents in the database based on a query
func (m *MongoOperations) UpdateMany(ctx context.Context, collectionType int, query, update bson.D, opts ...*options.UpdateOptions) (*mongo.UpdateResult, error) {
var result *mongo.UpdateResult
collection, err := m.GetCollection(collectionType)
if err != nil {
return result, err
}
result, err = collection.UpdateMany(ctx, query, update, opts...)
if err != nil {
return result, err
}
return result, nil
}
// Replace changes a document with a new one in the database based on a query
func (m *MongoOperations) Replace(ctx context.Context, collectionType int, query bson.D, replacement interface{}) (*mongo.UpdateResult, error) {
var result *mongo.UpdateResult
collection, err := m.GetCollection(collectionType)
if err != nil {
return result, err
}
// If the given item is not present then insert.
opts := options.Replace().SetUpsert(true)
result, err = collection.ReplaceOne(ctx, query, replacement, opts)
if err != nil {
return result, err
}
return result, nil
}
// Delete removes a document from the database based on a query
func (m *MongoOperations) Delete(ctx context.Context, collectionType int, query bson.D, opts ...*options.DeleteOptions) (*mongo.DeleteResult, error) {
var result *mongo.DeleteResult
collection, err := m.GetCollection(collectionType)
if err != nil {
return result, err
}
result, err = collection.DeleteOne(ctx, query, opts...)
if err != nil {
return result, err
}
return result, nil
}
// CountDocuments returns the number of documents in the collection that matches a query
func (m *MongoOperations) CountDocuments(ctx context.Context, collectionType int, query bson.D, opts ...*options.CountOptions) (int64, error) {
var result int64 = 0
collection, err := m.GetCollection(collectionType)
if err != nil {
return result, err
}
result, err = collection.CountDocuments(ctx, query, opts...)
if err != nil {
return result, err
}
return result, nil
}
// GetCollection fetches the correct collection based on the collection type
func (m *MongoOperations) GetCollection(collectionType int) (*mongo.Collection, error) {
return GetCollectionClient.getCollection(collectionType)
}

View File

@ -2,59 +2,64 @@ package project
import (
"context"
"errors"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/graph/model"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
)
var projectCollection *mongo.Collection
func init() {
projectCollection = mongodb.Database.Collection("project")
}
// CreateProject ...
// CreateProject creates a new project for a user
func CreateProject(ctx context.Context, project *Project) error {
// ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := projectCollection.InsertOne(ctx, project)
err := mongodb.Operator.Create(ctx, mongodb.ProjectCollection, project)
if err != nil {
log.Print("Error creating Project: ", err)
log.Print("Error creating project: ", err)
return err
}
return nil
}
// GetProject ...
// GetProject returns a project based on a query or filter value
func GetProject(ctx context.Context, query bson.D) (*Project, error) {
// ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var project = new(Project)
err := projectCollection.FindOne(ctx, query).Decode(project)
result, err := mongodb.Operator.Get(ctx, mongodb.ProjectCollection, query)
if err != nil {
log.Print("Error getting project with query :", query)
log.Print("Error getting project with query: ", query, "\nError message: ", err)
return nil, err
}
err = result.Decode(project)
if err != nil {
log.Print("Error unmarshalling the result in project struct: ", err)
return nil, err
}
return project, err
}
// GetProjectsByUserID ...
// GetProjectsByUserID returns a project based on the userID
func GetProjectsByUserID(ctx context.Context, userID string) ([]Project, error) {
// ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
projects := []Project{}
query := bson.M{"members": bson.M{"$elemMatch": bson.M{"user_id": userID, "invitation": bson.M{"$ne": DeclinedInvitation}}}}
cursor, err := projectCollection.Find(ctx, query)
var projects []Project
query := bson.D{
{"members", bson.D{
{"$elemMatch", bson.D{
{"user_id", userID},
{"invitation", bson.D{
{"$ne", DeclinedInvitation},
}},
}},
}}}
result, err := mongodb.Operator.List(ctx, mongodb.ProjectCollection, query)
if err != nil {
log.Print("Error getting project with userID: ", userID, " error: ", err)
return nil, err
}
err = cursor.All(ctx, &projects)
err = result.All(ctx, &projects)
if err != nil {
log.Print("Error getting project with userID: ", userID, " error: ", err)
return nil, err
@ -63,70 +68,106 @@ func GetProjectsByUserID(ctx context.Context, userID string) ([]Project, error)
return projects, err
}
// AddMember ...
// AddMember adds a new member into the project whose projectID is passed
func AddMember(ctx context.Context, projectID string, member *Member) error {
query := bson.D{{"_id", projectID}}
update := bson.D{{"$push", bson.D{
{"members", member},
}}}
query := bson.M{"_id": projectID}
update := bson.M{"$push": bson.M{"members": member}}
_, err := projectCollection.UpdateOne(ctx, query, update)
result, err := mongodb.Operator.Update(ctx, mongodb.ProjectCollection, query, update)
if err != nil {
log.Print("Error updating project with projectID: ", projectID, " error: ", err)
log.Print("Error in adding a member to project with projectID: ", projectID, "\nError: ", err)
return err
}
if result.MatchedCount == 0 {
return errors.New("could not find matching projectID in database")
}
return nil
}
// RemoveInvitation :Removes member or cancels the invitation
// RemoveInvitation removes member or cancels the invitation
func RemoveInvitation(ctx context.Context, projectID string, userID string, invitation Invitation) error {
query := bson.M{"_id": projectID}
update := bson.M{"$pull": bson.M{"members": bson.M{"user_id": userID}}}
_, err := projectCollection.UpdateOne(ctx, query, update)
query := bson.D{{"_id", projectID}}
update := bson.D{
{"$pull", bson.D{
{"members", bson.D{
{"user_id", userID},
}},
}},
}
result, err := mongodb.Operator.Update(ctx, mongodb.ProjectCollection, query, update)
if err != nil {
if invitation == AcceptedInvitation {
log.Print("Error Removing the member with userID:", userID, "from project with project id: ", projectID, err)
log.Print("Error removing the member with userID: ", userID, " from the project", "\nError message: ", err)
return err
}
log.Print("Error Removing the invite with userID:", userID, "from project with project id: ", projectID, err)
log.Print("Error removing the invite with userID:", userID, " from the project", "\nError message: ", err)
return err
}
if result.MatchedCount == 0 {
return errors.New("could not find matching projectID in database")
}
return nil
}
// UpdateInvite :Updates the status of sent invitation
// UpdateInvite updates the status of sent invitation
func UpdateInvite(ctx context.Context, projectID, userID string, invitation Invitation, Role *model.MemberRole) error {
options := options.Update().SetArrayFilters(options.ArrayFilters{
opts := options.Update().SetArrayFilters(options.ArrayFilters{
Filters: []interface{}{
bson.M{"elem.user_id": userID},
bson.D{{"elem.user_id", userID}},
},
})
query := bson.M{"_id": projectID}
var update bson.M
query := bson.D{{"_id", projectID}}
var update bson.D
switch invitation {
case PendingInvitation:
update = bson.M{"$set": bson.M{"members.$[elem].invitation": invitation, "members.$[elem].role": Role}}
update = bson.D{
{"$set", bson.D{
{"members.$[elem].invitation", invitation},
{"members.$[elem].role", Role},
}}}
case DeclinedInvitation:
update = bson.M{"$set": bson.M{"members.$[elem].invitation": invitation}}
update = bson.D{
{"$set", bson.D{
{"members.$[elem].invitation", invitation},
}}}
case AcceptedInvitation:
update = bson.M{"$set": bson.M{"members.$[elem].invitation": invitation, "members.$[elem].joined_at": time.Now().Format(time.RFC1123Z)}}
update = bson.D{
{"$set", bson.D{
{"members.$[elem].invitation", invitation},
{"members.$[elem].joined_at", time.Now().Format(time.RFC1123Z)},
}}}
case ExitedProject:
update = bson.M{"$set": bson.M{"members.$[elem].invitation": invitation}}
update = bson.D{
{"$set", bson.D{
{"members.$[elem].invitation", invitation},
}}}
}
_, err := projectCollection.UpdateOne(ctx, query, update, options)
result, err := mongodb.Operator.Update(ctx, mongodb.ProjectCollection, query, update, opts)
if err != nil {
log.Print("Error updating project with projectID: ", projectID, " error: ", err)
return err
}
if result.MatchedCount == 0 {
return errors.New("could not find matching projectID in database")
}
return nil
}
// UpdateProjectName :Updates Name of the project
func UpdateProjectName(ctx context.Context, projectID string, projectName string) error {
query := bson.M{"_id": projectID}
update := bson.M{"$set": bson.M{"name": projectName}}
query := bson.D{{"_id", projectID}}
update := bson.D{{"$set", bson.M{"name": projectName}}}
_, err := projectCollection.UpdateOne(ctx, query, update)
_, err := mongodb.Operator.Update(ctx, mongodb.ProjectCollection, query, update)
if err != nil {
return err
}

View File

@ -2,7 +2,7 @@ package project
import "github.com/litmuschaos/litmus/litmus-portal/graphql-server/graph/model"
// Project ...
// Project contains the required fields to be stored in the database for a project
type Project struct {
ID string `bson:"_id"`
Name string `bson:"name"`
@ -13,7 +13,7 @@ type Project struct {
RemovedAt string `bson:"removed_at"`
}
// GetOutputProject ...
// GetOutputProject takes a Project struct as input and returns the graphQL model equivalent
func (project *Project) GetOutputProject() *model.Project {
return &model.Project{
@ -27,10 +27,10 @@ func (project *Project) GetOutputProject() *model.Project {
}
}
// GetOutputMembers ...
// GetOutputMembers takes a Project struct as input and returns the graphQL model equivalent for a members of the project
func (project *Project) GetOutputMembers() []*model.Member {
outputMembers := []*model.Member{}
var outputMembers []*model.Member
for _, member := range project.Members {
outputMembers = append(outputMembers, member.GetOutputMember())
@ -39,7 +39,7 @@ func (project *Project) GetOutputMembers() []*model.Member {
return outputMembers
}
// Member ...
// Member contains the required fields to be stored in the database for a member
type Member struct {
UserID string `bson:"user_id"`
UserName string `bson:"username"`
@ -50,7 +50,7 @@ type Member struct {
JoinedAt string `bson:"joined_at"`
}
// GetOutputMember ...
// GetOutputMember takes a Member struct as input and returns the graphQL model equivalent
func (member *Member) GetOutputMember() *model.Member {
return &model.Member{
@ -64,19 +64,19 @@ func (member *Member) GetOutputMember() *model.Member {
}
}
// Invitation ...
// Invitation defines the type of the invitation that is sent by the Owner of the project to other users
type Invitation string
const (
// PendingInvitation ...
// PendingInvitation is the state when the Invitation is sent but not accepted
PendingInvitation Invitation = "Pending"
// AcceptedInvitation ...
// AcceptedInvitation is the state when the Invitation is sent and is accepted as well
AcceptedInvitation Invitation = "Accepted"
// DeclinedInvitation ...
// DeclinedInvitation is the state when the Invitation is sent but it is rejected/declined
DeclinedInvitation Invitation = "Declined"
//ExitedProject ...
//ExitedProject is the state when the user has exited the project
ExitedProject Invitation = "Exited"
)

View File

@ -5,26 +5,14 @@ import (
"log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
)
var (
userCollection *mongo.Collection
projectCollection *mongo.Collection
)
func init() {
userCollection = mongodb.Database.Collection("user")
projectCollection = mongodb.Database.Collection("project")
}
// InsertUser ...
func InsertUser(ctx context.Context, user *User) error {
// ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := userCollection.InsertOne(ctx, user)
// CreateUser inserts a new user to the database
func CreateUser(ctx context.Context, user *User) error {
err := mongodb.Operator.Create(ctx, mongodb.UserCollection, user)
if err != nil {
log.Print("Error creating User : ", err)
return err
@ -33,74 +21,97 @@ func InsertUser(ctx context.Context, user *User) error {
return nil
}
// GetUserByUserName ...
// GetUserByUserName returns user details based on username
func GetUserByUserName(ctx context.Context, username string) (*User, error) {
// ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
var user = new(User)
query := bson.M{"username": username}
err := userCollection.FindOne(ctx, query).Decode(user)
query := bson.D{{"username", username}}
result, err := mongodb.Operator.Get(ctx, mongodb.UserCollection, query)
if err != nil {
log.Print("Error getting user with username: ", username, " error: ", err)
log.Print("Error getting user with username: ", username, "\nError message: ", err)
return nil, err
}
err = result.Decode(user)
if err != nil {
log.Print("Error unmarshalling the result in user struct: ", err)
return nil, err
}
return user, err
}
// GetUserByUserID :returns user details based on userID
// GetUserByUserID returns user details based on userID
func GetUserByUserID(ctx context.Context, userID string) (*User, error) {
var user = new(User)
query := bson.M{"_id": userID}
err := userCollection.FindOne(ctx, query).Decode(user)
query := bson.D{{"_id", userID}}
result, err := mongodb.Operator.Get(ctx, mongodb.UserCollection, query)
if err != nil {
log.Print("Error getting user with userID: ", userID, " error: ", err)
log.Print("Error getting user with userID: ", userID, "\nError message: ", err)
return nil, err
}
err = result.Decode(user)
if err != nil {
log.Print("Error unmarshalling the result in user struct ", err)
return nil, err
}
return user, err
}
// GetUsers ...
// GetUsers returns the list of users present in the project
func GetUsers(ctx context.Context) ([]User, error) {
// ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
query := bson.D{{}}
cursor, err := userCollection.Find(ctx, query)
result, err := mongodb.Operator.List(ctx, mongodb.UserCollection, query)
if err != nil {
log.Print("ERROR GETTING USERS : ", err)
log.Print("Error getting users : ", err)
return []User{}, err
}
var users []User
err = cursor.All(ctx, &users)
err = result.All(ctx, &users)
if err != nil {
log.Print("Error deserializing users in the user object : ", err)
log.Print("Error unmarshalling the result in users array: ", err)
return []User{}, err
}
return users, nil
}
// UpdateUser ...
// UpdateUser updates the details of user in both user and project DB collections
func UpdateUser(ctx context.Context, user *User) error {
filter := bson.M{"_id": user.ID}
update := bson.M{"$set": bson.M{"name": user.Name, "email": user.Email, "company_name": user.CompanyName, "updated_at": user.UpdatedAt}}
filter := bson.D{{"_id", user.ID}}
update := bson.D{
{"$set", bson.D{
{"name", user.Name},
{"email", user.Email},
{"company_name", user.CompanyName},
{"updated_at", user.UpdatedAt},
}},
}
result, err := userCollection.UpdateOne(ctx, filter, update)
if err != nil || result.ModifiedCount != 1 {
log.Print("Error updating User : ", err)
_, err := mongodb.Operator.Update(ctx, mongodb.UserCollection, filter, update)
if err != nil {
log.Print("Error updating user: ", err)
return err
}
opts := options.Update().SetArrayFilters(options.ArrayFilters{
Filters: []interface{}{
bson.M{"elem.user_id": user.ID},
bson.D{{"elem.user_id", user.ID}},
},
})
filter = bson.M{}
update = bson.M{"$set": bson.M{"members.$[elem].name": user.Name, "members.$[elem].email": user.Email, "members.$[elem].company_name": user.CompanyName}}
filter = bson.D{{}}
update = bson.D{
{"$set", bson.D{
{"members.$[elem].name", user.Name},
{"members.$[elem].email", user.Email},
{"members.$[elem].company_name", user.CompanyName},
}},
}
_, err = projectCollection.UpdateMany(ctx, filter, update, opts)
_, err = mongodb.Operator.UpdateMany(ctx, mongodb.ProjectCollection, filter, update, opts)
if err != nil {
log.Print("Error updating User in projects : ", err)
log.Print("Error updating user in projects : ", err)
return err
}

View File

@ -2,7 +2,7 @@ package usermanagement
import "github.com/litmuschaos/litmus/litmus-portal/graphql-server/graph/model"
// User ...
// User contains the required fields to be stored in the database for a user
type User struct {
ID string `bson:"_id"`
Username string `bson:"username"`
@ -17,7 +17,7 @@ type User struct {
RemovedAt string `bson:"removed_at"`
}
// GetOutputUser ...
// GetOutputUser takes a User struct as input and returns the graphQL model equivalent
func (user User) GetOutputUser() *model.User {
return &model.User{

View File

@ -3,70 +3,64 @@ package workflow
import (
"context"
"errors"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
"go.mongodb.org/mongo-driver/bson"
)
var (
workflowCollection *mongo.Collection
backgroundContext = context.Background()
backgroundContext = context.Background()
)
func init() {
workflowCollection = mongodb.Database.Collection("workflow-collection")
_, err := workflowCollection.Indexes().CreateMany(backgroundContext, []mongo.IndexModel{
{
Keys: bson.M{
"workflow_id": 1,
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.M{
"workflow_name": 1,
},
Options: options.Index().SetUnique(true),
},
})
if err != nil {
log.Fatal("Error Creating Index for Workflow Collection: ", err)
}
}
// UpdateWorkflowRun takes workflowID and wfRun parameters to update the workflow run details in the database
func UpdateWorkflowRun(workflowID string, wfRun ChaosWorkflowRun) (int, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
count, err := workflowCollection.CountDocuments(ctx, bson.M{"workflow_id": workflowID, "workflow_runs.workflow_run_id": wfRun.WorkflowRunID})
count, err := mongodb.Operator.CountDocuments(ctx, mongodb.WorkflowCollection, bson.D{
{"workflow_id", workflowID},
{"workflow_runs.workflow_run_id", wfRun.WorkflowRunID},
})
if err != nil {
return 0, err
}
updateCount := 1
if count == 0 {
filter := bson.M{"workflow_id": workflowID}
update := bson.M{"$push": bson.M{"workflow_runs": wfRun}}
updateResp, err := workflowCollection.UpdateOne(ctx, filter, update)
query := bson.D{{"workflow_id", workflowID}}
update := bson.D{
{"$push", bson.D{
{"workflow_runs", wfRun},
}}}
result, err := mongodb.Operator.Update(ctx, mongodb.WorkflowCollection, query, update)
if err != nil {
return 0, err
}
if updateResp.MatchedCount == 0 {
if result.MatchedCount == 0 {
return 0, errors.New("workflow not found")
}
} else if count == 1 {
filter := bson.M{"workflow_id": workflowID, "workflow_runs": bson.M{"$elemMatch": bson.M{"workflow_run_id": wfRun.WorkflowRunID, "completed": false}}}
update := bson.M{"$set": bson.M{"workflow_runs.$.last_updated": wfRun.LastUpdated, "workflow_runs.$.execution_data": wfRun.ExecutionData, "workflow_runs.$.completed": wfRun.Completed}}
updateResp, err := workflowCollection.UpdateOne(ctx, filter, update)
query := bson.D{
{"workflow_id", workflowID},
{"workflow_runs", bson.D{
{"$elemMatch", bson.D{
{"workflow_run_id", wfRun.WorkflowRunID},
{"completed", false},
}},
}}}
update := bson.D{
{"$set", bson.D{
{"workflow_runs.$.last_updated", wfRun.LastUpdated},
{"workflow_runs.$.execution_data", wfRun.ExecutionData},
{"workflow_runs.$.completed", wfRun.Completed},
}}}
result, err := mongodb.Operator.Update(ctx, mongodb.WorkflowCollection, query, update)
if err != nil {
return 0, err
}
updateCount = int(updateResp.MatchedCount)
updateCount = int(result.MatchedCount)
}
return updateCount, nil
@ -76,13 +70,13 @@ func UpdateWorkflowRun(workflowID string, wfRun ChaosWorkflowRun) (int, error) {
func GetWorkflows(query bson.D) ([]ChaosWorkFlowInput, error) {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
cursor, err := workflowCollection.Find(ctx, query)
results, err := mongodb.Operator.List(ctx, mongodb.WorkflowCollection, query)
if err != nil {
return nil, err
}
var workflows []ChaosWorkFlowInput
err = cursor.All(ctx, &workflows)
err = results.All(ctx, &workflows)
if err != nil {
return nil, err
}
@ -95,13 +89,13 @@ func GetWorkflowsByClusterID(clusterID string) ([]ChaosWorkFlowInput, error) {
query := bson.D{{"cluster_id", clusterID}}
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
cursor, err := workflowCollection.Find(ctx, query)
results, err := mongodb.Operator.List(ctx, mongodb.WorkflowCollection, query)
if err != nil {
return nil, err
}
var workflows []ChaosWorkFlowInput
err = cursor.All(ctx, &workflows)
err = results.All(ctx, &workflows)
if err != nil {
return nil, err
}
@ -111,7 +105,7 @@ func GetWorkflowsByClusterID(clusterID string) ([]ChaosWorkFlowInput, error) {
// InsertChaosWorkflow takes details of a workflow and inserts into the database collection
func InsertChaosWorkflow(chaosWorkflow ChaosWorkFlowInput) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := workflowCollection.InsertOne(ctx, chaosWorkflow)
err := mongodb.Operator.Create(ctx, mongodb.WorkflowCollection, chaosWorkflow)
if err != nil {
return err
}
@ -123,7 +117,7 @@ func InsertChaosWorkflow(chaosWorkflow ChaosWorkFlowInput) error {
func UpdateChaosWorkflow(query bson.D, update bson.D) error {
ctx, _ := context.WithTimeout(backgroundContext, 10*time.Second)
_, err := workflowCollection.UpdateOne(ctx, query, update)
_, err := mongodb.Operator.Update(ctx, mongodb.WorkflowCollection, query, update)
if err != nil {
return err
}

View File

@ -7,18 +7,11 @@ import (
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
var workflowtemplateCollection *mongo.Collection
func init() {
workflowtemplateCollection = mongodb.Database.Collection("workflow-template")
}
// CreateWorkflowTemplate add the template details in the database
func CreateWorkflowTemplate(ctx context.Context, template *ManifestTemplate) error {
_, err := workflowtemplateCollection.InsertOne(ctx, template)
err := mongodb.Operator.Create(ctx, mongodb.WorkflowTemplateCollection, template)
if err != nil {
log.Print("Error while creating template: ", err)
}
@ -27,13 +20,13 @@ func CreateWorkflowTemplate(ctx context.Context, template *ManifestTemplate) err
// GetTemplatesByProjectID is used to query the list of templates present in the project
func GetTemplatesByProjectID(ctx context.Context, projectID string) ([]ManifestTemplate, error) {
query := bson.M{"project_id": projectID, "is_removed": false}
cursor, err := workflowtemplateCollection.Find(ctx, query)
query := bson.D{{"project_id", projectID}, {"is_removed", false}}
results, err := mongodb.Operator.List(ctx, mongodb.WorkflowTemplateCollection, query)
if err != nil {
log.Print("Error getting template: ", err)
}
var templates []ManifestTemplate
err = cursor.All(ctx, &templates)
err = results.All(ctx, &templates)
if err != nil {
log.Println(err)
@ -45,7 +38,8 @@ func GetTemplatesByProjectID(ctx context.Context, projectID string) ([]ManifestT
// GetTemplateByTemplateID is used to query a selected template using template id
func GetTemplateByTemplateID(ctx context.Context, templateID string) (ManifestTemplate, error) {
var template ManifestTemplate
err := workflowtemplateCollection.FindOne(ctx, bson.M{"template_id": templateID}).Decode(&template)
result, err := mongodb.Operator.Get(ctx, mongodb.WorkflowTemplateCollection, bson.D{{"template_id", templateID}})
err = result.Decode(&template)
if err != nil {
return ManifestTemplate{}, err
}
@ -54,7 +48,7 @@ func GetTemplateByTemplateID(ctx context.Context, templateID string) (ManifestTe
// UpdateTemplateManifest is used to update the template details
func UpdateTemplateManifest(ctx context.Context, query bson.D, update bson.D) error {
updateResult, err := workflowtemplateCollection.UpdateOne(ctx, query, update)
updateResult, err := mongodb.Operator.Update(ctx, mongodb.WorkflowTemplateCollection, query, update)
if err != nil {
return err
}

View File

@ -20,16 +20,16 @@ import (
selfDeployer "github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/self-deployer"
)
// CreateProjectWithUser :creates a project for the user
// CreateProjectWithUser creates a project for the user
func CreateProjectWithUser(ctx context.Context, projectName string, userID string) (*model.Project, error) {
var (
self_cluster = os.Getenv("SELF_CLUSTER")
selfCluster = os.Getenv("SELF_CLUSTER")
)
user, er := dbOperationsUserManagement.GetUserByUserID(ctx, userID)
if er != nil {
log.Print("ERROR", er)
return nil, er
user, err := dbOperationsUserManagement.GetUserByUserID(ctx, userID)
if err != nil {
log.Print("Error in fetching the user", err)
return nil, err
}
uuid := uuid.New()
@ -50,9 +50,9 @@ func CreateProjectWithUser(ctx context.Context, projectName string, userID strin
CreatedAt: time.Now().String(),
}
err := dbOperationsProject.CreateProject(ctx, newProject)
err = dbOperationsProject.CreateProject(ctx, newProject)
if err != nil {
log.Print("ERROR", err)
log.Print("Error in creating the project", err)
return nil, err
}
@ -65,7 +65,7 @@ func CreateProjectWithUser(ctx context.Context, projectName string, userID strin
log.Print("Cloning https://github.com/litmuschaos/chaos-charts")
go myhub.AddMyHub(context.Background(), defaultHub, newProject.ID)
if strings.ToLower(self_cluster) == "true" && strings.ToLower(*user.Role) == "admin" {
if strings.ToLower(selfCluster) == "true" && strings.ToLower(*user.Role) == "admin" {
log.Print("Starting self deployer")
go selfDeployer.StartDeployer(newProject.ID)
}
@ -73,7 +73,7 @@ func CreateProjectWithUser(ctx context.Context, projectName string, userID strin
return newProject.GetOutputProject(), nil
}
// GetProject ...
// GetProject queries the project with a given projectID from the database
func GetProject(ctx context.Context, projectID string) (*model.Project, error) {
project, err := dbOperationsProject.GetProject(ctx, bson.D{{"_id", projectID}})
@ -83,7 +83,7 @@ func GetProject(ctx context.Context, projectID string) (*model.Project, error) {
return project.GetOutputProject(), nil
}
// GetProjectsByUserID ...
// GetProjectsByUserID queries the project with a given userID from the database and returns it in the appropriate format
func GetProjectsByUserID(ctx context.Context, userID string) ([]*model.Project, error) {
projects, err := dbOperationsProject.GetProjectsByUserID(ctx, userID)
@ -91,14 +91,15 @@ func GetProjectsByUserID(ctx context.Context, userID string) ([]*model.Project,
return nil, err
}
outputProjects := []*model.Project{}
var outputProjects []*model.Project
for _, project := range projects {
outputProjects = append(outputProjects, project.GetOutputProject())
}
return outputProjects, nil
}
// SendInvitation :Send an invitation
// SendInvitation send an invitation to a new user and
// returns an error if the member is already part of the project
func SendInvitation(ctx context.Context, member model.MemberInput) (*model.Member, error) {
invitation, err := getInvitation(ctx, member)
@ -107,7 +108,7 @@ func SendInvitation(ctx context.Context, member model.MemberInput) (*model.Membe
}
if invitation == dbSchemaProject.AcceptedInvitation {
return nil, errors.New("This user is already a member of your project")
return nil, errors.New("this user is already a member of this project")
} else if invitation == dbSchemaProject.PendingInvitation || invitation == dbSchemaProject.DeclinedInvitation || invitation == dbSchemaProject.ExitedProject {
err = dbOperationsProject.UpdateInvite(ctx, member.ProjectID, member.UserID, dbSchemaProject.PendingInvitation, member.Role)
if err != nil {
@ -133,37 +134,37 @@ func SendInvitation(ctx context.Context, member model.MemberInput) (*model.Membe
return newMember.GetOutputMember(), err
}
// AcceptInvitation :Accept an invitaion
// AcceptInvitation accept an invitation
func AcceptInvitation(ctx context.Context, member model.MemberInput) (string, error) {
err := dbOperationsProject.UpdateInvite(ctx, member.ProjectID, member.UserID, dbSchemaProject.AcceptedInvitation, nil)
if err != nil {
return "Unsuccessful", err
}
return "Successfull", nil
return "Successful", nil
}
// DeclineInvitation :Decline an Invitaion
// DeclineInvitation decline an Invitation
func DeclineInvitation(ctx context.Context, member model.MemberInput) (string, error) {
err := dbOperationsProject.UpdateInvite(ctx, member.ProjectID, member.UserID, dbSchemaProject.DeclinedInvitation, nil)
if err != nil {
return "Unsuccessful", err
}
return "Successfull", nil
return "Successful", nil
}
//LeaveProject :Leave a Project
//LeaveProject leaves a project
func LeaveProject(ctx context.Context, member model.MemberInput) (string, error) {
err := dbOperationsProject.UpdateInvite(ctx, member.ProjectID, member.UserID, dbSchemaProject.ExitedProject, nil)
if err != nil {
return "Unsuccessful", err
}
return "Successfull", err
return "Successful", err
}
// getInvitation :Returns the Invitation Status
// getInvitation returns the Invitation status
func getInvitation(ctx context.Context, member model.MemberInput) (dbSchemaProject.Invitation, error) {
project, err := dbOperationsProject.GetProject(ctx, bson.D{{"_id", member.ProjectID}})
@ -179,7 +180,7 @@ func getInvitation(ctx context.Context, member model.MemberInput) (dbSchemaProje
return "", nil
}
// RemoveInvitation :Removes member or cancels invitation
// RemoveInvitation removes member or cancels invitation
func RemoveInvitation(ctx context.Context, member model.MemberInput) (string, error) {
invitation, err := getInvitation(ctx, member)

View File

@ -19,14 +19,15 @@ const (
PendingInvitation = "Pending"
)
// CreateUser :creates a user
// CreateUser checks if the user with the given username is already present in the database
// if not it creates a new user and puts in the DB
func CreateUser(ctx context.Context, user model.CreateUserInput) (*model.User, error) {
outputUser, err := GetUser(ctx, user.Username)
if err != nil && err != mongo.ErrNoDocuments {
return nil, err
} else if outputUser != nil {
return outputUser, errors.New("User already exists")
return outputUser, errors.New("user already exists")
}
newUser := &dbSchemaUserManagement.User{
@ -39,9 +40,9 @@ func CreateUser(ctx context.Context, user model.CreateUserInput) (*model.User, e
Role: &user.Role,
}
err = dbOperationsUserManagement.InsertUser(ctx, newUser)
err = dbOperationsUserManagement.CreateUser(ctx, newUser)
if err != nil {
log.Print("ERROR", err)
log.Print("Error in creating a new user:", err)
return nil, err
}
@ -49,7 +50,9 @@ func CreateUser(ctx context.Context, user model.CreateUserInput) (*model.User, e
return outputUser, nil
}
// GetUser ...
// GetUser queries the user collection for a user with a given username,
// then queries the project collection for the projects of the user with the userID
// and finally return the user with its projects set properly
func GetUser(ctx context.Context, username string) (*model.User, error) {
user, err := dbOperationsUserManagement.GetUserByUserName(ctx, username)
@ -67,7 +70,7 @@ func GetUser(ctx context.Context, username string) (*model.User, error) {
return outputUser, nil
}
// GetUsers ...
// GetUsers queries the list of all the users from the DB and returns it in the appropriate format
func GetUsers(ctx context.Context) ([]*model.User, error) {
users, err := dbOperationsUserManagement.GetUsers(ctx)
@ -83,7 +86,7 @@ func GetUsers(ctx context.Context) ([]*model.User, error) {
return outputUsers, nil
}
// UpdateUser ...
// UpdateUser updates the user details and returns a status
func UpdateUser(ctx context.Context, user model.UpdateUserInput) (string, error) {
dbUser := &dbSchemaUserManagement.User{

View File

@ -7,6 +7,8 @@ import (
"runtime"
"time"
"github.com/litmuschaos/litmus/litmus-portal/graphql-server/pkg/database/mongodb"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/transport"
@ -39,6 +41,9 @@ func main() {
if port == "" {
port = defaultPort
}
// Initialize the mongo client
mongodb.Client = mongodb.Client.Initialize()
srv := handler.New(generated.NewExecutableSchema(graph.NewConfig()))
srv.AddTransport(transport.POST{})
srv.AddTransport(transport.GET{})