1pub const BUCKET_SCRIPT_CURRENT: &str = "script_current";
8pub const BUCKET_SCRIPT_STATUS: &str = "script_status";
9pub const BUCKET_AGENTS_STATE: &str = "agents_state";
10pub const BUCKET_AGENT_CONFIG: &str = "agent_config";
11pub const BUCKET_AGENT_GROUPS: &str = "agent_groups";
12pub const BUCKET_SCHEDULES: &str = "schedules";
13
14pub const BUCKET_JOBS: &str = "jobs";
20
21pub const OBJECT_AGENT_RELEASES: &str = "agent_releases";
24
25pub const KEY_AGENT_TARGET_VERSION: &str = "target_version";
29
30pub const KEY_AGENT_CONFIG_GLOBAL: &str = "global";
38pub const PREFIX_AGENT_CONFIG_GROUPS: &str = "groups.";
39pub const PREFIX_AGENT_CONFIG_PCS: &str = "pcs.";
40
41pub fn agent_config_group_key(group: &str) -> String {
42 format!("{PREFIX_AGENT_CONFIG_GROUPS}{group}")
43}
44
45pub fn agent_config_pc_key(pc_id: &str) -> String {
46 format!("{PREFIX_AGENT_CONFIG_PCS}{pc_id}")
47}
48
49pub fn parse_agent_config_group_key(key: &str) -> Option<&str> {
52 key.strip_prefix(PREFIX_AGENT_CONFIG_GROUPS)
53}
54
55pub fn parse_agent_config_pc_key(key: &str) -> Option<&str> {
57 key.strip_prefix(PREFIX_AGENT_CONFIG_PCS)
58}
59
60pub const SCRIPT_STATUS_ACTIVE: &str = "ACTIVE";
61pub const SCRIPT_STATUS_REVOKED: &str = "REVOKED";
62
63pub const STREAM_INVENTORY: &str = "INVENTORY";
64pub const STREAM_RESULTS: &str = "RESULTS";
65pub const STREAM_EXEC: &str = "EXEC";
66pub const STREAM_EVENTS: &str = "EVENTS";
67pub const STREAM_AUDIT: &str = "AUDIT";
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
77 fn bucket_names_are_domain_safe() {
78 for name in [
79 BUCKET_SCRIPT_CURRENT,
80 BUCKET_SCRIPT_STATUS,
81 BUCKET_AGENTS_STATE,
82 BUCKET_AGENT_CONFIG,
83 BUCKET_AGENT_GROUPS,
84 BUCKET_SCHEDULES,
85 BUCKET_JOBS,
86 OBJECT_AGENT_RELEASES,
87 ] {
88 assert!(
89 !name.contains('.'),
90 "bucket name {name:?} contains a dot, which NATS KV rejects"
91 );
92 assert!(
93 name.chars()
94 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
95 "bucket name {name:?} has non-domain-safe characters"
96 );
97 }
98 }
99
100 #[test]
101 fn stream_names_are_unique() {
102 let names = [
103 STREAM_INVENTORY,
104 STREAM_RESULTS,
105 STREAM_EXEC,
106 STREAM_EVENTS,
107 STREAM_AUDIT,
108 ];
109 let mut deduped = names.to_vec();
110 deduped.sort_unstable();
111 deduped.dedup();
112 assert_eq!(
113 deduped.len(),
114 names.len(),
115 "stream constants collide: {names:?}"
116 );
117 }
118
119 #[test]
120 fn script_status_strings() {
121 assert_eq!(SCRIPT_STATUS_ACTIVE, "ACTIVE");
122 assert_eq!(SCRIPT_STATUS_REVOKED, "REVOKED");
123 assert_ne!(SCRIPT_STATUS_ACTIVE, SCRIPT_STATUS_REVOKED);
124 }
125
126 #[test]
127 fn key_agent_target_version_constant() {
128 assert_eq!(KEY_AGENT_TARGET_VERSION, "target_version");
129 }
130
131 #[test]
132 fn agent_config_group_key_round_trips() {
133 let k = agent_config_group_key("canary");
134 assert_eq!(k, "groups.canary");
135 assert_eq!(parse_agent_config_group_key(&k), Some("canary"));
136 }
137
138 #[test]
139 fn agent_config_pc_key_round_trips() {
140 let k = agent_config_pc_key("MINIPC-01");
141 assert_eq!(k, "pcs.MINIPC-01");
142 assert_eq!(parse_agent_config_pc_key(&k), Some("MINIPC-01"));
143 }
144
145 #[test]
146 fn agent_config_scope_keys_do_not_collide() {
147 assert_ne!(PREFIX_AGENT_CONFIG_GROUPS, PREFIX_AGENT_CONFIG_PCS);
154 assert!(parse_agent_config_group_key("pcs.someone").is_none());
155 assert!(parse_agent_config_pc_key("groups.someone").is_none());
156 assert_eq!(parse_agent_config_group_key("global"), None);
157 assert_eq!(parse_agent_config_pc_key("global"), None);
158 }
159}