Skip to content

Commit 2e812e4

Browse files
committed
traffic_ctl: Add config reset command
Adds `traffic_ctl config reset` to reset configuration records to their default values. Supports both record name format (proxy.config.*) and YAML format (records.*) for path matching. There is no new ATS rpc handler needed it just use the existing API and checks for differences between current value and default value. This includes Autests. Examples: traffic_ctl config reset records traffic_ctl config reset proxy.config.diags.debug.enabled traffic_ctl config reset records.diags
1 parent 0e42870 commit 2e812e4

File tree

7 files changed

+272
-50
lines changed

7 files changed

+272
-50
lines changed

doc/appendices/command-line/traffic_ctl.en.rst

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,60 @@ Display the current value of a configuration record.
294294
max: !<tag:yaml.org,2002:int> 100
295295
296296
297+
.. program:: traffic_ctl config
298+
.. option:: reset PATH [PATH ...]
299+
300+
Reset configuration record(s) to their default values. The PATH argument is used as a
301+
regex pattern to match against record names. Multiple paths at once can be provided.
302+
303+
- ``records`` - Reset all configuration records to defaults
304+
- A partial path like ``proxy.config.http`` or ``records.http`` - Reset all records matching the pattern
305+
- A full record name like ``proxy.config.diags.debug.enabled`` - Reset a specific record
306+
307+
**Path Format Support**
308+
309+
Both record name format and YAML format are supported. Paths starting with ``records.``
310+
are automatically converted to ``proxy.config.`` before matching:
311+
312+
====================================== ======================================
313+
YAML Format Record Name Format
314+
====================================== ======================================
315+
``records.http`` ``proxy.config.http``
316+
``records.diags.debug.enabled`` ``proxy.config.diags.debug.enabled``
317+
``records.cache.ram_cache.size`` ``proxy.config.cache.ram_cache.size``
318+
====================================== ======================================
319+
320+
This allows you to use the same path style as in :file:`records.yaml` configuration files.
321+
322+
Examples:
323+
324+
Reset all records to defaults:
325+
326+
.. code-block:: bash
327+
328+
$ traffic_ctl config reset records
329+
330+
Reset all HTTP configuration records (both formats are equivalent):
331+
332+
.. code-block:: bash
333+
334+
$ traffic_ctl config reset proxy.config.http
335+
$ traffic_ctl config reset records.http
336+
337+
Reset a specific record:
338+
339+
.. code-block:: bash
340+
341+
$ traffic_ctl config reset proxy.config.diags.debug.enabled
342+
343+
Using YAML-style path for the same record:
344+
345+
.. code-block:: bash
346+
347+
$ traffic_ctl config reset records.diags.debug.enabled
348+
349+
350+
297351
.. program:: traffic_ctl config
298352
.. option:: status
299353

src/mgmt/rpc/handlers/config/Configuration.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,5 @@ reload_config(std::string_view const & /* id ATS_UNUSED */, YAML::Node const & /
206206

207207
return resp;
208208
}
209+
209210
} // namespace rpc::handlers::config

src/traffic_ctl/CtrlCommands.cc

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,21 @@ const StringToFormatFlagsMap _Fmt_str_to_enum = {
4545
{"json", BasePrinter::Options::FormatFlags::JSON},
4646
{"rpc", BasePrinter::Options::FormatFlags::RPC }
4747
};
48+
49+
constexpr std::string_view YAML_PREFIX{"records."};
50+
constexpr std::string_view RECORD_PREFIX{"proxy.config."};
51+
52+
/// Convert YAML-style path (records.diags.debug) to record name format (proxy.config.diags.debug).
53+
/// If the path doesn't start with "records.", it's returned unchanged.
54+
std::string
55+
yaml_to_record_name(std::string_view path)
56+
{
57+
swoc::TextView tv{path};
58+
if (tv.starts_with(YAML_PREFIX)) {
59+
return std::string{RECORD_PREFIX} + std::string{path.substr(YAML_PREFIX.size())};
60+
}
61+
return std::string{path};
62+
}
4863
} // namespace
4964

5065
BasePrinter::Options::FormatFlags
@@ -142,6 +157,9 @@ ConfigCommand::ConfigCommand(ts::Arguments *args) : RecordCommand(args)
142157
} else if (args->get(SET_STR)) {
143158
_printer = std::make_unique<ConfigSetPrinter>(printOpts);
144159
_invoked_func = [&]() { config_set(); };
160+
} else if (args->get(RESET_STR)) {
161+
_printer = std::make_unique<ConfigSetPrinter>(printOpts);
162+
_invoked_func = [&]() { config_reset(); };
145163
} else if (args->get(STATUS_STR)) {
146164
_printer = std::make_unique<ConfigStatusPrinter>(printOpts);
147165
_invoked_func = [&]() { config_status(); };
@@ -237,6 +255,49 @@ ConfigCommand::config_set()
237255
_printer->write_output(response);
238256
}
239257

258+
void
259+
ConfigCommand::config_reset()
260+
{
261+
auto const &paths = get_parsed_arguments()->get(RESET_STR);
262+
263+
// Build lookup request - always use REGEX to support partial path matching
264+
shared::rpc::RecordLookupRequest lookup_request;
265+
266+
if (paths.empty() || (paths.size() == 1 && paths[0] == "records")) {
267+
lookup_request.emplace_rec(".*", shared::rpc::REGEX, shared::rpc::CONFIG_REC_TYPES);
268+
} else {
269+
for (auto const &path : paths) {
270+
// Convert YAML-style path (records.*) to record name format (proxy.config.*)
271+
auto record_path = yaml_to_record_name(path);
272+
lookup_request.emplace_rec(record_path, shared::rpc::REGEX, shared::rpc::CONFIG_REC_TYPES);
273+
}
274+
}
275+
276+
// Lookup matching records
277+
auto lookup_response = invoke_rpc(lookup_request);
278+
if (lookup_response.is_error()) {
279+
_printer->write_output(lookup_response);
280+
return;
281+
}
282+
283+
// Build reset request from modified records (current != default)
284+
auto const &records = lookup_response.result.as<shared::rpc::RecordLookUpResponse>();
285+
ConfigSetRecordRequest set_request;
286+
287+
for (auto const &rec : records.recordList) {
288+
if (rec.currentValue != rec.defaultValue) {
289+
set_request.params.push_back(ConfigSetRecordRequest::Params{rec.name, rec.defaultValue});
290+
}
291+
}
292+
293+
if (set_request.params.size() == 0) {
294+
std::cout << "No records to reset (all matching records are already at default values)\n";
295+
return;
296+
}
297+
298+
_printer->write_output(invoke_rpc(set_request));
299+
}
300+
240301
void
241302
ConfigCommand::config_reload()
242303
{

src/traffic_ctl/CtrlCommands.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class ConfigCommand : public RecordCommand
128128
static inline const std::string DIFF_STR{"diff"};
129129
static inline const std::string DEFAULTS_STR{"defaults"};
130130
static inline const std::string SET_STR{"set"};
131+
static inline const std::string RESET_STR{"reset"};
131132
static inline const std::string COLD_STR{"cold"};
132133
static inline const std::string APPEND_STR{"append"};
133134
static inline const std::string STATUS_STR{"status"};
@@ -141,6 +142,7 @@ class ConfigCommand : public RecordCommand
141142
void config_diff();
142143
void config_status();
143144
void config_set();
145+
void config_reset();
144146
void file_config_set();
145147
void config_reload();
146148
void config_show_file_registry();

src/traffic_ctl/traffic_ctl.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ main([[maybe_unused]] int argc, const char **argv)
134134
"Add type tag to the yaml field. This is needed if the record is not registered inside ATS. [only relevant if --cold set]",
135135
"", 1)
136136
.add_example_usage("traffic_ctl config set RECORD VALUE");
137+
config_command
138+
.add_command("reset", "Reset configuration values matching a path pattern to their defaults", "", MORE_THAN_ZERO_ARG_N,
139+
Command_Execute)
140+
.add_example_usage("traffic_ctl config reset records")
141+
.add_example_usage("traffic_ctl config reset proxy.config.http")
142+
.add_example_usage("traffic_ctl config reset proxy.config.http.cache_enabled");
137143

138144
config_command.add_command("registry", "Show configuration file registry", Command_Execute)
139145
.add_example_usage("traffic_ctl config registry");

tests/gold_tests/traffic_ctl/traffic_ctl_config_output.test.py

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,27 @@
4242

4343
##### CONFIG GET
4444

45-
# YAML output
45+
# Test 0: YAML output
4646
traffic_ctl.config().get("proxy.config.diags.debug.tags").as_records().validate_with_goldfile("t1_yaml.gold")
47-
# Default output
47+
# Test 1: Default output
4848
traffic_ctl.config().get("proxy.config.diags.debug.enabled").validate_with_text("proxy.config.diags.debug.enabled: 1")
49-
# Default output with default.
49+
# Test 2: Default output with default.
5050
traffic_ctl.config().get("proxy.config.diags.debug.tags").with_default() \
5151
.validate_with_text("proxy.config.diags.debug.tags: rpc # default http|dns")
5252

53-
# Now same output test but with defaults, traffic_ctl supports adding default value
53+
# Test 3: Now same output test but with defaults, traffic_ctl supports adding default value
5454
# when using --records.
5555
traffic_ctl.config().get("proxy.config.diags.debug.tags").as_records().with_default().validate_with_goldfile("t2_yaml.gold")
56+
# Test 4:
5657
traffic_ctl.config().get(
5758
"proxy.config.diags.debug.tags proxy.config.diags.debug.enabled proxy.config.diags.debug.throttling_interval_msec").as_records(
5859
).with_default().validate_with_goldfile("t3_yaml.gold")
5960

6061
##### CONFIG MATCH
62+
# Test 5:
6163
traffic_ctl.config().match("threads").with_default().validate_with_goldfile("match.gold")
6264

63-
# The idea is to check the traffic_ctl yaml emitter when a value starts with the
65+
# Test 6: The idea is to check the traffic_ctl yaml emitter when a value starts with the
6466
# same prefix of a node like:
6567
# diags:
6668
# logfile:
@@ -70,12 +72,70 @@
7072
traffic_ctl.config().match("diags.logfile").as_records().validate_with_goldfile("t4_yaml.gold")
7173

7274
##### CONFIG DIFF
75+
# Test 7:
7376
traffic_ctl.config().diff().validate_with_goldfile("diff.gold")
77+
# Test 8:
7478
traffic_ctl.config().diff().as_records().validate_with_goldfile("diff_yaml.gold")
7579

7680
##### CONFIG DESCRIBE
77-
# don't really care about values, but just output and that the command actually went through
81+
# Test 9: don't really care about values, but just output and that the command actually went through
7882
traffic_ctl.config().describe("proxy.config.http.server_ports").validate_with_goldfile("describe.gold")
7983

80-
# Make sure that the command returns an exit code of 2
84+
##### CONFIG RESET
85+
# Test 10: Reset a single modified record (proxy.config.diags.debug.tags is set to "rpc" in records_yaml,
86+
# default is "http|dns", so it should be reset)
87+
traffic_ctl.config().reset("proxy.config.diags.debug.tags").validate_with_text(
88+
"Set proxy.config.diags.debug.tags, please wait 10 seconds for traffic server to sync "
89+
"configuration, restart is not required")
90+
# Test 11: Validate the record was reset to its default value
91+
traffic_ctl.config().get("proxy.config.diags.debug.tags").validate_with_text("proxy.config.diags.debug.tags: http|dns")
92+
93+
# Test 12: Reset records matching a partial path (proxy.config.diags)
94+
# First set the record back to non-default for this test
95+
traffic_ctl.config().set("proxy.config.diags.debug.tags", "rpc").exec()
96+
# Test 13: Resetting proxy.config.diags should reset all matching modified records under that path
97+
traffic_ctl.config().reset("proxy.config.diags").validate_contains_all(
98+
"Set proxy.config.diags.debug.tags", "Set proxy.config.diags.debug.enabled")
99+
# Test 14: Validate the record was reset to its default value
100+
traffic_ctl.config().get("proxy.config.diags.debug.tags").validate_with_text("proxy.config.diags.debug.tags: http|dns")
101+
102+
# Test 15: Reset all records using "records" keyword
103+
# First set the record back to non-default for this test
104+
traffic_ctl.config().set("proxy.config.diags.debug.tags", "rpc").exec()
105+
# Test 16: This will reset all modified records (including proxy.config.diags.debug.tags)
106+
# Some may require restart, which is ok, we can use diff anyways as the records that needs
107+
# restart will just chage the value but won't have any effect.
108+
traffic_ctl.config().reset("records").exec()
109+
# Validate the diff
110+
# Test 17: Validate the diff
111+
traffic_ctl.config().diff().validate_with_text("")
112+
# Test 18: Validate the record was reset to its default value
113+
traffic_ctl.config().get("proxy.config.diags.debug.tags").validate_with_text("proxy.config.diags.debug.tags: http|dns")
114+
115+
# # Test resetting when no records need resetting (all already at default)
116+
# # Create a new instance with default values only
117+
# traffic_ctl_default = Make_traffic_ctl(Test, None)
118+
# traffic_ctl_default.config().reset("proxy.config.diags.debug.enabled").validate_with_text(
119+
# "No records to reset (all matching records are already at default values)")
120+
121+
##### CONFIG RESET with YAML-style paths (records.* format)
122+
# Test 19: Set a record to non-default first
123+
traffic_ctl.config().set("proxy.config.diags.debug.tags", "yaml_test").exec()
124+
# Test 20: Reset using YAML-style path (records.diags.debug.tags instead of proxy.config.diags.debug.tags)
125+
traffic_ctl.config().reset("records.diags.debug.tags").validate_with_text(
126+
"Set proxy.config.diags.debug.tags, please wait 10 seconds for traffic server to sync "
127+
"configuration, restart is not required")
128+
# Test 21: Validate the record was reset to its default value
129+
traffic_ctl.config().get("proxy.config.diags.debug.tags").validate_with_text("proxy.config.diags.debug.tags: http|dns")
130+
131+
# Test 22: Reset using YAML-style partial path (records.diags)
132+
traffic_ctl.config().set("proxy.config.diags.debug.tags", "yaml_partial_test").exec()
133+
traffic_ctl.config().set("proxy.config.diags.debug.enabled", "1").exec()
134+
# Test 23: Reset using records.diags (YAML format)
135+
traffic_ctl.config().reset("records.diags").validate_contains_all(
136+
"Set proxy.config.diags.debug.tags", "Set proxy.config.diags.debug.enabled")
137+
# Test 24: Validate record was reset
138+
traffic_ctl.config().get("proxy.config.diags.debug.tags").validate_with_text("proxy.config.diags.debug.tags: http|dns")
139+
140+
# Test 25: Make sure that the command returns an exit code of 2
81141
traffic_ctl.config().get("invalid.should.set.the.exit.code.to.2").validate_with_exit_code(2)

0 commit comments

Comments
 (0)