anaconda/anaconda-40.22.3.13/pyanaconda/modules/common/structures/subscription.py
2024-11-14 21:39:56 -08:00

536 lines
16 KiB
Python

#
# DBus structures for subscription related data.
#
# Copyright (C) 2020 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from dasbus.structure import DBusData
from dasbus.typing import * # pylint: disable=wildcard-import
from pyanaconda.core.constants import DEFAULT_SUBSCRIPTION_REQUEST_TYPE
from pyanaconda.modules.common.structures.secret import SecretData, SecretDataList
__all__ = ["SystemPurposeData", "SubscriptionRequest", "AttachedSubscription"]
class SystemPurposeData(DBusData):
"""System purpose data."""
def __init__(self):
self._role = ""
self._sla = ""
self._usage = ""
self._addons = []
@property
def role(self) -> Str:
"""Return the System Purpose role (if any).
:return: system purpose role
"""
return self._role
@role.setter
def role(self, role: Str):
self._role = role
@property
def sla(self) -> Str:
"""Return the System Purpose SLA (if any).
:return: system purpose SLA
"""
return self._sla
@sla.setter
def sla(self, sla: Str):
self._sla = sla
@property
def usage(self) -> Str:
"""Return the System Purpose usage (if any).
:return: system purpose usage
"""
return self._usage
@usage.setter
def usage(self, usage: Str):
self._usage = usage
@property
def addons(self) -> List[Str]:
"""Return list of additional layered products or features (if any).
:return: system purpose addons
"""
return self._addons
@addons.setter
def addons(self, addons: List[Str]):
self._addons = addons
def check_data_available(self):
"""A helper function used to determining if some system purpose data is available.
Otherwise we would have to query all the fields each time we want to check if we
have any system purpose data available.
:return: is any system purpose data is available
:rtype: bool
"""
return any((self.role, self.sla, self.usage, self.addons))
def __eq__(self, other_instance):
"""Used to determining if other SystemPurposeData instance has the same data.
Otherwise we would have to compare all the fields each time we want to check if the
two SystemPurposeData instances have the same data.
:param other_instance: another SystemPurposeData to compare with this one
:type other_instance: SystemPurposeData instance
:return: True if the other structure has the same system purpose data as this one,
False otherwise
:rtype: bool
"""
# if the other instance is not instance of SubscriptionRequest,
# then it is always considered to be different
if not isinstance(other_instance, SystemPurposeData):
return False
# addon ordering is not important
if set(self.addons) != set(other_instance.addons):
return False
elif self.role != other_instance.role:
return False
elif self.sla != other_instance.sla:
return False
elif self.usage != other_instance.usage:
return False
else:
return True
class SubscriptionRequest(DBusData):
"""Data for a subscription request.
NOTE: Names of some of the fields are based on
how the given keys are called in rhsm.conf.
"""
def __init__(self):
# subscription request type
# (based on authentication method used)
self._type = DEFAULT_SUBSCRIPTION_REQUEST_TYPE
# user identification
# - in case an account is member
# of multiple organizations, both
# organization and account username
# need to be set
self._organization = ""
self._redhat_account_username = ""
# Candlepin instance
self._server_hostname = ""
# CDN base url
self._rhsm_baseurl = ""
# RHSM HTTP proxy
self._server_proxy_hostname = ""
self._server_proxy_port = -1
self._server_proxy_user = ""
# private data
# - we are using SecretData & SecretDataList
# nested DBus structures to protect this
# sensitive data
# - this way they can be set-only & easily
# removed from SubscriptionRequest on
# output from the Subscription module
# - they also support a robust way of clearing
# previously set sensitive data if required
self._redhat_account_password = SecretData()
self._activation_keys = SecretDataList()
self._server_proxy_password = SecretData()
@property
def type(self) -> Str:
"""Subscription request type.
Subscription request type is based on the authentication method used.
At the moment the following two are supported:
- username + password
- organization id + one or more activation keys
By default username + password is used.
Valid values are:
"username_password"
"org_activation_key"
:return: subscription request type
:rtype: str
"""
return self._type
@type.setter
def type(self, request_type: Str):
self._type = request_type
@property
def organization(self) -> Str:
"""Organization id for subscription purposes.
In most cases one of the following will be used:
- org id + one or more activation keys
- username + password
There is also a less often expected use case,
which applies if the same user account exists
in multiple organizations on the same Candlepin
instance. In such a case both username and
organization id needs to be set.
:return: organization id
:rtype: str
"""
return self._organization
@organization.setter
def organization(self, organization: Str):
self._organization = organization
@property
def account_username(self) -> Str:
"""Red Hat account username for subscription purposes.
In case the account for the given username is member
of multiple organizations, organization id needs to
be specified as well or else the registration attempt
will not be successful.
:return: Red Hat account username
:rtype: str
"""
return self._redhat_account_username
@account_username.setter
def account_username(self, account_username: Str):
self._redhat_account_username = account_username
@property
def server_hostname(self) -> Str:
"""Subscription server hostname.
This is basically a URL pointing to a Candlepin
instance to be used. It could be the one handling
general subscriptions hosted by Red Hat or one
embedded in a Satellite deployment.
If no custom server hostname is set, the default
value used by subscription manager will be used,
which is usually the URL pointing to the general
purpose Red Hat hosted Candlepin instance.
:return: Candlepin instance URL
:rtype: str
"""
return self._server_hostname
@server_hostname.setter
def server_hostname(self, server_hostname: Str):
self._server_hostname = server_hostname
@property
def rhsm_baseurl(self) -> Str:
"""CDN repository base URL.
Sets the base URL for the RHSM generated
repo file.
Setting this to a non default value only
makes sense if registering against Satellite
(as you would want to use the repos hosted
on the given Satellite instance) or possibly
during testing.
If no custom rhsm baseurl is set, the default
value used by subscription managed will be used,
which is generally baseurl for the Red Hat CDN.
:return: RHSM base url
:rtype: str
"""
return self._rhsm_baseurl
@rhsm_baseurl.setter
def rhsm_baseurl(self, rhsm_baseurl: Str):
self._rhsm_baseurl = rhsm_baseurl
@property
def server_proxy_hostname(self) -> Str:
"""RHSM HTTP proxy - hostname.
This is the hostname of the RHSM HTTP
proxy, which will be used for subscription
purposes only, eq. this will not configure
a system wide HTTP proxy.
:return: RHSM HTTP proxy hostname
:rtype: str
"""
return self._server_proxy_hostname
@server_proxy_hostname.setter
def server_proxy_hostname(self, hostname: Str):
self._server_proxy_hostname = hostname
@property
def server_proxy_port(self) -> Int:
"""RHSM HTTP proxy - port number.
-1 means port has not been set.
:returns: RHSM HTTP proxy port number
:rtype: int
"""
return self._server_proxy_port
@server_proxy_port.setter
def server_proxy_port(self, port_number: Int):
self._server_proxy_port = port_number
@property
def server_proxy_user(self) -> Str:
"""RHSM HTTP proxy - access username.
:return: RHSM HTTP proxy access username
:rtype: str
"""
return self._server_proxy_user
@server_proxy_user.setter
def server_proxy_user(self, username: Str):
self._server_proxy_user = username
# private data
# - generally sensitive data such as passwords
# or activation keys
# - these values should be "write only",
# meaning data goes to the Subscription
# module but can't be read out later one
# via the public API
# - only the Subscription module should have
# have access to these data internally &
# use them appropriately (eq. register
# the system, authenticate to HTTP proxy, etc.)
# - it should be also possible to explicitly
# clear a previously set secret
# - to protect these values we are using
# SecretData & SecretDataList, see their
# implementation for more information
@property
def account_password(self) -> SecretData:
"""Red Hat account password.
NOTE: This property is stored in SecretData
nested DBus structure to protect its contents.
:return: Red hat account password stored in a SecretData instance
:rtype: SecretData instance
"""
return self._redhat_account_password
@account_password.setter
def account_password(self, password: SecretData):
self._redhat_account_password = password
@property
def activation_keys(self) -> SecretDataList:
"""List of activation keys.
For a successful activation key based registration
at least one activation key needs to be set.
NOTE: This property is stored in SecretDataList
nested DBus structure to protect its contents.
:return: list of activation keys stored in SecretDataList instance
:rtype: SecretDataList instance
"""
return self._activation_keys
@activation_keys.setter
def activation_keys(self, activation_keys: SecretDataList):
self._activation_keys = activation_keys
@property
def server_proxy_password(self) -> SecretData:
"""RHSM HTTP proxy - access password.
NOTE: This property is stored in SecretData
nested DBus structure to protect its contents.
:return: RHSM HTTP proxy password stored in SecretData instance
:rtype: SecretData instance
"""
return self._server_proxy_password
@server_proxy_password.setter
def server_proxy_password(self, password: SecretData):
self._server_proxy_password = password
class AttachedSubscription(DBusData):
"""Data for a single attached subscription."""
def __init__(self):
self._name = ""
self._service_level = ""
self._sku = ""
self._contract = ""
self._start_date = ""
self._end_date = ""
# we can expect at least one entitlement
# to be consumed per attached subscription
self._consumed_entitlement_count = 1
@property
def name(self) -> Str:
"""Name of the attached subscription.
Example: "Red Hat Beta Access"
:return: subscription name
:rtype: str
"""
return self._name
@name.setter
def name(self, name: Str):
self._name = name
@property
def service_level(self) -> Str:
"""Service level of the attached subscription.
Example: "Premium"
:return: service level
:rtype: str
"""
return self._service_level
@service_level.setter
def service_level(self, service_level: Str):
self._service_level = service_level
@property
def sku(self) -> Str:
"""SKU id of the attached subscription.
Example: "MBT8547"
:return: SKU id
:rtype: str
"""
return self._sku
@sku.setter
def sku(self, sku: Str):
self._sku = sku
@property
def contract(self) -> Str:
"""Contract identifier.
Example: "32754658"
:return: contract identifier
:rtype: str
"""
return self._contract
@contract.setter
def contract(self, contract: Str):
self._contract = contract
@property
def start_date(self) -> Str:
"""Subscription start date.
We do not guarantee fixed date format,
but we aim for the date to look good
when displayed in a GUI and be human
readable.
For context see the following bug, that
illustrates the issues we are having with
the source date for this property, that
prevent us from providing a consistent
date format:
https://bugzilla.redhat.com/show_bug.cgi?id=1793501
Example: "Nov 04, 2019"
:return: start date of the subscription
:rtype: str
"""
return self._start_date
@start_date.setter
def start_date(self, start_date: Str):
self._start_date = start_date
@property
def end_date(self) -> Str:
"""Subscription end date.
We do not guarantee fixed date format,
but we aim for the date to look good
when displayed in a GUI and be human
readable.
For context see the following bug, that
illustrates the issues we are having with
the source date for this property, that
prevent us from providing a consistent
date format:
https://bugzilla.redhat.com/show_bug.cgi?id=1793501
Example: "Nov 04, 2020"
:return: end date of the subscription
:rtype: str
"""
return self._end_date
@end_date.setter
def end_date(self, end_date: Str):
self._end_date = end_date
@property
def consumed_entitlement_count(self) -> Int:
"""Number of consumed entitlements for this subscription.
Example: "1"
:return: consumed entitlement number
:rtype: int
"""
return self._consumed_entitlement_count
@consumed_entitlement_count.setter
def consumed_entitlement_count(self, consumed_entitlement_count: Int):
self._consumed_entitlement_count = consumed_entitlement_count