# Copyright (C) 2008 Red Hat, Inc # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # a long with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. $: << File.dirname(File.expand_path(__FILE__)) gem 'reststop', '~> 0.2' require 'yaml' require 'fileutils' require 'rubygems' require 'picnic' require 'reststop' require 'genome-dsl' require 'restr' require 'cgi' require 'xmlrpc/client' require 'pp' CONTEXT="/genome" Camping.goes :Genomed Genomed.picnic! module Genomed::Controllers class MachineTypes < REST 'machine_types' include GenomeDsl # GET /types/foo # GET /types/foo.xml def read(type) @machine = machines.find {|m| m.name == type} render :view_type end # GET /types # GET /types.xml def list @machines = machines render :list_types end end class Nodes < REST 'nodes' # GET /nodes/foo # GET /nodes/foo.xml def read(name) @name = name begin @info = YAML.load(File.read("/etc/genome/nodes/#{@name}/node.yaml")) render :view_node rescue # node doesn't exist yet render :add end end # GET /nodes # GET /nodes.xml def list @nodes = Dir["/etc/genome/nodes/*"].map { |m| File.basename(m) } render :list_nodes end def create if input.wizard puts "You're using the wizard!" puts input.inspect elsif input.yaml node_dir = "/etc/genome/nodes/#{input.node_name}" persist_node(input.node_name, input.yaml) elsif input.xml xml = XmlSimple.xml_in(input.xml) params = Hash.new xml["parameters"].each do |p| p.each_key do |k| params[k] = p[k].to_s #The value is an array. Yay. end end persist_node(xml["name"].to_s, YAML.dump({"classes" => xml["class"], "parameters" => params})) end redirect R(Nodes) if @format == :HTML end def persist_node(node, yaml) node_dir = "/etc/genome/nodes/#{node}" FileUtils.mkdir_p(node_dir) unless File.exist?(node_dir) File.open(node_dir + "/node.yaml", "w") {|f| f.puts yaml} end end class Wizard < REST 'wizard' include GenomeDsl # GET /wizard/foo # GET /wizard/foo.xml def read(type) @machine = machines.find {|m| m.name == type} render :view_type end # GET /types # GET /types.xml def list @machines = machines render :list_types end def create @machine_type = input.machine_type redirect CONTEXT + R(Nodes) end end end module Genomed::Views def initialize(*args) super(*args) @x = Builder::XmlMarkup.new(:indent => 1) end module HTML def layout html do head do title 'Genome' link :rel => 'stylesheet', :type => 'text/css', :href => '/styles.css', :media => 'screen' end body do div.header! do div.headerLogo! {} end div.body! do div.nav_menu! do ul do li { a("Machine Types", :href => CONTEXT + R(Genomed::Controllers::MachineTypes)) } li { a("Nodes", :href => CONTEXT + R(Genomed::Controllers::Nodes)) } end end div.content! do div.inner! do self << yield end end end end end end def add form(:method => 'post', :action => CONTEXT + R(Genomed::Controllers::Nodes)) do h2 "YAML" textarea :name => 'yaml', :rows => '25', :cols => '100'; br input :name => 'node_name', :value => @name input :type => 'submit', :value => "Submit" end end def view_type p do h1 @machine.name p @machine.desc form(:method => 'post', :action => CONTEXT + R(Genomed::Controllers::Nodes)) do h2 "Fully qualified domain name" input :name => "fqdn", :type => 'text', :size => 45, :value => "[prefix]-#{@machine.name}.usersys.redhat.com" h2 "Classes" @machine.classes.each_with_index do |c, i| input :name => "class#{i}", :type => 'text', :value => c; br end h2 "Parameters" fieldset do @machine.facts.each do |f| a(f.name, :href => "fix me", :title => f.desc); br input :name => "param_" + f.name, :type => 'text', :size => 45, :value => f.default; br end end input :type => 'hidden', :name => 'node_name', :value => @name input :type => 'hidden', :name => 'wizard', :value => true input :type => 'submit', :value => "Submit" end end end def view_node h1 @name p "This form allows you to submit the YAML to be used by the Puppetmaster to " + "determine the configuration to be compiled for a particular host." form(:method => 'post', :action => CONTEXT + R(Genomed::Controllers::Nodes)) do textarea ::YAML.dump(@info), :name => 'yaml', :rows => '25', :cols => '100'; br input :type => 'hidden', :name => 'node_name', :value => @name input :type => 'submit', :value => "Submit" end end def list_nodes h1 "Nodes:" p "To create a new node just browse to the page corresponding to the hostname. " + "eg, #{CONTEXT + R(Genomed::Controllers::Nodes, "[hostname]")}." p do ol do @nodes.each do |n| # BUG: default format is not getting preserved @format = :HTML li {a(n, :href => CONTEXT + R(Genomed::Controllers::Nodes, n))} end end end end def list_types p do p "Click the links to create a new instance of a particular machine type." ol do @machines.each do |m| li do #h1 {a(m.name, :href => R(Genomed::Controllers::MachineTypes, m.name))} h1 m.name p(m.desc) end end end end end end default_format :HTML module YAML CONTENT_TYPE = 'text/plain' def layout yield end # This should only be used for Puppet's external nodes def view_node ::YAML.dump(@info) end end module XML def layout yield end def list_types @x.instruct! @x.machine_types { @machines.each do |m| @x.machine_type { @x.name(m.name) @x.description(m.desc) } end } end def view_type @x.instruct! @x.machine { @x.name(@machine.name) @x.description(@machine.desc) @machine.classes.each {|c| @x.class(c)} @machine.facts.each {|f| @x.fact { @x.name(f.name) @x.description(f.desc) @x.default(f.default) } } } end def list_nodes @x.instruct! @x.nodes { @nodes.each {|n| @x.node(n)} } end def view_node # There no reason we should only support params and classes. # It might be nice to simply iterate over all the keys and # display their values. @x.instruct! @x.node { @x.name(@name) @info["parameters"].each_pair do |n,v| @x.parameters { instance_eval("@x.#{n}(v)") } end @info["classes"].each {|c| @x.class(c)} } end end end # Required by picnic def Genomed.create; end Genomed.start_picnic