From cbcdd28dc9a96b018219a25cef8b1d1bfc3320fe Mon Sep 17 00:00:00 2001 From: "C. Allwardt" <3979063+craig8@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:09:49 -0700 Subject: [PATCH 01/11] fix when vctl is called with no arguments. --- volttron/platform/control/control_parser.py | 320 ++++++++++---------- 1 file changed, 157 insertions(+), 163 deletions(-) diff --git a/volttron/platform/control/control_parser.py b/volttron/platform/control/control_parser.py index 0c10fd44a9..5a256800d2 100644 --- a/volttron/platform/control/control_parser.py +++ b/volttron/platform/control/control_parser.py @@ -24,27 +24,26 @@ # Monkeypatch for gevent from volttron.utils import monkey_patch + monkey_patch() import argparse import collections import logging -import logging.handlers import logging.config +import logging.handlers import os import sys - -from datetime import timedelta, datetime +from datetime import datetime, timedelta import gevent import gevent.event -# noinspection PyUnresolvedReferences - from volttron.platform import aip as aipmod -from volttron.platform import config -from volttron.platform import get_home, get_address -from volttron.platform import jsonapi +from volttron.platform import config, get_address, get_home, is_rabbitmq_available, jsonapi +from volttron.platform.agent import utils +from volttron.platform.agent.known_identities import PLATFORM_HEALTH +from volttron.platform.agent.utils import is_secure_mode, wait_for_volttron_shutdown from volttron.platform.control.control_auth import add_auth_parser from volttron.platform.control.control_certs import add_certs_parser from volttron.platform.control.control_config import add_config_store_parser @@ -52,25 +51,18 @@ from volttron.platform.control.control_rmq import add_rabbitmq_parser from volttron.platform.control.control_rpc import add_rpc_agent_parser from volttron.platform.control.control_utils import ( - _list_agents, - _show_filtered_agents, - _show_filtered_agents_status, - filter_agent, - filter_agents, - get_filtered_agents - ) -from volttron.platform.agent import utils -from volttron.platform.agent.known_identities import PLATFORM_HEALTH + _list_agents, _show_filtered_agents, _show_filtered_agents_status, + filter_agent, filter_agents, get_filtered_agents) +from volttron.platform.control.install_agents import InstallRuntimeError, add_install_agent_parser from volttron.platform.jsonrpc import RemoteError from volttron.platform.keystore import KeyStore, KnownHostsStore +from volttron.platform.vip.agent.errors import Unreachable, VIPError + +# noinspection PyUnresolvedReferences -from volttron.platform.vip.agent.errors import VIPError, Unreachable -from volttron.platform.agent.utils import is_secure_mode, wait_for_volttron_shutdown -from volttron.platform.control.install_agents import add_install_agent_parser, InstallRuntimeError -from volttron.platform import is_rabbitmq_available if is_rabbitmq_available(): - from volttron.utils.rmq_setup import check_rabbit_status from volttron.utils.rmq_config_params import RMQConfig + from volttron.utils.rmq_setup import check_rabbit_status try: import volttron.restricted @@ -86,8 +78,7 @@ # will be volttron.platform.main or main.py instead of __main__ _log = logging.getLogger( - os.path.basename(sys.argv[0]) if __name__ == "__main__" else __name__ -) + os.path.basename(sys.argv[0]) if __name__ == "__main__" else __name__) # Allows server side logging. # _log.setLevel(logging.DEBUG) @@ -96,16 +87,16 @@ CHUNK_SIZE = 4096 -def log_to_file(file, level=logging.WARNING, + +def log_to_file(file, + level=logging.WARNING, handler_class=logging.StreamHandler): """Direct log output to a file (or something like one).""" handler = handler_class(file) handler.setLevel(level) handler.setFormatter( utils.AgentFormatter( - "%(asctime)s %(composite_name)s %(levelname)s: %(message)s" - ) - ) + "%(asctime)s %(composite_name)s %(levelname)s: %(message)s")) root = logging.getLogger() root.setLevel(level) root.addHandler(handler) @@ -123,17 +114,17 @@ def tag_agent(opts): msg = "multiple agents selected" else: msg = "agent not found" - _stderr.write( - "{}: error: {}: {}\n".format(opts.command, msg, opts.agent)) + _stderr.write("{}: error: {}: {}\n".format(opts.command, msg, + opts.agent)) return 10 - (agent,) = agents + (agent, ) = agents if opts.tag: _stdout.write("Tagging {} {}\n".format(agent.uuid, agent.name)) opts.aip.tag_agent(agent.uuid, opts.tag) elif opts.remove: if agent.tag is not None: - _stdout.write( - "Removing tag for {} {}\n".format(agent.uuid, agent.name)) + _stdout.write("Removing tag for {} {}\n".format( + agent.uuid, agent.name)) opts.aip.tag_agent(agent.uuid, None) else: if agent.tag is not None: @@ -144,27 +135,25 @@ def remove_agent(opts, remove_auth=True): agents = _list_agents(opts.aip) for pattern, match in filter_agents(agents, opts.pattern, opts): if not match: - _stderr.write( - "{}: error: agent not found: {}\n".format(opts.command, - pattern) - ) + _stderr.write("{}: error: agent not found: {}\n".format( + opts.command, pattern)) elif len(match) > 1 and not opts.force: _stderr.write( "{}: error: pattern returned multiple agents: {}\n".format( - opts.command, pattern - ) - ) + opts.command, pattern)) _stderr.write( "Use -f or --force to force removal of multiple agents.\n") return 10 for agent in match: _stdout.write("Removing {} {}\n".format(agent.uuid, agent.name)) - opts.connection.call("remove_agent", agent.uuid, + opts.connection.call("remove_agent", + agent.uuid, remove_auth=remove_auth) # TODO: Remove AIP def list_agents(opts): + def get_priority(agent): return opts.aip.agent_priority(agent.uuid) or "" @@ -193,11 +182,8 @@ def update_health_cache(opts): do_update = True # Make sure we update if we don't have any health dicts, or if the cache # has timed out. - if ( - health_cache_timeout_date is not None - and t_now < health_cache_timeout_date - and health_cache - ): + if (health_cache_timeout_date is not None + and t_now < health_cache_timeout_date and health_cache): do_update = False if do_update: @@ -205,12 +191,10 @@ def update_health_cache(opts): if opts.connection.server: health_cache.update( opts.connection.server.vip.rpc.call( - PLATFORM_HEALTH, "get_platform_health" - ).get(timeout=4) - ) + PLATFORM_HEALTH, "get_platform_health").get(timeout=4)) health_cache_timeout_date = datetime.now() + timedelta( - seconds=health_cache_timeout - ) + seconds=health_cache_timeout) + # TODO: Remove AIP def status_agents(opts): @@ -229,12 +213,14 @@ def status_agents(opts): agent = agents[uuid] agents[uuid] = agent._replace(agent_user=agent_user) except KeyError: - Agent = collections.namedtuple("Agent", - "name tag uuid vip_identity " - "agent_user") - agents[uuid] = agent = Agent( - name, None, uuid, vip_identity=identity, agent_user=agent_user - ) + Agent = collections.namedtuple( + "Agent", "name tag uuid vip_identity " + "agent_user") + agents[uuid] = agent = Agent(name, + None, + uuid, + vip_identity=identity, + agent_user=agent_user) status[uuid] = stat agents = list(agents.values()) @@ -268,6 +254,7 @@ def get_health(agent): _show_filtered_agents_status(opts, get_status, get_health, agents) + #TODO: Remove AIP def agent_health(opts): agents = {agent.uuid: agent for agent in _list_agents(opts.aip)}.values() @@ -295,21 +282,17 @@ def agent_health(opts): def clear_status(opts): opts.connection.call("clear_status", opts.clear_all) + # TODO: Remove AIP def enable_agent(opts): agents = _list_agents(opts.aip) for pattern, match in filter_agents(agents, opts.pattern, opts): if not match: - _stderr.write( - "{}: error: agent not found: {}\n".format(opts.command, - pattern) - ) + _stderr.write("{}: error: agent not found: {}\n".format( + opts.command, pattern)) for agent in match: - _stdout.write( - "Enabling {} {} with priority {}\n".format( - agent.uuid, agent.name, opts.priority - ) - ) + _stdout.write("Enabling {} {} with priority {}\n".format( + agent.uuid, agent.name, opts.priority)) opts.aip.prioritize_agent(agent.uuid, opts.priority) @@ -317,15 +300,13 @@ def disable_agent(opts): agents = _list_agents(opts.aip) for pattern, match in filter_agents(agents, opts.pattern, opts): if not match: - _stderr.write( - "{}: error: agent not found: {}\n".format(opts.command, - pattern) - ) + _stderr.write("{}: error: agent not found: {}\n".format( + opts.command, pattern)) for agent in match: priority = opts.aip.agent_priority(agent.uuid) if priority is not None: - _stdout.write( - "Disabling {} {}\n".format(agent.uuid, agent.name)) + _stdout.write("Disabling {} {}\n".format( + agent.uuid, agent.name)) opts.aip.prioritize_agent(agent.uuid, None) @@ -358,12 +339,16 @@ def act_on_agent(action, opts): agents, pattern_to_use = [a for a in agents if a.tag is not None], '*' # filter agents and update regex pattern - for pattern, filtered_agents in filter_agents(agents, pattern_to_use, opts): + for pattern, filtered_agents in filter_agents(agents, pattern_to_use, + opts): if not filtered_agents: - _stderr.write(f"Agents NOT found using 'vctl {opts.command}' on pattern: {pattern}\n") + _stderr.write( + f"Agents NOT found using 'vctl {opts.command}' on pattern: {pattern}\n" + ) for agent in filtered_agents: pid, status = call("agent_status", agent.uuid) - _call_action_on_agent(agent, pid, status, call, action) + _call_action_on_agent(agent, pid, status, call, action) + def _call_action_on_agent(agent, pid, status, call, action): if action == "start_agent": @@ -389,23 +374,17 @@ def shutdown_agents(opts): if "rmq" == utils.get_messagebus(): if not check_rabbit_status(): rmq_cfg = RMQConfig() - wait_period = ( - rmq_cfg.reconnect_delay() if rmq_cfg.reconnect_delay() < 60 - else 60 - ) + wait_period = (rmq_cfg.reconnect_delay() + if rmq_cfg.reconnect_delay() < 60 else 60) _stderr.write( "RabbitMQ server is not running.\n" "Waiting for {} seconds for possible reconnection and to " - "perform normal shutdown\n".format( - wait_period - ) - ) + "perform normal shutdown\n".format(wait_period)) gevent.sleep(wait_period) if not check_rabbit_status(): _stderr.write( "RabbitMQ server is still not running.\nShutting down " - "the platform forcefully\n" - ) + "the platform forcefully\n") opts.aip.brute_force_platform_shutdown() return opts.connection.call("shutdown") @@ -442,9 +421,8 @@ def send(): wheel.close() channel.close(linger=0) - result = connection.vip.rpc.call( - peer, "install_agent", os.path.basename(path), channel.name - ) + result = connection.vip.rpc.call(peer, "install_agent", + os.path.basename(path), channel.name) task = gevent.spawn(send) result.rawlink(lambda glt: task.kill(block=False)) _log.debug(f"Result is {result}") @@ -458,9 +436,6 @@ def send_agent(opts): return uuid - - - def do_stats(opts): call = opts.connection.call if opts.op == "status": @@ -478,7 +453,6 @@ def do_stats(opts): _stdout.write("%sabled\n" % ("en" if call("stats.enabled") else "dis")) - def priority(value): n = int(value) if not 0 <= n < 100: @@ -493,17 +467,18 @@ def get_keys(opts): key_store = KeyStore() publickey = key_store.public secretkey = key_store.secret - return {"publickey": publickey, "secretkey": secretkey, - "serverkey": serverkey} + return { + "publickey": publickey, + "secretkey": secretkey, + "serverkey": serverkey + } def main(): # Refuse to run as root if not getattr(os, "getuid", lambda: -1)(): - sys.stderr.write( - "%s: error: refusing to run as root to prevent " - "potential damage.\n" % os.path.basename(sys.argv[0]) - ) + sys.stderr.write("%s: error: refusing to run as root to prevent " + "potential damage.\n" % os.path.basename(sys.argv[0])) sys.exit(77) volttron_home = get_home() @@ -534,8 +509,7 @@ def main(): help="timeout in seconds for remote calls (default: %(default)g)", ) global_args.add_argument( - "--msgdebug", help="route all messages to an agent while debugging" - ) + "--msgdebug", help="route all messages to an agent while debugging") global_args.add_argument( "--vip-address", metavar="ZMQADDR", @@ -554,21 +528,24 @@ def main(): action="store_true", help="filter/search by agent name", ) - filterable.add_argument( - "--tag", dest="by_tag", action="store_true", - help="filter/search by tag name" - ) - filterable.add_argument( - "--all-tagged", dest="by_all_tagged", action="store_true", - help="filter/search by all tagged agents" - ) + filterable.add_argument("--tag", + dest="by_tag", + action="store_true", + help="filter/search by tag name") + filterable.add_argument("--all-tagged", + dest="by_all_tagged", + action="store_true", + help="filter/search by all tagged agents") filterable.add_argument( "--uuid", dest="by_uuid", action="store_true", help="filter/search by UUID (default)", ) - filterable.set_defaults(by_name=False, by_tag=False, by_all_tagged=False, by_uuid=False) + filterable.set_defaults(by_name=False, + by_tag=False, + by_all_tagged=False, + by_uuid=False) parser = config.ArgumentParser( prog=os.path.basename(sys.argv[0]), @@ -614,12 +591,13 @@ def main(): default=logging.WARNING, help="set logger verboseness", ) - parser.add_argument("--show-config", action="store_true", + parser.add_argument("--show-config", + action="store_true", help=argparse.SUPPRESS) - parser.add_argument( - "--json", action="store_true", default=False, - help="format output to json" - ) + parser.add_argument("--json", + action="store_true", + default=False, + help="format output to json") parser.add_help_argument() parser.set_defaults( @@ -627,9 +605,9 @@ def main(): volttron_home=volttron_home, ) - top_level_subparsers = parser.add_subparsers( - title="commands", metavar="", dest="command" - ) + top_level_subparsers = parser.add_subparsers(title="commands", + metavar="", + dest="command") def add_parser(*args, **kwargs) -> argparse.ArgumentParser: parents = kwargs.get("parents", []) @@ -643,28 +621,32 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: # ==================================================== add_install_agent_parser(add_parser, HAVE_RESTRICTED) - tag = add_parser("tag", parents=[filterable], + tag = add_parser("tag", + parents=[filterable], help="set, show, or remove agent tag") tag.add_argument("agent", help="UUID or name of agent") group = tag.add_mutually_exclusive_group() group.add_argument("tag", nargs="?", const=None, help="tag to give agent") - group.add_argument("-r", "--remove", action="store_true", + group.add_argument("-r", + "--remove", + action="store_true", help="remove tag") tag.set_defaults(func=tag_agent, tag=None, remove=False) remove = add_parser("remove", parents=[filterable], help="remove agent") remove.add_argument("pattern", nargs="+", help="UUID or name of agent") - remove.add_argument( - "-f", "--force", action="store_true", - help="force removal of multiple agents" - ) + remove.add_argument("-f", + "--force", + action="store_true", + help="force removal of multiple agents") remove.set_defaults(func=remove_agent, force=False) peers = add_parser("peerlist", help="list the peers connected to the platform") peers.set_defaults(func=list_peers) - list_ = add_parser("list", parents=[filterable], + list_ = add_parser("list", + parents=[filterable], help="list installed agent") list_.add_argument("pattern", nargs="*", help="UUID or name of agent") list_.add_argument( @@ -676,7 +658,8 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: ) list_.set_defaults(func=list_agents, min_uuid_len=1) - status = add_parser("status", parents=[filterable], + status = add_parser("status", + parents=[filterable], help="show status of agents") status.add_argument("pattern", nargs="*", help="UUID or name of agent") status.add_argument( @@ -688,9 +671,9 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: ) status.set_defaults(func=status_agents, min_uuid_len=1) - health = add_parser( - "health", parents=[filterable], help="show agent health as JSON" - ) + health = add_parser("health", + parents=[filterable], + help="show agent health as JSON") health.add_argument("pattern", nargs=1, help="UUID or name of agent") health.set_defaults(func=agent_health, min_uuid_len=1) @@ -704,27 +687,29 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: ) clear.set_defaults(func=clear_status, clear_all=False) - enable = add_parser( - "enable", parents=[filterable], - help="enable agent to start automatically" - ) + enable = add_parser("enable", + parents=[filterable], + help="enable agent to start automatically") enable.add_argument("pattern", nargs="+", help="UUID or name of agent") - enable.add_argument( - "-p", "--priority", type=priority, - help="2-digit priority from 00 to 99" - ) + enable.add_argument("-p", + "--priority", + type=priority, + help="2-digit priority from 00 to 99") enable.set_defaults(func=enable_agent, priority="50") - disable = add_parser( - "disable", parents=[filterable], - help="prevent agent from start automatically" - ) + disable = add_parser("disable", + parents=[filterable], + help="prevent agent from start automatically") disable.add_argument("pattern", nargs="+", help="UUID or name of agent") disable.set_defaults(func=disable_agent) - start = add_parser("start", parents=[filterable], + start = add_parser("start", + parents=[filterable], help="start installed agent") - start.add_argument("pattern", nargs="*", help="UUID or name of agent", default='') + start.add_argument("pattern", + nargs="*", + help="UUID or name of agent", + default='') if HAVE_RESTRICTED: start.add_argument( "--verify", @@ -741,11 +726,17 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: start.set_defaults(func=start_agent) stop = add_parser("stop", parents=[filterable], help="stop agent") - stop.add_argument("pattern", nargs="*", help="UUID or name of agent", default='') + stop.add_argument("pattern", + nargs="*", + help="UUID or name of agent", + default='') stop.set_defaults(func=stop_agent) restart = add_parser("restart", parents=[filterable], help="restart agent") - restart.add_argument("pattern", nargs="*", help="UUID or name of agent", default='') + restart.add_argument("pattern", + nargs="*", + help="UUID or name of agent", + default='') restart.set_defaults(func=restart_agent) run = add_parser("run", help="start any agent by path") @@ -765,7 +756,6 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: ) run.set_defaults(func=run_agent) - # ==================================================== # rpc commands # ==================================================== @@ -787,10 +777,9 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: add_config_store_parser(add_parser) shutdown = add_parser("shutdown", help="stop all agents") - shutdown.add_argument( - "--platform", action="store_true", - help="also stop the platform process" - ) + shutdown.add_argument("--platform", + action="store_true", + help="also stop the platform process") shutdown.set_defaults(func=shutdown_agents, platform=False) send = add_parser("send", help="send agent and start on a remote platform") @@ -800,9 +789,9 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: stats = add_parser("stats", help="manage router message statistics tracking") op = stats.add_argument( - "op", choices=["status", "enable", "disable", "dump", "pprint"], - nargs="?" - ) + "op", + choices=["status", "enable", "disable", "dump", "pprint"], + nargs="?") stats.set_defaults(func=do_stats, op="status") # ============================================================================== @@ -820,12 +809,14 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: "create-cgroups", help="setup VOLTTRON control group for restricted execution", ) - cgroup.add_argument( - "-u", "--user", metavar="USER", help="owning user name or ID" - ) - cgroup.add_argument( - "-g", "--group", metavar="GROUP", help="owning group name or ID" - ) + cgroup.add_argument("-u", + "--user", + metavar="USER", + help="owning user name or ID") + cgroup.add_argument("-g", + "--group", + metavar="GROUP", + help="owning group name or ID") cgroup.set_defaults(func=create_cgroups, user=None, group=None) # Parse and expand options @@ -840,10 +831,8 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: if args[0] not in ("list", "tag", "auth", "rabbitmq", "certs"): # check pid file if not utils.is_volttron_running(volttron_home): - _stderr.write( - "VOLTTRON is not running. This command " - "requires VOLTTRON platform to be running\n" - ) + _stderr.write("VOLTTRON is not running. This command " + "requires VOLTTRON platform to be running\n") return 10 conf = os.path.join(volttron_home, "config") @@ -868,13 +857,18 @@ def add_parser(*args, **kwargs) -> argparse.ArgumentParser: elif opts.log == "-": log_to_file(sys.stdout, level) elif opts.log: - log_to_file(opts.log, level, + log_to_file(opts.log, + level, handler_class=logging.handlers.WatchedFileHandler) else: log_to_file(None, 100, handler_class=lambda x: logging.NullHandler()) if opts.log_config: logging.config.fileConfig(opts.log_config) + if not hasattr(opts, "func"): + parser.print_help() + sys.exit(0) + opts.aip = aipmod.AIPplatform(opts) opts.aip.setup() From aa7f2f18f645ed0cc6f43e674f8084f4e15540a3 Mon Sep 17 00:00:00 2001 From: Chandrika Sivaramakrishnan Date: Tue, 20 Feb 2024 16:09:04 -0800 Subject: [PATCH 02/11] work around for issue #3154 --- volttron/platform/instance_setup.py | 68 +++++++++++------------------ 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/volttron/platform/instance_setup.py b/volttron/platform/instance_setup.py index a022639ec2..56cbdb26a3 100644 --- a/volttron/platform/instance_setup.py +++ b/volttron/platform/instance_setup.py @@ -39,7 +39,6 @@ from gevent.subprocess import Popen from zmq import green as zmq -from requirements import extras_require from volttron.platform import is_rabbitmq_available from volttron.platform.auth import certs from volttron.platform import jsonapi @@ -336,12 +335,7 @@ def _get_dependencies(): return dependencies -def _check_dependencies_met(requirement): - try: - dependencies_needed = extras_require[requirement] - except KeyError: - print(f"ERROR: Requirement {requirement} was not found in requirements.py") - return False +def _check_dependencies_met(dependencies_needed): current_dependencies = _get_dependencies() for dependency in dependencies_needed: if "==" in dependency: @@ -358,15 +352,21 @@ def _check_dependencies_met(requirement): def set_dependencies(requirement): try: + # go up two level above env/bin + sys.path.append(os.path.dirname(os.path.dirname(sys.path[0]))) + from requirements import extras_require dependencies_needed = extras_require[requirement] except KeyError: - print("ERROR: Incorrect requirement chosen") + print(f"ERROR: Incorrect requirement chosen: {requirement}") + return + + if not _check_dependencies_met(dependencies_needed): + print(f"Installing {requirement} dependencies...") + cmds = [sys.executable, "-m", "pip", "install"] + for dependency in dependencies_needed: + cmds.append(dependency) + subprocess.check_call(cmds) return - cmds = [sys.executable, "-m", "pip", "install"] - for dependency in dependencies_needed: - cmds.append(dependency) - subprocess.check_call(cmds) - return def _create_web_certs(): @@ -893,10 +893,7 @@ def wizard(): prompt = 'Is this instance web enabled?' response = prompt_response(prompt, valid_answers=y_or_n, default='N') if response in y: - if not _check_dependencies_met('web'): - print("Web dependencies not installed. Installing now...") - set_dependencies('web') - print("Done!") + set_dependencies('web') if config_opts['message-bus'] == 'rmq': do_web_enabled_rmq(volttron_home) elif config_opts['message-bus'] == 'zmq': @@ -916,13 +913,9 @@ def wizard(): prompt = 'Will this instance be controlled by volttron central?' response = prompt_response(prompt, valid_answers=y_or_n, default='Y') if response in y: - if not _check_dependencies_met("drivers") or not _check_dependencies_met("web"): - print("VCP dependencies not installed. Installing now...") - if not _check_dependencies_met("drivers"): - set_dependencies("drivers") - if not _check_dependencies_met("web"): - set_dependencies("web") - print("Done!") + print("Checking for VCP dependencies.....") + set_dependencies("drivers") + set_dependencies("web") do_vcp() prompt = 'Would you like to install a platform historian?' @@ -932,10 +925,8 @@ def wizard(): prompt = 'Would you like to install a platform driver?' response = prompt_response(prompt, valid_answers=y_or_n, default='N') if response in y: - if not _check_dependencies_met("drivers"): - print("Driver dependencies not installed. Installing now...") - set_dependencies("drivers") - print("Done!") + print("Checking Driver dependencies...") + set_dependencies("drivers") do_platform_driver() prompt = 'Would you like to install a listener agent?' @@ -954,13 +945,9 @@ def wizard(): prompt = 'Will this instance be controlled by volttron central?' response = prompt_response(prompt, valid_answers=y_or_n, default='Y') if response in y: - if not _check_dependencies_met("drivers") or not _check_dependencies_met("web"): - print("VCP dependencies not installed. Installing now...") - if not _check_dependencies_met("drivers"): - set_dependencies("drivers") - if not _check_dependencies_met("web"): - set_dependencies("web") - print("Done!") + print("Checking VCP dependencies...") + set_dependencies("drivers") + set_dependencies("web") do_vcp() prompt = 'Would you like to install a platform historian?' @@ -970,10 +957,8 @@ def wizard(): prompt = 'Would you like to install a platform driver?' response = prompt_response(prompt, valid_answers=y_or_n, default='N') if response in y: - if not _check_dependencies_met("drivers"): - print("Driver dependencies not installed. Installing now...") - set_dependencies("drivers") - print("Done!") + print("Checking Driver dependencies...") + set_dependencies("drivers") do_platform_driver() prompt = 'Would you like to install a listener agent?' @@ -1114,10 +1099,9 @@ def process_rmq_inputs(args_dict, instance_name=None): vhome = get_home() - if args_dict['installation-type'] in ['federation', 'shovel'] and not _check_dependencies_met('web'): - print("Web dependencies not installed. Installing now...") + if args_dict['installation-type'] in ['federation', 'shovel']: + print("Checking Web dependencies...") set_dependencies('web') - print("Done!") if args_dict['config'] is not None: if not os.path.exists(vhome): From 33672ff96a1c253efebf7211222f94142feb34cc Mon Sep 17 00:00:00 2001 From: "C. Allwardt" <3979063+craig8@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:33:56 -0700 Subject: [PATCH 03/11] bump actions to not have warnings for node 16 --- .github/workflows/pytest-auth.yml | 4 ++-- .github/workflows/pytest-dbutils-backup_db.yml | 4 ++-- .github/workflows/pytest-dbutils-influxdbfuncts.yml | 4 ++-- .github/workflows/pytest-dbutils-mysqlfuncts.yml | 4 ++-- .github/workflows/pytest-dbutils-postgresqlfuncts.yml | 4 ++-- .github/workflows/pytest-dbutils-sqlitefuncts.yml | 4 ++-- .github/workflows/pytest-dbutils-timescaldbfuncts.yml | 4 ++-- .github/workflows/pytest-miscellaneous-tests.yml | 4 ++-- .github/workflows/pytest-testutils.yml | 4 ++-- .github/workflows/pytest-vctl.yml | 4 ++-- .github/workflows/pytest-web.yml | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/pytest-auth.yml b/.github/workflows/pytest-auth.yml index 3b8c10c250..feaeca61bf 100644 --- a/.github/workflows/pytest-auth.yml +++ b/.github/workflows/pytest-auth.yml @@ -54,7 +54,7 @@ jobs: # setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -69,7 +69,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-backup_db.yml b/.github/workflows/pytest-dbutils-backup_db.yml index beecf28097..bc677c6b8d 100644 --- a/.github/workflows/pytest-dbutils-backup_db.yml +++ b/.github/workflows/pytest-dbutils-backup_db.yml @@ -55,7 +55,7 @@ jobs: # setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -75,7 +75,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-influxdbfuncts.yml b/.github/workflows/pytest-dbutils-influxdbfuncts.yml index ff3dcc5552..47b335e9e8 100644 --- a/.github/workflows/pytest-dbutils-influxdbfuncts.yml +++ b/.github/workflows/pytest-dbutils-influxdbfuncts.yml @@ -44,7 +44,7 @@ jobs: # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -64,7 +64,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-mysqlfuncts.yml b/.github/workflows/pytest-dbutils-mysqlfuncts.yml index 37e3068ffc..6454fa4a86 100644 --- a/.github/workflows/pytest-dbutils-mysqlfuncts.yml +++ b/.github/workflows/pytest-dbutils-mysqlfuncts.yml @@ -44,7 +44,7 @@ jobs: # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -64,7 +64,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-postgresqlfuncts.yml b/.github/workflows/pytest-dbutils-postgresqlfuncts.yml index 0398771cdb..87499a2384 100644 --- a/.github/workflows/pytest-dbutils-postgresqlfuncts.yml +++ b/.github/workflows/pytest-dbutils-postgresqlfuncts.yml @@ -44,7 +44,7 @@ jobs: # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -64,7 +64,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-sqlitefuncts.yml b/.github/workflows/pytest-dbutils-sqlitefuncts.yml index 3848e6efa8..e5bb742d7d 100644 --- a/.github/workflows/pytest-dbutils-sqlitefuncts.yml +++ b/.github/workflows/pytest-dbutils-sqlitefuncts.yml @@ -43,7 +43,7 @@ jobs: # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -63,7 +63,7 @@ jobs: test_output_suffix: ${{ env.OUTPUT_SUFFIX }} - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-dbutils-timescaldbfuncts.yml b/.github/workflows/pytest-dbutils-timescaldbfuncts.yml index 1aeb461487..7639d195c7 100644 --- a/.github/workflows/pytest-dbutils-timescaldbfuncts.yml +++ b/.github/workflows/pytest-dbutils-timescaldbfuncts.yml @@ -43,7 +43,7 @@ jobs: # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -63,7 +63,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-miscellaneous-tests.yml b/.github/workflows/pytest-miscellaneous-tests.yml index 9fc023b5a9..80dc6d8d27 100644 --- a/.github/workflows/pytest-miscellaneous-tests.yml +++ b/.github/workflows/pytest-miscellaneous-tests.yml @@ -51,7 +51,7 @@ jobs: # Setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -98,7 +98,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-testutils.yml b/.github/workflows/pytest-testutils.yml index 39cebe91aa..fa1a06887b 100644 --- a/.github/workflows/pytest-testutils.yml +++ b/.github/workflows/pytest-testutils.yml @@ -42,7 +42,7 @@ jobs: # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -57,7 +57,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-vctl.yml b/.github/workflows/pytest-vctl.yml index d0d5d868fb..b541753236 100644 --- a/.github/workflows/pytest-vctl.yml +++ b/.github/workflows/pytest-vctl.yml @@ -53,7 +53,7 @@ jobs: # Attempt to restore the cache from the build-dependency-cache workflow if present then # the output value steps.check_files.outputs.files_exists will be set (see the next step for usage) - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -68,7 +68,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report diff --git a/.github/workflows/pytest-web.yml b/.github/workflows/pytest-web.yml index 43b0540aa4..fe0496f35a 100644 --- a/.github/workflows/pytest-web.yml +++ b/.github/workflows/pytest-web.yml @@ -51,7 +51,7 @@ jobs: # setup the python environment for the operating system - name: Set up Python ${{matrix.os}} ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -66,7 +66,7 @@ jobs: # Archive the results from the pytest to storage. - name: Archive test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: pytest-report From 32d54ffe1f2a210f378dbd56c76809b4026d2d44 Mon Sep 17 00:00:00 2001 From: "C. Allwardt" <3979063+craig8@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:49:19 -0700 Subject: [PATCH 04/11] Update version of rtd --- docs/source/conf.py | 78 +++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 80eaeb23f6..dc75f60eb2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -16,12 +16,14 @@ # import sys # sys.path.insert(0, os.path.abspath('.')) -from glob import glob -from mock import Mock as MagicMock import os import subprocess import sys +from glob import glob + import yaml +from mock import Mock as MagicMock + # Copied from volttron.platform.agent.util because it is not required # that volttron be installed to utilize this script. @@ -69,14 +71,17 @@ def execute_command(cmds, class Mock(MagicMock): + @classmethod def __getattr__(cls, name): - return Mock() + return Mock() -autodoc_mock_imports = ['loadshape', 'numpy', 'sympy', 'xlrd', 'stomp', 'oadr2', 'pyodbc', 'lxml', 'pytest', - 'pint', 'pandas', 'suds', 'paho', 'pymongo', 'bson', 'subprocess32', 'heaters', 'meters', - 'hvac', 'blinds', 'vehicles'] +autodoc_mock_imports = [ + 'loadshape', 'numpy', 'sympy', 'xlrd', 'stomp', 'oadr2', 'pyodbc', 'lxml', + 'pytest', 'pint', 'pandas', 'suds', 'paho', 'pymongo', 'bson', + 'subprocess32', 'heaters', 'meters', 'hvac', 'blinds', 'vehicles' +] # -- Project information ----------------------------------------------------- @@ -87,8 +92,7 @@ def __getattr__(cls, name): # The short X.Y version version = '9.0' # The full version, including alpha/beta/rc tags -release = '9.0-rc' - +release = '9.0' # -- General configuration --------------------------------------------------- @@ -151,7 +155,6 @@ def __getattr__(cls, name): # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' - # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for @@ -180,13 +183,11 @@ def __getattr__(cls, name): # # html_sidebars = {} - # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'VOLTTRONdoc' - # -- Options for LaTeX output ------------------------------------------------ latex_elements = { @@ -215,16 +216,11 @@ def __getattr__(cls, name): 'The VOLTTRON Community', 'manual'), ] - # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (main_doc, 'volttron', 'VOLTTRON Documentation', - [author], 1) -] - +man_pages = [(main_doc, 'volttron', 'VOLTTRON Documentation', [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -232,20 +228,22 @@ def __getattr__(cls, name): # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (main_doc, 'VOLTTRON', 'VOLTTRON Documentation', - author, 'VOLTTRON', 'One line description of project.', - 'Miscellaneous'), + (main_doc, 'VOLTTRON', 'VOLTTRON Documentation', author, 'VOLTTRON', + 'One line description of project.', 'Miscellaneous'), ] - # -- Extension configuration ------------------------------------------------- # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/3.6': None, - 'volttron-ansible': ('https://volttron.readthedocs.io/projects/volttron-ansible/en/main/', - None)} +intersphinx_mapping = { + 'https://docs.python.org/3.6': + None, + 'volttron-ansible': + ('https://volttron.readthedocs.io/projects/volttron-ansible/en/main/', + None) +} # -- Options for todo extension ---------------------------------------------- @@ -290,11 +288,15 @@ def generate_apidoc(app): # generate api-docs for each api docs directory for docs_subdir in config.keys(): docs_subdir_path = os.path.join(apidocs_base_dir, docs_subdir) - agent_dirs = glob(os.path.join(volttron_root, config[docs_subdir]["path"], "*/")) + agent_dirs = glob( + os.path.join(volttron_root, config[docs_subdir]["path"], "*/")) file_excludes = [] if config[docs_subdir].get("file_excludes"): - for exclude_pattern in config[docs_subdir].get("file_excludes", []): - file_excludes.append(os.path.join(volttron_root, config[docs_subdir]["path"], exclude_pattern)) + for exclude_pattern in config[docs_subdir].get( + "file_excludes", []): + file_excludes.append( + os.path.join(volttron_root, config[docs_subdir]["path"], + exclude_pattern)) print("after file excludes. calling apidoc") agent_excludes = \ config[docs_subdir].get("agent_excludes") if config[docs_subdir].get("agent_excludes", []) else [] @@ -311,19 +313,24 @@ def run_apidoc(docs_dir, agent_dirs, agent_excludes, exclude_pattern): :param agent_excludes: agent directories to be skipped :param exclude_pattern: file name patterns to be excluded. This passed on to sphinx-apidoc command for exclude """ - print(f"In run apidoc params {docs_dir}, {agent_dirs}, {agent_excludes}, {exclude_pattern}") + print( + f"In run apidoc params {docs_dir}, {agent_dirs}, {agent_excludes}, {exclude_pattern}" + ) for agent_src_dir in agent_dirs: agent_src_dir = os.path.abspath(agent_src_dir) - agent_src_dir = agent_src_dir[:-1] if agent_src_dir.endswith("/") else agent_src_dir + agent_src_dir = agent_src_dir[:-1] if agent_src_dir.endswith( + "/") else agent_src_dir name = os.path.basename(agent_src_dir) agent_doc_dir = os.path.join(docs_dir, name) if name not in agent_excludes: sys.path.insert(0, agent_src_dir) - cmd = ["sphinx-apidoc", '-e', '-a', '-M', '-d 4', - '-t', os.path.join(script_dir, 'apidocs-templates'), - '--force', '-o', agent_doc_dir, agent_src_dir, - os.path.join(agent_src_dir, "setup.py"), os.path.join(agent_src_dir, "conftest.py") - ] + cmd = [ + "sphinx-apidoc", '-e', '-a', '-M', '-d 4', '-t', + os.path.join(script_dir, 'apidocs-templates'), '--force', '-o', + agent_doc_dir, agent_src_dir, + os.path.join(agent_src_dir, "setup.py"), + os.path.join(agent_src_dir, "conftest.py") + ] cmd.extend(exclude_pattern) subprocess.check_call(cmd) @@ -363,5 +370,6 @@ def clean_api_rst(app, exception): global apidocs_base_dir import shutil if os.path.exists(apidocs_base_dir): - print("Cleanup: Removing apidocs directory {}".format(apidocs_base_dir)) + print( + "Cleanup: Removing apidocs directory {}".format(apidocs_base_dir)) shutil.rmtree(apidocs_base_dir) From 169473deea22092979816de1fff7a1900691beed Mon Sep 17 00:00:00 2001 From: "C. Allwardt" <3979063+craig8@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:57:27 -0700 Subject: [PATCH 05/11] Remove slack from the community page --- docs/source/developing-volttron/community.rst | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/source/developing-volttron/community.rst b/docs/source/developing-volttron/community.rst index 05f32dde04..24718c7d1c 100644 --- a/docs/source/developing-volttron/community.rst +++ b/docs/source/developing-volttron/community.rst @@ -12,18 +12,10 @@ Contributing back to the project, which is encouraged but not required, enhances To learn more, check out :ref:`Contributing ` and :ref:`Documentation `. -Slack Channel -============= - -volttron-community.slack.com is where the |VOLTTRON| community at large can ask questions and meet with others -using |VOLTTRON|. To be added to Slack please email the VOLTTRON team at -`volttron@pnnl.gov `__. - - Mailing List ============ -Join the mailing list by emailing `volttron@pnnl.gov `__. +Join the mailing list at Eclipse: https://projects.eclipse.org/projects/iot.volttron/contact Stack Overflow @@ -39,8 +31,8 @@ Office Hours PNNL hosts office hours every other week on Fridays at 11 AM (PST). These meetings are designed to be very informal where VOLTTRON developers can answer specific questions about the inner workings of VOLTTRON. These meetings are also available for topical discussions of different aspects of the VOLTTRON platform. Currently the office hours are -available through a Zoom meeting. To be invited to the link meeting, contact the volttron team via email: -``__ +available through a Zoom meeting. All members of the mailing list will receive invites to the meetings. Join the +mailing list https://projects.eclipse.org/projects/iot.volttron/contact. Meetings are recorded and can be reviewed `here `__. From 3177ff8a7f837bce99efeafa7e4bc66da509beb8 Mon Sep 17 00:00:00 2001 From: Craig <3979063+craig8@users.noreply.github.com> Date: Mon, 25 Mar 2024 16:14:50 -0700 Subject: [PATCH 06/11] require 3.8 of python --- bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.py b/bootstrap.py index 6abc0ce359..19548817a4 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -227,7 +227,7 @@ def main(argv=sys.argv): sys.exit(77) # Python3 for life! - if sys.version_info.major < 3 or sys.version_info.minor < 6: + if sys.version_info.major < 3 or sys.version_info.minor < 8: sys.stderr.write('error: Python >= 3.8 is required\n') sys.exit(1) From db467aac631f04e1e21bfe63963b43bac3efd230 Mon Sep 17 00:00:00 2001 From: Chandrika Sivaramakrishnan Date: Tue, 26 Mar 2024 14:31:49 -0700 Subject: [PATCH 07/11] fix for issue#3159 (fix for deprecated pip --install-options) --- bootstrap.py | 2 +- requirements.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap.py b/bootstrap.py index 19548817a4..8121b03c4c 100644 --- a/bootstrap.py +++ b/bootstrap.py @@ -123,7 +123,7 @@ def update(operation, verbose=None, offline=False, optional_requirements=[], rab # option_requirements contains wheel as first entry # Build option_requirements separately to pass install options - build_option = '--build-option' if wheeling else '--install-option' + build_option = '--build-option' if wheeling else '--config-settings' for requirement, options in option_requirements: args = [] diff --git a/requirements.py b/requirements.py index 80fa44c40e..249d9b56ce 100644 --- a/requirements.py +++ b/requirements.py @@ -30,7 +30,7 @@ # wheel version 0.31 has removed metadata.json file # https://github.com/pypa/wheel/issues/195 # so sticking to 0.30 for now. Could upgrade to wheel 0.31 with code changes -option_requirements = [('wheel==0.30', []), ('pyzmq==22.2.1', ['--zmq=bundled'])] +option_requirements = [('pip==24.0', []), ('wheel==0.30', []), ('pyzmq==22.2.1', ['--zmq=bundled'])] install_requires = ['gevent==21.12.0', From cc71c445c749c04973a33a0bdcfdf94e26eeff57 Mon Sep 17 00:00:00 2001 From: Chandrika Sivaramakrishnan Date: Thu, 28 Mar 2024 11:00:42 -0700 Subject: [PATCH 08/11] handled minor gevent timeout --- volttrontesting/services/historian/test_historian.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/volttrontesting/services/historian/test_historian.py b/volttrontesting/services/historian/test_historian.py index afa49acf41..352cbfea6a 100644 --- a/volttrontesting/services/historian/test_historian.py +++ b/volttrontesting/services/historian/test_historian.py @@ -1443,6 +1443,8 @@ def test_invalid_query(request, historian, publish_agent, query_agent, start=now, count=20, order="LAST_TO_FIRST").get(timeout=10) + except gevent.timeout.Timeout: + assert True except Exception as error: print("exception: {}".format(error)) assert "No route to host:" in str(error) From 50290afbb6cc9176fda4d0f778e839bd2931626b Mon Sep 17 00:00:00 2001 From: "David M. Raker" Date: Thu, 28 Mar 2024 10:33:16 -0700 Subject: [PATCH 09/11] Minor updates to bacnet and modbus_tk tests. --- .../interfaces/modbus_tk/tests/test_battery_meter.py | 2 +- services/core/PlatformDriverAgent/tests/test_bacnet.py | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py index 5c7a868b66..0ac107061f 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_battery_meter.py @@ -387,7 +387,7 @@ def scrape_all(self, agent, device_name): return agent.vip.rpc.call(PLATFORM_DRIVER, 'scrape_all', device_name)\ .get(timeout=10) - @pytest.mark.xfail(is_running_in_container(), reason='Fails to set points on this test setup, only in Docker.') + @pytest.mark.skip('This test has been unreliable.') def test_scrape_all(self, agent): for key in registers_dict.keys(): self.set_point(agent, 'modbus_tk', key, registers_dict[key]) diff --git a/services/core/PlatformDriverAgent/tests/test_bacnet.py b/services/core/PlatformDriverAgent/tests/test_bacnet.py index 6c608e42e9..476a4fc5f2 100644 --- a/services/core/PlatformDriverAgent/tests/test_bacnet.py +++ b/services/core/PlatformDriverAgent/tests/test_bacnet.py @@ -77,7 +77,15 @@ def test_get_point_should_succeed(bacnet_test_agent): @pytest.fixture(scope="module") def bacnet_proxy_agent(volttron_instance): - device_address = socket.gethostbyname(socket.gethostname() + ".local") + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.settimeout(0) + try: + s.connect(('8.8.8.8', 1)) + device_address = s.getsockname()[0] + except Exception: + device_address = '127.0.0.1' + finally: + s.close() print(f"Device address for proxy agent for testing: {device_address}") bacnet_proxy_agent_config = { "device_address": device_address, From 74503d988a147a0bad5a69bf4eb392e355ec9d15 Mon Sep 17 00:00:00 2001 From: "David M. Raker" Date: Thu, 28 Mar 2024 14:04:13 -0700 Subject: [PATCH 10/11] Fixed missing import in modbus_tk/tests/test_driver_demo_board.py --- .../interfaces/modbus_tk/tests/test_driver_demo_board.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_driver_demo_board.py b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_driver_demo_board.py index ea58ded782..593c2a684f 100644 --- a/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_driver_demo_board.py +++ b/services/core/PlatformDriverAgent/platform_driver/interfaces/modbus_tk/tests/test_driver_demo_board.py @@ -2,6 +2,9 @@ import gevent import pytest + +from pathlib import Path + from volttron.platform.agent.known_identities import CONFIGURATION_STORE, PLATFORM_DRIVER from volttron.platform import jsonapi from volttrontesting.utils.platformwrapper import PlatformWrapper From 28e7f07836c0f2ce3a6a6105d4bfc6b4d3494ea5 Mon Sep 17 00:00:00 2001 From: Craig <3979063+craig8@users.noreply.github.com> Date: Fri, 29 Mar 2024 13:04:41 -0700 Subject: [PATCH 11/11] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 6999280281..bea8985a36 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ ![image](docs/source/files/VOLLTRON_Logo_Black_Horizontal_with_Tagline.png) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/fcf58045b4804edf8f4d3ecde3016f76)](https://app.codacy.com/gh/VOLTTRON/volttron?utm_source=github.com&utm_medium=referral&utm_content=VOLTTRON/volttron&utm_campaign=Badge_Grade_Settings) +# VOLTTRON + +This repository is for the current production VOLTTRON. We are working on VOLTTRON 10 (modular) which is available under +github at https://github.com/eclipse-volttron/. The modular version of VOLTTRON will help ease deployment and support +flexible deployment where in only required agents/applications can be installed, thereby simplifying setup and upgrade +steps for the end user. The VOLTTRON team are currently working on porting agents from monolithic VOLTTRON to the +modular version of VOLTTRON. To know more about modular VOLTTRON, please visit our new documentation site available +at https://eclipse-volttron.readthedocs.io/en/latest/. We would love for you to try it out and give us early +feedback. Also, until our work on modular VOLTTRON is completed, please continue cloning and using this +repository for your production systems. VOLTTRON™ is an open source platform for distributed sensing and control. The platform provides services for collecting and storing data from buildings and