6156: support config format for setting a node's hostname
authorradhika <radhika@curoverse.com>
Tue, 16 Jun 2015 15:32:55 +0000 (11:32 -0400)
committerradhika <radhika@curoverse.com>
Tue, 16 Jun 2015 15:32:55 +0000 (11:32 -0400)
services/api/app/models/node.rb
services/api/config/application.default.yml
services/api/test/fixtures/nodes.yml
services/api/test/unit/node_test.rb

index 1cd6387cff37da82f23eeaf0d040ca64c57bf14e..0ec91369417492e32b2679750601e45eb2e8d537 100644 (file)
@@ -94,7 +94,7 @@ class Node < ArvadosModel
       end
     end
 
-    # Assign hostname
+    # Assign slot_number
     if self.slot_number.nil?
       try_slot = 0
       begin
@@ -107,6 +107,10 @@ class Node < ArvadosModel
         end
         raise "No available node slots" if try_slot == Rails.configuration.max_compute_nodes
       end while true
+    end
+
+    # Assign hostname
+    if self.hostname.nil? and Rails.configuration.assign_node_hostname
       self.hostname = self.class.hostname_for_slot(self.slot_number)
     end
 
@@ -205,21 +209,36 @@ class Node < ArvadosModel
   end
 
   def self.hostname_for_slot(slot_number)
-    "compute#{slot_number}"
+    config = Rails.configuration.assign_node_hostname
+
+    return nil if !config
+
+    begin
+      if config.include?('%')
+        sprintf(config, {:slot_number => slot_number})
+      else
+        eval('"' + config + '"')
+      end
+    rescue => e
+      logger.error "Eror generating hostname: #{e.message}"
+      return nil
+    end
   end
 
   # At startup, make sure all DNS entries exist.  Otherwise, slurmctld
   # will refuse to start.
   if Rails.configuration.dns_server_conf_dir and Rails.configuration.dns_server_conf_template
     (0..Rails.configuration.max_compute_nodes-1).each do |slot_number|
-      hostname = hostname_for_slot(slot_number)
-      hostfile = File.join Rails.configuration.dns_server_conf_dir, "#{hostname}.conf"
-      if !File.exists? hostfile
-        n = Node.where(:slot_number => slot_number).first
-        if n.nil? or n.ip_address.nil?
-          dns_server_update(hostname, '127.40.4.0')
-        else
-          dns_server_update(hostname, n.ip_address)
+      if Rails.configuration.assign_node_hostname
+        hostname = hostname_for_slot(slot_number)
+        hostfile = File.join Rails.configuration.dns_server_conf_dir, "#{hostname}.conf"
+        if !File.exists? hostfile
+          n = Node.where(:slot_number => slot_number).first
+          if n.nil? or n.ip_address.nil?
+            dns_server_update(hostname, '127.40.4.0')
+          else
+            dns_server_update(hostname, n.ip_address)
+          end
         end
       end
     end
index 54880039581570fb9f89cc860bf8bc771474f39d..8f3207a71921e6ac06c939579f95bbd0a1f2458d 100644 (file)
@@ -329,3 +329,21 @@ common:
 
   # Docker image to be used when none found in runtime_constraints of a job
   default_docker_image_for_jobs: false
+
+  # Hostname to assign to a compute node when it sends a "ping" and the
+  # hostname in its Node record is nil.
+  # During bootstrapping, the "ping" script is expected to notice the
+  # hostname given in the ping response, and update its unix hostname
+  # accordingly.
+  # If false, leave the hostname alone (this is appropriate if your compute
+  # nodes' hostnames are already assigned by some other mechanism).
+  #
+  # One way or another, the hostnames of your node records should agree
+  # with your DNS records and your /etc/slurm-llnl/slurm.conf files.
+  #
+  # Example for compute0000, compute0001, ....:
+  # assign_node_hostname: compute#{slot_number.to_s.rjust(4, "0")}
+  # or
+  # assign_node_hostname: compute%<slot_number>04d
+  # (See http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-format for more.)
+  assign_node_hostname: compute#{slot_number}
index 15115012fac5027c9ce8060e85cb54d297c40923..6ca22e152615c30180de4fc07a5e6d19c2b8ed12 100644 (file)
@@ -54,3 +54,27 @@ was_idle_now_down:
     ping_secret: "1bd1yi0x4lb5q4gzqqtrnq30oyj08r8dtdimmanbqw49z1anz2"
     slurm_state: "idle"
     total_cpu_cores: 16
+
+new_with_no_hostname:
+  uuid: zzzzz-7ekkf-newnohostname00
+  owner_uuid: zzzzz-tpzed-000000000000000
+  hostname: ~
+  slot_number: ~
+  ip_address: 172.17.2.173
+  last_ping_at: ~
+  first_ping_at: ~
+  job_uuid: ~
+  info:
+    ping_secret: "abcdyi0x4lb5q4gzqqtrnq30oyj08r8dtdimmanbqw49z1anz2"
+
+new_with_custom_hostname:
+  uuid: zzzzz-7ekkf-newwithhostname
+  owner_uuid: zzzzz-tpzed-000000000000000
+  hostname: custom1
+  slot_number: 23
+  ip_address: 172.17.2.173
+  last_ping_at: ~
+  first_ping_at: ~
+  job_uuid: ~
+  info:
+    ping_secret: "abcdyi0x4lb5q4gzqqtrnq30oyj08r8dtdimmanbqw49z1anz2"
index 98e260be9dcb05d233833f38605059fa76f6c733..96d31a8c4c679c2b508490c53f30d3bf7db23e87 100644 (file)
@@ -75,4 +75,66 @@ class NodeTest < ActiveSupport::TestCase
     Rails.configuration.dns_server_reload_command = 'ignored!'
     assert Node.dns_server_update 'compute65535', '127.0.0.127'
   end
+
+  test "ping new node with no hostname and default config" do
+    node = ping_node(:new_with_no_hostname, {})
+    slot_number = node.slot_number
+    refute_nil slot_number
+    assert_equal("compute#{slot_number}", node.hostname)
+  end
+
+  test "ping new node with no hostname and no config" do
+    Rails.configuration.assign_node_hostname = false
+    node = ping_node(:new_with_no_hostname, {})
+    refute_nil node.slot_number
+    assert_nil node.hostname
+  end
+
+  [
+    'compute#{slot_number.to_s.rjust(4, "0")}',
+    'compute%<slot_number>04d',
+  ].each do |config|
+    test "ping new node with zero padding config #{config}" do
+      Rails.configuration.assign_node_hostname = config
+      node = ping_node(:new_with_no_hostname, {})
+      slot_number = node.slot_number
+      refute_nil slot_number
+      assert_equal("compute000#{slot_number}", node.hostname)
+    end
+  end
+
+  test "ping node with hostname and config and expect hostname unchanged" do
+    node = ping_node(:new_with_custom_hostname, {})
+    assert_equal(23, node.slot_number)
+    assert_equal("custom1", node.hostname)
+  end
+
+  test "ping node with hostname and no config and expect hostname unchanged" do
+    Rails.configuration.assign_node_hostname = false
+    node = ping_node(:new_with_custom_hostname, {})
+    assert_equal(23, node.slot_number)
+    assert_equal("custom1", node.hostname)
+  end
+
+  # Ping two nodes: one with no hostname and the other with a hostname.
+  # Verify that the first one gets a hostname and second one is unchanged.
+  test "ping two nodes one with no hostname and one with hostname and check hostnames" do
+    # ping node with no hostname and expect it set with config format
+    node = ping_node(:new_with_no_hostname, {})
+    slot_number = node.slot_number
+    refute_nil node.slot_number
+    assert_equal "compute#{slot_number}", node.hostname
+
+    # ping node with a hostname and expect it to be unchanged
+    node2 = ping_node(:new_with_custom_hostname, {})
+    refute_nil node2.slot_number
+    assert_equal "custom1", node2.hostname
+  end
+
+  test "ping node with no hostname and malformed config and expect nil for hostname" do
+    Rails.configuration.assign_node_hostname = 'compute%<slot_number>04'  # should end with "04d"
+    node = ping_node(:new_with_no_hostname, {})
+    refute_nil node.slot_number
+    assert_equal(nil, node.hostname)
+  end
 end