cliutil

package
v0.0.72 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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

func ApplyGenesisOverride(root map[string]interface{}, expr string, fieldPath ...string) error

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

func ApplyOverride(root map[string]interface{}, expr string, fieldPath ...string) error

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

func ApplySet(root map[string]interface{}, expr string) error

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

func EmitStatus(w io.Writer, err error)

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

func NewClient(cfg *rest.Config) (client.Client, error)

NewClient builds a controller-runtime client for unstructured SSA; no scheme registration needed since GVK is read off the object.

func ParseGenesisAccount

func ParseGenesisAccount(entry string) (string, string, error)

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

func RejectCPULimit(root map[string]interface{}) error

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

func ResolveStoragePerformance(iops, throughput string) (string, error)

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

func ToStatus(err error) *metav1.Status

ToStatus extracts an apiserver metav1.Status from err (walking %w wraps), or synthesizes an InternalError for a plain Go error.

func UsageError

func UsageError(format string, args ...interface{}) error

UsageError reports CLI validation failures as Status{Reason:Invalid} (BadRequest) so the stderr discriminator above still works.

func ValidatePhase

func ValidatePhase(until string, legal []string) error

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

func ValidateQuantity(flag, value string) error

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

func ValidateStoragePerformanceSelection(root map[string]interface{}) error

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

func WatchExitError(err error, name, ns, until string, timeout time.Duration) error

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL