예제 #1
0
func (tl *transactionEventLogger) Delete(s *schema.Schema, resourceID interface{}) error {
	resource, err := tl.Fetch(s, transaction.IDFilter(resourceID))
	if err != nil {
		return err
	}
	configVersion := int64(0)
	if resource.Schema().StateVersioning() {
		state, err := tl.StateFetch(s, transaction.IDFilter(resourceID))
		if err != nil {
			return err
		}
		configVersion = state.ConfigVersion + 1
	}
	err = tl.Transaction.Delete(s, resourceID)
	if err != nil {
		return err
	}
	return tl.logEvent("delete", resource, configVersion)
}
예제 #2
0
// DeleteResource deletes the resource specified by the schema and ID
func DeleteResource(context middleware.Context,
	dataStore db.DB,
	resourceSchema *schema.Schema,
	resourceID string,
) error {
	context["id"] = resourceID
	environmentManager := extension.GetManager()
	environment, ok := environmentManager.GetEnvironment(resourceSchema.ID)
	if !ok {
		return fmt.Errorf("No environment for schema")
	}
	auth := context["auth"].(schema.Authorization)
	policy, err := loadPolicy(context, "delete", strings.Replace(resourceSchema.GetSingleURL(), ":id", resourceID, 1), auth)
	if err != nil {
		return err
	}
	context["policy"] = policy
	preTransaction, err := dataStore.Begin()
	if err != nil {
		return fmt.Errorf("cannot create transaction: %v", err)
	}
	tenantIDs := policy.GetTenantIDFilter(schema.ActionDelete, auth.TenantID())
	filter := transaction.IDFilter(resourceID)
	if tenantIDs != nil {
		filter["tenant_id"] = tenantIDs
	}
	resource, fetchErr := preTransaction.Fetch(resourceSchema, filter)
	preTransaction.Close()

	if resource != nil {
		context["resource"] = resource.Data()
	}

	if err := extension.HandleEvent(context, environment, "pre_delete"); err != nil {
		return err
	}
	if fetchErr != nil {
		return ResourceError{err, "", NotFound}
	}
	if err := InTransaction(
		context, dataStore,
		transaction.GetIsolationLevel(resourceSchema, schema.ActionDelete),
		func() error {
			return DeleteResourceInTransaction(context, resourceSchema, resourceID)
		},
	); err != nil {
		return err
	}
	if err := extension.HandleEvent(context, environment, "post_delete"); err != nil {
		return err
	}
	return nil
}
예제 #3
0
파일: db.go 프로젝트: vozhyk-/gohan
//CopyDBResources copies resources from input database to output database
func CopyDBResources(input, output DB, overrideExisting bool) error {
	schemaManager := schema.GetManager()
	schemas := schemaManager.OrderedSchemas()
	if len(schemas) == 0 {
		return fmt.Errorf(noSchemasInManagerError)
	}

	itx, err := input.Begin()
	if err != nil {
		return err
	}
	defer itx.Close()

	otx, err := output.Begin()
	if err != nil {
		return err
	}
	defer otx.Close()

	for _, s := range schemas {
		if s.IsAbstract() {
			continue
		}
		log.Info("Populating resources for schema %s", s.ID)
		resources, _, err := itx.List(s, nil, nil)
		if err != nil {
			return err
		}

		for _, resource := range resources {
			log.Info("Creating resource %s", resource.ID())
			destResource, _ := otx.Fetch(s, transaction.IDFilter(resource.ID()))
			if destResource == nil {
				resource.PopulateDefaults()
				err := otx.Create(resource)
				if err != nil {
					return err
				}
			} else if overrideExisting {
				err := otx.Update(resource)
				if err != nil {
					return err
				}
			}
		}
	}
	err = itx.Commit()
	if err != nil {
		return err
	}
	return otx.Commit()
}
예제 #4
0
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)
}
예제 #5
0
파일: gohan.go 프로젝트: vozhyk-/gohan
//DBGet get resource from a db.
func DBGet(tx transaction.Transaction, schemaID string, id string, tenantID string) (map[string]interface{}, error) {
	manager := schema.GetManager()
	schemaObj, ok := manager.Schema(schemaID)
	if !ok {
		return nil, fmt.Errorf("Schema %s not found", schemaID)
	}
	filter := transaction.IDFilter(id)
	if tenantID != "" {
		filter["tenant_id"] = tenantID
	}
	resp, err := tx.Fetch(schemaObj, filter)
	if err != nil {
		return nil, err
	}
	return resp.Data(), err
}
예제 #6
0
파일: gohan_db.go 프로젝트: vozhyk-/gohan
//GohanDbFetch gets resource from database
func GohanDbFetch(tx transaction.Transaction, schemaID, ID,
	tenantID string) (*schema.Resource, error) {

	schema, err := getSchema(schemaID)
	if err != nil {
		return nil, err
	}
	filter := transaction.IDFilter(ID)
	if tenantID != "" {
		filter["tenant_id"] = tenantID
	}
	resp, err := tx.Fetch(schema, filter)
	if err != nil {
		return nil, fmt.Errorf("Error during gohan_db_fetch: %s", err.Error())
	}
	return resp, nil
}
예제 #7
0
//DeleteResourceInTransaction deletes resources in a transaction
func DeleteResourceInTransaction(context middleware.Context, resourceSchema *schema.Schema, resourceID string) error {
	mainTransaction := context["transaction"].(transaction.Transaction)
	environmentManager := extension.GetManager()
	environment, ok := environmentManager.GetEnvironment(resourceSchema.ID)
	if !ok {
		return fmt.Errorf("No environment for schema")
	}

	auth := context["auth"].(schema.Authorization)
	policy := context["policy"].(*schema.Policy)
	tenantIDs := policy.GetTenantIDFilter(schema.ActionDelete, auth.TenantID())
	filter := transaction.IDFilter(resourceID)
	if tenantIDs != nil {
		filter["tenant_id"] = tenantIDs
	}
	resource, err := mainTransaction.Fetch(resourceSchema, filter)
	log.Debug("%s %s", resource, err)
	if err != nil {
		return err
	}
	if resource != nil {
		context["resource"] = resource.Data()
	}
	// apply property filter
	err = policy.ApplyPropertyConditionFilter(schema.ActionUpdate, resource.Data(), nil)
	if err != nil {
		return ResourceError{err, "", Unauthorized}
	}
	if err := extension.HandleEvent(context, environment, "pre_delete_in_transaction"); err != nil {
		return err
	}

	err = mainTransaction.Delete(resourceSchema, resourceID)
	if err != nil {
		return ResourceError{err, "", DeleteFailed}
	}

	if err := extension.HandleEvent(context, environment, "post_delete_in_transaction"); err != nil {
		return err
	}
	return nil
}
예제 #8
0
파일: gohan_db.go 프로젝트: vozhyk-/gohan
//GohanDbStateFetch gets resource's state from database
func GohanDbStateFetch(tx transaction.Transaction, schemaID, ID,
	tenantID string) (map[string]interface{}, error) {

	schema, err := getSchema(schemaID)
	if err != nil {
		return map[string]interface{}{}, err
	}
	filter := transaction.IDFilter(ID)
	if tenantID != "" {
		filter["tenant_id"] = tenantID
	}
	resp, err := tx.StateFetch(schema, filter)
	if err != nil {
		return map[string]interface{}{}, fmt.Errorf("Error during gohan_db_state_fetch: %s", err.Error())
	}
	data := map[string]interface{}{
		"config_version": resp.ConfigVersion,
		"state_version":  resp.StateVersion,
		"error":          resp.Error,
		"state":          resp.State,
		"monitoring":     resp.Monitoring,
	}
	return data, nil
}
예제 #9
0
// CreateOrUpdateResource updates resource if it existed and otherwise creates it and returns true.
func CreateOrUpdateResource(
	context middleware.Context,
	dataStore db.DB, identityService middleware.IdentityService,
	resourceSchema *schema.Schema,
	resourceID string, dataMap map[string]interface{},
) (bool, error) {
	auth := context["auth"].(schema.Authorization)

	//LoadPolicy
	policy, err := loadPolicy(context, "update", strings.Replace(resourceSchema.GetSingleURL(), ":id", resourceID, 1), auth)
	if err != nil {
		return false, err
	}

	preTransaction, err := dataStore.Begin()
	if err != nil {
		return false, fmt.Errorf("cannot create transaction: %v", err)
	}
	tenantIDs := policy.GetTenantIDFilter(schema.ActionUpdate, auth.TenantID())
	filter := transaction.IDFilter(resourceID)
	if tenantIDs != nil {
		filter["tenant_id"] = tenantIDs
	}
	_, fetchErr := preTransaction.Fetch(resourceSchema, filter)
	preTransaction.Close()

	if fetchErr != nil {
		dataMap["id"] = resourceID
		if err := CreateResource(context, dataStore, identityService, resourceSchema, dataMap); err != nil {
			return false, err
		}
		return true, err
	}

	return false, UpdateResource(context, dataStore, identityService, resourceSchema, resourceID, dataMap)
}
예제 #10
0
//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)
	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_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)
	}
	filter := transaction.IDFilter(resourceID)
	if tenantIDs != nil {
		filter["tenant_id"] = tenantIDs
	}
	object, err := mainTransaction.Fetch(resourceSchema, filter)

	if err != nil || object == nil {
		return ResourceError{err, "", NotFound}
	}

	response := map[string]interface{}{}
	response[resourceSchema.Singular] = object.Data()
	context["response"] = response

	if err := extension.HandleEvent(context, environment, "post_show_in_transaction"); err != nil {
		return err
	}
	return
}
예제 #11
0
// UpdateResourceInTransaction updates resource in db in transaction
func UpdateResourceInTransaction(
	context middleware.Context,
	resourceSchema *schema.Schema, resourceID string,
	dataMap map[string]interface{}, tenantIDs []string) error {

	manager := schema.GetManager()
	mainTransaction := context["transaction"].(transaction.Transaction)
	environmentManager := extension.GetManager()
	environment, ok := environmentManager.GetEnvironment(resourceSchema.ID)
	if !ok {
		return fmt.Errorf("No environment for schema")
	}
	filter := transaction.IDFilter(resourceID)
	if tenantIDs != nil {
		filter["tenant_id"] = tenantIDs
	}
	resource, err := mainTransaction.Fetch(
		resourceSchema, filter)
	if err != nil {
		return ResourceError{err, err.Error(), WrongQuery}
	}

	policy := context["policy"].(*schema.Policy)
	// apply property filter
	err = policy.ApplyPropertyConditionFilter(schema.ActionUpdate, resource.Data(), dataMap)
	if err != nil {
		return ResourceError{err, "", Unauthorized}
	}

	err = resource.Update(dataMap)
	if err != nil {
		return ResourceError{err, err.Error(), WrongData}
	}
	context["resource"] = resource.Data()

	if err := extension.HandleEvent(context, environment, "pre_update_in_transaction"); err != nil {
		return err
	}

	dataMap, ok = context["resource"].(map[string]interface{})
	if !ok {
		return fmt.Errorf("Resource not JSON: %s", err)
	}
	resource, err = manager.LoadResource(resourceSchema.ID, dataMap)
	if err != nil {
		return fmt.Errorf("Loading Resource failed: %s", err)
	}

	err = mainTransaction.Update(resource)
	if err != nil {
		return ResourceError{err, fmt.Sprintf("Failed to store data in database: %v", err), UpdateFailed}
	}

	response := map[string]interface{}{}
	response[resourceSchema.Singular] = resource.Data()
	context["response"] = response

	if err := extension.HandleEvent(context, environment, "post_update_in_transaction"); err != nil {
		return err
	}

	return nil
}
예제 #12
0
파일: db_test.go 프로젝트: vozhyk-/gohan
					}
					_, _, err := tx.List(networkSchema, filter, nil)
					Expect(err).To(HaveOccurred())
				})

				It("Shows related resources", func() {
					list, num, err := tx.List(serverSchema, nil, nil)
					Expect(err).ToNot(HaveOccurred())
					Expect(num).To(Equal(uint64(1)))
					Expect(list).To(HaveLen(1))
					Expect(list[0].Data()).To(HaveKeyWithValue("network", HaveKeyWithValue("name", networkResource1.Data()["name"])))
					Expect(tx.Commit()).To(Succeed())
				})

				It("Fetches an existing resource", func() {
					networkResourceFetched, err := tx.Fetch(networkSchema, transaction.IDFilter(networkResource1.ID()))
					Expect(err).ToNot(HaveOccurred())
					Expect(networkResourceFetched).To(util.MatchAsJSON(networkResource1))
					Expect(tx.Commit()).To(Succeed())
				})

				It("Updates the resource properly", func() {
					By("Not allowing to update some fields")
					Expect(networkResource1.Update(map[string]interface{}{"id": "new_id"})).ToNot(Succeed())

					By("Updating other fields")
					Expect(networkResource1.Update(map[string]interface{}{"name": "new_name"})).To(Succeed())
					Expect(tx.Update(networkResource1)).To(Succeed())
					Expect(tx.Commit()).To(Succeed())
				})
예제 #13
0
파일: sync.go 프로젝트: vozhyk-/gohan
//MonitoringUpdate updates the state in the db based on the sync event
func MonitoringUpdate(response *gohan_sync.Event, server *Server) error {
	dataStore := server.db
	schemaPath := "/" + strings.TrimPrefix(response.Key, monitoringPrefix)
	var curSchema = schema.GetSchemaByPath(schemaPath)
	if curSchema == nil || !curSchema.StateVersioning() {
		log.Debug("Monitoring update on unexpected path '%s'", schemaPath)
		return nil
	}
	resourceID := curSchema.GetResourceIDFromPath(schemaPath)

	tx, err := dataStore.Begin()
	if err != nil {
		return err
	}
	defer tx.Close()
	err = tx.SetIsolationLevel(transaction.GetIsolationLevel(curSchema, MonitoringUpdateEventName))
	if err != nil {
		return err
	}
	curResource, err := tx.Fetch(curSchema, transaction.IDFilter(resourceID))
	if err != nil {
		return err
	}
	resourceState, err := tx.StateFetch(curSchema, transaction.IDFilter(resourceID))
	if err != nil {
		return err
	}
	if resourceState.ConfigVersion != resourceState.StateVersion {
		return nil
	}
	var ok bool
	monitoringVersion, ok := response.Data["version"].(float64)
	if !ok {
		return fmt.Errorf("No version in monitoring information")
	}
	if resourceState.ConfigVersion != int64(monitoringVersion) {
		return nil
	}
	resourceState.Monitoring, ok = response.Data["monitoring"].(string)
	if !ok {
		return fmt.Errorf("No monitoring in monitoring information")
	}

	environmentManager := extension.GetManager()
	environment, haveEnvironment := environmentManager.GetEnvironment(curSchema.ID)
	context := map[string]interface{}{}
	context["resource"] = curResource.Data()
	context["schema"] = curSchema
	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()
}
예제 #14
0
파일: sync.go 프로젝트: vozhyk-/gohan
//StateUpdate updates the state in the db based on the sync event
func StateUpdate(response *gohan_sync.Event, server *Server) error {
	dataStore := server.db
	schemaPath := "/" + strings.TrimPrefix(response.Key, statePrefix)
	var curSchema = schema.GetSchemaByPath(schemaPath)
	if curSchema == nil || !curSchema.StateVersioning() {
		log.Debug("State update on unexpected path '%s'", schemaPath)
		return nil
	}
	resourceID := curSchema.GetResourceIDFromPath(schemaPath)

	tx, err := dataStore.Begin()
	if err != nil {
		return err
	}
	defer tx.Close()
	err = tx.SetIsolationLevel(transaction.GetIsolationLevel(curSchema, StateUpdateEventName))
	if err != nil {
		return err
	}
	curResource, err := tx.Fetch(curSchema, transaction.IDFilter(resourceID))
	if err != nil {
		return err
	}
	resourceState, err := tx.StateFetch(curSchema, transaction.IDFilter(resourceID))
	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["schema"] = curSchema
		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()
}
예제 #15
0
				It("Should work", func() {
					possibleEvent = gohan_sync.Event{
						Action: "this is ignored here",
						Data: map[string]interface{}{
							"version": float64(1),
							"error":   "",
							"state":   "Ni malvarmetas",
						},
						Key: statePrefix + networkResource.Path(),
					}
					Expect(srv.StateUpdate(&possibleEvent, server)).To(Succeed())

					tx, err := wrappedTestDB.Begin()
					Expect(err).ToNot(HaveOccurred())
					defer tx.Close()
					afterState, err := tx.StateFetch(networkSchema, transaction.IDFilter(networkResource.ID()))
					Expect(err).ToNot(HaveOccurred())
					Expect(tx.Commit()).To(Succeed())
					Expect(afterState.ConfigVersion).To(Equal(int64(1)))
					Expect(afterState.StateVersion).To(Equal(int64(1)))
					Expect(afterState.State).To(Equal("Ni malvarmetas"))
					Expect(afterState.Error).To(Equal(""))
					Expect(afterState.Monitoring).To(Equal(""))
				})

				It("Should ignore backwards updates", func() {
					possibleEvent = gohan_sync.Event{
						Action: "this is ignored here",
						Data: map[string]interface{}{
							"version": float64(1),
							"error":   "",