[28848] in Source-Commits

home help back first fref pref prev next nref lref last post

moira commit [debian]: More testing.

daemon@ATHENA.MIT.EDU (Anders Kaseorg)
Wed Apr 25 23:50:22 2018

Date: Wed, 25 Apr 2018 23:49:59 -0400
From: Anders Kaseorg <andersk@mit.edu>
Message-Id: <201804260349.w3Q3nxqr025362@drugstore.mit.edu>
To: source-commits@mit.edu

https://github.com/mit-athena/moira/commit/1ba690ff4c45305d705b477a020a3f3a18c1cd45
commit 1ba690ff4c45305d705b477a020a3f3a18c1cd45
Author: Garry Zacheiss <zacheiss@mit.edu>
Date:   Mon Sep 25 16:42:31 2017 -0400

    More testing.

 moira/clients/stella/stella.c            |   77 +++++++++-----
 moira/incremental/infoblox/infoblox.incr |  166 +++++++++++++++++++-----------
 moira/man/stella.1                       |    2 +-
 moira/server/mr_server.h                 |    4 +-
 moira/server/qaccess.pc                  |   33 ++++++
 moira/server/qsetup.pc                   |   24 ++++-
 moira/server/qsupport.pc                 |  122 ++++++++++++++++++++++
 moira/server/queries2.c                  |   34 ++++++
 8 files changed, 367 insertions(+), 95 deletions(-)

diff --git a/moira/clients/stella/stella.c b/moira/clients/stella/stella.c
index 0f68bd5..48face2 100644
--- a/moira/clients/stella/stella.c
+++ b/moira/clients/stella/stella.c
@@ -55,7 +55,7 @@ int list_container_flag, update_container_flag, unformatted_flag;
 int list_identifier_flag, update_identifier_flag;
 int list_resource_records_flag, update_resource_records_flag;
 int set_host_opt_flag, set_ttl_flag, set_ptr_flag;
-int add_dynamic_host_flag, show_host_usage_flag;
+int add_dynamic_host_flag, show_host_usage_flag, upgrade_priv_addr_flag;
 
 struct string_list *alias_add_queue, *alias_remove_queue;
 struct string_list *address_add_queue, *address_remove_queue;
@@ -105,6 +105,7 @@ int main(int argc, char **argv)
   list_container_flag = update_container_flag = list_resource_records_flag = 0;
   list_identifier_flag = update_identifier_flag = show_host_usage_flag = 0;
   set_host_opt_flag = set_ttl_flag = set_ptr_flag = add_dynamic_host_flag = 0;
+  upgrade_priv_addr_flag = 0;
   newname = address = network = h_status = vendor = model = NULL;
   os = location = contact = billing_contact = account_number = adm_cmt = NULL;
   op_cmt = opt = NULL;
@@ -384,6 +385,8 @@ int main(int argc, char **argv)
 	    list_resource_records_flag++;
 	  else if (argis("su", "showusage"))
 	    show_host_usage_flag++;
+	  else if (argis("up4", "upgradeprivaddr"))
+	    upgrade_priv_addr_flag++;
 	  else if (argis("adh", "adddynamic")) {
 	    add_dynamic_host_flag++;
             if (arg - argv < argc - 1) {
@@ -439,7 +442,7 @@ int main(int argc, char **argv)
        update_alias_flag || update_address_flag || update_container_flag || \
        list_container_flag || update_identifier_flag || list_identifier_flag || \
        update_resource_records_flag || list_resource_records_flag || set_host_opt_flag || \
-       set_ttl_flag || set_ptr_flag || add_dynamic_host_flag || show_host_usage_flag)) {
+       set_ttl_flag || set_ptr_flag || add_dynamic_host_flag || show_host_usage_flag || upgrade_priv_addr_flag)) {
     info_flag++;
   }
 
@@ -448,7 +451,7 @@ int main(int argc, char **argv)
 				update_alias_flag || update_address_flag || update_container_flag || \
 				list_container_flag || update_identifier_flag || list_resource_records_flag || \
 				update_resource_records_flag || list_identifier_flag || set_host_opt_flag || \
-				set_ttl_flag || set_ptr_flag ||	show_host_usage_flag))
+				set_ttl_flag || set_ptr_flag ||	show_host_usage_flag || upgrade_priv_addr_flag))
     {
       com_err(whoami, 0, "-adh / -adddynamic option must be the only argument provided.");
       exit(1);
@@ -719,8 +722,9 @@ int main(int argc, char **argv)
     }
   }
 
-  if (address_add_queue) {
-    struct string_list *q = address_add_queue;
+  /* Need to process address removals first */
+  if (address_remove_queue) {
+    struct string_list *q = address_remove_queue;
 
     while (q) {
       /* string is of the form network:address */
@@ -729,27 +733,26 @@ int main(int argc, char **argv)
 
       netaddr = mrcl_parse_netaddr(q->string);
       if (!netaddr)
-	{
-	  com_err(whoami, 0, "Could not parse network address specification while adding host address.");
-	  exit(1);
-	}
+        {
+          com_err(whoami, 0, "Could not parse network address specification while removing host address.");
+          exit(1);
+        }
 
       args[0] = canonicalize_hostname(strdup(hostname));
       args[1] = netaddr->network;
       args[2] = netaddr->address;
 
-      status = wrap_mr_query("add_host_address", 3, args, NULL, NULL);
+      status = wrap_mr_query("delete_host_address", 3, args, NULL, NULL);
       if (status) {
-	com_err(whoami, status, "while adding host address");
-	exit(1);
+        com_err(whoami, status, "while removing host address");
+        exit(1);
       }
-
       q = q->next;
     }
   }
 
-  if (address_remove_queue) {
-    struct string_list *q = address_remove_queue;
+  if (address_add_queue) {
+    struct string_list *q = address_add_queue;
 
     while (q) {
       /* string is of the form network:address */
@@ -759,7 +762,7 @@ int main(int argc, char **argv)
       netaddr = mrcl_parse_netaddr(q->string);
       if (!netaddr)
 	{
-	  com_err(whoami, 0, "Could not parse network address specification while removing host address.");
+	  com_err(whoami, 0, "Could not parse network address specification while adding host address.");
 	  exit(1);
 	}
 
@@ -767,11 +770,12 @@ int main(int argc, char **argv)
       args[1] = netaddr->network;
       args[2] = netaddr->address;
 
-      status = wrap_mr_query("delete_host_address", 3, args, NULL, NULL);
+      status = wrap_mr_query("add_host_address", 3, args, NULL, NULL);
       if (status) {
-	com_err(whoami, status, "while removing host address");
+	com_err(whoami, status, "while adding host address");
 	exit(1);
       }
+
       q = q->next;
     }
   }
@@ -1102,6 +1106,21 @@ int main(int argc, char **argv)
 	}
     }
 
+  /* upgrade private address */
+  if (upgrade_priv_addr_flag)
+    {
+      char *argv[1];
+
+      argv[0] = canonicalize_hostname(strdup(hostname));
+
+      status = wrap_mr_query("upgrade_host_private_ipv4_addr", 1, argv, NULL, NULL);
+      if (status)
+	if (status != MR_NO_MATCH) {
+	  com_err(whoami, status, "while upgrading host private IPv4 address");
+	  exit(1);
+	}
+    }
+
   if (set_host_opt_flag) {
     char *argv[3];
 
@@ -1310,7 +1329,9 @@ void usage(char **argv)
   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-arr | -addrecord record",
 	  "-drr | -delrecord record");
   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-lrr | -listrecords",
-	  "-db  | -database host[:port]");
+	  "-up4  | -upgradeprivaddr");
+  fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db  | -database host[:port]",
+	  "");
   exit(1);
 }
 
@@ -1344,10 +1365,8 @@ int show_address_info(int argc, char **argv, void *hint)
 {
   char tbuf[BUFSIZ];
 
-  sprintf(tbuf, "%s:%s", argv[2], argv[3]);
-  printf("Address:  %-16s    Network:    %-16s", tbuf, argv[1]);
-  if (atoi(argv[5]) == 1)
-    printf("    PTR record: yes");
+  sprintf(tbuf, "%s:%s%s", argv[2], argv[3], atoi(argv[5]) == 1 ? "*" : "");
+  printf("Address:  %-24s    Network:    %-16s", tbuf, argv[1]);
   if (atoi(argv[4]) != DEFAULT_TTL)
     printf("    DNS TTL:  %-16s", argv[4]);
   printf("\n");
@@ -1445,17 +1464,17 @@ void show_host_info(char **argv)
 
   sprintf(tbuf, "%s %s", argv[M_OWNER_TYPE],
           strcmp(argv[M_OWNER_TYPE], "NONE") ? argv[M_OWNER_NAME] : "");
-  printf("Owner:    %-16s    Use data:   %s\n", tbuf, argv[M_INUSE]);
-  printf("Status:   %-16s    Changed:    %s\n",
+  printf("Owner:    %-24s    Use data:   %s\n", tbuf, argv[M_INUSE]);
+  printf("Status:   %-24s    Changed:    %s\n",
           MacState(atoi(argv[M_STAT])), argv[M_STAT_CHNG]);
   printf("\n");
-  printf("Vendor:   %-16s    Location:        %s\n", argv[M_VENDOR], 
+  printf("Vendor:   %-24s    Location:        %s\n", argv[M_VENDOR], 
 	 argv[M_LOC]);
-  printf("Model:    %-16s    Contact:         %s\n", argv[M_MODEL], 
+  printf("Model:    %-24s    Contact:         %s\n", argv[M_MODEL], 
 	 argv[M_CONTACT]);
-  printf("OS:       %-16s    Billing Contact: %s\n", argv[M_OS], 
+  printf("OS:       %-24s    Billing Contact: %s\n", argv[M_OS], 
 	 argv[M_BILL_CONTACT]);
-  printf("Opt:      %-16s    Account Number:  %s\n", argv[M_USE],
+  printf("Opt:      %-24s    Account Number:  %s\n", argv[M_USE],
 	 argv[M_ACCT_NUMBER]);
   printf("\nAdm cmt: %s\n", argv[M_ACOMMENT]);
   printf("Op cmt:  %s\n", argv[M_OCOMMENT]);
diff --git a/moira/incremental/infoblox/infoblox.incr b/moira/incremental/infoblox/infoblox.incr
index 6fe4de6..12e3550 100755
--- a/moira/incremental/infoblox/infoblox.incr
+++ b/moira/incremental/infoblox/infoblox.incr
@@ -125,9 +125,6 @@ def mach_to_ib(record):
     
     ib_host_record = {
         'name' : record[0].lower(),
-        'ttl' : default_ttl,
-        'use_ttl' : False,
-        'disable' : False,
         'extattrs' : extattrs
         }
 
@@ -196,9 +193,12 @@ def ib_create_host(record, myviews=None):
         log('ib_search_by_name returned error, aborting')
         return
 
-    # For creation, use dummy IPs.
+    # For creation, use dummy v4 IP and default TTL.
     ib_record['ipv4addrs'] = [ { 'ipv4addr' : '0.0.0.0' } ]
     ib_record['ipv6addrs'] = [ ]
+    ib_record['ttl'] = default_ttl
+    ib_record['use_ttl'] = False
+    ib_record['disable'] = True
 
     if myviews == None:
         myviews = views
@@ -279,7 +279,7 @@ def ib_update_host(before, after):
             critical_log('Record already exists in view %s for new name %s, old name %s' % (view, before_record['name'], after_record['name']))
         elif len(mach_id_results[view]) == 0:
             log('No record exists for mach id %s in view %s, creating' % (moira_mach_id, view))
-            ib_create_host(after)
+            ib_create_host(after, myviews=view)
         elif len(mach_id_results[view]) > 1:
             critical_log('Mutiple records exist for mach_id %s in view %s, should not happen!' % (moira_mach_id, view))
         elif mach_id_results[view][0]['extattrs']['moira_managed']['value'] != 1:
@@ -536,7 +536,11 @@ def ib_add_host_duid(record):
         else:
             search_result = search_results[view][0]
 
-            ipv6addrs = [ { 'ipv6addr' : search_result['ipv6addrs'][0]['ipv6addr'] } ]
+            if 'ipv6addrs' in search_result and 'ipv6addr' in search_result['ipv6addrs'][0]:
+                ipv6addrs = [ { 'ipv6addr' : search_result['ipv6addrs'][0]['ipv6addr'] } ]
+            else:
+                ipv6addrs = [ {} ]
+
             ipv6addrs[0]['duid'] = id_value
             ipv6addrs[0]['configure_for_dhcp'] = True
 
@@ -593,7 +597,7 @@ def ib_add_host_mac(record):
             log('Added %s %s to host %s in view %s: %s' % (id_type, id_value, ib_record['name'], view, r.text))
 
 def ib_add_host_ipv4_address(record):
-    ib_record = { 'name' : record[0].lower() }
+    ib_record = { 'name' : record[0].lower(), 'disable' : False }
 
     ttl = int(record[4])
     if ttl == default_ttl:
@@ -626,7 +630,7 @@ def ib_add_host_ipv4_address(record):
 
             ipv4addrs = [ { 'ipv4addr' : address } ]
             # preserve MAC address if assigned.
-            if 'mac' in search_result['ipv4addrs'][0]:
+            if 'ipv4addrs' in search_result and 'mac' in search_result['ipv4addrs'][0]:
                 ipv4addrs[0]['mac'] = search_result['ipv4addrs'][0]['mac']
                 ipv4addrs[0]['configure_for_dhcp'] = True
 
@@ -644,7 +648,7 @@ def ib_add_host_ipv4_address(record):
             log('Added IPv4 address %s to host %s in view %s: %s' % (address, ib_record['name'], view, r.text))
 
 def ib_add_host_ipv6_address(record):
-    ib_record = { 'name' : record[0].lower() }
+    ib_record = { 'name' : record[0].lower(), 'disable' : False }
 
     ttl = int(record[4])
     if ttl == default_ttl:
@@ -683,6 +687,10 @@ def ib_add_host_ipv6_address(record):
 
             ib_record['ipv6addrs'] = ipv6addrs
 
+            # Handle v6 only case; if v4 address is set to 0.0.0.0, set it to empty array.
+            if 'ipv4addrs' in search_result and search_result['ipv4addrs'][0]['ipv4addr'] == '0.0.0.0':
+                ib_record['ipv4addrs'] = []
+
             ib_ref = search_result['_ref']
             ib_url = ib_base_url + '/' + ib_ref
             headers = { 'Content-Type' : 'application/json' }
@@ -1091,7 +1099,10 @@ def ib_delete_host_duid(record):
         else:
             search_result = search_results[view][0]
 
-            ipv6addrs = [ { 'ipv6addr' : search_result['ipv6addrs'][0]['ipv6addr'] } ]
+            if 'ipv6addrs' in search_result and 'ipv6addr' in search_result['ipv6addrs'][0]:
+                ipv6addrs = [ { 'ipv6addr' : search_result['ipv6addrs'][0]['ipv6addr'] } ]
+            else:
+                ipv6addrs = [ {} ]
 
             if 'duid' in search_result['ipv6addrs'][0]:
                 if search_result['ipv6addrs'][0]['duid'] == id_value:
@@ -1178,11 +1189,16 @@ def ib_delete_host_ipv4_address(record):
             # exactly one result, as expected.
             search_result = search_results[view][0]
 
-            ipv4addrs = [ { 'ipv4addr' : '0.0.0.0' } ]
-            # preserve MAC address if assigned.
-            if 'mac' in search_result['ipv4addrs'][0]:
-                ipv4addrs[0]['mac'] = search_result['ipv4addrs'][0]['mac']
-                ipv4addrs[0]['configure_for_dhcp'] = True
+            # Do we still have a v6 address assigned?
+            if 'ipv6addrs' in search_result and search_result['ipv6addrs'][0]['ipv6addr'] != '::':
+                ipv4addrs = []
+            else:
+                ipv4addrs = [ { 'ipv4addr' : '0.0.0.0' } ]
+                # preserve MAC address if assigned.
+                if 'mac' in search_result['ipv4addrs'][0]:
+                    ipv4addrs[0]['mac'] = search_result['ipv4addrs'][0]['mac']
+                    ipv4addrs[0]['configure_for_dhcp'] = True
+                    ib_record['disable'] = True
 
             ib_record['ipv4addrs'] = ipv4addrs
 
@@ -1219,18 +1235,26 @@ def ib_delete_host_ipv6_address(record):
             ipv6addrs = [ ]
             # preserve DUID if assigned.
             if 'ipv6addrs' in search_result and 'duid' in search_result['ipv6addrs'][0]:
+                ipv6addrs[0] = {}
                 ipv6addrs[0]['duid'] = search_result['ipv6addrs'][0]['duid']
                 ipv6addrs[0]['configure_for_dhcp'] = True
                           
             ib_record['ipv6addrs'] = ipv6addrs
 
+            # Do we still have a valid v4 address?
+            if 'ipv4addrs' not in search_result:
+                ib_record['ipv4addrs'] = [ { 'ipv4addr' : '0.0.0.0' } ]
+                ib_record['disable'] = True
+            elif 'ipv4addrs' in search_result and search_result['ipv4addrs'][0]['ipv4addr'] == '0.0.0.0':
+                ib_record['disable'] = True
+
             ib_ref = search_result['_ref']
             ib_url = ib_base_url + '/' + ib_ref
             headers = { 'Content-Type' : 'application/json' }
 
             r = requests.put(ib_url, data=json.dumps(ib_record), headers=headers, auth=(ib_user, ib_passwd))
             if r.status_code != requests.codes.ok:
-                critical_log('Infoblox API call failed in ib_delete_host_ipv6_address for name %s address %s view %s' % (ib_record['name'], address, view))
+                critical_log('Infoblox API call failed in ib_delete_host_ipv6_address for name %s address %s view %s with HTTP return %s: %s' % (ib_record['name'], address, view, r.status_code, r.text))
                 continue
 
             log('Deleted IPv6 address %s for host %s in view %s: %s' % (address, ib_record['name'], view, r.text))
@@ -1577,31 +1601,33 @@ def do_machine(before, after):
                                 ib_add_aaaa_record(record)
 
                     # host records
-                    for record in get_moira_host_records(hostname):
+                    for record in get_moira_hostrecords(hostname):
                         ib_add_hostrecord(record)
 
                     # mach identifiers
-                    for record in get_moira_mach_identifiers(hostname):
+                    for record in get_moira_host_identifiers(hostname):
                         ib_add_host_identifier(record)
                 else:
                     for record in get_moira_hostaliases(hostname):
                         ib_add_cname(record)
 
             else:
-                # active before and after, update host record
-                ib_update_host(before, after)
-
-                # If hostname changed, need to handle other bits of information
+                # active before and after
                 before_hostname = before[0]
                 after_hostname = after[0]
 
-                if before_hostname != after_hostname:
+                canon_before = canonical_for_hostname(before_hostname)
+                canon_after = canonical_for_hostname(after_hostname)
 
-                    canon_before = canonical_for_hostname(before_hostname)
-                    canon_after = canonical_for_hostname(after_hostname)
+                # If hostname changed, need to handle other bits of information
+                if before_hostname != after_hostname:
 
                     # If we're no longer canonical, delete the host object.
-                    if canon_before == True and canon_after == False:
+                    if canon_before == True and canon_after == True:
+                        ib_update_host(before, after)
+                    elif canon_before == False and canon_after == True:
+                        ib_create_host(after)
+                    elif canon_after == False:
                         ib_delete_host(before)
                                
                     # Host records
@@ -1609,8 +1635,9 @@ def do_machine(before, after):
                         if canon_after == True:
                             ib_add_hostrecord(record)
                         if canon_before == True:
-                            record[0] = before_hostname
-                            ib_delete_hostrecord(record)
+                            recordlist = list(record)
+                            recordlist[0] = before_hostname
+                            ib_delete_hostrecord(recordlist)
 
                     # CNAMEs.  Aliases directly associated with the host record
                     # will have moved as part of ib_update_host()
@@ -1618,13 +1645,15 @@ def do_machine(before, after):
                         if canon_before == True and canon_after == False:
                             ib_add_cname(record)
                         elif canon_before == False and canon_after == True:
+                            recordlist = list(record)
+                            recordlist[1] = before_hostname
+                            ib_delete_cname(recordlist)
                             ib_add_host_alias(record)
-                            record[0] = before_hostname
-                            ib_delete_cname(record)
                         elif canon_before == False and canon_after == False:
                             ib_add_cname(record)
-                            record[0] = before_hostname
-                            ib_delete_cname(record)
+                            recordlist = list(record)
+                            recordlist[1] = before_hostname
+                            ib_delete_cname(recordlist)
 
                     # Host addreses        
                     for record in get_moira_hostaddresses(after_hostname):
@@ -1639,23 +1668,26 @@ def do_machine(before, after):
                                 elif addr_type == 'IPV6':
                                     ib_add_aaaa_record(record)
                         if canon_before == True:
-                            record[0] = before_hostname
+                            recordlist = list(record)
+                            recordlist[0] = before_hostname
                             if has_ptr == 0:
                                 if addr_type == 'IPV4':
-                                    ib_delete_a_record(record)
+                                    ib_delete_a_record(recordlist)
                                 elif addr_type == 'IPV6':
-                                    ib_delete_aaaa_record(record)
+                                    ib_delete_aaaa_record(recordlist)
+                else:
+                    ib_update_host(before, after)
 
 # Handle hostalias incremental
 def do_hostalias(before, after):
     # Add
     if before == []:
         hostname = after[1]
-        if canonical_for_hostname(hostname) == True:
-            ib_add_host_alias(after)
-        else:
-            status = int(get_moira_host_status(hostname))
-            if status == 1:
+        status = int(get_moira_host_status(hostname))
+        if status == 1:
+            if canonical_for_hostname(hostname) == True:
+                ib_add_host_alias(after)
+            else:
                 ib_add_cname(after)
     # Delete
     elif after == []:
@@ -1663,9 +1695,7 @@ def do_hostalias(before, after):
         if canonical_for_hostname(hostname) == True:
             ib_delete_host_alias(before)
         else:
-            status = int(get_moira_host_status(hostname))
-            if status == 1:
-                ib_delete_cname(before)
+            ib_delete_cname(before)
     # update case with both before and after not empty can't happen
 
 # Handle hostaddress incremental
@@ -1675,7 +1705,8 @@ def do_hostaddress(before, after):
         hostname = after[0]
         has_ptr = int(after[5])
         addr_type = after[2]
-        if canonical_for_hostname(hostname) == True:
+        status = int(get_moira_host_status(hostname))
+        if status == 1 and canonical_for_hostname(hostname) == True:
             if has_ptr == 1:
                 if addr_type == 'IPV4':
                     ib_add_host_ipv4_address(after)
@@ -1706,27 +1737,25 @@ def do_hostaddress(before, after):
                         ib_delete_a_record(before)
                     elif addr_type == 'IPV6':
                         ib_delete_aaaa_record(before)
-    # Update - TTL or PTR bit might change, but never both at the same time.
+    # Update - TTL, PTR, or address might change, but only one at a time.
     else:
         hostname = after[0]
         before_ptr = int(before[5])
         after_ptr = int(after[5])
         addr_type = after[2]
+        before_address = before[3]
+        after_address = after[3]
 
-        if before_ptr == after_ptr:
-            # if here, ttl must have changed.
-            if after_ptr == 1:
-                ib_set_host_ttl(after)
-            else:
-                status = int(get_moira_host_status(hostname))
-                if status == 1:
-                    if addr_type == 'IPV4':
-                        ib_set_a_record_ttl(after)
-                    elif addr_type == 'IPV6':
-                        ib_set_aaaa_record_ttl(after)
-        else:
+        status = int(get_moira_host_status(hostname))
+
+        if before_address != after_address:
+            # This can only change if we're upgrading a host to a public address.
+            # Otherwise it would be a delete and an add.
+            if status == 1:
+                ib_delete_host_ipv4_address(before)
+                ib_add_host_ipv4_address(after)
+        elif before_ptr != after_ptr:
             # ptr bit changed.
-            status = int(get_moira_host_status(hostname))
             if status == 1:
                 if before_ptr == 0 and after_ptr == 1:
                     if addr_type == 'IPV4':
@@ -1742,6 +1771,16 @@ def do_hostaddress(before, after):
                     elif addr_type == 'IPV6':
                         ib_delete_host_ipv6_address(before)
                         ib_add_aaaa_record(after)
+        else:
+            # if here, ttl must have changed.
+            if status == 1:
+                if after_ptr == 1:
+                    ib_set_host_ttl(after)
+                else:
+                    if addr_type == 'IPV4':
+                        ib_set_a_record_ttl(after)
+                    elif addr_type == 'IPV6':
+                        ib_set_aaaa_record_ttl(after)
 
 # Handle hostrecord incremental
 def do_hostrecord(before, after):
@@ -1766,11 +1805,14 @@ def do_hostrecord(before, after):
                 log('received incremental for unsupported DNS RR type %s' % (rr_type))
     # Update - only thing that can change is TTL
     else:
+        hostname = after[0]
         rr_type = after[1]
-        if rr_type in rr_types:
-            ib_set_record_ttl(after)
-        else:
-            log('received incremental for unsupported DNS RR type %s' % (rr_type))
+        status = int(get_moira_host_status(hostname))
+        if status == 1 and canonical_for_hostname(hostname) == True:
+            if rr_type in rr_types:
+                ib_set_record_ttl(after)
+            else:
+                log('received incremental for unsupported DNS RR type %s' % (rr_type))
 
 # Handle machidentifier incremental
 def do_machidentifier(before, after):
diff --git a/moira/man/stella.1 b/moira/man/stella.1
index 257f857..a78a170 100644
--- a/moira/man/stella.1
+++ b/moira/man/stella.1
@@ -42,7 +42,7 @@ specified host.  Unlike clusters, a machine may only belong to a
 single container.
 .IP \fB-addcontainer\ \fIcontainer\ \fRor\ \fB-acn\ \fIcontainer\fR
 This will add the specified host to \fIcontainer\fR.
-.IP \fB-deletecontainer\ \fIcontainer\fRor \ \fB-dcn\ \fIcontainer\fR
+.IP \fB-deletecontainer\ \fIcontainer\ \fRor\ \fB-dcn\ \fIcontainer\fR
 This will delete the specified host from \fIcontainer\fR. 
 
 .IP \fB-listidentifier\ \fRor\ \fB-lid\fR
diff --git a/moira/server/mr_server.h b/moira/server/mr_server.h
index 01d0f96..8a23a93 100644
--- a/moira/server/mr_server.h
+++ b/moira/server/mr_server.h
@@ -172,6 +172,7 @@ int access_adhr(struct query *q, char *argv[], client *cl);
 int access_ahal(struct query *q, char *argv[], client *cl);
 int access_ahad(struct query *q, char *argv[], client *cl);
 int access_machidentifier(struct query *q, char *argv[], client *cl);
+int access_uhp4(struct query *q, char *argv[], client *cl);
 int access_snt(struct query *q, char *argv[], client *cl);
 int access_printer(struct query *q, char *argv[], client *cl);
 int access_zephyr(struct query *q, char *argv[], client *cl);
@@ -270,6 +271,7 @@ int setup_ghst(struct query *q, char *argv[], client *cl);
 int setup_ahst(struct query *q, char *argv[], client *cl);
 int setup_ahal(struct query *q, char *argv[], client *cl);
 int setup_ahad(struct query *q, char *argv[], client *cl);
+int setup_uhp4(struct query *q, char *argv[], client *cl);
 int setup_srrt(struct query *q, char *argv[], client *cl);
 int setup_shap(struct query *q, char *argv[], client *cl);
 int setup_ahid(struct query *q, char *argv[], client *cl);
@@ -294,7 +296,7 @@ int do_user_reservation(struct query *q, char *argv[], client *cl);
 int update_container(struct query *q, char *argv[], client *cl);
 int set_container_list(struct query *q, char *argv[], client *cl);
 int update_user_password_expiration(struct query *q, char *argv[], client *cl);
-
+int upgrade_host_private_ipv4_addr(struct query *q, char *argv[], client *cl);
 int get_ace_use(struct query *q, char **argv, client *cl,
 		int (*action)(int, char *[], void *), void *actarg);
 int get_host_by_owner(struct query *q, char **argv, client *cl,
diff --git a/moira/server/qaccess.pc b/moira/server/qaccess.pc
index abc3f58..4aacbbd 100644
--- a/moira/server/qaccess.pc
+++ b/moira/server/qaccess.pc
@@ -1045,6 +1045,39 @@ int access_machidentifier(struct query *q, char *argv[], client *cl)
   return MR_PERM;
 }
 
+int access_uhp4(struct query *q, char *argv[], client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  int cnt, mid, sid, moid, soid;
+  char mtype[MACHINE_OWNER_TYPE_SIZE], stype[SUBNET_OWNER_TYPE_SIZE];
+  char address[HOSTADDRESS_ADDRESS_SIZE];
+  EXEC SQL END DECLARE SECTION;
+  int status;
+
+  mid = *(int *)argv[0];
+
+  /* Host owner? */
+  EXEC SQL SELECT m.owner_type, m.owner_id INTO :mtype, :moid FROM machine m where mach_id = :mid;
+  if (dbms_errno)
+    return mr_errcode;
+
+  status = find_member(mtype, moid,cl);
+  if (status)
+    return MR_SUCCESS;
+
+  /* Owner of subnet containing primary v4 address */
+  EXEC SQL SELECT s.owner_type, s.owner_id INTO :stype, :soid FROM hostaddress ha, subnet s
+    WHERE ha.mach_id = :mid AND ha.ptr = 1 AND ha.snet_id = s.snet_id AND s.addr_type = 'IPV4';
+  if (dbms_errno)
+    return mr_errcode;
+
+  status = find_member(stype, soid, cl);
+  if (status)
+    return MR_SUCCESS;
+
+  return MR_PERM;
+}
+
 /* access_snt - check for retrieving network structure
  */
 
diff --git a/moira/server/qsetup.pc b/moira/server/qsetup.pc
index 5ce2f80..a90549a 100644
--- a/moira/server/qsetup.pc
+++ b/moira/server/qsetup.pc
@@ -1362,7 +1362,7 @@ int setup_ahst(struct query *q, char **argv, client *cl)
   if (row == 1)
     {
       EXEC SQL SELECT COUNT(*) INTO :cnt FROM hostrecord
-	WHERE mach_id = :id;
+	WHERE mach_id = :id AND rr_type = 'NS';
       if (dbms_errno)
 	return mr_errcode;
       if (cnt != 0)
@@ -1410,7 +1410,7 @@ int setup_ahal(struct query *q, char **argv, client *cl)
     return MR_EXISTS;
 
   /* No aliases if you have NS records / are a delegated zone */
-  EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostrecord hr, machine m
+  EXEC SQL SELECT count(*) INTO :cnt FROM hostrecord hr, machine m
     WHERE m.name = UPPER(:name) AND m.mach_id = hr.mach_id AND hr.rr_type = 'NS';
   if (dbms_errno)
     return mr_errcode;
@@ -1670,6 +1670,26 @@ int setup_ahad(struct query *q, char **argv, client *cl)
   return MR_SUCCESS;
 }
 
+int setup_uhp4(struct query *q, char **argv, client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  int cnt, mid;
+  EXEC SQL END DECLARE SECTION;
+
+  mid = *(int *)argv[0];
+
+  /* Host must have 1 IPv4 address marked as primary on a subnet ending in -PRIVATE */
+  EXEC SQL SELECT COUNT(*) INTO :cnt FROM hostaddress ha, subnet s WHERE
+    ha.mach_id = :mid and ha.ptr = 1 AND ha.snet_id = s.snet_id AND s.addr_type = 'IPV4'
+    AND s.name LIKE '%-PRIVATE';
+  if (dbms_errno)
+    return mr_errcode;
+  if (cnt != 1)
+    return MR_ADDRESS;
+
+  return MR_SUCCESS;
+}
+
 int setup_srrt(struct query *q, char **argv, client *cl)
 {
   char *p;
diff --git a/moira/server/qsupport.pc b/moira/server/qsupport.pc
index d690a03..04843b2 100644
--- a/moira/server/qsupport.pc
+++ b/moira/server/qsupport.pc
@@ -2966,3 +2966,125 @@ int add_dynamic_host_record(struct query *q, char *argv[], client *cl,
 
   return MR_SUCCESS;
 }
+
+int upgrade_host_private_ipv4_addr(struct query *q, char *argv[], client *cl)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  int cnt, mid, sid, public_sid, mask, table, ttl;
+  char sname[SUBNET_NAME_SIZE], public_sname[SUBNET_NAME_SIZE];
+  char address[HOSTADDRESS_ADDRESS_SIZE], public_address[HOSTADDRESS_ADDRESS_SIZE];
+  char saddr[SUBNET_SADDR_SIZE], high[SUBNET_HIGH_SIZE], low[SUBNET_LOW_SIZE];
+  char buf[INET_ADDRSTRLEN];
+  EXEC SQL END DECLARE SECTION;
+  struct sockaddr_in sa, saddr_sa, mask_sa, low_sa, high_sa;
+  unsigned int isaddr, imask, ihigh, ilow, value;
+  int status;
+  char *maskstr, *incr_argv[3];;
+
+  mid = *(int *)argv[0];
+  table = q->rtable;
+
+  /* Get existing private address.  This must return only one row if we got this far. */
+  EXEC SQL SELECT ha.address, s.name, s.snet_id, ha.ttl INTO :address, :sname, :sid, :ttl
+    FROM hostaddress ha, subnet s WHERE ha.mach_id = :mid AND ha.ptr = 1 
+    AND ha.snet_id = s.snet_id AND s.addr_type = 'IPV4'
+    AND s.name LIKE '%-PRIVATE';
+  if (dbms_errno)
+    return mr_errcode;
+
+  strmove(address, strtrim(address));
+  strmove(sname, strtrim(sname));
+
+  /* Get informtion for corresponding public subnet */
+  strcpy(public_sname, sname);
+  public_sname[strlen(sname) - strlen("-PRIVATE")] = '\0';
+  EXEC SQL SELECT snet_id INTO :public_sid FROM SUBNET WHERE name = :public_sname;
+  if (dbms_errno)
+    return mr_errcode;
+
+  /* Generate a unique address on the public subnet */
+  EXEC SQL SELECT saddr, mask, low, high INTO :saddr, :mask, :low, :high FROM subnet
+    WHERE snet_id = :public_sid;
+  if (dbms_errno)
+    return mr_errcode;
+
+  /* First, convert subnet strings into something we can work with */
+  if (inet_pton(AF_INET, strtrim(saddr), &(saddr_sa.sin_addr)) < 1)
+    return MR_ADDRESS;
+
+  /* mask - bit size, not string */
+  maskstr = masksize_to_mask("IPV4", mask);
+  if (!maskstr)
+    return MR_ADDRESS;
+
+  if (inet_pton(AF_INET, maskstr, &(mask_sa.sin_addr)) < 1)
+    return MR_ADDRESS;
+
+  if (inet_pton(AF_INET, strtrim(low), &(low_sa.sin_addr)) < 1)
+    return MR_ADDRESS;
+
+  if (inet_pton(AF_INET, strtrim(high), &(high_sa.sin_addr)) < 1)
+    return MR_ADDRESS;
+
+  isaddr = ntohl(saddr_sa.sin_addr.s_addr);
+  imask = ntohl(mask_sa.sin_addr.s_addr);
+  ilow = ntohl(low_sa.sin_addr.s_addr);
+  ihigh = ntohl(high_sa.sin_addr.s_addr);
+
+  for (value = ilow; value <= ihigh; value++)
+    {
+      if (((value & 0xff) == 0) || ((value & 0xff) == 255))
+	continue;
+
+      sa.sin_addr.s_addr = htonl(value);
+      if (inet_ntop(AF_INET, &(sa.sin_addr), buf, INET_ADDRSTRLEN) == NULL)
+	return MR_ADDRESS;
+
+      EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaddress
+	WHERE address = :buf;
+      if (dbms_errno)
+	return mr_errcode;
+      if (cnt == 0)
+	break;
+    }
+
+  if (cnt != 0)
+    return MR_NO_ID;
+  else
+    strcpy(public_address, buf);
+
+  /* Build "before" incremental argv */
+  incr_argv[0] = xmalloc(0);
+  status = id_to_name(mid, MACHINE_TABLE, &incr_argv[0]);
+  if (status)
+    return status;
+
+  incr_argv[1] = address;
+  incr_argv[2] = sname;
+
+  incremental_before(table, NULL, incr_argv);
+
+  /* Delete old host address record */
+  EXEC SQL DELETE FROM hostaddress WHERE mach_id = :mid
+    AND address = :address AND snet_id = :sid;
+  if (dbms_errno)
+    return mr_errcode;
+
+  /* Insert new record */
+  EXEC SQL INSERT INTO HOSTADDRESS (mach_id, snet_id, address, ttl, ptr)
+    VALUES (:mid, :public_sid, :public_address, :ttl, 1);
+  if (dbms_errno)
+    return mr_errcode;
+
+  /* Build "after" incremental argv, argv[0] remains the same */
+  incr_argv[1] = public_address;
+  incr_argv[2] = public_sname;
+
+  incremental_after(table, NULL, incr_argv);
+
+  status = set_mach_modtime_by_id(q, argv, cl);
+  if (status)
+    return status;
+
+  return MR_SUCCESS;
+}
diff --git a/moira/server/queries2.c b/moira/server/queries2.c
index 9d7314f..26384bb 100644
--- a/moira/server/queries2.c
+++ b/moira/server/queries2.c
@@ -2305,6 +2305,22 @@ static struct validate dhad_validate = {
   followup_dhad,
 };
 
+static char *uhp4_fields[] = {
+  "name",
+};
+
+static struct validate uhp4_validate = {
+  VOmach0,
+  1,
+  0,
+  0,
+  0,
+  "mach_id",
+  access_uhp4,
+  setup_uhp4,
+  upgrade_host_private_ipv4_addr,
+};
+
 static char *ghrr_fields[] = {
   "name", "rr_type",
   "name", "rr_type", "rr_value", "ttl",
@@ -7700,6 +7716,24 @@ struct query Queries[] = {
   },
 
   {
+    /* Q_UPGRADE_HOST_PRIVATE_IPV4_ADDR */
+    "upgrade_host_private_ipv4_addr",
+    "uhp4",
+    17,
+    MR_Q_UPDATE,
+    0,
+    HOSTADDRESS_TABLE,
+    0,
+    uhp4_fields,
+    1,
+    1,
+    NULL,
+    0,
+    NULL,
+    &uhp4_validate,
+  },
+
+  {
     /* Q_DHAD - DELETE_HOST_ADDRESS */
     "delete_host_address",
     "dhad",

home help back first fref pref prev next nref lref last post