Documentation
¶
Overview ¶
Package cliutil holds the CR-agnostic plumbing shared by seictl's `network` and `node` command trees: the -o printer, the metav1.Status error discipline, kubeconfig/namespace resolution, and the --set/--override/--genesis-override expression parsers. Everything here is independent of which GVK a tree binds (that lives in internal/seiapi plus each tree's gvk.go); the per-tree render() functions differ only in their discrete flags and apply-time auto-wiring.
Index ¶
- Variables
- func ApplyGenesisOverride(root map[string]interface{}, expr string, fieldPath ...string) error
- func ApplyOverride(root map[string]interface{}, expr string, fieldPath ...string) error
- func ApplySet(root map[string]interface{}, expr string) error
- func EmitStatus(w io.Writer, err error)
- func MakePrinter(format string) (printers.ResourcePrinter, error)
- func MatchPhase(obj *unstructured.Unstructured, until string) (bool, error)
- func MatchPhaseAtLeastGeneration(obj *unstructured.Unstructured, until string, minGeneration int64) (bool, error)
- func NewClient(cfg *rest.Config) (client.Client, error)
- func ParseGenesisAccount(entry string) (string, string, error)
- func RejectCPULimit(root map[string]interface{}) error
- func ResolveStoragePerformance(iops, throughput string) (string, error)
- func RunWatch(ctx context.Context, cfg *rest.Config, gvr schema.GroupVersionResource, ...) error
- func RunWatchGen(ctx context.Context, cfg *rest.Config, gvr schema.GroupVersionResource, ...) error
- func StoragePerformanceMenu() string
- func ToStatus(err error) *metav1.Status
- func UsageError(format string, args ...interface{}) error
- func ValidatePhase(until string, legal []string) error
- func ValidateQuantity(flag, value string) error
- func ValidateStoragePerformanceSelection(root map[string]interface{}) error
- func WatchExitError(err error, name, ns, until string, timeout time.Duration) error
- type Kubeconfig
- type StoragePerformanceOffering
Constants ¶
This section is empty.
Variables ¶
var Version = "dev"
Version is stamped onto the seictl.sei.io/version provenance annotation by both command trees' render(). Linker override:
-ldflags "-X 'github.com/sei-protocol/seictl/internal/cliutil.Version=$VERSION'"
`make build` wires version.json; bare `go build`/`go test` see "dev".
Functions ¶
func ApplyGenesisOverride ¶
ApplyGenesisOverride writes a single key=value pair into the string-keyed JSON-valued map at fieldPath (for SeiNetwork this is spec.genesis.overrides). The key is a dotted cosmos-module path (module.field[.field...]) — the first segment must be a key in app_state of the genesis JSON. Value parses as JSON if it parses (number, bool, object, array, or JSON-quoted string); otherwise it's stored as a raw string.
Distinct from ApplyOverride because the genesis-overrides map's value type is map[string]<JSON> rather than map[string]string, and the key shape is validated upstream by the sidecar's applyGenesisOverrides. Single-segment keys are rejected here so the user sees the issue at apply time rather than after the network has stalled retrying the assemble-genesis task.
func ApplyOverride ¶
ApplyOverride writes a single key=value pair into the string-keyed map at fieldPath (for SeiNode this is spec.overrides). Keys may contain dots because the overrides map's keys are themselves dotted TOML paths.
func ApplySet ¶
ApplySet writes a single dotted-path --set expression. Each segment is a map key, optionally suffixed with `[N]` to step into a list at index N after the key. Empty intermediate maps and lists are created on demand.
List-index rules:
- idx == len(list) appends a new element (extends the list by one).
- idx < len(list) sets in place on the existing element.
- idx > len(list) errors; sparse indices are not supported.
func EmitStatus ¶
EmitStatus writes err as a metav1.Status so callers can `jq -r .reason` to discriminate failure classes. Wraps non-Status errors as InternalError.
func MakePrinter ¶
func MakePrinter(format string) (printers.ResourcePrinter, error)
MakePrinter returns a printer for -o values: yaml (default), json, name (kind/name), jsonpath=<template>. Anything else is a usage error the caller surfaces via EmitStatus.
func MatchPhase ¶
func MatchPhase(obj *unstructured.Unstructured, until string) (bool, error)
MatchPhase decides whether a single CR event satisfies the --until condition. Returns (true, nil) on match, (false, error) on terminal Failed phase, (false, nil) otherwise so the watch keeps streaming. The CR-agnostic mechanism each tree shares; the legal --until set differs per tree and is validated at parse time (see ValidatePhase).
func MatchPhaseAtLeastGeneration ¶ added in v0.0.65
func MatchPhaseAtLeastGeneration(obj *unstructured.Unstructured, until string, minGeneration int64) (bool, error)
MatchPhaseAtLeastGeneration is MatchPhase gated on the controller having observed at least minGeneration. A terminal phase (Complete or Failed) is honored only once status.observedGeneration catches up to the generation the caller applied, so an apply-then-watch cannot false-green on — or replay the stale failure of — a prior run of a re-applied CR. minGeneration == 0 is the ungated case (observedGeneration defaults to 0), so MatchPhase's existing callers are unaffected.
func NewClient ¶
NewClient builds a controller-runtime client for unstructured SSA; no scheme registration needed since GVK is read off the object.
func ParseGenesisAccount ¶
ParseGenesisAccount parses a `<address>:<balance>` --genesis-account entry. The balance side accepts the standard cosmos coin format (one or more `<int><denom>` separated by commas — e.g. `1000usei,500uatom`).
func RejectCPULimit ¶ added in v0.0.72
RejectCPULimit fails a render carrying spec.resources.limits.cpu. No discrete flag writes that path, but --set can reach it, and the CRD's CEL rejects it at admission (seinode_types.go:152 — "resources.limits accepts only memory: seid deliberately carries no CPU limit").
Narrow by design: limits.memory is left alone because the CRD permits it when it equals requests.memory. Rejecting the whole limits block here would forbid a spelling the schema allows.
func ResolveStoragePerformance ¶ added in v0.0.72
ResolveStoragePerformance maps an operator-supplied (IOPS, throughput) pair to the name of the VolumeAttributesClass that encodes it. An empty string means the standard tier: no class name, so the caller leaves spec.dataVolume.storage.volumeAttributesClassName unset.
Refusing here rather than at admission is the point (Spec 001 Req 3.4). In the GitOps flow an unsupported pair that renders cleanly is not discovered until the CR has been committed, merged, and reconciled by Flux — and because the field is create-only, the remedy at that stage is a new chain rather than an edit.
func RunWatch ¶
func RunWatch(ctx context.Context, cfg *rest.Config, gvr schema.GroupVersionResource, ns, name, until string, timeout time.Duration, out io.Writer) error
RunWatch streams every event for the named resource as one NDJSON line on out, returning nil when MatchPhase(obj, until) is satisfied and a metav1.Status-shaped error on timeout / terminal Failed / API error.
func RunWatchGen ¶ added in v0.0.65
func RunWatchGen(ctx context.Context, cfg *rest.Config, gvr schema.GroupVersionResource, ns, name, until string, minGeneration int64, timeout time.Duration, out io.Writer) error
RunWatchGen is RunWatch with a generation gate: a terminal phase is honored only once status.observedGeneration >= minGeneration (see MatchPhaseAtLeastGeneration). Pass the generation returned by the apply so the watch cannot match a stale terminal result the controller has not re-confirmed for this apply. minGeneration == 0 is the ungated RunWatch.
func StoragePerformanceMenu ¶ added in v0.0.72
func StoragePerformanceMenu() string
StoragePerformanceMenu renders the supported set for an error message: every offering's pair alongside the class name it resolves to, plus the standard tier (Spec 001 Req 3.5).
The standard tier is a legal selection, not the absence of one (DR-001:81-88): omitting both flags leaves volumeAttributesClassName unset on the PVC, and the gp3 StorageClass defaults supply the baseline. A menu that listed only the named classes would read as if a selection were mandatory.
func ToStatus ¶
ToStatus extracts an apiserver metav1.Status from err (walking %w wraps), or synthesizes an InternalError for a plain Go error.
func UsageError ¶
UsageError reports CLI validation failures as Status{Reason:Invalid} (BadRequest) so the stderr discriminator above still works.
func ValidatePhase ¶
ValidatePhase rejects an --until value not in the resource's phase enum at parse time, so an illegal phase is a crisp Invalid usage error rather than a full-timeout wait. legal lists the allowed phases for the message.
func ValidateQuantity ¶ added in v0.0.72
ValidateQuantity rejects a resource-flag value the apiserver would reject at admission. Without it a `--memory 32GB` renders a CR that only fails once it has been committed, PR-merged, and picked up by Flux — the operator learns about the typo minutes later, from someone else's reconcile loop. Empty means "flag unset"; the preset default stands.
Parsing alone is not enough: ParseQuantity happily accepts "0" and "-5Gi", which the CRD's CEL then rejects for requiring positive values (seinode_types.go:153 requests, :196 storage). Those land on the same post-merge reconcile as an unparseable value, so they fail here too.
func ValidateStoragePerformanceSelection ¶ added in v0.0.72
ValidateStoragePerformanceSelection is the final guard on the rendered object, mirroring RejectCPULimit: it re-reads what actually landed on spec.dataVolume.storage after every layer, so --set cannot smuggle in a class name that no supported pair resolves to, and cannot pair a supported class with a data volume too small to carry its IOPS.
Reading the object rather than the flags is what makes the guard total: --set spec.dataVolume.storage.volumeAttributesClassName=... and --set spec.dataVolume.storage.resources.requests.storage=... both reach these paths without going through ResolveStoragePerformance.
func WatchExitError ¶
WatchExitError shapes the err that came out of UntilWithSync into a metav1.Status so stderr discrimination (`jq -r .reason`) covers timeout / NotFound / terminal-Failed-phase / transient API failure uniformly.
Types ¶
type Kubeconfig ¶
type Kubeconfig struct {
// contains filtered or unexported fields
}
Kubeconfig honors --kubeconfig, $KUBECONFIG colon-merge, in-cluster fallback, and kubectl namespace precedence (override > context > "default") through a single deferred loader.
func LoadKubeconfig ¶
func LoadKubeconfig(explicitPath, namespaceOverride string) *Kubeconfig
LoadKubeconfig builds a deferred loader from an explicit path (or the standard resolution chain when empty) and an optional -n override.
func (*Kubeconfig) Namespace ¶
func (k *Kubeconfig) Namespace() (string, error)
Namespace resolves the effective namespace (override > context > "default").
func (*Kubeconfig) RESTConfig ¶
func (k *Kubeconfig) RESTConfig() (*rest.Config, error)
RESTConfig resolves the loader to a *rest.Config.
type StoragePerformanceOffering ¶ added in v0.0.72
type StoragePerformanceOffering struct {
IOPS int64 // provisioned IOPS
Throughput int64 // MiB/s
ClassName string // the VolumeAttributesClass that encodes the pair
}
StoragePerformanceOffering is one supported point on the gp3 performance menu: a pair of the standard performance parameters, and the VolumeAttributesClass that encodes that pair.
The direction is one-way (Spec 001 Req 3.2): the operator supplies the pair, the harness resolves the name. Nothing in this file accepts a class name as operator input — ValidateStoragePerformanceSelection reads one back off the rendered object only to reject a name that no offering resolves to.
func StoragePerformanceOfferings ¶ added in v0.0.72
func StoragePerformanceOfferings() []StoragePerformanceOffering
StoragePerformanceOfferings returns the supported set. Callers that need to exercise every tier — rather than the one that happens to be shipping today — range over this, so a tier added here is covered without an edit at the call site.
func (StoragePerformanceOffering) MinSizeGiB ¶ added in v0.0.72
func (o StoragePerformanceOffering) MinSizeGiB() int64
MinSizeGiB is the smallest data volume this offering's IOPS is legal on, rounding up: 10000 IOPS needs 20 GiB.