diff --git a/gui/system/forms.py b/gui/system/forms.py index dd04c7fbd363..323aa6a4681e 100644 --- a/gui/system/forms.py +++ b/gui/system/forms.py @@ -3636,7 +3636,12 @@ def clean_backup_password2(self): return pwd2 -class SupportForm(ModelForm): +class SupportForm(ModelForm, MiddlewareModelForm): + + middleware_attr_prefix = "" + middleware_attr_schema = "support" + middleware_plugin = "support" + is_singletone = True class Meta: model = models.Support diff --git a/src/middlewared/middlewared/plugins/alert.py b/src/middlewared/middlewared/plugins/alert.py index 5d2284433cab..70e77b2e48e6 100644 --- a/src/middlewared/middlewared/plugins/alert.py +++ b/src/middlewared/middlewared/plugins/alert.py @@ -5,9 +5,6 @@ import os import traceback -from freenasUI.support.utils import get_license -from licenselib.license import ContractType - from middlewared.alert.base import ( AlertLevel, Alert, @@ -237,50 +234,31 @@ async def send_alerts(self, job): if not await self.middleware.call("system.is_freenas"): new_hardware_alerts = [alert for alert in new_alerts if ALERT_SOURCES[alert.source].hardware] if new_hardware_alerts: - license = get_license() - if license and license.contract_type in [ContractType.silver.value, ContractType.gold.value]: + if await self.middleware.call("support.is_available_and_enabled"): + support = await self.middleware.call("support.config") + msg = [f"* {alert.formatted}" for alert in new_hardware_alerts] + + serial = (await self.middleware.call("system.info"))["system_serial"] + + for name, verbose_name in await self.middleware.call("support.fields"): + value = support[name] + if value: + msg += ["", "{}: {}".format(verbose_name, value)] + try: - support = await self.middleware.call("datastore.query", "system.support", None, - {"get": True}) - except IndexError: - await self.middleware.call("datastore.insert", "system.support", {}) - - support = await self.middleware.call("datastore.query", "system.support", None, - {"get": True}) - - if support["enabled"]: - msg = [f"* {alert.formatted}" for alert in new_hardware_alerts] - - serial = (await self.middleware.call("system.info"))["system_serial"] - - for name, verbose_name in ( - ("name", "Contact Name"), - ("title", "Contact Title"), - ("email", "Contact E-mail"), - ("phone", "Contact Phone"), - ("secondary_name", "Secondary Contact Name"), - ("secondary_title", "Secondary Contact Title"), - ("secondary_email", "Secondary Contact E-mail"), - ("secondary_phone", "Secondary Contact Phone"), - ): - value = getattr(support, name) - if value: - msg += ["", "{}: {}".format(verbose_name, value)] - - try: - await self.middleware.call("support.new_ticket", { - "title": "Automatic alert (%s)" % serial, - "body": "\n".join(msg), - "attach_debug": False, - "category": "Hardware", - "criticality": "Loss of Functionality", - "environment": "Production", - "name": "Automatic Alert", - "email": "auto-support@ixsystems.com", - "phone": "-", - }) - except Exception: - self.logger.error(f"Failed to create a support ticket", exc_info=True) + await self.middleware.call("support.new_ticket", { + "title": "Automatic alert (%s)" % serial, + "body": "\n".join(msg), + "attach_debug": False, + "category": "Hardware", + "criticality": "Loss of Functionality", + "environment": "Production", + "name": "Automatic Alert", + "email": "auto-support@ixsystems.com", + "phone": "-", + }) + except Exception: + self.logger.error(f"Failed to create a support ticket", exc_info=True) async def __run_alerts(self): master_node = "A" diff --git a/src/middlewared/middlewared/plugins/support.py b/src/middlewared/middlewared/plugins/support.py index 4cf86a776ca1..3012482923c5 100644 --- a/src/middlewared/middlewared/plugins/support.py +++ b/src/middlewared/middlewared/plugins/support.py @@ -10,7 +10,7 @@ from middlewared.pipe import Pipes from middlewared.schema import Bool, Dict, Int, Str, accepts -from middlewared.service import CallError, Service, job +from middlewared.service import CallError, ConfigService, job, ValidationErrors from middlewared.utils import Popen # FIXME: Remove when we can generate debug and move license to middleware @@ -28,7 +28,90 @@ ADDRESS = 'support-proxy.ixsystems.com' -class SupportService(Service): +class SupportService(ConfigService): + + class Config: + datastore = 'system.support' + + @accepts(Dict( + 'support_update', + Bool('enabled', null=True), + Str('name'), + Str('title'), + Str('email'), + Str('phone'), + Str('secondary_name'), + Str('secondary_title'), + Str('secondary_email'), + Str('secondary_phone'), + update=True + )) + async def do_update(self, data): + """ + Update Proactive Support settings. + """ + + config_data = await self.config() + config_data.update(data) + + verrors = ValidationErrors() + if config_data['enabled']: + for key in ['name', 'title', 'email', 'phone']: + for prefix in ['', 'secondary_']: + field = prefix + key + if not config_data[field]: + verrors.add(f'support_update.{field}', 'This field is required') + if verrors: + raise verrors + + await self.middleware.call( + 'datastore.update', + self._config.datastore, + config_data['id'], + config_data, + ) + + return await self.config() + + @accepts() + async def is_available(self): + """ + Returns whether Proactive Support is available for this product type and current license. + """ + + if await self.middleware.call('system.is_freenas'): + return False + + license = (await self.middleware.call('system.info'))['license'] + if license is None: + return False + + return license['contract_type'] in ['SILVER', 'GOLD'] + + @accepts() + async def is_available_and_enabled(self): + """ + Returns whether Proactive Support is available and enabled. + """ + + return await self.is_available() and (await self.config())['enabled'] + + @accepts() + async def fields(self): + """ + Returns list of pairs of field names and field titles for Proactive Support. + """ + + return ( + ("name", "Contact Name"), + ("title", "Contact Title"), + ("email", "Contact E-mail"), + ("phone", "Contact Phone"), + ("secondary_name", "Secondary Contact Name"), + ("secondary_title", "Secondary Contact Title"), + ("secondary_email", "Secondary Contact E-mail"), + ("secondary_phone", "Secondary Contact Phone"), + ) @accepts( Str('username'),