def _launch_agent(self, agent_uuid, agent_path, name=None): execenv = self.agents.get(agent_uuid) if execenv and execenv.process.poll() is None: _log.warning('request to start already running agent %s', agent_path) raise ValueError('agent is already running') pkg = UnpackedPackage(agent_path) if auth is not None and self.env.verify_agents: auth.UnpackedPackageVerifier(pkg.distinfo).verify() metadata = pkg.metadata try: exports = metadata['extensions']['python.exports'] except KeyError: try: exports = metadata['exports'] except KeyError: raise ValueError('no entry points exported') try: module = exports['volttron.agent']['launch'] except KeyError: try: module = exports['setuptools.installation']['eggsecutable'] except KeyError: _log.error('no agent launch class specified in package %s', agent_path) raise ValueError('no agent launch class specified in package') config = os.path.join(pkg.distinfo, 'config') tag = self.agent_tag(agent_uuid) environ = os.environ.copy() environ['PYTHONPATH'] = ':'.join([agent_path] + sys.path) environ['PATH'] = (os.path.abspath(os.path.dirname(sys.executable)) + ':' + environ['PATH']) if os.path.exists(config): environ['AGENT_CONFIG'] = config else: environ.pop('AGENT_CONFIG', None) if tag: environ['AGENT_TAG'] = tag else: environ.pop('AGENT_TAG', None) environ['AGENT_SUB_ADDR'] = self.subscribe_address environ['AGENT_PUB_ADDR'] = self.publish_address environ['AGENT_UUID'] = agent_uuid module, _, func = module.partition(':') if func: code = '__import__({0!r}, fromlist=[{1!r}]).{1}()'.format( module, func) argv = [sys.executable, '-c', code] else: argv = [sys.executable, '-m', module] resmon = getattr(self.env, 'resmon', None) if resmon is None: execenv = ExecutionEnvironment() else: execreqs = self._read_execreqs(pkg.distinfo) execenv = self._reserve_resources(resmon, execreqs) execenv.name = name or agent_path _log.info('starting agent %s', agent_path) data_dir = os.path.join(os.path.dirname(pkg.distinfo), '{}.agent-data'.format(pkg.package_name)) if not os.path.exists(data_dir): os.mkdir(data_dir) execenv.execute(argv, cwd=data_dir, env=environ, close_fds=True, stdin=open(os.devnull), stdout=PIPE, stderr=PIPE) self.agents[agent_uuid] = execenv pid = execenv.process.pid _log.info('agent %s has PID %s', agent_path, pid) gevent.spawn( log_stream, 'agents.stderr', name, pid, argv[0], _log_stream('agents.log', name, pid, logging.ERROR, gevent_readlines(execenv.process.stderr))) gevent.spawn(log_stream, 'agents.stdout', name, pid, argv[0], ((logging.INFO, line) for line in gevent_readlines(execenv.process.stdout)))
def start_agent(self, agent_uuid): name = self.agent_name(agent_uuid) agent_path = os.path.join(self.install_dir, agent_uuid, name) execenv = self.agents.get(agent_uuid) if execenv and execenv.process.poll() is None: _log.warning('request to start already running agent %s', agent_path) raise ValueError('agent is already running') pkg = UnpackedPackage(agent_path) if auth is not None and self.env.verify_agents: auth.UnpackedPackageVerifier(pkg.distinfo).verify() metadata = pkg.metadata try: exports = metadata['extensions']['python.exports'] except KeyError: try: exports = metadata['exports'] except KeyError: raise ValueError('no entry points exported') try: module = exports['volttron.agent']['launch'] except KeyError: try: module = exports['setuptools.installation']['eggsecutable'] except KeyError: _log.error('no agent launch class specified in package %s', agent_path) raise ValueError('no agent launch class specified in package') config = os.path.join(pkg.distinfo, 'config') tag = self.agent_tag(agent_uuid) environ = os.environ.copy() environ['PYTHONPATH'] = ':'.join([agent_path] + sys.path) environ['PATH'] = (os.path.abspath(os.path.dirname(sys.executable)) + ':' + environ['PATH']) if os.path.exists(config): environ['AGENT_CONFIG'] = config else: environ.pop('AGENT_CONFIG', None) if tag: environ['AGENT_TAG'] = tag else: environ.pop('AGENT_TAG', None) environ['AGENT_SUB_ADDR'] = self.subscribe_address environ['AGENT_PUB_ADDR'] = self.publish_address environ['AGENT_UUID'] = agent_uuid environ['_LAUNCHED_BY_PLATFORM'] = '1' #For backwards compatibility create the identity file if it does not exist. identity_file = os.path.join(self.install_dir, agent_uuid, "IDENTITY") if not os.path.exists(identity_file): _log.debug( 'IDENTITY FILE MISSING: CREATING IDENTITY FILE WITH VALUE: {}'. format(agent_uuid)) with open(identity_file, 'wb') as fp: fp.write(agent_uuid) with open(identity_file, 'rb') as fp: agent_vip_identity = fp.read() environ['AGENT_VIP_IDENTITY'] = agent_vip_identity module, _, func = module.partition(':') if func: code = '__import__({0!r}, fromlist=[{1!r}]).{1}()'.format( module, func) argv = [sys.executable, '-c', code] else: argv = [sys.executable, '-m', module] resmon = getattr(self.env, 'resmon', None) if resmon is None: execenv = ExecutionEnvironment() else: execreqs = self._read_execreqs(pkg.distinfo) execenv = self._reserve_resources(resmon, execreqs) execenv.name = name or agent_path _log.info('starting agent %s', agent_path) data_dir = self._get_data_dir(agent_path) execenv.execute(argv, cwd=data_dir, env=environ, close_fds=True, stdin=open(os.devnull), stdout=PIPE, stderr=PIPE) self.agents[agent_uuid] = execenv proc = execenv.process _log.info('agent %s has PID %s', agent_path, proc.pid) gevent.spawn( log_stream, 'agents.stderr', name, proc.pid, argv[0], log_entries('agents.log', name, proc.pid, logging.ERROR, proc.stderr)) gevent.spawn(log_stream, 'agents.stdout', name, proc.pid, argv[0], ((logging.INFO, line.rstrip('\r\n')) for line in proc.stdout)) return self.agent_status(agent_uuid)
def start_agent(self, agent_uuid): name = self.agent_name(agent_uuid) agent_dir = os.path.join(self.install_dir, agent_uuid) agent_path_with_name = os.path.join(agent_dir, name) execenv = self.agents.get(agent_uuid) if execenv and execenv.process.poll() is None: _log.warning('request to start already running agent %s', agent_path_with_name) raise ValueError('agent is already running') pkg = UnpackedPackage(agent_path_with_name) if auth is not None and self.env.verify_agents: auth.UnpackedPackageVerifier(pkg.distinfo).verify() metadata = pkg.metadata try: exports = metadata['extensions']['python.exports'] except KeyError: try: exports = metadata['exports'] except KeyError: raise ValueError('no entry points exported') try: module = exports['volttron.agent']['launch'] except KeyError: try: module = exports['setuptools.installation']['eggsecutable'] except KeyError: _log.error('no agent launch class specified in package %s', agent_path_with_name) raise ValueError('no agent launch class specified in package') config = os.path.join(pkg.distinfo, 'config') tag = self.agent_tag(agent_uuid) environ = os.environ.copy() environ['PYTHONPATH'] = ':'.join([agent_path_with_name] + sys.path) environ['PATH'] = (os.path.abspath(os.path.dirname(sys.executable)) + ':' + environ['PATH']) if os.path.exists(config): environ['AGENT_CONFIG'] = config else: environ.pop('AGENT_CONFIG', None) if tag: environ['AGENT_TAG'] = tag else: environ.pop('AGENT_TAG', None) environ['AGENT_SUB_ADDR'] = self.subscribe_address environ['AGENT_PUB_ADDR'] = self.publish_address environ['AGENT_UUID'] = agent_uuid environ['_LAUNCHED_BY_PLATFORM'] = '1' # For backwards compatibility create the identity file if it does not # exist. identity_file = os.path.join(self.install_dir, agent_uuid, "IDENTITY") if not os.path.exists(identity_file): _log.debug( 'IDENTITY FILE MISSING: CREATING IDENTITY FILE WITH VALUE: {}'. format(agent_uuid)) with open(identity_file, 'w') as fp: fp.write(agent_uuid) with open(identity_file, 'r') as fp: agent_vip_identity = fp.read() environ['AGENT_VIP_IDENTITY'] = agent_vip_identity module, _, func = module.partition(':') # if func: # code = '__import__({0!r}, fromlist=[{1!r}]).{1}()'.format(module, # func) # argv = [sys.executable, '-c', code] # else: argv = [sys.executable, '-m', module] resmon = getattr(self.env, 'resmon', None) agent_user = None data_dir = self._get_agent_data_dir(agent_path_with_name) if self.secure_agent_user: _log.info("Starting agent securely...") user_id_path = os.path.join(agent_dir, "USER_ID") try: with open(user_id_path, "r") as user_id_file: volttron_agent_id = user_id_file.readline() pwd.getpwnam(volttron_agent_id) agent_user = volttron_agent_id _log.info("Found secure volttron agent user {}".format( agent_user)) except (IOError, KeyError) as err: _log.info("No existing volttron agent user was found at {} due " "to {}".format(user_id_path, err)) # May be switched from normal to secure mode with existing agents. To handle this case # create users and also set permissions again for existing files agent_user = self.add_agent_user(name, agent_dir) self.set_agent_user_permissions(agent_user, agent_uuid, agent_dir) # additionally give permissions to contents of agent-data dir. # This is needed only for agents installed before switching to # secure mode. Agents installed in secure mode will own files # in agent-data dir # Moved this to the top so that "agent-data" directory gets # created in the beginning #data_dir = self._get_agent_data_dir(agent_path_with_name) for (root, directories, files) in os.walk(data_dir, topdown=True): for directory in directories: self.set_acl_for_path("rwx", agent_user, os.path.join(root, directory)) for f in files: self.set_acl_for_path("rwx", agent_user, os.path.join(root, f)) if self.message_bus == 'rmq': rmq_user = get_fq_identity(agent_vip_identity, self.instance_name) _log.info("Create RMQ user {} for agent {}".format(rmq_user, agent_vip_identity)) self.rmq_mgmt.create_user_with_permissions(rmq_user, self.rmq_mgmt.get_default_permissions(rmq_user), ssl_auth=True) key_file = certs.Certs().private_key_file(rmq_user) if not os.path.exists(key_file): # This could happen when user switches from zmq to rmq after installing agent _log.info(f"agent certs don't exists. creating certs for agent") certs.Certs().create_signed_cert_files(rmq_user, overwrite=False) if self.secure_agent_user: # give read access to user to its own private key file. self.set_acl_for_path("r", agent_user, key_file) if resmon is None: if agent_user: execenv = SecureExecutionEnvironment(agent_user=agent_user) else: execenv = ExecutionEnvironment() else: execreqs = self._read_execreqs(pkg.distinfo) execenv = self._reserve_resources(resmon, execreqs, agent_user=agent_user) execenv.name = name or agent_path_with_name _log.info('starting agent %s', agent_path_with_name) # data_dir = self._get_agent_data_dir(agent_path_with_name) _log.info("starting agent using {} ".format(type(execenv))) execenv.execute(argv, cwd=agent_path_with_name, env=environ, close_fds=True, stdin=open(os.devnull), stdout=PIPE, stderr=PIPE) self.agents[agent_uuid] = execenv proc = execenv.process _log.info('agent %s has PID %s', agent_path_with_name, proc.pid) gevent.spawn(log_stream, 'agents.stderr', name, proc.pid, argv[0], log_entries('agents.log', name, proc.pid, logging.ERROR, proc.stderr)) gevent.spawn(log_stream, 'agents.stdout', name, proc.pid, argv[0], ((logging.INFO, line) for line in (l.splitlines() for l in proc.stdout))) return self.agent_status(agent_uuid)