//StateFetch fetches the state of the specified resource func (tx *Transaction) StateFetch(s *schema.Schema, filter transaction.Filter) (state transaction.ResourceState, err error) { if !s.StateVersioning() { err = fmt.Errorf("Schema %s does not support state versioning.", s.ID) return } cols := makeStateColumns(s) q := sq.Select(cols...).From(quote(s.GetDbTableName())) q, _ = addFilterToQuery(s, q, filter, true) sql, args, err := q.ToSql() if err != nil { return } logQuery(sql, args...) rows, err := tx.transaction.Queryx(sql, args...) if err != nil { return } defer rows.Close() if !rows.Next() { err = fmt.Errorf("No resource found") return } data := map[string]interface{}{} rows.MapScan(data) err = decodeState(data, &state) return }
//GenTableDef generates create table sql func (db *DB) GenTableDef(s *schema.Schema, cascade bool) string { schemaManager := schema.GetManager() cols, relations := db.genTableCols(s, cascade, nil) if s.Parent != "" { foreignSchema, _ := schemaManager.Schema(s.Parent) cascadeString := "" if cascade || s.OnParentDeleteCascade { cascadeString = "on delete cascade" } relations = append(relations, fmt.Sprintf("foreign key(`%s_id`) REFERENCES `%s`(id) %s", s.Parent, foreignSchema.GetDbTableName(), cascadeString)) } if s.StateVersioning() { cols = append(cols, quote(configVersionColumnName)+"int not null default 1") cols = append(cols, quote(stateVersionColumnName)+"int not null default 0") cols = append(cols, quote(stateErrorColumnName)+"text not null default ''") cols = append(cols, quote(stateColumnName)+"text not null default ''") cols = append(cols, quote(stateMonitoringColumnName)+"text not null default ''") } cols = append(cols, relations...) tableSQL := fmt.Sprintf("create table `%s` (%s);\n", s.GetDbTableName(), strings.Join(cols, ",")) log.Debug("Creating table: " + tableSQL) return tableSQL }
//GenTableDef generates table create sql func (db *DB) GenTableDef(s *schema.Schema, cascade bool) string { schemaManager := schema.GetManager() var cols []string var relations []string cascadeString := "" if cascade { cascadeString = "on delete cascade" } for _, property := range s.Properties { handler := db.handlers[property.Type] dataType := property.SQLType if db.sqlType == "sqlite3" { dataType = strings.Replace(dataType, "auto_increment", "autoincrement", 1) } if dataType == "" { dataType = handler.dataType(&property) if property.ID == "id" { dataType += " primary key" } else { if property.Nullable { dataType += " null" } else { dataType += " not null" } if property.Unique { dataType += " unique" } } } sql := "`" + property.ID + "`" + dataType cols = append(cols, sql) if property.Relation != "" { foreignSchema, _ := schemaManager.Schema(property.Relation) if foreignSchema != nil { relations = append(relations, fmt.Sprintf("foreign key(`%s`) REFERENCES `%s`(id) %s", property.ID, foreignSchema.GetDbTableName(), cascadeString)) } } } if s.Parent != "" { foreignSchema, _ := schemaManager.Schema(s.Parent) relations = append(relations, fmt.Sprintf("foreign key(`%s_id`) REFERENCES `%s`(id) %s", s.Parent, foreignSchema.GetDbTableName(), cascadeString)) } if s.StateVersioning() { cols = append(cols, quote(configVersionColumnName)+"int not null default 1") cols = append(cols, quote(stateVersionColumnName)+"int not null default 0") cols = append(cols, quote(stateErrorColumnName)+"text not null default ''") cols = append(cols, quote(stateColumnName)+"text not null default ''") cols = append(cols, quote(stateMonitoringColumnName)+"text not null default ''") } cols = append(cols, relations...) tableSQL := fmt.Sprintf("create table `%s` (%s);\n", s.GetDbTableName(), strings.Join(cols, ",")) log.Debug("Creating table: " + tableSQL) return tableSQL }
//MonitoringUpdate updates the state in the db based on the sync event func MonitoringUpdate(response *gohan_sync.Event, server *Server) error { lockKey := lockPath + response.Key err := server.sync.Lock(lockKey, false) if err != nil { return err } defer func() { server.sync.Unlock(lockKey) }() dataStore := server.db schemaPath := "/" + strings.TrimPrefix(response.Key, monitoringPrefix) var curSchema *schema.Schema manager := schema.GetManager() for _, s := range manager.Schemas() { if strings.HasPrefix(schemaPath, s.URL) { curSchema = s break } } if curSchema == nil || !curSchema.StateVersioning() { log.Debug("Monitoring update on unexpected path '%s'", schemaPath) return nil } resourceID := strings.TrimPrefix(schemaPath, curSchema.URL+"/") tx, err := dataStore.Begin() if err != nil { return err } defer tx.Close() curResource, err := tx.Fetch(curSchema, resourceID, nil) if err != nil { return err } resourceState, err := tx.StateFetch(curSchema, resourceID, nil) if err != nil { return err } if resourceState.ConfigVersion != resourceState.StateVersion { return nil } var ok bool resourceState.Monitoring, ok = response.Data["monitoring"].(string) if !ok { return fmt.Errorf("No monitoring in state information") } environmentManager := extension.GetManager() environment, haveEnvironment := environmentManager.GetEnvironment(curSchema.ID) context := map[string]interface{}{} context["resource"] = curResource.Data() context["monitoring"] = resourceState.Monitoring context["transaction"] = tx if haveEnvironment { if err := extension.HandleEvent(context, environment, "pre_monitoring_update_in_transaction"); err != nil { return err } } err = tx.StateUpdate(curResource, &resourceState) if err != nil { return err } if haveEnvironment { if err := extension.HandleEvent(context, environment, "post_monitoring_update_in_transaction"); err != nil { return err } } return tx.Commit() }
//StateUpdate updates the state in the db based on the sync event func StateUpdate(response *gohan_sync.Event, server *Server) error { lockKey := lockPath + response.Key err := server.sync.Lock(lockKey, false) if err != nil { return err } defer func() { server.sync.Unlock(lockKey) }() dataStore := server.db schemaPath := "/" + strings.TrimPrefix(response.Key, statePrefix) var curSchema *schema.Schema manager := schema.GetManager() for _, s := range manager.Schemas() { if strings.HasPrefix(schemaPath, s.URL) { curSchema = s break } } if curSchema == nil || !curSchema.StateVersioning() { log.Debug("State update on unexpected path '%s'", schemaPath) return nil } resourceID := strings.TrimPrefix(schemaPath, curSchema.URL+"/") tx, err := dataStore.Begin() if err != nil { return err } defer tx.Close() curResource, err := tx.Fetch(curSchema, resourceID, nil) if err != nil { return err } resourceState, err := tx.StateFetch(curSchema, resourceID, nil) if err != nil { return err } if resourceState.StateVersion == resourceState.ConfigVersion { return nil } stateVersion, ok := response.Data["version"].(float64) if !ok { return fmt.Errorf("No version in state information") } oldStateVersion := resourceState.StateVersion resourceState.StateVersion = int64(stateVersion) if resourceState.StateVersion < oldStateVersion { return nil } if newError, ok := response.Data["error"].(string); ok { resourceState.Error = newError } if newState, ok := response.Data["state"].(string); ok { resourceState.State = newState } environmentManager := extension.GetManager() environment, haveEnvironment := environmentManager.GetEnvironment(curSchema.ID) context := map[string]interface{}{} if haveEnvironment { serviceAuthorization, _ := server.keystoneIdentity.GetServiceAuthorization() context["catalog"] = serviceAuthorization.Catalog() context["auth_token"] = serviceAuthorization.AuthToken() context["resource"] = curResource.Data() context["state"] = response.Data context["config_version"] = resourceState.ConfigVersion context["transaction"] = tx if err := extension.HandleEvent(context, environment, "pre_state_update_in_transaction"); err != nil { return err } } err = tx.StateUpdate(curResource, &resourceState) if err != nil { return err } if haveEnvironment { if err := extension.HandleEvent(context, environment, "post_state_update_in_transaction"); err != nil { return err } } return tx.Commit() }