Example #1
0
 def delete(self, domain):  # , username=None):
     """Delete a record from domain."""
     headers = {}
     headers['X-API-Key'] = PDNS_API_KEY
     data = {
         "rrsets": [{
             "name": self.name.rstrip('.') + '.',
             "type": self.type,
             "changetype": "DELETE",
             "records": [],
         }]
     }
     try:
         url = urlparse.urljoin(
             PDNS_STATS_URL,
             API_EXTENDED_URL + '/servers/localhost/zones/%s' % domain)
         jdata = utils.fetch_json(url,
                                  headers=headers,
                                  method='PATCH',
                                  data=data)
         LOGGING.debug(jdata)
         return {'status': 'ok', 'msg': 'Record was removed successfully'}
     except Exception:
         LOGGING.error("Cannot remove record %s/%s/%s from domain %s",
                       self.name, self.type, self.data, domain)
         return {
             'status':
             'error',
             'msg':
             'There was something wrong in delete, please contact administrator'
         }
Example #2
0
def is_allowed_domain(domainname, current_user_id, checkrole=True):
    """Build a query to populate domains with user and group acls considered."""
    uqry = db.session.query(User)\
             .filter(User.id == current_user_id)\
             .first()
    if uqry:
        if uqry.role_id == 1:
            LOGGING.debug('user is an admin %s', uqry.username)
            return True

    domidqry = db.session.query(Domain.id)\
                 .filter(Domain.name == domainname)\
                 .first()
    retval = True
    if domidqry:
        if checkrole:
            duqry = db.session.query(Domain.id) \
                      .join(DomainUser)\
                      .filter(DomainUser.user_id == current_user_id)\
                      .subquery('duqry')
        dgqry = query_acldomains_fromuser(current_user_id)
        dgqry = dgqry.subquery('dgqry')

        netqry = db.session.query(Domain.id)
        if checkrole:
            netqry = netqry.filter(
                db.or_(Domain.id.in_(dgqry), Domain.id.in_(duqry)))
        else:
            netqry = netqry.filter(Domain.id.in_(dgqry))
        netqry = netqry.filter(Domain.id == domidqry.id)\
                       .all()

        retval = bool(netqry)

    return retval
Example #3
0
 def set(self, value):
     """Set data to Database."""
     try:
         self.value = value
         db.session.commit()
         return True
     except Exception:
         LOGGING.error('Unable to set DomainSetting value')
         LOGGING.debug(traceback.format_exc())
         db.session.rollback()
         return False
Example #4
0
 def remove_all(cls):
     """Remove all history from DB."""
     try:
         db.session.query(History).delete()
         db.session.commit()
         LOGGING.info("Removed all history")
         return True
     except Exception:
         db.session.rollback()
         LOGGING.error("Cannot remove history")
         LOGGING.debug(traceback.format_exc())
         return False
Example #5
0
 def getcurrent_onrecord(self, domain):
     """For history, we want the current status of a name."""
     # self.name is required to be the name we are looking for
     retval = dict()
     LOGGING.debug('getcurrent_onrecord() domain "%s" "%s"', domain,
                   self.name)
     jdata = self.get_record_data(domain, fetchonly=True)
     rrsets = None
     if 'rrsets' in jdata:
         rrsets = jdata['rrsets']
         findme = self.name
     if 'records' in jdata:
         rrsets = jdata['records']
         re_endindot = re.compile(r'\.$')
         findme = re_endindot.sub('', self.name)
     LOGGING.debug("getcurrent_onrecord findme : %s self.name %s", findme,
                   self.name)
     cnter = None
     if rrsets:
         LOGGING.debug("getcurrent_onrecord iterating to find of name : %s",
                       findme)
         for cnter, item in enumerate(rrsets):
             if item['name'] == findme:
                 retval = item
     LOGGING.debug(
         "getcurrent_onrecord returning : %s searching for %s in %s records",
         pformat(retval), self.name, cnter)
     return retval
Example #6
0
    def get_statistic(self):
        """Get server statistics."""
        headers = {}
        headers['X-API-Key'] = PDNS_API_KEY

        try:
            url = urlparse.urljoin(
                PDNS_STATS_URL,
                API_EXTENDED_URL + '/servers/%s/statistics' % self.server_id)
            jdata = utils.fetch_json(url, headers=headers, method='GET')
            return jdata
        except Exception:
            LOGGING.error("Can not get server statistics.")
            LOGGING.debug(traceback.format_exc())
            return []
Example #7
0
    def add(cls,
            domain_name,
            domain_type,
            soa_edit_api,
            domain_ns=None,
            domain_master_ips=None):
        """Add a domain to power dns."""
        if not domain_ns:
            domain_ns = [
                'dns001.den01.pop', 'dns002.den01.pop', 'dns001.iad02.pop',
                'dns002.iad02.pop', 'dns001.sin01.pop', 'dns002.sin01.pop',
                'dns001.ams01.pop', 'dns002.ams01.pop'
            ]
        if not domain_master_ips:
            domain_master_ips = []
        headers = {}
        headers['X-API-Key'] = PDNS_API_KEY

        domain_name = domain_name + '.'
        domain_ns = [ns + '.' for ns in domain_ns]

        post_data = {
            "name": domain_name,
            "kind": domain_type,
            "masters": domain_master_ips,
            "nameservers": domain_ns,
        }

        if soa_edit_api != 'OFF':
            post_data["soa_edit_api"] = soa_edit_api

        try:
            jdata = utils.fetch_json(urlparse.urljoin(
                PDNS_STATS_URL, API_EXTENDED_URL + '/servers/localhost/zones'),
                                     headers=headers,
                                     method='POST',
                                     data=post_data)
            if 'error' in jdata.keys():
                LOGGING.error(jdata['error'])
                return {'status': 'error', 'msg': jdata['error']}
            else:
                LOGGING.info('Added domain %s successfully', domain_name)
                return {'status': 'ok', 'msg': 'Added domain successfully'}
        except Exception as err:
            LOGGING.error('Cannot add domain %s', domain_name)
            traceback.format_exc()
            LOGGING.debug(str(err))
            return {'status': 'error', 'msg': 'Cannot add this domain.'}
Example #8
0
 def delete(cls, domain_name):
     """Delete a single domain name from powerdns."""
     headers = {}
     headers['X-API-Key'] = PDNS_API_KEY
     try:
         url = urlparse.urljoin(
             PDNS_STATS_URL,
             API_EXTENDED_URL + '/servers/localhost/zones/%s' % domain_name)
         utils.fetch_json(url, headers=headers, method='DELETE')
         LOGGING.info('Delete domain %s successfully', domain_name)
         return {'status': 'ok', 'msg': 'Delete domain successfully'}
     except Exception as e:
         tbck = traceback.format_exc()
         LOGGING.error('Cannot delete domain %s', domain_name)
         LOGGING.debug(str(e))
         LOGGING.debug(str(tbck))
         return {'status': 'error', 'msg': 'Cannot delete domain'}
Example #9
0
 def set(cls, setting, value):
     """Set Setting."""
     setting = str(setting)
     new_value = str(value)
     current_setting = Setting.query.filter(Setting.name == setting).first()
     try:
         if current_setting:
             current_setting.value = new_value
             db.session.commit()
             return True
         else:
             LOGGING.error('Setting %s does not exist', setting)
             return False
     except Exception:
         LOGGING.error('Cannot edit setting %s', setting)
         LOGGING.debug(traceback.format_exec())
         db.session.rollback()
         return False
Example #10
0
 def toggle(cls, setting):
     """Toggle Setting."""
     setting = str(setting)
     current_setting = Setting.query.filter(Setting.name == setting).first()
     try:
         if current_setting:
             if current_setting.value == "True":
                 current_setting.value = "False"
             else:
                 current_setting.value = "True"
             db.session.commit()
             return True
         else:
             LOGGING.error('Setting %s does not exist', setting)
             return False
     except Exception:
         LOGGING.error('Cannot toggle setting %s', setting)
         LOGGING.debug(traceback.format_exec())
         db.session.rollback()
         return False
Example #11
0
 def set_mainteance(cls, mode):
     """mode = True/False."""
     mode = str(mode)
     maintenance = Setting.query.filter(
         Setting.name == 'maintenance').first()
     try:
         if maintenance:
             if maintenance.value != mode:
                 maintenance.value = mode
                 db.session.commit()
             return True
         else:
             s = Setting(name='maintenance', value=mode)
             db.session.add(s)
             db.session.commit()
             return True
     except Exception:
         LOGGING.error('Cannot set maintenance to %s', mode)
         LOGGING.debug(traceback.format_exc())
         db.session.rollback()
         return False
Example #12
0
    def set_admin(self, is_admin):
        """Set role for a user.

        is_admin == True  => Administrator
        is_admin == False => User
        """
        user_role_name = 'Administrator' if is_admin else 'User'
        role = Role.query.filter(Role.name == user_role_name).first()

        try:
            if role:
                user = User.query.filter(
                    User.username == self.username).first()
                user.role_id = role.id
                db.session.commit()
                return True
            else:
                return False
        except Exception:
            db.session.roleback()
            LOGGING.error('Cannot change user role in DB')
            LOGGING.debug(traceback.format_exc())
            return False
Example #13
0
    def update(cls):
        """Fetch zones (domains) from PowerDNS and update into DB."""
        # pylint: disable=R0915,R0914
        db_domain = Domain.query.all()
        list_db_domain = [d.name for d in db_domain]
        dict_db_domain = dict((x.name, x) for x in db_domain)

        headers = {}
        headers['X-API-Key'] = PDNS_API_KEY
        try:
            jdata = utils.fetch_json(urlparse.urljoin(
                PDNS_STATS_URL, API_EXTENDED_URL + '/servers/localhost/zones'),
                                     headers=headers)
            list_jdomain = [d['name'].rstrip('.') for d in jdata]
            try:
                # domains should remove from db since it doesn't exist in powerdns anymore
                should_removed_db_domain = list(
                    set(list_db_domain).difference(list_jdomain))
                for d in should_removed_db_domain:
                    # revoke permission before delete domain
                    domain = Domain.query.filter(Domain.name == d).first()
                    domain_user = DomainUser.query.filter(
                        DomainUser.domain_id == domain.id)
                    if domain_user:
                        domain_user.delete()
                        db.session.commit()
                    domain_setting = DomainSetting.query.filter(
                        DomainSetting.domain_id == domain.id)
                    if domain_setting:
                        domain_setting.delete()
                        db.session.commit()

                    # then remove domain
                    Domain.query.filter(Domain.name == d).delete()
                    db.session.commit()
            except Exception:
                LOGGING.error('Can not delete domain from DB')
                LOGGING.debug(traceback.format_exc())
                db.session.rollback()

            # update/add new domain
            for data in jdata:
                d = dict_db_domain.get(data['name'].rstrip('.'), None)
                changed = False
                if d:
                    # existing domain, only update if something actually has changed
                    tst1 = 1 if data['last_check'] else 0
                    # pylint: disable=R0916
                    if (d.master != str(data['masters'])
                            or d.type != data['kind']
                            or d.serial != data['serial']
                            or d.notified_serial != data['notified_serial']
                            or d.last_check != tst1
                            or d.dnssec != data['dnssec']):

                        d.master = str(data['masters'])
                        d.type = data['kind']
                        d.serial = data['serial']
                        d.notified_serial = data['notified_serial']
                        d.last_check = 1 if data['last_check'] else 0
                        d.dnssec = 1 if data['dnssec'] else 0
                        changed = True

                else:
                    # add new domain
                    d = Domain()
                    d.name = data['name'].rstrip('.')
                    d.master = str(data['masters'])
                    d.type = data['kind']
                    d.serial = data['serial']
                    d.notified_serial = data['notified_serial']
                    d.last_check = data['last_check']
                    d.dnssec = 1 if data['dnssec'] else 0
                    db.session.add(d)
                    changed = True
                if changed:
                    try:
                        db.session.commit()
                    except Exception:
                        db.session.rollback()
            return {
                'status': 'ok',
                'msg': 'Domain table has been updated successfully'
            }
        except Exception as err:
            LOGGING.error('Can not update domain table. %s', str(err))
            return {'status': 'error', 'msg': 'Can not update domain table'}
Example #14
0
    def update(self, domain, content, username):
        """Update single record."""
        headers = {}
        headers['X-API-Key'] = PDNS_API_KEY

        if NEW_SCHEMA:
            data = {
                "rrsets": [{
                    "name":
                    self.name,
                    "type":
                    self.type,
                    "ttl":
                    self.ttl,
                    "changetype":
                    "REPLACE",
                    "records": [{
                        "content": content,
                        "disabled": self.status,
                    }]
                }]
            }
        else:
            data = {
                "rrsets": [{
                    "name":
                    self.name,
                    "type":
                    self.type,
                    "changetype":
                    "REPLACE",
                    "records": [{
                        "content": content,
                        "disabled": self.status,
                        "name": self.name,
                        "ttl": self.ttl,
                        "type": self.type,
                        "priority": 10,
                    }]
                }]
            }
        try:
            url = urlparse.urljoin(
                PDNS_STATS_URL,
                API_EXTENDED_URL + '/servers/localhost/zones/%s' % domain)
            # LOGGING.debug("update dyndns data: %s", data)
            # LOGGING.debug("update dyndns domain: %s", domain)
            current = self.getcurrent_onrecord(domain)
            utils.fetch_json(url, headers=headers, method='PATCH', data=data)
            self.history_write(domain,
                               current,
                               data,
                               'REPLACE',
                               name=self.name,
                               created_by=username)
            LOGGING.debug("update dyndns data: %s", data)
            # LOGGING.debug("update dyndns url: %s", url)
            return {'status': 'ok', 'msg': 'Record was updated successfully'}
        except Exception as e:
            LOGGING.error(
                "Cannot add record %s/%s/%s to domain %s. DETAIL: %s",
                self.name, self.type, self.data, domain, str(e))
            return {
                'status':
                'error',
                'msg':
                'There was something wrong in update, please contact administrator'
            }
Example #15
0
    def apply(self, domain, post_records):
        """Apply record changes to domain."""
        # pylint: disable=R0912,R0915,R0914
        LOGGING.info('apply() domain is %s', (domain))
        records = []
        for r in post_records:
            r_name = domain if r['record_name'] in [
                '@', ''
            ] else r['record_name'] + '.' + domain
            r_type = r['record_type']
            if PRETTY_IPV6_PTR:  # only if activated
                if NEW_SCHEMA:  # only if new schema
                    if r_type == 'PTR':  # only ptr
                        if ':' in r['record_name']:  # dirty ipv6 check
                            r_name = r['record_name']

            record = {
                "name": r_name,
                "type": r_type,
                "content": r['record_data'],
                "disabled":
                True if r['record_status'] == 'Disabled' else False,
                "ttl": int(r['record_ttl']) if r['record_ttl'] else 3600,
            }
            records.append(record)

        deleted_records, new_records = self.compare(domain, records)

        self.records_delete = []
        for r in deleted_records:
            r_name = r['name'].rstrip('.') + '.' if NEW_SCHEMA else r['name']
            r_type = r['type']
            if PRETTY_IPV6_PTR:  # only if activated
                if NEW_SCHEMA:  # only if new schema
                    if r_type == 'PTR':  # only ptr
                        if ':' in r['name']:  # dirty ipv6 check
                            r_name = dns.reversename.from_address(
                                r['name']).to_text()

            record = {
                "name": r_name,
                "type": r_type,
                "changetype": "DELETE",
                "records": [],
            }
            self.records_delete.append(record)

        # postdata_for_delete = {"rrsets": self.records_delete}

        records = []
        for r in new_records:
            if NEW_SCHEMA:
                r_name = r['name'].rstrip('.') + '.'
                r_type = r['type']
                if PRETTY_IPV6_PTR:  # only if activated
                    if r_type == 'PTR':  # only ptr
                        if ':' in r['name']:  # dirty ipv6 check
                            r_name = r['name']

                record = {
                    "name":
                    r_name,
                    "type":
                    r_type,
                    "changetype":
                    "REPLACE",
                    "ttl":
                    r['ttl'],
                    "records": [{
                        "content": r['content'],
                        "disabled": r['disabled'],
                    }]
                }
            else:
                # priority field for pdns 3.4.1.
                # https://doc.powerdns.com/md/authoritative/upgrading/
                record = {
                    "name":
                    r['name'],
                    "type":
                    r['type'],
                    "changetype":
                    "REPLACE",
                    "records": [{
                        "content": r['content'],
                        "disabled": r['disabled'],
                        "name": r['name'],
                        "ttl": r['ttl'],
                        "type": r['type'],
                        "priority": 10,
                    }]
                }

            records.append(record)

        # Adjustment to add multiple records which described in
        # https://github.com/ngoduykhanh/PowerDNS-Admin/issues/5#issuecomment-181637576
        self.fnl_recs = []
        records = sorted(records,
                         key=lambda item:
                         (item["name"], item["type"], item["changetype"]))
        for key, group in itertools.groupby(
                records, lambda item:
            (item["name"], item["type"], item["changetype"])):
            if NEW_SCHEMA:
                r_name = key[0]
                r_type = key[1]
                r_changetype = key[2]

                if PRETTY_IPV6_PTR:  # only if activated
                    if r_type == 'PTR':  # only ptr
                        if ':' in r_name:  # dirty ipv6 check
                            r_name = dns.reversename.from_address(
                                r_name).to_text()

                new_record = {
                    "name": r_name,
                    "type": r_type,
                    "changetype": r_changetype,
                    "ttl": None,
                    "records": [],
                }
                for item in group:
                    temp_content = item['records'][0]['content']
                    temp_disabled = item['records'][0]['disabled']
                    if key[1] in ['MX', 'CNAME', 'SRV', 'NS']:
                        if temp_content.strip()[-1:] != '.':
                            temp_content += '.'

                    if new_record['ttl'] is None:
                        new_record['ttl'] = item['ttl']
                    new_record['records'].append({
                        "content": temp_content,
                        "disabled": temp_disabled
                    })
                self.fnl_recs.append(new_record)

            else:

                self.fnl_recs.append({
                    "name":
                    key[0],
                    "type":
                    key[1],
                    "changetype":
                    key[2],
                    "records": [{
                        "content": item['records'][0]['content'],
                        "disabled": item['records'][0]['disabled'],
                        "name": key[0],
                        "ttl": item['records'][0]['ttl'],
                        "type": key[1],
                        "priority": 10,
                    } for item in group]
                })
        self.final_records_limit()
        postdata_for_changes = {"rrsets": self.net_final}
        LOGGING.info('apply() postdata_for_changes is %s',
                     (json.dumps(postdata_for_changes)))

        try:
            headers = {}
            headers['X-API-Key'] = PDNS_API_KEY
            url = urlparse.urljoin(
                PDNS_STATS_URL,
                API_EXTENDED_URL + '/servers/localhost/zones/%s' % domain)
            # utils.fetch_json(url, headers=headers, method='PATCH', data=postdata_for_delete)
            jdata2 = utils.fetch_json(url,
                                      headers=headers,
                                      method='PATCH',
                                      data=postdata_for_changes)

            if 'error' in jdata2.keys():
                LOGGING.error('Cannot apply record changes.')
                LOGGING.debug(jdata2['error'])
                return {'status': 'error', 'msg': jdata2['error']}
            else:
                # should this get postdata_for_changes ??? instead of the deprecated new_records, deleted_records
                # postdata_for_changes is final_records_limit
                if not re.search('in-addr.arpa', domain):
                    self.auto_ptr(domain)

                LOGGING.debug("update dyndns data: %s", postdata_for_changes)
                LOGGING.debug("update dyndns url: %s", url)

                LOGGING.info('Record was applied successfully.')
                self.history_log_apply(domain)
                return {
                    'status': 'ok',
                    'msg': 'Record was applied successfully'
                }

        except Exception as error:
            LOGGING.error(
                "Cannot apply record changes to domain %s. DETAIL: %s",
                str(error), domain)
            return {
                'status': 'error',
                'msg':
                'There was something wrong, please contact administrator'
            }
Example #16
0
    def add(self, domain, created_by=None):
        """Add a record to domains."""
        # validate record first
        rec = self.get_record_data(domain)
        # pylint: disable=W0110
        records = rec['records']
        check = filter(lambda check: check['name'] == self.name, records)
        if check:
            # pylint: disable=E1136
            rec = check[0]
            if rec['type'] in ('A', 'AAAA', 'CNAME'):
                return {
                    'status': 'error',
                    'msg':
                    'Record already exists with type "A", "AAAA" or "CNAME"'
                }

        # continue if the record is ready to be added
        headers = {}
        headers['X-API-Key'] = PDNS_API_KEY

        if NEW_SCHEMA:
            data = {
                "rrsets": [{
                    "name":
                    self.name.rstrip('.') + '.',
                    "type":
                    self.type,
                    "changetype":
                    "REPLACE",
                    "ttl":
                    self.ttl,
                    "records": [{
                        "content": self.data,
                        "disabled": self.status,
                    }]
                }]
            }
        else:
            data = {
                "rrsets": [{
                    "name":
                    self.name,
                    "type":
                    self.type,
                    "changetype":
                    "REPLACE",
                    "records": [{
                        "content": self.data,
                        "disabled": self.status,
                        "name": self.name,
                        "ttl": self.ttl,
                        "type": self.type
                    }]
                }]
            }

        try:
            url = urlparse.urljoin(
                PDNS_STATS_URL,
                API_EXTENDED_URL + '/servers/localhost/zones/%s' % domain)
            LOGGING.debug('add data to pdns server %s', data)
            current = self.getcurrent_onrecord(domain)
            LOGGING.debug('rec.add() current "%s" "%s" "%s"', current, domain,
                          self.name)
            jdata = utils.fetch_json(url,
                                     headers=headers,
                                     method='PATCH',
                                     data=data)
            LOGGING.debug('fetch_json result %s', jdata)
            self.history_write(domain,
                               current,
                               data['rrsets'],
                               'REPLACE',
                               name=self.name,
                               created_by=created_by)
            return {'status': 'ok', 'msg': 'Record was added successfully'}
        except Exception as e:
            LOGGING.error(
                "Cannot add record %s/%s/%s to domain %s. DETAIL: %s",
                self.name, self.type, self.data, domain, str(e))
            return {
                'status':
                'error',
                'msg':
                'There was something wrong in Add, please contact administrator'
            }