Пример #1
0
def domain_info(aDict):
 """Function docstring for domain_info TBD

 Args:
  - id (required)
  - type (required)
  - master (required)
  - name (required)
  - server_id (optional)

 Output:
 """
 ret = {'id':aDict['id']}
 args = aDict
 with DB() as db:
  if args['id'] == 'new' and not (args.get('op') == 'update'):
   db.do("SELECT id, server, node FROM servers WHERE type = 'DNS'")
   ret['servers'] = db.get_rows()
   ret['data'] = {'id':'new','name':'new-name','master':'ip-of-master','type':'MASTER', 'notified_serial':0 }
  else:
   if args['id'] == 'new':
    db.do("SELECT id, 'new' AS foreign_id, server, node FROM servers WHERE id = %s"%args.pop('server_id','0'))
   else:
    db.do("SELECT servers.id, foreign_id, server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id WHERE domains.id = %s"%args['id'])
   ret['infra'] = db.get_row()
   args['id']   = ret['infra'].pop('foreign_id',None)
   ret.update(node_call(ret['infra']['node'],ret['infra']['server'],'domain_info',args))
   if str(ret.get('insert',0)) == '1':
    ret['cache'] = db.insert_dict('domains',{'name':args['name'],'server_id':ret['infra']['id'],'foreign_id':ret['data']['id']})
    ret['id'] = db.get_last_id() 
 return ret
Пример #2
0
def record_info(aDict):
 """Function docstring for record_info TBD

 Args:
  - id (required)
  - domain_id (required)

  - name (optional)
  - content (optional)
  - type (optional)

 Output:
 """
 ret = {}
 args = aDict
 domain_id = aDict['domain_id']

 with DB() as db:
  if aDict['id'] == 'new' and not (aDict.get('op') == 'update'):
   ret['data'] = {'id':'new','domain_id':domain_id,'name':'key','content':'value','type':'type-of-record','ttl':'3600','foreign_id':'NA'}
  else:
   db.do("SELECT foreign_id, server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id WHERE domains.id = %s"%domain_id)
   infra = db.get_row()
   args['domain_id'] = infra['foreign_id']
   ret = node_call(infra['node'],infra['server'],'record_info',args)
   ret['data']['domain_id']  = domain_id
 return ret
Пример #3
0
def sync(aDict):
    """Function docstring for sync:  reload the DHCP server to use updated info

 Args:
  - id (required). Server id on master node

 Output:
 """
    from zdcp.SettingsContainer import SC
    from zdcp.core.common import node_call
    entries = node_call('master', 'device', 'server_macs', {'id': aDict['id']})
    # Create file
    with open(SC['iscdhcp']['static'], 'w') as leasefile:
        for entry in entries['data']:
            leasefile.write(
                "host {0: <30} {{ hardware ethernet {1}; fixed-address {2}; }} # Id: {3}, Network: {4}\n"
                .format("%(hostname)s.%(domain)s" % entry, entry['mac'],
                        entry['ip'], entry['id'], entry['network']))

    # Reload
    from subprocess import check_output, CalledProcessError
    ret = {}
    try:
        ret['output'] = check_output(SC['iscdhcp']['reload'].split())
    except CalledProcessError as c:
        ret['code'] = c.returncode
        ret['output'] = c.output

    ret['result'] = 'NOT_OK' if ret['output'] else 'OK'
    return ret
Пример #4
0
def domain_list(aDict):
 """Function docstring for domain_list.

 Args:
  - filter (optional)
  - dict (optional)
  - sync (optional)
  - exclude (optional)

 Output:
  - filter:forward/reverse
 """
 ret = {}
 with DB() as db:
  if aDict.get('sync'):
   org = {}
   db.do("SELECT id, server, node FROM servers WHERE type = 'DNS'")
   servers = db.get_rows()
   for server in servers:
    org[server['id']] = node_call(server['node'],server['server'],'domain_list')['domains']
   ret.update({'sync':{'added':[],'deleted':[],'type_fix':0}})
   db.do("SELECT domains.*, CONCAT(server_id,'_',foreign_id) AS srv_id FROM domains")
   cache = db.get_dict('srv_id')
   for srv,domains in org.iteritems():
    for dom in domains:
     tmp = cache.pop("%s_%s"%(srv,dom['id']),None)
     if not tmp:
      ret['sync']['added'].append(dom)
      # Add forward here
      db.insert_dict('domains',{'name':dom['name'],'server_id':srv,'foreign_id':dom['id'],'type':'reverse' if 'arpa' in dom['name'] else 'forward'},"ON DUPLICATE KEY UPDATE name = '%s'"%dom['name'])
     else:
      ret['sync']['type_fix'] += db.do("UPDATE domains SET type = '%s' WHERE id = %s"%('reverse' if 'arpa' in dom['name'] else 'forward',tmp['id']))
   for id,dom in cache.iteritems():
    dom.pop('srv_id',None)
    ret['sync']['deleted'].append(dom)
    db.do("DELETE FROM domains WHERE id = '%s'"%dom['id'])

  filter = []
  if aDict.get('filter'):
   filter.append("domains.type = '%s'"%aDict.get('filter'))
  if aDict.get('exclude'):
   db.do("SELECT server_id FROM domains WHERE id = '%s'"%(aDict.get('exclude')))
   filter.append('server_id = %s'%(db.get_val('server_id')))
   filter.append("domains.id <> '%s'"%aDict.get('exclude'))

  ret['count']   = db.do("SELECT domains.*, server FROM domains LEFT JOIN servers ON domains.server_id = servers.id WHERE %s ORDER BY name"%('TRUE' if len(filter) == 0 else " AND ".join(filter)))
  ret['domains'] = db.get_rows() if not aDict.get('dict') else db.get_dict(aDict.get('dict'))
 return ret
Пример #5
0
def record_delete(aDict):
 """Function docstring for record_delete TBD

 Args:
  - id (required)
  - domain_id (required)

 Output:
 """
 args = aDict
 with DB() as db:
  db.do("SELECT foreign_id, server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id WHERE domains.id = %s"%args['domain_id'])
  infra = db.get_row()
 args['domain_id'] = infra['foreign_id']
 ret = node_call(infra['node'],infra['server'],'record_delete',args)
 return ret
Пример #6
0
def domain_save(aDict):
 """Function saves state and records for a domain, for dynamic DNS servers this is a No OP

 Args:
  - id (required)

 Output:
  - result
 """
 ret = {}
 id = aDict['id']
 with DB() as db:
  db.do("SELECT foreign_id, server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id WHERE domains.id = %s"%id)
  infra = db.get_row()
  ret = node_call(infra['node'],infra['server'],'domain_save',{'id':infra['foreign_id']})
 return {'result':ret['result']}
Пример #7
0
def domain_delete(aDict):
 """Function domain_delete deletes a domain from local cache and remote DNS server. All records will be transferred to default (0) domain.

 Args:
  - id (required)

 Output:
 """
 ret = {}
 id = int(aDict['id'])
 with DB() as db:
  db.do("SELECT foreign_id, server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id WHERE domains.id = %i"%id)
  infra = db.get_row()
  ret = node_call(infra['node'],infra['server'],'domain_delete',{'id':infra['foreign_id']})
  ret['local'] = db.do("UPDATE devices SET a_dom_id = 0 WHERE a_dom_id = %i"%id)
  ret['cache'] = db.do("DELETE FROM domains WHERE id = %i"%id) if ret['domain'] else 0
 return ret
Пример #8
0
def server_sync(aDict):
    """Server sync sends sync message to server @ node and convey result. What sync means is server dependent

 Args:
  - id (required):

 Output:
 """
    ret = {}
    with DB() as db:
        ret['found'] = (db.do("SELECT node,server FROM servers WHERE id = %s" %
                              aDict['id']) == 1)
        if ret['found']:
            from zdcp.core.common import node_call
            data = db.get_row()
            ret['result'] = node_call(data['node'], data['server'], 'sync',
                                      {'id': aDict['id']})
    return ret
Пример #9
0
def server_leases(aDict):
 """Server_leases returns free or active server leases for DHCP servers

 Args:
  - type (required). active/free

 Output:
 """
 from zdcp.core.common import node_call
 ret = {'data':[]}
 with DB() as db:
  ret['servers'] = db.do("SELECT server,node FROM servers WHERE type = 'DHCP'")
  servers = db.get_rows()
 for srv in servers:
  data = node_call(srv['node'],srv['server'],'leases',{'type':aDict['type']})['data']
  if data:
   ret['data'].extend(data)
 return ret
Пример #10
0
def top(aDict):
 """Function docstring for top TBD

 Args:
  - count (optional)

 Output:
 """
 ret = {'top':{},'who':{}}
 args = {'count':aDict.get('count',20)}
 with DB() as db: 
  db.do("SELECT server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id")
  servers = db.get_rows()
 for infra in servers:
  res = node_call(infra['node'],infra['server'],'top',args)
  ret['top']["%(node)s_%(server)s"%infra] = res['top']
  ret['who']["%(node)s_%(server)s"%infra] = res['who']
 return ret
Пример #11
0
def record_device_delete(aDict):
 """Function docstring for record_device_delete TBD

 Args:
  - a_id (optional) - id/0
  - ptr_id (optional) - id/0
  - a_domain_id (optional required)
  - ptr_domain_id (optional required)

 Output:
 """
 ret = {'A':0,'PTR':0}
 with DB() as db:
  for tp in ['a','ptr']:
   domain_id = aDict.get('%s_domain_id'%tp)
   id = str(aDict.get('%s_id'%tp,'0'))
   if domain_id > 0 and id != '0':
    db.do("SELECT foreign_id, server, node FROM domains LEFT JOIN servers ON domains.server_id = servers.id WHERE domains.id = '%s'"%(domain_id))
    infra = db.get_row()
    args = {'id':id,'domain_id':infra['foreign_id']}
    ret[tp.upper()] = node_call(infra['node'],infra['server'],'record_delete',args)['deleted']
 return ret
Пример #12
0
def record_list(aDict):
 """Function docstring for record_list TBD

 Args:
  - type (optional)
  - domain_id (required), <B>use cached one</B>

 Output:
 """
 args = aDict
 with DB() as db:
  if aDict.get('domain_id'):
   db.do("SELECT foreign_id, server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id WHERE domains.id = %s"%aDict['domain_id'])
   infra = db.get_row()
   args['domain_id'] = infra['foreign_id']
  else:
   # Strictly internal use - this one fetch all records for consistency check
   id = aDict.pop('server_id','0')
   db.do("SELECT server, node FROM servers WHERE id = %s"%id)
   infra = db.get_row()
 ret = node_call(infra['node'],infra['server'],'record_list',args)
 ret['domain_id'] = aDict.get('domain_id',0)
 return ret
Пример #13
0
def record_device_create(aDict):
 """Function docstring for record_device_create. The function actually only creates records for an existing device, and update the device..
 It does not expect 'overlapping' reverse or forwarding zones - hence bypassing IPAM's PTR registration and does lookup for first available reverse record

 Args:
  - device_id (required)
  - ip (required)
  - type (required)
  - domain_id (required)
  - fqdn (required)

 Output:
 """
 ret = {}
 args = {'op':'update','id':'new','type':aDict['type'].upper()}
 if args['type'] == 'A':
  args['name'] = aDict['fqdn']
  args['content'] = aDict['ip']
 elif args['type'] == 'PTR':
  def GL_ip2ptr(addr):
   octets = addr.split('.')
   octets.reverse()
   octets.append("in-addr.arpa")
   return ".".join(octets)
  args['name'] = GL_ip2ptr(aDict['ip'])
  args['content'] = aDict['fqdn']

 with DB() as db:
  db.do("SELECT foreign_id, server, node FROM servers LEFT JOIN domains ON domains.server_id = servers.id WHERE domains.id = %s"%aDict['domain_id'])
  infra = db.get_row()
  args['domain_id'] = infra['foreign_id']
  ret['record'] = node_call(infra['node'],infra['server'],'record_info',args)
  opres = str(ret['record'].get('update')) == "1" or str(ret['record'].get('insert')) == "1"
  if opres and (args['type'] in ['A','PTR']):
   ret['device'] = {'id':aDict['device_id']}
   ret['device']['update'] = db.do("UPDATE devices SET %s_id = '%s' WHERE id = %s"%(aDict['type'].lower(),ret['record']['data']['id'],aDict['device_id']))
 return ret
Пример #14
0
def record_device_update(aDict):
 """Function docstring for record_device_update. Tries to update DNS server with new info and fetch A and PTR id if they exist... (None, A, A + PTR)
  "Tricky" part is when device MOVED from one domain to another AND this means server change, then we need to do delete first on old server. If IP address changed PTR might have moved.

 Args:
  - id (required)     - id/new. ID is used to detect if moving device between domains... i.e. to fetch old info
  - a_id (required)   - id/0/new
  - ptr_id (required) - id/0/new
  - hostname (required)

  - ip_old (required)
  - ip_new (required)
  - a_domain_id_old (required)
  - a_domain_id_new (required)

 Output:
 """
 ret  = {'A':{'found':False,'record_id':0,'domain_id':aDict['a_domain_id_new']},'PTR':{'found':False,'record_id':0},'device':{'found':False},'server':{}}
 aDict['a_domain_id_old'] = int(aDict['a_domain_id_old'])
 aDict['a_domain_id_new'] = int(aDict['a_domain_id_new'])
 data = {}

 def GL_ip2ptr(addr):
  octets = addr.split('.')
  octets.reverse()
  octets.append("in-addr.arpa")
  return ".".join(octets)

 with DB() as db:
  domains = {'name':{},'foreign_id':{}}
  db.do("SELECT domains.id AS domain_id, server_id, foreign_id, name, server, node FROM domains LEFT JOIN servers ON domains.server_id = servers.id")
  domains['id']   = db.get_dict('domain_id')
  for dom in domains['id'].values():
   domains['name'][dom['name']] = dom
   domains['foreign_id'][dom['foreign_id']] = dom

  #
  # A record: check if valid domain, then if not a_id == 'new' check if we moved to new server, if so delete record and set a_id to new
  #
  a_id  = 'new' if str(aDict['a_id']) == '0' else aDict['a_id']
  infra = domains['id'].get(aDict['a_domain_id_new'],None)

  if not infra:
   return ret

  if a_id != 'new':
   old = domains['id'].get(aDict['a_domain_id_old'],None)
   if old['server_id'] != infra['server_id']:
    ret['server']['A'] = node_call(old['node'],old['server'],'record_delete',{'id':a_id})
    a_id = 'new'
   else:
    ret['server']['A'] = 'remain'
  fqdn  = "%s.%s"%(aDict['hostname'], infra['name'])
  data['A']= {'server':infra['server'], 'node':infra['node'], 'domain_id':infra['domain_id'],'args':{'type':'A','id':a_id, 'domain_id':infra['foreign_id'], 'content':aDict['ip_new'], 'name':fqdn}}

  #
  # PTR record:  check if valid domain, then check if moved to new server, if so record and set ptr_id to new
  #
  ptr_id = 'new' if str(aDict['ptr_id']) == '0' else aDict['ptr_id']
  ptr  = GL_ip2ptr(aDict['ip_new'])
  arpa = ptr.partition('.')[2]
  infra = domains['name'].get(arpa,None)
  if infra and fqdn:
   if ptr_id != 'new':
    old_ptr  = GL_ip2ptr(aDict['ip_old'])
    old_arpa = ptr.partition('.')[2]
    old = domains['name'].get(old_arpa,None)
    if old['server_id'] != infra['server_id']:
     ret['server']['PTR'] = node_call(old['node'],old['server'],'record_delete',{'id':ptr_id})
     ptr_id = 'new'
    else:
     ret['server']['PTR'] = 'remain'
   data['PTR']= {'server':infra['server'], 'node':infra['node'], 'domain_id':infra['domain_id'], 'args':{'type':'PTR','id':ptr_id, 'domain_id':infra['foreign_id'], 'content':fqdn, 'name':ptr}}

 for type,infra in data.iteritems():
  if infra['server']:
   infra['args']['op'] = 'update'
   res = node_call(infra['node'],infra['server'],'record_info',infra['args'])
   if not res['found']:
    # real 'op' should be insert as we now reset the record id to create new one
    infra['args']['id'] = 'new'
    res = node_call(infra['node'],infra['server'],'record_info',infra['args'])
   if res['found']:
    ret[type]['found']     = True
    ret[type]['record_id'] = res['data']['id']
    ret[type]['domain_id'] = domains['foreign_id'].get(res['data']['domain_id'],{'domain_id':0})['domain_id']
    ret[type]['update']    = res.get('update',False)
    ret[type]['insert']    = res.get('insert',False)
 return ret