Permalink
Browse files

Merge pull request #1 from jfontan/master

Add onecast tool
  • Loading branch information...
2 parents 3057740 + 816c5ee commit 3848a3db9eb4065ddf6b8656dc394146bc5c1ff2 @jmelis jmelis committed Jul 11, 2012
Showing with 230 additions and 0 deletions.
  1. +73 −0 README.md
  2. +157 −0 onecast
View
@@ -20,6 +20,7 @@ Commands
- [__oneirb__](#oneirb): Opens an IRB session with all the OpenNebula libraries.
- [__oneconf__](#oneconf): Modifies the default configuration files.
- [__onebootstrap__](#onebootstrap): Creates initial OpenNebula resources.
+- [__onecast__](#onecast): OpenNebula templates with variables.
onelog
------
@@ -133,3 +134,75 @@ All of these resources can be customized by editing the files inside
The datastore where the images will be instantiated needs to have `DEFAULT =
YES` inside the template. This is only necessary if more than one datastore is
created.
+
+onecast
+-------
+
+This tool that can rewrite parts of a VM template substituting the variables it
+contains by some values that the user provides. It also gets values from the
+environment if the values are not explicitly provided by the user and can also
+have a default value so they will be translated to something meaningful if not
+found by other methods.
+
+An example of a VM template meaningful to onecast can be this one:
+
+ NAME = "${NAME}"
+ CPU = ${CPU|1.0}
+ VCPU = ${CPU|1}
+ MEMORY = ${MEMORY|512}
+ DISK = [
+ SOURCE = "${HOME}/images/vm.img",
+ TARGET = sda
+ ]
+
+In this example we can see that the placeholder for the variable values is
+specified with `${VARIABLE}`. The name of the variable is case sensitive and
+this will be translated to its value (user provided or from the environment) or
+left blank if not found. We have to be careful with variables not set or they
+will render the template unusable in some cases. To overcome this problem, and
+also to give some values that the user may not want to modify, default values
+can be provided alongside the variable name. Variable names with default values
+are specified with `${VARIABLE|default value}`. Doing so if the variable is not
+set by the user in the command line or found in the environment it will be
+substituted by the default value.
+
+It is also very useful to use environment variables to get some information
+specific to the user, in this example we suppose every user has a file called
+`images/vm.img` in their home directory so we use `$HOME` environment variable
+to point to it.
+
+To generate the final template we use the this command:
+
+ $ onecast -d NAME="test vm" test.one
+ NAME = "test vm"
+ CPU = 1.0
+ VCPU = 1
+ MEMORY = 512
+ DISK = [
+ SOURCE = "/home/oneuser/images/vm.img",
+ TARGET = sda
+ ]
+
+We have to specify the template file to the onecast script and we can also
+provide variables using _-d_ option. This option will have an argument in this
+form `NAME=value` that will be used to substitute any variable in the template
+with that name. More than one of those variables can be added in the command
+line. As another example to illustrate this we can also set the memory to 1Gb
+issuing this command:
+
+ $ onecast -d NAME="test vm" -d MEMORY=1024 test.one
+ NAME = "test vm"
+ CPU = 1.0
+ VCPU = 1
+ MEMORY = 1024
+ DISK = [
+ SOURCE = "/home/oneuser/images/vm.img",
+ TARGET = sda
+ ]
+
+The output of the command can then be redirected to a file and use it to create
+a new VM or use the parameter _-c_ so the VM is automatically sent to
+OpenNebula:
+
+ $ onecast -d NAME="test vm" -d MEMORY=1024 test.one -c
+ ID: 9
View
157 onecast
@@ -0,0 +1,157 @@
+#!/usr/bin/env ruby
+
+require 'getoptlong'
+require 'tempfile'
+require 'open-uri'
+
+HELP_TEXT=<<EOT
+Usage:
+ onecast [<options>] <base_template>
+
+Options:
+ -d, --data <name>=<value> Sets the value that goes into a template
+ -c, --create [vm|vnet|image] Calls create command of onvm, onevnet
+ or oneimage. If the object type is no
+ specified then onevm is called
+ -h, --help Prints this help text
+
+Template:
+ Template variables have the form ${NAME}. The name of the variable is
+ case sensitive and is translated to the value specified in the command
+ line or the environment. It can also have a default value if the variable
+ is not specified in the command line or not found in the environment this
+ way ${NAME|default value}.
+EOT
+
+class OneCast
+ attr_reader :vars, :error
+
+ REG_VAR=/\$\{([^}|]+)(\|([^}]+))?\}/
+
+ def initialize(template, data)
+ @vars=ENV.to_hash
+ @error=nil
+ @template=template.clone
+
+ data.each do |text|
+ parsed=parse_data_variable(text)
+ raise "Bad formatted variable: '#{text}'" if !parsed
+ @vars[parsed[0]]=parsed[1].gsub("\\n", "\n")
+ end
+ end
+
+ def rewrite_template
+ @error=nil
+
+ @template.gsub(REG_VAR) do |var|
+ match=REG_VAR.match(var)
+
+ var_name=match[1]
+ default_value=match[3]
+
+ d=@vars[var_name]
+
+ d||=default_value
+
+ if !d
+ @error||=''
+ @error+="Variable '#{var_name}' not set. "
+ end
+
+ d
+ end
+ end
+
+private
+
+ def parse_data_variable(text)
+ m=(/^([^=]+)=["']?(.*)["']?/m).match(text)
+ if m
+ m[1,2]
+ else
+ nil
+ end
+ end
+
+end
+
+def print_help
+ puts HELP_TEXT
+end
+
+opts = GetoptLong.new(
+ [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
+ [ '--data', '-d', GetoptLong::REQUIRED_ARGUMENT ],
+ [ '--create', '-c', GetoptLong::OPTIONAL_ARGUMENT]
+)
+
+text_variables=Array.new
+create=false
+
+begin
+ opts.each do |opt, arg|
+ case opt
+ when '--data'
+ text_variables<<arg
+ when '--create'
+ case arg
+ when nil, ''
+ create='vm'
+ when 'vm', 'vnet', 'image'
+ create=arg
+ else
+ raise "Invalid object to create '#{arg}'."
+ end
+ when '--help'
+ print_help
+ exit(0)
+ else
+ print_help
+ exit(0)
+ end
+ end
+rescue StandardError => e
+ STDERR.puts e
+ print_help
+ exit(-1)
+end
+
+template_name=ARGV[0]
+
+if !template_name
+ STDERR.puts "ERROR: Template file not provided.\n\n"
+ print_help
+ exit(-1)
+end
+
+begin
+ file=open(template_name)
+ template_text=file.read
+ file.close
+rescue
+ puts "Could not read template file '#{template_name}'."
+ exit(-1)
+end
+
+begin
+ onecast=OneCast.new(template_text, text_variables)
+rescue Exception => e
+ puts e
+ exit(-1)
+end
+
+final_template=onecast.rewrite_template
+errors=onecast.error
+
+
+STDERR.puts errors if errors
+
+if create
+ temp=Tempfile.new "#{create}.one"
+ temp.write final_template
+ temp.close
+ system "one#{create} create -v #{temp.path}"
+ temp.unlink
+else
+ puts final_template
+end

0 comments on commit 3848a3d

Please sign in to comment.