diff --git a/generators/wiki/cpu_parameters.rb b/generators/wiki/cpu_parameters.rb
index 418875937e16f8a4b4e9aab5cb44ee311b3a2cfa..f141066420c7a0d644093aee59947ed349e83d9b 100644
--- a/generators/wiki/cpu_parameters.rb
+++ b/generators/wiki/cpu_parameters.rb
@@ -1,90 +1,67 @@
-require "optparse"
-require "mediawiki_api"
-
 require_relative '../lib/input_loader'
+require_relative './wiki_generator'
 require_relative './mw_utils'
 
-options = {}
-
-opt_parse = OptionParser.new do |opts|
-  opts.banner = "Usage: cpuParameters.rb --api-user user --api-password password"
+class CPUParametersGenerator < WikiGenerator
 
-  opts.on('-u=user', '--api-user=user', String, 'User for HTTP authentication ') do |user|
-    options[:user] = user
+  def initialize(page_name)
+    super(page_name)
   end
 
-  opts.on('-p=pwd', '--api-password=pwd', String, 'Password for HTTP authentication') do |pwd|
-    options[:pwd] = pwd
+  def generate_content
+
+    table_columns = ["Installation date", "Site", "Cluster", "CPU Family", "CPU Version", "Core Codename", "Frequency", "Server type", "HT enabled", "Turboboost enabled", "P-State driver", "C-State driver"]
+    table_data = []
+    global_hash = load_yaml_file_hierarchy(File.expand_path("../../input/grid5000/", File.dirname(__FILE__)))
+
+    # Loop over Grid'5000 sites
+    global_hash["sites"].each { |site_uid, site_hash|
+      site_hash.fetch("clusters").each { |cluster_uid, cluster_hash|
+
+        node_hash = cluster_hash.fetch('nodes').first[1]
+
+        cpu_family = node_hash["processor"]["model"] rescue ""
+        cpu_version = node_hash["processor"]["version"] rescue ""
+        cpu_freq = node_hash["processor"]["clock_speed"] / 1000000000.0 rescue 0.0 #GHz
+        cpu_codename = node_hash["processor"]["microarchitecture"] rescue ""
+        ht_enabled = node_hash["bios"]["configuration"]["ht_enabled"] rescue false
+        turboboost_enabled = node_hash["bios"]["configuration"]["turboboost_enabled"] rescue false
+        pstate_driver = node_hash["operating_system"]["pstate_driver"] rescue ""
+        cstate_driver = node_hash["operating_system"]["cstate_driver"] rescue ""
+
+        #One line per cluster
+        table_data << [
+          DateTime.new(*cluster_hash["created_at"].to_s.scan(/\d+/).map {|i| i.to_i}).strftime("%Y-%m-%d"),
+          site_uid,
+          cluster_uid,
+          cpu_family,
+          cpu_version,
+          cpu_codename,
+          cpu_freq.to_s + " GHz",
+          cluster_hash["model"],
+          ht_enabled ? "{{Yes}}" : "{{No}}",
+          turboboost_enabled ? "{{Yes}}" : "{{No}}",
+          pstate_driver,
+          cstate_driver
+        ]
+      }
+    }
+    #Sort by cluster date
+    table_data.sort_by! { |row|
+      DateTime.parse(row[0])
+    }
+
+    #Table construction
+    table_options = 'class="G5KDataTable" border="1" style="text-align: center;"'
+    @generated_content = MW.generate_table(table_options, table_columns, table_data)
+    @generated_content += MW.italic(MW.small("Generated from the Grid5000 APIs on " + Time.now.strftime("%Y-%m-%d")))
+    @generated_content += MW::LINE_FEED
   end
 end
 
-opt_parse.parse!
+generator = CPUParametersGenerator.new("Generated/CPUParameters")
 
-if (options[:user].nil? || options[:pwd].nil?)
-  puts opt_parse.to_s
-  exit
+options = WikiGenerator::parse_options
+if (options)
+  WikiGenerator::exec(generator, options)
 end
-
-target_page = "Generated/CPUParameters"
-
-table_columns = ["Installation date", "Site", "Cluster", "CPU Family", "CPU Version", "Core Codename", "Frequency", "Server type", "HT enabled", "Turboboost enabled", "P-State driver", "C-State driver"]
-
-table_data = []
-
-global_hash = load_yaml_file_hierarchy(File.expand_path("../../input/grid5000/", File.dirname(__FILE__)))
-
-# Loop over Grid'5000 sites
-global_hash["sites"].each { |site_uid, site_hash|
-
-  site_hash.fetch("clusters").each { |cluster_uid, cluster_hash|
-
-    node_hash = cluster_hash.fetch('nodes').first[1]
-
-    cpu_family = node_hash["processor"]["model"] rescue ""
-    cpu_version = node_hash["processor"]["version"] rescue ""
-    cpu_freq = node_hash["processor"]["clock_speed"] / 1000000000.0 rescue 0.0 #GHz
-    cpu_codename = node_hash["processor"]["microarchitecture"] rescue ""
-
-    ht_enabled = node_hash["bios"]["configuration"]["ht_enabled"] rescue false
-    turboboost_enabled = node_hash["bios"]["configuration"]["turboboost_enabled"] rescue false
-    pstate_driver = node_hash["operating_system"]["pstate_driver"] rescue ""
-    cstate_driver = node_hash["operating_system"]["cstate_driver"] rescue ""
-
-    #One line per cluster
-    table_data << [
-      DateTime.new(*cluster_hash["created_at"].to_s.scan(/\d+/).map {|i| i.to_i}).strftime("%Y-%m-%d"),
-      site_uid,
-      cluster_uid,
-      cpu_family,
-      cpu_version,
-      cpu_codename,
-      cpu_freq.to_s + " GHz",
-      cluster_hash["model"],
-      ht_enabled ? "{{Yes}}" : "{{No}}",
-      turboboost_enabled ? "{{Yes}}" : "{{No}}",
-      pstate_driver,
-      cstate_driver
-    ]
-
-  }
-}
-
-#Sort by cluster date
-table_data.sort_by! { |row|
-  DateTime.parse(row[0])
-}
-
-#Table construction
-
-table_options = 'class="G5KDataTable" border="1" style="text-align: center;"'
-
-page_text = MW.generate_table(table_options, table_columns, table_data)
-
-page_text += MW.italic(MW.small("Generated from the Grid5000 APIs on " + Time.now.strftime("%Y-%m-%d")))
-
-#Finally Create/modify the page on mediawiki
-client = MediawikiApi::Client.new(MW::BASE_URL)
-client.log_in(options[:user], options[:pwd])
-client.edit({"title" => target_page, "text" => page_text })
-
-puts "Page '#{target_page}' created/updated"
diff --git a/generators/wiki/mw_utils.rb b/generators/wiki/mw_utils.rb
index cba7652365d3953ea89fdb8160e4ce00ebc915de..f3c3ec5ab8565d281d9ad74ff5bd7946351dc154 100644
--- a/generators/wiki/mw_utils.rb
+++ b/generators/wiki/mw_utils.rb
@@ -1,9 +1,38 @@
+require 'open-uri'
+require 'uri'
+require 'net/http'
+require 'net/https'
+
+#Adding method to mediawiki_api client
+module MediawikiApi
+
+  class Client
+
+    def get_page_content(page_name)
+      get_conn = Faraday.new(url: MW::BASE_URL + "index.php/#{page_name}") do |faraday|
+        faraday.request :multipart
+        faraday.request :url_encoded
+        faraday.use :cookie_jar, jar: @cookies
+        faraday.use FaradayMiddleware::FollowRedirects
+        faraday.adapter Faraday.default_adapter
+      end
+      params = {
+        :token_type => false,
+        :action => 'raw'
+      }
+      params[:token] = get_token(:csrf)
+      res = get_conn.send(:get, '', params)
+      res.body
+    end
+  end
 
+end
 #Defines MediaWiki helpers
-
 module MW
 
-  BASE_URL = "https://www.grid5000.fr/mediawiki/api.php"
+  BASE_URL = "https://www.grid5000.fr/mediawiki/"
+
+  API_URL = BASE_URL + "api.php"
 
   TABLE_START = "{|"
 
@@ -61,5 +90,4 @@ module MW
   def self.bold(text)
     "'''" + text + "'''"
   end
-
 end
diff --git a/generators/wiki/wiki_generator.rb b/generators/wiki/wiki_generator.rb
new file mode 100644
index 0000000000000000000000000000000000000000..41a7c48249f69afcba119bf6b9f5e5ae3f2c4d3b
--- /dev/null
+++ b/generators/wiki/wiki_generator.rb
@@ -0,0 +1,107 @@
+
+require "optparse"
+require "mediawiki_api"
+require "diffy"
+
+require_relative "./mw_utils"
+
+class WikiGenerator
+
+  def initialize(page_name)
+    @mw_client = MediawikiApi::Client.new(MW::API_URL)
+    @page_name = page_name
+  end
+
+  def login(options)
+    if (options[:user] && options[:pwd])
+      @mw_client.log_in(options[:user], options[:pwd])
+    end
+  end
+
+  def generate_content
+    raise "To be implemented in actual generators"
+  end
+
+  #Actually edit the mediawiki page with the new generated content
+  def update_page
+    @mw_client.edit({"title" => @page_name, "text" => @generated_content })
+  end
+
+  #Get the given page content and print a diff if any
+  #Return true if there are differences, false otherwise
+  def diff_page()
+    wiki_content = @mw_client.get_page_content(@page_name)
+    diff = Diffy::Diff.new(wiki_content, @generated_content, :context => 0)
+    if (diff.to_s.empty?)
+      return false
+    end
+    puts "Differences between generated and current wiki content for page #{@page_name}:\n#{diff.to_s(:color)}"
+  end
+
+  #print generator content to stdout
+  def print()
+    puts @generated_content
+  end
+
+  #Generic static method for cli arguments parsing
+  def self.parse_options
+    options = {
+      :diff => false,
+      :print => false,
+      :update => false
+    }
+
+    opt_parse = OptionParser.new do |opts|
+      opts.banner = "Usage: <wiki_generator>.rb --api-user user --api-password password"
+
+      opts.on('-u=user', '--api-user=user', String, 'User for HTTP authentication ') do |user|
+        options[:user] = user
+      end
+
+      opts.on('-p=pwd', '--api-password=pwd', String, 'Password for HTTP authentication') do |pwd|
+        options[:pwd] = pwd
+      end
+
+      opts.on('-d', '--diff', 'Print a diff of the current wiki page against the content to generated') do
+        options[:diff] = true
+      end
+
+      opts.on('-u', '--update', 'Update the wiki page with the new generated content') do
+        options[:update] = true
+      end
+
+      opts.on('-p', '--print', 'Print the new generated content on stdout') do
+        options[:print] = true
+      end
+
+      # Print an options summary.
+      opts.on_tail("-h", "--help", "Show this message") do
+        puts opts
+        exit
+      end
+    end
+    opt_parse.parse!
+    if (!options[:diff] && !options[:print] && !options[:update])
+      puts "At least one action must be given!\n#{opt_parse.to_s}"
+      return false
+    end
+    return options
+  end
+
+  #Execute actions on generator based on given options
+  def self.exec(generator, options)
+    generator.login(options)
+    generator.generate_content()
+
+    if (options[:diff])
+      generator.diff_page
+    end
+    if (options[:print])
+      generator.print
+    end
+    if (options[:update])
+      generator.update_page
+    end
+  end
+
+end