コード例 #1
0
ファイル: views.py プロジェクト: bartleydirk/PowerDNS-Admin
def domain_management(domain_name):
    """Route to manage domain attributes."""
    if request.method == 'GET':
        domain = Domain.query.filter(Domain.name == domain_name).first()
        if not domain:
            return redirect(url_for('error', code=404))
        users = User.query.all()

        # get list of user ids to initilize selection data
        d = Domain(name=domain_name)
        domain_user_ids = d.get_user()

        return render_template('domain_management.html', domain=domain, users=users, domain_user_ids=domain_user_ids)

    if request.method == 'POST':
        # username in right column
        new_user_list = request.form.getlist('domain_multi_user[]')

        # get list of user ids to compare
        d = Domain(name=domain_name)
        domain_user_ids = d.get_user()

        # grant/revoke user privielges
        d.grant_privielges(new_user_list)

        history = History(msg='Change domain %s access control' % domain_name,
                          detail=str({'user_has_access': new_user_list}), created_by=current_user.username)
        history.add()

        return redirect(url_for('domain_management', domain_name=domain_name))

    return None
コード例 #2
0
ファイル: views.py プロジェクト: bartleydirk/PowerDNS-Admin
def domain_add():
    """Route to add a Domain."""
    # pylint: disable=R0914,R0912,
    # here here here
    if request.method == 'POST':
        try:
            domain_name = request.form.getlist('domain_name')[0]
            domain_type = request.form.getlist('radio_type')[0]
            soa_edit_api = request.form.getlist('radio_type_soa_edit_api')[0]

            if ' ' in domain_name or not domain_name or not domain_type:
                return render_template('errors/400.html', msg="Please correct your input"), 400

            if domain_type == 'slave':
                if request.form.getlist('domain_master_address'):
                    domain_master_string = request.form.getlist('domain_master_address')[0]
                    domain_master_string = domain_master_string.replace(' ', '')
                    domain_master_ips = domain_master_string.split(',')
            else:
                domain_master_ips = []
            d = Domain()
            result = d.add(domain_name=domain_name, domain_type=domain_type, soa_edit_api=soa_edit_api,
                           domain_master_ips=domain_master_ips)

            # The soa record will show a.misconfigured.powerdns.server
            rec = Record()
            recs = rec.get_record_data('pop')
            soacontent = None
            nsrecords = None
            nscontent = None
            for item in recs['records']:
                if item['name'] == 'pop' and item['type'] == 'SOA':
                    soacontent = item['content']
                if item['type'] == 'NS':
                    nsrecords = item['records']
                    nscontent = item['content']

            if soacontent:
                soarec = Record(name=domain_name, type='SOA', ttl=3600)
                soarec.update(domain_name, soacontent, username=current_user.username)
            if nsrecords and nscontent:
                for nsrec in nsrecords:
                    nsrec_ = Record(name=domain_name, type='NS', ttl=3600)
                    nsrec_.update(domain_name, nsrec['content'], username=current_user.username)
            # end update the record using pop as a base
            if result['status'] == 'ok':
                history = History(msg='Add domain %s' % domain_name,
                                  detail=str({'domain_type': domain_type, 'domain_master_ips': domain_master_ips}),
                                  created_by=current_user.username)
                history.add()
                return redirect(url_for('dashboard'))
            else:
                return render_template('errors/400.html', msg=result['msg']), 400
        except Exception:
            return redirect(url_for('error', code=500))
    return render_template('domain_add.html')
コード例 #3
0
ファイル: views.py プロジェクト: bartleydirk/PowerDNS-Admin
def domain_delete(domain_name):
    """Route to delete a domain."""
    d = Domain()
    result = d.delete(domain_name)

    if result['status'] == 'error':
        return redirect(url_for('error', code=500))

    history = History(msg='Delete domain %s' % domain_name, created_by=current_user.username)
    history.add()

    return redirect(url_for('dashboard'))
コード例 #4
0
ファイル: api.py プロジェクト: ysirawit/PowerDNS-Admin
def api_login_delete_zone(domain_name):
    pdns_api_url = Setting().get('pdns_api_url')
    pdns_api_key = Setting().get('pdns_api_key')
    pdns_version = Setting().get('pdns_version')
    api_uri_with_prefix = utils.pdns_api_extended_uri(pdns_version)
    api_full_uri = api_uri_with_prefix + '/servers/localhost/zones'
    api_full_uri += '/' + domain_name
    headers = {}
    headers['X-API-Key'] = pdns_api_key

    domain = Domain.query.filter(Domain.name == domain_name)

    if not domain:
        abort(404)

    if g.user.role.name not in ['Administrator', 'Operator']:
        user_domains_obj_list = g.user.get_domains()
        user_domains_list = [item.name for item in user_domains_obj_list]

        if domain_name not in user_domains_list:
            raise DomainAccessForbidden()

    msg_str = "Sending request to powerdns API {0}"
    logging.debug(msg_str.format(domain_name))

    try:
        resp = utils.fetch_remote(
            urljoin(pdns_api_url, api_full_uri),
            method='DELETE',
            headers=headers,
            accept='application/json; q=1'
        )

        if resp.status_code == 204:
            logging.debug("Request to powerdns API successful")

            history = History(
                msg='Delete domain {0}'.format(domain_name),
                detail='',
                created_by=g.user.username
            )
            history.add()

            domain = Domain()
            domain.update()
    except Exception as e:
        logging.error('Error: {0}'.format(e))
        abort(500)

    return resp.content, resp.status_code, resp.headers.items()
コード例 #5
0
ファイル: views.py プロジェクト: bartleydirk/PowerDNS-Admin
def admin_setdomainsetting(domain_name):
    """View Set Admin domain settings."""
    if request.method == 'POST':
        #
        # post data should in format
        # {'action': 'set_setting', 'setting': 'default_action, 'value': 'True'}
        #
        try:
            pdata = request.data
            jdata = json.loads(pdata)
            data = jdata['data']
            if jdata['action'] == 'set_setting':
                new_setting = data['setting']
                new_value = str(data['value'])
                domain = Domain.query.filter(Domain.name == domain_name).first()
                setting = DomainSetting.query.filter(DomainSetting.domain == domain)\
                                       .filter(DomainSetting.setting == new_setting)\
                                       .first()

                if setting:
                    if setting.set(new_value):
                        history = History(msg='Setting %s changed value to %s for %s'
                                          % (new_setting, new_value, domain.name),
                                          created_by=current_user.username)
                        history.add()
                        retval = make_response(jsonify({'status': 'ok', 'msg': 'Setting updated.'}))
                    else:
                        retval = make_response(jsonify({'status': 'error', 'msg': 'Unable to set value of setting.'}))
                else:
                    if domain.add_setting(new_setting, new_value):
                        history = History(msg='New setting %s with value %s for %s has been created'
                                          % (new_setting, new_value, domain.name), created_by=current_user.username)
                        history.add()
                        retval = make_response(jsonify({'status': 'ok', 'msg': 'New setting created and updated.'}))
                    else:
                        retval = make_response(jsonify({'status': 'error', 'msg': 'Unable to create new setting.'}))
            else:
                retval = make_response(jsonify({'status': 'error', 'msg': 'Action not supported.'}), 400)
        except Exception:
            print traceback.format_exc()
            retval = make_response(jsonify({'status': 'error',
                                            'msg': 'There is something wrong, please contact Administrator.'}), 400)
    return retval
コード例 #6
0
ファイル: api.py プロジェクト: ysirawit/PowerDNS-Admin
def api_login_create_zone():
    pdns_api_url = Setting().get('pdns_api_url')
    pdns_api_key = Setting().get('pdns_api_key')
    pdns_version = Setting().get('pdns_version')
    api_uri_with_prefix = utils.pdns_api_extended_uri(pdns_version)
    api_full_uri = api_uri_with_prefix + '/servers/localhost/zones'
    headers = {}
    headers['X-API-Key'] = pdns_api_key

    msg_str = "Sending request to powerdns API {0}"
    msg = msg_str.format(request.get_json(force=True))
    logging.debug(msg)

    resp = utils.fetch_remote(
        urljoin(pdns_api_url, api_full_uri),
        method='POST',
        data=request.get_json(force=True),
        headers=headers,
        accept='application/json; q=1'
    )

    if resp.status_code == 201:
        logging.debug("Request to powerdns API successful")
        data = request.get_json(force=True)

        history = History(
            msg='Add domain {0}'.format(data['name'].rstrip('.')),
            detail=json.dumps(data),
            created_by=g.user.username
        )
        history.add()

        if g.user.role.name not in ['Administrator', 'Operator']:
            logging.debug("User is ordinary user, assigning created domain")
            domain = Domain(name=data['name'].rstrip('.'))
            domain.update()
            domain.grant_privileges([g.user.username])

        domain = Domain()
        domain.update()

    return resp.content, resp.status_code, resp.headers.items()
コード例 #7
0
def admin_history():
    """A method to act as route for rendering history page."""
    retval = None
    if request.method == 'POST':
        history = History()
        result = history.remove_all()
        if result:
            history = History(msg='Remove all histories',
                              created_by=current_user.username)
            history.add()

            retval = make_response(
                jsonify({
                    'status': 'ok',
                    'msg': 'Changed user role successfully.'
                }), 200)
        else:
            retval = make_response(
                jsonify({
                    'status': 'error',
                    'msg': 'Can not remove histories.'
                }), 500)

    if request.method == 'GET':
        domain = request.values.get('domain')
        name = request.values.get('name')
        histories = db.session.query(History.id, History.created_by, History.msg,
                                     db.func.CONVERT_TZ(History.created_on, '+00:00', '-07:00').label('created_on'),
                                     History.name, History.changetype, Domain.name.label('domainname'))\
                      .outerjoin(Domain, Domain.id == History.domain)\
                      .order_by(db.desc(History.id))
        if name:
            histories = histories.filter(History.name == '%s.' % (name))
        if domain:
            sqry = db.session.query(Domain.id)\
                     .filter(Domain.name == domain)\
                     .first()
            histories = histories.filter(History.domain == sqry)
        histories = histories.all()
        retval = render_template('admin_history.html', histories=histories)
    return retval
コード例 #8
0
def api_create_zone(server_id):
    resp = helper.forward_request()

    if resp.status_code == 201:
        logging.debug("Request to powerdns API successful")
        data = request.get_json(force=True)

        history = History(msg='Add domain {0}'.format(
            data['name'].rstrip('.')),
                          detail=json.dumps(data),
                          created_by=g.apikey.description)
        history.add()

        if g.apikey.role.name not in ['Administrator', 'Operator']:
            logging.debug("Apikey is user key, assigning created domain")
            domain = Domain(name=data['name'].rstrip('.'))
            g.apikey.domains.append(domain)

        domain = Domain()
        domain.update()

    return resp.content, resp.status_code, resp.headers.items()
コード例 #9
0
ファイル: views.py プロジェクト: bartleydirk/PowerDNS-Admin
def admin_manageuser():
    """View to manage a user."""
    # pylint: disable=R0912,R0914
    retval = None
    if request.method == 'GET':
        # query all users
        users = db.session.query(User)\
                  .order_by(User.username)

        # use an instance of DisplayUserAcls to help with displaying what groups users are members of
        dua = DisplayUserAcls()

        retval = render_template('admin_manageuser.html', users=users, dua=dua)

    if request.method == 'POST':
        #
        # post data should in format
        # {'action': 'delete_user', 'data': 'username'}
        #
        try:
            action = request.form['action']
            username = request.form['username']
            if action == 'delete_user':
                user = User(username=username)
                result = user.delete()
                if result:
                    history = History(msg='Delete username %s' % username, created_by=current_user.username)
                    history.add()
                    retval = make_response(jsonify({'status': 'ok', 'msg': 'User has been removed.'}), 200)
                else:
                    retval = make_response(jsonify({'status': 'error', 'msg': 'Cannot remove user.'}), 500)

            elif action == 'revoke_user_privielges':
                user = User(username=username)
                result = user.revoke_privilege()
                if result:
                    history = History(msg='Revoke %s user privielges' % username, created_by=current_user.username)
                    history.add()
                    retval = make_response(jsonify({'status': 'ok', 'msg': 'Revoked user privielges.'}), 200)
                else:
                    retval = make_response(jsonify({'status': 'error', 'msg': 'Cannot revoke user privilege.'}), 500)

            elif action == 'set_admin':
                is_admin = request.form['is_admin']
                user = User(username=username)
                result = user.set_admin(booleanval(is_admin))
                if result:
                    history = History(msg='Change user role of %s' % username, created_by=current_user.username)
                    history.add()
                    retval = make_response(jsonify({'status': 'ok', 'msg': 'Changed user role successfully.'}), 200)
                else:
                    retval = make_response(jsonify({'status': 'error', 'msg': 'Cannot change user role.'}), 500)
            else:
                retval = make_response(jsonify({'status': 'error', 'msg': 'Action not supported.'}), 400)
        except Exception:
            print traceback.format_exc()
            retval = make_response(jsonify({'status': 'error',
                                            'msg': 'There is something wrong, please contact Administrator.'}), 400)
    return retval
コード例 #10
0
def populate():
    server_1 = get_server_id('gis-license-1')

    server_2 = get_server_id('gis-license-2')

    update_1 = Updates.start(server_1)

    update_2 = Updates.start(server_2)

    dummy_data = [
        # server 1
        (update_1, server_1, {
            'user_id': get_user_id('Gus'),
            'workstation_id': get_workstation_id('Gus-PC'),
            'product_id': get_product_id(server_1, 'ARC/INFO', 0, 3),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Ted'),
            'workstation_id': get_workstation_id('Ted-PC'),
            'product_id': get_product_id(server_1, 'ARC/INFO', 0, 3),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Lin'),
            'workstation_id': get_workstation_id('Lin-PC'),
            'product_id': get_product_id(server_1, 'VIEWER', 0, 5),
            'time_out': random_date()
        }, True),
        (update_1, server_1, {
            'user_id': get_user_id('Sue'),
            'workstation_id': get_workstation_id('Ted-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Ike'),
            'workstation_id': get_workstation_id('Ike-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Mary'),
            'workstation_id': get_workstation_id('Mary-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Sally'),
            'workstation_id': get_workstation_id('Sally-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Ron'),
            'workstation_id': get_workstation_id('Ron-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Bill'),
            'workstation_id': get_workstation_id('Bill-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, True),
        (update_1, server_1, {
            'user_id': get_user_id('Nancy'),
            'workstation_id': get_workstation_id('Nancy-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, True),
        (update_1, server_1, {
            'user_id': get_user_id('Will'),
            'workstation_id': get_workstation_id('Will-PC'),
            'product_id': get_product_id(server_1, 'EDITOR', 5, 10),
            'time_out': random_date()
        }, True),
        (update_1, server_1, {
            'user_id': get_user_id('Sam'),
            'workstation_id': get_workstation_id('Sam-PC'),
            'product_id': get_product_id(server_1, 'DESKTOPBASICP', 2, 2),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Pat'),
            'workstation_id': get_workstation_id('Pat-PC'),
            'product_id': get_product_id(server_1, 'DESKTOPBASICP', 2, 2),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Alf'),
            'workstation_id': get_workstation_id('Alf-PC'),
            'product_id': get_product_id(server_1, 'DESKTOPADVP', 1, 4),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Sam'),
            'workstation_id': get_workstation_id('Sam-PC'),
            'product_id': get_product_id(server_1, '3DANALYSTP', 2, 4),
            'time_out': random_date()
        }, False),
        (update_1, server_1, {
            'user_id': get_user_id('Pat'),
            'workstation_id': get_workstation_id('Pat-PC'),
            'product_id': get_product_id(server_1, '3DANALYSTP', 2, 4),
            'time_out': random_date()
        }, False),

        # server 2
        (update_2, server_2, {
            'user_id': get_user_id('Bob'),
            'workstation_id': get_workstation_id('Pat-PC'),
            'product_id': get_product_id(server_2, 'ARC/INFO', 2, 3),
            'time_out': random_date()
        }, False),
        (update_2, server_2, {
            'user_id': get_user_id('Kim'),
            'workstation_id': get_workstation_id('Alf-PC'),
            'product_id': get_product_id(server_2, 'ARC/INFO', 2, 3),
            'time_out': random_date()
        }, False),
        (update_2, server_2, {
            'user_id': get_user_id('Joe'),
            'workstation_id': get_workstation_id('Joe-PC'),
            'product_id': get_product_id(server_2, 'VIEWER', 0, 10),
            'time_out': random_date()
        }, True),
        (update_2, server_2, {
            'user_id': get_user_id('Liz'),
            'workstation_id': get_workstation_id('Joe-PC'),
            'product_id': get_product_id(server_2, 'VIEWER', 0, 10),
            'time_out': random_date()
        }, True),
        (update_2, server_2, {
            'user_id': get_user_id('Pam'),
            'workstation_id': get_workstation_id('Pam-PC'),
            'product_id': get_product_id(server_2, 'EDITOR', 1, 10),
            'time_out': random_date()
        }, False),
        (update_2, server_2, {
            'user_id': get_user_id('Ann'),
            'workstation_id': get_workstation_id('Ann-PC'),
            'product_id': get_product_id(server_2, 'DESKTOPBASICP', 0, 2),
            'time_out': random_date()
        }, True),
        (update_2, server_2, {
            'user_id': get_user_id('Bob'),
            'workstation_id': get_workstation_id('Bob-PC'),
            'product_id': get_product_id(server_2, 'NETWORK', 2, 2),
            'time_out': random_date()
        }, False),
        (update_2, server_2, {
            'user_id': get_user_id('Kim'),
            'workstation_id': get_workstation_id('Kim-PC'),
            'product_id': get_product_id(server_2, 'NETWORK', 2, 2),
            'time_out': random_date()
        }, False),
    ]

    for d in dummy_data:
        id = History.add(d[0], d[1], **d[2])
        if d[3]:
            check_in(server_id=d[1], h=id, data=d[2])

    Updates.end(update_1, 'UP', '')
    Updates.end(update_2, 'UP', '')
コード例 #11
0
def read(license_file=None):
    """
    entry point for reading license data from a FlexLM license server.
    :param license_file: manually pass in a license file in the same format the lmutil.exe displays data.
    :return:
    """
    for s in license_servers:
        try:
            info = ''
            server_id = Server.upsert(s['hostname'], s['port'])
            update_id = Updates.start(server_id)
            check_year(server_id)
            checked_out_history_ids = []
            if license_file:
                with open(license_file) as process:
                    lines = process.read()
            else:
                process = subprocess.Popen([
                    lm_util, "lmstat", "-f", "-c", "{}@{}".format(
                        s['port'], s['hostname'])
                ],
                                           stdout=subprocess.PIPE,
                                           stderr=subprocess.PIPE,
                                           bufsize=1,
                                           universal_newlines=True)
                lines = process.stdout.read()
            has_error = parse_error_info(lines)
            if has_error:
                reset(update_id, server_id,
                      '{}@{}: {}'.format(s['port'], s['hostname'], has_error))
                raise Exception(has_error)
            license_data = split_license_data(lines)
            updates = {'update_id': update_id, 'status': None}
            server_information = parse_server_info(lines)
            if server_information:
                updates['status'] = server_information[2]
            else:
                updates['status'] = "DOWN"
                reset(update_id, server_id,
                      '{}@{} is DOWN'.format(s['port'], s['hostname']))
                raise Exception(has_error)
            for lic in license_data:
                split_line = lic.split('FLOATING LICENSE')
                product_id = add_product(split_line[0], server_id=server_id)
                users_and_workstations = add_users_and_workstations(
                    split_line[-1])
                if product_id and len(users_and_workstations):
                    data = map_product_id(product_id, users_and_workstations)
                    for kwargs in data:
                        history_id = History.add(update_id=update_id,
                                                 server_id=server_id,
                                                 **kwargs)
                        checked_out_history_ids.append(history_id)
            dt = datetime.now().replace(second=0, microsecond=0)
            checked_out = History.time_in_none(server_id)
            for c in checked_out:
                if c.id not in checked_out_history_ids:
                    History.update(c.id, dt, server_id)
        except Exception as e:
            info = "{} error: {}".format(s['hostname'], str(e))
            logger.error(str(e))
            pass
        finally:
            logger.info('Finished reading data from \'{}\'. '
                        'Update details | id:{} | status:{} | info:{}.'.format(
                            s['hostname'], update_id, updates['status'], info))
            Updates.end(update_id, updates['status'], info)
コード例 #12
0
ファイル: views.py プロジェクト: bartleydirk/PowerDNS-Admin
def dyndns_update():
    """Dynamic Dns Update."""
    # pylint: disable=R0912,R0914
    # dyndns protocol response codes in use are:
    # good: update successful
    # nochg: IP address already set to update address
    # nohost: hostname does not exist for this user account
    # 911: server error
    # have to use 200 HTTP return codes because ddclient does not read the return string if the code is other than 200
    # reference: https://help.dyn.com/remote-access-api/perform-update/
    # reference: https://help.dyn.com/remote-access-api/return-codes/
    hostname = request.args.get('hostname')
    myip = request.args.get('myip')

    try:
        # get all domains owned by the current user
        domains = User(id=current_user.id).get_domain()
    except Exception:
        return render_template('dyndns.html', response='911'), 200

    domain = None
    domain_segments = hostname.split('.')
    for _ in range(len(domain_segments)):
        domain_segments.pop(0)
        full_domain = '.'.join(domain_segments)
        potential_domain = Domain.query.filter(Domain.name == full_domain).first()
        if potential_domain in domains:
            domain = potential_domain
            break

    if not domain:
        history = History(msg="DynDNS update: attempted update of %s but it does not exist for this user" % hostname,
                          created_by=current_user.username)
        history.add()
        return render_template('dyndns.html', response='nohost'), 200

    r = Record()
    r.name = hostname
    # check if the user requested record exists within this domain
    retval = None
    if r.exists(domain.name) and r.is_allowed:
        if r.data == myip:
            # record content did not change, return 'nochg'
            history = History(msg="DynDNS update: attempted update of %s but record did not change" % hostname,
                              created_by=current_user.username)
            history.add()
            retval = render_template('dyndns.html', response='nochg'), 200
        else:
            oldip = r.data
            result = r.update(domain.name, myip, username=current_user.username)
            if result['status'] == 'ok':
                msg = 'DynDNS update: updated record %s in zone %s, it changed from %s to %s' % \
                    (hostname, domain.name, oldip, myip)
                history = History(msg=msg, created_by=current_user.username)
                history.add()
                retval = render_template('dyndns.html', response='good'), 200
            else:
                retval = render_template('dyndns.html', response='911'), 200
    elif r.is_allowed:
        ondemand_creation = DomainSetting.query.filter(DomainSetting.domain == domain) \
                                               .filter(DomainSetting.setting == 'create_via_dyndns') \
                                               .first()
        if not ondemand_creation and strtobool(ondemand_creation.value):
            record = Record(name=hostname, type='A', data=myip, status=False, ttl=3600)
            result = record.add(domain.name)
            if result['status'] == 'ok':
                msg = 'DynDNS update: created record %s in zone %s, it now represents %s' % \
                    (hostname, domain.name, myip)
                history = History(msg=msg, detail=str(result), created_by=current_user.username)
                history.add()
                retval = render_template('dyndns.html', response='good'), 200
    if retval:
        return retval
    msg = "DynDNS update: attempted update of %s but it does not exist for this user" % hostname
    history = History(msg=msg, created_by=current_user.username)
    history.add()
    return render_template('dyndns.html', response='nohost'), 200