def _detach(cfg: config.UAConfig, assume_yes: bool) -> int: """Detach the machine from the active Ubuntu Advantage subscription, :param cfg: a ``config.UAConfig`` instance :param assume_yes: Assume a yes answer to any prompts requested. In this case, it means automatically disable any service during detach. @return: 0 on success, 1 otherwise """ to_disable = [] for ent_cls in entitlements.ENTITLEMENT_CLASSES: ent = ent_cls(cfg) if ent.can_disable(silent=True): to_disable.append(ent) if to_disable: suffix = "s" if len(to_disable) > 1 else "" print("Detach will disable the following service{}:".format(suffix)) for ent in to_disable: print(" {}".format(ent.name)) if not util.prompt_for_confirmation(assume_yes=assume_yes): return 1 for ent in to_disable: ent.disable(silent=True) contract_client = contract.UAContractClient(cfg) machine_token = cfg.machine_token["machineToken"] contract_id = cfg.machine_token["machineTokenInfo"]["contractInfo"]["id"] contract_client.detach_machine_from_contract(machine_token, contract_id) cfg.delete_cache() print(ua_status.MESSAGE_DETACH_SUCCESS) return 0
def action_detach(args, cfg): """Perform the detach action for this machine. @return: 0 on success, 1 otherwise """ to_disable = [] for ent_cls in entitlements.ENTITLEMENT_CLASSES: ent = ent_cls(cfg) if ent.can_disable(silent=True): to_disable.append(ent) if to_disable: suffix = "s" if len(to_disable) > 1 else "" print("Detach will disable the following service{}:".format(suffix)) for ent in to_disable: print(" {}".format(ent.name)) if not args.assume_yes and not util.prompt_for_confirmation(): return 1 for ent in to_disable: ent.disable(silent=True) contract_client = contract.UAContractClient(cfg) machine_token = cfg.machine_token["machineToken"] contract_id = cfg.machine_token["machineTokenInfo"]["contractInfo"]["id"] contract_client.detach_machine_from_contract(machine_token, contract_id) cfg.delete_cache() print(ua_status.MESSAGE_DETACH_SUCCESS) return 0
def _enable_required_services( self, ) -> Tuple[bool, Optional[messages.NamedMessage]]: """ Prompt user when required services are found during enable. When enabling a service, we may find that there are required services that must be enabled first. In that situation, we can ask the user if the required service should be enabled before proceeding. """ from uaclient.entitlements import entitlement_factory for required_service in self.required_services: try: ent_cls = entitlement_factory( cfg=self.cfg, name=required_service ) except exceptions.EntitlementNotFoundError: msg = messages.REQUIRED_SERVICE_NOT_FOUND.format( service=required_service ) return False, msg ent = ent_cls(self.cfg, allow_beta=True) is_service_disabled = ( ent.application_status()[0] == ApplicationStatus.DISABLED ) if is_service_disabled: user_msg = messages.REQUIRED_SERVICE.format( service_being_enabled=self.title, required_service=ent.title, ) e_msg = messages.REQUIRED_SERVICE_STOPS_ENABLE.format( service_being_enabled=self.title, required_service=ent.title, ) if not util.prompt_for_confirmation( msg=user_msg, assume_yes=self.assume_yes ): return False, e_msg event.info("Enabling required service: {}".format(ent.title)) ret, fail = ent.enable(silent=True) if not ret: error_msg = "" if fail.message and fail.message.msg: error_msg = "\n" + fail.message.msg msg = messages.ERROR_ENABLING_REQUIRED_SERVICE.format( error=error_msg, service=ent.title ) return ret, msg return True, None
def handle_incompatible_services( self, ) -> Tuple[bool, Optional[messages.NamedMessage]]: """ Prompt user when incompatible services are found during enable. When enabling a service, we may find that there is an incompatible service already enable. In that situation, we can ask the user if the incompatible service should be disabled before proceeding. There are also different ways to configure that behavior: We can disable removing incompatible service during enable by adding the following lines into uaclient.conf: features: block_disable_on_enable: true """ cfg_block_disable_on_enable = util.is_config_value_true( config=self.cfg.cfg, path_to_value="features.block_disable_on_enable", ) for service in self.blocking_incompatible_services(): ent = service.entitlement(self.cfg, assume_yes=True) user_msg = messages.INCOMPATIBLE_SERVICE.format( service_being_enabled=self.title, incompatible_service=ent.title, ) e_msg = messages.INCOMPATIBLE_SERVICE_STOPS_ENABLE.format( service_being_enabled=self.title, incompatible_service=ent.title, ) if cfg_block_disable_on_enable: return False, e_msg if not util.prompt_for_confirmation( msg=user_msg, assume_yes=self.assume_yes ): return False, e_msg disable_msg = "Disabling incompatible service: {}".format( ent.title ) event.info(disable_msg) ret = ent.disable(silent=True) if not ret: return ret, None return True, None
def action_detach(args, cfg): """Perform the detach action for this machine. @return: 0 on success, 1 otherwise """ to_disable = [] for ent_cls in entitlements.ENTITLEMENT_CLASSES: ent = ent_cls(cfg) if ent.can_disable(silent=True): to_disable.append(ent) if to_disable: suffix = "s" if len(to_disable) > 1 else "" print("Detach will disable the following service{}:".format(suffix)) for ent in to_disable: print(" {}".format(ent.name)) if not util.prompt_for_confirmation(): return 1 for ent in to_disable: ent.disable(silent=True) cfg.delete_cache() print(ua_status.MESSAGE_DETACH_SUCCESS) return 0
def _disable_dependent_services( self, silent: bool ) -> Tuple[bool, Optional[messages.NamedMessage]]: """ Disable dependent services When performing a disable operation, we might have other services that depend on the original services. If that is true, we will alert the user about this and prompt for confirmation to disable these services as well. @param silent: Boolean set True to silence print/log of messages """ from uaclient.entitlements import entitlement_factory for dependent_service in self.dependent_services: try: ent_cls = entitlement_factory( cfg=self.cfg, name=dependent_service ) except exceptions.EntitlementNotFoundError: msg = messages.DEPENDENT_SERVICE_NOT_FOUND.format( service=dependent_service ) event.info(info_msg=msg.msg, file_type=sys.stderr) return False, msg ent = ent_cls(cfg=self.cfg, assume_yes=True) is_service_enabled = ( ent.application_status()[0] == ApplicationStatus.ENABLED ) if is_service_enabled: user_msg = messages.DEPENDENT_SERVICE.format( dependent_service=ent.title, service_being_disabled=self.title, ) e_msg = messages.DEPENDENT_SERVICE_STOPS_DISABLE.format( service_being_disabled=self.title, dependent_service=ent.title, ) if not util.prompt_for_confirmation( msg=user_msg, assume_yes=self.assume_yes ): return False, e_msg if not silent: event.info( messages.DISABLING_DEPENDENT_SERVICE.format( required_service=ent.title ) ) ret, fail = ent.disable(silent=True) if not ret: error_msg = "" if fail.message and fail.message.msg: error_msg = "\n" + fail.message.msg msg = messages.FAILED_DISABLING_DEPENDENT_SERVICE.format( error=error_msg, required_service=ent.title ) return False, msg return True, None
def test_prompt_text(self, m_input, assume_yes, message, input_calls): util.prompt_for_confirmation(msg=message, assume_yes=assume_yes) assert input_calls == m_input.call_args_list
def test_input_conversion(self, m_input, return_value, user_input): m_input.return_value = user_input assert return_value == util.prompt_for_confirmation()
def test_prompt_text(self, m_input): util.prompt_for_confirmation() assert [mock.call("Are you sure? (y/N) ")] == m_input.call_args_list