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 OBJECT_AGENT_RELEASES: &str = "agent_releases";
17
18pub const KEY_AGENT_TARGET_VERSION: &str = "target_version";
22
23pub const KEY_AGENT_CONFIG_GLOBAL: &str = "global";
31pub const PREFIX_AGENT_CONFIG_GROUPS: &str = "groups.";
32pub const PREFIX_AGENT_CONFIG_PCS: &str = "pcs.";
33
34pub fn agent_config_group_key(group: &str) -> String {
35 format!("{PREFIX_AGENT_CONFIG_GROUPS}{group}")
36}
37
38pub fn agent_config_pc_key(pc_id: &str) -> String {
39 format!("{PREFIX_AGENT_CONFIG_PCS}{pc_id}")
40}
41
42pub fn parse_agent_config_group_key(key: &str) -> Option<&str> {
45 key.strip_prefix(PREFIX_AGENT_CONFIG_GROUPS)
46}
47
48pub fn parse_agent_config_pc_key(key: &str) -> Option<&str> {
50 key.strip_prefix(PREFIX_AGENT_CONFIG_PCS)
51}
52
53pub const SCRIPT_STATUS_ACTIVE: &str = "ACTIVE";
54pub const SCRIPT_STATUS_REVOKED: &str = "REVOKED";
55
56pub const STREAM_INVENTORY: &str = "INVENTORY";
57pub const STREAM_RESULTS: &str = "RESULTS";
58pub const STREAM_DEPLOY: &str = "DEPLOY";
59pub const STREAM_EVENTS: &str = "EVENTS";
60pub const STREAM_AUDIT: &str = "AUDIT";
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
70 fn bucket_names_are_domain_safe() {
71 for name in [
72 BUCKET_SCRIPT_CURRENT,
73 BUCKET_SCRIPT_STATUS,
74 BUCKET_AGENTS_STATE,
75 BUCKET_AGENT_CONFIG,
76 BUCKET_AGENT_GROUPS,
77 BUCKET_SCHEDULES,
78 OBJECT_AGENT_RELEASES,
79 ] {
80 assert!(
81 !name.contains('.'),
82 "bucket name {name:?} contains a dot, which NATS KV rejects"
83 );
84 assert!(
85 name.chars()
86 .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
87 "bucket name {name:?} has non-domain-safe characters"
88 );
89 }
90 }
91
92 #[test]
93 fn stream_names_are_unique() {
94 let names = [
95 STREAM_INVENTORY,
96 STREAM_RESULTS,
97 STREAM_DEPLOY,
98 STREAM_EVENTS,
99 STREAM_AUDIT,
100 ];
101 let mut deduped = names.to_vec();
102 deduped.sort_unstable();
103 deduped.dedup();
104 assert_eq!(
105 deduped.len(),
106 names.len(),
107 "stream constants collide: {names:?}"
108 );
109 }
110
111 #[test]
112 fn script_status_strings() {
113 assert_eq!(SCRIPT_STATUS_ACTIVE, "ACTIVE");
114 assert_eq!(SCRIPT_STATUS_REVOKED, "REVOKED");
115 assert_ne!(SCRIPT_STATUS_ACTIVE, SCRIPT_STATUS_REVOKED);
116 }
117
118 #[test]
119 fn key_agent_target_version_constant() {
120 assert_eq!(KEY_AGENT_TARGET_VERSION, "target_version");
121 }
122
123 #[test]
124 fn agent_config_group_key_round_trips() {
125 let k = agent_config_group_key("canary");
126 assert_eq!(k, "groups.canary");
127 assert_eq!(parse_agent_config_group_key(&k), Some("canary"));
128 }
129
130 #[test]
131 fn agent_config_pc_key_round_trips() {
132 let k = agent_config_pc_key("MINIPC-01");
133 assert_eq!(k, "pcs.MINIPC-01");
134 assert_eq!(parse_agent_config_pc_key(&k), Some("MINIPC-01"));
135 }
136
137 #[test]
138 fn agent_config_scope_keys_do_not_collide() {
139 assert_ne!(PREFIX_AGENT_CONFIG_GROUPS, PREFIX_AGENT_CONFIG_PCS);
146 assert!(parse_agent_config_group_key("pcs.someone").is_none());
147 assert!(parse_agent_config_pc_key("groups.someone").is_none());
148 assert_eq!(parse_agent_config_group_key("global"), None);
149 assert_eq!(parse_agent_config_pc_key("global"), None);
150 }
151}