-
Notifications
You must be signed in to change notification settings - Fork 241
Support hybrid datastore for Organization Units #886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive support for hybrid datastore functionality for Organization Units and significantly expands the export API to support multiple resource types beyond just applications. The changes enable immutable resource management for Identity Providers, Notification Senders, User Schemas, and Organization Units through file-based YAML configurations.
Key Changes:
- Hybrid datastore support for Organization Units (combining file-based and database stores)
- Extended export functionality for Identity Providers, Notification Senders, and User Schemas
- File-based store implementations for IDP, Notification Senders, User Schemas, and OUs
- Immutable resource mode checks in service layers to prevent modifications
- Enhanced parameterization for IDP properties in export templates
Reviewed changes
Copilot reviewed 48 out of 48 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
backend/internal/ou/hybrid_store.go |
Implements hybrid store combining file-based and database stores for OUs |
backend/internal/ou/file_based_store.go |
File-based storage implementation for Organization Units |
backend/internal/ou/init.go |
OU initialization with hybrid store support and topological sorting |
backend/internal/idp/file_based_store.go |
File-based storage for Identity Providers |
backend/internal/idp/service.go |
Immutable mode checks for IDP CRUD operations |
backend/internal/notification/file_based_store.go |
File-based storage for Notification Senders |
backend/internal/notification/init.go |
Notification sender initialization with file-based support |
backend/internal/userschema/file_based_store.go |
File-based storage for User Schemas |
backend/internal/userschema/init.go |
User schema initialization with file-based support |
backend/internal/system/export/service.go |
Extended export service supporting multiple resource types |
backend/internal/system/export/parameterizer.go |
Dynamic property parameterization for IDP exports |
backend/internal/system/export/template_rules.go |
Template rules for IDP property parameterization |
backend/internal/system/export/model.go |
Added fields for IDPs, notification senders, and user schemas |
backend/internal/system/file_based_runtime/manager.go |
Returns empty array instead of error for non-existent directories |
tests/integration/export/exportapi_test.go |
Comprehensive integration tests for IDP export functionality |
docs/guides/immutable-configurations/*.md |
Updated documentation for IDP support |
|
|
||
| // GetOrganizationUnitList retrieves root organization units from both stores with pagination. | ||
| // File-based OUs are returned first, followed by database OUs. | ||
| func (h *ouHybridStore) GetOrganizationUnitList(limit, offset int) ([]OrganizationUnitBasic, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handling pagination is going to be complex
| _, err := h.fileStore.GetOrganizationUnit(ou.ID) | ||
| if err == nil { | ||
| return errors.New("cannot create organization unit: ID conflicts with immutable file-based OU") | ||
| } | ||
| if err != ErrOrganizationUnitNotFound { | ||
| return fmt.Errorf("error checking file store: %w", err) | ||
| } | ||
|
|
||
| // Check handle conflict in file store | ||
| hasConflict, err := h.fileStore.CheckOrganizationUnitHandleConflict(ou.Handle, ou.Parent) | ||
| if err != nil { | ||
| return fmt.Errorf("error checking handle conflict in file store: %w", err) | ||
| } | ||
| if hasConflict { | ||
| return errors.New("cannot create organization unit: handle conflicts with immutable file-based OU") | ||
| } | ||
|
|
||
| // Check name conflict in file store | ||
| hasConflict, err = h.fileStore.CheckOrganizationUnitNameConflict(ou.Name, ou.Parent) | ||
| if err != nil { | ||
| return fmt.Errorf("error checking name conflict in file store: %w", err) | ||
| } | ||
| if hasConflict { | ||
| return errors.New("cannot create organization unit: name conflicts with immutable file-based OU") | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this part of the service layer?
Service layer will call hybridStore.CheckOrganizationUnitNameConflict and hybridStore will check from both stores
| // Check if exists in file store (immutable) | ||
| _, err := h.fileStore.GetOrganizationUnit(ou.ID) | ||
| if err == nil { | ||
| return errors.New("cannot update organization unit: exists in immutable file-based store") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this means when listing the resource or getting the resource, a flag needs to be sent to indicate whether the resource is readOnly. Else handling the UX in developer portal is going to be problem.
In highlevel, we need think though this hybrid pattern a bit more.
Purpose
Support hybrid datastore for Organization Units