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.
209 lines
8.4 KiB
Plaintext
209 lines
8.4 KiB
Plaintext
MARKER:
|
|
- Move to pegjs-import
|
|
- Replace all 'this is a bug' errors with @joepie91/unreachable
|
|
- LVM / mdraid support and tabs (+ complete refactoring LVM implementation)
|
|
- Switch hashing to argon2id
|
|
- Switch child_process to execa
|
|
|
|
Next:
|
|
- ISO/image download and storage
|
|
- Progress streams + cancellation of operation
|
|
- lossy-push-value-stream for progress updates
|
|
- Audit logging
|
|
- VM creation/initialization + GraphQL API for VM management
|
|
|
|
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
|
|
- Image feeds for disk images / installation media
|
|
- Allow arbitrary amount of image feeds to be configured
|
|
- Make auto-update optional, and allow a 'whitelist every source host explicitly' setting, for improved supply chain security
|
|
- Eventually figure out a sensible signature mechanism for this, that also transitively verifies that the content at the source URLs has not changed
|
|
- Make sure to clearly document the security caveats
|
|
- The ID of each image from a feed is colon-prefixed with the feed ID, to prevent namespace conflicts
|
|
- Eventually allow highly-restricted Markdown for the image descriptions?
|
|
|
|
----------------------
|
|
|
|
QEMU setup:
|
|
- Ensure to set discard=on for any -blockdev arguments to QEMU - this makes it so that deletes on the guest FS actually free up blocks in the host volume when using a thin pool or sparse file, preventing endless growth of volumes over time.
|
|
|
|
----------------------
|
|
|
|
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.
|
|
|
|
|
|
----------------
|
|
|
|
Disk images
|
|
Installation media
|
|
Preinstalled images
|
|
Host nodes
|
|
Hardware
|
|
Storage pools
|
|
Network pools
|
|
VMs
|
|
|
|
|
|
SCHEMA
|
|
======
|
|
|
|
storage pools
|
|
-------------
|
|
|
|
id
|
|
type: lvm | folder
|
|
vg_name?
|
|
path?
|
|
|
|
|
|
storage volumes
|
|
---------------
|
|
|
|
id (name is derived from this)
|
|
pool_id
|
|
|
|
|
|
instances
|
|
---------
|
|
|
|
id (name is derived from this, prefixed with cvm-)
|
|
attached_image_id
|
|
|
|
storage_attachments
|
|
----------------
|
|
|
|
instance_id
|
|
volume_id
|
|
is_primary
|
|
|
|
MARKER: Implement storage pool setup + network pools + VM spawn
|
|
|
|
FIXME: disconnecting the SMART-broken drive during a slow storage-devices overview load causes *all* storage devices to show as unknown
|