def test_list_installed_products_with_filter(self): self.mock_cp.getConsumer.return_value = CONTENT_JSON self.mock_cert_sorter.reasons = mock.Mock() self.mock_cert_sorter.reasons.get_product_reasons = mock.Mock( return_value=[]) self.mock_cert_sorter.get_status = mock.Mock(return_value="subscribed") # Mock methods in calculator self.mock_calculator.calculate = mock.Mock() self.mock_calculator.calculate.return_value.begin = mock.Mock() self.mock_calculator.calculate.return_value.begin.return_value.astimezone = mock.Mock( ) self.mock_calculator.calculate.return_value.begin.return_value.astimezone.return_value.strftime = mock.Mock( return_value='{d.day}.{d.month}.{d.year}'.format(d=START_DATE)) self.mock_calculator.calculate.return_value.end = mock.Mock() self.mock_calculator.calculate.return_value.end.return_value.astimezone = mock.Mock( ) self.mock_calculator.calculate.return_value.end.return_value.astimezone.return_value.strftime = mock.Mock( return_value='{d.day}.{d.month}.{d.year}'.format(d=END_DATE)) expected_result = [ (u'Red Hat Enterprise Linux Server - Extended Update Support', '70', u'7.2', u'x86_64', 'subscribed', [], '{d.day}.{d.month}.{d.year}'.format(d=START_DATE), '{d.day}.{d.month}.{d.year}'.format(d=END_DATE)), ] self.mock_cert_sorter.installed_products = { '69': self._create_rhel74_cert(), '70': self._create_rhel72_ues_cert() } result = products.InstalledProducts(self.mock_cp).list("*Extended*") self.assertEqual(expected_result, result)
def show_autosubscribe_output(uep, identity): """ Try to show auto-attach output :param uep: object with connection to candlepin :param identity: object with identity :return: return 1, when all installed products are subscribed, otherwise return 0 """ if is_simple_content_access(uep=uep, identity=identity): return 0 installed_products = products.InstalledProducts(uep).list() if not installed_products: # Returning an error code here breaks registering when no products are installed, and the # AttachCommand already performs this check before calling. print(_("No products installed.")) return 0 log.debug("Attempted to auto-attach/heal the system.") print(_("Installed Product Current Status:")) subscribed = 1 all_subscribed = True for product in installed_products: if product[4] == SUBSCRIBED: subscribed = 0 status = STATUS_MAP[product[4]] if product[4] == NOT_SUBSCRIBED: all_subscribed = False print(columnize(PRODUCT_STATUS, echo_columnize_callback, product[0], status) + "\n") if not all_subscribed: print(_("Unable to find available subscriptions for all your installed products.")) return subscribed
def get_pools(self, pool_subsets=None, matches=None, pool_only=None, match_installed=None, no_overlap=None, service_level=None, show_all=None, on_date=None, future=None, after=None, **kwargs): # We accept a **kwargs argument so that the DBus object can pass whatever dictionary it receives # via keyword expansion. if kwargs: raise exceptions.ValidationError(_("Unknown arguments: %s") % kwargs.keys()) if isinstance(pool_subsets, six.string_types): pool_subsets = [pool_subsets] # [] or None means look at all pools if not pool_subsets: pool_subsets = ['installed', 'consumed', 'available'] options = { 'pool_subsets': pool_subsets, 'matches': matches, 'pool_only': pool_only, 'match_installed': match_installed, 'no_overlap': no_overlap, 'service_level': service_level, 'show_all': show_all, 'on_date': on_date, 'future': future, 'after': after, } self.validate_options(options) results = {} if 'installed' in pool_subsets: installed = products.InstalledProducts(self.cp).list(matches) results['installed'] = [x._asdict() for x in installed] if 'consumed' in pool_subsets: consumed = self.get_consumed_product_pools(service_level=service_level, matches=matches) if pool_only: results['consumed'] = [x._asdict()['pool_id'] for x in consumed] else: results['consumed'] = [x._asdict() for x in consumed] if 'available' in pool_subsets: available = self.get_available_pools( show_all=show_all, on_date=on_date, no_overlap=no_overlap, match_installed=match_installed, matches=matches, service_level=service_level, future=future, after=after, ) if pool_only: results['available'] = [x['id'] for x in available] else: results['available'] = available return results
def test_list_installed_products_without_filter(self): self.mock_cp.getConsumer.return_value = CONTENT_JSON self.mock_cert_sorter.reasons = mock.Mock() self.mock_cert_sorter.reasons.get_product_reasons = mock.Mock( return_value=[]) self.mock_cert_sorter.get_status = mock.Mock(return_value="subscribed") # Mock methods in calculator self.mock_calculator.calculate = mock.Mock() self.mock_calculator.calculate.return_value.begin = mock.Mock() self.mock_calculator.calculate.return_value.begin.return_value.astimezone = mock.Mock( ) self.mock_calculator.calculate.return_value.begin.return_value.astimezone.return_value.strftime = ( mock.Mock(return_value="{d.day}.{d.month}.{d.year}".format( d=START_DATE))) self.mock_calculator.calculate.return_value.end = mock.Mock() self.mock_calculator.calculate.return_value.end.return_value.astimezone = mock.Mock( ) self.mock_calculator.calculate.return_value.end.return_value.astimezone.return_value.strftime = ( mock.Mock(return_value="{d.day}.{d.month}.{d.year}".format( d=END_DATE))) expected_result = [ ( "Red Hat Enterprise Linux Server", "69", "7.4", "x86_64", "subscribed", [], "{d.day}.{d.month}.{d.year}".format(d=START_DATE), "{d.day}.{d.month}.{d.year}".format(d=END_DATE), ), ( "Red Hat Enterprise Linux Server - Extended Update Support", "70", "7.2", "x86_64", "subscribed", [], "{d.day}.{d.month}.{d.year}".format(d=START_DATE), "{d.day}.{d.month}.{d.year}".format(d=END_DATE), ), ] self.mock_cert_sorter.installed_products = { "69": self._create_rhel74_cert(), "70": self._create_rhel72_ues_cert(), } result = products.InstalledProducts(self.mock_cp).list() self.assertEqual(expected_result, result)
def test_list_no_installed_products(self): self.mock_cp.getConsumer.return_value = NO_CONTENT_JSON self.mock_cert_sorter.installed_products = [] result = products.InstalledProducts(self.mock_cp).list() self.assertEqual([], result)
def update(self): entries = [] range_calculator = inj.require( inj.PRODUCT_DATE_RANGE_CALCULATOR, self.backend.cp_provider.get_consumer_auth_cp()) installed_products = products.InstalledProducts( self.backend.cp_provider.get_consumer_auth_cp()).list() for product in installed_products: entry = {} entry['product'] = product[0] entry['product_id'] = product_id = product[1] entry['version'] = product[2] entry['arch'] = product[ 3] # TODO: need to test, when more more architectures is supported status = product[4] # NOTE: following code cannot be used, because start_date and expiration_date # are stored in textual form in product and GUI requires datetime format. # entry['start_date'] = product[6] # entry['expiration_date'] = product[7] # Common properties entry['align'] = 0.5 # TODO: Pull this date logic out into a separate lib! # This is also used in mysubstab... if status != NOT_SUBSCRIBED: compliant_range = range_calculator.calculate(product_id) start = '' end = '' if compliant_range: start = compliant_range.begin() end = compliant_range.end() entry['start_date'] = start entry['expiration_date'] = end contract_ids, sub_names = self._calc_subs_providing( product_id, compliant_range) contract = friendly_join(contract_ids) num_of_contracts = len(contract_ids) entry['subscription'] = list(sub_names) if status == FUTURE_SUBSCRIBED: entry['image'] = self._render_icon('red') entry['status'] = _('Future Subscription') entry['validity_note'] = _("Future Subscribed") elif status == EXPIRED: entry['image'] = self._render_icon('red') entry['status'] = _('Expired') sub_numbers = set([]) for ent_cert in self.entitlement_dir.list_for_product( product_id): order = ent_cert.order # FIXME: getSubscription() seems to always be None...? if order.subscription: sub_numbers.add(order.subscription) subs_str = ', '.join(sub_numbers) entry['validity_note'] = \ _('Subscription %s is expired') % subs_str elif status == PARTIALLY_SUBSCRIBED: entry['image'] = self._render_icon('yellow') entry['status'] = _('Partially Subscribed') entry['validity_note'] = _("Partially Subscribed") elif status == UNKNOWN: entry['image'] = self._render_icon('unknown') entry['status'] = _('Unknown') if not self.backend.cs.is_registered(): entry['validity_note'] = _("System is not registered.") else: # System must be registered but unable to reach server: entry['validity_note'] = _( "Entitlement server is unreachable.") else: entry['image'] = self._render_icon('green') entry['status'] = _('Subscribed') entry['validity_note'] = \ ungettext("Covered by contract %s through %s", 'Covered by contracts %s through %s', num_of_contracts) % \ (contract, managerlib.format_date(entry['expiration_date'])) else: entry['image'] = self._render_icon('red') entry['status'] = _('Not Subscribed') entry['validity_note'] = _("Not Subscribed") entries.append(entry) self._entries = entries
def _do_command(self): """ Executes the command. """ self.assert_should_be_registered() self._validate_options() # --pool or --file turns off default auto attach if self.options.pool or self.options.file: self.auto_attach = False # Do not try to do auto-attach, when simple content access mode is used # BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1826300 # if is_simple_content_access(uep=self.cp, identity=self.identity): if self.auto_attach is True: self._print_ignore_auto_attach_mesage() else: self._print_ignore_attach_message() return 0 installed_products_num = 0 return_code = 0 report = None # TODO: change to if self.auto_attach: else: pool/file stuff try: cert_action_client = ActionClient(skips=[PackageProfileActionInvoker]) cert_action_client.update() cert_update = True attach_service = attach.AttachService(self.cp) if self.options.pool: subscribed = False for pool in self.options.pool: # odd html strings will cause issues, reject them here. if pool.find("#") >= 0: system_exit(os.EX_USAGE, _("Please enter a valid numeric pool ID.")) try: ents = attach_service.attach_pool(pool, self.options.quantity) # Usually just one, but may as well be safe: for ent in ents: pool_json = ent["pool"] print( _("Successfully attached a subscription for: {name}").format( name=pool_json["productName"] ) ) log.debug( "Attached a subscription for {name}".format(name=pool_json["productName"]) ) subscribed = True except connection.RestlibException as re: log.exception(re) exception_mapper = ExceptionMapper() mapped_message = exception_mapper.get_message(re) if re.code == 403: print(mapped_message) # already subscribed. elif re.code == 400 or re.code == 404: print(mapped_message) # no such pool. else: system_exit(os.EX_SOFTWARE, mapped_message) # some other error.. don't try again if not subscribed: return_code = 1 # must be auto else: installed_products_num = len(products.InstalledProducts(self.cp).list()) # if we are green, we don't need to go to the server self.sorter = inj.require(inj.CERT_SORTER) if self.sorter.is_valid(): if not installed_products_num: print(_("No Installed products on system. " "No need to attach subscriptions.")) else: print( _( "All installed products are covered by valid entitlements. " "No need to update subscriptions at this time." ) ) cert_update = False else: # If service level specified, make an additional request to # verify service levels are supported on the server: if self.options.service_level: consumer = self.cp.getConsumer(self.identity.uuid) if "serviceLevel" not in consumer: system_exit( os.EX_UNAVAILABLE, _( "Error: The --servicelevel option is not " "supported by the server. Did not " "complete your request." ), ) attach_service.attach_auto(self.options.service_level) if self.options.service_level is not None: # RHBZ 1632797 we should only save the sla if the sla was actually # specified. The uep and consumer_uuid are None, because service_level was sent # to candlepin server using attach_service.attach_auto() save_sla_to_syspurpose_metadata( uep=None, consumer_uuid=None, service_level=self.options.service_level ) print(_("Service level set to: {}").format(self.options.service_level)) if cert_update: report = self.entcertlib.update() profile_action_client = ProfileActionClient() profile_action_client.update() if report and report.exceptions(): print(_("Entitlement Certificate(s) update failed due to the following reasons:")) for e in report.exceptions(): print("\t-", str(e)) elif self.auto_attach: if not installed_products_num: return_code = 1 else: self.sorter.force_cert_check() # Make sure that we get fresh status of installed products status_cache = inj.require(inj.ENTITLEMENT_STATUS_CACHE) status_cache.load_status( self.sorter.cp_provider.get_consumer_auth_cp(), self.sorter.identity.uuid, self.sorter.on_date, ) self.sorter.load() # run this after entcertlib update, so we have the new entitlements return_code = show_autosubscribe_output(self.cp, self.identity) except Exception as e: handle_exception("Unable to attach: {e}".format(e=e), e) # it is okay to call this no matter what happens above, # it's just a notification to perform a check self._request_validity_check() return return_code
def _do_command(self): """ Executes the command. """ self._validate_options() if self.options.installed and not self.options.pid_only: installed_products = products.InstalledProducts(self.cp).list( self.options.filter_string) if len(installed_products): print("+-------------------------------------------+") print(_(" Installed Product Status")) print("+-------------------------------------------+") for product in installed_products: if is_simple_content_access(self.cp, self.identity): print( columnize( INSTALLED_PRODUCT_STATUS_SCA, none_wrap_columnize_callback, product[0], # Name product[1], # ID product[2], # Version product[3], # Arch ) + "\n") else: status = STATUS_MAP[product[4]] print( columnize( INSTALLED_PRODUCT_STATUS, none_wrap_columnize_callback, product[0], # Name product[1], # ID product[2], # Version product[3], # Arch status, # Status product[5], # Status details product[6], # Start product[7], # End ) + "\n") else: if self.options.filter_string: print( _('No installed products were found matching the expression "{filter}".' ).format(filter=self.options.filter_string)) else: print(_("No installed products to list")) if self.options.available: self.assert_should_be_registered() on_date = None after_date = None if self.options.on_date: on_date = self._parse_date(self.options.on_date) elif self.options.after_date: after_date = self._parse_date(self.options.after_date) epools = entitlement.EntitlementService().get_available_pools( show_all=self.options.all, on_date=on_date, no_overlap=self.options.no_overlap, match_installed=self.options.match_installed, matches=self.options.filter_string, service_level=self.options.service_level, after_date=after_date, ) if len(epools): if self.options.pid_only: for data in epools: print(data["id"]) else: print("+-------------------------------------------+") print(" " + _("Available Subscriptions")) print("+-------------------------------------------+") for data in epools: if PoolWrapper(data).is_virt_only(): entitlement_type = _("Virtual") else: entitlement_type = _("Physical") if "management_enabled" in data and data[ "management_enabled"]: data["management_enabled"] = _("Yes") else: data["management_enabled"] = _("No") kwargs = { "filter_string": self.options.filter_string, "match_columns": AVAILABLE_SUBS_MATCH_COLUMNS, "is_atty": sys.stdout.isatty(), } print( columnize( AVAILABLE_SUBS_LIST, highlight_by_filter_string_columnize_cb, data["productName"], data["providedProducts"], data["productId"], data["contractNumber"] or "", data["id"], data["management_enabled"], data["quantity"], data["suggested"], data["service_type"] or "", self._split_mulit_value_field( data["roles"]), data["service_level"] or "", data["usage"] or "", self._split_mulit_value_field(data["addons"]), data["pool_type"], data["startDate"], data["endDate"], entitlement_type, **kwargs) + "\n") elif not self.options.pid_only: if self.options.filter_string and self.options.service_level: print( _('No available subscription pools were found matching the expression "{filter}" and the service level "{level}".' ).format(filter=self.options.filter_string, level=self.options.service_level)) elif self.options.filter_string: print( _('No available subscription pools were found matching the expression "{filter}".' ).format(filter=self.options.filter_string)) elif self.options.service_level: print( _('No available subscription pools were found matching the service level "{level}".' ).format(level=self.options.service_level)) else: print(_("No available subscription pools to list")) if self.options.consumed: self.print_consumed( service_level=self.options.service_level, filter_string=self.options.filter_string, pid_only=self.options.pid_only, )
def get_pools(self, pool_subsets=None, matches=None, pool_only=None, match_installed=None, no_overlap=None, service_level=None, show_all=None, on_date=None, future=None, after_date=None, page=0, items_per_page=0, **kwargs): # We accept a **kwargs argument so that the DBus object can pass whatever dictionary it receives # via keyword expansion. if kwargs: raise exceptions.ValidationError( _("Unknown arguments: %s") % kwargs.keys()) if isinstance(pool_subsets, str): pool_subsets = [pool_subsets] # [] or None means look at all pools if not pool_subsets: pool_subsets = ["installed", "consumed", "available"] options = { "pool_subsets": pool_subsets, "matches": matches, "pool_only": pool_only, "match_installed": match_installed, "no_overlap": no_overlap, "service_level": service_level, "show_all": show_all, "on_date": on_date, "future": future, "after_date": after_date, } self.validate_options(options) results = {} if "installed" in pool_subsets: installed = products.InstalledProducts(self.cp).list( matches, iso_dates=True) results["installed"] = [x._asdict() for x in installed] if "consumed" in pool_subsets: consumed = self.get_consumed_product_pools( service_level=service_level, matches=matches, iso_dates=True) if pool_only: results["consumed"] = [ x._asdict()["pool_id"] for x in consumed ] else: results["consumed"] = [x._asdict() for x in consumed] if "available" in pool_subsets: available = self.get_available_pools( show_all=show_all, on_date=on_date, no_overlap=no_overlap, match_installed=match_installed, matches=matches, service_level=service_level, future=future, after_date=after_date, page=int(page), items_per_page=int(items_per_page), iso_dates=True, ) if pool_only: results["available"] = [x["id"] for x in available] else: results["available"] = available return results