def _update(self, cache_only):
        """ update entitlement certificates """
        logger.info(_('Updating Subscription Management repositories.'))

        # XXX: Importing inline as you must be root to read the config file
        from subscription_manager.identity import ConsumerIdentity

        cert_file = str(ConsumerIdentity.certpath())
        key_file = str(ConsumerIdentity.keypath())

        identity = inj.require(inj.IDENTITY)

        # In containers we have no identity, but we may have entitlements inherited
        # from the host, which need to generate a redhat.repo.
        if identity.is_valid():
            try:
                connection.UEPConnection(cert_file=cert_file, key_file=key_file)
            # FIXME: catchall exception
            except Exception:
                # log
                logger.info(_("Unable to connect to Subscription Management Service"))
                return
        else:
            logger.info(_("Unable to read consumer identity"))

        if config.in_container():
            logger.info(_("Subscription Manager is operating in container mode."))

        if not cache_only:
            cert_action_invoker = EntCertActionInvoker()
            cert_action_invoker.update()

        repo_action_invoker = RepoActionInvoker(cache_only=cache_only)
        repo_action_invoker.update()
示例#2
0
    def RegisterWithActivationKeys(self, org, activation_keys, options,
                                   connection_options, locale):
        """
        Note this method is registration ONLY.  Auto-attach is a separate process.
        """
        connection_options = dbus_utils.dbus_to_python(connection_options,
                                                       expected_type=dict)
        options = dbus_utils.dbus_to_python(options, expected_type=dict)
        options["activation_keys"] = dbus_utils.dbus_to_python(
            activation_keys, expected_type=list)
        org = dbus_utils.dbus_to_python(org, expected_type=str)
        locale = dbus_utils.dbus_to_python(locale, expected_type=str)

        with DBusSender() as dbus_sender:
            dbus_sender.set_cmd_line(sender=self.sender,
                                     cmd_line=self.cmd_line)
            Locale.set(locale)
            cp = self.build_uep(connection_options)

            register_service = RegisterService(cp)
            consumer = register_service.register(org, **options)

            log.debug("System registered, updating entitlements if needed")
            ent_cert_lib = EntCertActionInvoker()
            ent_cert_lib.update()

            dbus_sender.reset_cmd_line()

        return json.dumps(consumer)
示例#3
0
    def _update(cache_only):
        """
        Update entitlement certificates and redhat.repo
        :param cache_only: is True, when rhsm.full_refresh_on_yum is set to 0 in rhsm.conf
        """

        logger.info(_('Updating Subscription Management repositories.'))

        identity = inj.require(inj.IDENTITY)

        if not identity.is_valid():
            logger.info(_("Unable to read consumer identity"))

        if config.in_container():
            logger.info(
                _("Subscription Manager is operating in container mode."))

        if cache_only is True:
            log.debug('DNF subscription-manager operates in cache-only mode')

        if not cache_only and not config.in_container():
            log.debug(
                'Trying to update entitlement certificates and redhat.repo')
            cert_action_invoker = EntCertActionInvoker()
            cert_action_invoker.update()
        else:
            log.debug('Skipping updating of entitlement certificates')

        log.debug('Generating redhat.repo')
        repo_action_invoker = RepoActionInvoker(cache_only=cache_only)
        repo_action_invoker.update()
示例#4
0
def update(conduit, cache_only):
    """
    Update entitlement certificates
    """
    if os.getuid() != 0:
        conduit.info(
            3, 'Not root, Subscription Management repositories not updated')
        return
    conduit.info(3, 'Updating Subscription Management repositories.')

    identity = inj.require(inj.IDENTITY)

    if not identity.is_valid():
        conduit.info(3, "Unable to read consumer identity")

    # In containers we have no identity, but we may have entitlements inherited
    # from the host, which need to generate a redhat.repo.
    if config.in_container():
        conduit.info(3, "Subscription Manager is operating in container mode.")

    if not cache_only and not config.in_container():
        cert_action_invoker = EntCertActionInvoker(locker=YumRepoLocker(
            conduit=conduit))
        cert_action_invoker.update()

    if cache_only or config.in_container():
        repo_action_invoker = RepoActionInvoker(
            cache_only=cache_only, locker=YumRepoLocker(conduit=conduit))
        repo_action_invoker.update()
示例#5
0
    def _get_libset(self):

        self.entcertlib = EntCertActionInvoker()
        self.repolib = RepoActionInvoker()

        lib_set = [self.entcertlib, self.repolib]
        return lib_set
示例#6
0
    def _get_libset(self):

        self.entcertlib = EntCertActionInvoker()
        self.content_action_client = ContentActionClient()

        lib_set = [self.entcertlib, self.content_action_client]
        return lib_set
示例#7
0
    def _get_libset(self):

        # TODO: replace with FSM thats progress through this async and wait/joins if needed
        self.entcertlib = EntCertActionInvoker()
        self.content_client = ContentActionClient()
        self.factlib = FactsActionInvoker()
        self.profilelib = PackageProfileActionInvoker()
        self.installedprodlib = InstalledProductsActionInvoker()
        self.idcertlib = IdentityCertActionInvoker()
        self.syspurposelib = SyspurposeSyncActionInvoker()

        # WARNING: order is important here, we need to update a number
        # of things before attempting to autoheal, and we need to autoheal
        # before attempting to fetch our certificates:
        lib_set = [
            self.entcertlib,
            self.idcertlib,
            self.content_client,
            self.factlib,
            self.profilelib,
            self.installedprodlib,
            self.syspurposelib,
        ]

        return lib_set
示例#8
0
    def _get_libset(self):

        self.entcertlib = EntCertActionInvoker()
        self.installedprodlib = InstalledProductsActionInvoker()
        self.healinglib = HealingActionInvoker()

        lib_set = [self.installedprodlib, self.healinglib, self.entcertlib]

        return lib_set
def update(conduit, cache_only):
    """
    Update entitlement certificates
    """
    if os.getuid() != 0:
        conduit.info(
            3, 'Not root, Subscription Management repositories not updated')
        return
    conduit.info(3, 'Updating Subscription Management repositories.')

    # XXX: Importing inline as you must be root to read the config file
    from subscription_manager.identity import ConsumerIdentity

    cert_file = ConsumerIdentity.certpath()
    key_file = ConsumerIdentity.keypath()

    identity = inj.require(inj.IDENTITY)

    # In containers we have no identity, but we may have entitlements inherited
    # from the host, which need to generate a redhat.repo.
    if identity.is_valid():
        if not cache_only:
            try:
                connection.UEPConnection(cert_file=cert_file,
                                         key_file=key_file)
            except Exception:
                # log
                conduit.info(
                    2, "Unable to connect to Subscription Management Service")
                return
    else:
        conduit.info(3, "Unable to read consumer identity")

    if config.in_container():
        conduit.info(3, "Subscription Manager is operating in container mode.")

    if not cache_only and not config.in_container():
        cert_action_invoker = EntCertActionInvoker(locker=YumRepoLocker(
            conduit=conduit))
        cert_action_invoker.update()

    repo_action_invoker = RepoActionInvoker(
        cache_only=cache_only, locker=YumRepoLocker(conduit=conduit))
    repo_action_invoker.update()
示例#10
0
    def create_uep(self):
        # Re-initialize our connection:
        self.cp_provider.set_connection_info()

        # These objects hold a reference to the old uep and must be updated:
        # FIXME: We should find a way to update the connection so that the
        #        conncection objects are refreshed rather than recreated.

        self.certlib = EntCertActionInvoker()
        self.overrides = Overrides()
示例#11
0
    def __init__(self):
        self.identity = require(IDENTITY)
        self.cp_provider = require(CP_PROVIDER)

        self.update()

        self.product_dir = inj.require(inj.PROD_DIR)
        self.entitlement_dir = inj.require(inj.ENT_DIR)
        self.certlib = EntCertActionInvoker()
        self.overrides = Overrides()

        self.cs = require(CERT_SORTER)
def update(conduit, cache_only):
    """ update entitlement certificates """
    if os.getuid() != 0:
        conduit.info(3, 'Not root, Subscription Management repositories not updated')
        return
    conduit.info(3, 'Updating Subscription Management repositories.')

    # XXX: Importing inline as you must be root to read the config file
    from subscription_manager.identity import ConsumerIdentity

    cert_file = ConsumerIdentity.certpath()
    key_file = ConsumerIdentity.keypath()

    identity = inj.require(inj.IDENTITY)

    # In containers we have no identity, but we may have entitlements inherited
    # from the host, which need to generate a redhat.repo.
    if identity.is_valid():
        try:
            connection.UEPConnection(cert_file=cert_file, key_file=key_file)
        # FIXME: catchall exception
        except Exception:
            # log
            conduit.info(2, "Unable to connect to Subscription Management Service")
            return
    else:
        conduit.info(3, "Unable to read consumer identity")

    if config.in_container():
        conduit.info(3, "Subscription Manager is operating in container mode.")

    if not cache_only:
        cert_action_invoker = EntCertActionInvoker(locker=YumRepoLocker(conduit=conduit))
        cert_action_invoker.update()

    repo_action_invoker = RepoActionInvoker(cache_only=cache_only, locker=YumRepoLocker(conduit=conduit))
    repo_action_invoker.update()
示例#13
0
    def _update(self, cache_only):
        """ update entitlement certificates """
        logger.info(_('Updating Subscription Management repositories.'))

        # XXX: Importing inline as you must be root to read the config file
        from subscription_manager.identity import ConsumerIdentity

        cert_file = str(ConsumerIdentity.certpath())
        key_file = str(ConsumerIdentity.keypath())

        identity = inj.require(inj.IDENTITY)

        # In containers we have no identity, but we may have entitlements inherited
        # from the host, which need to generate a redhat.repo.
        if identity.is_valid():
            try:
                connection.UEPConnection(cert_file=cert_file,
                                         key_file=key_file)
            # FIXME: catchall exception
            except Exception:
                # log
                logger.info(
                    _("Unable to connect to Subscription Management Service"))
                return
        else:
            logger.info(_("Unable to read consumer identity"))

        if config.in_container():
            logger.info(
                _("Subscription Manager is operating in container mode."))

        if not cache_only and not config.in_container():
            cert_action_invoker = EntCertActionInvoker()
            cert_action_invoker.update()

        repo_action_invoker = RepoActionInvoker(cache_only=cache_only)
        repo_action_invoker.update()
示例#14
0
    def _get_libset(self):

        self.entcertlib = EntCertActionInvoker()
        self.repolib = RepoActionInvoker()
        self.factlib = FactsActionInvoker()
        self.profilelib = PackageProfileActionInvoker()
        self.installedprodlib = InstalledProductsActionInvoker()
        self.idcertlib = IdentityCertActionInvoker()

        # WARNING: order is important here, we need to update a number
        # of things before attempting to autoheal, and we need to autoheal
        # before attempting to fetch our certificates:
        lib_set = [
            self.entcertlib, self.idcertlib, self.repolib, self.factlib,
            self.profilelib, self.installedprodlib
        ]

        return lib_set
示例#15
0
 def __init__(self, cp=None):
     self.cp = cp
     self.identity = inj.require(inj.IDENTITY)
     self.product_dir = inj.require(inj.PROD_DIR)
     self.entitlement_dir = inj.require(inj.ENT_DIR)
     self.entcertlib = EntCertActionInvoker()
示例#16
0
class EntitlementService(object):
    def __init__(self, cp=None):
        self.cp = cp
        self.identity = inj.require(inj.IDENTITY)
        self.product_dir = inj.require(inj.PROD_DIR)
        self.entitlement_dir = inj.require(inj.ENT_DIR)
        self.entcertlib = EntCertActionInvoker()

    @classmethod
    def parse_date(cls, on_date):
        """
        Return new datetime parsed from date
        :param on_date: String representing date
        :return It returns datetime.datime structure representing date
        """
        try:
            on_date = datetime.datetime.strptime(on_date, "%Y-%m-%d")
        except ValueError:
            raise ValueError(
                _("Date entered is invalid. Date should be in YYYY-MM-DD format (example: "
                  ) + time.strftime("%Y-%m-%d", time.localtime()) + " )")
        if on_date.date() < datetime.datetime.now().date():
            raise ValueError(_("Past dates are not allowed"))
        return on_date

    def get_status(self, on_date=None, force=False):
        sorter = inj.require(inj.CERT_SORTER, on_date)
        # When singleton CertSorter was created with different argument on_date, then
        # it is necessary to update corresponding attribute in object (dependency
        # injection doesn't do it automatically).
        if sorter.on_date != on_date:
            sorter.on_date = on_date

        # Force reload status from the server to be sure that we get valid status for new date.
        # It is necessary to do it for rhsm.service, because it can run for very long time without
        # restart.
        if force is True:
            log.debug("Deleting cache entitlement status cache")
            status_cache = inj.require(inj.ENTITLEMENT_STATUS_CACHE)
            status_cache.server_status = None
            status_cache.delete_cache()

        sorter.load()

        if self.identity.is_valid():
            overall_status = sorter.get_system_status()
            overall_status_id = sorter.get_system_status_id()
            reasons = sorter.reasons.get_name_message_map()
            reason_ids = sorter.reasons.get_reason_ids_map()
            valid = sorter.is_valid()
            status = {
                "status": overall_status,
                "status_id": overall_status_id,
                "reasons": reasons,
                "reason_ids": reason_ids,
                "valid": valid,
            }
        else:
            status = {
                "status": _("Unknown"),
                "status_id": "unknown",
                "reasons": {},
                "reason_ids": {},
                "valid": False,
            }
        log.debug("entitlement status: %s" % str(status))
        return status

    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

    def get_consumed_product_pools(self,
                                   service_level=None,
                                   matches=None,
                                   iso_dates=False):
        # Use a named tuple so that the result can be unpacked into other functions
        OldConsumedStatus = collections.namedtuple(
            "OldConsumedStatus",
            [
                "subscription_name",
                "provides",
                "sku",
                "contract",
                "account",
                "serial",
                "pool_id",
                "provides_management",
                "active",
                "quantity_used",
                "service_type",
                "service_level",
                "status_details",
                "subscription_type",
                "starts",
                "ends",
                "system_type",
            ],
        )
        # Use a named tuple so that the result can be unpacked into other functions
        ConsumedStatus = collections.namedtuple(
            "ConsumedStatus",
            [
                "subscription_name",
                "provides",
                "sku",
                "contract",
                "account",
                "serial",
                "pool_id",
                "provides_management",
                "active",
                "quantity_used",
                "service_type",
                "roles",
                "service_level",
                "usage",
                "addons",
                "status_details",
                "subscription_type",
                "starts",
                "ends",
                "system_type",
            ],
        )
        sorter = inj.require(inj.CERT_SORTER)
        cert_reasons_map = sorter.reasons.get_subscription_reasons_map()
        pooltype_cache = inj.require(inj.POOLTYPE_CACHE)

        consumed_statuses = []
        # FIXME: the cache of CertificateDirectory should be smart enough and refreshing
        # should not be necessary. When new certificate is installed/deleted and rhsm-service
        # is running, then list of certificate is not automatically refreshed ATM.
        self.entitlement_dir.refresh()
        certs = self.entitlement_dir.list()
        cert_filter = utils.EntitlementCertificateFilter(
            filter_string=matches, service_level=service_level)

        if service_level is not None or matches is not None:
            certs = list(filter(cert_filter.match, certs))

        if iso_dates:
            date_formatter = managerlib.format_iso8601_date
        else:
            date_formatter = managerlib.format_date

        # Now we need to transform the EntitlementCertificate object into
        # something JSON-like for consumption
        for cert in certs:
            # for some certs, order can be empty
            # so we default the values and populate them if
            # they exist. BZ974587
            name = ""
            sku = ""
            contract = ""
            account = ""
            quantity_used = ""
            service_type = ""
            roles = ""
            service_level = ""
            usage = ""
            addons = ""
            system_type = ""
            provides_management = "No"

            order = cert.order

            if order:
                service_type = order.service_type or ""
                service_level = order.service_level or ""
                if cert.version.major >= 3 and cert.version.minor >= 4:
                    roles = order.roles or ""
                    usage = order.usage or ""
                    addons = order.addons or ""
                else:
                    roles = None
                    usage = None
                    addons = None
                name = order.name
                sku = order.sku
                contract = order.contract or ""
                account = order.account or ""
                quantity_used = order.quantity_used
                if order.virt_only:
                    system_type = _("Virtual")
                else:
                    system_type = _("Physical")

                if order.provides_management:
                    provides_management = _("Yes")
                else:
                    provides_management = _("No")

            pool_id = _("Not Available")
            if hasattr(cert.pool, "id"):
                pool_id = cert.pool.id

            provided_products = {p.id: p.name for p in cert.products}

            reasons = []
            pool_type = ""

            if inj.require(inj.CERT_SORTER).are_reasons_supported():
                if cert.subject and "CN" in cert.subject:
                    if cert.subject["CN"] in cert_reasons_map:
                        reasons = cert_reasons_map[cert.subject["CN"]]
                    pool_type = pooltype_cache.get(pool_id)

                # 1180400: Status details is empty when GUI is not
                if not reasons:
                    if cert in sorter.valid_entitlement_certs:
                        reasons.append(_("Subscription is current"))
                    else:
                        if cert.valid_range.end() < datetime.datetime.now(
                                certificate.GMT()):
                            reasons.append(_("Subscription is expired"))
                        else:
                            reasons.append(_("Subscription has not begun"))
            else:
                reasons.append(
                    _("Subscription management service doesn't support Status Details."
                      ))

            if roles is None and usage is None and addons is None:
                consumed_statuses.append(
                    OldConsumedStatus(
                        name,
                        provided_products,
                        sku,
                        contract,
                        account,
                        cert.serial,
                        pool_id,
                        provides_management,
                        cert.is_valid(),
                        quantity_used,
                        service_type,
                        service_level,
                        reasons,
                        pool_type,
                        date_formatter(cert.valid_range.begin()),
                        date_formatter(cert.valid_range.end()),
                        system_type,
                    ))
            else:
                consumed_statuses.append(
                    ConsumedStatus(
                        name,
                        provided_products,
                        sku,
                        contract,
                        account,
                        cert.serial,
                        pool_id,
                        provides_management,
                        cert.is_valid(),
                        quantity_used,
                        service_type,
                        roles,
                        service_level,
                        usage,
                        addons,
                        reasons,
                        pool_type,
                        date_formatter(cert.valid_range.begin()),
                        date_formatter(cert.valid_range.end()),
                        system_type,
                    ))
        return consumed_statuses

    def get_available_pools(
        self,
        show_all=None,
        on_date=None,
        no_overlap=None,
        match_installed=None,
        matches=None,
        service_level=None,
        future=None,
        after_date=None,
        page=0,
        items_per_page=0,
        iso_dates=False,
    ):
        """
        Get list of available pools
        :param show_all:
        :param on_date:
        :param no_overlap:
        :param match_installed:
        :param matches:
        :param service_level:
        :param future:
        :param after_date:
        :param page:
        :param items_per_page:
        :param iso_dates:
        :return:
        """

        # Values used for REST API calls and caching are bigger, because it makes using of cache and
        # API more efficient
        if show_all is not True:
            _page = int(page / 4)
            _items_per_page = 4 * items_per_page
        else:
            page = items_per_page = 0
            _page = _items_per_page = 0

        filter_options = {
            "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": _page,
            "items_per_page": _items_per_page,
        }

        # Try to get identity
        identity = inj.require(inj.IDENTITY)

        # Try to get available pools from cache
        cache = inj.require(inj.AVAILABLE_ENTITLEMENT_CACHE)
        available_pools = cache.get_not_obsolete_data(identity, filter_options)

        if len(available_pools) == 0:
            available_pools = managerlib.get_available_entitlements(
                get_all=show_all,
                active_on=on_date,
                overlapping=no_overlap,
                uninstalled=match_installed,
                filter_string=matches,
                future=future,
                after_date=after_date,
                page=_page,
                items_per_page=_items_per_page,
                iso_dates=iso_dates,
            )

            timeout = cache.timeout()

            data = {
                identity.uuid: {
                    "filter_options": filter_options,
                    "pools": available_pools,
                    "timeout": time.time() + timeout,
                }
            }
            cache.available_entitlements = data
            cache.write_cache()

        def filter_pool_by_service_level(pool_data):
            pool_level = ""
            if pool_data["service_level"]:
                pool_level = pool_data["service_level"]
            return service_level.lower() == pool_level.lower()

        if service_level is not None:
            available_pools = list(
                filter(filter_pool_by_service_level, available_pools))

        # When pagination result of available pools is requested, then reduce too long list
        if items_per_page > 0:
            # Reduce too long list to requested "page"
            lo_idx = (page * items_per_page) % _items_per_page
            hi_idx = ((page + 1) * items_per_page) % _items_per_page
            if hi_idx == 0:
                hi_idx = _items_per_page

            # Own filtering of the list
            available_pools = available_pools[lo_idx:hi_idx]

            # Add requested page and number of items per page to the result too
            for item in available_pools:
                item["page"] = page
                item["items_per_page"] = items_per_page

        return available_pools

    def validate_options(self, options):
        if not set(["installed", "consumed", "available"]).issuperset(
                options["pool_subsets"]):
            raise exceptions.ValidationError(
                _('Error: invalid listing type provided.  Only "installed", '
                  '"consumed", or "available" are allowed'))
        if options["show_all"] and "available" not in options["pool_subsets"]:
            raise exceptions.ValidationError(
                _("Error: --all is only applicable with --available"))
        elif options["on_date"] and "available" not in options["pool_subsets"]:
            raise exceptions.ValidationError(
                _("Error: --ondate is only applicable with --available"))
        elif options["service_level"] is not None and not set(
            ["consumed", "available"]).intersection(options["pool_subsets"]):
            raise exceptions.ValidationError(
                _("Error: --servicelevel is only applicable with --available or --consumed"
                  ))
        elif options["match_installed"] and "available" not in options[
                "pool_subsets"]:
            raise exceptions.ValidationError(
                _("Error: --match-installed is only applicable with --available"
                  ))
        elif options["no_overlap"] and "available" not in options[
                "pool_subsets"]:
            raise exceptions.ValidationError(
                _("Error: --no-overlap is only applicable with --available"))
        elif options["pool_only"] and not set(
            ["consumed", "available"]).intersection(options["pool_subsets"]):
            raise exceptions.ValidationError(
                _("Error: --pool-only is only applicable with --available and/or --consumed"
                  ))
        elif not self.identity.is_valid(
        ) and "available" in options["pool_subsets"]:
            raise exceptions.ValidationError(
                _("Error: this system is not registered"))

    def _unbind_ids(self, unbind_method, consumer_uuid, ids):
        """
        Method for unbinding entitlements
        :param unbind_method: unbindByPoolId or unbindBySerial
        :param consumer_uuid: UUID of consumer
        :param ids: List of serials or pool_ids
        :return: Tuple of two lists containing unbinded and not-unbinded subscriptions
        """
        success = []
        failure = []
        for id_ in ids:
            try:
                unbind_method(consumer_uuid, id_)
                success.append(id_)
            except connection.RestlibException as re:
                if re.code == 410:
                    raise
                failure.append(id_)
                log.error(re)
        return success, failure

    def remove_all_entitlements(self):
        """
        Try to remove all entilements
        :return: Result of REST API call
        """

        response = self.cp.unbindAll(self.identity.uuid)
        self.entcertlib.update()

        return response

    def remove_entilements_by_pool_ids(self, pool_ids):
        """
        Try to remove entitlements by pool IDs
        :param pool_ids: List of pool IDs
        :return: List of serial numbers of removed subscriptions
        """

        removed_serials = []
        _pool_ids = utils.unique_list_items(pool_ids)  # Don't allow duplicates
        # FIXME: the cache of CertificateDirectory should be smart enough and refreshing
        # should not be necessary. I vote for i-notify to be used there somehow.
        self.entitlement_dir.refresh()
        pool_id_to_serials = self.entitlement_dir.list_serials_for_pool_ids(
            _pool_ids)
        removed_pools, unremoved_pools = self._unbind_ids(
            self.cp.unbindByPoolId, self.identity.uuid, _pool_ids)
        if removed_pools:
            for pool_id in removed_pools:
                removed_serials.extend(pool_id_to_serials[pool_id])
        self.entcertlib.update()

        return removed_pools, unremoved_pools, removed_serials

    def remove_entitlements_by_serials(self, serials):
        """
        Try to remove pools by Serial numbers
        :param serials: List of serial numbers
        :return: List of serial numbers of already removed subscriptions
        """

        _serials = utils.unique_list_items(serials)  # Don't allow duplicates
        removed_serials, unremoved_serials = self._unbind_ids(
            self.cp.unbindBySerial, self.identity.uuid, _serials)
        self.entcertlib.update()

        return removed_serials, unremoved_serials

    def reload(self):
        """
        This callback function is called, when there is detected any change in directory with entitlement
        certificates (e.g. certificate is installed or removed)
        :return:
        """
        sorter = inj.require(inj.CERT_SORTER, on_date=None)
        status_cache = inj.require(inj.ENTITLEMENT_STATUS_CACHE)
        log.debug("Clearing in-memory cache of file %s" %
                  status_cache.CACHE_FILE)
        status_cache.server_status = None
        sorter.load()

    def refresh(self, remove_cache=False, force=False):
        """
        Try to refresh entitlement certificate(s) from candlepin server
        :return: Report of EntCertActionInvoker
        """

        if remove_cache is True:
            # remove content_access cache, ensuring we get it fresh
            content_access = inj.require(inj.CONTENT_ACCESS_CACHE)
            if content_access.exists():
                content_access.remove()
            # Also remove the content access mode cache to be sure we display
            # SCA or regular mode correctly
            content_access_mode = inj.require(inj.CONTENT_ACCESS_MODE_CACHE)
            if content_access_mode.exists():
                content_access_mode.delete_cache()

        if force is True:
            # Force a regen of the entitlement certs for this consumer
            if not self.cp.regenEntitlementCertificates(
                    self.identity.uuid, True):
                log.debug(
                    "Warning: Unable to refresh entitlement certificates; service likely unavailable"
                )

        return self.entcertlib.update()
示例#17
0
class EntitlementService(object):
    def __init__(self, cp=None):
        self.cp = cp
        self.identity = inj.require(inj.IDENTITY)
        self.product_dir = inj.require(inj.PROD_DIR)
        self.entitlement_dir = inj.require(inj.ENT_DIR)
        self.entcertlib = EntCertActionInvoker()

    def get_status(self, on_date=None):
        sorter = inj.require(inj.CERT_SORTER, on_date)
        if self.identity.is_valid():
            overall_status = sorter.get_system_status()
            reasons = sorter.reasons.get_name_message_map()
            valid = sorter.is_valid()
            return {'status': overall_status, 'reasons': reasons, 'valid': valid}
        else:
            return {'status': 'Unknown', 'reasons': {}, 'valid': False}

    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 get_consumed_product_pools(self, service_level=None, matches=None):
        # Use a named tuple so that the result can be unpacked into other functions
        ConsumedStatus = collections.namedtuple('ConsumedStatus', [
            'subscription_name',
            'provides',
            'sku',
            'contract',
            'account',
            'serial',
            'pool_id',
            'provides_management',
            'active',
            'quantity_used',
            'service_level',
            'service_type',
            'status_details',
            'subscription_type',
            'starts',
            'ends',
            'system_type',
        ])
        sorter = inj.require(inj.CERT_SORTER)
        cert_reasons_map = sorter.reasons.get_subscription_reasons_map()
        pooltype_cache = inj.require(inj.POOLTYPE_CACHE)

        consumed_statuses = []
        # FIXME: the cache of CertificateDirectory should be smart enough and refreshing
        # should not be necessary. When new certificate is installed/deleted and rhsm-service
        # is running, then list of certificate is not automatically refreshed ATM.
        self.entitlement_dir.refresh()
        certs = self.entitlement_dir.list()
        cert_filter = utils.EntitlementCertificateFilter(filter_string=matches, service_level=service_level)

        if service_level is not None or matches is not None:
            certs = list(filter(cert_filter.match, certs))

        # Now we need to transform the EntitlementCertificate object into
        # something JSON-like for consumption
        for cert in certs:
            # for some certs, order can be empty
            # so we default the values and populate them if
            # they exist. BZ974587
            name = ""
            sku = ""
            contract = ""
            account = ""
            quantity_used = ""
            service_level = ""
            service_type = ""
            system_type = ""
            provides_management = "No"

            order = cert.order

            if order:
                service_level = order.service_level or ""
                service_type = order.service_type or ""
                name = order.name
                sku = order.sku
                contract = order.contract or ""
                account = order.account or ""
                quantity_used = order.quantity_used
                if order.virt_only:
                    system_type = _("Virtual")
                else:
                    system_type = _("Physical")

                if order.provides_management:
                    provides_management = _("Yes")
                else:
                    provides_management = _("No")

            pool_id = _("Not Available")
            if hasattr(cert.pool, "id"):
                pool_id = cert.pool.id

            product_names = [p.name for p in cert.products]

            reasons = []
            pool_type = ''

            if inj.require(inj.CERT_SORTER).are_reasons_supported():
                if cert.subject and 'CN' in cert.subject:
                    if cert.subject['CN'] in cert_reasons_map:
                        reasons = cert_reasons_map[cert.subject['CN']]
                    pool_type = pooltype_cache.get(pool_id)

                # 1180400: Status details is empty when GUI is not
                if not reasons:
                    if cert in sorter.valid_entitlement_certs:
                        reasons.append(_("Subscription is current"))
                    else:
                        if cert.valid_range.end() < datetime.datetime.now(certificate.GMT()):
                            reasons.append(_("Subscription is expired"))
                        else:
                            reasons.append(_("Subscription has not begun"))
            else:
                reasons.append(_("Subscription management service doesn't support Status Details."))

            consumed_statuses.append(ConsumedStatus(
                name,
                product_names,
                sku,
                contract,
                account,
                cert.serial,
                pool_id,
                provides_management,
                cert.is_valid(),
                quantity_used,
                service_level,
                service_type,
                reasons,
                pool_type,
                managerlib.format_date(cert.valid_range.begin()),
                managerlib.format_date(cert.valid_range.end()),
                system_type))
        return consumed_statuses

    def get_available_pools(self, show_all=None, on_date=None, no_overlap=None,
                            match_installed=None, matches=None, service_level=None, future=None,
                            after=None):
        available_pools = managerlib.get_available_entitlements(
            get_all=show_all,
            active_on=on_date,
            overlapping=no_overlap,
            uninstalled=match_installed,
            filter_string=matches,
            future=future,
            after=after,
        )

        def filter_pool_by_service_level(pool_data):
            pool_level = ""
            if pool_data['service_level']:
                pool_level = pool_data['service_level']
            return service_level.lower() == pool_level.lower()

        if service_level is not None:
            available_pools = list(filter(filter_pool_by_service_level, available_pools))

        return available_pools

    def validate_options(self, options):
        if not set(['installed', 'consumed', 'available']).issuperset(options['pool_subsets']):
            raise exceptions.ValidationError(
                _('Error: invalid listing type provided.  Only "installed", '
                  '"consumed", or "available" are allowed')
            )
        if options['show_all'] and 'available' not in options['pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --all is only applicable with --available")
            )
        elif options['on_date'] and 'available' not in options['pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --ondate is only applicable with --available")
            )
        elif options['service_level'] is not None \
                and not set(['consumed', 'available']).intersection(options['pool_subsets']):
            raise exceptions.ValidationError(
                _("Error: --servicelevel is only applicable with --available or --consumed")
            )
        elif options['match_installed'] and 'available' not in options['pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --match-installed is only applicable with --available")
            )
        elif options['no_overlap'] and 'available' not in options['pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --no-overlap is only applicable with --available")
            )
        elif options['pool_only'] \
                and not set(['consumed', 'available']).intersection(options['pool_subsets']):
            raise exceptions.ValidationError(
                _("Error: --pool-only is only applicable with --available and/or --consumed")
            )
        elif not self.identity.is_valid() and 'available' in options['pool_subsets']:
            raise exceptions.ValidationError(_("Error: this system is not registered"))

    def _unbind_ids(self, unbind_method, consumer_uuid, ids):
        """
        Method for unbinding entitlements
        :param unbind_method: unbindByPoolId or unbindBySerial
        :param consumer_uuid: UUID of consumer
        :param ids: List of serials or pool_ids
        :return: Tuple of two lists containing unbinded and not-unbinded subscriptions
        """
        success = []
        failure = []
        for id_ in ids:
            try:
                unbind_method(consumer_uuid, id_)
                success.append(id_)
            except connection.RestlibException as re:
                if re.code == 410:
                    raise
                failure.append(id_)
                log.error(re)
        return success, failure

    def remove_all_entitlements(self):
        """
        Try to remove all entilements
        :return: Result of REST API call
        """

        response = self.cp.unbindAll(self.identity.uuid)
        self.entcertlib.update()

        return response

    def remove_entilements_by_pool_ids(self, pool_ids):
        """
        Try to remove entitlements by pool IDs
        :param pool_ids: List of pool IDs
        :return: List of serial numbers of removed subscriptions
        """

        removed_serials = []
        _pool_ids = utils.unique_list_items(pool_ids)  # Don't allow duplicates
        # FIXME: the cache of CertificateDirectory should be smart enough and refreshing
        # should not be necessary. I vote for i-notify to be used there somehow.
        self.entitlement_dir.refresh()
        pool_id_to_serials = self.entitlement_dir.list_serials_for_pool_ids(_pool_ids)
        removed_pools, unremoved_pools = self._unbind_ids(self.cp.unbindByPoolId, self.identity.uuid, _pool_ids)
        if removed_pools:
            for pool_id in removed_pools:
                removed_serials.extend(pool_id_to_serials[pool_id])
        self.entcertlib.update()

        return removed_pools, unremoved_pools, removed_serials

    def remove_entitlements_by_serials(self, serials):
        """
        Try to remove pools by Serial numbers
        :param serials: List of serial numbers
        :return: List of serial numbers of already removed subscriptions
        """

        _serials = utils.unique_list_items(serials)  # Don't allow duplicates
        removed_serials, unremoved_serials = self._unbind_ids(self.cp.unbindBySerial, self.identity.uuid, _serials)
        self.entcertlib.update()

        return removed_serials, unremoved_serials
示例#18
0
    def main(self, args=None):

        # TODO: For now, we disable the CLI entirely. We may want to allow some commands in the future.
        if rhsm.config.in_container():
            system_exit(
                os.EX_CONFIG,
                _("subscription-manager is disabled when running inside a container. Please refer to your host system for subscription management.\n"
                  ))

        config_changed = False

        # In testing we sometimes specify args, otherwise use the default:
        if not args:
            args = sys.argv[1:]

        (self.options, self.args) = self.parser.parse_known_args(args)

        # we dont need argv[0] in this list...
        self.args = self.args[1:]
        # check for unparsed arguments
        if self.args:
            for arg in self.args:
                print(_("cannot parse argument: {}").format(arg))
            system_exit(os.EX_USAGE)

        if hasattr(self.options, "insecure") and self.options.insecure:
            conf["server"]["insecure"] = "1"
            config_changed = True

        if hasattr(self.options, "server_url") and self.options.server_url:
            try:
                (self.server_hostname, self.server_port,
                 self.server_prefix) = parse_server_info(
                     self.options.server_url, conf)
            except ServerUrlParseError as e:
                print(_("Error parsing serverurl:"))
                handle_exception("Error parsing serverurl:", e)

            conf["server"]["hostname"] = self.server_hostname
            conf["server"]["port"] = self.server_port
            conf["server"]["prefix"] = self.server_prefix
            if self.server_port:
                self.server_port = int(self.server_port)
            config_changed = True

        if hasattr(self.options, "base_url") and self.options.base_url:
            try:
                (baseurl_server_hostname, baseurl_server_port,
                 baseurl_server_prefix) = parse_baseurl_info(
                     self.options.base_url)
            except ServerUrlParseError as e:
                print(_("Error parsing baseurl:"))
                handle_exception("Error parsing baseurl:", e)

            conf["rhsm"]["baseurl"] = format_baseurl(baseurl_server_hostname,
                                                     baseurl_server_port,
                                                     baseurl_server_prefix)
            config_changed = True

        # support foo.example.com:3128 format
        if hasattr(self.options, "proxy_url") and self.options.proxy_url:
            parts = remove_scheme(self.options.proxy_url).split(':')
            self.proxy_hostname = parts[0]
            # no ':'
            if len(parts) > 1:
                self.proxy_port = int(parts[1])
            else:
                # if no port specified, use the one from the config, or fallback to the default
                self.proxy_port = conf['server'].get_int(
                    'proxy_port') or rhsm.config.DEFAULT_PROXY_PORT
            config_changed = True

        if hasattr(self.options, "proxy_user") and self.options.proxy_user:
            self.proxy_user = self.options.proxy_user
        if hasattr(self.options,
                   "proxy_password") and self.options.proxy_password:
            self.proxy_password = self.options.proxy_password
        if hasattr(self.options, "no_proxy") and self.options.no_proxy:
            self.no_proxy = self.options.no_proxy

        # Proxy information isn't written to the config, so we have to make sure
        # the sorter gets it
        connection_info = {}
        if self.proxy_hostname:
            connection_info['proxy_hostname_arg'] = self.proxy_hostname
        if self.proxy_port:
            connection_info['proxy_port_arg'] = self.proxy_port
        if self.proxy_user:
            connection_info['proxy_user_arg'] = self.proxy_user
        if self.proxy_password:
            connection_info['proxy_password_arg'] = self.proxy_password
        if self.server_hostname:
            connection_info['host'] = self.server_hostname
        if self.server_port:
            connection_info['ssl_port'] = self.server_port
        if self.server_prefix:
            connection_info['handler'] = self.server_prefix
        if self.no_proxy:
            connection_info['no_proxy_arg'] = self.no_proxy

        self.cp_provider = inj.require(inj.CP_PROVIDER)
        self.cp_provider.set_connection_info(**connection_info)
        self.log.debug("X-Correlation-ID: {id}".format(id=self.correlation_id))
        self.cp_provider.set_correlation_id(self.correlation_id)

        self.log_client_version()

        if self.require_connection():
            # make sure we pass in the new server info, otherwise we
            # we use the defaults from connection module init
            # we've set self.proxy* here, so we'll use them if they
            # are set
            self.cp = self.cp_provider.get_consumer_auth_cp()

            # no auth cp for get / (resources) and
            # get /status (status and versions)
            self.no_auth_cp = self.cp_provider.get_no_auth_cp()

            self.entcertlib = EntCertActionInvoker()

            if config_changed:
                try:
                    # catch host/port issues; does not catch auth issues
                    if not self.test_proxy_connection():
                        system_exit(
                            os.EX_UNAVAILABLE,
                            _("Proxy connection failed, please check your settings."
                              ))

                    # this tries to actually connect to the server and ping it
                    if not is_valid_server_info(self.no_auth_cp):
                        system_exit(
                            os.EX_UNAVAILABLE,
                            _("Unable to reach the server at {host}:{port}{handler}"
                              ).format(host=self.no_auth_cp.host,
                                       port=self.no_auth_cp.ssl_port,
                                       handler=self.no_auth_cp.handler))

                except MissingCaCertException:
                    system_exit(
                        os.EX_CONFIG,
                        _("Error: CA certificate for subscription service has not been installed."
                          ))
                except ProxyException:
                    system_exit(
                        os.EX_UNAVAILABLE,
                        _("Proxy connection failed, please check your settings."
                          ))

        else:
            self.cp = None

        # do the work, catch most common errors here:
        try:

            return_code = self._do_command()

            # Only persist the config changes if there was no exception
            if config_changed and self.persist_server_options():
                conf.persist()

            if return_code is not None:
                return return_code
        except (CertificateException, ssl.SSLError) as e:
            log.error(e)
            system_exit(os.EX_SOFTWARE,
                        _('System certificates corrupted. Please reregister.'))
        except connection.GoneException as ge:
            if ge.deleted_id == self.identity.uuid:
                log.critical(
                    "Consumer profile \"{uuid}\" has been deleted from the server."
                    .format(uuid=self.identity.uuid))
                system_exit(
                    os.EX_UNAVAILABLE,
                    _("Consumer profile \"{uuid}\" has been deleted from the server. You can use command clean or unregister to remove local profile."
                      ).format(uuid=self.identity.uuid))
            else:
                raise ge
        except InvalidCLIOptionError as err:
            # This exception is handled in cli module
            raise err
        except Exception as err:
            handle_exception("exception caught in subscription-manager", err)
示例#19
0
class EntitlementService(object):
    def __init__(self, cp=None):
        self.cp = cp
        self.identity = inj.require(inj.IDENTITY)
        self.product_dir = inj.require(inj.PROD_DIR)
        self.entitlement_dir = inj.require(inj.ENT_DIR)
        self.entcertlib = EntCertActionInvoker()

    @classmethod
    def parse_date(cls, on_date):
        """
        Return new datetime parsed from date
        :param on_date: String representing date
        :return It returns datetime.datime structure representing date
        """
        try:
            on_date = datetime.datetime.strptime(on_date, '%Y-%m-%d')
        except ValueError:
            raise ValueError(
                _("Date entered is invalid. Date should be in YYYY-MM-DD format (example: "
                  ) + time.strftime("%Y-%m-%d", time.localtime()) + " )")
        if on_date.date() < datetime.datetime.now().date():
            raise ValueError(_("Past dates are not allowed"))
        return on_date

    def get_status(self, on_date=None):
        sorter = inj.require(inj.CERT_SORTER, on_date)
        # When singleton CertSorter was created with different argument on_date, then
        # it is necessary to update corresponding attribute in object (dependency
        # injection doesn't do it automatically).
        if sorter.on_date != on_date:
            sorter.on_date = on_date
            # Force reload status from the server to be sure that we get valid status for new date.
            # It is necessary to do it for rhsm.service, because it can run for very long time without
            # restart.
            sorter.load()
        if self.identity.is_valid():
            overall_status = sorter.get_system_status()
            reasons = sorter.reasons.get_name_message_map()
            valid = sorter.is_valid()
            return {
                'status': overall_status,
                'reasons': reasons,
                'valid': valid
            }
        else:
            return {'status': 'Unknown', 'reasons': {}, 'valid': False}

    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,
                  **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_date': after_date,
        }
        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_date=after_date,
            )
            if pool_only:
                results['available'] = [x['id'] for x in available]
            else:
                results['available'] = available

        return results

    def get_consumed_product_pools(self, service_level=None, matches=None):
        # Use a named tuple so that the result can be unpacked into other functions
        ConsumedStatus = collections.namedtuple('ConsumedStatus', [
            'subscription_name',
            'provides',
            'sku',
            'contract',
            'account',
            'serial',
            'pool_id',
            'provides_management',
            'active',
            'quantity_used',
            'service_level',
            'service_type',
            'status_details',
            'subscription_type',
            'starts',
            'ends',
            'system_type',
        ])
        sorter = inj.require(inj.CERT_SORTER)
        cert_reasons_map = sorter.reasons.get_subscription_reasons_map()
        pooltype_cache = inj.require(inj.POOLTYPE_CACHE)

        consumed_statuses = []
        # FIXME: the cache of CertificateDirectory should be smart enough and refreshing
        # should not be necessary. When new certificate is installed/deleted and rhsm-service
        # is running, then list of certificate is not automatically refreshed ATM.
        self.entitlement_dir.refresh()
        certs = self.entitlement_dir.list()
        cert_filter = utils.EntitlementCertificateFilter(
            filter_string=matches, service_level=service_level)

        if service_level is not None or matches is not None:
            certs = list(filter(cert_filter.match, certs))

        # Now we need to transform the EntitlementCertificate object into
        # something JSON-like for consumption
        for cert in certs:
            # for some certs, order can be empty
            # so we default the values and populate them if
            # they exist. BZ974587
            name = ""
            sku = ""
            contract = ""
            account = ""
            quantity_used = ""
            service_level = ""
            service_type = ""
            system_type = ""
            provides_management = "No"

            order = cert.order

            if order:
                service_level = order.service_level or ""
                service_type = order.service_type or ""
                name = order.name
                sku = order.sku
                contract = order.contract or ""
                account = order.account or ""
                quantity_used = order.quantity_used
                if order.virt_only:
                    system_type = _("Virtual")
                else:
                    system_type = _("Physical")

                if order.provides_management:
                    provides_management = _("Yes")
                else:
                    provides_management = _("No")

            pool_id = _("Not Available")
            if hasattr(cert.pool, "id"):
                pool_id = cert.pool.id

            product_names = [p.name for p in cert.products]

            reasons = []
            pool_type = ''

            if inj.require(inj.CERT_SORTER).are_reasons_supported():
                if cert.subject and 'CN' in cert.subject:
                    if cert.subject['CN'] in cert_reasons_map:
                        reasons = cert_reasons_map[cert.subject['CN']]
                    pool_type = pooltype_cache.get(pool_id)

                # 1180400: Status details is empty when GUI is not
                if not reasons:
                    if cert in sorter.valid_entitlement_certs:
                        reasons.append(_("Subscription is current"))
                    else:
                        if cert.valid_range.end() < datetime.datetime.now(
                                certificate.GMT()):
                            reasons.append(_("Subscription is expired"))
                        else:
                            reasons.append(_("Subscription has not begun"))
            else:
                reasons.append(
                    _("Subscription management service doesn't support Status Details."
                      ))

            consumed_statuses.append(
                ConsumedStatus(
                    name, product_names, sku, contract,
                    account, cert.serial, pool_id, provides_management,
                    cert.is_valid(), quantity_used, service_level,
                    service_type, reasons, pool_type,
                    managerlib.format_date(cert.valid_range.begin()),
                    managerlib.format_date(cert.valid_range.end()),
                    system_type))
        return consumed_statuses

    def get_available_pools(self,
                            show_all=None,
                            on_date=None,
                            no_overlap=None,
                            match_installed=None,
                            matches=None,
                            service_level=None,
                            future=None,
                            after_date=None):
        available_pools = managerlib.get_available_entitlements(
            get_all=show_all,
            active_on=on_date,
            overlapping=no_overlap,
            uninstalled=match_installed,
            filter_string=matches,
            future=future,
            after_date=after_date,
        )

        def filter_pool_by_service_level(pool_data):
            pool_level = ""
            if pool_data['service_level']:
                pool_level = pool_data['service_level']
            return service_level.lower() == pool_level.lower()

        if service_level is not None:
            available_pools = list(
                filter(filter_pool_by_service_level, available_pools))

        return available_pools

    def validate_options(self, options):
        if not set(['installed', 'consumed', 'available']).issuperset(
                options['pool_subsets']):
            raise exceptions.ValidationError(
                _('Error: invalid listing type provided.  Only "installed", '
                  '"consumed", or "available" are allowed'))
        if options['show_all'] and 'available' not in options['pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --all is only applicable with --available"))
        elif options['on_date'] and 'available' not in options['pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --ondate is only applicable with --available"))
        elif options['service_level'] is not None \
                and not set(['consumed', 'available']).intersection(options['pool_subsets']):
            raise exceptions.ValidationError(
                _("Error: --servicelevel is only applicable with --available or --consumed"
                  ))
        elif options['match_installed'] and 'available' not in options[
                'pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --match-installed is only applicable with --available"
                  ))
        elif options['no_overlap'] and 'available' not in options[
                'pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: --no-overlap is only applicable with --available"))
        elif options['pool_only'] \
                and not set(['consumed', 'available']).intersection(options['pool_subsets']):
            raise exceptions.ValidationError(
                _("Error: --pool-only is only applicable with --available and/or --consumed"
                  ))
        elif not self.identity.is_valid(
        ) and 'available' in options['pool_subsets']:
            raise exceptions.ValidationError(
                _("Error: this system is not registered"))

    def _unbind_ids(self, unbind_method, consumer_uuid, ids):
        """
        Method for unbinding entitlements
        :param unbind_method: unbindByPoolId or unbindBySerial
        :param consumer_uuid: UUID of consumer
        :param ids: List of serials or pool_ids
        :return: Tuple of two lists containing unbinded and not-unbinded subscriptions
        """
        success = []
        failure = []
        for id_ in ids:
            try:
                unbind_method(consumer_uuid, id_)
                success.append(id_)
            except connection.RestlibException as re:
                if re.code == 410:
                    raise
                failure.append(id_)
                log.error(re)
        return success, failure

    def remove_all_entitlements(self):
        """
        Try to remove all entilements
        :return: Result of REST API call
        """

        response = self.cp.unbindAll(self.identity.uuid)
        self.entcertlib.update()

        return response

    def remove_entilements_by_pool_ids(self, pool_ids):
        """
        Try to remove entitlements by pool IDs
        :param pool_ids: List of pool IDs
        :return: List of serial numbers of removed subscriptions
        """

        removed_serials = []
        _pool_ids = utils.unique_list_items(pool_ids)  # Don't allow duplicates
        # FIXME: the cache of CertificateDirectory should be smart enough and refreshing
        # should not be necessary. I vote for i-notify to be used there somehow.
        self.entitlement_dir.refresh()
        pool_id_to_serials = self.entitlement_dir.list_serials_for_pool_ids(
            _pool_ids)
        removed_pools, unremoved_pools = self._unbind_ids(
            self.cp.unbindByPoolId, self.identity.uuid, _pool_ids)
        if removed_pools:
            for pool_id in removed_pools:
                removed_serials.extend(pool_id_to_serials[pool_id])
        self.entcertlib.update()

        return removed_pools, unremoved_pools, removed_serials

    def remove_entitlements_by_serials(self, serials):
        """
        Try to remove pools by Serial numbers
        :param serials: List of serial numbers
        :return: List of serial numbers of already removed subscriptions
        """

        _serials = utils.unique_list_items(serials)  # Don't allow duplicates
        removed_serials, unremoved_serials = self._unbind_ids(
            self.cp.unbindBySerial, self.identity.uuid, _serials)
        self.entcertlib.update()

        return removed_serials, unremoved_serials

    def reload(self):
        sorter = inj.require(inj.CERT_SORTER, on_date=None)
        sorter.load()
示例#20
0
 def __init__(self, cp=None):
     self.cp = cp
     self.identity = inj.require(inj.IDENTITY)
     self.product_dir = inj.require(inj.PROD_DIR)
     self.entitlement_dir = inj.require(inj.ENT_DIR)
     self.entcertlib = EntCertActionInvoker()