You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cvm/notes.txt

141 lines
6.7 KiB
Plaintext

MARKER:
- Replace local `unreachable` with @joepie91/unreachable
- Update all Validatem usage to new validateArguments API
- LVM / mdraid support and tabs (+ complete refactoring LVM implementation)
- Switch hashing to argon2id
- Switch child_process to execa
IDEAS:
- contextual sidebar on add/edit form pages that shows/highlights all the relevant data for deciding what to fill into the form
- eg. all storage devices and pools when creating a new volume
- or highlighting the currently-editing volume in an edit screen
----------------------
API architecture
- Level 0: (src/wrappers) Data source implementations
- Eg. output-parsing wrappers using `execBinary`, but implementations might also be provided by a third-party module entirely
- The APIs for these are specific to the implementation
- Level 1: (src/api/data-sources) Data source connectors
- These provide a standardized interface over the data source implementations, exposing each individual semantically distinct operation as a function
- That function takes either of:
- An array of identifiers of 'items' to obtain information about
- The `All` symbol to obtain all items
- Level 2: (src/graphql/data-object) The 'data object' abstraction
- Takes in a definition of a GraphQL object's structure, and which properties should be obtained from what data source connectors
- Definition structured as (dataSource => (field => dataGetter))
- The `dataSource` may either be:
- The name of the data source connector to obtain the source data from
- The special `LocalProperties` symbol, which specifies:
- Data that is immediately known upon object instantiation, and doesn't require accessing a data source
- Eg. the identifier that the object was initialized with
- Functions that produce data objects of other types, the instantiation of which doesn't require accessing a data source
- Eg. because it is initialized with the same identifier
- The `field` may either be:
- A string name, in which case it defines how to resolve that specific property on the data object
- The special `ID` symbol, in which case it defines by which identifier to request the 'thing' from the data source connector.
- Usually this will be the identifier that the data object is initialized with.
- The `dataGetter` is either:
- A function, mapping from the source data to a value, called with (sourceData, queryArgs, context)
- sourceData: The result object originating from the data source lookup
- queryArgs: The arguments passed to the property access in the GraphQL query
- context: The full GraphQL context + 'properties' key if DependsOn is used
- A string, specifying the property to extract from the source data, equivalent to `(sourceData) => sourceData[property]`
- NOTE: The dataSources are not specified directly in the data object definition! They're provided via GraphQL context separately.
- Level 3: (src/api/types)
- The actual data object definitions
- Parametric modules, take the full set of types as their argument
- Specified as a *function that instantiates and returns* a newly created data object, when initialized with some sort of identifier value
- Eg. the 'path' for a block device, or the 'ID' for a user
- The instantiation function is free to choose the arguments it accepts for initialization (and how to use them), but a destructured object is recommended
------------
Dynamic data lookup
Sometimes there are special cases where we can't (reliably) obtain particular data from the same source, eg. the correct data source connector to invoke may be dependent on some other data in the object. Need to figure out an API that allows representing this ergonomically.
Maybe have an async "resolve these data sources" API that can be used from within a custom handler? This would sidestep the issue where particularly complex cases are hard or impossible to represent in a declarative format, by just making it custom logic entirely.
Maybe something similar for resolving properties defined elsewhere on the object? Otherwise any custom handler in the [Dynamic] block would invoke the handlers for *all* of these dependencies (which are specified on a block level), even when they are not needed for that particular handler.
-------------
execBinary redesign
- requireOnStdout
- expectOnStdout
- failOnStdout
- requireOnStderr
- expectOnStderr
- failOnStderr
Types of handling:
- requireOn*: a result must be produced by the parsing adapter
- expectOn*: a result *may* be produced by the parsing adapter
- failOn*: if a result is produced by the parsing adapter, that constitutes an error
Adapter:
A { create: Function, supportsStreams: Boolean } object that, upon initialization/calling `create`, returns a function that takes the string or stream of output, and returns a result or throws an error/NoResult. Example adapters:
- matchLiteral: match a literal string
- booleanResult: switches from "return undefined or throw NoResult" to "return true or false"
- matchRegex: match a regular expression and extract data
- matchPeg: run a PEG parser and use its output
- matchMultiple: run multiple adapters and combine the results into a single (keyed) object
matchMultiple example:
matchMultiple({
deviceName: matchRegex(/name: (.+)/, ([ name ]) => name),
isNVMe: matchLiteral("protocol: NVMe", { booleanResult: true })
})
- Different kinds of output handling:
- expect*: require that the handler produce a result
- if result: OK
- if no result: fail
- if parsing error: fail
- handle*: optionally produce a result
- if result: OK
- if no result: OK
- if parsing error: fail
- fail*: when output is detected, produce an error
- if result: fail
- if no result: OK
- if parsing error: fail
- expectStderr (convert stderr to success result) vs. detectStderr (convert stderr to thrown error)
- expectStdout
- expectEmptyOutput
Create various utility methods for parsing stdout/stderr, that can be used separately within the expect* and detect* methods
Some sort of matchAll([ .. ]) utility for returning the results of multiple handlers/extractors? Maybe follow the 'messages' model that PostCSS follows?
Interceptor model? That can also produce messages, and modify the flags and such of the invocation
TODO: Publish error-chain! Separating out the error chaining itself, from the display
Adapt from other cause-retaining error types
full-chain instanceof?
---------------
Glossary
Bind mount
"Mounts" a folder on one (mounted) filesystem, as a separate mount/filesystem, essentially mirroring it under another location
Loopback device
Virtual block device that can be mounted, and is backed by a *file* on another (mounted) filesystem.
----------------
Utilities
fuser
Show which processes use the named files, sockets, or filesystems.