managerkit

package module
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: MIT Imports: 6 Imported by: 0

README

managerkit

github.com/confighub/sdk/managerkit holds the shared parts of a manager tool: a command-line tool that manages one concern across a fleet of ConfigHub Units, such as namespaces, workload scheduling, autoscaling or observability. Each such tool knows its own concern -- which resources to read, which functions to run and what rules to enforce -- and gets the rest from this module: where shared policy lives, how a policy pack is installed and reported, how reusable edits are stored and applied, and how a write reports what it changed. Tools built this way have the same commands, flags and output, so an operator, or an agent, that has used one can use the next.

cub-manage, a cub plugin that manages Kubernetes namespaces, RBAC, network policy, workloads, scheduling, autoscaling and observability as one command group each, is built on it.

What it is not

Reading a fleet is core/cubapi: SnapshotLoader joins a Unit query with a resource query, and MemoizedClient caches the reads. The generic command-line surface is cliutil: QueryFlags and its Space-label shorthands, output parsing and tables. Rendering a ConfigDiff is cubutil/diffview. What is in managerkit is a convention of manager tools rather than a ConfigHub primitive, which is why it is a module of its own.

Packages

  • managerkit -- CommonSpace, the Space (common) where manager tools keep what an organization shares: guardrail Triggers, the profile library, and the Attributes a validating function reads. One Space rather than one per tool, because a Space selects guardrails with one WhereTrigger naming one policy Space; every command that writes there takes a flag to put it elsewhere. Also AddOutputFlag and Render, the -o/--output flag every command has. And BindComponentResolver, which lets --component name a Component by slug in a command whose flags come from cliutil.QueryFlags. It defaults to JSON rather than a table, because these tools are read by agents as often as by people; json, yaml, table, jq=<expr> and yq=<expr> are accepted.
  • managerkit/guardrails -- a tool's policy pack: a group of validating Triggers defined once in the policy Space and selected by the WhereTrigger of each Space, or Target, that opts into the group. A tool supplies a Pack of Rules, each a CEL expression over the resource r run by vet-cel, or another validating function; the package supplies guardrails install (dry run by default, --commit to apply) and guardrails status, and for a rule that needs more than one resource to decide, guardrails annotate, which writes the tool's findings onto each Unit as an annotation the rule then checks. A resource is excepted from one rule by the annotation exceptions.guardrails.confighub.com/<rule>, whose value says why; guardrails exception adds and removes them, and lists every resource excepted, with its reason. Each rule's Trigger is created with a backing Unit, which keeps its revision history. Rules install as warnings and are made blocking with cub trigger update <slug> --space <policy-space> --unwarn, which a later install leaves in place. A Space that already selects Triggers its own way is reported and left alone.
  • managerkit/profiles -- a library of profiles: named, reusable edits stored as ConfigHub Invocations, each a function with preset arguments and optional parameters supplied at apply time. A profile that edits one kind of resource names it in WhereResource, which is stored with the profile, since a Unit can hold several resources and a function otherwise runs on all of them. A tool declares a Library of Specs and gets profile install, profile list and profile apply <profile> <space>/<unit>, plus fleet-edit --profile <slug> to apply one profile to every Unit a filter selects; it refuses to run without one. Each profile's Invocation is created with a backing Unit, which keeps its revision history.
  • managerkit/write -- the reporting half of a mutating command: ParseUnitRef for the <space>/<unit> argument, Change for the change description and dry run, and ReportMutations, which renders the function results per Unit, followed on a table by the diff of each Unit that changed or, on a dry run, would change, and after a commit by ReleaseNote: nothing reaches a Target until the Space is released.
  • managerkit/configmaps -- the configmaps pack: the Mutation Triggers that roll a workload when a ConfigMap it uses changes, and bound the immutable ConfigMaps render-configmap leaves behind. SetHash runs set-hash data binaryData on the ConfigMaps not rendered, keeping the confighub.com/Hash that Needs/Provides carries to each pod template's hash.confighub.com/<configmap> annotation, and Prune runs prune-configmaps. Both are labeled Pack: configmaps (Labels). cub variant upload creates them in a Space that runs its own Triggers; a tool installs them into a policy Space for the Spaces that select their Triggers from there.

Example

A tool declares its pack and library and adds the commands they build to its own:

package cli

import (
	"context"

	"github.com/spf13/cobra"

	"github.com/confighub/sdk/core/cubapi"
	api "github.com/confighub/sdk/core/function/api"
	"github.com/confighub/sdk/managerkit/guardrails"
	"github.com/confighub/sdk/managerkit/profiles"
)

func preflight(ctx context.Context) (*cubapi.Client, error) {
	// Verify the ConfigHub session and return a client.
	return nil, nil
}

var pack = guardrails.Pack{
	Group: "scheduling",
	Rules: []guardrails.Rule{{
		Slug:        "deployment-needs-node-selector",
		Description: "Warns on a Deployment with no nodeSelector.",
		Expression:  "r.kind != 'Deployment' || has(r.spec.template.spec.nodeSelector)",
	}},
}

var library = profiles.Library{
	Tool:           "cub-manage",
	Noun:           "placement profile",
	Target:         "a workload",
	Preflight:      preflight,
	InvocationName: func() string { return "cub manage" },
	Profiles: []profiles.Spec{{
		Slug:        "node-pool",
		Description: "set-yq: pin to the node pool named by --param pool",
		Function:    "set-yq",
		Args: []api.FunctionArgument{
			profiles.Arg("yq-expression", `.spec.template.spec.nodeSelector.pool = $params.pool`),
			profiles.YQParamArg("pool"),
		},
		Params: []profiles.Param{{Name: "pool"}},
	}},
}

func addCommands(root *cobra.Command) {
	guardrailsCmd := &cobra.Command{Use: "guardrails", Short: "Install and inspect the scheduling policy pack"}
	guardrailsCmd.AddCommand(pack.InstallCmd(preflight), pack.StatusCmd(preflight))
	root.AddCommand(guardrailsCmd, library.Command())
}

The rule opens with a kind test so that it passes for every resource it does not govern; a rule that fails everything else it is run on blocks those Units once it is made blocking.

Documentation

Overview

Package managerkit holds what manager tools -- command-line tools that each manage one concern across a fleet, such as namespaces, scheduling or autoscaling -- agree on. Its subpackages are the shared parts of such a tool: guardrails installs a policy pack, profiles a library of reusable edits, and write reports what a mutating command did.

Reading a fleet is github.com/confighub/sdk/core/cubapi (SnapshotLoader, MemoizedClient), and the generic command-line surface is github.com/confighub/sdk/cliutil (QueryFlags and its Space-label shorthands, the output and table helpers). What is here is a convention of manager tools rather than a ConfigHub primitive.

Index

Constants

View Source
const (
	OutputJSON  = "json"
	OutputTable = "table"
)

Output formats. JSON is the default so that the tools compose; a table is for a human reading one answer.

A command does not compare against these: Render decides, and a command only renders its table when Render declines. They are here because the flag's default is one of them.

View Source
const CommonSpace = "common"

CommonSpace is the Space manager tools put whatever an organization keeps in common: the guardrail Triggers, the profile library, the Attributes a validating function reads.

One Space rather than one per tool. A Space selects guardrails with one WhereTrigger naming one policy Space and the groups it has opted into, so per-tool policy Spaces could not be combined in it. Profiles have no such constraint, but an operator should still have one place to look rather than one per tool they happen to have installed.

Every command that writes here takes a flag to put it elsewhere.

Variables

This section is empty.

Functions

func AddOutputFlag

func AddOutputFlag(cmd *cobra.Command, dest *string)

AddOutputFlag registers the -o/--output flag every command in a manager tool has.

The default is JSON rather than a table, which is the opposite of what a person at a terminal usually wants. Manager tools are meant to be read by an agent as often as by a person, and an agent that has to parse a table is an agent that will eventually parse it wrong.

func BindComponentResolver added in v0.10.3

func BindComponentResolver(cmd *cobra.Command, q *cliutil.QueryFlags, preflight func(context.Context) (*cubapi.Client, error))

BindComponentResolver lets --component on q name a Component by slug as well as by ID. QueryFlags cannot look a slug up on its own, having no client, so this resolves it with the client preflight returns when the command runs.

func ProgressWriter

func ProgressWriter(cmd *cobra.Command, output string) io.Writer

ProgressWriter is where a command writes the lines it prints while it works: stdout under a table, which is text throughout, and stderr under every format Render writes, whose stdout has to hold the value alone for it to parse.

func Render

func Render(w io.Writer, output string, v any) (bool, error)

Render writes v in the format output names, reporting whether it did.

It handles every format that is a projection of the value itself: json, yaml, and the jq and yq expressions, which walk what the JSON is built from. It returns false for a table, which only the command can render -- a table's columns are a decision about what matters, not something derivable from the value.

So the calling convention is: ask Render first, and render the table only if it declined.

if done, err := managerkit.Render(out, output, report); done || err != nil {
	return err
}
printTable(cmd, report)
return nil

name, wide and custom-columns are refused. cliutil parses them and can render them over an entity with named columns, but these commands report their own models rather than entities, and no command here has named columns for one.

Types

This section is empty.

Directories

Path Synopsis
Package configmaps defines the configmaps pack: the Mutation Triggers that keep the hashes that roll a workload when a ConfigMap it uses changes, and that bound how many immutable ConfigMaps render-configmap leaves behind.
Package configmaps defines the configmaps pack: the Mutation Triggers that keep the hashes that roll a workload when a ConfigMap it uses changes, and that bound how many immutable ConfigMaps render-configmap leaves behind.
Package guardrails installs and inspects a tool's policy pack: a group of validating Triggers defined once in a policy Space and selected by the WhereTrigger of each Space, and Target, that opts into the group.
Package guardrails installs and inspects a tool's policy pack: a group of validating Triggers defined once in a policy Space and selected by the WhereTrigger of each Space, and Target, that opts into the group.
Package profiles is the profile library manager tools share: named, reusable edits stored as ConfigHub Invocations, applied to one Unit or to a selector of them.
Package profiles is the profile library manager tools share: named, reusable edits stored as ConfigHub Invocations, applied to one Unit or to a selector of them.
Package write is the surface the mutating commands of manager tools share: naming the Unit to write to, saying whether this is a dry run, and reporting what a function invocation did -- including, path by path, what it changed or on a dry run would change, so a reader can judge a change before committing it.
Package write is the surface the mutating commands of manager tools share: naming the Unit to write to, saying whether this is a dry run, and reporting what a function invocation did -- including, path by path, what it changed or on a dry run would change, so a reader can judge a change before committing it.

Jump to

Keyboard shortcuts

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