Documentation
¶
Index ¶
- Constants
- Variables
- func CompareKernelVersions(a, b string) (result int, ok bool)
- func HasCapability(capabilities []*agentv1pb.Capability, name string) bool
- func HasCapabilityVersion(capabilities []*agentv1pb.Capability, name, version string) bool
- func HelloKernelMinVersion(labels map[string]string) string
- func HelloKernelVersion(labels map[string]string) string
- func HelloProtocolRevision(labels map[string]string) uint32
- func KernelSum(sums, name string) (string, bool)
- func MaintenanceEventID(raw []byte) string
- func Negotiated(agent, server []*agentv1pb.Capability, name string) bool
- func NegotiatedCapabilities(agent, server []*agentv1pb.Capability) []string
- func SameAgentVersion(a, b string) bool
- func SameVersionLine(a, b string) bool
- func TransientReportAcks(agent, server []*agentv1pb.Capability) bool
- func ValidateCapabilities(capabilities []*agentv1pb.Capability) error
- func ValidatePackageReportKind(kind string) error
- func ValidatePackageReportPayloadSize(payload []byte) error
- func VersionLine(version string) (line string, ok bool)
- type AgentIdentity
- type AgentNode
- type Compatibility
- type CompatibilityInput
- type CompatibilityProblem
- type MaintenanceEvent
- type UpgradeArtifact
- type UpgradeKernel
- type UpgradeRequest
- type UpgradeState
Constants ¶
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" // (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).
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).
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" // 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).
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.
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.
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.
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.
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" // 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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
const ( ProtocolV1 = "anix.agent.v1" CapabilityVersionV1 = "v1" )
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.
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).
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).
const EnrollmentCredentialPrefix = "anixagt_"
EnrollmentCredentialPrefix starts every one-time agent enrollment credential, so secret scanners can recognize them.
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).
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.
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 ¶
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) )
var ( ErrCapabilitiesRequired = errors.New("hello capabilities are required") ErrCapabilityNameRequired = errors.New("capability name is required") )
var ConfigErrorCodes = []string{ ConfigErrorCodeFormatUnsupported, ConfigErrorCodeHashMismatch, ConfigErrorCodeInvalid, ConfigErrorCodeApplyFailed, }
ConfigErrorCodes are the ConfigStatus codes this contract defines.
var DataPlaneCapabilities = []string{ CapabilityConfig, CapabilityUsers, CapabilityReports, CapabilityPackageReports, CapabilityForward, CapabilityMaintenance, CapabilityAlive, CapabilityArtifacts, CapabilityReleases, CapabilityUpgrade, CapabilityDestinations, CapabilityNetwork, }
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.
var ( // ErrInvalidAgentIdentity reports a node name, SPIFFE ID or certificate // that is not an AnixOps agent identity. ErrInvalidAgentIdentity = errors.New("invalid AnixOps agent identity") )
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.
var ErrInvalidUpgradeRequest = errors.New("invalid agent upgrade request")
ErrInvalidUpgradeRequest wraps every reason ParseUpgradeRequest refuses.
var ErrMaintenanceEventWrongNode = errors.New("maintenance event of another node")
ErrMaintenanceEventWrongNode reports an event of another node; it also matches ErrInvalidMaintenanceEvent.
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 ¶
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 ¶
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 ¶
HelloKernelVersion returns the anx-node release a Hello's labels name (LabelKernelVersion), "" when they name none or a malformed one.
func HelloProtocolRevision ¶
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 ¶
KernelSum returns the SHA-256 that a SHA256SUMS manifest (sha256sum output: "<hex> <name>", or "<hex> *<name>") lists for name.
func MaintenanceEventID ¶
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 ¶
SameAgentVersion reports whether two Agent versions name one release, with or without the leading "v".
func SameVersionLine ¶
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 ¶
ValidatePackageReportKind checks a PackageReport kind.
func ValidatePackageReportPayloadSize ¶
ValidatePackageReportPayloadSize checks payload_json against MaxPackageReportPayloadBytes.
func VersionLine ¶
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 ¶
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) URL ¶
func (id AgentIdentity) URL() *url.URL
URL returns the SPIFFE ID as a URI SAN.
type AgentNode ¶
AgentNode names the node an agent runs on. Proxy and forward node ids overlap, so the kind is part of the name.
func ParseAgentNode ¶
ParseAgentNode parses "proxy-<id>" or "forward-<id>".
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 ¶
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.
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.