Skip to content

Commit 51ff3b9

Browse files
authored
Merge pull request VOLTTRON#2882 from bonicim/feature/vctl-tag
Add --all-tagged option; add and fix vctl tests
2 parents 94e74e6 + 029454a commit 51ff3b9

File tree

3 files changed

+283
-48
lines changed

3 files changed

+283
-48
lines changed

volttron/platform/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ class ArgumentParser(_argparse.ArgumentParser):
326326

327327
def __init__(self, *args, **kwargs):
328328
allow_in_config = kwargs.pop('allow_in_config', True)
329-
super(ArgumentParser, self).__init__(*args, **kwargs)
329+
super(ArgumentParser, self).__init__(allow_abbrev=False, *args, **kwargs)
330330
self.allow_in_config = allow_in_config
331331
self.register('action', 'add_const', AddConstAction)
332332
self.register('action', 'store_list', ListAction)

volttron/platform/control.py

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,7 @@ def wrapper(opts, *args, **kwargs):
818818
return func(opts, *args, **kwargs)
819819
return wrapper
820820

821+
821822
def _list_agents(aip):
822823
return [
823824
Agent(name, aip.agent_tag(uuid), uuid, aip.agent_identity(uuid), "")
@@ -845,13 +846,13 @@ def escape(pattern):
845846

846847

847848
def filter_agents(agents, patterns, opts):
848-
by_name, by_tag, by_uuid = opts.by_name, opts.by_tag, opts.by_uuid
849+
by_name, by_tag, by_uuid, by_all_tagged = opts.by_name, opts.by_tag, opts.by_uuid, opts.by_all_tagged
849850
for pattern in patterns:
850851
regex, _ = escape(pattern)
851852
result = set()
852853

853854
# if no option is selected, try matching based on uuid
854-
if not (by_uuid or by_name or by_tag):
855+
if not (by_uuid or by_name or by_tag or by_all_tagged):
855856
reobj = re.compile(regex)
856857
matches = [agent for agent in agents if reobj.match(agent.uuid)]
857858
if len(matches) == 1:
@@ -873,6 +874,9 @@ def filter_agents(agents, patterns, opts):
873874
if by_tag:
874875
result.update(
875876
agent for agent in agents if reobj.match(agent.tag or ""))
877+
if by_all_tagged:
878+
result.update(
879+
agent for agent in agents if reobj.match(agent.tag))
876880
yield pattern, result
877881

878882

@@ -1534,43 +1538,51 @@ def disable_agent(opts):
15341538

15351539
@needs_connection
15361540
def start_agent(opts):
1537-
call = opts.connection.call
1538-
agents = _list_agents(opts.aip)
1539-
for pattern, match in filter_agents(agents, opts.pattern, opts):
1540-
if not match:
1541-
_stderr.write(
1542-
"{}: error: agent not found: {}\n".format(opts.command,
1543-
pattern)
1544-
)
1545-
for agent in match:
1546-
pid, status = call("agent_status", agent.uuid)
1547-
if pid is None or status is not None:
1548-
_stdout.write(
1549-
"Starting {} {}\n".format(agent.uuid, agent.name))
1550-
call("start_agent", agent.uuid)
1541+
act_on_agent("start_agent", opts)
15511542

15521543

15531544
@needs_connection
15541545
def stop_agent(opts):
1546+
act_on_agent("stop_agent", opts)
1547+
1548+
1549+
def restart_agent(opts):
1550+
act_on_agent("stop_agent", opts)
1551+
act_on_agent("start_agent", opts)
1552+
1553+
1554+
def act_on_agent(action, opts):
15551555
call = opts.connection.call
15561556
agents = _list_agents(opts.aip)
1557-
for pattern, match in filter_agents(agents, opts.pattern, opts):
1557+
pattern_to_use = opts.pattern
1558+
1559+
if not opts.by_all_tagged and not opts.pattern:
1560+
raise ValueError("Missing argument. Command requires at least one argument.")
1561+
1562+
# prefilter all agents and update regex pattern for only tagged agents
1563+
if opts.by_all_tagged and not opts.pattern:
1564+
agents, pattern_to_use = [a for a in agents if a.tag is not None], '*'
1565+
1566+
for pattern, match in filter_agents(agents, pattern_to_use, opts):
15581567
if not match:
1559-
_stderr.write(
1560-
"{}: error: agent not found: {}\n".format(opts.command,
1561-
pattern)
1562-
)
1568+
_stderr.write(f"{opts.command}: error: agent not found: {pattern}\n")
15631569
for agent in match:
15641570
pid, status = call("agent_status", agent.uuid)
1565-
if pid and status is None:
1566-
_stdout.write(
1567-
"Stopping {} {}\n".format(agent.uuid, agent.name))
1568-
call("stop_agent", agent.uuid)
1571+
_call_action_on_agent(agent, pid, status, call, action)
15691572

15701573

1571-
def restart_agent(opts):
1572-
stop_agent(opts)
1573-
start_agent(opts)
1574+
def _call_action_on_agent(agent, pid, status, call, action):
1575+
if action == "start_agent":
1576+
if pid is None or status is not None:
1577+
_stdout.write(f"Starting {agent.uuid} {agent.name}\n")
1578+
call(action, agent.uuid)
1579+
return
1580+
1581+
if action == "stop_agent":
1582+
if pid and status is None:
1583+
_stdout.write(f"Stopping {agent.uuid} {agent.name}\n")
1584+
call(action, agent.uuid)
1585+
return
15741586

15751587

15761588
@needs_connection
@@ -3264,13 +3276,17 @@ def main():
32643276
"--tag", dest="by_tag", action="store_true",
32653277
help="filter/search by tag name"
32663278
)
3279+
filterable.add_argument(
3280+
"--all-tagged", dest="by_all_tagged", action="store_true",
3281+
help="filter/search by all tagged agents"
3282+
)
32673283
filterable.add_argument(
32683284
"--uuid",
32693285
dest="by_uuid",
32703286
action="store_true",
32713287
help="filter/search by UUID (default)",
32723288
)
3273-
filterable.set_defaults(by_name=False, by_tag=False, by_uuid=False)
3289+
filterable.set_defaults(by_name=False, by_tag=False, by_all_tagged=False, by_uuid=False)
32743290

32753291
parser = config.ArgumentParser(
32763292
prog=os.path.basename(sys.argv[0]),
@@ -3423,7 +3439,7 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser:
34233439

34243440
start = add_parser("start", parents=[filterable],
34253441
help="start installed agent")
3426-
start.add_argument("pattern", nargs="+", help="UUID or name of agent")
3442+
start.add_argument("pattern", nargs="*", help="UUID or name of agent", default='')
34273443
if HAVE_RESTRICTED:
34283444
start.add_argument(
34293445
"--verify",
@@ -3440,11 +3456,11 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser:
34403456
start.set_defaults(func=start_agent)
34413457

34423458
stop = add_parser("stop", parents=[filterable], help="stop agent")
3443-
stop.add_argument("pattern", nargs="+", help="UUID or name of agent")
3459+
stop.add_argument("pattern", nargs="*", help="UUID or name of agent", default='')
34443460
stop.set_defaults(func=stop_agent)
34453461

34463462
restart = add_parser("restart", parents=[filterable], help="restart agent")
3447-
restart.add_argument("pattern", nargs="+", help="UUID or name of agent")
3463+
restart.add_argument("pattern", nargs="*", help="UUID or name of agent", default='')
34483464
restart.set_defaults(func=restart_agent)
34493465

34503466
run = add_parser("run", help="start any agent by path")

0 commit comments

Comments
 (0)