//CreateResourceInTransaction craete db resource model in transaction func CreateResourceInTransaction(context middleware.Context, resource *schema.Resource) error { resourceSchema := resource.Schema() mainTransaction := context["transaction"].(transaction.Transaction) environmentManager := extension.GetManager() environment, ok := environmentManager.GetEnvironment(resourceSchema.ID) if !ok { return fmt.Errorf("No environment for schema") } if err := extension.HandleEvent(context, environment, "pre_create_in_transaction"); err != nil { return err } if err := mainTransaction.Create(resource); err != nil { log.Debug("%s transaction error", err) return ResourceError{ err, fmt.Sprintf("Failed to store data in database: %v", err), CreateFailed} } response := map[string]interface{}{} response[resourceSchema.Singular] = resource.Data() context["response"] = response if err := extension.HandleEvent(context, environment, "post_create_in_transaction"); err != nil { return err } return nil }
//Create create resource in the db func (tx *Transaction) Create(resource *schema.Resource) error { var cols []string var values []interface{} db := tx.db s := resource.Schema() data := resource.Data() q := sq.Insert(quote(s.GetDbTableName())) for _, attr := range s.Properties { //TODO(nati) support optional value if _, ok := data[attr.ID]; ok { handler := db.handler(&attr) cols = append(cols, quote(attr.ID)) encoded, err := handler.encode(&attr, data[attr.ID]) if err != nil { return fmt.Errorf("SQL Create encoding error: %s", err) } values = append(values, encoded) } } q = q.Columns(cols...).Values(values...) sql, args, err := q.ToSql() if err != nil { return err } return tx.Exec(sql, args...) }
//Create create resource in the db func (tx *Transaction) Create(resource *schema.Resource) error { db := tx.db db.load() s := resource.Schema() data := resource.Data() table := db.getTable(s) db.data[s.GetDbTableName()] = append(table, data) db.write() return nil }
//Update update resource in the db func (tx *Transaction) Update(resource *schema.Resource) error { s := resource.Schema() data := resource.Data() db := tx.db q := sq.Update(quote(s.GetDbTableName())) for _, attr := range s.Properties { //TODO(nati) support optional value if _, ok := data[attr.ID]; ok { handler := db.handler(&attr) encoded, err := handler.encode(&attr, data[attr.ID]) if err != nil { return fmt.Errorf("SQL Update encoding error: %s", err) } q = q.Set(quote(attr.ID), encoded) } } if s.Parent != "" { q.Set(s.ParentSchemaPropertyID(), resource.ParentID()) } q = q.Where(sq.Eq{"id": resource.ID()}) sql, args, err := q.ToSql() if err != nil { return err } return tx.Exec(sql, args...) }
func (tl *transactionEventLogger) logEvent(eventType string, resource *schema.Resource, version int64) error { schemaManager := schema.GetManager() eventSchema, ok := schemaManager.Schema("event") if !ok { return fmt.Errorf("event schema not found") } if resource.Schema().Metadata["nosync"] == true { log.Debug("skipping event logging for schema: %s", resource.Schema().ID) return nil } body, err := resource.JSONString() if err != nil { return fmt.Errorf("Error during event resource deserialisation: %s", err.Error()) } eventResource, err := schema.NewResource(eventSchema, map[string]interface{}{ "type": eventType, "path": resource.Path(), "version": version, "body": body, "timestamp": int64(time.Now().Unix()), }) tl.eventLogged = true return tl.Transaction.Create(eventResource) }
//Update update resource in the db func (tx *Transaction) Update(resource *schema.Resource) error { q, err := tx.updateQuery(resource) if err != nil { return err } sql, args, err := q.ToSql() if err != nil { return err } if resource.Schema().StateVersioning() { sql += ", `" + configVersionColumnName + "` = `" + configVersionColumnName + "` + 1" } sql += " WHERE id = ?" args = append(args, resource.ID()) return tx.Exec(sql, args...) }
//StateUpdate update resource state func (tx *Transaction) StateUpdate(resource *schema.Resource, state *transaction.ResourceState) error { q, err := tx.updateQuery(resource) if err != nil { return err } if resource.Schema().StateVersioning() && state != nil { q = q.Set(quote(stateVersionColumnName), state.StateVersion) q = q.Set(quote(stateErrorColumnName), state.Error) q = q.Set(quote(stateColumnName), state.State) q = q.Set(quote(stateMonitoringColumnName), state.Monitoring) } q = q.Where(sq.Eq{"id": resource.ID()}) sql, args, err := q.ToSql() if err != nil { return err } return tx.Exec(sql, args...) }
//GetSingleResourceInTransaction get resource in single transaction func GetSingleResourceInTransaction(context middleware.Context, resourceSchema *schema.Schema, resourceID string, tenantIDs []string) (err error) { mainTransaction := context["transaction"].(transaction.Transaction) auth := context["auth"].(schema.Authorization) environmentManager := extension.GetManager() environment, ok := environmentManager.GetEnvironment(resourceSchema.ID) if !ok { return fmt.Errorf("no environment for schema") } if err := handleEvent(context, environment, "pre_show_in_transaction"); err != nil { return err } if rawResponse, ok := context["response"]; ok { if _, ok := rawResponse.(map[string]interface{}); ok { return nil } return fmt.Errorf("extension returned invalid JSON: %v", rawResponse) } var object *schema.Resource if resourceSchema.ID == "schema" { manager := schema.GetManager() requestedSchema, _ := manager.Schema(resourceID) object, err = GetSchema(requestedSchema, auth) } else { object, err = mainTransaction.Fetch(resourceSchema, resourceID, tenantIDs) } if err != nil || object == nil { return ResourceError{err, "", NotFound} } response := map[string]interface{}{} response[resourceSchema.Singular] = object.Data() context["response"] = response if err := handleEvent(context, environment, "post_show_in_transaction"); err != nil { return err } return }
func (server *Server) syncEvent(resource *schema.Resource) error { schemaManager := schema.GetManager() eventSchema, _ := schemaManager.Schema("event") tx, err := server.db.Begin() if err != nil { return err } defer tx.Close() eventType := resource.Get("type").(string) path := resource.Get("path").(string) body := resource.Get("body").(string) log.Debug("event %s", eventType) if eventType == "create" || eventType == "update" { log.Debug("set %s on sync", path) err = server.sync.Update(path, body) if err != nil { log.Error(fmt.Sprintf("%s on sync", err)) return err } } else if eventType == "delete" { log.Debug("delete %s", path) err = server.sync.Delete(path) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) return err } } log.Debug("delete event %d", resource.Get("id")) id := resource.Get("id") err = tx.Delete(eventSchema, id) if err != nil { log.Error(fmt.Sprintf("delete failed: %s", err)) return err } err = tx.Commit() if err != nil { log.Error(fmt.Sprintf("commit failed: %s", err)) return err } return nil }
func (tl *transactionEventLogger) Update(resource *schema.Resource) error { err := tl.Transaction.Update(resource) if err != nil { return err } if !resource.Schema().StateVersioning() { return tl.logEvent("update", resource, 0) } state, err := tl.StateFetch(resource.Schema(), transaction.IDFilter(resource.ID())) if err != nil { return err } return tl.logEvent("update", resource, state.ConfigVersion) }
//Update update resource in the db func (tx *Transaction) Update(resource *schema.Resource) error { db := tx.db db.load() s := resource.Schema() data := resource.Data() table := db.getTable(s) for _, rawDataInDB := range table { dataInDB := rawDataInDB.(map[string]interface{}) if dataInDB["id"] == resource.ID() { for key, value := range data { dataInDB[key] = value } } } db.write() return nil }
func (tx *Transaction) updateQuery(resource *schema.Resource) (sq.UpdateBuilder, error) { s := resource.Schema() db := tx.db data := resource.Data() q := sq.Update(quote(s.GetDbTableName())) for _, attr := range s.Properties { //TODO(nati) support optional value if _, ok := data[attr.ID]; ok { handler := db.handler(&attr) encoded, err := handler.encode(&attr, data[attr.ID]) if err != nil { return q, fmt.Errorf("SQL Update encoding error: %s", err) } q = q.Set(quote(attr.ID), encoded) } } if s.Parent != "" { q = q.Set(s.ParentSchemaPropertyID(), resource.ParentID()) } return q, nil }
Expect(server.Sync()).To(Succeed()) _, err = sync.Fetch(networkResource.Path()) Expect(err).To(HaveOccurred(), "Failed to sync db resource deletion to sync backend") }) }) Describe("Updating the state", func() { const ( statePrefix = "/state" monitoringPrefix = "/monitoring" ) var ( networkSchema *schema.Schema networkResource *schema.Resource wrappedTestDB db.DB possibleEvent gohan_sync.Event ) BeforeEach(func() { manager := schema.GetManager() var ok bool networkSchema, ok = manager.Schema("network") Expect(ok).To(BeTrue()) network := getNetwork("Red", "red") var err error networkResource, err = manager.LoadResource("network", network) Expect(err).ToNot(HaveOccurred()) wrappedTestDB = &srv.DbSyncWrapper{DB: testDB} tx, err := wrappedTestDB.Begin() defer tx.Close()
func (server *Server) syncEvent(resource *schema.Resource) error { schemaManager := schema.GetManager() eventSchema, _ := schemaManager.Schema("event") tx, err := server.db.Begin() if err != nil { return err } defer tx.Close() eventType := resource.Get("type").(string) path := resource.Get("path").(string) path = configPrefix + path body := resource.Get("body").(string) version, _ := resource.Get("version").(uint64) log.Debug("event %s", eventType) if eventType == "create" || eventType == "update" { log.Debug("set %s on sync", path) content, err := json.Marshal(map[string]interface{}{ "body": body, "version": version, }) if err != nil { log.Error(fmt.Sprintf("When marshalling sync object: %s", err)) return err } err = server.sync.Update(path, string(content)) if err != nil { log.Error(fmt.Sprintf("%s on sync", err)) return err } } else if eventType == "delete" { log.Debug("delete %s", path) err = server.sync.Delete(path) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) return err } } log.Debug("delete event %d", resource.Get("id")) id := resource.Get("id") err = tx.Delete(eventSchema, id) if err != nil { log.Error(fmt.Sprintf("delete failed: %s", err)) return err } err = tx.Commit() if err != nil { log.Error(fmt.Sprintf("commit failed: %s", err)) return err } return nil }
"github.com/cloudwan/gohan/schema" "github.com/cloudwan/gohan/util" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Database operation test", func() { var ( err error ok bool conn string dbType string manager *schema.Manager networkSchema *schema.Schema serverSchema *schema.Schema networkResource1 *schema.Resource networkResource2 *schema.Resource subnetResource *schema.Resource serverResource *schema.Resource dataStore db.DB ) BeforeEach(func() { manager = schema.GetManager() Expect(manager.LoadSchemaFromFile("../etc/schema/gohan.json")).To(Succeed()) }) AfterEach(func() {
func (server *Server) syncEvent(resource *schema.Resource) error { schemaManager := schema.GetManager() eventSchema, _ := schemaManager.Schema("event") tx, err := server.db.Begin() if err != nil { return err } defer tx.Close() eventType := resource.Get("type").(string) resourcePath := resource.Get("path").(string) body := resource.Get("body").(string) path := generatePath(resourcePath, body) version, ok := resource.Get("version").(int) if !ok { log.Debug("cannot cast version value in int for %s", path) } log.Debug("event %s", eventType) if eventType == "create" || eventType == "update" { log.Debug("set %s on sync", path) content, err := json.Marshal(map[string]interface{}{ "body": body, "version": version, }) if err != nil { log.Error(fmt.Sprintf("When marshalling sync object: %s", err)) return err } err = server.sync.Update(path, string(content)) if err != nil { log.Error(fmt.Sprintf("%s on sync", err)) return err } } else if eventType == "delete" { log.Debug("delete %s", resourcePath) deletePath := resourcePath resourceSchema := schema.GetSchemaByURLPath(resourcePath) if _, ok := resourceSchema.SyncKeyTemplate(); ok { var data map[string]interface{} err := json.Unmarshal(([]byte)(body), &data) deletePath, err = resourceSchema.GenerateCustomPath(data) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s - generating of custom path failed", err)) return err } } log.Debug("deleting %s", statePrefix+deletePath) err = server.sync.Delete(statePrefix + deletePath) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) } log.Debug("deleting %s", monitoringPrefix+deletePath) err = server.sync.Delete(monitoringPrefix + deletePath) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) } log.Debug("deleting %s", resourcePath) err = server.sync.Delete(path) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) return err } } log.Debug("delete event %d", resource.Get("id")) id := resource.Get("id") err = tx.Delete(eventSchema, id) if err != nil { log.Error(fmt.Sprintf("delete failed: %s", err)) return err } err = tx.Commit() if err != nil { log.Error(fmt.Sprintf("commit failed: %s", err)) return err } return nil }
func makePluralKey(resource *schema.Resource) string { s := resource.Schema() key := s.Prefix + "/" + s.Plural return key }
func (server *Server) syncEvent(resource *schema.Resource) error { schemaManager := schema.GetManager() eventSchema, _ := schemaManager.Schema("event") tx, err := server.db.Begin() if err != nil { return err } defer tx.Close() eventType := resource.Get("type").(string) resourcePath := resource.Get("path").(string) body := resource.Get("body").(string) syncPlain := resource.Get("sync_plain").(bool) syncProperty := resource.Get("sync_property").(string) path := generatePath(resourcePath, body) version, ok := resource.Get("version").(int) if !ok { log.Debug("cannot cast version value in int for %s", path) } log.Debug("event %s", eventType) if eventType == "create" || eventType == "update" { log.Debug("set %s on sync", path) content := body var data map[string]interface{} if syncProperty != "" { err = json.Unmarshal(([]byte)(body), &data) if err != nil { log.Error(fmt.Sprintf("failed to unmarshal body on sync: %s", err)) return err } target, ok := data[syncProperty] if !ok { return fmt.Errorf("could not find property `%s`", syncProperty) } jsonData, err := json.Marshal(target) if err != nil { return err } content = string(jsonData) } if syncPlain { var target interface{} json.Unmarshal([]byte(content), &target) switch target.(type) { case string: content = fmt.Sprintf("%v", target) } } else { data, err := json.Marshal(map[string]interface{}{ "body": content, "version": version, }) if err != nil { log.Error(fmt.Sprintf("When marshalling sync object: %s", err)) return err } content = string(data) } err = server.sync.Update(path, content) if err != nil { log.Error(fmt.Sprintf("%s on sync", err)) return err } } else if eventType == "delete" { log.Debug("delete %s", resourcePath) deletePath := resourcePath resourceSchema := schema.GetSchemaByURLPath(resourcePath) if _, ok := resourceSchema.SyncKeyTemplate(); ok { var data map[string]interface{} json.Unmarshal(([]byte)(body), &data) deletePath, err = resourceSchema.GenerateCustomPath(data) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s - generating of custom path failed", err)) return err } } log.Debug("deleting %s", statePrefix+deletePath) err = server.sync.Delete(statePrefix + deletePath) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) } log.Debug("deleting %s", monitoringPrefix+deletePath) err = server.sync.Delete(monitoringPrefix + deletePath) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) } log.Debug("deleting %s", resourcePath) err = server.sync.Delete(path) if err != nil { log.Error(fmt.Sprintf("Delete from sync failed %s", err)) return err } } log.Debug("delete event %d", resource.Get("id")) id := resource.Get("id") err = tx.Delete(eventSchema, id) if err != nil { log.Error(fmt.Sprintf("delete failed: %s", err)) return err } err = tx.Commit() if err != nil { log.Error(fmt.Sprintf("commit failed: %s", err)) return err } return nil }