vmc_knife 0.0.01

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
21
+ This software downloads additional open source software components upon install
22
+ that are distributed under separate terms and conditions. Please see the license
23
+ information provided in the individual software components for more information.
24
+
data/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # VMC Knife
2
+ Extensions for vmc: the VMware Cloud CLI; the command line interface to VMware's Application Platform
3
+
4
+ MIT license
5
+
6
+ ## Usecase
7
+ Prepare a file that describes the list of applications to deploy, their settings, their environment variables, required data-services and names, build file for the apps.
8
+ Run the deployment file on the command: will either install update, modify the apps on the cloudfoundry.
9
+ Run the deployment file via a web-interface.
10
+
11
+ prepare a vmc deployment file.
12
+ vmc_knife vmc_deployment_file.json
13
+
14
+
data/bin/vmc_knife ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../../lib/vmc_knife', __FILE__)
4
+
5
+ VMC::Cli::KnifeRunner.run(ARGV.dup)
6
+
@@ -0,0 +1,40 @@
1
+ require 'rest_client'
2
+
3
+ # Make sure the rest-client won't time out too quickly:
4
+ # vmc uses the rest-client for its rest calls but does not let us configure the timeouts.
5
+ # We monkey patch here.
6
+ module RestClient
7
+
8
+ class << self
9
+ attr_accessor :timeout
10
+ attr_accessor :open_timeout
11
+ end
12
+
13
+ class Request
14
+
15
+ def self.execute(args, &block)
16
+ #puts "Calling overriden RestClient::Request execute"
17
+ timeouts = {:timeout=>90000000, :open_timeout=>90000000}
18
+ args.merge!(timeouts)
19
+ #puts "Req args #{args}"
20
+ new(args).execute(& block)
21
+ end
22
+
23
+ end
24
+
25
+ def self.post(url, payload, headers={}, &block)
26
+ Request.execute(:method => :post,
27
+ :url => url,
28
+ :payload => payload,
29
+ :headers => headers,
30
+ :timeout=>@timeout,
31
+ :open_timeout=>@open_timeout,
32
+ &block)
33
+ end
34
+
35
+
36
+ end
37
+
38
+ #RestClient.open_timeout = 90000000
39
+ #RestClient.timeout = 90000000
40
+
@@ -0,0 +1,138 @@
1
+ require 'rubygems'
2
+ require 'cli' #this is the cli from vmc.
3
+
4
+ # Adds some new commands to the vmc's cli.
5
+ #
6
+ # Reconfigure applications according to a saas recipe.
7
+ # The SaaS recipe is a json object that contains the manifest of each application.
8
+ # as well as a short declaration of the services expected and their nature.
9
+ # Usage: edit the json recipe.
10
+ # vmc_knife configure-applications
11
+ #
12
+ # Also bundles utilities to reconfigure the hostname of the cloud_controller and the gateways accordingly:
13
+ # vmc_knife configure-vcap
14
+ # and publish the urls in the deployed apps with zeroconf on ubuntu (avahi)
15
+ # vmc configure-vcap-mdns
16
+ class VMC::Cli::KnifeRunner < VMC::Cli::Runner
17
+
18
+ def parse_command!
19
+ # just return if already set, happends with -v, -h
20
+ return if @namespace && @action
21
+
22
+ verb = @args.first
23
+ case verb
24
+
25
+ when 'expand-manifest'
26
+ usage('vmc_knife expand-manifest <path_to_json_manifest> <path_to_destination_expanded_manifest>')
27
+ @args.shift # consumes the argument.
28
+ if @args.size == 1
29
+ set_cmd(:knife, :expand_manifest, 1)
30
+ elsif @args.size == 2
31
+ set_cmd(:knife, :expand_manifest, 2)
32
+ else
33
+ set_cmd(:knife, :expand_manifest)
34
+ end
35
+ when 'login', 'target'
36
+ usage('vmc_knife login [<path_to_json_manifest>]')
37
+ @args.shift # consumes the argument.
38
+ if @args.size == 1
39
+ set_cmd(:knifemisc, :login, 1)
40
+ else
41
+ set_cmd(:knifemisc, :login)
42
+ end
43
+ when 'configure-all'
44
+ usage('vmc_knife configure-all [<path_to_cloud_controller_config_yml>] [<path_to_json_manifest_or_uri>]')
45
+ @args.shift # consumes the argument.
46
+ if @args.size <= 2
47
+ set_cmd(:knife, :configure_all, @args.size)
48
+ else
49
+ set_cmd(:knife, :configure_all, @args.size) # too many
50
+ end
51
+ when 'configure-vcap'
52
+ usage('vmc_knife configure-vcap [<path_to_cloud_controller_config_yml>] [<path_to_json_manifest_or_uri>]')
53
+ @args.shift # consumes the argument.
54
+ if @args.size <= 2
55
+ set_cmd(:knife, :configure_cloud_controller, @args.size)
56
+ else
57
+ set_cmd(:knife, :configure_cloud_controller, @args.size) # too many
58
+ end
59
+ when 'configure-vcap-etc-hosts'
60
+ usage('vmc_knife configure-vap-etc-hosts [<path_to_etc_hosts>] [<path_to_json_manifest_or_uri>]')
61
+ @args.shift # consumes the argument.
62
+ if @args.size <= 2
63
+ set_cmd(:knife, :configure_etc_hosts, @args.size)
64
+ else
65
+ set_cmd(:knife, :configure_etc_hosts, @args.size) # too many
66
+ end
67
+ when 'configure-vcap-mdns'
68
+ usage('vmc_knife configure-vap-mdns [<path_to_aliases>]')
69
+ @args.shift # consumes the argument.
70
+ if @args.size <= 2
71
+ set_cmd(:knife, :configure_etc_avahi_aliases, @args.size)
72
+ else
73
+ set_cmd(:knife, :configure_etc_avahi_aliases, @args.size) # too many
74
+ end
75
+ when 'configure-applications'
76
+ usage('vmc_knife configure-applications [<applications_regexp>]')
77
+ @args.shift # consumes the argument.
78
+ if @args.size <= 2
79
+ set_cmd(:knifeapps, :configure_applications, @args.size)
80
+ else
81
+ set_cmd(:knifeapps, :configure_applications, @args.size) # too many
82
+ end
83
+ when 'configure-services'
84
+ usage('vmc_knife configure-services [<services_regexp>]')
85
+ @args.shift # consumes the argument.
86
+ if @args.size <= 2
87
+ set_cmd(:knifeapps, :configure_services, @args.size)
88
+ else
89
+ set_cmd(:knifeapps, :configure_services, @args.size) # too many
90
+ end
91
+ when 'configure-recipes'
92
+ usage('vmc_knife configure-recipes [<recipes_regexp>]')
93
+ @args.shift # consumes the argument.
94
+ if @args.size <= 2
95
+ set_cmd(:knifeapps, :configure_recipes, @args.size)
96
+ else
97
+ set_cmd(:knifeapps, :configure_recipes, @args.size) # too many
98
+ end
99
+ when 'upload-applications'
100
+ usage('vmc_knife upload-applications [<applications_regexp>]')
101
+ @args.shift # consumes the argument.
102
+ if @args.size <= 2
103
+ set_cmd(:knifeapps, :upload_applications, @args.size)
104
+ else
105
+ set_cmd(:knifeapps, :upload_applications, @args.size) # too many
106
+ end
107
+ when 'start-applications'
108
+ usage('vmc_knife start-applications [<applications_regexp>]')
109
+ @args.shift # consumes the argument.
110
+ if @args.size <= 2
111
+ set_cmd(:knifeapps, :start_applications, @args.size)
112
+ else
113
+ set_cmd(:knifeapps, :start_applications, @args.size) # too many
114
+ end
115
+ when 'stop-applications'
116
+ usage('vmc_knife stop-applications [<applications_regexp>]')
117
+ @args.shift # consumes the argument.
118
+ if @args.size <= 2
119
+ set_cmd(:knifeapps, :stop_applications, @args.size)
120
+ else
121
+ set_cmd(:knifeapps, :stop_applications, @args.size) # too many
122
+ end
123
+ when 'restart-applications'
124
+ usage('vmc_knife restart-applications [<applications_regexp>]')
125
+ @args.shift # consumes the argument.
126
+ if @args.size <= 2
127
+ set_cmd(:knifeapps, :restart_applications, @args.size)
128
+ else
129
+ set_cmd(:knifeapps, :restart_applications, @args.size) # too many
130
+ end
131
+ when 'help'
132
+ display "vmc_knife expand-manifest|login|start/stop/restart-applications|upload-applications|configure|configure-recipes|configure-applications|configure-services|configure-vcap|configure-vcap-mdns|configure-vcap-etc-hosts [<manifest_path>]"
133
+ else
134
+ super
135
+ end
136
+ end
137
+
138
+ end
@@ -0,0 +1,186 @@
1
+ # Commands for vmc_knife.
2
+
3
+ module VMC::KNIFE::Cli
4
+
5
+ #loads the manifest file.
6
+ #when the path is not specified, look in the current directory.
7
+ #when the path is a directory, look for the first json file it can find.
8
+ #the json file actually loaded is set as the attribute @manifest_path
9
+ def load_manifest(manifest_file_path=nil)
10
+ manifest_file_path = Dir.pwd if manifest_file_path.nil?
11
+ if File.directory? manifest_file_path
12
+ #look for the first .json file if possible that is not an expanded.json
13
+ Dir.glob(File.join(manifest_file_path,"*.json")).each do |file|
14
+ @manifest_path = file
15
+ if VMC::Cli::Config.trace
16
+ display "Using the manifest #{@manifest_path}"
17
+ end
18
+ return VMC::KNIFE::JSON_EXPANDER.expand_json @manifest_path
19
+ end
20
+ raise "Unable to find a *.json file in #{manifest_file_path}"
21
+ else
22
+ @manifest_path = manifest_file_path
23
+ return VMC::KNIFE::JSON_EXPANDER.expand_json @manifest_path
24
+ end
25
+ end
26
+ end
27
+
28
+ module VMC::Cli::Command
29
+
30
+ class Knife < Base
31
+ include VMC::KNIFE::Cli
32
+
33
+ # expands the json manifest. outputs it in the destination path.
34
+ def expand_manifest(manifest_file_path, destination=nil)
35
+ res = VMC::KNIFE::JSON_EXPANDER.expand_json manifest_file_path
36
+ if destination.nil?
37
+ noextension = File.basename(manifest_file_path, File.extname(manifest_file_path))
38
+ destination = File.join File.dirname(manifest_file_path), "#{noextension}.expanded.json"
39
+ end
40
+ display "Expanding the manifest #{manifest_file_path} into #{destination}"
41
+ if VMC::Cli::Config.trace
42
+ display JSON.pretty_generate(res)
43
+ end
44
+ File.open(destination, 'w') {|f| f.write(JSON.pretty_generate(res)) }
45
+ end
46
+
47
+ # updates the cloud_controller
48
+ def configure_cloud_controller(cloud_controller_yml=nil,manifest_file_path_or_uri=nil)
49
+ __update(manifest_file_path_or_uri,cloud_controller_yml,VMC::KNIFE::VCAPUpdateCloudControllerConfig,"cloud_controller")
50
+ end
51
+ # updates /etc/hosts
52
+ def configure_etc_hosts(etc_hosts=nil,manifest_file_path_or_uri=nil)
53
+ __update(manifest_file_path_or_uri,etc_hosts,VMC::KNIFE::VCAPUpdateEtcHosts,"/etc/hosts")
54
+ end
55
+ # updates /etc/avahi/aliases
56
+ def configure_etc_avahi_aliases(etc_avahi_aliases=nil,manifest_file_path=nil)
57
+ man = load_manifest(manifest_file_path)
58
+ update_aliases = VMC::KNIFE::VCAPUpdateAvahiAliases.new(etc_avahi_aliases,man,client)
59
+ update_aliases.do_exec = true
60
+ update_aliases.execute
61
+ end
62
+
63
+ def configure_all(manifest_file_path_or_uri=nil)
64
+ display "Stop applications ..."
65
+ VMC::Cli::Command::Knifeapps.new(@options).stop_applications(nil,manifest_file_path_or_uri)
66
+ display "Configure_cloud_controller ..."
67
+ configure_cloud_controller(nil,manifest_file_path_or_uri)
68
+ display "Configure_etc_hosts ..."
69
+ configure_etc_hosts(nil,manifest_file_path_or_uri)
70
+ display "Login again ..."
71
+ VMC::Cli::Command::Knifemisc.new(@options).login(manifest_file_path_or_uri)
72
+ display "Configure_applications ..."
73
+ VMC::Cli::Command::Knifeapps.new(@options).configure_applications(nil,manifest_file_path_or_uri)
74
+ display "Configure_etc_avahi_aliases ..."
75
+ configure_etc_avahi_aliases(nil,manifest_file_path_or_uri)
76
+ display "Start applications ..."
77
+ VMC::Cli::Command::Knifeapps.new(@options).start_applications(nil,manifest_file_path_or_uri)
78
+ end
79
+
80
+ private
81
+ def __update(manifest_file_path_or_uri,config,_class,msg_label)
82
+ unless manifest_file_path_or_uri.nil?
83
+ if File.exists? manifest_file_path_or_uri
84
+ man = load_manifest(manifest_file_path_or_uri)
85
+ uri = man['target']
86
+ else
87
+ uri = manifest_file_path_or_uri
88
+ end
89
+ else
90
+ man = load_manifest(nil)
91
+ uri = man['target']
92
+ end
93
+ raise "No uri defined" unless uri
94
+ update_cc = _class.new(uri,config)
95
+ if update_cc.update_pending()
96
+ display "Configuring #{msg_label} with uri: #{uri}" if VMC::Cli::Config.trace
97
+ update_cc.execute()
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ class Knifemisc < Misc
104
+ include VMC::KNIFE::Cli
105
+
106
+ # configures the target and login according to the info in the manifest.
107
+ def login(manifest_file_path=nil)
108
+ man = load_manifest(manifest_file_path)
109
+ target_url = man['target']
110
+ raise "No target defined in the manifest #{@manifest_path}" if target_url.nil?
111
+ set_target(target_url)
112
+
113
+ email = man['email']
114
+ password = man['password']
115
+ @options[:email] = email if email
116
+ @options[:password] = password if password
117
+
118
+ tries ||= 0
119
+ # login_and_save_token:
120
+ token = client.login(email, password)
121
+ VMC::Cli::Config.store_token(token)
122
+
123
+ rescue VMC::Client::TargetError
124
+ display "Problem with login, invalid account or password.".red
125
+ retry if (tries += 1) < 3 && prompt_ok && !@options[:password]
126
+ exit 1
127
+ rescue => e
128
+ display "Problem with login, #{e}, try again or register for an account.".red
129
+ display e.backtrace
130
+ exit 1
131
+
132
+ end
133
+
134
+ end
135
+
136
+ class Knifeapps < Apps
137
+ include VMC::KNIFE::Cli
138
+
139
+ def configure_applications(app_names_regexp=nil,manifest_file_path=nil)
140
+ configure(nil,nil,app_names_regexp,manifest_file_path)
141
+ end
142
+ def configure_services(services_names_regexp=nil,manifest_file_path=nil)
143
+ configure(nil,nil,services_names_regexp,manifest_file_path)
144
+ end
145
+ def configure_recipes(recipe_names_regexp=nil,manifest_file_path=nil)
146
+ configure(recipe_names_regexp,nil,nil,manifest_file_path)
147
+ end
148
+
149
+ # Configure the applications according to their manifest.
150
+ # The parameters are related to selecting a subset of the applications to configure.
151
+ # nil means all apps for all recipes found in the manifest are configured.
152
+ # @param recipes The list of recipes: nil: search the apps in all recipes
153
+ # @param app_role_names The names of the apps in each recipe; nil: configure all apps found.
154
+ def configure(recipes_regexp=nil,app_names_regexp=nil,service_names_regexp=nil,manifest_file_path=nil)
155
+ man = load_manifest(manifest_file_path)
156
+ configurer = VMC::KNIFE::RecipesConfigurationApplier.new(man,client,recipes_regexp,app_names_regexp,service_names_regexp)
157
+ if VMC::Cli::Config.trace
158
+ display "Pending updates"
159
+ display JSON.pretty_generate(configurer.updates_pending)
160
+ end
161
+ configurer.execute
162
+ end
163
+
164
+ def upload_applications(app_names_regexp=nil,manifest_file_path=nil)
165
+ recipe_configuror(:upload,nil,nil,app_names_regexp,manifest_file_path)
166
+ end
167
+ def start_applications(app_names_regexp=nil,manifest_file_path=nil)
168
+ recipe_configuror(:start,nil,nil,app_names_regexp,manifest_file_path)
169
+ end
170
+ def stop_applications(app_names_regexp=nil,manifest_file_path=nil)
171
+ recipe_configuror(:stop,nil,nil,app_names_regexp,manifest_file_path)
172
+ end
173
+ def restart_applications(app_names_regexp=nil,manifest_file_path=nil)
174
+ recipe_configuror(:restart,nil,nil,app_names_regexp,manifest_file_path)
175
+ end
176
+
177
+ def recipe_configuror(method_sym_name,recipes_regexp=nil,app_names_regexp=nil,service_names_regexp=nil,manifest_file_path=nil)
178
+ man = load_manifest(manifest_file_path)
179
+ configurer = VMC::KNIFE::RecipesConfigurationApplier.new(man,client,recipes_regexp,app_names_regexp,service_names_regexp)
180
+ method_object = configurer.method(method_sym_name)
181
+ method_object.call
182
+ end
183
+
184
+ end
185
+
186
+ end
@@ -0,0 +1,83 @@
1
+ require 'json'
2
+ module VMC
3
+ module KNIFE
4
+ module JSON_DIFF
5
+
6
+ DIFF_NODE_NAME = "__diff__"
7
+ TYPE_NODE_NAME = "__type__"
8
+ PLUS="+"
9
+ MINUS="-"
10
+ CHANGED="=>"
11
+ DISPLAY_TYPE_ONLY_WHEN_CHANGE=true
12
+
13
+ def self.compare(a,b,pretty=true)
14
+ if a.kind_of?(String) && b.kind_of?(String) && File.exists?(a) && File.exists?(b)
15
+ a = JSON.parse File.open(a).read
16
+ b = JSON.parse File.open(b).read
17
+ end
18
+ if pretty
19
+ JSON.pretty_generate compare_tree(a, b)
20
+ else
21
+ compare_tree(a, b).to_json
22
+ end
23
+ end
24
+
25
+ def self.compare_tree(a, b)
26
+ typeA = a.class.name
27
+ typeB = b.class.name
28
+
29
+ aString = a.to_s unless is_array_or_hash?(a)
30
+ bString = b.to_s unless is_array_or_hash?(b)
31
+
32
+ node = Hash.new
33
+ if a.nil?
34
+ node[DIFF_NODE_NAME]=PLUS
35
+ node[TYPE_NODE_NAME]=typeB unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
36
+ node['value']=bString if bString
37
+ elsif b.nil?
38
+ node[DIFF_NODE_NAME]=MINUS
39
+ node[TYPE_NODE_NAME]=typeA unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
40
+ node['value']=aString if aString
41
+ elsif (typeA != typeB) || (!aString.nil? && a != b)
42
+ node[DIFF_NODE_NAME]=CHANGED
43
+ if typeA != typeB
44
+ node[TYPE_NODE_NAME]="#{typeA} => #{typeB}"
45
+ else
46
+ node[TYPE_NODE_NAME]=typeA unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
47
+ end
48
+ node['value']="#{aString} => #{bString}" if aString
49
+ else
50
+ node[TYPE_NODE_NAME]=typeA unless DISPLAY_TYPE_ONLY_WHEN_CHANGE
51
+ node['value']=aString if aString
52
+ end
53
+
54
+ if aString
55
+ return node
56
+ end
57
+ child_node=node
58
+ # child_node = Hash.new
59
+ # node['child']=child_node
60
+ keys = Array.new
61
+ keys = collect_keys(a,keys)
62
+ keys = collect_keys(b,keys)
63
+ keys.sort!
64
+ for i in 0..(keys.length-1)
65
+ if (keys[i] != keys[i-1])
66
+ value = compare_tree(a && a[keys[i]], b && b[keys[i]]);
67
+ child_node[keys[i]]=value
68
+ end
69
+ end
70
+ node
71
+ end
72
+ private
73
+ def self.is_array_or_hash?(obj)
74
+ obj.kind_of?(Array) || obj.kind_of?(Hash)
75
+ end
76
+ def self.collect_keys(obj, collector)
77
+ return Array.new unless obj.kind_of? Hash
78
+ collector + obj.keys
79
+ end
80
+
81
+ end # end of JSON_DIFF
82
+ end # end of KNIFE
83
+ end
@@ -0,0 +1,95 @@
1
+ require 'vmc/client'
2
+ require 'json'
3
+
4
+ module VMC
5
+ module KNIFE
6
+ module JSON_EXPANDER
7
+
8
+ # Loads a json file.
9
+ # Makes up to 10 passes evaluating ruby in the values that contain #{}.
10
+ def self.expand_json(file_path)
11
+ raise "The file #{file_path} does not exist" unless File.exists? file_path
12
+ data = JSON.parse File.open(file_path).read
13
+ #puts "got data #{data.to_json}"
14
+ passes = 0
15
+ while passes < 100
16
+ #puts "pass #{passes}"
17
+ break unless expand_data(data,data)
18
+ passes += 1
19
+ end
20
+ puts data.to_json unless passes < 100
21
+ raise "More than 100 passes evaluating the ruby template in the json file" unless passes < 100
22
+ #puts "got data #{data.to_json}"
23
+ data
24
+ end
25
+
26
+ # Traverses the JSON object
27
+ # Eval the values that are strings and contain a #{}
28
+ # Does not do it recursively
29
+ # data The root data passed as 'this' in the binding to the eval function
30
+ # @return true if there was a change.
31
+ def self.expand_data(data,current)
32
+ at_least_one_eval = false
33
+ if current.kind_of? Hash
34
+ current.each_pair do | k, v |
35
+ if v.kind_of? String
36
+ if /\#{.+}/ =~ v
37
+ at_least_one_eval = true
38
+ begin
39
+ evalled = eval_v(v,data,current)
40
+ current[k] = evalled unless evalled.nil?
41
+ rescue => e
42
+ raise "Error thrown evaluating #{v}: #{e.inspect}"
43
+ end
44
+ end
45
+ else
46
+ at_least_one_eval ||= expand_data(data,v)
47
+ end
48
+ end
49
+ elsif current.kind_of? Array
50
+ index = 0
51
+ current.each do | v |
52
+ if v.kind_of? String
53
+ if /\#{.+}/ =~ v
54
+ at_least_one_eval = true
55
+ begin
56
+ evalled = eval_v(v,data,current)
57
+ current[index] = evalled unless evalled.nil?
58
+ rescue => e
59
+ raise "Error thrown evaluating #{v}: #{e.inspect}"
60
+ end
61
+ end
62
+ else
63
+ at_least_one_eval ||= expand_data(data,v)
64
+ end
65
+ index+=1
66
+ end
67
+ end
68
+ at_least_one_eval
69
+ end
70
+
71
+ # internal eval a reference.
72
+ # the reference is always wrapped in a json string.
73
+ # however if it is purely a ruby script ("#{ruby here}" ) we unwrap it
74
+ # to avoid casting the result into a string.
75
+ def self.eval_v(v,data,current)
76
+ #puts "evalling #{v}"
77
+ if /^\#{([^}]*)}$/ =~ v
78
+ val = $1
79
+ else
80
+ val = '"'+v+'"'
81
+ end
82
+ evalled = eval(val,get_binding(data,current))
83
+ #puts "evaluating #{v} => #{evalled} class #{evalled.class.name}"
84
+ evalled
85
+ end
86
+
87
+ def self.get_binding(this,current)
88
+ binding
89
+ end
90
+
91
+ end #end of JSON_EXPANDER
92
+
93
+ end # end of KNIFE
94
+
95
+ end
@@ -0,0 +1,8 @@
1
+ module VMC
2
+ module KNIFE
3
+ module Cli
4
+ # This version number is used as the RubyGem release version.
5
+ VERSION = '0.0.01'
6
+ end
7
+ end
8
+ end