opennebula 4.90.10.rc1 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ActionManager.rb +278 -0
- data/lib/CommandManager.rb +242 -0
- data/lib/DriverExecHelper.rb +215 -0
- data/lib/OpenNebulaDriver.rb +233 -0
- data/lib/VirtualMachineDriver.rb +376 -0
- data/lib/cloud/CloudClient.rb +1 -1
- data/lib/opennebula/virtual_machine.rb +1 -0
- data/lib/opennebula.rb +1 -1
- data/lib/vcenter_driver.rb +2716 -0
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 16cda589536bb5239ef70cb6898e8b00e3ebd9c9
|
4
|
+
data.tar.gz: 4e71745bc284fb49c762321fc7523064c3f11716
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd3b03e5187e2efe9d6cee742e58e917b6fec606388282657c9a4a0b276facc22e859084b9e26d9447e2b664997727653ff33e6792d0744b80a7e7c16436da87
|
7
|
+
data.tar.gz: 3dec23410ed0b0b8f53f9bdec6bea441b70d1df9f8cdb3f1a270a8cbba313750565e16a0f2c78985c9f00184120c03252b53fc7e63ca1a111a4350116c70e239
|
@@ -0,0 +1,278 @@
|
|
1
|
+
# -------------------------------------------------------------------------- */
|
2
|
+
# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems #
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
4
|
+
# not use this file except in compliance with the License. You may obtain */
|
5
|
+
# a copy of the License at */
|
6
|
+
# */
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0 */
|
8
|
+
# */
|
9
|
+
# Unless required by applicable law or agreed to in writing, software */
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS, */
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
12
|
+
# See the License for the specific language governing permissions and */
|
13
|
+
# limitations under the License. */
|
14
|
+
# -------------------------------------------------------------------------- */
|
15
|
+
|
16
|
+
require 'thread'
|
17
|
+
|
18
|
+
=begin rdoc
|
19
|
+
|
20
|
+
This class provides support to handle actions. Class methods, or actions, can be
|
21
|
+
registered in the action manager. The manager will wait for actions to be
|
22
|
+
triggered (thread-safe), and will execute them concurrently. The action manager
|
23
|
+
can be used to synchronize different objects in different threads
|
24
|
+
|
25
|
+
== Example
|
26
|
+
|
27
|
+
class Sample
|
28
|
+
attr_reader :am
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@am = ActionManager.new(15,true)
|
32
|
+
|
33
|
+
@am.register_action("SLEEP",method("sleep_action"))
|
34
|
+
end
|
35
|
+
|
36
|
+
def sleep_action(secs)
|
37
|
+
sleep(secs)
|
38
|
+
end
|
39
|
+
|
40
|
+
def finalize_action
|
41
|
+
p "Exiting..."
|
42
|
+
@am.stop_listener
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
s = Sample.new
|
48
|
+
|
49
|
+
s.@am.start_listener
|
50
|
+
|
51
|
+
# Objects in other threads can trigger actions like this
|
52
|
+
# s.am.trigger_action("SLEEP",rand(3)+1)
|
53
|
+
# s.am.trigger_action("FINALIZE")
|
54
|
+
=end
|
55
|
+
|
56
|
+
class ActionManager
|
57
|
+
|
58
|
+
# Creates a new Action Manager
|
59
|
+
#
|
60
|
+
# +concurrency+ is the maximun number of actions that can run at the same
|
61
|
+
# time
|
62
|
+
# +threaded+ if true actions will be executed by default in a different
|
63
|
+
# thread
|
64
|
+
def initialize(concurrency=10, threaded=true)
|
65
|
+
@finalize = false
|
66
|
+
@actions = Hash.new
|
67
|
+
@threaded = threaded
|
68
|
+
|
69
|
+
@concurrency = concurrency
|
70
|
+
@num_running = 0
|
71
|
+
|
72
|
+
@action_queue = Array.new
|
73
|
+
@action_running = Hash.new
|
74
|
+
|
75
|
+
@threads_mutex = Mutex.new
|
76
|
+
@threads_cond = ConditionVariable.new
|
77
|
+
end
|
78
|
+
|
79
|
+
# Registers a new action in the manager. An action is defined by:
|
80
|
+
#
|
81
|
+
# +aname+ name of the action, it will identify the action
|
82
|
+
# +method+ it's invoked with call. It should be a Proc or Method object
|
83
|
+
# +threaded+ execute the action in a new thread
|
84
|
+
def register_action(aname, method, threaded=nil)
|
85
|
+
threaded ||= @threaded
|
86
|
+
|
87
|
+
@actions[aname]={
|
88
|
+
:method => method,
|
89
|
+
:threaded => threaded
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
# Triggers the execution of the action.
|
94
|
+
#
|
95
|
+
# +aname+ name of the action
|
96
|
+
# +action_id+ an id to identify the action (to cancel it later)
|
97
|
+
# +aargs+ arguments to call the action
|
98
|
+
def trigger_action(aname, action_id, *aargs)
|
99
|
+
|
100
|
+
@threads_mutex.synchronize {
|
101
|
+
return if @finalize
|
102
|
+
|
103
|
+
if aname == :FINALIZE
|
104
|
+
finalize if respond_to?(:finalize)
|
105
|
+
@finalize = true
|
106
|
+
@threads_cond.signal if @num_running == 0
|
107
|
+
return
|
108
|
+
end
|
109
|
+
|
110
|
+
if !@actions.has_key?(aname)
|
111
|
+
return
|
112
|
+
end
|
113
|
+
|
114
|
+
arity=@actions[aname][:method].arity
|
115
|
+
|
116
|
+
if arity < 0
|
117
|
+
# Last parameter is an array
|
118
|
+
arity = -arity - 1
|
119
|
+
if arity > aargs.length
|
120
|
+
# Message has not enough parameters
|
121
|
+
return
|
122
|
+
end
|
123
|
+
# Converts last parameters to an array
|
124
|
+
aargs[arity..-1]=[aargs[arity..-1]]
|
125
|
+
else
|
126
|
+
if arity != aargs.length
|
127
|
+
return
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
@action_queue << @actions[aname].merge(:args => aargs,
|
132
|
+
:id => action_id)
|
133
|
+
|
134
|
+
if @num_running < @concurrency
|
135
|
+
@threads_cond.signal
|
136
|
+
end
|
137
|
+
}
|
138
|
+
end
|
139
|
+
|
140
|
+
def cancel_action(action_id)
|
141
|
+
@threads_mutex.synchronize {
|
142
|
+
action = @action_running[action_id]
|
143
|
+
if action
|
144
|
+
thread = action[:thread]
|
145
|
+
else
|
146
|
+
thread = nil
|
147
|
+
end
|
148
|
+
|
149
|
+
if thread
|
150
|
+
thread.kill
|
151
|
+
|
152
|
+
@num_running -= 1
|
153
|
+
delete_running_action(action_id)
|
154
|
+
|
155
|
+
@threads_cond.signal
|
156
|
+
else
|
157
|
+
i = @action_queue.select{|x| x[:id] == action_id}.first
|
158
|
+
@action_queue.delete(i) if i
|
159
|
+
end
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
def start_listener
|
164
|
+
while true
|
165
|
+
@threads_mutex.synchronize {
|
166
|
+
while ((@concurrency - @num_running)==0) || empty_queue
|
167
|
+
@threads_cond.wait(@threads_mutex)
|
168
|
+
|
169
|
+
return if (@finalize && @num_running == 0)
|
170
|
+
end
|
171
|
+
|
172
|
+
run_action
|
173
|
+
}
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
protected
|
178
|
+
|
179
|
+
def delete_running_action(action_id)
|
180
|
+
@action_running.delete(action_id)
|
181
|
+
end
|
182
|
+
|
183
|
+
def get_runable_action
|
184
|
+
@action_queue.shift
|
185
|
+
end
|
186
|
+
|
187
|
+
def empty_queue
|
188
|
+
@action_queue.size==0
|
189
|
+
end
|
190
|
+
|
191
|
+
def run_action
|
192
|
+
action = get_runable_action
|
193
|
+
|
194
|
+
if action
|
195
|
+
@num_running += 1
|
196
|
+
|
197
|
+
if action[:threaded]
|
198
|
+
thread = Thread.new {
|
199
|
+
action[:method].call(*action[:args])
|
200
|
+
|
201
|
+
@threads_mutex.synchronize {
|
202
|
+
@num_running -= 1
|
203
|
+
delete_running_action(action[:id])
|
204
|
+
|
205
|
+
@threads_cond.signal
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
action[:thread] = thread
|
210
|
+
@action_running[action[:id]] = action
|
211
|
+
else
|
212
|
+
action[:method].call(*action[:args])
|
213
|
+
|
214
|
+
@num_running -= 1
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
if __FILE__ == $0
|
221
|
+
|
222
|
+
class Sample
|
223
|
+
attr_reader :am
|
224
|
+
|
225
|
+
def initialize
|
226
|
+
@am = ActionManager.new(15,true)
|
227
|
+
|
228
|
+
@am.register_action(:SLEEP,method("sleep_action"))
|
229
|
+
# @am.register_action(:SLEEP,Proc.new{|s,i| p s ; sleep(s)})
|
230
|
+
@am.register_action(:NOP,method("nop_action"))
|
231
|
+
|
232
|
+
def @am.get_runable_action
|
233
|
+
action = super
|
234
|
+
puts "getting: #{action.inspect}"
|
235
|
+
action
|
236
|
+
end
|
237
|
+
|
238
|
+
def @am.delete_running_action(action_id)
|
239
|
+
puts "deleting: #{action_id}"
|
240
|
+
super(action_id)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def sleep_action(secs, id)
|
245
|
+
p "ID: #{id} sleeping #{secs} seconds"
|
246
|
+
sleep(secs)
|
247
|
+
p "ID: #{id} Awaken!"
|
248
|
+
end
|
249
|
+
|
250
|
+
def nop_action
|
251
|
+
p " - Just an action"
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
s = Sample.new
|
257
|
+
|
258
|
+
Thread.new {
|
259
|
+
sleep 1
|
260
|
+
|
261
|
+
100.times {|n|
|
262
|
+
s.am.trigger_action(:SLEEP,n,rand(3)+1,n)
|
263
|
+
s.am.trigger_action(:NOP,100+n)
|
264
|
+
}
|
265
|
+
|
266
|
+
s.am.trigger_action(:SLEEP,301,5,301)
|
267
|
+
|
268
|
+
s.am.cancel_action(301)
|
269
|
+
|
270
|
+
s.am.trigger_action(:FINALIZE,0)
|
271
|
+
|
272
|
+
s.am.trigger_action(:SLEEP,999,rand(3)+1,999)
|
273
|
+
s.am.trigger_action(:SLEEP,333,rand(3)+1,333)
|
274
|
+
}
|
275
|
+
|
276
|
+
s.am.start_listener
|
277
|
+
end
|
278
|
+
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# --------------------------------------------------------------------------
|
2
|
+
# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
5
|
+
# not use this file except in compliance with the License. You may obtain
|
6
|
+
# a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
# --------------------------------------------------------------------------
|
16
|
+
|
17
|
+
require 'pp'
|
18
|
+
require 'open3'
|
19
|
+
require 'stringio'
|
20
|
+
|
21
|
+
# Generic command executor that holds the code shared by all the command
|
22
|
+
# executors.
|
23
|
+
#
|
24
|
+
# Properties:
|
25
|
+
#
|
26
|
+
# * +code+: integer holding the exit code. Read-only
|
27
|
+
# * +stdout+: string of the standard output. Read-only
|
28
|
+
# * +stderr+: string of the standard error. Read-only
|
29
|
+
# * +command+: command to execute. Read-only
|
30
|
+
#
|
31
|
+
# The protocol for scripts to log is as follows:
|
32
|
+
#
|
33
|
+
# * Log messages will be sent to STDOUT
|
34
|
+
# * The script will return 0 if it succeded or any other value
|
35
|
+
# if there was a failure
|
36
|
+
# * In case of failure the cause of the error will be written to STDERR
|
37
|
+
# wrapped by start and end marks as follows:
|
38
|
+
#
|
39
|
+
# ERROR MESSAGE --8<------
|
40
|
+
# error message for the failure
|
41
|
+
# ERROR MESSAGE ------>8--
|
42
|
+
|
43
|
+
|
44
|
+
class GenericCommand
|
45
|
+
attr_reader :code, :stdout, :stderr, :command
|
46
|
+
|
47
|
+
# Creates a command and runs it
|
48
|
+
def self.run(command, logger=nil, stdin=nil)
|
49
|
+
cmd = self.new(command, logger, stdin)
|
50
|
+
cmd.run
|
51
|
+
cmd
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates the new command:
|
55
|
+
# +command+: string with the command to be executed
|
56
|
+
# +logger+: proc that takes a message parameter and logs it
|
57
|
+
def initialize(command, logger=nil, stdin=nil)
|
58
|
+
@command = command
|
59
|
+
@logger = logger
|
60
|
+
@stdin = stdin
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sends a log message to the logger proc
|
64
|
+
def log(message)
|
65
|
+
@logger.call(message) if @logger
|
66
|
+
end
|
67
|
+
|
68
|
+
# Runs the command
|
69
|
+
def run
|
70
|
+
std = execute
|
71
|
+
|
72
|
+
# Close standard IO descriptors
|
73
|
+
if @stdin
|
74
|
+
std[0] << @stdin
|
75
|
+
std[0].flush
|
76
|
+
end
|
77
|
+
std[0].close if !std[0].closed?
|
78
|
+
|
79
|
+
@stdout=std[1].read
|
80
|
+
std[1].close if !std[1].closed?
|
81
|
+
|
82
|
+
@stderr=std[2].read
|
83
|
+
std[2].close if !std[2].closed?
|
84
|
+
|
85
|
+
@code=get_exit_code(@stderr)
|
86
|
+
|
87
|
+
if @code!=0
|
88
|
+
log("Command execution fail: #{command}")
|
89
|
+
log(@stderr)
|
90
|
+
end
|
91
|
+
|
92
|
+
return @code
|
93
|
+
end
|
94
|
+
|
95
|
+
# Parses error message from +stderr+ output
|
96
|
+
def get_error_message
|
97
|
+
tmp=@stderr.scan(/^ERROR MESSAGE --8<------\n(.*?)ERROR MESSAGE ------>8--$/m)
|
98
|
+
return "-" if !tmp[0]
|
99
|
+
tmp[0].join(' ').strip
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
# Gets exit code from STDERR
|
105
|
+
def get_exit_code(str)
|
106
|
+
tmp=str.scan(/^ExitCode: (\d*)$/)
|
107
|
+
return nil if !tmp[0]
|
108
|
+
tmp[0][0].to_i
|
109
|
+
end
|
110
|
+
|
111
|
+
# Low level command execution. This method has to be redefined
|
112
|
+
# for each kind of command execution. Returns an array with
|
113
|
+
# +stdin+, +stdout+ and +stderr+ handlers of the command execution.
|
114
|
+
def execute
|
115
|
+
puts "About to execute \"#{@command}\""
|
116
|
+
[StringIO.new, StringIO.new, StringIO.new]
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
# Executes commands in the machine where it is called. See documentation
|
122
|
+
# for GenericCommand
|
123
|
+
class LocalCommand < GenericCommand
|
124
|
+
private
|
125
|
+
|
126
|
+
def execute
|
127
|
+
Open3.popen3("#{command} ; echo ExitCode: $? 1>&2")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Executes commands in a remote machine ussing ssh. See documentation
|
132
|
+
# for GenericCommand
|
133
|
+
class SSHCommand < GenericCommand
|
134
|
+
attr_accessor :host
|
135
|
+
|
136
|
+
# Creates a command and runs it
|
137
|
+
def self.run(command, host, logger=nil, stdin=nil)
|
138
|
+
cmd=self.new(command, host, logger, stdin)
|
139
|
+
cmd.run
|
140
|
+
cmd
|
141
|
+
end
|
142
|
+
|
143
|
+
# This one takes another parameter. +host+ is the machine
|
144
|
+
# where the command is going to be executed
|
145
|
+
def initialize(command, host, logger=nil, stdin=nil)
|
146
|
+
@host=host
|
147
|
+
super(command, logger, stdin)
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def execute
|
153
|
+
if @stdin
|
154
|
+
Open3.popen3("ssh #{@host} #{@command} ; echo ExitCode: $? 1>&2")
|
155
|
+
else
|
156
|
+
Open3.popen3("ssh -n #{@host} #{@command} ; echo ExitCode: $? 1>&2")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class RemotesCommand < SSHCommand
|
162
|
+
|
163
|
+
# Creates a command and runs it
|
164
|
+
def self.run(command, host, remote_dir, logger=nil, stdin=nil, retries=0)
|
165
|
+
cmd_file = command.split(' ')[0]
|
166
|
+
|
167
|
+
cmd_string = "'if [ -x \"#{cmd_file}\" ]; then #{command}; else\
|
168
|
+
exit #{MAGIC_RC}; fi'"
|
169
|
+
|
170
|
+
cmd = self.new(cmd_string, host, logger, stdin)
|
171
|
+
cmd.run
|
172
|
+
|
173
|
+
while cmd.code != 0 and retries != 0
|
174
|
+
if cmd.code == MAGIC_RC
|
175
|
+
update_remotes(host, remote_dir, logger)
|
176
|
+
end
|
177
|
+
|
178
|
+
sleep 1
|
179
|
+
cmd.run
|
180
|
+
retries = retries - 1
|
181
|
+
end
|
182
|
+
|
183
|
+
cmd
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
ONE_LOCATION=ENV["ONE_LOCATION"]
|
189
|
+
|
190
|
+
if !ONE_LOCATION
|
191
|
+
REMOTES_LOCATION="/var/lib/one/remotes"
|
192
|
+
else
|
193
|
+
REMOTES_LOCATION=ONE_LOCATION+"/var/remotes/"
|
194
|
+
end
|
195
|
+
|
196
|
+
MAGIC_RC = 42
|
197
|
+
|
198
|
+
def self.update_remotes(host, remote_dir, logger=nil)
|
199
|
+
if logger != nil
|
200
|
+
logger.call("Remote worker node files not found")
|
201
|
+
logger.call("Updating remotes")
|
202
|
+
end
|
203
|
+
|
204
|
+
#recreate remote dir structure
|
205
|
+
SSHCommand.run("mkdir -p #{remote_dir}",host,logger)
|
206
|
+
|
207
|
+
# Use SCP to sync:
|
208
|
+
sync_cmd = "scp -rp #{REMOTES_LOCATION}/. #{host}:#{remote_dir}"
|
209
|
+
|
210
|
+
# Use rsync to sync:
|
211
|
+
# sync_cmd = "rsync -Laz #{REMOTES_LOCATION} #{host}:#{@remote_dir}"
|
212
|
+
LocalCommand.run(sync_cmd, logger)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
if $0 == __FILE__
|
218
|
+
|
219
|
+
command=GenericCommand.run("uname -a")
|
220
|
+
puts command.stderr
|
221
|
+
|
222
|
+
local_command=LocalCommand.run("uname -a")
|
223
|
+
puts "STDOUT:"
|
224
|
+
puts local_command.stdout
|
225
|
+
puts
|
226
|
+
puts "STDERR:"
|
227
|
+
puts local_command.stderr
|
228
|
+
|
229
|
+
ssh_command=SSHCommand.run("uname -a", "localhost")
|
230
|
+
puts "STDOUT:"
|
231
|
+
puts ssh_command.stdout
|
232
|
+
puts
|
233
|
+
puts "STDERR:"
|
234
|
+
puts ssh_command.stderr
|
235
|
+
|
236
|
+
fd = File.new("/etc/passwd")
|
237
|
+
str = String.new
|
238
|
+
fd.each {|line| str << line}
|
239
|
+
fd.close
|
240
|
+
|
241
|
+
ssh_in = SSHCommand.run("cat > /tmp/test","localhost",nil,str)
|
242
|
+
end
|