Example #1
0
def index(request):
    sw_name = get_sw_name().lower()

    license, reason = utils.get_license()
    allow_update = True
    if hasattr(notifier, 'failover_status'):
        status = notifier().failover_status()
        if status not in ('MASTER', 'SINGLE'):
            allow_update = False

    context = {
        'sw_name': sw_name,
        'license': license,
        'fc_enabled': utils.fc_enabled(),
        'allow_update': allow_update,
    }
    for c in appPool.hook_view_context('support.index', request):
        context.update(c)

    if not notifier().is_freenas():
        form = forms.ProductionForm()
        if request.method == 'POST':
            form = forms.ProductionForm(request.POST)
            if form.is_valid():
                form.save()
                return JsonResp(
                    request,
                    message='Production status successfully updated.'
                )

        context['production_form'] = form

    return render(request, 'support/home.html', context)
Example #2
0
    def is_available(cls, support=None):
        """
        Checks whether the Proactive Support tab should be shown.
        It should only be for TrueNAS and Siver/Gold Customers.

        Returns:
            tuple(bool, Support instance)
        """
        if notifier().is_freenas():
            return False, support
        if support is None:
            try:
                support = cls.objects.order_by('-id')[0]
            except IndexError:
                support = cls.objects.create()

        license, error = get_license()
        if license is None:
            return False, support
        if license.contract_type in (
                ContractType.silver,
                ContractType.gold,
        ):
            return True, support
        return False, support
Example #3
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == 'POST':
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, 'wb+') as f:
                f.write(form.cleaned_data.get('license').encode('ascii'))
            try:
                _n = notifier()
                if hasattr(_n, 'failover_getpeer'):
                    ip, secret = _n.failover_getpeer()
                    if ip:
                        s = _n.failover_rpc(ip=ip)
                        _n.sync_file_send(s, secret, utils.LICENSE_FILE)
            except Exception as e:
                log.debug("Failed to sync license file: %s", e)
            return JsonResp(request, message=_('License updated.'))
        else:
            return JsonResp(request, form=form)
    else:
        form = forms.LicenseUpdateForm()
    return render(request, 'support/license_update.html', {
        'form': form,
        'license': license,
    })
Example #4
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == 'POST':
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, 'wb+') as f:
                f.write(form.cleaned_data.get('license').encode('ascii'))
            events = []
            try:
                _n = notifier()
                if not _n.is_freenas():
                    s = _n.failover_rpc()
                    if s is not None:
                        _n.sync_file_send(s, utils.LICENSE_FILE)
                form.done(request, events)
            except Exception as e:
                log.debug("Failed to sync license file: %s", e, exc_info=True)
            return JsonResp(request,
                            events=events,
                            message=_('License updated.'))
        else:
            return JsonResp(request, form=form)
    else:
        form = forms.LicenseUpdateForm()
    return render(request, 'support/license_update.html', {
        'form': form,
        'license': license,
    })
Example #5
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == 'POST':
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, 'wb+') as f:
                f.write(form.cleaned_data.get('license').encode('ascii'))
            try:
                _n = notifier()
                if hasattr(_n, 'failover_getpeer'):
                    ip, secret = _n.failover_getpeer()
                    if ip:
                        s = _n.failover_rpc(ip=ip)
                        _n.sync_file_send(s, secret, utils.LICENSE_FILE)
            except Exception as e:
                log.debug("Failed to sync license file: %s", e)
            return JsonResp(request, message=_('License updated.'))
        else:
            return JsonResp(request, form=form)
    else:
        form = forms.LicenseUpdateForm()
    return render(request, 'support/license_update.html', {
        'form': form,
        'license': license,
    })
Example #6
0
    def is_available(cls, support=None):
        """
        Checks whether the Proactive Support tab should be shown.
        It should only be for TrueNAS and Siver/Gold Customers.

        Returns:
            tuple(bool, Support instance)
        """
        if notifier().is_freenas():
            return False, support
        if support is None:
            try:
                support = cls.objects.order_by('-id')[0]
            except IndexError:
                support = cls.objects.create()

        license, error = get_license()
        if license is None:
            return False, support
        if license.contract_type in (
            ContractType.silver,
            ContractType.gold,
        ):
            return True, support
        return False, support
Example #7
0
    async def info(self):
        """
        Returns basic system information.
        """
        uptime = (await (await Popen(
            "env -u TZ uptime | awk -F', load averages:' '{ print $1 }'",
            stdout=subprocess.PIPE,
            shell=True,
        )).communicate())[0].decode().strip()

        serial = (await (await Popen(
            ['dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE,
        )).communicate())[0].decode().strip() or None

        product = (await (await Popen(
            ['dmidecode', '-s', 'system-product-name'],
            stdout=subprocess.PIPE,
        )).communicate())[0].decode().strip() or None

        license = get_license()[0]
        if license:
            license = {
                "contract_type":
                ContractType(license.contract_type).name.upper(),
                "contract_end": license.contract_end,
            }

        return {
            'version':
            self.version(),
            'hostname':
            socket.gethostname(),
            'physmem':
            sysctl.filter('hw.physmem')[0].value,
            'model':
            sysctl.filter('hw.model')[0].value,
            'cores':
            sysctl.filter('hw.ncpu')[0].value,
            'loadavg':
            os.getloadavg(),
            'uptime':
            uptime,
            'system_serial':
            serial,
            'system_product':
            product,
            'license':
            license,
            'boottime':
            datetime.fromtimestamp(
                struct.unpack('l',
                              sysctl.filter('kern.boottime')[0].value[:8])[0]),
            'datetime':
            datetime.utcnow(),
            'timezone':
            (await self.middleware.call('datastore.config',
                                        'system.settings'))['stg_timezone'],
        }
Example #8
0
    def ticket(self, support, alerts):
        node = alert_node()
        dismisseds = [a.message_id for a in mAlert.objects.filter(node=node)]
        msgs = []
        for alert in alerts:
            if alert.getId() not in dismisseds:
                msgs.append(str(alert))
        if len(msgs) == 0:
            return

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE,
            encoding='utf8',
        ).communicate()[0].split('\n')[0].upper()

        license, reason = get_license()
        if license:
            company = license.customer_name.decode()
        else:
            company = 'Unknown'

        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:
                msgs += ['', '{}: {}'.format(verbose_name, value)]

        with client as c:
            try:
                rv = c.call('support.new_ticket', {
                    'title': 'Automatic alert (%s)' % serial,
                    'body': '\n'.join(msgs),
                    'version': get_sw_version().split('-', 1)[-1],
                    'debug': False,
                    'company': company,
                    'serial': serial,
                    'department': 20,
                    'category': 'Hardware',
                    'criticality': 'Loss of Functionality',
                    'environment': 'Production',
                    'name': 'Automatic Alert',
                    'email': '*****@*****.**',
                    'phone': '-',
                },
                            job=True)
                log.debug(
                    f'Automatic alert ticket successfully created: {rv["url"]}'
                )
            except ClientException as e:
                log.error(f'Failed to create a support ticket: {e.error}')
Example #9
0
def license_status(request):

    sw_name = get_sw_name().lower()
    license, reason = utils.get_license()
    if (license is None and sw_name != 'freenas') or license.expired:
        return HttpResponse('PROMPT')

    return HttpResponse('OK')
Example #10
0
def license_status(request):

    sw_name = get_sw_name().lower()
    license, reason = utils.get_license()
    if (license is None and sw_name != "freenas") or license.expired:
        return HttpResponse("PROMPT")

    return HttpResponse("OK")
Example #11
0
def license_status(request):

    sw_name = get_sw_name().lower()
    license, reason = utils.get_license()
    if (license is None and sw_name != 'freenas') or license.expired:
        return HttpResponse('PROMPT')

    return HttpResponse('OK')
Example #12
0
def license_status(request):

    sw_name = get_sw_name().lower()
    license = utils.get_license()[0]
    if (license is None and sw_name != 'freenas') or (license is not None
                                                      and license['expired']):
        return HttpResponse('PROMPT')

    return HttpResponse('OK')
Example #13
0
    def ticket(self, support, alerts):
        node = alert_node()
        dismisseds = [a.message_id for a in mAlert.objects.filter(node=node)]
        msgs = []
        for alert in alerts:
            if alert.getId() not in dismisseds:
                msgs.append(str(alert))
        if len(msgs) == 0:
            return

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE,
            encoding='utf8',
        ).communicate()[0].split('\n')[0].upper()

        license, reason = get_license()
        if license:
            company = license.customer_name.decode()
        else:
            company = 'Unknown'

        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:
                msgs += ['', '{}: {}'.format(verbose_name, value)]

        with client as c:
            try:
                rv = c.call('support.new_ticket', {
                    'title': 'Automatic alert (%s)' % serial,
                    'body': '\n'.join(msgs),
                    'version': get_sw_version().split('-', 1)[-1],
                    'debug': False,
                    'company': company,
                    'serial': serial,
                    'department': 20,
                    'category': 'Hardware',
                    'criticality': 'Loss of Functionality',
                    'environment': 'Production',
                    'name': 'Automatic Alert',
                    'email': '*****@*****.**',
                    'phone': '-',
                }, job=True)
                log.debug(f'Automatic alert ticket successfully created: {rv["url"]}')
            except ClientException as e:
                log.error(f'Failed to create a support ticket: {e.error}')
Example #14
0
    def ticket(self, alerts):
        node = alert_node()
        dismisseds = [
            a.message_id
            for a in mAlert.objects.filter(dismiss=True, node=node)
        ]
        msgs = []
        for alert in alerts:
            if alert.getId() not in dismisseds:
                msgs.append(unicode(alert).encode('utf8'))
        if len(msgs) == 0:
            return

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE).communicate()[0].split('\n')[0].upper()

        license, reason = get_license()
        if license:
            company = license.customer_name
        else:
            company = 'Unknown'

        success, msg, ticketnum = new_ticket({
            'title':
            'Automatic alert (%s)' % serial,
            'body':
            '\n'.join(msgs),
            'version':
            get_sw_version().split('-', 1)[-1],
            'debug':
            False,
            'company':
            company,
            'serial':
            serial,
            'department':
            20,
            'category':
            'Hardware',
            'criticality':
            'Loss of Functionality',
            'environment':
            'Production',
            'name':
            'Automatic Alert',
            'email':
            '*****@*****.**',
            'phone':
            '-',
        })
        if not success:
            log.error("Failed to create a support ticket: %s", msg)
        else:
            log.debug("Automatic alert ticket successfully created: %s", msg)
Example #15
0
def index(request):
    sw_name = get_sw_name().lower()

    license, reason = utils.get_license()
    allow_update = True
    if hasattr(notifier, "failover_status"):
        status = notifier().failover_status()
        if status not in ("MASTER", "SINGLE"):
            allow_update = False

    context = {"sw_name": sw_name, "license": license, "allow_update": allow_update}
    for c in appPool.hook_view_context("support.index", request):
        context.update(c)

    return render(request, "support/home.html", context)
Example #16
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == 'POST':
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, 'wb+') as f:
                f.write(form.cleaned_data.get('license').encode('ascii'))
            with client as c:
                c.call('etc.generate', 'rc')
            events = []
            try:
                _n = notifier()
                if not _n.is_freenas():
                    with client as c:
                        _n.sync_file_send(c, utils.LICENSE_FILE)
                        c.call('failover.call_remote', 'etc.generate', ['rc'])
                form.done(request, events)
            except Exception as e:
                log.debug("Failed to sync license file: %s", e, exc_info=True)
            return JsonResp(request,
                            events=events,
                            message=_('License updated.'))
        else:
            return JsonResp(request, form=form)
    else:
        _n = notifier()
        try:
            if not _n.is_freenas() and _n.failover_licensed():
                with client as c:
                    c.call('failover.call_remote', 'core.ping')
        except ClientException:
            return render(request, 'failover/failover_down.html')
        form = forms.LicenseUpdateForm()

    eula = None
    if not notifier().is_freenas():
        if os.path.exists('/usr/local/share/truenas/eula.html'):
            with open('/usr/local/share/truenas/eula.html',
                      'r',
                      encoding='utf8') as f:
                eula = f.read()

    return render(request, 'support/license_update.html', {
        'eula': eula,
        'form': form,
        'license': license,
    })
Example #17
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == 'POST':
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, 'wb+') as f:
                f.write(form.cleaned_data.get('license').encode('ascii'))
            return JsonResp(request, message=_('License updated.'))
        else:
            return JsonResp(request, form=form)
    else:
        form = forms.LicenseUpdateForm()
    return render(request, 'support/license_update.html', {
        'form': form,
        'license': license,
    })
Example #18
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == 'POST':
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, 'wb+') as f:
                f.write(form.cleaned_data.get('license').encode('ascii'))
            events = []
            try:
                _n = notifier()
                if not _n.is_freenas():
                    s = _n.failover_rpc()
                    if s is not None:
                        _n.sync_file_send(s, utils.LICENSE_FILE)
                form.done(request, events)
            except Exception as e:
                log.debug("Failed to sync license file: %s", e, exc_info=True)
            return JsonResp(
                request,
                events=events,
                message=_('License updated.')
            )
        else:
            return JsonResp(request, form=form)
    else:
        _n = notifier()
        try:
            if not _n.is_freenas() and _n.failover_licensed():
                s = _n.failover_rpc()
                s.ping()
        except socket.error:
            return render(request, 'failover/failover_down.html')
        form = forms.LicenseUpdateForm()

    eula = None
    if not notifier().is_freenas():
        if os.path.exists('/usr/local/share/truenas/eula'):
            with open('/usr/local/share/truenas/eula', 'r') as f:
                eula = f.read().decode('utf8')

    return render(request, 'support/license_update.html', {
        'eula': eula,
        'form': form,
        'license': license,
    })
Example #19
0
def index(request):
    sw_name = get_sw_name().lower()

    license, reason = utils.get_license()
    allow_update = True
    if hasattr(notifier, 'failover_status'):
        status = notifier().failover_status()
        if status not in ('MASTER', 'SINGLE'):
            allow_update = False

    context = {
        'sw_name': sw_name,
        'license': license,
        'allow_update': allow_update,
    }
    for c in appPool.hook_view_context('support.index', request):
        context.update(c)

    return render(request, 'support/home.html', context)
Example #20
0
def index(request):
    sw_name = get_sw_name().lower()

    license, reason = utils.get_license()
    allow_update = True
    if hasattr(notifier, 'failover_status'):
        status = notifier().failover_status()
        if status not in ('MASTER', 'SINGLE'):
            allow_update = False

    context = {
        'sw_name': sw_name,
        'license': license,
        'allow_update': allow_update,
    }
    for c in appPool.hook_view_context('support.index', request):
        context.update(c)

    return render(request, 'support/home.html', context)
Example #21
0
def index(request):
    if request.method == 'POST':
        if request.POST.get('eula') == 'unaccept':
            request.session.pop('noeula', None)
            with client as c:
                c.call('truenas.unaccept_eula')
            return HttpResponseRedirect('/')

    sw_name = get_sw_name().lower()

    license = utils.get_license()[0]
    allow_update = True
    if hasattr(notifier, 'failover_status'):
        status = notifier().failover_status()
        if status not in ('MASTER', 'SINGLE'):
            allow_update = False

    context = {
        'sw_name': sw_name,
        'license': license,
        'fc_enabled': utils.fc_enabled(),
        'allow_update': allow_update,
    }
    for c in appPool.hook_view_context('support.index', request):
        context.update(c)
    if not notifier().is_freenas():
        with client as c:
            context['eula_not_accepted'] = not c.call('truenas.is_eula_accepted')

    if not notifier().is_freenas():
        form = forms.ProductionForm()
        if request.method == 'POST':
            form = forms.ProductionForm(request.POST)
            if form.is_valid():
                form.save()
                return JsonResp(
                    request,
                    message='Production status successfully updated.'
                )

        context['production_form'] = form

    return render(request, 'support/home.html', context)
Example #22
0
    def ticket(self, alerts):
        node = alert_node()
        dismisseds = [a.message_id
                      for a in mAlert.objects.filter(dismiss=True, node=node)]
        msgs = []
        for alert in alerts:
            if alert.getId() not in dismisseds:
                msgs.append(unicode(alert).encode('utf8'))
        if len(msgs) == 0:
            return

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE
        ).communicate()[0].split('\n')[0].upper()

        license, reason = get_license()
        if license:
            company = license.customer_name
        else:
            company = 'Unknown'

        success, msg, ticketnum = new_ticket({
            'title': 'Automatic alert (%s)' % serial,
            'body': '\n'.join(msgs),
            'version': get_sw_version().split('-', 1)[-1],
            'debug': False,
            'company': company,
            'serial': serial,
            'department': 20,
            'category': 'Hardware',
            'criticality': 'Loss of Functionality',
            'environment': 'Production',
            'name': 'Automatic Alert',
            'email': '*****@*****.**',
            'phone': '-',
        })
        if not success:
            log.error("Failed to create a support ticket: %s", msg)
        else:
            log.debug("Automatic alert ticket successfully created: %s", msg)
Example #23
0
def license_update(request):

    license = utils.get_license()[0]
    if request.method == 'POST':
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with client as c:
                try:
                    c.call('system.license_update', form.cleaned_data.get('license'))
                except Exception as e:
                    form._errors['__all__'] = form.error_class([str(e)])
                    return JsonResp(request, form=form)

            return JsonResp(
                request,
                message=_('License updated.')
            )
        else:
            return JsonResp(request, form=form)
    else:
        _n = notifier()
        try:
            if not _n.is_freenas() and _n.failover_licensed():
                with client as c:
                    c.call('failover.call_remote', 'core.ping')
        except ClientException:
            return render(request, 'failover/failover_down.html')
        form = forms.LicenseUpdateForm()

    eula = None
    if not notifier().is_freenas():
        if os.path.exists('/usr/local/share/truenas/eula.html'):
            with open('/usr/local/share/truenas/eula.html', 'r', encoding='utf8') as f:
                eula = f.read()

    return render(request, 'support/license_update.html', {
        'eula': eula,
        'form': form,
        'license': license,
    })
Example #24
0
 async def __get_license(self):
     licenseobj = get_license()[0]
     if not licenseobj:
         return
     license = {
         "system_serial": licenseobj.system_serial,
         "system_serial_ha": licenseobj.system_serial_ha,
         "contract_type":
         ContractType(licenseobj.contract_type).name.upper(),
         "contract_end": licenseobj.contract_end,
         "features": [],
     }
     for feature in licenseobj.features:
         license["features"].append(feature.name.upper())
     # Licenses issued before 2017-04-14 had a bug in the feature bit
     # for fibre channel, which means they were issued having
     # dedup+jails instead.
     if (licenseobj.contract_start < date(2017, 4, 14)
             and Features.dedup in licenseobj.features
             and Features.jails in licenseobj.features):
         license["features"].append(Features.fibrechannel.name.upper())
     return license
Example #25
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == "POST":
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, "wb+") as f:
                f.write(form.cleaned_data.get("license").encode("ascii"))
            events = []
            try:
                _n = notifier()
                if not _n.is_freenas():
                    s = _n.failover_rpc()
                    if s is not None:
                        _n.sync_file_send(s, utils.LICENSE_FILE)
                form.done(request, events)
            except Exception as e:
                log.debug("Failed to sync license file: %s", e, exc_info=True)
            return JsonResp(request, events=events, message=_("License updated."))
        else:
            return JsonResp(request, form=form)
    else:
        _n = notifier()
        try:
            if not _n.is_freenas() and _n.failover_licensed():
                s = _n.failover_rpc()
                s.ping()
        except socket.error:
            return render(request, "failover/failover_down.html")
        form = forms.LicenseUpdateForm()

    eula = None
    if not notifier().is_freenas():
        if os.path.exists("/usr/local/share/truenas/eula"):
            with open("/usr/local/share/truenas/eula", "r") as f:
                eula = f.read().decode("utf8")

    return render(request, "support/license_update.html", {"eula": eula, "form": form, "license": license})
Example #26
0
 async def __get_license(self):
     licenseobj = get_license()[0]
     if not licenseobj:
         return
     license = {
         "system_serial": licenseobj.system_serial,
         "system_serial_ha": licenseobj.system_serial_ha,
         "contract_type": ContractType(licenseobj.contract_type).name.upper(),
         "contract_end": licenseobj.contract_end,
         "features": [],
     }
     for feature in licenseobj.features:
         license["features"].append(feature.name.upper())
     # Licenses issued before 2017-04-14 had a bug in the feature bit
     # for fibre channel, which means they were issued having
     # dedup+jails instead.
     if (
         licenseobj.contract_start < date(2017, 4, 14) and
         Features.dedup in licenseobj.features and
         Features.jails in licenseobj.features
     ):
         license["features"].append(Features.fibrechannel.name.upper())
     return license
Example #27
0
def license_update(request):

    license, reason = utils.get_license()
    if request.method == "POST":
        form = forms.LicenseUpdateForm(request.POST)
        if form.is_valid():
            with open(utils.LICENSE_FILE, "wb+") as f:
                f.write(form.cleaned_data.get("license").encode("ascii"))
            events = []
            try:
                _n = notifier()
                if not _n.is_freenas():
                    s = _n.failover_rpc()
                    if s is not None:
                        _n.sync_file_send(s, utils.LICENSE_FILE)
                form.done(request, events)
            except Exception as e:
                log.debug("Failed to sync license file: %s", e, exc_info=True)
            return JsonResp(request, events=events, message=_("License updated."))
        else:
            return JsonResp(request, form=form)
    else:
        form = forms.LicenseUpdateForm()
    return render(request, "support/license_update.html", {"form": form, "license": license})
Example #28
0
    def hook_app_tabs_system(self, request):
        from freenasUI.freeadmin.sqlite3_ha.base import NO_SYNC_MAP
        from freenasUI.middleware.notifier import notifier
        from freenasUI.system import models
        from freenasUI.support.utils import get_license
        tabmodels = [
            models.Settings,
            models.Advanced,
            models.Email,
            models.SystemDataset,
            models.Tunable,
            models.CloudCredentials,
            models.AlertDefaultSettings,
            models.AlertService,
            models.CertificateAuthority,
            models.Certificate,
        ]

        tabs = []
        if (
            hasattr(notifier, 'failover_status') and
            notifier().failover_status() == 'BACKUP'
        ):
            backup = True
        else:
            backup = False
        tabs.append({
            'name': 'SysInfo',
            'focus': 'system.SysInfo',
            'verbose_name': _('Information'),
            'url': reverse('system_info'),
        })

        for model in tabmodels:
            if backup and model._meta.db_table not in NO_SYNC_MAP:
                continue
            # System Dataset has only one hidden field
            if backup and model._meta.db_table == 'system_systemdataset':
                continue
            if model._admin.deletable is False:
                try:
                    obj = model.objects.order_by('-id')[0]
                except IndexError:
                    obj = model.objects.create()
                url = obj.get_edit_url() + '?inline=true'
                verbose_name = model._meta.verbose_name
                focus = 'system.%s' % model._meta.object_name
            else:
                url = reverse('freeadmin_%s_%s_datagrid' % (
                    model._meta.app_label,
                    model._meta.model_name,
                ))
                verbose_name = model._meta.verbose_name_plural
                focus = 'system.%s.View' % model._meta.object_name
            tabs.append({
                'name': model._meta.object_name,
                'focus': focus,
                'verbose_name': verbose_name,
                'url': url,
            })

        tabs.insert(2, {
            'name': 'BootEnv',
            'focus': 'system.BootEnv',
            'verbose_name': _('Boot'),
            'url': reverse('system_bootenv_datagrid'),
        })

        tabs.insert(8, {
            'name': 'Update',
            'focus': 'system.Update',
            'verbose_name': _('Update'),
            'url': reverse('system_update_index'),
        })

        tabs.insert(13, {
            'name': 'Support',
            'focus': 'system.Support',
            'verbose_name': _('Support'),
            'url': reverse('support_home'),
        })

        license = get_license()[0]
        if license is not None and not notifier().is_freenas():
            support = models.Support.objects.order_by('-id')[0]
            tabs.insert(14, {
                'name': 'Proactive Support',
                'focus': 'system.ProactiveSupport',
                'verbose_name': _('Proactive Support'),
                'url': support.get_edit_url() + '?inline=true',
            })

            tabs.insert(15, {
                'name': 'ViewEnclosure',
                'focus': 'storage.ViewEnclosure',
                'verbose_name': _('View Enclosure'),
                'url': reverse('storage_enclosure_status'),
            })

        return tabs
Example #29
0
    async def new_ticket(self, job, data):
        """
        Creates a new ticket for support.
        This is done using the support proxy API.
        For FreeNAS it will be created on Redmine and for TrueNAS on SupportSuite.

        For FreeNAS `criticality`, `environment`, `phone`, `name` and `email` attributes are not required.
        For TrueNAS `username`, `password` and `type` attributes are not required.
        """

        job.set_progress(1, 'Gathering data')

        sw_name = 'freenas' if await self.middleware.call('system.is_freenas') else 'truenas'

        if sw_name == 'freenas':
            required_attrs = ('type', 'username', 'password')
        else:
            required_attrs = ('phone', 'name', 'email', 'criticality', 'environment')
            data['serial'] = (await (await Popen(['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'], stdout=subprocess.PIPE)).communicate())[0].decode().split('\n')[0].upper()
            license = get_license()[0]
            if license:
                data['company'] = license.customer_name
            else:
                data['company'] = 'Unknown'

        for i in required_attrs:
            if i not in data:
                raise CallError(f'{i} is required', errno.EINVAL)

        data['version'] = (await self.middleware.call('system.version')).split('-', 1)[-1]
        if 'username' in data:
            data['user'] = data.pop('username')
        debug = data.pop('attach_debug')

        type_ = data.get('type')
        if type_:
            data['type'] = type_.lower()

        job.set_progress(20, 'Submitting ticket')

        try:
            r = await self.middleware.run_in_thread(lambda: requests.post(
                f'https://{ADDRESS}/{sw_name}/api/v1.0/ticket',
                data=json.dumps(data),
                headers={'Content-Type': 'application/json'},
                timeout=10,
            ))
            result = r.json()
        except simplejson.JSONDecodeError:
            self.logger.debug(f'Failed to decode ticket attachment response: {r.text}')
            raise CallError('Invalid proxy server response', errno.EBADMSG)
        except requests.ConnectionError as e:
            raise CallError(f'Connection error {e}', errno.EBADF)
        except requests.Timeout:
            raise CallError('Connection time out', errno.ETIMEDOUT)

        if r.status_code != 200:
            self.logger.debug(f'Support Ticket failed ({r.status_code}): {r.text}', r.status_code, r.text)
            raise CallError('Ticket creation failed, try again later.', errno.EINVAL)

        if result['error']:
            raise CallError(result['message'], errno.EINVAL)

        ticket = result.get('ticketnum')
        url = result.get('message')
        if not ticket:
            raise CallError('New ticket number was not informed', errno.EINVAL)
        job.set_progress(50, f'Ticket created: {ticket}', extra={'ticket': ticket})

        if debug:
            # FIXME: generate debug from middleware
            mntpt, direc, dump = await self.middleware.run_in_thread(debug_get_settings)

            job.set_progress(60, 'Generating debug file')
            await self.middleware.run_in_thread(debug_generate)

            not_freenas = not (await self.middleware.call('system.is_freenas'))
            if not_freenas:
                not_freenas &= await self.middleware.call('notifier.failover_licensed')
            if not_freenas:
                debug_file = f'{direc}/debug.tar'
                debug_name = 'debug-{}.tar'.format(time.strftime('%Y%m%d%H%M%S'))
            else:
                debug_file = dump
                debug_name = 'debug-{}-{}.txz'.format(
                    socket.gethostname().split('.')[0],
                    time.strftime('%Y%m%d%H%M%S'),
                )

            job.set_progress(80, 'Attaching debug file')

            # 20M filesize limit
            if os.path.getsize(debug_file) > 20971520:
                raise CallError('Debug too large to attach', errno.EFBIG)

            t = {
                'ticket': ticket,
                'filename': debug_name,
            }
            if 'user' in data:
                t['username'] = data['user']
            if 'password' in data:
                t['password'] = data['password']
            tjob = await self.middleware.call('support.attach_ticket', t, pipes=Pipes(input=self.middleware.pipe()))

            with open(debug_file, 'rb') as f:
                await self.middleware.run_in_io_thread(shutil.copyfileobj, f, tjob.pipes.input.w)
                await self.middleware.run_in_io_thread(tjob.pipes.input.w.close)

            await tjob.wait()
        else:
            job.set_progress(100)

        return {
            'ticket': ticket,
            'url': url,
        }
Example #30
0
def ticket(request):

    step = 2 if request.FILES.getlist("attachment") else 1

    files = []
    if request.POST.get("debug") == "on":
        debug = True
        with open(TICKET_PROGRESS, "w") as f:
            f.write(json.dumps({"indeterminate": True, "step": step}))
        step += 1

        mntpt, direc, dump = debug_get_settings()
        debug_run(direc)
        files.append(File(open(dump, "rb"), name=os.path.basename(dump)))
    else:
        debug = False

    with open(TICKET_PROGRESS, "w") as f:
        f.write(json.dumps({"indeterminate": True, "step": step}))
    step += 1

    data = {
        "title": request.POST.get("subject"),
        "body": request.POST.get("desc"),
        "version": get_sw_version().split("-", 1)[-1],
        "category": request.POST.get("category"),
        "debug": debug,
    }

    if get_sw_name().lower() == "freenas":
        data.update(
            {
                "user": request.POST.get("username"),
                "password": request.POST.get("password"),
                "type": request.POST.get("type"),
            }
        )
    else:

        serial = (
            subprocess.Popen(["/usr/local/sbin/dmidecode", "-s", "system-serial-number"], stdout=subprocess.PIPE)
            .communicate()[0]
            .split("\n")[0]
            .upper()
        )

        license, reason = utils.get_license()
        if license:
            company = license.customer_name
        else:
            company = "Unknown"

        data.update(
            {
                "phone": request.POST.get("phone"),
                "name": request.POST.get("name"),
                "company": company,
                "email": request.POST.get("email"),
                "criticality": request.POST.get("criticality"),
                "environment": request.POST.get("environment"),
                "serial": serial,
            }
        )

    success, msg, tid = utils.new_ticket(data)

    with open(TICKET_PROGRESS, "w") as f:
        f.write(json.dumps({"indeterminate": True, "step": step}))
    step += 1

    data = {"message": msg, "error": not success}

    if not success:
        pass
    else:

        files.extend(request.FILES.getlist("attachment"))
        for f in files:
            success, attachmsg = utils.ticket_attach(
                {"user": request.POST.get("username"), "password": request.POST.get("password"), "ticketnum": tid}, f
            )

    data = "<html><body><textarea>%s</textarea></boby></html>" % (json.dumps(data),)
    return HttpResponse(data)
Example #31
0
def ticket(request):

    step = 2 if request.FILES.getlist('attachment') else 1

    files = []
    if request.POST.get('debug') == 'on':
        debug = True
        with open(TICKET_PROGRESS, 'w') as f:
            f.write(json.dumps({'indeterminate': True, 'step': step}))
        step += 1

        mntpt, direc, dump = debug_get_settings()
        debug_generate()

        _n = notifier()
        if not _n.is_freenas() and _n.failover_licensed():
            debug_file = '%s/debug.tar' % direc
            debug_name = 'debug-%s.tar' % time.strftime('%Y%m%d%H%M%S')
        else:
            gc = GlobalConfiguration.objects.all().order_by('-id')[0]
            debug_file = dump
            debug_name = 'debug-%s-%s.txz' % (
                gc.gc_hostname.encode('utf-8'),
                time.strftime('%Y%m%d%H%M%S'),
            )

        files.append(File(open(debug_file, 'rb'), name=debug_name))
    else:
        debug = False

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {
        'title': request.POST.get('subject'),
        'body': request.POST.get('desc'),
        'version': get_sw_version().split('-', 1)[-1],
        'category': request.POST.get('category'),
        'debug': debug,
    }

    if get_sw_name().lower() == 'freenas':
        data.update({
            'user': request.POST.get('username'),
            'password': request.POST.get('password'),
            'type': request.POST.get('type'),
        })
    else:

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE
        ).communicate()[0].split('\n')[0].upper()

        license, reason = utils.get_license()
        if license:
            company = license.customer_name
        else:
            company = 'Unknown'

        data.update({
            'phone': request.POST.get('phone'),
            'name': request.POST.get('name'),
            'company': company,
            'email': request.POST.get('email'),
            'criticality': request.POST.get('criticality'),
            'environment': request.POST.get('environment'),
            'serial': serial,
        })

    success, msg, tid = utils.new_ticket(data)

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {'message': msg, 'error': not success}

    if not success:
        pass
    else:

        files.extend(request.FILES.getlist('attachment'))
        for f in files:
            success, attachmsg = utils.ticket_attach({
                'user': request.POST.get('username'),
                'password': request.POST.get('password'),
                'ticketnum': tid,
            }, f)

    data = (
        '<html><body><textarea>%s</textarea></boby></html>' % (
            json.dumps(data),
        )
    )
    return HttpResponse(data)
Example #32
0
def ticket(request):

    step = 2 if request.FILES.getlist('attachment') else 1

    files = []
    if request.POST.get('debug') == 'on':
        debug = True
        with open(TICKET_PROGRESS, 'w') as f:
            f.write(json.dumps({'indeterminate': True, 'step': step}))
        step += 1

        mntpt, direc, dump = debug_get_settings()
        debug_run(direc)
        files.append(File(open(dump, 'rb'), name=os.path.basename(dump)))
    else:
        debug = False

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {
        'title': request.POST.get('subject'),
        'body': request.POST.get('desc'),
        'version': get_sw_version().split('-', 1)[-1],
        'category': request.POST.get('category'),
        'debug': debug,
    }

    if get_sw_name().lower() == 'freenas':
        data.update({
            'user': request.POST.get('username'),
            'password': request.POST.get('password'),
            'type': request.POST.get('type'),
        })
    else:

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE
        ).communicate()[0].split('\n')[0].upper()

        license, reason = utils.get_license()
        if license:
            company = license.customer_name
        else:
            company = 'Unknown'

        data.update({
            'phone': request.POST.get('phone'),
            'name': request.POST.get('name'),
            'company': company,
            'email': request.POST.get('email'),
            'criticality': request.POST.get('criticality'),
            'environment': request.POST.get('environment'),
            'serial': serial,
        })

    success, msg, tid = utils.new_ticket(data)

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {'message': msg, 'error': not success}

    if not success:
        pass
    else:

        files.extend(request.FILES.getlist('attachment'))
        for f in files:
            success, attachmsg = utils.ticket_attach({
                'user': request.POST.get('username'),
                'password': request.POST.get('password'),
                'ticketnum': tid,
            }, f)

    data = (
        '<html><body><textarea>%s</textarea></boby></html>' % (
            json.dumps(data),
        )
    )
    return HttpResponse(data)
Example #33
0
    async def process_alerts(self, job):
        if not await self.middleware.call("system.ready"):
            return

        if (not await self.middleware.call('system.is_freenas')
                and await self.middleware.call('notifier.failover_licensed')
                and await self.middleware.call('notifier.failover_status')
                == 'BACKUP'):
            return

        await self.__run_alerts()

        default_settings = (
            await
            self.middleware.call("alertdefaultsettings.config"))["settings"]

        all_alerts = self.__get_all_alerts()

        now = datetime.now()
        for policy_name, policy in self.policies.items():
            gone_alerts, new_alerts = policy.receive_alerts(now, self.alerts)

            for alert_service_desc in await self.middleware.call(
                    "datastore.query", "system.alertservice"):
                service_settings = dict(default_settings,
                                        **alert_service_desc["settings"])

                service_gone_alerts = [
                    alert for alert in gone_alerts if service_settings.get(
                        alert.source, DEFAULT_POLICY) == policy_name
                ]
                service_new_alerts = [
                    alert for alert in new_alerts if service_settings.get(
                        alert.source, DEFAULT_POLICY) == policy_name
                ]

                if not service_gone_alerts and not service_new_alerts:
                    continue

                factory = ALERT_SERVICES_FACTORIES.get(
                    alert_service_desc["type"])
                if factory is None:
                    self.logger.error("Alert service %r does not exist",
                                      alert_service_desc["type"])
                    continue

                try:
                    alert_service = factory(self.middleware,
                                            alert_service_desc["attributes"])
                except Exception:
                    self.logger.error(
                        "Error creating alert service %r with parameters=%r",
                        alert_service_desc["type"],
                        alert_service_desc["attributes"],
                        exc_info=True)
                    continue

                if all_alerts or service_gone_alerts or service_new_alerts:
                    try:
                        await alert_service.send(all_alerts,
                                                 service_gone_alerts,
                                                 service_new_alerts)
                    except Exception:
                        self.logger.error("Error in alert service %r",
                                          alert_service_desc["type"],
                                          exc_info=True)

            if policy_name == "IMMEDIATELY":
                for alert in new_alerts:
                    if alert.mail:
                        await self.middleware.call("mail.send", alert.mail)

                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
                        ]:
                            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":
                                            "*****@*****.**",
                                            "phone": "-",
                                        })
                                except Exception:
                                    self.logger.error(
                                        f"Failed to create a support ticket",
                                        exc_info=True)
Example #34
0
    def hook_app_tabs_system(self, request):
        from freenasUI.freeadmin.sqlite3_ha.base import NO_SYNC_MAP
        from freenasUI.middleware.notifier import notifier
        from freenasUI.system import models
        from freenasUI.support.utils import get_license
        tabmodels = [
            models.Settings, models.Advanced, models.Email,
            models.SystemDataset, models.Tunable, models.CloudCredentials,
            models.AlertDefaultSettings, models.AlertService,
            models.CertificateAuthority, models.Certificate,
            models.ACMEDNSAuthenticator
        ]

        tabs = []
        if (hasattr(notifier, 'failover_status')
                and notifier().failover_status() == 'BACKUP'):
            backup = True
        else:
            backup = False
        tabs.append({
            'name': 'SysInfo',
            'focus': 'system.SysInfo',
            'verbose_name': _('Information'),
            'url': reverse('system_info'),
        })

        for model in tabmodels:
            if backup and model._meta.db_table not in NO_SYNC_MAP:
                continue
            # System Dataset has only one hidden field
            if backup and model._meta.db_table == 'system_systemdataset':
                continue
            if model._admin.deletable is False:
                try:
                    obj = model.objects.order_by('-id')[0]
                except IndexError:
                    obj = model.objects.create()
                url = obj.get_edit_url() + '?inline=true'
                verbose_name = model._meta.verbose_name
                focus = 'system.%s' % model._meta.object_name
            else:
                url = reverse('freeadmin_%s_%s_datagrid' % (
                    model._meta.app_label,
                    model._meta.model_name,
                ))
                verbose_name = model._meta.verbose_name_plural
                focus = 'system.%s.View' % model._meta.object_name
            tabs.append({
                'name': model._meta.object_name,
                'focus': focus,
                'verbose_name': verbose_name,
                'url': url,
            })

        tabs.insert(
            2, {
                'name': 'BootEnv',
                'focus': 'system.BootEnv',
                'verbose_name': _('Boot'),
                'url': reverse('system_bootenv_datagrid'),
            })

        tabs.insert(
            8, {
                'name': 'Update',
                'focus': 'system.Update',
                'verbose_name': _('Update'),
                'url': reverse('system_update_index'),
            })

        tabs.insert(
            13, {
                'name':
                'Support',
                'focus':
                'system.Support',
                'verbose_name':
                _('Support'),
                'url':
                reverse('support_home'),
                'onload':
                'support_production_init();'
                if not notifier().is_freenas() else ''
            })

        license = get_license()[0]
        if license is not None and not notifier().is_freenas():
            support = models.Support.objects.order_by('-id')[0]
            tabs.insert(
                14, {
                    'name': 'Proactive Support',
                    'focus': 'system.ProactiveSupport',
                    'verbose_name': _('Proactive Support'),
                    'url': support.get_edit_url() + '?inline=true',
                })

            tabs.insert(
                15, {
                    'name': 'ViewEnclosure',
                    'focus': 'system.ViewEnclosure',
                    'verbose_name': _('View Enclosure'),
                    'url': reverse('storage_enclosure_status'),
                })

        return tabs
Example #35
0
def ticket(request):

    step = 2 if request.FILES.getlist('attachment') else 1

    files = []
    if request.POST.get('debug') == 'on':
        debug = True
        with open(TICKET_PROGRESS, 'w') as f:
            f.write(json.dumps({'indeterminate': True, 'step': step}))
        step += 1

        mntpt, direc, dump = debug_get_settings()
        debug_generate()

        _n = notifier()
        if not _n.is_freenas() and _n.failover_licensed():
            debug_file = '%s/debug.tar' % direc
            debug_name = 'debug-%s.tar' % time.strftime('%Y%m%d%H%M%S')
        else:
            gc = GlobalConfiguration.objects.all().order_by('-id')[0]
            debug_file = dump
            debug_name = 'debug-%s-%s.txz' % (
                gc.gc_hostname.encode('utf-8'),
                time.strftime('%Y%m%d%H%M%S'),
            )

        files.append(File(open(debug_file, 'rb'), name=debug_name))
    else:
        debug = False

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {
        'title': request.POST.get('subject'),
        'body': request.POST.get('desc'),
        'version': get_sw_version().split('-', 1)[-1],
        'category': request.POST.get('category'),
        'debug': debug,
    }

    if get_sw_name().lower() == 'freenas':
        data.update({
            'user': request.POST.get('username'),
            'password': request.POST.get('password'),
            'type': request.POST.get('type'),
        })
    else:

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE).communicate()[0].split('\n')[0].upper()

        license, reason = utils.get_license()
        if license:
            company = license.customer_name
        else:
            company = 'Unknown'

        data.update({
            'phone': request.POST.get('phone'),
            'name': request.POST.get('name'),
            'company': company,
            'email': request.POST.get('email'),
            'criticality': request.POST.get('criticality'),
            'environment': request.POST.get('environment'),
            'serial': serial,
        })

    success, msg, tid = utils.new_ticket(data)

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {'message': msg, 'error': not success}

    if not success:
        pass
    else:

        files.extend(request.FILES.getlist('attachment'))
        for f in files:
            success, attachmsg = utils.ticket_attach(
                {
                    'user': request.POST.get('username'),
                    'password': request.POST.get('password'),
                    'ticketnum': tid,
                }, f)

    data = ('<html><body><textarea>%s</textarea></boby></html>' %
            (json.dumps(data), ))
    return HttpResponse(data)
Example #36
0
    async def new_ticket(self, job, data):
        """
        Creates a new ticket for support.
        This is done using the support proxy API.
        For FreeNAS it will be created on Redmine and for TrueNAS on SupportSuite.

        For FreeNAS `criticality`, `environment`, `phone`, `name` and `email` attributes are not required.
        For TrueNAS `username`, `password` and `type` attributes are not required.
        """

        job.set_progress(1, 'Gathering data')

        sw_name = 'freenas' if await self.middleware.call('system.is_freenas'
                                                          ) else 'truenas'

        if sw_name == 'freenas':
            required_attrs = ('type', 'username', 'password')
        else:
            required_attrs = ('phone', 'name', 'email', 'criticality',
                              'environment')
            data['serial'] = (await (await Popen(
                ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
                stdout=subprocess.PIPE)).communicate()
                              )[0].decode().split('\n')[0].upper()
            license = get_license()[0]
            if license:
                data['company'] = license.customer_name
            else:
                data['company'] = 'Unknown'

        for i in required_attrs:
            if i not in data:
                raise CallError(f'{i} is required', errno.EINVAL)

        data['version'] = (await self.middleware.call('system.version')).split(
            '-', 1)[-1]
        if 'username' in data:
            data['user'] = data.pop('username')
        debug = data.pop('attach_debug')

        type_ = data.get('type')
        if type_:
            data['type'] = type_.lower()

        job.set_progress(20, 'Submitting ticket')

        try:
            r = await self.middleware.run_in_thread(lambda: requests.post(
                f'https://{ADDRESS}/{sw_name}/api/v1.0/ticket',
                data=json.dumps(data),
                headers={'Content-Type': 'application/json'},
                timeout=10,
            ))
            result = r.json()
        except simplejson.JSONDecodeError:
            self.logger.debug(
                f'Failed to decode ticket attachment response: {r.text}')
            raise CallError('Invalid proxy server response', errno.EBADMSG)
        except requests.ConnectionError as e:
            raise CallError(f'Connection error {e}', errno.EBADF)
        except requests.Timeout:
            raise CallError('Connection time out', errno.ETIMEDOUT)

        if r.status_code != 200:
            self.logger.debug(
                f'Support Ticket failed ({r.status_code}): {r.text}',
                r.status_code, r.text)
            raise CallError('Ticket creation failed, try again later.',
                            errno.EINVAL)

        if result['error']:
            raise CallError(result['message'], errno.EINVAL)

        ticket = result.get('ticketnum')
        url = result.get('message')
        if not ticket:
            raise CallError('New ticket number was not informed', errno.EINVAL)
        job.set_progress(50,
                         f'Ticket created: {ticket}',
                         extra={'ticket': ticket})

        if debug:
            # FIXME: generate debug from middleware
            mntpt, direc, dump = await self.middleware.run_in_thread(
                debug_get_settings)

            job.set_progress(60, 'Generating debug file')
            await self.middleware.run_in_thread(debug_generate)

            not_freenas = not (await self.middleware.call('system.is_freenas'))
            if not_freenas:
                not_freenas &= await self.middleware.call(
                    'notifier.failover_licensed')
            if not_freenas:
                debug_file = f'{direc}/debug.tar'
                debug_name = 'debug-{}.tar'.format(
                    time.strftime('%Y%m%d%H%M%S'))
            else:
                debug_file = dump
                debug_name = 'debug-{}-{}.txz'.format(
                    socket.gethostname().split('.')[0],
                    time.strftime('%Y%m%d%H%M%S'),
                )

            job.set_progress(80, 'Attaching debug file')

            t = {
                'ticket': ticket,
                'filename': debug_name,
            }
            if 'user' in data:
                t['username'] = data['user']
            if 'password' in data:
                t['password'] = data['password']
            tjob = await self.middleware.call(
                'support.attach_ticket',
                t,
                pipes=Pipes(input=self.middleware.pipe()))

            with open(debug_file, 'rb') as f:
                await self.middleware.run_in_io_thread(shutil.copyfileobj, f,
                                                       tjob.pipes.input.w)
                await self.middleware.run_in_io_thread(tjob.pipes.input.w.close
                                                       )

            await tjob.wait()
        else:
            job.set_progress(100)

        return {
            'ticket': ticket,
            'url': url,
        }
Example #37
0
    async def process_alerts(self, job):
        if not await self.middleware.call("system.ready"):
            return

        if (
            not await self.middleware.call('system.is_freenas') and
            await self.middleware.call('notifier.failover_licensed') and
            await self.middleware.call('notifier.failover_status') == 'BACKUP'
        ):
            return

        await self.__run_alerts()

        default_settings = (await self.middleware.call("alertdefaultsettings.config"))["settings"]

        all_alerts = self.__get_all_alerts()

        now = datetime.now()
        for policy_name, policy in self.policies.items():
            gone_alerts, new_alerts = policy.receive_alerts(now, self.alerts)

            for alert_service_desc in await self.middleware.call("datastore.query", "system.alertservice"):
                service_settings = dict(default_settings, **alert_service_desc["settings"])

                service_gone_alerts = [alert for alert in gone_alerts
                                       if service_settings.get(alert.source, DEFAULT_POLICY) == policy_name]
                service_new_alerts = [alert for alert in new_alerts
                                      if service_settings.get(alert.source, DEFAULT_POLICY) == policy_name]

                if not service_gone_alerts and not service_new_alerts:
                    continue

                factory = ALERT_SERVICES_FACTORIES.get(alert_service_desc["type"])
                if factory is None:
                    self.logger.error("Alert service %r does not exist", alert_service_desc["type"])
                    continue

                try:
                    alert_service = factory(self.middleware, alert_service_desc["attributes"])
                except Exception:
                    self.logger.error("Error creating alert service %r with parameters=%r",
                                      alert_service_desc["type"], alert_service_desc["attributes"], exc_info=True)
                    continue

                if all_alerts or service_gone_alerts or service_new_alerts:
                    try:
                        await alert_service.send(all_alerts, service_gone_alerts, service_new_alerts)
                    except Exception:
                        self.logger.error("Error in alert service %r", alert_service_desc["type"], exc_info=True)

            if policy_name == "IMMEDIATELY":
                for alert in new_alerts:
                    if alert.mail:
                        await self.middleware.call("mail.send", alert.mail)

                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]:
                            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._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": "*****@*****.**",
                                        "phone": "-",
                                    })
                                except Exception:
                                    self.logger.error(f"Failed to create a support ticket", exc_info=True)
Example #38
0
def ticket(request):

    step = 2 if request.FILES.getlist('attachment') else 1

    files = []
    if request.POST.get('debug') == 'on':
        debug = True
        with open(TICKET_PROGRESS, 'w') as f:
            f.write(json.dumps({'indeterminate': True, 'step': step}))
        step += 1

        mntpt, direc, dump = debug_get_settings()
        debug_run(direc)
        files.append(File(open(dump, 'rb'), name=os.path.basename(dump)))
    else:
        debug = False

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {
        'title': request.POST.get('subject'),
        'body': request.POST.get('desc'),
        'version': get_sw_version().split('-', 1)[-1],
        'category': request.POST.get('category'),
        'debug': debug,
    }

    if get_sw_name().lower() == 'freenas':
        data.update({
            'user': request.POST.get('username'),
            'password': request.POST.get('password'),
            'type': request.POST.get('type'),
        })
    else:

        serial = subprocess.Popen(
            ['/usr/local/sbin/dmidecode', '-s', 'system-serial-number'],
            stdout=subprocess.PIPE).communicate()[0].split('\n')[0].upper()

        license, reason = utils.get_license()
        if license:
            company = license.customer_name
        else:
            company = 'Unknown'

        data.update({
            'phone': request.POST.get('phone'),
            'name': request.POST.get('name'),
            'company': company,
            'email': request.POST.get('email'),
            'criticality': request.POST.get('criticality'),
            'environment': request.POST.get('environment'),
            'serial': serial,
        })

    success, msg, tid = utils.new_ticket(data)

    with open(TICKET_PROGRESS, 'w') as f:
        f.write(json.dumps({'indeterminate': True, 'step': step}))
    step += 1

    data = {'message': msg, 'error': not success}

    if not success:
        pass
    else:

        files.extend(request.FILES.getlist('attachment'))
        for f in files:
            success, attachmsg = utils.ticket_attach(
                {
                    'user': request.POST.get('username'),
                    'password': request.POST.get('password'),
                    'ticketnum': tid,
                }, f)

    data = ('<html><body><textarea>%s</textarea></boby></html>' %
            (json.dumps(data), ))
    return HttpResponse(data)