agentcontrol

package
v0.0.0-...-59577d4 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (
	// ReportErrorCodeBatchIDInvalid: no batch_id, or one over 128 bytes.
	ReportErrorCodeBatchIDInvalid = "report_batch_id_invalid"
	// ReportErrorCodeInvalid: an entry is malformed (an empty entry, a
	// user_id of 0, fields_json that is not JSON).
	ReportErrorCodeInvalid = "report_invalid"
	// ReportErrorCodeCounterOverflow: bytes beyond the 64-bit counter range.
	ReportErrorCodeCounterOverflow = "report_counter_overflow"
	// ReportErrorCodeNodeGone: the stream's node no longer exists.
	ReportErrorCodeNodeGone = "report_node_gone"
	// ReportErrorCodeUnavailable: Control could not record the batch now
	// (its database failed). applied is false and error empty; the Agent
	// keeps the batch and resends it after ReportAck.retry_after_ms. Sent
	// only to an Agent that negotiated ReportsAttributeTransientAck.
	ReportErrorCodeUnavailable = "report_unavailable"
)

ReportAck.error_code (reports.v1).

View Source
const (
	ReportsAttributeTransientAck = "transient_ack"
	ReportsTransientAckV1        = "v1"
)

ReportsAttributeTransientAck is the Capability attribute of reports.v1 with which an Agent asks for a ReportAck of ReportErrorCodeUnavailable when Control cannot record a batch now, instead of no answer. Its value is ReportsTransientAckV1. Control echoes the attribute on its reports.v1 in HelloAck.server_capabilities when it sends such answers; without it, it sends none (an Agent that did not ask would drop the batch).

View Source
const (
	// MaintenanceErrorCodeSchemaUnsupported: the batch's version is not
	// MaintenanceSchemaV1.
	MaintenanceErrorCodeSchemaUnsupported = "maintenance_schema_unsupported"
	// MaintenanceErrorCodeBatchTooLarge: more than MaxMaintenanceBatchEvents
	// events, or more than MaxMaintenanceBatchBytes.
	MaintenanceErrorCodeBatchTooLarge = "maintenance_batch_too_large"
	// MaintenanceErrorCodeEventInvalid: the event is not a valid
	// anixops.maintenance/v1 event (ParseMaintenanceEvent).
	MaintenanceErrorCodeEventInvalid = "maintenance_event_invalid"
	// MaintenanceErrorCodeWrongNode: the event's node_id is not the
	// stream's node.
	MaintenanceErrorCodeWrongNode = "maintenance_event_wrong_node"
	// MaintenanceErrorCodeNodeGone: the stream's node no longer exists.
	MaintenanceErrorCodeNodeGone = "maintenance_node_gone"
	// MaintenanceErrorCodeUnavailable: Control could not store the event
	// now; persisted is false and error empty, and the Agent sends it again
	// after MaintenanceEventResult.retry_after_ms.
	MaintenanceErrorCodeUnavailable = "maintenance_unavailable"
)

MaintenanceEventResult.error_code (maintenance.v1).

View Source
const (
	// ConfigErrorCodeFormatUnsupported: the snapshot's format is one the
	// Agent does not know.
	ConfigErrorCodeFormatUnsupported = "config_format_unsupported"
	// ConfigErrorCodeHashMismatch: config_hash is not the SHA-256 of
	// config_json.
	ConfigErrorCodeHashMismatch = "config_hash_mismatch"
	// ConfigErrorCodeInvalid: the document does not parse or fails the
	// Agent's checks.
	ConfigErrorCodeInvalid = "config_invalid"
	// ConfigErrorCodeApplyFailed: the Agent could not run the configuration
	// (a core or driver refused it).
	ConfigErrorCodeApplyFailed = "config_apply_failed"
)

ConfigStatus.error_code (config.v1), set by the Agent when applied is false.

View Source
const (
	// ErrorCodePluginReleaseAddressInvalid (InvalidArgument): the request
	// lacks a plugin_id, version, 64-hex sha256 or positive size.
	ErrorCodePluginReleaseAddressInvalid = "invalid_plugin_release_address"
	// ErrorCodePluginReleaseAddressMismatch (InvalidArgument): the address
	// is not the release's verified content.
	ErrorCodePluginReleaseAddressMismatch = "plugin_release_address_mismatch"
	// ErrorCodePluginReleaseNotAssigned (PermissionDenied): the
	// certificate's node has no enabled assignment of the release, or the
	// release is not an official enabled Agent release.
	ErrorCodePluginReleaseNotAssigned = "plugin_release_not_assigned"
	// ErrorCodePluginReleaseNotFound (NotFound): the assigned release or its
	// artifact is gone.
	ErrorCodePluginReleaseNotFound = "plugin_release_not_found"
	// ErrorCodePluginReleaseIntegrityFailed (FailedPrecondition): the
	// stored release no longer verifies.
	ErrorCodePluginReleaseIntegrityFailed = "plugin_release_integrity_failed"
	// ErrorCodePluginReleaseBusy (ResourceExhausted): the node has as many
	// downloads running as Control allows; retry later.
	ErrorCodePluginReleaseBusy = "plugin_release_download_busy"
)

AgentArtifacts refusals (artifacts.v1), in the MetadataErrorCode trailer. They are the codes of the HTTP plugin download's JSON body.

View Source
const (
	// ErrorCodeReleaseRequestInvalid (InvalidArgument): the kind, version,
	// asset or offset names no release file.
	ErrorCodeReleaseRequestInvalid = "invalid_release_request"
	// ErrorCodeReleaseNotFound (NotFound): Control holds no such file.
	ErrorCodeReleaseNotFound = "release_not_found"
)

Release download refusals (AgentArtifacts.DownloadRelease), in the MetadataErrorCode trailer.

View Source
const (
	// ReleaseKindAgent names an Agent release asset (UpgradeArtifact).
	ReleaseKindAgent = "agent"
	// ReleaseKindKernel names a kernel package (UpgradeKernel); its value
	// is the kernel's name.
	ReleaseKindKernel = KernelAnxNode
)

Release kinds of DownloadReleaseRequest.kind.

View Source
const (
	// ErrorCodeLinkNotNegotiated (FailedPrecondition): the node's Agent did
	// not negotiate forward.v1 in its last Hello. Ask again after a HelloAck
	// that lists forward.v1.
	ErrorCodeLinkNotNegotiated = "link_cert_not_negotiated"
	// ErrorCodeLinkRequestInvalid (InvalidArgument): the CSR is malformed,
	// uses an unsupported key or the agent certificate's own key, or names
	// anything but the node's DNS name and SPIFFE ID. An Agent bug: fix the
	// request, with a fresh key.
	ErrorCodeLinkRequestInvalid = "link_cert_request_invalid"
	// ErrorCodeLinkUnavailable (FailedPrecondition): this Control issues no
	// link certificates (no built-in CA, or an external PKI) or has no link
	// CA yet. Keep the current link certificate and retry later.
	ErrorCodeLinkUnavailable = "link_cert_unavailable"
)

Forward link certificate refusals (AgentEnrollment.IssueLinkCertificate and GetLinkTrustBundle, owner decision H28), in the MetadataErrorCode trailer. Calls without a valid agent client certificate answer the agent_cert_* codes.

View Source
const (
	// LabelProtocolRevision is the Hello label in which an Agent names the
	// protocol revision it speaks (a decimal number). An Agent that
	// predates the label speaks ProtocolRevisionBaseline.
	LabelProtocolRevision = "protocol.revision"
	// LabelKernelMinVersion is the Hello label in which an Agent names the
	// oldest anx-node release it works with (KernelVersionPattern); an
	// Agent that predates the label names none.
	LabelKernelMinVersion = "kernel.anx-node.min"

	// ProtocolRevisionBaseline is the revision of the v5.0.0 contract:
	// every Agent released before LabelProtocolRevision speaks it.
	ProtocolRevisionBaseline uint32 = 1
	// ProtocolRevisionCurrent is the newest revision this SDK defines.
	// Raise it, and add a line to the revision table of
	// docs/reference/agent-versioning.md, with the contract change that
	// introduces it.
	ProtocolRevisionCurrent uint32 = 3
	// ProtocolRevisionUserKeys is the revision from which an Agent serves a
	// user's stored Shadowsocks 2022 key (users.v1 extra
	// UserExtraSS2022Key) next to the legacy one.
	ProtocolRevisionUserKeys uint32 = 2
	// ProtocolRevisionSnell is the revision from which an Agent runs a
	// configuration answer of node type snell.
	ProtocolRevisionSnell uint32 = 3
)

Agent protocol revisions and version compatibility (docs/reference/agent-versioning.md).

Since v5.0.0 Control and the Agent are released separately: they share the major and minor version (the version line, 5.0) and number their patches independently. What decides whether a Control and an Agent work together is the protocol revision: a whole number inside anix.agent.v1 that grows by one whenever the contract gains something a side relies on (a message, a field or a capability the other side must serve). The Agent names the revision it speaks in a Hello label; Control serves a range of revisions and judges every session against it.

View Source
const (
	// CompatibilityOK: the Agent and Control work together.
	CompatibilityOK = "compatible"
	// CompatibilityWarning: they work together, but something should be
	// upgraded (Control is older than the Agent, or the version lines
	// differ).
	CompatibilityWarning = "warning"
	// CompatibilityIncompatible: the Agent, or its kernel, is older than
	// Control or the Agent supports; features fail until it is upgraded.
	CompatibilityIncompatible = "incompatible"
)

Compatibility statuses, from best to worst.

View Source
const (
	// ProblemAgentProtocolTooOld: the Agent speaks a revision below the
	// oldest Control serves. Upgrade the Agent.
	ProblemAgentProtocolTooOld = "agent_protocol_too_old"
	// ProblemAgentProtocolTooNew: the Agent speaks a revision above the
	// newest Control serves; the newer features stay off. Upgrade Control.
	ProblemAgentProtocolTooNew = "agent_protocol_too_new"
	// ProblemVersionLineMismatch: the Agent's major.minor is not Control's.
	ProblemVersionLineMismatch = "version_line_mismatch"
	// ProblemKernelTooOld: the anx-node release is older than the Agent
	// needs. Upgrade the kernel.
	ProblemKernelTooOld = "kernel_too_old"
)

Compatibility problem codes.

View Source
const (
	// CapabilityConfig: Control sends ConfigSnapshot and the Agent answers
	// ConfigStatus; Hello.config_revision is read.
	CapabilityConfig = "config"
	// CapabilityUsers: Control sends UserDelta; Hello.users_cursor is read.
	CapabilityUsers = "users"
	// CapabilityReports: the Agent sends TrafficReport, LogBatch and
	// NodeStatus, and Control answers reports with ReportAck.
	CapabilityReports = "reports"
	// CapabilityDiag: the Agent runs node-side diagnostics, the forward
	// checks of the agent.diagnostic operation (PROTOCOL.md, "Diagnostic
	// operation"), so Control may choose the node as a vantage. It adds no
	// payload; Control records it on the session and sends the checks only
	// with agent.diagnostic listed too.
	CapabilityDiag = "diag"
	// CapabilityPackageReports: the Agent sends PackageReport, the latest
	// observation of a plugin package; Control does not acknowledge it.
	CapabilityPackageReports = "package-reports"
	// CapabilityForward: the node forwards (forward-sdk.md section 8).
	// Control carries the node's NodeForwardState in an
	// anixops.nodeconfig/v2 ConfigSnapshot (so it needs config.v1 too) and
	// accepts the node's NodeForwardReport as a PackageReport (with
	// package-reports.v1). The Agent's Hello lists it with the node's
	// NodeCapabilities in an attribute (sdk/forward/wire).
	CapabilityForward = "forward"
	// CapabilityMaintenance: the Agent sends its maintenance outbox as
	// MaintenanceEvents, and Control answers each batch with
	// MaintenanceAck (maintenance.go; PROTOCOL.md, "Maintenance events").
	CapabilityMaintenance = "maintenance"
	// CapabilityAlive: Control sends AliveList, every user's online device
	// count across all nodes, so the Agent enforces
	// device limits against every node's connections.
	CapabilityAlive = "alive"
	// CapabilityArtifacts: Control serves the AgentArtifacts service
	// (artifacts.proto) to the session's client certificate, so the Agent
	// downloads its node's plugin releases without the node API key. It
	// adds no stream payload.
	CapabilityArtifacts = "artifacts"
	// CapabilityReleases: Control serves AgentArtifacts.DownloadRelease
	// (artifacts.proto) to the session's client certificate, so the Agent
	// downloads the Agent and kernel files of an agent.upgrade operation
	// over the mTLS connection instead of their https URL, which stays the
	// fallback. It adds no stream payload.
	CapabilityReleases = "releases"
	// CapabilityDestinations: the Agent sends DestinationReport, each
	// user's traffic by destination domain, and Control answers it with
	// ReportAck as it answers reports.v1 batches.
	CapabilityDestinations = "destinations"
	// CapabilityNetwork: the device runs the network model
	// (docs/design/network-model, sdk/network). Control carries the
	// device's NetworkPlan as the member "network" of the nodeconfig
	// document (so it needs config.v1 too) and accepts the device's
	// NetworkStatus as a PackageReport (with package-reports.v1). The
	// Agent's Hello lists it with the device's DeviceCapabilities in an
	// attribute.
	CapabilityNetwork = "network"
)

Data-plane capabilities of the control stream (PROTOCOL.md, "Data plane"). Each is advertised at CapabilityVersionV1, so the protocol writes them config.v1, users.v1 and reports.v1. An Agent lists the ones it implements in Hello.capabilities; Control lists the ones it serves in HelloAck.server_capabilities. A feature is in use on a session only when both list it (Negotiated), and neither side sends its payloads otherwise.

View Source
const (
	// MetadataNodeID carries the node id with a node credential.
	MetadataNodeID = "x-node-id"
	// MetadataAPIKey carries a proxy node's API key, or a forward node's
	// token when MetadataNodeKind is NodeKindForward.
	MetadataAPIKey = "x-api-key"
	// MetadataNodeKind names the table of MetadataNodeID: NodeKindProxy (the
	// default) or NodeKindForward. Only AgentEnrollment.Enroll reads it.
	MetadataNodeKind = "x-node-kind"
	// MetadataAuthDeprecated is the response header Control sends when an
	// Agent authenticated with its legacy node credential although client
	// certificates are preferred (agent_control.mtls: preferred).
	MetadataAuthDeprecated = "x-anix-auth-deprecated"
	// MetadataAuthSunset accompanies MetadataAuthDeprecated when Control
	// announces a date (agent_control.legacy_sunset) after which legacy
	// credentials may be refused, as an HTTP-date (RFC 9110).
	MetadataAuthSunset = "x-anix-auth-sunset"
	// MetadataAuthDeprecationLink accompanies MetadataAuthDeprecated: where
	// the operator reads how to move the node to client certificates.
	MetadataAuthDeprecationLink = "x-anix-auth-deprecation-link"
	// MetadataErrorCode is the trailer of a call Control refused for a
	// machine-readable reason, such as ErrorCodeMTLSRequired.
	MetadataErrorCode = "x-anix-error-code"
	// ErrorCodeMTLSRequired refuses legacy credentials on an AnixOps Agent
	// channel under agent_control.mtls: required. HTTP answers carry it as
	// the "code" of their JSON body.
	ErrorCodeMTLSRequired = "agent_mtls_required"
)

Metadata keys an Agent sends on Control's agent listener.

View Source
const (
	// ErrorCodeCertRevoked: the certificate, its enrollment or its node's
	// credentials were revoked, or the node was disabled or deleted (which
	// revokes them).
	ErrorCodeCertRevoked = "agent_cert_revoked"
	// ErrorCodeCertExpired: the certificate's not_after has passed, at
	// connection or, on an open stream, at a heartbeat.
	ErrorCodeCertExpired = "agent_cert_expired"
	// ErrorCodeCertInvalid: the certificate does not authenticate an agent
	// of this Control: unparsable, not chaining to the agent trust bundle,
	// not yet valid, without client-auth usage, without exactly one agent
	// SPIFFE ID, or presented while Control runs no agent PKI.
	ErrorCodeCertInvalid = "agent_cert_invalid"
	// ErrorCodeCertWrongNode: the certificate names another node than the
	// call: x-node-id or x-node-kind, an envelope's node_id, or a forward
	// node's certificate on the proxy-only v2board services.
	ErrorCodeCertWrongNode = "agent_cert_wrong_node"
	// ErrorCodeCertWrongCluster: the certificate is an agent certificate of
	// another cluster.
	ErrorCodeCertWrongCluster = "agent_cert_wrong_cluster"
	// ErrorCodeEnrollmentRejected answers AgentEnrollment.Enroll for any
	// unusable bootstrap credential (unknown, used, expired or revoked
	// enrollment credential, wrong node key or token, disabled node): one
	// answer, so credentials cannot be probed.
	ErrorCodeEnrollmentRejected = "agent_enrollment_rejected"
	// ErrorCodeJoinRejected answers AgentEnrollment.Join (PermissionDenied)
	// for any unusable join token: unknown, of a deleted group, expired, or
	// of a group at its node cap. One answer, without detail, so tokens
	// cannot be probed; Control audits the reason.
	ErrorCodeJoinRejected = "join_rejected"
)

Error codes of a refused agent client certificate, in the MetadataErrorCode trailer of an Unauthenticated (or, for ErrorCodeCertWrongNode on an envelope, PermissionDenied) answer of ControlStream, Renew and GetTrustBundle. An Agent that gets one discards the certificate and enrolls again, except for ErrorCodeCertWrongNode, which names its own configuration error. A transient failure (Unavailable) carries no code: retry it.

View Source
const (
	// NodeKindProxy is a proxy node, a v2_node row.
	NodeKindProxy = "proxy"
	// NodeKindForward is a forward node, a v2_forward_node row.
	NodeKindForward = "forward"
)

Node kinds of an agent identity.

View Source
const (
	// MaintenanceSchemaV1 is MaintenanceEvents.version.
	MaintenanceSchemaV1 = "anixops.maintenance/v1"
	// MaxMaintenanceBatchEvents caps the events of one MaintenanceEvents.
	MaxMaintenanceBatchEvents = 50
	// MaxMaintenanceEventBytes caps one event's JSON.
	MaxMaintenanceEventBytes = 16 << 10
	// MaxMaintenanceBatchBytes caps the events of one batch together.
	MaxMaintenanceBatchBytes = 256 << 10
	// MaxMaintenanceEventIDLength caps an event_id.
	MaxMaintenanceEventIDLength = 128
)

The maintenance events of maintenance.v1 (PROTOCOL.md, "Maintenance events"): the Agent's durable maintenance outbox, plugin health incidents and recoveries, in the schema anixops.maintenance/v1 the legacy agent WebSocket's maintenance_events message carries. A MaintenanceEvents message holds one JSON object per event.

View Source
const (
	// MaxPackageReportPayloadBytes caps PackageReport.payload_json.
	MaxPackageReportPayloadBytes = 256 << 10
	// MaxPackageReportKindLength caps PackageReport.kind.
	MaxPackageReportKindLength = 64
)

Generic limits of a PackageReport (package-reports.v1; PROTOCOL.md, "Package reports"). They hold for every kind; each kind's schema adds its own rules (for systemd.services, sdk/telemetry/systemdreport).

View Source
const (
	ProtocolV1          = "anix.agent.v1"
	CapabilityVersionV1 = "v1"
)
View Source
const (
	// CapabilityUpgrade: the Agent applies agent.upgrade operations through
	// its privileged updater (anixops-agent-updater.path). It adds no
	// stream payload.
	CapabilityUpgrade = "upgrade"
	// OperationKindAgentUpgrade is the DesiredOperation kind of an upgrade
	// or a rollback. It is not a capability name: the session must
	// negotiate upgrade.v1.
	OperationKindAgentUpgrade = "agent.upgrade"
	// UpgradeSchemaV1 is UpgradeRequest.Schema.
	UpgradeSchemaV1 = "anixops.agent-upgrade/v1"
	// UpgradeActionUpgrade installs TargetVersion from Artifacts.
	UpgradeActionUpgrade = "upgrade"
	// UpgradeActionRollback reinstates the binary the Agent kept from its
	// last upgrade, which must be TargetVersion; it carries no artifacts.
	UpgradeActionRollback = "rollback"
	// MaxUpgradeRequestBytes bounds payload_json.
	MaxUpgradeRequestBytes = 16 << 10
	// MaxUpgradeArtifactBytes bounds an artifact's size (the release zip).
	MaxUpgradeArtifactBytes = 256 << 20
	// KernelAnxNode is UpgradeKernel.Name of anx-node, AnixOps' own node
	// kernel with ANX (the private anx release), which the Agent runs as
	// its anixcore core.
	KernelAnxNode = "anx-node"
	// LabelKernelVersion is the Hello label in which an Agent names the
	// anx-node release it has installed (KernelVersionPattern); an Agent
	// without a kernel, or one that predates the label, leaves it out.
	LabelKernelVersion = "kernel.anx-node"
	// MaxUpgradeKernelBytes bounds a kernel package's size.
	MaxUpgradeKernelBytes = 64 << 20
)

Agent upgrades (upgrade.v1, PROTOCOL.md "Agent upgrades"): Control pushes an Agent release in canary batches (forward-sdk.md section 9, H19) as the DesiredOperation kind OperationKindAgentUpgrade, whose payload_json is an UpgradeRequest. Control sends it only on a session that negotiated CapabilityUpgrade, and an Agent never upgrades on its own.

View Source
const (
	// UpgradePhaseDownloading: APPLYING, fetching the artifact.
	UpgradePhaseDownloading = "downloading"
	// UpgradePhaseVerifying: APPLYING, checking size, SHA-256 and the
	// Ed25519 signature.
	UpgradePhaseVerifying = "verifying"
	// UpgradePhaseHandedOff: SUCCEEDED, the staged release and the request
	// are with the updater, which restarts the Agent. Control closes the
	// loop on the next Hello's agent_version.
	UpgradePhaseHandedOff = "handed_off"
	// UpgradePhaseCurrent: SUCCEEDED, the Agent already runs TargetVersion
	// (a replay after the restart, or a host that was upgraded through
	// another node identity).
	UpgradePhaseCurrent = "current"
)

Phases an Agent reports in the ObservedState.state_json of an agent.upgrade operation (UpgradeState.Phase).

View Source
const (
	UpgradeErrorInvalidRequest = "upgrade_invalid_request"
	UpgradeErrorNoArtifact     = "upgrade_no_artifact"
	UpgradeErrorDownload       = "upgrade_download_failed"
	UpgradeErrorDigest         = "upgrade_digest_mismatch"
	UpgradeErrorSignature      = "upgrade_signature_invalid"
	UpgradeErrorUpdater        = "upgrade_updater_unavailable"
	UpgradeErrorNoPrevious     = "upgrade_no_previous_release"
	UpgradeErrorBusy           = "upgrade_in_progress"
	UpgradeErrorDowngrade      = "upgrade_downgrade_refused"
)

Error codes of a FAILED agent.upgrade (UpgradeState.ErrorCode).

View Source
const EnrollmentCredentialPrefix = "anixagt_"

EnrollmentCredentialPrefix starts every one-time agent enrollment credential, so secret scanners can recognize them.

View Source
const ErrorCodeCapabilityNotNegotiated = "agent_capability_not_negotiated"

ErrorCodeCapabilityNotNegotiated ends a stream that sent a data-plane payload whose capability the session did not negotiate (InvalidArgument, in the MetadataErrorCode trailer).

View Source
const JoinTokenPrefix = "anixjoin_"

JoinTokenPrefix starts every node group join token (AgentEnrollment.Join), so secret scanners can recognize them and the installer can tell a join token, which joins a group, from an enrollment credential, which enrolls an existing node.

View Source
const UserExtraSS2022Key = "ss2022_key"

UserExtraSS2022Key is the member of a users.v1 NodeUser's extra_json that carries the user's stored Shadowsocks 2022 key (std base64 of 32 bytes). An Agent of ProtocolRevisionUserKeys or later serves it as a second Shadowsocks 2022 user next to the legacy key derived from the UUID; an older Agent ignores it.

Variables

View Source
var (
	// ErrPackageReportKind means PackageReport.kind is empty, too long or
	// not lowercase dot-separated words.
	ErrPackageReportKind = errors.New("package report kind is invalid")
	// ErrPackageReportTooLarge means payload_json exceeds
	// MaxPackageReportPayloadBytes.
	ErrPackageReportTooLarge = fmt.Errorf("package report payload exceeds %d bytes", MaxPackageReportPayloadBytes)
)
View Source
var (
	ErrCapabilitiesRequired   = errors.New("hello capabilities are required")
	ErrCapabilityNameRequired = errors.New("capability name is required")
)

ConfigErrorCodes are the ConfigStatus codes this contract defines.

DataPlaneCapabilities are the capabilities of the data plane, the ones Control lists in HelloAck.server_capabilities when it serves them and the Agent's Hello lists them. upgrade.v1 (CapabilityUpgrade, upgrade.go) adds no payload but is offered by the same rule.

View Source
var (
	// ErrInvalidAgentIdentity reports a node name, SPIFFE ID or certificate
	// that is not an AnixOps agent identity.
	ErrInvalidAgentIdentity = errors.New("invalid AnixOps agent identity")
)
View Source
var ErrInvalidMaintenanceEvent = errors.New("invalid maintenance event")

ErrInvalidMaintenanceEvent reports an event that is not a valid anixops.maintenance/v1 event of the stream's node. Control refuses it for good.

View Source
var ErrInvalidUpgradeRequest = errors.New("invalid agent upgrade request")

ErrInvalidUpgradeRequest wraps every reason ParseUpgradeRequest refuses.

View Source
var ErrMaintenanceEventWrongNode = errors.New("maintenance event of another node")

ErrMaintenanceEventWrongNode reports an event of another node; it also matches ErrInvalidMaintenanceEvent.

View Source
var (

	// KernelVersionPattern matches a kernel release version (no "v").
	KernelVersionPattern = regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+(-(alpha|beta|rc)\.[0-9]+)?$`)
)

Functions

func CompareKernelVersions

func CompareKernelVersions(a, b string) (result int, ok bool)

CompareKernelVersions orders two anx-node release versions (KernelVersionPattern, alpha < beta < rc < the release): -1, 0 or 1; ok is false when either is not one.

func HasCapability

func HasCapability(capabilities []*agentv1pb.Capability, name string) bool

func HasCapabilityVersion

func HasCapabilityVersion(capabilities []*agentv1pb.Capability, name, version string) bool

func HelloKernelMinVersion

func HelloKernelMinVersion(labels map[string]string) string

HelloKernelMinVersion returns the oldest anx-node release a Hello's labels say the Agent works with (LabelKernelMinVersion), "" when they name none or a malformed one.

func HelloKernelVersion

func HelloKernelVersion(labels map[string]string) string

HelloKernelVersion returns the anx-node release a Hello's labels name (LabelKernelVersion), "" when they name none or a malformed one.

func HelloProtocolRevision

func HelloProtocolRevision(labels map[string]string) uint32

HelloProtocolRevision returns the protocol revision a Hello's labels name (LabelProtocolRevision): ProtocolRevisionBaseline when they name none (an Agent released before the label) or a malformed one.

func KernelSum

func KernelSum(sums, name string) (string, bool)

KernelSum returns the SHA-256 that a SHA256SUMS manifest (sha256sum output: "<hex> <name>", or "<hex> *<name>") lists for name.

func MaintenanceEventID

func MaintenanceEventID(raw []byte) string

MaintenanceEventID returns the event_id of a raw event when it is a valid event id, for answering an event that is otherwise refused; empty when the event cannot be read or its id is malformed.

func Negotiated

func Negotiated(agent, server []*agentv1pb.Capability, name string) bool

Negotiated reports whether a data-plane capability is in use on a session: both the Agent's Hello.capabilities and Control's HelloAck.server_capabilities list it at CapabilityVersionV1.

func NegotiatedCapabilities

func NegotiatedCapabilities(agent, server []*agentv1pb.Capability) []string

NegotiatedCapabilities lists the data-plane capabilities in use on a session (Negotiated), as name.version (config.v1), in the order of DataPlaneCapabilities.

func SameAgentVersion

func SameAgentVersion(a, b string) bool

SameAgentVersion reports whether two Agent versions name one release, with or without the leading "v".

func SameVersionLine

func SameVersionLine(a, b string) bool

SameVersionLine reports whether two release versions share major and minor. Either one unparsable is not the same line.

func TransientReportAcks

func TransientReportAcks(agent, server []*agentv1pb.Capability) bool

TransientReportAcks reports whether a session sends ReportAck of ReportErrorCodeUnavailable: both the Agent's and Control's reports.v1 carry ReportsAttributeTransientAck at ReportsTransientAckV1.

func ValidateCapabilities

func ValidateCapabilities(capabilities []*agentv1pb.Capability) error

func ValidatePackageReportKind

func ValidatePackageReportKind(kind string) error

ValidatePackageReportKind checks a PackageReport kind.

func ValidatePackageReportPayloadSize

func ValidatePackageReportPayloadSize(payload []byte) error

ValidatePackageReportPayloadSize checks payload_json against MaxPackageReportPayloadBytes.

func VersionLine

func VersionLine(version string) (line string, ok bool)

VersionLine returns the major.minor of a release version (v5.0.1 and 5.0.0-rc.29.hf.1 are both "5.0"); ok is false when version is not one.

Types

type AgentIdentity

type AgentIdentity struct {
	Cluster string
	Node    AgentNode
}

AgentIdentity is a parsed agent SPIFFE ID, spiffe://anixops/<cluster>/agent/<node>.

func AgentIdentityFromCertificate

func AgentIdentityFromCertificate(certificate *x509.Certificate) (AgentIdentity, error)

AgentIdentityFromCertificate returns the identity of a certificate that carries exactly one URI SAN, an agent SPIFFE ID, and no other SAN kinds.

func NewAgentIdentity

func NewAgentIdentity(cluster string, node AgentNode) (AgentIdentity, error)

NewAgentIdentity returns the identity of node in cluster.

func ParseAgentIdentity

func ParseAgentIdentity(raw string) (AgentIdentity, error)

ParseAgentIdentity parses an agent SPIFFE ID. Module and kernel identities of the same trust domain are not agent identities.

func (AgentIdentity) String

func (id AgentIdentity) String() string

String returns the SPIFFE ID.

func (AgentIdentity) URL

func (id AgentIdentity) URL() *url.URL

URL returns the SPIFFE ID as a URI SAN.

type AgentNode

type AgentNode struct {
	Kind string
	ID   uint32
}

AgentNode names the node an agent runs on. Proxy and forward node ids overlap, so the kind is part of the name.

func ParseAgentNode

func ParseAgentNode(name string) (AgentNode, error)

ParseAgentNode parses "proxy-<id>" or "forward-<id>".

func (AgentNode) String

func (n AgentNode) String() string

String returns the node name, "proxy-<id>" or "forward-<id>".

func (AgentNode) Valid

func (n AgentNode) Valid() bool

Valid reports whether n names a node.

type Compatibility

type Compatibility struct {
	// Status is the worst severity of Problems, CompatibilityOK without any.
	Status   string                 `json:"status"`
	Problems []CompatibilityProblem `json:"problems"`
}

Compatibility is the judgement of one Agent session.

func CheckCompatibility

func CheckCompatibility(in CompatibilityInput) Compatibility

CheckCompatibility judges an Agent session against the Control it is connected to.

type CompatibilityInput

type CompatibilityInput struct {
	// ControlVersion is Control's release (v5.0.1); "" skips the version
	// line check.
	ControlVersion string
	// MinRevision and MaxRevision are the protocol revisions Control
	// serves.
	MinRevision uint32
	MaxRevision uint32
	// AgentVersion is the Agent's release from its Hello.
	AgentVersion string
	// AgentRevision is HelloProtocolRevision of its labels.
	AgentRevision uint32
	// KernelVersion and KernelMinVersion are the anx-node release the
	// Agent runs and the oldest it works with; either "" skips the check.
	KernelVersion    string
	KernelMinVersion string
}

CompatibilityInput is what CheckCompatibility judges.

type CompatibilityProblem

type CompatibilityProblem struct {
	Code     string `json:"code"`
	Severity string `json:"severity"`
	Message  string `json:"message"`
}

CompatibilityProblem is one reason a session is not CompatibilityOK.

type MaintenanceEvent

type MaintenanceEvent struct {
	SchemaVersion       int        `json:"schema_version"`
	EventID             string     `json:"event_id"`
	OccurredAt          time.Time  `json:"occurred_at"`
	Environment         string     `json:"environment"`
	Source              string     `json:"source"`
	NodeID              string     `json:"node_id"`
	AgentVersion        string     `json:"agent_version,omitempty"`
	ConfigVersion       string     `json:"config_version,omitempty"`
	PluginID            string     `json:"plugin_id,omitempty"`
	PluginVersion       string     `json:"plugin_version,omitempty"`
	InstanceID          string     `json:"instance_id,omitempty"`
	ErrorCode           string     `json:"error_code"`
	Severity            string     `json:"severity"`
	Status              string     `json:"status"`
	FirstFailedAt       *time.Time `json:"first_failed_at,omitempty"`
	ConsecutiveFailures int        `json:"consecutive_failures,omitempty"`
	HealthySince        *time.Time `json:"healthy_since,omitempty"`
	SelfHealAction      string     `json:"self_heal_action,omitempty"`
	SelfHealResult      string     `json:"self_heal_result,omitempty"`
	DiagnosticRef       string     `json:"diagnostic_ref,omitempty"`
	TicketKey           string     `json:"ticket_key,omitempty"`
	RedactedSummary     string     `json:"redacted_summary,omitempty"`
}

MaintenanceEvent is one anixops.maintenance/v1 event.

func ParseMaintenanceEvent

func ParseMaintenanceEvent(raw []byte, node AgentNode, now time.Time) (MaintenanceEvent, error)

ParseMaintenanceEvent reads one event of a MaintenanceEvents batch sent on node's stream, at now: a JSON object of at most MaxMaintenanceEventBytes, valid by Validate, naming node. Fields the schema does not know are dropped. Errors wrap ErrInvalidMaintenanceEvent.

func (MaintenanceEvent) Validate

func (e MaintenanceEvent) Validate(now time.Time) error

Validate applies the anixops.maintenance/v1 rules the Agent's outbox applies before it queues an event, at now.

type UpgradeArtifact

type UpgradeArtifact struct {
	Arch      string `json:"arch"`
	Asset     string `json:"asset"`
	URL       string `json:"url"`
	SHA256    string `json:"sha256"`
	Size      int64  `json:"size"`
	Signature string `json:"signature"`
}

UpgradeArtifact is one architecture's release asset: the Agent picks the one whose Arch is its GOARCH, downloads URL, and verifies Size, SHA256 and Signature (base64 Ed25519 over the exact bytes, the release's .sig) with the official release key it embeds, never a key Control sends.

type UpgradeKernel

type UpgradeKernel struct {
	Name          string `json:"name"`
	Version       string `json:"version"`
	Arch          string `json:"arch"`
	Asset         string `json:"asset"`
	URL           string `json:"url"`
	SHA256        string `json:"sha256"`
	Size          int64  `json:"size"`
	Sums          string `json:"sums"`
	SumsSignature string `json:"sums_signature"`
}

UpgradeKernel is one architecture's kernel package that comes with an upgrade: the Agent's updater installs it next to the Agent binary, and the Agent then runs it as its anixcore core. Name is KernelAnxNode, Version its release without "v" (0.1.0-alpha.2), Asset the release tarball, served at URL. The trust is the kernel release's own signature: Sums is its SHA256SUMS, SumsSignature the SSH signature of Sums (`ssh-keygen -Y sign`, the release's SHA256SUMS.sig), which the Agent verifies with the kernel release key it embeds, never a key Control sends; SHA256 must be Asset's line in Sums.

type UpgradeRequest

type UpgradeRequest struct {
	Schema     string `json:"schema"`
	CampaignID string `json:"campaign_id"`
	Action     string `json:"action"`
	// TargetVersion is the release to run afterwards (v4.2.0).
	TargetVersion string `json:"target_version"`
	// PreviousVersion is the release the node ran when the campaign
	// offered it the upgrade; the updater keeps that binary for a
	// rollback. Empty when Control did not know it.
	PreviousVersion string            `json:"previous_version,omitempty"`
	Artifacts       []UpgradeArtifact `json:"artifacts,omitempty"`
	// Kernels are the kernel packages to install with the upgrade, at most
	// one per architecture. An Agent that already runs TargetVersion
	// installs a kernel it does not have yet; one that predates them
	// ignores the field.
	Kernels []UpgradeKernel `json:"kernels,omitempty"`
}

UpgradeRequest is the payload_json of an agent.upgrade operation. Fields may be added; an Agent ignores the ones it does not know.

func ParseUpgradeRequest

func ParseUpgradeRequest(data []byte) (UpgradeRequest, error)

ParseUpgradeRequest decodes and checks an agent.upgrade payload as both sides must: the schema, the action, release tags, and for an upgrade at least one artifact with an https URL, a SHA-256, a size and an Ed25519 signature, each architecture once.

func (UpgradeRequest) Artifact

func (r UpgradeRequest) Artifact(arch string) (UpgradeArtifact, bool)

Artifact returns the artifact of arch.

func (UpgradeRequest) Kernel

func (r UpgradeRequest) Kernel(arch string) (UpgradeKernel, bool)

Kernel returns the kernel package of arch.

func (UpgradeRequest) Validate

func (r UpgradeRequest) Validate() error

Validate checks the request (ParseUpgradeRequest).

type UpgradeState

type UpgradeState struct {
	Phase     string `json:"phase,omitempty"`
	Version   string `json:"version,omitempty"`
	ErrorCode string `json:"error_code,omitempty"`
}

UpgradeState is the state_json of an agent.upgrade ObservedState.

Jump to

Keyboard shortcuts

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