opennebula 4.90.10.rc1 → 5.0.0

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.
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