def get_routing_constraints(self, service_namespace_config): """ Returns a set of constraints in order to evenly group a marathon application amongst instances of a discovery type. If, for example, a given app's 'discover' key is set to 'region', then this function computes the constraints required to group the app evenly amongst each of the actual 'region' values in the cluster. It does so by querying the value of the region attribute for each slave in the cluster, returning a GROUP_BY constraint where the value is the number of unique regions. :param service_namespace_config: the config for this service :returns: a set of constraints for marathon """ discover_level = service_namespace_config.get_discover() slaves = get_slaves() if not slaves: raise NoSlavesAvailableError( "No slaves could be found in the cluster." ) filtered_slaves = filter_mesos_slaves_by_blacklist( slaves=slaves, blacklist=self.get_deploy_blacklist(), whitelist=self.get_deploy_whitelist(), ) if not filtered_slaves: raise NoSlavesAvailableError( ("No suitable slaves could be found in the cluster for %s.%s" "There are %d total slaves in the cluster, but after filtering" " those available to the app according to the constraints set" " by the deploy_blacklist and deploy_whitelist, there are 0" " available.") % (self.service, self.instance, len(slaves)) ) value_dict = get_mesos_slaves_grouped_by_attribute( filtered_slaves, discover_level ) routing_constraints = [[discover_level, "GROUP_BY", str(len(value_dict.keys()))]] return routing_constraints
def get_routing_constraints(self, service_namespace_config, system_paasta_config): """ Returns a set of constraints in order to evenly group a marathon application amongst instances of a discovery type. If, for example, a given app's 'discover' key is set to 'region', then this function computes the constraints required to group the app evenly amongst each of the actual 'region' values in the cluster. It does so by querying the value of the discover attribute for each expected slave in the cluster (as defined by the expected_slave_attributes key in system paasta config), returning a GROUP_BY constraint where the value is the number of unique values for that attribute. If you have not set expected_slave_attributes in the system paasta config, this function returns an empty list. :param service_namespace_config: the config for this service :returns: a set of constraints for marathon """ discover_level = service_namespace_config.get_discover() expected_slave_attributes = system_paasta_config.get_expected_slave_attributes( ) if expected_slave_attributes is None: return [] fake_slaves = [{"attributes": a} for a in expected_slave_attributes] filtered_slaves = filter_mesos_slaves_by_blacklist( slaves=fake_slaves, blacklist=self.get_deploy_blacklist( system_deploy_blacklist=system_paasta_config. get_deploy_blacklist(), ), whitelist=self.get_deploy_whitelist( system_deploy_whitelist=system_paasta_config. get_deploy_whitelist(), ), ) if not filtered_slaves: raise NoSlavesAvailableError(( "We do not believe any slaves on the cluster will match the constraints for %s.%s. If you believe " "this is incorrect, have your system administrator adjust the value of expected_slave_attributes " "in the system paasta configs.") % (self.service, self.instance), ) value_dict = get_mesos_slaves_grouped_by_attribute( filtered_slaves, discover_level, ) routing_constraints = [[ discover_level, "GROUP_BY", str(len(value_dict.keys())) ]] return routing_constraints
def test_get_desired_marathon_configs_handles_no_slaves(): with mock.patch( 'paasta_tools.list_marathon_service_instances.get_services_for_cluster', autospec=True, ), mock.patch( 'paasta_tools.list_marathon_service_instances.load_marathon_service_config', autospec=True, ), mock.patch( 'paasta_tools.list_marathon_service_instances.load_system_paasta_config', autospec=True, ) as mock_load_marathon_service_config: mock_load_marathon_service_config.return_value = mock.MagicMock( format_marathon_app_dict=mock.MagicMock( side_effect=NoSlavesAvailableError()), ) assert list_marathon_service_instances.get_desired_marathon_configs( '/fake/soadir/', ) == ({}, {})