Ejemplo n.º 1
0
    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)))
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)