//GetResources returns specified resources without calling non in_transaction events func GetResources(context middleware.Context, dataStore db.DB, resourceSchema *schema.Schema, filter map[string]interface{}, paginator *pagination.Paginator) error { return InTransaction( context, dataStore, transaction.GetIsolationLevel(resourceSchema, schema.ActionRead), func() error { return GetResourcesInTransaction(context, resourceSchema, filter, paginator) }, ) }
// 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 }
// GetSingleResource returns the resource specified by the schema and ID func GetSingleResource(context middleware.Context, dataStore db.DB, resourceSchema *schema.Schema, resourceID string) error { context["id"] = resourceID auth := context["auth"].(schema.Authorization) policy, err := loadPolicy(context, "read", strings.Replace(resourceSchema.GetSingleURL(), ":id", resourceID, 1), auth) if err != nil { return err } context["policy"] = policy 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"); 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) } if err := InTransaction( context, dataStore, transaction.GetIsolationLevel(resourceSchema, schema.ActionRead), func() error { return GetSingleResourceInTransaction(context, resourceSchema, resourceID, policy.GetTenantIDFilter(schema.ActionRead, auth.TenantID())) }, ); err != nil { return err } if err := extension.HandleEvent(context, environment, "post_show"); err != nil { return err } if err := ApplyPolicyForResource(context, resourceSchema); err != nil { return ResourceError{err, "", NotFound} } return nil }
// UpdateResource updates the resource specified by the schema and ID using the dataMap func UpdateResource( context middleware.Context, dataStore db.DB, identityService middleware.IdentityService, resourceSchema *schema.Schema, resourceID string, dataMap map[string]interface{}, ) error { context["id"] = resourceID //load environment environmentManager := extension.GetManager() environment, ok := environmentManager.GetEnvironment(resourceSchema.ID) if !ok { return fmt.Errorf("No environment for schema") } auth := context["auth"].(schema.Authorization) //load policy policy, err := loadPolicy(context, "update", strings.Replace(resourceSchema.GetSingleURL(), ":id", resourceID, 1), auth) if err != nil { return err } context["policy"] = policy //fillup default values if tenantID, ok := dataMap["tenant_id"]; ok && tenantID != nil { dataMap["tenant_name"], err = identityService.GetTenantName(tenantID.(string)) } if err != nil { return ResourceError{err, err.Error(), Unauthorized} } //check policy err = policy.Check(schema.ActionUpdate, auth, dataMap) delete(dataMap, "tenant_name") if err != nil { return ResourceError{err, err.Error(), Unauthorized} } context["resource"] = dataMap if err := extension.HandleEvent(context, environment, "pre_update"); err != nil { return err } if resourceData, ok := context["resource"].(map[string]interface{}); ok { dataMap = resourceData } if err := InTransaction( context, dataStore, transaction.GetIsolationLevel(resourceSchema, schema.ActionUpdate), func() error { return UpdateResourceInTransaction(context, resourceSchema, resourceID, dataMap, policy.GetTenantIDFilter(schema.ActionUpdate, auth.TenantID())) }, ); err != nil { return err } if err := extension.HandleEvent(context, environment, "post_update"); err != nil { return err } if err := ApplyPolicyForResource(context, resourceSchema); err != nil { return ResourceError{err, "", NotFound} } return nil }
// CreateResource creates the resource specified by the schema and dataMap func CreateResource( context middleware.Context, dataStore db.DB, identityService middleware.IdentityService, resourceSchema *schema.Schema, dataMap map[string]interface{}, ) error { manager := schema.GetManager() // Load environment environmentManager := extension.GetManager() environment, ok := environmentManager.GetEnvironment(resourceSchema.ID) if !ok { return fmt.Errorf("No environment for schema") } auth := context["auth"].(schema.Authorization) //LoadPolicy policy, err := loadPolicy(context, "create", resourceSchema.GetPluralURL(), auth) if err != nil { return err } _, err = resourceSchema.GetPropertyByID("tenant_id") if _, ok := dataMap["tenant_id"]; err == nil && !ok { dataMap["tenant_id"] = context["tenant_id"] } if tenantID, ok := dataMap["tenant_id"]; ok && tenantID != nil { dataMap["tenant_name"], err = identityService.GetTenantName(tenantID.(string)) if err != nil { return ResourceError{err, err.Error(), Unauthorized} } } //Apply policy for api input err = policy.Check(schema.ActionCreate, auth, dataMap) if err != nil { return ResourceError{err, err.Error(), Unauthorized} } delete(dataMap, "tenant_name") // apply property filter err = policy.ApplyPropertyConditionFilter(schema.ActionCreate, dataMap, nil) if err != nil { return ResourceError{err, err.Error(), Unauthorized} } context["resource"] = dataMap if id, ok := dataMap["id"]; !ok || id == "" { dataMap["id"] = uuid.NewV4().String() } context["id"] = dataMap["id"] if err := extension.HandleEvent(context, environment, "pre_create"); err != nil { return err } if resourceData, ok := context["resource"].(map[string]interface{}); ok { dataMap = resourceData } //Validation err = resourceSchema.ValidateOnCreate(dataMap) if err != nil { return ResourceError{err, fmt.Sprintf("Validation error: %s", err), WrongData} } resource, err := manager.LoadResource(resourceSchema.ID, dataMap) if err != nil { return err } //Fillup default err = resource.PopulateDefaults() if err != nil { return err } context["resource"] = resource.Data() if err := InTransaction( context, dataStore, transaction.GetIsolationLevel(resourceSchema, schema.ActionCreate), func() error { return CreateResourceInTransaction(context, resource) }, ); err != nil { return err } if err := extension.HandleEvent(context, environment, "post_create"); err != nil { return err } if err := ApplyPolicyForResource(context, resourceSchema); err != nil { return ResourceError{err, "", Unauthorized} } return nil }
//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() }
//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() }