From 1df7227dabf4b3ca71dc88b67090778c1d009e1d Mon Sep 17 00:00:00 2001
From: Samir Noir <samir.noir@inria.fr>
Date: Wed, 20 Nov 2019 17:40:10 +0100
Subject: [PATCH] add a wiki generator for the Status page

also cover bug 11115 by adding direct links to jenkin-status for each
Grid'5000 sites
---
 lib/refrepo/gen/wiki.rb                   |   5 +
 lib/refrepo/gen/wiki/generators/status.rb | 216 ++++++++++++++++++++++
 2 files changed, 221 insertions(+)
 create mode 100644 lib/refrepo/gen/wiki/generators/status.rb

diff --git a/lib/refrepo/gen/wiki.rb b/lib/refrepo/gen/wiki.rb
index 3f981758dc..1ecb98f306 100644
--- a/lib/refrepo/gen/wiki.rb
+++ b/lib/refrepo/gen/wiki.rb
@@ -6,6 +6,7 @@ require 'refrepo/gen/wiki/generators/hardware'
 require 'refrepo/gen/wiki/generators/oar_properties'
 require 'refrepo/gen/wiki/generators/site_hardware'
 require 'refrepo/gen/wiki/generators/site_network'
+require 'refrepo/gen/wiki/generators/status'
 
 module RefRepo::Gen::Wiki
 
@@ -22,6 +23,10 @@ module RefRepo::Gen::Wiki
       :gen => G5KHardwareGenerator,
       :page => 'Hardware'
     },
+    'status' => {
+      :gen => StatusGenerator,
+      :page => 'Status'
+    },
     'oar_properties' => {
       :gen => OarPropertiesGenerator,
       :page => 'OAR_Properties'
diff --git a/lib/refrepo/gen/wiki/generators/status.rb b/lib/refrepo/gen/wiki/generators/status.rb
new file mode 100644
index 0000000000..49d013874a
--- /dev/null
+++ b/lib/refrepo/gen/wiki/generators/status.rb
@@ -0,0 +1,216 @@
+# coding: utf-8
+
+class StatusGenerator < WikiGenerator
+
+  def initialize(page_name)
+    super(page_name)
+  end
+
+  def generate_content
+    @global_hash = get_global_hash
+    @site_uids = G5K::SITES
+
+    @generated_content = "__NOEDITSECTION__\n"
+    @generated_content += "{{Status|In production}}\n"
+    @generated_content += "{{Portal|User}}\n"
+    @generated_content += "{{Portal|Platform}}\n"
+    @generated_content += "\n= [https://www.grid5000.fr/status/ Current platform events] (maintenance, outages, issues...) =\n"
+    @generated_content += "If you experience problems, please check '''[https://www.grid5000.fr/status/ the platform's operation schedule]''' ''(Past, present and future incidents (planned or not...) are notified for all sites).''\n"
+    @generated_content += MW::LINE_FEED
+    @generated_content += MW::LINE_FEED
+    @generated_content += "For other long running minor issue that may affect your experiment, you can check the list of known artifacts : '''[https://intranet.grid5000.fr/status/artifact/ Grid5000 Artifacts]''' ''(this list is also displayed when you connect on frontends).''\n"
+    @generated_content += MW::LINE_FEED
+    @generated_content += generate_resources_reservations
+    @generated_content += MW::LINE_FEED
+    @generated_content += generate_network_monitoring
+    @generated_content += MW::LINE_FEED
+    @generated_content += generate_power_monitoring
+    @generated_content += MW::LINE_FEED
+    @generated_content += generate_usage_statistics
+    @generated_content += MW::LINE_FEED
+    @generated_content += generate_ganglia
+    @generated_content += MW::LINE_FEED
+    @generated_content += generate_jenkins
+    @generated_content += MW.italic(MW.small(generated_date_string))
+    @generated_content += MW::LINE_FEED
+  end
+
+  def generate_resources_reservations
+    data = "= Resources reservations (OAR) status =\n"
+    data += MW::LINE_FEED
+    data += "{|\n"
+    data += "|bgcolor=\"#aaaaaa\" colspan=\"8\"|\n"
+    data += "'''Monika''' ''(current placement and queued jobs status)''\n"
+    data += "|-\n"
+
+    # Loop over Grid'5000 sites for Monika's links
+    @site_uids.sort.each do |site_uid|
+      if has_queue_production?(site_uid)
+        data += "|bgcolor=\"#ffffff\" valign=\"top\" style=\"border:1px solid #cccccc;padding:1em;padding-top:0.5em;\"|\n"
+        data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/monika.cgi '''#{site_uid.capitalize}''']<br>\n"
+        data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/monika-prod.cgi '''#{site_uid.capitalize} (production)''']\n"
+      else
+        data += "|bgcolor=\"#ffffff\" valign=\"top\" style=\"border:1px solid #cccccc;padding:1em;padding-top:0.5em;\"|\n"
+        data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/monika.cgi '''#{site_uid.capitalize}''']\n"
+      end
+    end
+
+    data += "|-\n"
+    data += "|bgcolor=\"#aaaaaa\" colspan=\"8\"|\n"
+    data += "'''Drawgantt''' ''(past, current and future OAR jobs scheduling)''\n"
+    data += "|-\n"
+    data += "|bgcolor=\"#eeeeee\" colspan=\"8\"|\n"
+    data += "Default view:\n"
+    data += "|-\n"
+
+    # Loop over Grid'5000 sites for Drawgantt's links
+    @site_uids.sort.each do |site_uid|
+      data += "|bgcolor=\"#ffffff\" valign=\"top\" style=\"border:1px solid #cccccc;padding:1em;padding-top:0.5em;\"|\n"
+      data += "<big>'''#{site_uid.capitalize}'''</big><br>\n"
+      data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg/ '''nodes''']<br>\n"
+      if has_queue_production?(site_uid)
+        data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-prod/ '''nodes (production)''']<br>\n"
+      end
+      if has_reservable_disks?(site_uid)
+        data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-disks/ disks]<br>\n"
+      end
+      data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-subnets/ subnets]<br>\n"
+      data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-vlans/ vlans]\n"
+    end
+
+    data += "|-\n"
+    data += "|bgcolor=\"#eeeeee\" colspan=\"8\"|\n"
+    data += "Forecast view for 1 week:\n"
+    data += "|-\n"
+
+    # Loop over Grid'5000 sites for Drawgantt's weekly links
+    @site_uids.sort.each do |site_uid|
+      data += "|bgcolor=\"#ffffff\" valign=\"top\" style=\"border:1px solid #cccccc;padding:1em;padding-top:0.5em;\"|\n"
+      data += "<big>'''#{site_uid.capitalize}'''</big><br>\n"
+      data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg/?relative_start=-28800&relative_stop=604800 '''nodes''']<br>\n"
+      if has_queue_production?(site_uid)
+        data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-prod/?relative_start=-28800&relative_stop=604800 '''nodes (production)''']<br>\n"
+      end
+      if has_reservable_disks?(site_uid)
+        data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-disks/?relative_start=-28800&relative_stop=604800 disks]<br>\n"
+      end
+      data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-subnets/?relative_start=-28800&relative_stop=604800 subnets]<br>\n"
+      data += "[https://intranet.grid5000.fr/oar/#{site_uid.capitalize}/drawgantt-svg-vlans/?relative_start=-28800&relative_stop=604800 vlans]\n"
+    end
+
+    data += "|}\n"
+  end
+
+  def generate_network_monitoring
+    data = "= Network Monitoring =\n"
+    data += "== Backbone network status and load ==\n"
+    data += "[http://pasillo.renater.fr/weathermap/weathermap_g5k.html Grid'5000 Weathermap]  (courtesy of Renater)\n"
+    data += MW::LINE_FEED
+    data += "Shows the actual state of the opticals links between the Grid'5000 10Gb-ready sites. A link painted in black on the weathermap means that you won't be able to access this site nodes from the Grid'5000 internal network.\n"
+    data += MW::LINE_FEED
+    data += "== Sites network traffic ==\n"
+    data += MW::LINE_FEED
+    data + "A dashboard combining links and real-time data is available on the [https://intranet.grid5000.fr/net/Lille/ Grid'5000 Backbone Network Monitoring] page.\n"
+  end
+
+  def generate_power_monitoring
+    data = "= Power Monitoring =\n"
+    data += MW::LINE_FEED
+    data += "{|\n"
+    @site_uids.sort.each do |site_uid|
+      if has_power_monitoring?(site_uid)
+        data += "|bgcolor=\"#ffffff\" valign=\"top\" style=\"border:1px solid #cccccc;padding:1em;padding-top:0.5em;\"|\n"
+        data += "[https://intranet.grid5000.fr/supervision/#{site_uid}/monitoring/energy/last/minute/ '''#{site_uid.capitalize}''']\n"
+      end
+    end
+
+    data += "|}\n"
+    data += MW::LINE_FEED
+    data += "Clusters where kwapi is available are listed on this page : https://intranet.grid5000.fr/jenkins-status/?job=test_kwapi\n"
+  end
+
+  def generate_usage_statistics
+    data = "= Usage statistics =\n"
+    data + "[https://intranet.grid5000.fr/stats/ Stats5k] gathers a lot of statistics about the testbed.\n"
+  end
+
+  def generate_ganglia
+    data = "= Ganglia =\n"
+    data + "[https://intranet.grid5000.fr/ganglia/ Ganglia] provides resources usage metrics (memory, cpu, jobs...) for individual sites or the whole platform.\n"
+  end
+
+  def generate_jenkins
+    data = "= Jenkins =\n"
+    data += "[https://intranet.grid5000.fr/jenkins-status/ Jenkins] tests most of Grid'5000 services. The web interface provides a summary of results, indicating platform health. Detailed logs are not normally available to users, but access can be requested if needed.\n"
+    data += MW::LINE_FEED
+    data += "{|\n"
+
+    @site_uids.sort.each do |site_uid|
+      data += "|bgcolor=\"#ffffff\" valign=\"top\" style=\"border:1px solid #cccccc;padding:1em;padding-top:0.5em;\"|\n"
+      data += "[https://intranet.grid5000.fr/jenkins-status/?site=#{site_uid} '''#{site_uid.capitalize}''']\n"
+    end
+
+    data += "|}\n"
+  end
+
+  def has_reservable_disks?(site)
+    site_hash = @global_hash["sites"][site]
+    site_hash["clusters"].each_value do |cluster_hash|
+      cluster_hash.fetch('nodes').each_value do |node_hash|
+        sd = node_hash['storage_devices']
+        reservable_disks = sd.select{ |v| v['reservation'] == true }.count > 0
+
+        if reservable_disks
+          return true
+        end
+      end
+    end
+
+    false
+  end
+
+  def has_queue_production?(site)
+    site_hash = @global_hash["sites"][site]
+    site_hash["clusters"].each_value do |cluster_hash|
+      if cluster_hash["queues"].include?("production")
+        return true
+      end
+    end
+
+    false
+  end
+
+  def has_power_monitoring?(site)
+    site_hash = @global_hash["sites"][site]
+    site_hash["clusters"].each_value do |cluster_hash|
+      cluster_hash.fetch("nodes").each_value do | node_hash|
+        if node_hash["sensors"].has_key?("power") and node_hash["sensors"]["power"]["available"]
+          return true
+        end
+      end
+    end
+
+    false
+  end
+end
+
+if __FILE__ == $0
+  generator = StatusGenerator.new("Status")
+
+  options = WikiGenerator::parse_options
+  if (options)
+    ret = 2
+    begin
+      ret = generator.exec(options)
+    rescue MediawikiApi::ApiError => e
+      puts e, e.backtrace
+      ret = 3
+    rescue StandardError => e
+      puts "Error with node: #{generator.instance_variable_get(:@node)}"
+      puts e, e.backtrace
+      ret = 4
+    ensure
+      exit(ret)
+    end
+  end
+end
-- 
GitLab