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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c03ee98531e1a62d3b49aaf94ba9095902f47705
4
- data.tar.gz: 1e78cdfffd8f093032950c10187c08d9001d5974
3
+ metadata.gz: 16cda589536bb5239ef70cb6898e8b00e3ebd9c9
4
+ data.tar.gz: 4e71745bc284fb49c762321fc7523064c3f11716
5
5
  SHA512:
6
- metadata.gz: a5cdec6a7a768b3c5b909d79cc6a945b8d84e1826940a4faa55a3d1ef7d107e1ec4a5760e9186aa6d824341cca7aef8c3bff7e71c23dcb99dd8d0cf5c240a941
7
- data.tar.gz: 21ae1b74c18aec9e508c4e0a570d3159fa6e7b606bf03800643b447a5eea1dc3cb19418ce535fc4e2944fb70d735f88986348dd854e9a775ae57b61d408c29b9
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