ADR 0022, OpenAPI additions (agent mode, deploy, rollback, diff, pending changes, server-sent events), deployment_id in GetDesiredStateResponse for pushes picked up by polling, and the textdiff package (Myers, unified format). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
289 lines
8.5 KiB
Protocol Buffer
289 lines
8.5 KiB
Protocol Buffer
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
syntax = "proto3";
|
|
|
|
package ddi.agent.v1;
|
|
|
|
import "google/protobuf/duration.proto";
|
|
import "google/protobuf/timestamp.proto";
|
|
|
|
option go_package = "git.beugsiud.de/beug.k/DDI/proto/gen/ddi/agent/v1;agentv1";
|
|
|
|
// AgentService is implemented by the management server and called by agents.
|
|
// Agents always connect outbound (docs/adr/0007-server-agent-grpc-mtls.md).
|
|
// Every RPC except Enroll requires a client certificate issued by the
|
|
// server's internal CA (docs/adr/0008-interne-ca-enrollment.md).
|
|
service AgentService {
|
|
// Enroll exchanges a one-time token and a certificate signing request for a
|
|
// client certificate. It is the only RPC allowed without client certificate.
|
|
rpc Enroll(EnrollRequest) returns (EnrollResponse);
|
|
|
|
// RenewCertificate issues a new client certificate for a freshly generated
|
|
// key. Allowed with a certificate that expired at most 30 days ago.
|
|
rpc RenewCertificate(RenewCertificateRequest) returns (RenewCertificateResponse);
|
|
|
|
// Connect is the long-lived control stream. The agent sends Hello first,
|
|
// then heartbeats and command acknowledgements; the server answers with
|
|
// Welcome and pushes commands.
|
|
rpc Connect(stream ConnectRequest) returns (stream ConnectResponse);
|
|
|
|
// GetDesiredState returns the revision the agent should run. Used for
|
|
// auto_pull and as fallback when the Connect stream is unavailable.
|
|
rpc GetDesiredState(GetDesiredStateRequest) returns (GetDesiredStateResponse);
|
|
|
|
// FetchBundle downloads the signed configuration bundle of a revision
|
|
// (docs/adr/0009-signierte-config-bundles.md).
|
|
rpc FetchBundle(FetchBundleRequest) returns (FetchBundleResponse);
|
|
|
|
// ReportDeployment reports the outcome of applying a revision.
|
|
rpc ReportDeployment(ReportDeploymentRequest) returns (ReportDeploymentResponse);
|
|
|
|
// ReportLeases sends a batch of DHCP lease observations (DHCP agents only).
|
|
rpc ReportLeases(ReportLeasesRequest) returns (ReportLeasesResponse);
|
|
}
|
|
|
|
// Role of an agent.
|
|
enum Role {
|
|
ROLE_UNSPECIFIED = 0;
|
|
ROLE_DNS = 1;
|
|
ROLE_DHCP = 2;
|
|
}
|
|
|
|
// OperatingMode controls when an agent applies new revisions.
|
|
enum OperatingMode {
|
|
OPERATING_MODE_UNSPECIFIED = 0;
|
|
// The agent applies new revisions on its own within the pull interval.
|
|
OPERATING_MODE_AUTO_PULL = 1;
|
|
// The agent applies revisions only when told to (push from the UI).
|
|
OPERATING_MODE_MANUAL = 2;
|
|
}
|
|
|
|
// HealthState summarizes the state of the managed service.
|
|
enum HealthState {
|
|
HEALTH_STATE_UNSPECIFIED = 0;
|
|
HEALTH_STATE_OK = 1;
|
|
HEALTH_STATE_DEGRADED = 2;
|
|
HEALTH_STATE_FAILED = 3;
|
|
}
|
|
|
|
message EnrollRequest {
|
|
// One-time enrollment token in the form "<id>.<secret>".
|
|
string token = 1;
|
|
// PKCS#10 certificate signing request, DER encoded. The private key never
|
|
// leaves the agent.
|
|
bytes csr_der = 2;
|
|
Role role = 3;
|
|
string hostname = 4;
|
|
string agent_version = 5;
|
|
}
|
|
|
|
message EnrollResponse {
|
|
// Agent identifier assigned by the server (UUID).
|
|
string agent_id = 1;
|
|
// Issued client certificate, DER encoded.
|
|
bytes certificate_der = 2;
|
|
// CA chain, DER encoded, root last.
|
|
repeated bytes ca_certificates_der = 3;
|
|
// Ed25519 public key that verifies configuration bundles.
|
|
bytes bundle_signing_public_key = 4;
|
|
}
|
|
|
|
message RenewCertificateRequest {
|
|
bytes csr_der = 1;
|
|
}
|
|
|
|
message RenewCertificateResponse {
|
|
bytes certificate_der = 1;
|
|
repeated bytes ca_certificates_der = 2;
|
|
}
|
|
|
|
message ConnectRequest {
|
|
oneof message {
|
|
Hello hello = 1;
|
|
Heartbeat heartbeat = 2;
|
|
CommandAck command_ack = 3;
|
|
}
|
|
}
|
|
|
|
message ConnectResponse {
|
|
oneof message {
|
|
Welcome welcome = 1;
|
|
Command command = 2;
|
|
}
|
|
}
|
|
|
|
// Hello is the first message an agent sends on a new stream.
|
|
message Hello {
|
|
string agent_version = 1;
|
|
// Revision currently active on the agent (0 = none).
|
|
uint64 applied_revision = 2;
|
|
// Last revision that passed its health check.
|
|
uint64 last_good_revision = 3;
|
|
HealthStatus health = 4;
|
|
// Version of the managed service, e.g. "BIND 9.20.3" or "Kea 3.2.1".
|
|
string service_version = 5;
|
|
string hostname = 6;
|
|
}
|
|
|
|
message Heartbeat {
|
|
uint64 applied_revision = 1;
|
|
HealthStatus health = 2;
|
|
uint64 last_good_revision = 3;
|
|
}
|
|
|
|
message HealthStatus {
|
|
HealthState state = 1;
|
|
string message = 2;
|
|
google.protobuf.Timestamp checked_at = 3;
|
|
repeated HealthCheck checks = 4;
|
|
}
|
|
|
|
message HealthCheck {
|
|
string name = 1;
|
|
HealthState state = 2;
|
|
string message = 3;
|
|
}
|
|
|
|
// Welcome tells the agent its current settings.
|
|
message Welcome {
|
|
OperatingMode mode = 1;
|
|
google.protobuf.Duration pull_interval = 2;
|
|
google.protobuf.Duration heartbeat_interval = 3;
|
|
// Revision the agent should run (0 = none). In auto_pull mode the agent
|
|
// applies it right away if it is newer than its applied revision.
|
|
uint64 desired_revision = 4;
|
|
}
|
|
|
|
// Command is pushed by the server over the Connect stream.
|
|
message Command {
|
|
// Unique ID, echoed in CommandAck.
|
|
string command_id = 1;
|
|
oneof action {
|
|
ApplyRevisionCommand apply_revision = 10;
|
|
RenewCertificateCommand renew_certificate = 11;
|
|
}
|
|
}
|
|
|
|
// ApplyRevisionCommand asks the agent to fetch and apply a revision now.
|
|
message ApplyRevisionCommand {
|
|
uint64 revision = 1;
|
|
// Correlates server, agent logs and the deployment record.
|
|
string deployment_id = 2;
|
|
}
|
|
|
|
// RenewCertificateCommand asks the agent to renew its certificate now.
|
|
message RenewCertificateCommand {}
|
|
|
|
// CommandAck confirms receipt of a command. The outcome of an apply is
|
|
// reported separately via ReportDeployment.
|
|
message CommandAck {
|
|
string command_id = 1;
|
|
bool accepted = 2;
|
|
// Reason if not accepted (e.g. "maintenance window closed").
|
|
string message = 3;
|
|
}
|
|
|
|
message GetDesiredStateRequest {
|
|
uint64 applied_revision = 1;
|
|
}
|
|
|
|
message GetDesiredStateResponse {
|
|
// Revision the agent should run. 0 means no configuration assigned yet.
|
|
uint64 desired_revision = 1;
|
|
OperatingMode mode = 2;
|
|
google.protobuf.Duration pull_interval = 3;
|
|
// Set while an explicit push of desired_revision is open (not yet
|
|
// reported). The agent then applies desired_revision as a push with this
|
|
// deployment ID, also in manual mode (docs/adr/0022-ausrollen-pull-push-m4.md).
|
|
string deployment_id = 4;
|
|
}
|
|
|
|
message FetchBundleRequest {
|
|
uint64 revision = 1;
|
|
}
|
|
|
|
message FetchBundleResponse {
|
|
// Manifest bytes exactly as signed (JSON). Verify before parsing.
|
|
bytes manifest = 1;
|
|
// Ed25519 signature over manifest.
|
|
bytes signature = 2;
|
|
// Artifact contents; paths, modes and SHA-256 sums are in the manifest.
|
|
repeated Artifact artifacts = 3;
|
|
}
|
|
|
|
message Artifact {
|
|
string path = 1;
|
|
bytes content = 2;
|
|
}
|
|
|
|
// DeploymentTrigger says why an agent applied a revision.
|
|
enum DeploymentTrigger {
|
|
DEPLOYMENT_TRIGGER_UNSPECIFIED = 0;
|
|
DEPLOYMENT_TRIGGER_PULL = 1;
|
|
DEPLOYMENT_TRIGGER_PUSH = 2;
|
|
}
|
|
|
|
// DeploymentOutcome is the result of applying a revision.
|
|
enum DeploymentOutcome {
|
|
DEPLOYMENT_OUTCOME_UNSPECIFIED = 0;
|
|
// Validated, activated and healthy.
|
|
DEPLOYMENT_OUTCOME_SUCCEEDED = 1;
|
|
// Signature or syntax check failed; nothing was changed.
|
|
DEPLOYMENT_OUTCOME_REJECTED = 2;
|
|
// Activated but unhealthy; the previous revision was restored.
|
|
DEPLOYMENT_OUTCOME_ROLLED_BACK = 3;
|
|
// Activated, unhealthy and the rollback failed as well.
|
|
DEPLOYMENT_OUTCOME_FAILED = 4;
|
|
}
|
|
|
|
message ReportDeploymentRequest {
|
|
// Empty for pulls the server did not initiate.
|
|
string deployment_id = 1;
|
|
uint64 revision = 2;
|
|
DeploymentTrigger trigger = 3;
|
|
DeploymentOutcome outcome = 4;
|
|
// Human-readable details (English), e.g. checker output.
|
|
string message = 5;
|
|
// Revision active after this deployment.
|
|
uint64 active_revision = 6;
|
|
google.protobuf.Timestamp started_at = 7;
|
|
google.protobuf.Timestamp finished_at = 8;
|
|
}
|
|
|
|
message ReportDeploymentResponse {}
|
|
|
|
// LeaseState mirrors the Kea lease states relevant for address tracking.
|
|
enum LeaseState {
|
|
LEASE_STATE_UNSPECIFIED = 0;
|
|
LEASE_STATE_ACTIVE = 1;
|
|
LEASE_STATE_EXPIRED = 2;
|
|
LEASE_STATE_RELEASED = 3;
|
|
LEASE_STATE_DECLINED = 4;
|
|
}
|
|
|
|
message Lease {
|
|
// IPv4 or IPv6 address in text form.
|
|
string ip = 1;
|
|
// Hardware address, lowercase colon-separated.
|
|
string mac = 2;
|
|
string hostname = 3;
|
|
LeaseState state = 4;
|
|
google.protobuf.Timestamp expires_at = 5;
|
|
google.protobuf.Timestamp updated_at = 6;
|
|
// Kea subnet ID as rendered by the configuration generator.
|
|
uint32 subnet_id = 7;
|
|
string client_id = 8;
|
|
}
|
|
|
|
message ReportLeasesRequest {
|
|
// Monotonic per agent; lets the server drop duplicate batches.
|
|
uint64 sequence = 1;
|
|
// True if this batch is a full snapshot rather than a set of changes.
|
|
bool full_sync = 2;
|
|
repeated Lease leases = 3;
|
|
}
|
|
|
|
message ReportLeasesResponse {
|
|
uint64 acknowledged_sequence = 1;
|
|
}
|