Attention une mise à jour du service Gitlab va être effectuée le mardi 30 novembre entre 17h30 et 18h00. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes. Cette mise à jour intermédiaire en version 14.0.12 nous permettra de rapidement pouvoir mettre à votre disposition une version plus récente.

oar-properties.rb 6.09 KB
Newer Older
1 2
#!/usr/bin/ruby

3 4
# Generator for the OAR properties

5 6 7 8 9 10
require 'pp'
require 'erb'
require 'fileutils'
require 'pathname'
require 'json'
require 'time'
11 12 13 14
require 'yaml'
require 'hashdiff'
require 'optparse'
require 'net/ssh'
15

16
require '../oar-properties/lib/lib-oar-properties'
17 18
require '../lib/input_loader'

19
options = {}
Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
20
options[:sites] = %w{grenoble lille luxembourg lyon nancy nantes reims rennes sophia}
21
options[:diff]  = false
22
options[:sshkeys]  = []
23

24 25
OptionParser.new do |opts|
  opts.banner = "Usage: oar-properties.rb [options]"
26

27 28 29 30 31 32 33
  opts.separator ""
  opts.separator "Example: ruby oar-properties.rb -v -s nancy -d oarnodes-%s.yaml -o cmd-%s.sh"

  opts.separator ""
  opts.separator "Filters:"

  ###
34

35 36
  opts.on('-s', '--sites a,b,c', Array, 'Select site(s)',
                                        "Default: "+options[:sites].join(", ")) do |s|
Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
37
    raise "Wrong argument for -s option." unless (s - options[:sites]).empty?
38
    options[:sites] = s
39
  end
40 41 42

  opts.on('-c', '--clusters a,b,c', Array, 'Select clusters(s). Default: all') do |s|
    options[:clusters] = s
43 44
  end

45 46
  opts.on('-n', '--nodes a,b,c', Array, 'Select nodes(s). Default: all') do |n|
    options[:nodes] = n
47 48
  end

49
  ###
50

51 52
  opts.separator ""
  opts.separator "Output options:"
53

Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
54
  opts.on('-o FILE', '--output=FILE', 'Output oarnodesetting command into a file. Default: stdout') do |o|
55 56
    options[:output] = o
  end
57

58 59 60
  opts.on('-e', '--exec', 'Directly apply the changes to the OAR server') do |e|
    options[:exec] = e
  end
61 62 63 64

  opts.on('-k', '--ssh-keys k1,k2,k3', Array, 'SSH keys') do |k|
    options[:sshkeys] = k
  end
65 66 67 68 69 70 71 72 73 74
  
  opts.on("-d", "--diff [YAML filename]", 
          "Only generates the minimal list of commands needed to update the site configuration",
          "The optional YAML file is suppose to be the output of the 'oarnodes -Y' command.",
          "If the file does not exist, the script will get the data from the OAR server and save the result on disk for future use.",
          "If no filename is specified, the script will simply connect to the OAR server.",
          "You can use the '%s' placeholder for 'site'. Ex: oarnodes-%s.yaml") do |d|
    d = true if d == nil
    options[:diff] = d
  end
75
    
76 77 78 79 80
  ###

  opts.separator ""
  opts.separator "Common options:"

Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
81 82 83
  opts.on("-v", "--[no-]verbose", "Run verbosely", "Multiple -v options increase the verbosity. The maximum is 3.") do |v|
    options[:verbose] ||= 0
    options[:verbose] = options[:verbose] + 1
84
  end
85 86 87 88 89 90 91 92
  
  # Print an options summary.
  opts.on_tail("-h", "--help", "Show this message") do
    puts opts
    exit
  end
end.parse!

Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
93
puts "Options: #{options}" if options[:verbose]
94

95 96 97
nodelist_properties = {} # ["ref"]  : properties from the reference-repo
                         # ["oar"]  : properties from the OAR server
                         # ["diff"] : diff between "ref" and "oar"
98 99

#
100
# Get the OAR properties from the reference-repo (["ref"])
101 102
#

103
nodelist_properties["ref"] = {}
104
global_hash = load_yaml_file_hierarchy('../../input/grid5000/')
105 106 107
options[:sites].each { |site_uid| 
  nodelist_properties["ref"][site_uid] = get_nodelist_properties(site_uid, global_hash["sites"][site_uid]) 
}
108 109

#
110
# Get the current OAR properties from the OAR scheduler (["oar"])
111 112 113
#

nodelist_properties["oar"] = {}
114 115
options[:sites].each { |site_uid| 
  nodelist_properties["oar"][site_uid] = {}
116

117 118 119
  # This is only needed for the -d option  
  if options[:diff]
    filename = options[:diff].is_a?(String) ? options[:diff].gsub("%s", site_uid) : nil
120
    nodelist_properties["oar"][site_uid] = oarcmd_get_nodelist_properties(site_uid, filename, options[:sshkeys])
121 122
  end
}
123 124 125 126

#
# Diff
#
127 128 129
if options[:diff]
  header ||= false
  prev_diff = {}
130
  
131 132 133 134 135 136
  nodelist_properties["diff"] = {}
  
  nodelist_properties["ref"].each { |site_uid, site_properties| 
    nodelist_properties["diff"][site_uid] = {}

    site_properties.each_filtered_node_uid(options[:clusters], options[:nodes]) { |node_uid, node_properties_ref|
137
      
138
      node_properties_oar = nodelist_properties["oar"][site_uid][node_uid]
139
      
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
      diff      = diff_node_properties(node_properties_oar, node_properties_ref)
      diff_keys = diff.map{ |hashdiff_array| hashdiff_array[1] }
      
      nodelist_properties["diff"][site_uid][node_uid] = node_properties_ref.select { |key, value| diff_keys.include?(key) }
      
      case options[:verbose]
      when 1
        puts "#{node_uid}: #{diff_keys}"
      when 2
        # Give more details
        # puts "#{node_uid}: #{diff}"
        if !header
          header=true
          puts "Output format: ['~', 'key', 'old value', 'new value']"
        end
        if diff.size==0
          puts "  #{node_uid}: OK"
        elsif diff == prev_diff
          puts "  #{node_uid}: same as above"
        else
          puts "  #{node_uid}:"
          diff.each { |d| puts "    #{d}" } 
        end
        prev_diff = diff
      when 3
        # Even more details
        puts JSON.pretty_generate({node_uid => {"old values" => node_properties_oar, "new values" => node_properties_ref}})
Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
167
      end
168 169
    }
    
Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
170
  }
171
end # if options[:diff]
172 173

#
Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
174
# Output commands
175
#
176 177 178 179 180 181 182 183 184 185 186 187 188 189
if options[:output]
  opt = options[:diff] ? 'diff' : 'ref'
  nodelist_properties[opt].each { |site_uid, site_properties| 
    
    options[:output] ? o = File.open(options[:output].gsub("%s", site_uid),'w') : o = $stdout.dup
    
    site_properties.each_filtered_node_uid(options[:clusters], options[:nodes]) { |node_uid, node_properties|
      o.write(oarcmd_set_node_properties(node_uid, node_properties) + "\n")
    }
    
    o.close
    
  }
end
Jérémie Gaidamour's avatar
Jérémie Gaidamour committed
190

191 192 193 194 195 196 197 198
#
# Execute commands
#
if options[:exec]
  opt = options[:diff] ? 'diff' : 'ref'
  nodelist_properties[opt].each { |site_uid, site_properties| 
    
    puts "Connecting #{site_uid} ..."
199
    Net::SSH.start("oar.#{site_uid}.g5kadmin", 'g5kadmin', :keys => options[:sshkeys]) { |ssh|
200 201 202 203 204 205 206 207 208 209 210 211
    
      site_properties.each_filtered_node_uid(options[:clusters], options[:nodes]) { |node_uid, node_properties|
        cmd = oarcmd_set_node_properties(node_uid, node_properties)
        if cmd.size>0
          puts "#{cmd}" if options[:verbose]
          ssh_output = ssh.exec!('echo ' + cmd) 
          puts "#{ssh_output}" if options[:verbose]
        end
      }
    }
  }
end