def test_attach_subscription_task_success(self, environ_get): """Test the ParseAttachedSubscriptionsTask.""" # prepare mock proxies the task is expected to interact with rhsm_entitlement_proxy = Mock() rhsm_entitlement_proxy.GetPools.return_value = "foo" rhsm_syspurpose_proxy = Mock() rhsm_syspurpose_proxy.GetSyspurpose.return_value = "bar" task = ParseAttachedSubscriptionsTask( rhsm_entitlement_proxy=rhsm_entitlement_proxy, rhsm_syspurpose_proxy=rhsm_syspurpose_proxy) # mock the parsing methods subscription1 = AttachedSubscription() subscription2 = AttachedSubscription() task._parse_subscription_json = Mock() task._parse_subscription_json.return_value = [ subscription1, subscription2 ] system_purpose_data = SystemPurposeData() task._parse_system_purpose_json = Mock() task._parse_system_purpose_json.return_value = system_purpose_data # run the task result = task.run() # check DBus proxies were called as expected rhsm_entitlement_proxy.GetPools.assert_called_once_with( {'pool_subsets': get_variant(Str, "consumed")}, {}, "en_US.UTF-8") rhsm_syspurpose_proxy.GetSyspurpose.assert_called_once_with( "en_US.UTF-8") # check the parsing methods were called task._parse_subscription_json.assert_called_once_with("foo") task._parse_system_purpose_json.assert_called_once_with("bar") # check the result that has been returned is as expected self.assertEqual(result.attached_subscriptions, [subscription1, subscription2]) self.assertEqual(result.system_purpose_data, system_purpose_data)
def SystemPurposeData(self, system_purpose_data: Structure): """Set a new DBus structure holding system purpose data. :param system_purpose_data: DBus structure corresponding to SystemPurposeData """ converted_data = SystemPurposeData.from_structure(system_purpose_data) self.implementation.set_system_purpose_data(converted_data)
def _set_system_purpose_data(self): """Set system purpose data to the Subscription DBus module.""" self._subscription_module.SetSystemPurposeData( SystemPurposeData.to_structure(self.system_purpose_data) ) # also apply the data (only applies when needed) self._apply_system_purpose_data()
def __init__(self): super().__init__() # system purpose self._valid_roles = [] self._valid_slas = [] self._valid_usage_types = [] self._system_purpose_data = SystemPurposeData() self.system_purpose_data_changed = Signal() self._load_valid_system_purpose_values() # subscription request self._subscription_request = SubscriptionRequest() self.subscription_request_changed = Signal() # attached subscriptions self._attached_subscriptions = [] self.attached_subscriptions_changed = Signal() # Insights # What are the defaults for Red Hat Insights ? # - during a kickstart installation, the user # needs to opt-in by using the rhsm command # with the --connect-to-insights option # - during a GUI interactive installation the # "connect to Insights" checkbox is checked by default, # making Insights opt-out # - in both cases the system also needs to be subscribed, # or else the system can't be connected to Insights self._connect_to_insights = False self.connect_to_insights_changed = Signal() # registration status self.registered_changed = Signal() self._registered = False # subscription status self.subscription_attached_changed = Signal() self._subscription_attached = False # RHSM service startup and access self._rhsm_startup_task = StartRHSMTask( verify_ssl=conf.payload.verify_ssl) self._rhsm_observer = RHSMObserver( self._rhsm_startup_task.is_service_available) # RHSM config default values cache self._rhsm_config_defaults = None
def _parse_system_purpose_json(final_syspurpose_json): """Parse the JSON into a SystemPurposeData instance. The expected JSON is a simple three key dictionary listing the final System Purpose state after subscription/subscriptions have been attached. :param str final_syspurpose_json: JSON describing final syspurpose state :return: final system purpose data :rtype: SystemPurposeData instance """ system_purpose_data = SystemPurposeData() try: syspurpose_json = json.loads(final_syspurpose_json) except json.decoder.JSONDecodeError: log.warning( "subscription: failed to parse GetSyspurpose() JSON output") # empty system purpose data is better than an installation ending crash return system_purpose_data system_purpose_data.role = syspurpose_json.get("role", "") system_purpose_data.sla = syspurpose_json.get( "service_level_agreement", "") system_purpose_data.usage = syspurpose_json.get("usage", "") system_purpose_data.addons = syspurpose_json.get("addons", []) return system_purpose_data
def __init__(self): super().__init__() # system purpose self._valid_roles = [] self._valid_slas = [] self._valid_usage_types = [] self._system_purpose_data = SystemPurposeData() self.system_purpose_data_changed = Signal() self._load_valid_system_purpose_values()
def ks_out_command_only_test(self): """Test with only syspurpose command being used.""" ks_in = "syspurpose" ks_out = "" self._test_kickstart(ks_in, ks_out) # also test resulting module state structure = self.subscription_interface.SystemPurposeData system_purpose_data = SystemPurposeData.from_structure(structure) self.assertEqual(system_purpose_data.role, "") self.assertEqual(system_purpose_data.sla, "") self.assertEqual(system_purpose_data.usage, "") self.assertEqual(system_purpose_data.addons, [])
def test_system_purpose_json_parsing(self): """Test the system purpose JSON parsing method of ParseAttachedSubscriptionsTask.""" parse_method = ParseAttachedSubscriptionsTask._parse_system_purpose_json # the parsing method should be able to survive also getting an empty string expected_struct = {"role": "", "sla": "", "usage": "", "addons": []} struct = get_native(SystemPurposeData.to_structure(parse_method(""))) self.assertEqual(struct, expected_struct) # try parsing expected complete system purpose data system_purpose_dict = { "role": "important", "service_level_agreement": "it will work just fine", "usage": "careful", "addons": ["red", "green", "blue"] } system_purpose_json = json.dumps(system_purpose_dict) expected_struct = { "role": "important", "sla": "it will work just fine", "usage": "careful", "addons": ["red", "green", "blue"] } struct = get_native( SystemPurposeData.to_structure(parse_method(system_purpose_json))) self.assertEqual(struct, expected_struct) # try also partial parsing, just in case system_purpose_dict = { "role": "important", "usage": "careful", } system_purpose_json = json.dumps(system_purpose_dict) expected_struct = { "role": "important", "sla": "", "usage": "careful", "addons": [] } struct = get_native( SystemPurposeData.to_structure(parse_method(system_purpose_json))) self.assertEqual(struct, expected_struct)
def ks_out_set_all_usage_test(self): """Check kickstart with all options being used.""" ks_in = ''' syspurpose --role="FOO" --sla="BAR" --usage="BAZ" --addon="F Product" --addon="B Feature" ''' ks_out = ''' # Intended system purpose syspurpose --role="FOO" --sla="BAR" --usage="BAZ" --addon="F Product" --addon="B Feature" ''' self._test_kickstart(ks_in, ks_out) structure = self.subscription_interface.SystemPurposeData system_purpose_data = SystemPurposeData.from_structure(structure) self.assertEqual(system_purpose_data.role, 'FOO') self.assertEqual(system_purpose_data.sla, 'BAR') self.assertEqual(system_purpose_data.usage, 'BAZ') self.assertEqual(system_purpose_data.addons, ["F Product", "B Feature"])
def set_system_purpose_test(self): """Test if setting system purpose data from DBUS works correctly.""" system_purpose_data = { "role": get_variant(Str, "foo"), "sla": get_variant(Str, "bar"), "usage": get_variant(Str, "baz"), "addons": get_variant(List[Str], ["a", "b", "c"]) } self._test_dbus_property("SystemPurposeData", system_purpose_data) output_structure = self.subscription_interface.SystemPurposeData output_system_purpose_data = SystemPurposeData.from_structure( output_structure) self.assertEqual(output_system_purpose_data.role, "foo") self.assertEqual(output_system_purpose_data.sla, "bar") self.assertEqual(output_system_purpose_data.usage, "baz") self.assertEqual(output_system_purpose_data.addons, ["a", "b", "c"])
def test_system_purpose_task(self, give_the_system_purpose): """Test the SystemPurposeConfigurationTask task - not yet set.""" # prepare some system purpose data system_purpose_data = SystemPurposeData() system_purpose_data.role = "foo" system_purpose_data.sla = "bar" system_purpose_data.usage = "baz" system_purpose_data.addons = ["a", "b", "c"] task = SystemPurposeConfigurationTask(system_purpose_data) task.run() give_the_system_purpose.assert_called_once_with(sysroot="/", role="foo", sla="bar", usage="baz", addons=["a", "b", "c"])
def system_purpose_task_test(self, give_the_system_purpose): """Test the SystemPurposeConfigurationTask task.""" with tempfile.TemporaryDirectory() as sysroot: system_purpose_data = SystemPurposeData() system_purpose_data.role = "foo" system_purpose_data.sla = "bar" system_purpose_data.usage = "baz" system_purpose_data.addons = ["a", "b", "c"] task = SystemPurposeConfigurationTask(sysroot, system_purpose_data) task.run() give_the_system_purpose.assert_called_once_with( role="foo", sla="bar", usage="baz", addons=["a", "b", "c"], sysroot=sysroot)
def system_purpose_data_test(self): """Test the SystemPurposeData DBus structure.""" # create the SystemPurposeData structure system_purpose_data = SystemPurposeData() system_purpose_data.role = "foo" system_purpose_data.sla = "bar" system_purpose_data.usage = "baz" system_purpose_data.addons = ["a", "b", "c"] # create its expected representation expected_dict = { "role": get_variant(Str, "foo"), "sla": get_variant(Str, "bar"), "usage": get_variant(Str, "baz"), "addons": get_variant(List[Str], ["a", "b", "c"]) } # compare the two self.assertEqual(SystemPurposeData.to_structure(system_purpose_data), expected_dict)
def test_system_purpose_task_already_set(self, give_the_system_purpose, check_set): """Test the SystemPurposeConfigurationTask task - already set.""" # The task should still run give_the_system_purpose() even if system purpose # has already been set to make it possible to overwrite or clear existing data. check_set.return_value = True # prepare some system purpose data system_purpose_data = SystemPurposeData() system_purpose_data.role = "foo" system_purpose_data.sla = "bar" system_purpose_data.usage = "baz" system_purpose_data.addons = ["a", "b", "c"] task = SystemPurposeConfigurationTask(system_purpose_data) task.run() give_the_system_purpose.assert_called_once_with(sysroot="/", role="foo", sla="bar", usage="baz", addons=["a", "b", "c"])
def process_kickstart(self, data): """Process the kickstart data.""" log.debug("Processing kickstart data...") # system purpose # # Try if any of the values in kickstart match a valid field. # If it does, write the valid field value instead of the value from kickstart. # # This way a value in kickstart that has a different case and/or trailing white space # can still be used to preselect a value in a UI instead of being marked as a custom # user specified value. system_purpose_data = SystemPurposeData() system_purpose_data.role = system_purpose.process_field( data.syspurpose.role, self.valid_roles, "role" ) system_purpose_data.sla = system_purpose.process_field( data.syspurpose.sla, self.valid_slas, "sla" ) system_purpose_data.usage = system_purpose.process_field( data.syspurpose.usage, self.valid_usage_types, "usage" ) if data.syspurpose.addons: # As we do not have a list of valid addons available, we just use what was provided # by the user in kickstart verbatim. system_purpose_data.addons = data.syspurpose.addons self.set_system_purpose_data(system_purpose_data)
def process_kickstart(self, data): """Process the kickstart data.""" log.debug("Processing kickstart data...") # system purpose # # Try if any of the values in kickstart match a valid field. # If it does, write the valid field value instead of the value from kickstart. # # This way a value in kickstart that has a different case and/or trailing white space # can still be used to preselect a value in a UI instead of being marked as a custom # user specified value. system_purpose_data = SystemPurposeData() system_purpose_data.role = system_purpose.process_field( data.syspurpose.role, self.valid_roles, "role") system_purpose_data.sla = system_purpose.process_field( data.syspurpose.sla, self.valid_slas, "sla") system_purpose_data.usage = system_purpose.process_field( data.syspurpose.usage, self.valid_usage_types, "usage") if data.syspurpose.addons: # As we do not have a list of valid addons available, we just use what was provided # by the user in kickstart verbatim. system_purpose_data.addons = data.syspurpose.addons self.set_system_purpose_data(system_purpose_data) # apply system purpose data, if any, so that it is all in place when we start # talking to the RHSM service if self.system_purpose_data.check_data_available(): self._apply_syspurpose() # subscription request subscription_request = SubscriptionRequest() # credentials if data.rhsm.organization: subscription_request.organization = data.rhsm.organization if data.rhsm.activation_keys: subscription_request.activation_keys.set_secret( data.rhsm.activation_keys) # if org id and at least one activation key is set, switch authentication # type to ORG & KEY if data.rhsm.organization and data.rhsm.activation_keys: subscription_request.type = SUBSCRIPTION_REQUEST_TYPE_ORG_KEY # custom URLs if data.rhsm.server_hostname: subscription_request.server_hostname = data.rhsm.server_hostname if data.rhsm.rhsm_baseurl: subscription_request.rhsm_baseurl = data.rhsm.rhsm_baseurl # HTTP proxy if data.rhsm.proxy: # first try to parse the proxy string from kickstart try: proxy = ProxyString(data.rhsm.proxy) if proxy.host: # ensure port is an integer and set to -1 if unknown port = int(proxy.port) if proxy.port else -1 subscription_request.server_proxy_hostname = proxy.host subscription_request.server_proxy_port = port # ensure no username translates to the expected "" # instead of the None returned by the ProxyString class subscription_request.server_proxy_user = proxy.username or "" subscription_request.server_proxy_password.set_secret( proxy.password) except ProxyStringError as e: # should not be fatal, but definitely logged as error message = "Failed to parse proxy for the rhsm command: {}".format( str(e)) warnings.warn(message, KickstartParseWarning) # set the resulting subscription request self.set_subscription_request(subscription_request) # insights self.set_connect_to_insights(bool(data.rhsm.connect_to_insights))
def _get_system_purpose_data(self): """Get SystemPurposeData from the Subscription module.""" struct = self._subscription_module.SystemPurposeData return SystemPurposeData.from_structure(struct)
def SystemPurposeData(self) -> Structure: """Return DBus structure holding current system purpose data.""" return SystemPurposeData.to_structure( self.implementation.system_purpose_data)