-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Specification
CDSS
Currently, VaultInternal utilizes the create-destroy pattern. We're considering instead refactoring this into a create-destroy-start-stop pattern. This would allow us to align function usage between VaultManager and VaultInternal as follows:
VaultManager |
VaultInternal |
|---|---|
createVault |
createVaultInternal |
openVault |
start |
closeVault |
stop |
destroyVault |
destroy |
The meat of the logic should now be in 2 static methods of VaultInternal, representing "smart asynchronous creators" of VaultInternal. These should be:
VaultInternal.createVaultInternal - creates a new vault from scratch, think `git init`
VaultInternal.cloneVaultInternal - clones a vault, think `git clone`
creating a VaultInternal instance with new or existing state should use VaultInternal.createVaultInternal. First time cloning of a vault should use VaultInternal.cloneVaultInternal. Get all the isogit related side-effects (client-side logic) into these static methods, the VaultManager would only manage any additional metadata.
The start method now has to setup internal state, specifically Git state, it needs to initialize the repository and also perform the initial commit, however it has to be idempotent, so if these actions are already done, it won't bother with it.
The stop cannot stop efs, because the EFS lifecycle is handled outside by VaultManager
The destroy should then destroy the Vault internal state, however additional destruction management would have to occur inside the VaultManager which might mean it has to construct (and thus load into-memory) the instance before it can destroy it.
The cloning and pulling code should work using withF and withG as used by NodeConnectionManager. The cloning and pulling will need to have access to the ACL domain to ensure that permissions are properly set. Because permission checking occurs inside VaultManager and not VaultInternal and occurs before VaultInternal functions are executed, this would imply that VaultManager has access to the ACL and is bound to the ACL. Which would mean the meat of logic discussed above should be in VaultManager.
Metadata
The VaultInternal now needs to maintain its own DB domain to store vault related metadata. 2 new properties are relevant:
dirty- this is a Boolean that determines whether the vault is in a dirty state or notremote- if this contains a stringnodeId:vaultId, then this vault should be considered a "remote" vault and must be immutable - see Investigate usage of theremotefield for vault metadata optimisation #309 and No longer preserve vault ID oncloneVault#253
The internal domain is better than storing a POJO in the VaultManager. That logic should be removed in favor of VaultInternal having it's own internal domain, which is more efficient and more flexible.
Additional metadata along with the dirty Boolean can be added to enable us to fix #252. This will be important to ensure internal consistency of our vaults in the presence of program crashes and also inadvertent OS shutdowns or just program killing.
misc.
The implementations of the functions in VaultManager would internally call the respective function above in VaultInternal. This would also allow us to add any extra functionality that needs to be separate from the VaultInternal functions into the VaultManager. For example, on creation of a vault, there's a few factors that need to be considered:
- Locking:
VaultInternalhas no notion of the creation/destruction locks used in theObjectMapstructure, so this can be safely handled inVaultManager.createVault/destroyVault.
Conversely, we should remove any instances where we perform similar logic between the two corresponding functions, and ensure it's centralized in a single place.
Locking will be handled via two RWLock locks. One lock for the object map in VaultManager. The other lock for the VaultInternal instance. The VaultManager RWLock will handle the life cycle of the VaultInternal Instance. Write locking will be used for the creation/destroy lifecycle. read locking will be used with the WithVaults when accessing the vaults. The VaultInternal locking will be used for the respective readF/G and writeF/G functions.
Git repository: anything to do with git instantiation for the vault could also be centralised within VaultInternal.createVaultInternal
To ensure the integrity of the vaultName information we need to apply locking when reading and writing to the VaultName->VaultId mapping in the database. This is to ensure that when we check if a vaultName already exists in the mapping we can trust that this information is correct and avoid concurrency issues with vault creation and renaming.
Additional context
- As we discovered in Review and Refactor of
git/utils.tsfor Serving Vault Git Repositories #298, the usage of isogit is mostly client-side behavior. But server side behaviour is facilitated byVaultManagerand functions found insrc/git/utils.ts. - original comment on this Introducing vault sharing and the restrictions of pulling and cloning with vault permissions #266 (comment) based on discussion in our review with @scottmmorris https://vimeo.com/manage/videos/652339635
- discussion of
VaultInternal(fromcommitto end), as well as some discussion of CDSS withVaultInternalhttps://vimeo.com/manage/videos/652700328
A note on usage of the CDSS pattern:
create...: performs the dependency side-effects (i.e. creates any encapsulated dependencies before creating itself). That is, we can see this function as outside the instance of the classstart: performs the side-effects on the created instance (with the created instance coming from the constructor)
tasks
- Convert
VaultInternalto using the CDSS async-init pattern.- create a
createVaultInternalconstructor for creating aVaultInternalinstance on new or existing state. - create a
cloneVaultInternalconstructor for first time cloning of a vault. - all isogit related side effects and creating logic should be within these creation methods. Ideally
VaultManagershouldn't touch isogit at all. -
startmethod handles the creation of any state. This should be idempotent. this also handles anydbdomain creation. -
destroyshould destroy allVaultInternalstate.
- create a
- Cloning and pulling should use the with functions through the
NodeConnectionManager. - permissions will need to be checked before cloning and pulling.
- Move handling of metadata to inside of
VaultInternal- Implement a
dirtyfield for tracking if the git repo is in a dirty state. - Implement a
remotecontaining stringnodeId:vaultIdfor tracking remote node and vault. this is also used to check if the vault is immutable. - Any other metadata needs to be moved here as well.
- Add ability to VaultManager to access the metadata for checking if a vault exists and checking/updating vaultName.
- Implement a
- Update
VaultManagerandVaultInternalto useRWLocklocks.- Use object map write locking for
VaultInternallifecycle. - Use object map readLocking for accessing
VaultInternalcontents. - Use
VaultInternalwrite/read locking for the read/write functions. -
VaultManagergit handling functions should be using both read locks. -
VaultInternal.pullVaultshould respect the write lock. - add locking for
vaultName->vaultIdmetadata.
- Use object map write locking for
- Review and update tests for...
-
VaultManagerobject map life-cycle. -
VaultManagerobject map locking. -
VaultInternallife-cycle. -
VaultInternallocking. - git clone/pull permissions testing.
- concurrently creating vaults test.
- test for
VaultInternal.pullVaultlocking
-