wf_node_api 0.6.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 +7 -0
- data/.gitignore +7 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +66 -0
- data/LICENSE +340 -0
- data/Makefile +19 -0
- data/README.md +78 -0
- data/Rakefile +2 -0
- data/Vagrantfile +102 -0
- data/_docs/api/Api/NodeApi.html +123 -0
- data/_docs/api/Api.html +149 -0
- data/_docs/api/Config/Check.html +331 -0
- data/_docs/api/Config.html +115 -0
- data/_docs/api/ConfigCheck.html +365 -0
- data/_docs/api/ContainerManager.html +1632 -0
- data/_docs/api/ContainerManagerAdapter/Lxc.html +1352 -0
- data/_docs/api/ContainerManagerAdapter/Vserver.html +1358 -0
- data/_docs/api/ContainerManagerAdapter.html +151 -0
- data/_docs/api/Error/NotFound.html +134 -0
- data/_docs/api/Error.html +115 -0
- data/_docs/api/NotFoundError.html +157 -0
- data/_docs/api/OS.html +234 -0
- data/_docs/api/ResourceManager.html +322 -0
- data/_docs/api/ResourceManagerAdapter/Linux.html +326 -0
- data/_docs/api/ResourceManagerAdapter.html +149 -0
- data/_docs/api/WfNodeApi.html +163 -0
- data/_docs/api/_index.html +239 -0
- data/_docs/api/class_list.html +58 -0
- data/_docs/api/css/common.css +1 -0
- data/_docs/api/css/full_list.css +57 -0
- data/_docs/api/css/style.css +339 -0
- data/_docs/api/file.README.html +146 -0
- data/_docs/api/file_list.html +60 -0
- data/_docs/api/frames.html +26 -0
- data/_docs/api/index.html +146 -0
- data/_docs/api/js/app.js +219 -0
- data/_docs/api/js/full_list.js +181 -0
- data/_docs/api/js/jquery.js +4 -0
- data/_docs/api/method_list.html +273 -0
- data/_docs/api/top-level-namespace.html +244 -0
- data/_docs/rest/api_data.js +1 -0
- data/_docs/rest/api_data.json +1 -0
- data/_docs/rest/api_project.js +1 -0
- data/_docs/rest/api_project.json +1 -0
- data/_docs/rest/css/style.css +538 -0
- data/_docs/rest/header.md +3 -0
- data/_docs/rest/img/favicon.ico +0 -0
- data/_docs/rest/img/glyphicons-halflings-white.png +0 -0
- data/_docs/rest/img/glyphicons-halflings.png +0 -0
- data/_docs/rest/index.html +658 -0
- data/_docs/rest/locales/de.js +25 -0
- data/_docs/rest/locales/fr.js +25 -0
- data/_docs/rest/locales/locale.js +43 -0
- data/_docs/rest/locales/nl.js +25 -0
- data/_docs/rest/locales/pl.js +25 -0
- data/_docs/rest/locales/pt_br.js +25 -0
- data/_docs/rest/locales/ru.js +25 -0
- data/_docs/rest/locales/zh.js +25 -0
- data/_docs/rest/main.js +691 -0
- data/_docs/rest/utils/handlebars_helper.js +327 -0
- data/_docs/rest/utils/send_sample_request.js +158 -0
- data/_docs/rest/vendor/bootstrap-responsive.min.css +9 -0
- data/_docs/rest/vendor/bootstrap.min.css +9 -0
- data/_docs/rest/vendor/bootstrap.min.js +6 -0
- data/_docs/rest/vendor/diff_match_patch.min.js +49 -0
- data/_docs/rest/vendor/handlebars.min.js +28 -0
- data/_docs/rest/vendor/jquery.min.js +4 -0
- data/_docs/rest/vendor/lodash.min.js +61 -0
- data/_docs/rest/vendor/path-to-regexp/LICENSE +21 -0
- data/_docs/rest/vendor/path-to-regexp/index.js +205 -0
- data/_docs/rest/vendor/polyfill.js +100 -0
- data/_docs/rest/vendor/prettify/lang-apollo.js +2 -0
- data/_docs/rest/vendor/prettify/lang-basic.js +3 -0
- data/_docs/rest/vendor/prettify/lang-clj.js +18 -0
- data/_docs/rest/vendor/prettify/lang-css.js +2 -0
- data/_docs/rest/vendor/prettify/lang-dart.js +3 -0
- data/_docs/rest/vendor/prettify/lang-erlang.js +2 -0
- data/_docs/rest/vendor/prettify/lang-go.js +1 -0
- data/_docs/rest/vendor/prettify/lang-hs.js +2 -0
- data/_docs/rest/vendor/prettify/lang-lisp.js +3 -0
- data/_docs/rest/vendor/prettify/lang-llvm.js +1 -0
- data/_docs/rest/vendor/prettify/lang-lua.js +2 -0
- data/_docs/rest/vendor/prettify/lang-matlab.js +6 -0
- data/_docs/rest/vendor/prettify/lang-ml.js +2 -0
- data/_docs/rest/vendor/prettify/lang-mumps.js +2 -0
- data/_docs/rest/vendor/prettify/lang-n.js +4 -0
- data/_docs/rest/vendor/prettify/lang-pascal.js +3 -0
- data/_docs/rest/vendor/prettify/lang-proto.js +1 -0
- data/_docs/rest/vendor/prettify/lang-r.js +2 -0
- data/_docs/rest/vendor/prettify/lang-rd.js +1 -0
- data/_docs/rest/vendor/prettify/lang-scala.js +2 -0
- data/_docs/rest/vendor/prettify/lang-sql.js +2 -0
- data/_docs/rest/vendor/prettify/lang-tcl.js +3 -0
- data/_docs/rest/vendor/prettify/lang-tex.js +1 -0
- data/_docs/rest/vendor/prettify/lang-vb.js +2 -0
- data/_docs/rest/vendor/prettify/lang-vhdl.js +3 -0
- data/_docs/rest/vendor/prettify/lang-wiki.js +2 -0
- data/_docs/rest/vendor/prettify/lang-xq.js +3 -0
- data/_docs/rest/vendor/prettify/lang-yaml.js +2 -0
- data/_docs/rest/vendor/prettify/prettify.css +1 -0
- data/_docs/rest/vendor/prettify/prettify.js +30 -0
- data/_docs/rest/vendor/prettify/run_prettify.js +34 -0
- data/_docs/rest/vendor/prettify.css +101 -0
- data/_docs/rest/vendor/require.min.js +36 -0
- data/apidoc.json +23 -0
- data/bin/wf_node_api +80 -0
- data/lib/wf_node_api/api/node_api.rb +360 -0
- data/lib/wf_node_api/config/config_template.erb +50 -0
- data/lib/wf_node_api/config_check.rb +50 -0
- data/lib/wf_node_api/container_manager.rb +286 -0
- data/lib/wf_node_api/container_manager_adapter/lxc.rb +431 -0
- data/lib/wf_node_api/container_manager_adapter/vserver.rb +448 -0
- data/lib/wf_node_api/error/not_found.rb +27 -0
- data/lib/wf_node_api/os.rb +32 -0
- data/lib/wf_node_api/resource_manager.rb +49 -0
- data/lib/wf_node_api/resource_manager_adapter/linux.rb +53 -0
- data/lib/wf_node_api/translations.rb +38 -0
- data/lib/wf_node_api/version.rb +28 -0
- data/lib/wf_node_api.rb +57 -0
- data/manifests/files/dhozac-vserver.repo +4 -0
- data/wf-node-api.gemspec +53 -0
- metadata +221 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
__ ___ _ _ _____ ____ __ __
|
|
3
|
+
\ \ / / |__ (_) |_ ___| ___| _ ___ ___ / ___| \/ |
|
|
4
|
+
\ \ /\ / /| '_ \| | __/ _ \ |_ | | | / __|/ _ \ | | |\/| |
|
|
5
|
+
\ V V / | | | | | || __/ _|| |_| \__ \ __/ |___| | | |
|
|
6
|
+
\_/\_/ |_| |_|_|\__\___|_| \__,_|___/\___|\____|_| |_|
|
|
7
|
+
Container Manager
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2015 David Prandzioch <kontakt@davidprandzioch.de>
|
|
10
|
+
|
|
11
|
+
This program is free software; you can redistribute it and/or
|
|
12
|
+
modify it under the terms of the GNU General Public License
|
|
13
|
+
as published by the Free Software Foundation; either version 2
|
|
14
|
+
of the License, or (at your option) any later version.
|
|
15
|
+
|
|
16
|
+
This program is distributed in the hope that it will be useful,
|
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License
|
|
22
|
+
along with this program; if not, write to the Free Software
|
|
23
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
24
|
+
=end
|
|
25
|
+
|
|
26
|
+
module ContainerManagerAdapter
|
|
27
|
+
# Container adapter for linux-vserver. Encapsulates all vserver specific command line
|
|
28
|
+
# wrapping
|
|
29
|
+
class Vserver
|
|
30
|
+
# Lists all available containers
|
|
31
|
+
#
|
|
32
|
+
# @return [Array]
|
|
33
|
+
def containers
|
|
34
|
+
container_list = []
|
|
35
|
+
|
|
36
|
+
self.container_names.each do |item|
|
|
37
|
+
container_list << container(item)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
container_list
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Starts a container with the given name
|
|
44
|
+
#
|
|
45
|
+
# @param name [String] The container name
|
|
46
|
+
#
|
|
47
|
+
# @raise [RuntimeError]
|
|
48
|
+
#
|
|
49
|
+
# @return [String] CLI output
|
|
50
|
+
def start(name)
|
|
51
|
+
res = Open3.capture3($vserver_cmd_start.gsub('[name]', name))
|
|
52
|
+
|
|
53
|
+
if res[2].exitstatus == 0 && state(name) == 'RUNNING'
|
|
54
|
+
$logger.info("container " + name + " successfully started")
|
|
55
|
+
return res[0].strip
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
$logger.warn("container " + name + " could not be started")
|
|
59
|
+
raise RuntimeError, res[1].strip
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Stops a container with the given name
|
|
63
|
+
#
|
|
64
|
+
# @param name [String] The container name
|
|
65
|
+
#
|
|
66
|
+
# @raise [RuntimeError]
|
|
67
|
+
#
|
|
68
|
+
# @return [String] CLI output
|
|
69
|
+
def stop(name)
|
|
70
|
+
if state(name) == 'STOPPED'
|
|
71
|
+
$logger.warn("container " + name + " could not be stopped, because it is not running")
|
|
72
|
+
raise RuntimeError, 'container is not running'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
res = Open3.capture3($vserver_cmd_stop.gsub('[name]', name))
|
|
76
|
+
|
|
77
|
+
if res[2].exitstatus == 0 && state(name) == 'STOPPED'
|
|
78
|
+
$logger.info("container " + name + " successfully stopped")
|
|
79
|
+
return res[0].strip
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
$logger.warn("container " + name + " could not be stopped")
|
|
83
|
+
raise RuntimeError, res[1].strip
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Kills a container with the given name
|
|
87
|
+
#
|
|
88
|
+
# @param name [String] The container name
|
|
89
|
+
#
|
|
90
|
+
# @raise [RuntimeError]
|
|
91
|
+
#
|
|
92
|
+
# @return [String] CLI output
|
|
93
|
+
def kill(name)
|
|
94
|
+
return stop(name)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Deletes a container with the given name
|
|
98
|
+
#
|
|
99
|
+
# @param name [String] The container name
|
|
100
|
+
#
|
|
101
|
+
# @raise [RuntimeError]
|
|
102
|
+
#
|
|
103
|
+
# @return [String] CLI output
|
|
104
|
+
def delete(name)
|
|
105
|
+
res = Open3.capture3($vserver_cmd_destroy.gsub('[name]', name))
|
|
106
|
+
|
|
107
|
+
if res[1].empty? && res[2].exitstatus == 0
|
|
108
|
+
$logger.info("container " + name + " successfully deleted")
|
|
109
|
+
return res[0].strip
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
$logger.warn("container" + name + " could not be deleted")
|
|
113
|
+
raise RuntimeError, res[1].strip
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Returns information for a single container
|
|
117
|
+
#
|
|
118
|
+
# @param name [String] The container name
|
|
119
|
+
#
|
|
120
|
+
# @return [Hash] Hash with information about the container
|
|
121
|
+
def container(name)
|
|
122
|
+
data = {}
|
|
123
|
+
|
|
124
|
+
data[:name] = name
|
|
125
|
+
data[:state] = translate_state(state(name))
|
|
126
|
+
data[:ip_address] = ip_addr(name)
|
|
127
|
+
data[:cpu_usage] = 0
|
|
128
|
+
data[:cpu_cores] = assigned_cpu_cores(name).count
|
|
129
|
+
data[:memory_limit_bytes] = memory_limit(name).to_i
|
|
130
|
+
data[:memory_usage_bytes] = memory_usage(name).to_i
|
|
131
|
+
data[:disk_space_gb] = 0
|
|
132
|
+
data[:disk_usage_gb] = 0
|
|
133
|
+
data[:container_type] = 'vserver'
|
|
134
|
+
|
|
135
|
+
data
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Creates a container with the given parameters
|
|
139
|
+
#
|
|
140
|
+
# @param name [String] The container name
|
|
141
|
+
# @param ip_address [String] A valid IPv4 address
|
|
142
|
+
# @param disk_size_gb [Integer] The disk size in GB
|
|
143
|
+
# @param memory_limit_mb [Integer] The memory limit in MB
|
|
144
|
+
# @param cpu_core_count [Integer] Amount of Vcores to assign. 0 for no limit
|
|
145
|
+
#
|
|
146
|
+
# @raise [RuntimeError]
|
|
147
|
+
#
|
|
148
|
+
# @return [String] CLI output
|
|
149
|
+
def create_container(name, ip_address, disk_size_gb, memory_limit_mb, cpu_core_count)
|
|
150
|
+
output = ''
|
|
151
|
+
|
|
152
|
+
begin
|
|
153
|
+
if cpu_core_count != 0
|
|
154
|
+
cpuset = generate_cpu_set(cpu_core_count, ResourceManager.new('linux'))
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
new_context = highest_context() + 1
|
|
158
|
+
cmd = $vserver_cmd_create.gsub('[name]', name).gsub('[ip_address]', ip_address).gsub('[context]', new_context.to_s)
|
|
159
|
+
|
|
160
|
+
create_result = Open3.capture3(cmd)
|
|
161
|
+
|
|
162
|
+
output += create_result[0]
|
|
163
|
+
output += create_result[1]
|
|
164
|
+
|
|
165
|
+
if create_result[2].exitstatus != 0
|
|
166
|
+
raise RuntimeError, 'command did not exit with status 0'
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# memory limit
|
|
170
|
+
memory_limit_bytes = memory_limit_mb.to_i * 1024 * 1024
|
|
171
|
+
page_size = `#{$page_size_cmd}`.to_i
|
|
172
|
+
memory_limit_pages = memory_limit_bytes / page_size
|
|
173
|
+
|
|
174
|
+
write_config_file(name, '/rlimits/rss.hard', memory_limit_pages.to_s)
|
|
175
|
+
|
|
176
|
+
if cpu_core_count != 0
|
|
177
|
+
# cpu core limit
|
|
178
|
+
write_config_file(name, '/cgroup/cpuset.cpus', cpuset)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
$logger.info("creation of container " + name + " successful")
|
|
182
|
+
return output.strip
|
|
183
|
+
rescue => e
|
|
184
|
+
$logger.warn("container " + name + " could not be created, rolling back...")
|
|
185
|
+
|
|
186
|
+
# rollback
|
|
187
|
+
delete(name) if exist?(name)
|
|
188
|
+
|
|
189
|
+
output += e.message
|
|
190
|
+
raise RuntimeError, output.strip
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Checks if a container with the given name exists
|
|
195
|
+
#
|
|
196
|
+
# @param name [String] The container name
|
|
197
|
+
#
|
|
198
|
+
# @return [Boolean] Existing/not existing
|
|
199
|
+
def exist?(name)
|
|
200
|
+
self.container_names.include?(name)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Returns the amount of free cpu cores
|
|
204
|
+
#
|
|
205
|
+
# @param resman [ResourceManager] A ResourceManager instance
|
|
206
|
+
#
|
|
207
|
+
# @return [Integer] The amount of free cpu cores
|
|
208
|
+
def free_cpu_core_count(resman)
|
|
209
|
+
self.free_cpu_cores(resman).count
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
protected
|
|
213
|
+
# Writes the config file of a vserver
|
|
214
|
+
#
|
|
215
|
+
# @param name [String] The container name
|
|
216
|
+
# @param path [String] Filepath
|
|
217
|
+
# @param content [String] File contents
|
|
218
|
+
#
|
|
219
|
+
# @return [Boolean] Result of File.write
|
|
220
|
+
def write_config_file(name, path, content)
|
|
221
|
+
config_path = "#{$vserver_config_dir.gsub('[name]', name)}#{path}"
|
|
222
|
+
`mkdir -p #{File.dirname(config_path)}`
|
|
223
|
+
|
|
224
|
+
File.write(config_path, content)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Reads the config file of a vserver
|
|
228
|
+
#
|
|
229
|
+
# @param name [String] The container name
|
|
230
|
+
#
|
|
231
|
+
# @raise [StandardError]
|
|
232
|
+
#
|
|
233
|
+
# @return [String] Contents of the configuration file
|
|
234
|
+
def read_config_file(name, path)
|
|
235
|
+
config_path = "#{$vserver_config_dir.gsub('[name]', name)}#{path}"
|
|
236
|
+
|
|
237
|
+
if File.exists?(config_path) == false
|
|
238
|
+
return nil
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
File.read(config_path).strip
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Creates a map of the vserver contexts
|
|
245
|
+
#
|
|
246
|
+
# @return [Hash]
|
|
247
|
+
def context_map
|
|
248
|
+
map = {}
|
|
249
|
+
|
|
250
|
+
containers.each() do |container|
|
|
251
|
+
map[container[:name]] = context(container[:name])
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
map
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Reads the context for a specific container
|
|
258
|
+
#
|
|
259
|
+
# @param name [String] The container name
|
|
260
|
+
#
|
|
261
|
+
# @raise [RuntimeError]
|
|
262
|
+
#
|
|
263
|
+
# @return [Integer] The context ID
|
|
264
|
+
def context(name)
|
|
265
|
+
file = "#{$vserver_config_dir.gsub('[name]', name)}/context"
|
|
266
|
+
|
|
267
|
+
if false == File.readable?(file)
|
|
268
|
+
raise RuntimeError, "file #{file} is not readable"
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
context = File.read(file)
|
|
272
|
+
|
|
273
|
+
context.to_i
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# Returns the stats for a container
|
|
277
|
+
#
|
|
278
|
+
# @param name [String] The container name
|
|
279
|
+
#
|
|
280
|
+
# @return [Array] Stats
|
|
281
|
+
def vserver_stat(name)
|
|
282
|
+
res = `#{$vserver_cmd_stat.gsub('[name]', name)}`
|
|
283
|
+
|
|
284
|
+
res.split(' ').map(&:strip)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# Returns the current memory usage
|
|
288
|
+
#
|
|
289
|
+
# @param name [String] The container name
|
|
290
|
+
#
|
|
291
|
+
# @return [Integer] Memory usage
|
|
292
|
+
def memory_usage(name)
|
|
293
|
+
stat = vserver_stat(name)
|
|
294
|
+
|
|
295
|
+
if stat[2] == nil
|
|
296
|
+
return nil
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
(stat[2][0..-2].to_f * 1024.0 * 1024.0).to_i
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Finds the highest context
|
|
303
|
+
#
|
|
304
|
+
# @return [Integer] The highest context
|
|
305
|
+
def highest_context
|
|
306
|
+
contextmap = context_map()
|
|
307
|
+
|
|
308
|
+
if contextmap.empty?
|
|
309
|
+
return 1
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
contextmap.max_by{|k, v| v}.last
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Returns the ip address for a container
|
|
316
|
+
#
|
|
317
|
+
# @return [String] The IP address
|
|
318
|
+
def ip_addr(name)
|
|
319
|
+
read_config_file(name, '/interfaces/0/ip')
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Returns the state for a container
|
|
323
|
+
#
|
|
324
|
+
# @param name [String] The container name
|
|
325
|
+
#
|
|
326
|
+
# @return [String] Container status, STOPPED or RUNNING
|
|
327
|
+
def state(name)
|
|
328
|
+
output = `#{$vserver_cmd_stat.gsub('[name]', name)}`
|
|
329
|
+
|
|
330
|
+
if output.empty?
|
|
331
|
+
return 'STOPPED'
|
|
332
|
+
else
|
|
333
|
+
return 'RUNNING'
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Returns the memory limit for a container
|
|
338
|
+
#
|
|
339
|
+
# @param name [String] The container name
|
|
340
|
+
#
|
|
341
|
+
# @return [Integer|NilClass] Memory limit in bytes
|
|
342
|
+
def memory_limit(name)
|
|
343
|
+
ctx = context(name)
|
|
344
|
+
page_size = `#{$page_size_cmd}`.to_i
|
|
345
|
+
|
|
346
|
+
memory_limit_result = `#{$vserver_cmd_get_memory_limit.gsub('[context]', ctx.to_s)}`
|
|
347
|
+
parts = memory_limit_result.split(' ').map(&:strip)
|
|
348
|
+
|
|
349
|
+
if parts.empty?
|
|
350
|
+
return nil
|
|
351
|
+
else
|
|
352
|
+
return (parts.last.to_i * page_size)
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Gets the globally assigned cpu cores
|
|
357
|
+
#
|
|
358
|
+
# @return [Array]
|
|
359
|
+
def used_cpu_cores
|
|
360
|
+
used_cores = []
|
|
361
|
+
|
|
362
|
+
container_names.each do |c|
|
|
363
|
+
self.assigned_cpu_cores(c).each do |cpu|
|
|
364
|
+
used_cores.push(cpu)
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
used_cores
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Gets the cpu cores assigned to a container
|
|
372
|
+
#
|
|
373
|
+
# @param name [String] The container name
|
|
374
|
+
#
|
|
375
|
+
# @return [Array] with cpu core ids
|
|
376
|
+
def assigned_cpu_cores(name)
|
|
377
|
+
value = self.read_config_file(name, '/cgroup/cpuset.cpus')
|
|
378
|
+
used_cores = []
|
|
379
|
+
|
|
380
|
+
if value == nil
|
|
381
|
+
return used_cores
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
value.split(',').each do |cpu|
|
|
385
|
+
if cpu.include?('-')
|
|
386
|
+
range = Range.new(*cpu.split('-').map(&:to_i))
|
|
387
|
+
|
|
388
|
+
range.each do |i|
|
|
389
|
+
used_cores.push(i)
|
|
390
|
+
end
|
|
391
|
+
else
|
|
392
|
+
used_cores.push(cpu.to_i)
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
used_cores
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
# Finds free cpu cores
|
|
400
|
+
#
|
|
401
|
+
# @param resman [ResourceManager] A ResourceManager instance
|
|
402
|
+
#
|
|
403
|
+
# @return [Array] Free cpu cores
|
|
404
|
+
def free_cpu_cores(resman)
|
|
405
|
+
raise ArgumentError, 'no valid ResourceManager instance' unless resman.is_a?(ResourceManager)
|
|
406
|
+
|
|
407
|
+
free_cores = []
|
|
408
|
+
used_cores = self.used_cpu_cores()
|
|
409
|
+
|
|
410
|
+
(0..(resman.total_cpu_cores-1)).each do |i|
|
|
411
|
+
if used_cores.include?(i) == false
|
|
412
|
+
free_cores.push(i)
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
free_cores
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# Generates a cpu set for a container
|
|
420
|
+
#
|
|
421
|
+
# @param count [Integer] Number of cpu cores to use
|
|
422
|
+
# @param resman [ResourceManager] A ResourceManager instance
|
|
423
|
+
#
|
|
424
|
+
# @raise [RuntimeError]
|
|
425
|
+
#
|
|
426
|
+
# @return [String] cpuset string
|
|
427
|
+
def generate_cpu_set(count, resman)
|
|
428
|
+
count = count.to_i
|
|
429
|
+
free_cores = self.free_cpu_cores(resman)
|
|
430
|
+
|
|
431
|
+
if count > free_cores.count
|
|
432
|
+
raise RuntimeError, 'not enough cpu cores left'
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
cores_to_use = []
|
|
436
|
+
|
|
437
|
+
count.times do
|
|
438
|
+
cores_to_use.push(free_cores.shift)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
cores_to_use.join(',')
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def container_names
|
|
445
|
+
`#{$vserver_cmd_ls}`.lines.map(&:strip).uniq
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
__ ___ _ _ _____ ____ __ __
|
|
3
|
+
\ \ / / |__ (_) |_ ___| ___| _ ___ ___ / ___| \/ |
|
|
4
|
+
\ \ /\ / /| '_ \| | __/ _ \ |_ | | | / __|/ _ \ | | |\/| |
|
|
5
|
+
\ V V / | | | | | || __/ _|| |_| \__ \ __/ |___| | | |
|
|
6
|
+
\_/\_/ |_| |_|_|\__\___|_| \__,_|___/\___|\____|_| |_|
|
|
7
|
+
Container Manager
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2015 David Prandzioch <kontakt@davidprandzioch.de>
|
|
10
|
+
|
|
11
|
+
This program is free software; you can redistribute it and/or
|
|
12
|
+
modify it under the terms of the GNU General Public License
|
|
13
|
+
as published by the Free Software Foundation; either version 2
|
|
14
|
+
of the License, or (at your option) any later version.
|
|
15
|
+
|
|
16
|
+
This program is distributed in the hope that it will be useful,
|
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License
|
|
22
|
+
along with this program; if not, write to the Free Software
|
|
23
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
24
|
+
=end
|
|
25
|
+
|
|
26
|
+
class NotFoundError < StandardError
|
|
27
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
__ ___ _ _ _____ ____ __ __
|
|
3
|
+
\ \ / / |__ (_) |_ ___| ___| _ ___ ___ / ___| \/ |
|
|
4
|
+
\ \ /\ / /| '_ \| | __/ _ \ |_ | | | / __|/ _ \ | | |\/| |
|
|
5
|
+
\ V V / | | | | | || __/ _|| |_| \__ \ __/ |___| | | |
|
|
6
|
+
\_/\_/ |_| |_|_|\__\___|_| \__,_|___/\___|\____|_| |_|
|
|
7
|
+
Container Manager
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2015 David Prandzioch <kontakt@davidprandzioch.de>
|
|
10
|
+
|
|
11
|
+
This program is free software; you can redistribute it and/or
|
|
12
|
+
modify it under the terms of the GNU General Public License
|
|
13
|
+
as published by the Free Software Foundation; either version 2
|
|
14
|
+
of the License, or (at your option) any later version.
|
|
15
|
+
|
|
16
|
+
This program is distributed in the hope that it will be useful,
|
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License
|
|
22
|
+
along with this program; if not, write to the Free Software
|
|
23
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
24
|
+
=end
|
|
25
|
+
|
|
26
|
+
module OS
|
|
27
|
+
# Returns true if this is a linux system
|
|
28
|
+
# @return [Boolean]
|
|
29
|
+
def self.linux?
|
|
30
|
+
RUBY_PLATFORM.include?('linux')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
__ ___ _ _ _____ ____ __ __
|
|
3
|
+
\ \ / / |__ (_) |_ ___| ___| _ ___ ___ / ___| \/ |
|
|
4
|
+
\ \ /\ / /| '_ \| | __/ _ \ |_ | | | / __|/ _ \ | | |\/| |
|
|
5
|
+
\ V V / | | | | | || __/ _|| |_| \__ \ __/ |___| | | |
|
|
6
|
+
\_/\_/ |_| |_|_|\__\___|_| \__,_|___/\___|\____|_| |_|
|
|
7
|
+
Container Manager
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2015 David Prandzioch <kontakt@davidprandzioch.de>
|
|
10
|
+
|
|
11
|
+
This program is free software; you can redistribute it and/or
|
|
12
|
+
modify it under the terms of the GNU General Public License
|
|
13
|
+
as published by the Free Software Foundation; either version 2
|
|
14
|
+
of the License, or (at your option) any later version.
|
|
15
|
+
|
|
16
|
+
This program is distributed in the hope that it will be useful,
|
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License
|
|
22
|
+
along with this program; if not, write to the Free Software
|
|
23
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
24
|
+
=end
|
|
25
|
+
|
|
26
|
+
# Top level class for resource management
|
|
27
|
+
class ResourceManager
|
|
28
|
+
|
|
29
|
+
# Initializes the ResourceManager with a matching adapter
|
|
30
|
+
#
|
|
31
|
+
# @raise [ArgumentError]
|
|
32
|
+
def initialize(type)
|
|
33
|
+
@resman = nil
|
|
34
|
+
|
|
35
|
+
if type == 'linux'
|
|
36
|
+
@resman = ResourceManagerAdapter::Linux.new
|
|
37
|
+
else
|
|
38
|
+
raise ArgumentError, 'invalid resourcemanager type supplied'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns the total number of cpu cores available on the system
|
|
43
|
+
#
|
|
44
|
+
# @return [Integer]
|
|
45
|
+
def total_cpu_cores
|
|
46
|
+
@resman.total_cpu_cores
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
__ ___ _ _ _____ ____ __ __
|
|
3
|
+
\ \ / / |__ (_) |_ ___| ___| _ ___ ___ / ___| \/ |
|
|
4
|
+
\ \ /\ / /| '_ \| | __/ _ \ |_ | | | / __|/ _ \ | | |\/| |
|
|
5
|
+
\ V V / | | | | | || __/ _|| |_| \__ \ __/ |___| | | |
|
|
6
|
+
\_/\_/ |_| |_|_|\__\___|_| \__,_|___/\___|\____|_| |_|
|
|
7
|
+
Container Manager
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2015 David Prandzioch <kontakt@davidprandzioch.de>
|
|
10
|
+
|
|
11
|
+
This program is free software; you can redistribute it and/or
|
|
12
|
+
modify it under the terms of the GNU General Public License
|
|
13
|
+
as published by the Free Software Foundation; either version 2
|
|
14
|
+
of the License, or (at your option) any later version.
|
|
15
|
+
|
|
16
|
+
This program is distributed in the hope that it will be useful,
|
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License
|
|
22
|
+
along with this program; if not, write to the Free Software
|
|
23
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
24
|
+
=end
|
|
25
|
+
|
|
26
|
+
module ResourceManagerAdapter
|
|
27
|
+
# ResourceManager adapter for Linux
|
|
28
|
+
class Linux
|
|
29
|
+
|
|
30
|
+
# Initializes the adapter
|
|
31
|
+
#
|
|
32
|
+
# @raise [RuntimeError]
|
|
33
|
+
def initialize
|
|
34
|
+
if $container_type == 'LXC' && File.exists?($lxc_cgroup_mount_path) == false
|
|
35
|
+
raise RuntimeError, 'no cgroup node found'
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Finds the total amount of cpu cores
|
|
40
|
+
#
|
|
41
|
+
# @return [Integer]
|
|
42
|
+
def total_cpu_cores
|
|
43
|
+
cpu_cores = `nproc`.strip.to_i
|
|
44
|
+
|
|
45
|
+
if $?.exitstatus != 0
|
|
46
|
+
raise RuntimeError, 'could not run nproc'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
return cpu_cores
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
__ ___ _ _ _____ ____ __ __
|
|
3
|
+
\ \ / / |__ (_) |_ ___| ___| _ ___ ___ / ___| \/ |
|
|
4
|
+
\ \ /\ / /| '_ \| | __/ _ \ |_ | | | / __|/ _ \ | | |\/| |
|
|
5
|
+
\ V V / | | | | | || __/ _|| |_| \__ \ __/ |___| | | |
|
|
6
|
+
\_/\_/ |_| |_|_|\__\___|_| \__,_|___/\___|\____|_| |_|
|
|
7
|
+
Container Manager
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2015 David Prandzioch <kontakt@davidprandzioch.de>
|
|
10
|
+
|
|
11
|
+
This program is free software; you can redistribute it and/or
|
|
12
|
+
modify it under the terms of the GNU General Public License
|
|
13
|
+
as published by the Free Software Foundation; either version 2
|
|
14
|
+
of the License, or (at your option) any later version.
|
|
15
|
+
|
|
16
|
+
This program is distributed in the hope that it will be useful,
|
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License
|
|
22
|
+
along with this program; if not, write to the Free Software
|
|
23
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
24
|
+
=end
|
|
25
|
+
|
|
26
|
+
# Translates a container state to the whitefuses states
|
|
27
|
+
#
|
|
28
|
+
# @param state [String] Original state
|
|
29
|
+
#
|
|
30
|
+
# @return [String] The translated state
|
|
31
|
+
def translate_state(state)
|
|
32
|
+
case state
|
|
33
|
+
when 'RUNNING'
|
|
34
|
+
return 'RUNNING'
|
|
35
|
+
else
|
|
36
|
+
return 'STOPPED'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
__ ___ _ _ _____ ____ __ __
|
|
3
|
+
\ \ / / |__ (_) |_ ___| ___| _ ___ ___ / ___| \/ |
|
|
4
|
+
\ \ /\ / /| '_ \| | __/ _ \ |_ | | | / __|/ _ \ | | |\/| |
|
|
5
|
+
\ V V / | | | | | || __/ _|| |_| \__ \ __/ |___| | | |
|
|
6
|
+
\_/\_/ |_| |_|_|\__\___|_| \__,_|___/\___|\____|_| |_|
|
|
7
|
+
Container Manager
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2015 David Prandzioch <kontakt@davidprandzioch.de>
|
|
10
|
+
|
|
11
|
+
This program is free software; you can redistribute it and/or
|
|
12
|
+
modify it under the terms of the GNU General Public License
|
|
13
|
+
as published by the Free Software Foundation; either version 2
|
|
14
|
+
of the License, or (at your option) any later version.
|
|
15
|
+
|
|
16
|
+
This program is distributed in the hope that it will be useful,
|
|
17
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
+
GNU General Public License for more details.
|
|
20
|
+
|
|
21
|
+
You should have received a copy of the GNU General Public License
|
|
22
|
+
along with this program; if not, write to the Free Software
|
|
23
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
24
|
+
=end
|
|
25
|
+
|
|
26
|
+
module WfNodeApi
|
|
27
|
+
VERSION = '0.6.0'
|
|
28
|
+
end
|