def get_dependencies_for_product(self, product: BaseProduct): """ для онкретного продукта получить его зависимости, без рекурсии :param product: :return: """ if not product: return None #logging.debug("Get dependency for '{0}'".format(product)) dependencies_names = product.get_dependencies() dependencies = ProductCollection() if not dependencies_names: #logging.debug("There are no dependencies for '{0}'".format(product)) pass else: for name in dependencies_names: if isinstance(name, list): name = self.get_first_or_installed(name) logging.debug("choice dependence '{0}'".format(name)) dependent_product = self.core.feed.get_product_or_exception(name) dependencies.add_product(dependent_product) return dependencies
def remove_not_installed(self, products: ProductCollection): """ удалить из списка продуктов, те что еще не установлены используется для фильтра перед uninstall :param products: :return: """ logging.debug(products) result = ProductCollection() for p in products: if self.core.current_storage.is_product_installed(p.get_product_with_version()): result.append(p) logging.debug(result) return result
def remove_not_installed(self, products: ProductCollection): """ удалить из списка продуктов, те что еще не установлены используется для фильтра перед uninstall :param products: :return: """ logging.debug(products) result = ProductCollection() for p in products: if self.core.current_storage.is_product_installed( p.get_product_with_version()): result.append(p) logging.debug(result) return result
def create_uninstall_task(self, products: ProductCollection): """ фабричный метод: создать такс с переданными параметрами, с типом COMMAND_UNINSTALL сохранить в базе данных зхапустить воркер :param requested_products: :param products: :param parameter_manager: :return: """ title = 'Uninstalling products: {0}'.format(', '.join([product.title for product in products])) state = { 'products': products.get_names_list(), } settings = Core.get_instance().settings.get_state() task = Task( command=Task.COMMAND_UNINSTALL, title=title, params=json.dumps(state, sort_keys=True, indent=1), settings=json.dumps(settings, sort_keys=True, indent=1)) task.save() self.task = task self.run_worker(task.id) return task.id
def create_upgrade_task(self, requested_products: list, products: ProductCollection): """ фабричный метод: создать такс с переданными параметрами, с типом COMMAND_UPGRADE сохранить в базе данных зхапустить воркер :param requested_products: :param products: :param parameter_manager: :return: """ title = 'Upgrading products: {0}'.format(', '.join([product_name for product_name in requested_products])) state = { 'requested_products': requested_products, 'products': products.get_names_list(), 'parameters': {} } settings = Core.get_instance().settings.get_state() logging.debug('state: {0}'.format(state)) task = Task( command=Task.COMMAND_UPGRADE, title=title, params=json.dumps(state, sort_keys=True, indent=1), settings=json.dumps(settings, sort_keys=True, indent=1) ) task.save() # production # For debug worker uncomment this #self.task.execute() return task.id
def do(self): """ Install products by tornado worker """ parameters = None dm = DependencyManager() product_flat_list = [ dm.get_dependencies(product_name) for product_name in self.product_names ] product_list = InstallCommand.flat_deps4products( product_flat_list, False) if self.args_parameters.yml_params: parameters = ParametersParserYmlFile( self.args_parameters.yml_params).get() elif self.args_parameters.json_params: parameters = ParametersParserJsonFile( self.args_parameters.json_params).get() elif self.args_parameters.parameters: parameters = ParametersParserStr( self.args_parameters.parameters).get() else: # then fill with empty params parameters = EmptyParameters().get(product_list) # добывает список продуктов из списка имён products = ProductCollection(product_list, feeds=(self.core.feed, self.core.current), ready_json=True) # парсим параметры установки из запроса # создаём менеджер параметров parameter_manager = ParametersManager(self.core, products, parameters) # все ли параметры заполнены? if parameter_manager.are_all_parameters_filled(): # TODO move TornadoWorker to core # create tornado worker web.taskqueue.tornado_worker.TornadoWorker.create_instance() # всё ок, создаём задание на установку task = TaskFactory.create_task("install", products, parameter_manager) task_id = TaskManager.queue_task(task) callback_exit = lambda job, exit_code: InstallCommand.console_exit( self, job, exit_code) TornadoWorker.start_new_task(task, callback_exit, False) core.core.core_event_loop_start() else: raise InstallCommandError("Not all parameters specified")
def test_dependencies_versions2(self): products = ProductCollection(['A2']) dm = DependencyManager() products = dm.get_products_with_dependencies(products) self.assertEqual(len(products), 2) p1 = products[0] self.assertEqual(p1.name, 'P1') self.assertEqual(p1.version, '1.1') a1 = products[1] self.assertEqual(a1.name, 'A2')
def get_products_with_dependencies(self, product_collection: ProductCollection): """ плоский список продуктов и их зависимостей :param product_collection: :return: """ result = ProductCollection() self._get_products_with_dependencies(product_collection, result) #result.reverse() return result
def remove_installed(products: ProductCollection, strict_version=True): """ удалить из списка продуктов, те что уже установлены используется для фильтра перед install :param products: :param strict_version: :return: """ logging.debug('input product list: {0}'.format(products)) result = ProductCollection() for p in products: if strict_version: if not p.is_installed(): result.append(p) else: if not p.is_installed_any_version(): result.append(p) logging.debug('result product list: {0}'.format(result)) return result
def _get_products_with_dependencies(self, products: ProductCollection, result: ProductCollection): """ вспомогательная рекурсивная функция для поиска зависимостей :param products: :param result: :return: """ if not products: logging.debug("products is None") return for p in products: if not result.product_in_coll(p): result.add_product(p) logging.debug("Added '{0}'".format(p.get_product_with_version())) dependencies = self.get_dependencies_for_product(p) if dependencies and len(dependencies) > 0: # recursion ! for dep in dependencies: logging.debug("\tdependant from: '{0}'".format(dep.get_product_with_version())) self._get_products_with_dependencies(dependencies, result)
def create_install_task(self, requested_products: list, products: ProductCollection, parameter_manager: ParametersManager): """ фабричный метод: создать такс с переданными параметрами, с типом COMMAND_INSTALL сохранить в базе данных зхапустить воркер :param requested_products: те продукты которые выбрал пользователь :param products: продукты для установки (продукты которые выбрал пользователь + зависимости) :param parameter_manager: :return: номер таска """ title = 'Installing products: {0}'.format(', '.join([product_name for product_name in requested_products])) state = { 'requested_products': requested_products, 'products': products.to_json_list(), 'parameters': parameter_manager.get_state() } settings = Core.get_instance().settings.get_state() for product in products.to_json_list(): state = { 'requested_products': requested_products, 'products': product, 'parameters': parameter_manager.get_state() } state2save = json.dumps(state, sort_keys=True, indent=1) task = Task( command=Task.COMMAND_INSTALL, title=title, params=state2save, settings=json.dumps(settings, sort_keys=True, indent=1) ) task.save() # production # For debug worker uncomment this # self.task.execute() return task.id
def upgrade(request): """ Обрабатывает запросы на апгрейд продуктов. Форматы входных запросов и выходных ответов такие же как для install() """ if request.method != 'POST': # принимаем только пост-запросы return HttpResponseNotAllowed(['POST']) # парсим джейсон запрос req = json_request(request) initial = 'initial' in req dm = DependencyManager() requested_products = req['requested_products'] core = Core.get_instance() if initial: # если это начальный запрос, то отдаем дерево зависимостей resp = { 'task': None, 'items': [ dm.get_dependencies(product_name) for product_name in requested_products ] } else: # это запрос на апгрейд # список имён продуктов, которые нужно апгрейдить (с зависимостями) product_list = [item['product'] for item in req['install_products']] product_list.reverse() # добывает спсисоко продуктов из списка имён products = ProductCollection(product_list) parsed_parameters = ParametersParserJson(req['install_products']).get() # создаём менеджер параметров parameter_manager = ParametersManager(core, products, parsed_parameters) # создаёт задачу на апгрейд task = TaskFactory.create_task("upgrade", products, parameter_manager) task_id = TaskManager.queue_task(task) TornadoWorker.start_new_task(task) resp = { 'task': { 'id': task_id, }, 'items': None } return resp
def uninstall(request): """ Обрабатывает запросы на деинсталляцию продуктов. """ if request.method != 'POST': # принимаем только пост-запросы return HttpResponseNotAllowed(['POST']) # парсим джейсон запрос req = json_request(request) # это начальный запрос ? # список имён продуктов для деинсталляции requested_products = req['requested_products'] # добываем список продуктов из списка имён products = ProductCollection( [product_name for product_name in requested_products], feed=Core.get_instance().current_storage.feed, # feed=Core.get_instance().feed, fail_on_product_not_found=False) if req["command"] == "start": # для начального запроса отдает список продуктов resp = { 'task': None, 'state': 'product_list', 'items': [{ 'product': product.to_dict(True), 'parameters': [], 'error': None } for product in products] } else: # создаём задачу на деинсталляцию task = TaskFactory.create_task("uninstall", products) task_id = TaskManager.queue_task(task) TornadoWorker.start_new_task(task) # и готовим ответ веб-интерфейсу, что уставнока началась resp = {'task': {'id': task_id}, "state": "uninstalling"} return resp
def install(request): """ Этот вызов используется для передать в веб-интерфейс дерево зависимостей и принять от него запрос на установку. Примеры запросов и ответов: начальный запрос: command: "start" requested_products: [JavaJettyTemplate] ответ: task: id: 168 url: /task/168/ items: paramters: [...] product: name: ... title: ... and: - item 1... - item 2... """ # TODO do not give ability to install application through this function if request.method != 'POST': # принимаем только пост-запросы resp = HttpResponseNotAllowed(['POST']) return resp # джейсон запрос в питоний словарь req = json_request(request) # это начальный запрос? dm = DependencyManager() core = Core.get_instance() # продукты, которые запрошены на установку (без зависимостей) requested_products = req['requested_products'] if req["command"] == "start": # если это начальный запрос, то отдаем дерево зависимостей resp = { 'task': None, "state": "requirements", 'items': [ dm.get_dependencies(product_name) for product_name in requested_products ] } else: # это запрос на установку # список имён продуктов, которые нужно установить # ВАЖНЫЙ МОМЕНТ (с зависимостями) product_list = [item['product'] for item in req['install_products']] # переворачиваем его product_list.reverse() # добывает спсисоко продуктов из списка имён products = ProductCollection(product_list, feeds=(core.feed, core.current)) # парсим параметры установки из запроса parsed_parameters = ParametersParserJson(req['install_products']).get() # создаём менеджер параметров parameter_manager = ParametersManager(core, products, parsed_parameters) # все ли параметры заполнены? if parameter_manager.are_all_parameters_filled(): # всё ок, создаём задание на установку task = TaskFactory.create_task("install", products, parameter_manager) task_id = TaskManager.queue_task(task) TornadoWorker.start_new_task(task) # и готовим ответ веб-интерфейсу, что уставнока началась resp = { 'task': { 'id': task_id, }, } else: # что-то не так с параметрами, возвращаем в веб морду ошибку resp = { 'task': None, 'items': [ dm.get_dependencies(product_name) for product_name in req['requested_products'] ], 'error': [parameter_manager.get_error(product) for product in products] } return resp