opennebula-cli 6.4.0 → 6.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/onedatastore +1 -1
- data/bin/oneflow +1 -1
- data/bin/oneflow-template +10 -12
- data/bin/onehost +1 -1
- data/bin/oneimage +6 -6
- data/bin/onelog +87 -12
- data/bin/onemarket +1 -1
- data/bin/onemarketapp +3 -3
- data/bin/onesecgroup +1 -1
- data/bin/onetemplate +44 -10
- data/bin/onevcenter +37 -2
- data/bin/onevm +23 -17
- data/bin/onevmgroup +1 -1
- data/bin/onevnet +3 -3
- data/bin/onevntemplate +41 -6
- data/bin/onevrouter +1 -1
- data/lib/one_helper/onevcenter_helper.rb +0 -55
- data/lib/one_helper/onevm_helper.rb +1 -1
- data/lib/one_helper.rb +51 -3
- data/share/schemas/xsd/host.xsd +2 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e72258e445621b7bb43729bce0ef5f95f4a0debd990f3983bd8845fa19eebc0
|
4
|
+
data.tar.gz: 4776aa4b2f7e59f114dee073504b2029f37cbf99ca544be0924af26a3f969a5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8293cbaf48c76f3601a0dd2d06b63aa3ff52bbbbb4c2fd510578224a4555cee0b0c9b6fae7486de1bc922d9cbc2a9844a4bac06e8b394ebea1b145dc6bae2718
|
7
|
+
data.tar.gz: e42b6fc85a88aa97ca9be7d1f464b048993ca443c9119121cae800018ef1f27a90899e2d0cbcd18e72ac142b7bd8aac2568bcf1997933e42388f7896f96bd289
|
data/bin/onedatastore
CHANGED
@@ -158,7 +158,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
158
158
|
|
159
159
|
command :chmod, chmod_desc, [:range, :datastoreid_list], :octet do
|
160
160
|
helper.perform_actions(args[0], options, 'Permissions changed') do |obj|
|
161
|
-
obj.chmod_octet(args[1])
|
161
|
+
obj.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
data/bin/oneflow
CHANGED
@@ -285,7 +285,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
285
285
|
|
286
286
|
Service.perform_actions(args[0]) do |service_id|
|
287
287
|
params = {}
|
288
|
-
params['octet'] = args[1]
|
288
|
+
params['octet'] = OpenNebulaHelper.to_octet(args[1])
|
289
289
|
|
290
290
|
json = Service.build_json_action('chmod', params)
|
291
291
|
|
data/bin/oneflow-template
CHANGED
@@ -59,7 +59,6 @@ require 'tempfile'
|
|
59
59
|
|
60
60
|
require 'command_parser'
|
61
61
|
require 'opennebula/oneflow_client'
|
62
|
-
require 'models'
|
63
62
|
require 'cli_helper'
|
64
63
|
require 'one_helper/oneflowtemplate_helper'
|
65
64
|
|
@@ -235,26 +234,26 @@ CommandParser::CmdParser.new(ARGV) do
|
|
235
234
|
Instantiate a Service Template
|
236
235
|
EOT
|
237
236
|
|
238
|
-
command :instantiate,
|
239
|
-
instantiate_desc,
|
240
|
-
:templateid,
|
241
|
-
[:file, nil],
|
237
|
+
command :instantiate, instantiate_desc, :templateid, [:file, nil],
|
242
238
|
:options => [MULTIPLE, Service::JSON_FORMAT, Service::TOP] do
|
243
239
|
number = options[:multiple] || 1
|
244
240
|
params = {}
|
245
241
|
rc = 0
|
242
|
+
client = helper.client(options)
|
246
243
|
|
247
244
|
number.times do
|
248
245
|
params['merge_template'] = nil
|
249
246
|
params['merge_template'] = JSON.parse(File.read(args[1])) if args[1]
|
250
247
|
|
251
248
|
unless params['merge_template']
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
249
|
+
response = client.get("#{RESOURCE_PATH}/#{args[0]}")
|
250
|
+
|
251
|
+
if CloudClient.is_error?(response)
|
252
|
+
rc = [response.code.to_i, response.to_s]
|
253
|
+
break
|
254
|
+
end
|
256
255
|
|
257
|
-
body = JSON.parse(
|
256
|
+
body = JSON.parse(response.body)['DOCUMENT']['TEMPLATE']['BODY']
|
258
257
|
|
259
258
|
params['merge_template'] = helper.custom_attrs(
|
260
259
|
body['custom_attrs']
|
@@ -267,7 +266,6 @@ CommandParser::CmdParser.new(ARGV) do
|
|
267
266
|
end
|
268
267
|
|
269
268
|
json = Service.build_json_action('instantiate', params)
|
270
|
-
client = helper.client(options)
|
271
269
|
response = client.post("#{RESOURCE_PATH}/#{args[0]}/action", json)
|
272
270
|
|
273
271
|
if CloudClient.is_error?(response)
|
@@ -346,7 +344,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
346
344
|
|
347
345
|
Service.perform_actions(args[0]) do |service_id|
|
348
346
|
params = {}
|
349
|
-
params['octet'] = args[1]
|
347
|
+
params['octet'] = OpenNebulaHelper.to_octet(args[1])
|
350
348
|
|
351
349
|
json = Service.build_json_action('chmod', params)
|
352
350
|
|
data/bin/onehost
CHANGED
@@ -339,7 +339,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
339
339
|
rescue StandardError => e
|
340
340
|
STDERR.puts e
|
341
341
|
end
|
342
|
-
helper.perform_actions(args[0], options, '
|
342
|
+
helper.perform_actions(args[0], options, 'flushing') do |host|
|
343
343
|
host.flush action
|
344
344
|
end
|
345
345
|
end
|
data/bin/oneimage
CHANGED
@@ -234,7 +234,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
234
234
|
|
235
235
|
command :clone, clone_desc, :imageid, :name,
|
236
236
|
:options => [OneDatastoreHelper::DATASTORE] do
|
237
|
-
helper.perform_action(args[0], options, '
|
237
|
+
helper.perform_action(args[0], options, 'cloning') do |image|
|
238
238
|
ds_id = options[:datastore] || -1 # -1 clones to self
|
239
239
|
res = image.clone(args[1], ds_id)
|
240
240
|
|
@@ -252,7 +252,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
252
252
|
EOT
|
253
253
|
|
254
254
|
command :delete, delete_desc, [:range, :imageid_list] do
|
255
|
-
helper.perform_actions(args[0], options, '
|
255
|
+
helper.perform_actions(args[0], options, 'deleting') do |image|
|
256
256
|
image.delete
|
257
257
|
end
|
258
258
|
end
|
@@ -363,7 +363,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
363
363
|
command :chmod, chmod_desc, [:range, :imageid_list], :octet do
|
364
364
|
helper.perform_actions(args[0], options,
|
365
365
|
'Permissions changed') do |image|
|
366
|
-
image.chmod_octet(args[1])
|
366
|
+
image.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
367
367
|
end
|
368
368
|
end
|
369
369
|
|
@@ -382,7 +382,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
382
382
|
EOT
|
383
383
|
|
384
384
|
command :'snapshot-delete', snapshot_delete_desc, :imageid, :snapshot_id do
|
385
|
-
helper.perform_action(args[0], options, 'snapshot
|
385
|
+
helper.perform_action(args[0], options, 'deleting snapshot') do |o|
|
386
386
|
o.snapshot_delete(args[1].to_i)
|
387
387
|
end
|
388
388
|
end
|
@@ -392,7 +392,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
392
392
|
EOT
|
393
393
|
|
394
394
|
command :'snapshot-revert', snapshot_revert_desc, :imageid, :snapshot_id do
|
395
|
-
helper.perform_action(args[0], options, 'image state
|
395
|
+
helper.perform_action(args[0], options, 'reverting image state') do |o|
|
396
396
|
o.snapshot_revert(args[1].to_i)
|
397
397
|
end
|
398
398
|
end
|
@@ -405,7 +405,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
405
405
|
snapshot_flatten_desc,
|
406
406
|
:imageid,
|
407
407
|
:snapshot_id do
|
408
|
-
helper.perform_action(args[0], options, 'snapshot
|
408
|
+
helper.perform_action(args[0], options, 'flattening snapshot') do |o|
|
409
409
|
o.snapshot_flatten(args[1].to_i)
|
410
410
|
end
|
411
411
|
end
|
data/bin/onelog
CHANGED
@@ -20,10 +20,34 @@ ONE_LOCATION = ENV['ONE_LOCATION']
|
|
20
20
|
|
21
21
|
if !ONE_LOCATION
|
22
22
|
RUBY_LIB_LOCATION = '/usr/lib/one/ruby'
|
23
|
+
GEMS_LOCATION = '/usr/share/one/gems'
|
24
|
+
LOG_LOCATION = '/var/log/one'
|
23
25
|
else
|
24
26
|
RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
|
27
|
+
GEMS_LOCATION = ONE_LOCATION + '/share/gems'
|
28
|
+
LOG_LOCATION = ONE_LOCATION + '/var'
|
25
29
|
end
|
26
30
|
|
31
|
+
# %%RUBYGEMS_SETUP_BEGIN%%
|
32
|
+
if File.directory?(GEMS_LOCATION)
|
33
|
+
real_gems_path = File.realpath(GEMS_LOCATION)
|
34
|
+
if !defined?(Gem) || Gem.path != [real_gems_path]
|
35
|
+
$LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ }
|
36
|
+
|
37
|
+
# Suppress warnings from Rubygems
|
38
|
+
# https://github.com/OpenNebula/one/issues/5379
|
39
|
+
begin
|
40
|
+
verb = $VERBOSE
|
41
|
+
$VERBOSE = nil
|
42
|
+
require 'rubygems'
|
43
|
+
Gem.use_paths(real_gems_path)
|
44
|
+
ensure
|
45
|
+
$VERBOSE = verb
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# %%RUBYGEMS_SETUP_END%%
|
50
|
+
|
27
51
|
$LOAD_PATH << RUBY_LIB_LOCATION
|
28
52
|
$LOAD_PATH << RUBY_LIB_LOCATION + '/cli'
|
29
53
|
|
@@ -33,13 +57,13 @@ DEFAULT_PAGER = 'less'
|
|
33
57
|
# List of OpenNebula services and the logs files
|
34
58
|
SERVICES = {
|
35
59
|
'fireedge' => { :log => 'fireedge.log', :error => 'fireedge.error' },
|
36
|
-
'monitor' => 'monitor.log',
|
37
|
-
'novnc' => 'novnc.log',
|
38
|
-
'oned' => 'oned.log',
|
60
|
+
'monitor' => { :log => 'monitor.log' },
|
61
|
+
'novnc' => { :log => 'novnc.log' },
|
62
|
+
'oned' => { :log => 'oned.log' },
|
39
63
|
'onehem' => { :log => 'onehem.log', :error => 'onehem.error' },
|
40
|
-
'sched' => 'sched.log',
|
64
|
+
'sched' => { :log => 'sched.log' },
|
41
65
|
'sunstone' => { :log => 'sunstone.log', :error => 'sunstone.error' },
|
42
|
-
'vcenter' => 'vcenter_monitor.log'
|
66
|
+
'vcenter' => { :log => 'vcenter_monitor.log' }
|
43
67
|
}
|
44
68
|
|
45
69
|
require 'command_parser'
|
@@ -77,25 +101,76 @@ CommandParser::CmdParser.new(ARGV) do
|
|
77
101
|
EOT
|
78
102
|
|
79
103
|
command :get, get_desc, :service, :options => [TYPE, PAGER, PAGER_OPTS] do
|
80
|
-
|
104
|
+
logs = SERVICES[args[0]]
|
105
|
+
pager = options[:pager] || DEFAULT_PAGER
|
106
|
+
|
107
|
+
unless logs
|
81
108
|
STDERR.puts "Service '#{args[0]}' not found"
|
82
109
|
exit 1
|
83
110
|
end
|
84
111
|
|
85
|
-
if options[:type] && !
|
112
|
+
if options[:type] && !logs[options[:type].to_sym]
|
86
113
|
STDERR.puts "Log file type '#{options[:type]}' not found"
|
87
114
|
exit 1
|
88
115
|
end
|
89
116
|
|
90
|
-
|
91
|
-
|
117
|
+
options[:type].nil? ? f = logs[:log] : f = logs[options[:type].to_sym]
|
118
|
+
|
119
|
+
system("#{pager} #{options[:pager_opts]} #{LOG_LOCATION}/#{f}")
|
120
|
+
end
|
121
|
+
|
122
|
+
vm_desc = <<-EOT.unindent
|
123
|
+
Gets VM log
|
124
|
+
EOT
|
125
|
+
|
126
|
+
command :'get-vm', vm_desc, :id, :options => [PAGER, PAGER_OPTS] do
|
127
|
+
pager = options[:pager] || DEFAULT_PAGER
|
128
|
+
|
129
|
+
begin
|
130
|
+
Integer(args[0])
|
131
|
+
|
132
|
+
if !ONE_LOCATION
|
133
|
+
file = "#{LOG_LOCATION}/#{args[0]}.log"
|
134
|
+
else
|
135
|
+
file = "#{LOG_LOCATION}/vms/#{args[0]}/vm.log"
|
136
|
+
end
|
137
|
+
|
138
|
+
unless File.exist?(file)
|
139
|
+
STDERR.puts "No LOG file found for '#{args[0]}' VM"
|
140
|
+
exit 1
|
141
|
+
end
|
142
|
+
|
143
|
+
system("#{pager} #{options[:pager_opts]} #{file}")
|
144
|
+
rescue StandardError
|
145
|
+
STDERR.puts 'Only ID is supported'
|
146
|
+
exit 1
|
92
147
|
end
|
148
|
+
end
|
93
149
|
|
94
|
-
|
150
|
+
service_desc = <<-EOT.unindent
|
151
|
+
Gets Service log
|
152
|
+
EOT
|
153
|
+
|
154
|
+
command :'get-service',
|
155
|
+
service_desc,
|
156
|
+
:id,
|
157
|
+
:options => [PAGER, PAGER_OPTS] do
|
95
158
|
pager = options[:pager] || DEFAULT_PAGER
|
96
159
|
|
97
|
-
|
160
|
+
begin
|
161
|
+
Integer(args[0])
|
162
|
+
|
163
|
+
file = "#{LOG_LOCATION}/oneflow/#{args[0]}.log"
|
98
164
|
|
99
|
-
|
165
|
+
unless File.exist?(file)
|
166
|
+
STDERR.puts "No LOG file found for '#{args[0]}' service"
|
167
|
+
exit 1
|
168
|
+
end
|
169
|
+
|
170
|
+
system("#{pager} #{options[:pager_opts]} #{file}")
|
171
|
+
rescue StandardError
|
172
|
+
STDERR.puts 'Only ID is supported'
|
173
|
+
exit 1
|
174
|
+
end
|
100
175
|
end
|
101
176
|
end
|
data/bin/onemarket
CHANGED
@@ -151,7 +151,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
151
151
|
|
152
152
|
command :chmod, chmod_desc, [:range, :marketplaceid_list], :octet do
|
153
153
|
helper.perform_actions(args[0], options, 'Permissions changed') do |obj|
|
154
|
-
obj.chmod_octet(args[1])
|
154
|
+
obj.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
data/bin/onemarketapp
CHANGED
@@ -284,7 +284,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
284
284
|
EOT
|
285
285
|
|
286
286
|
command :export, export_desc, :appid, :name, :options => EXPORT_OPTIONS do
|
287
|
-
helper.perform_action(args[0], options, '
|
287
|
+
helper.perform_action(args[0], options, 'exporting') do |obj|
|
288
288
|
tag ="tag=#{options[:tag]}" if options[:tag]
|
289
289
|
|
290
290
|
obj.extend(MarketPlaceAppExt)
|
@@ -325,7 +325,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
325
325
|
|
326
326
|
command :download, download_desc, :appid, :path,
|
327
327
|
:options => [OpenNebulaHelper::FORCE] do
|
328
|
-
helper.perform_action(args[0], options, '
|
328
|
+
helper.perform_action(args[0], options, 'downloading') do
|
329
329
|
download_args = [:marketplaceapp, args[0], args[1], options[:force]]
|
330
330
|
OpenNebulaHelper.download_resource_sunstone(*download_args)
|
331
331
|
end
|
@@ -388,7 +388,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
388
388
|
|
389
389
|
command :chmod, chmod_desc, [:range, :appid_list], :octet do
|
390
390
|
helper.perform_actions(args[0], options, 'Permissions changed') do |app|
|
391
|
-
app.chmod_octet(args[1])
|
391
|
+
app.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
392
392
|
end
|
393
393
|
end
|
394
394
|
|
data/bin/onesecgroup
CHANGED
@@ -174,7 +174,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
174
174
|
|
175
175
|
command :chmod, chmod_desc, [:range, :secgroupid_list], :octet do
|
176
176
|
helper.perform_actions(args[0], options, 'Permissions changed') do |t|
|
177
|
-
t.chmod_octet(args[1])
|
177
|
+
t.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
178
178
|
end
|
179
179
|
end
|
180
180
|
|
data/bin/onetemplate
CHANGED
@@ -87,6 +87,14 @@ CommandParser::CmdParser.new(ARGV) do
|
|
87
87
|
:description => 'lock all actions'
|
88
88
|
}
|
89
89
|
|
90
|
+
PREFIX = {
|
91
|
+
:name => 'prefix',
|
92
|
+
:large => '--prefix prefix',
|
93
|
+
:description => 'Prefix to autogenerate name, e.g: 001, 01',
|
94
|
+
:format => String
|
95
|
+
|
96
|
+
}
|
97
|
+
|
90
98
|
########################################################################
|
91
99
|
# Global Options
|
92
100
|
########################################################################
|
@@ -102,7 +110,8 @@ CommandParser::CmdParser.new(ARGV) do
|
|
102
110
|
OneTemplateHelper::MULTIPLE,
|
103
111
|
OneTemplateHelper::USERDATA,
|
104
112
|
OneVMHelper::HOLD,
|
105
|
-
OneTemplateHelper::PERSISTENT
|
113
|
+
OneTemplateHelper::PERSISTENT,
|
114
|
+
PREFIX
|
106
115
|
]
|
107
116
|
|
108
117
|
########################################################################
|
@@ -252,16 +261,37 @@ CommandParser::CmdParser.new(ARGV) do
|
|
252
261
|
number = options[:multiple] || 1
|
253
262
|
user_inputs = options[:user_inputs]
|
254
263
|
|
255
|
-
number.times do |i|
|
256
|
-
exit_code = helper.perform_action(
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
264
|
+
number.times.each_with_index do |i, index|
|
265
|
+
exit_code = helper.perform_action(
|
266
|
+
args[0],
|
267
|
+
options,
|
268
|
+
'instantiated'
|
269
|
+
) do |t|
|
270
|
+
name = options[:name]
|
271
|
+
prefix = options[:prefix]
|
272
|
+
c_i = nil
|
273
|
+
p = nil
|
274
|
+
|
275
|
+
if prefix && name
|
276
|
+
# Get leading zeros
|
277
|
+
p = prefix.scan(/^0+/)[0]
|
278
|
+
|
279
|
+
# Get current index
|
280
|
+
c_i = prefix.gsub(p, '') if p
|
281
|
+
|
282
|
+
# Convert it to Integer to check if we can use it
|
283
|
+
begin
|
284
|
+
c_i = Integer(c_i)
|
285
|
+
name = name.gsub('%i', "#{p}#{c_i + index}")
|
286
|
+
rescue StandardError
|
287
|
+
end
|
288
|
+
elsif name
|
289
|
+
name = name.gsub('%i', i.to_s)
|
290
|
+
end
|
262
291
|
|
292
|
+
on_hold = !options[:hold].nil?
|
263
293
|
extra_template = ''
|
264
|
-
rc
|
294
|
+
rc = t.info
|
265
295
|
|
266
296
|
if OpenNebula.is_error?(rc)
|
267
297
|
STDERR.puts rc.message
|
@@ -281,6 +311,10 @@ CommandParser::CmdParser.new(ARGV) do
|
|
281
311
|
extra_template = res.last
|
282
312
|
end
|
283
313
|
|
314
|
+
if c_i
|
315
|
+
extra_template.gsub!('%i', "#{p}#{c_i + index}")
|
316
|
+
end
|
317
|
+
|
284
318
|
if !user_inputs
|
285
319
|
user_inputs = OneTemplateHelper.get_user_inputs(t.to_hash)
|
286
320
|
else
|
@@ -344,7 +378,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
344
378
|
recursive = (options[:recursive] == true)
|
345
379
|
|
346
380
|
helper.perform_actions(args[0], options, 'Permissions changed') do |t|
|
347
|
-
t.chmod_octet(args[1], recursive)
|
381
|
+
t.chmod_octet(OpenNebulaHelper.to_octet(args[1]), recursive)
|
348
382
|
end
|
349
383
|
end
|
350
384
|
|
data/bin/onevcenter
CHANGED
@@ -409,7 +409,42 @@ CommandParser::CmdParser.new(ARGV) do
|
|
409
409
|
|
410
410
|
begin
|
411
411
|
print '.'
|
412
|
-
|
412
|
+
|
413
|
+
client = Client.new
|
414
|
+
|
415
|
+
vm_pool = VirtualMachinePool.new(client, -1)
|
416
|
+
host_pool = HostPool.new(client)
|
417
|
+
deploy_id = -1
|
418
|
+
host_id = -1
|
419
|
+
hostname = ''
|
420
|
+
|
421
|
+
rc = vm_pool.info
|
422
|
+
raise rc.message if OpenNebula.is_error?(rc)
|
423
|
+
|
424
|
+
rc = host_pool.info
|
425
|
+
raise rc.message if OpenNebula.is_error?(rc)
|
426
|
+
|
427
|
+
vm_pool.each do |vm|
|
428
|
+
next if vm.id.to_s != vmid
|
429
|
+
|
430
|
+
deploy_id = vm.deploy_id
|
431
|
+
vm_history = vm.to_hash['VM']['HISTORY_RECORDS']['HISTORY']
|
432
|
+
hostname = vm_history['HOSTNAME']
|
433
|
+
break
|
434
|
+
end
|
435
|
+
|
436
|
+
host_pool.each do |host|
|
437
|
+
if host.name == hostname
|
438
|
+
host_id = host.id
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
vi_client = VCenterDriver::VIClient.new_from_host(host_id)
|
443
|
+
vm = VCenterDriver::VirtualMachine
|
444
|
+
.new(vi_client, deploy_id, vmid)
|
445
|
+
|
446
|
+
keys = vm.extra_config_keys
|
447
|
+
|
413
448
|
print '.'
|
414
449
|
|
415
450
|
if keys.empty?
|
@@ -422,7 +457,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
422
457
|
puts 'The following keys will be removed:'
|
423
458
|
keys.each {|key| puts "\t- #{key}" }
|
424
459
|
|
425
|
-
|
460
|
+
vm.clear_tags
|
426
461
|
rescue StandardError => e
|
427
462
|
STDERR.puts "Couldn't clear VM tags. Reason: #{e.message}"
|
428
463
|
exit 1
|
data/bin/onevm
CHANGED
@@ -472,7 +472,13 @@ CommandParser::CmdParser.new(ARGV) do
|
|
472
472
|
verbose = "disk #{disk_id} prepared to be saved in " \
|
473
473
|
"the image #{image_name}"
|
474
474
|
else
|
475
|
-
snapshot_id =
|
475
|
+
err, snapshot_id = helper.retrieve_disk_snapshot_id(args[0],
|
476
|
+
snapshot_id)
|
477
|
+
|
478
|
+
if err == -1
|
479
|
+
STDERR.puts snapshot_id
|
480
|
+
exit(-1)
|
481
|
+
end
|
476
482
|
|
477
483
|
verbose = "disk #{disk_id} snapshot #{snapshot_id} prepared to " \
|
478
484
|
"be saved in the image #{image_name}"
|
@@ -511,7 +517,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
511
517
|
if !options[:schedule].nil?
|
512
518
|
helper.schedule_actions(args[0], options, command_name)
|
513
519
|
else
|
514
|
-
helper.perform_actions(args[0], options, '
|
520
|
+
helper.perform_actions(args[0], options, 'terminating') do |vm|
|
515
521
|
vm.terminate(options[:hard] == true)
|
516
522
|
end
|
517
523
|
end
|
@@ -827,7 +833,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
827
833
|
template << ' ]'
|
828
834
|
end
|
829
835
|
|
830
|
-
helper.perform_action(args[0], options, '
|
836
|
+
helper.perform_action(args[0], options, 'Attaching disk') do |vm|
|
831
837
|
vm.disk_attach(template)
|
832
838
|
end
|
833
839
|
end
|
@@ -841,7 +847,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
841
847
|
command :"disk-detach", disk_detach_desc, :vmid, :diskid do
|
842
848
|
diskid = args[1].to_i
|
843
849
|
|
844
|
-
helper.perform_action(args[0], options, '
|
850
|
+
helper.perform_action(args[0], options, 'Detaching disk') do |vm|
|
845
851
|
vm.disk_detach(diskid)
|
846
852
|
end
|
847
853
|
end
|
@@ -904,7 +910,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
904
910
|
end
|
905
911
|
end
|
906
912
|
|
907
|
-
helper.perform_action(args[0], options, '
|
913
|
+
helper.perform_action(args[0], options, 'Attaching NIC') do |vm|
|
908
914
|
vm.nic_attach(template)
|
909
915
|
end
|
910
916
|
end
|
@@ -918,7 +924,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
918
924
|
command :"nic-detach", nic_detach_desc, :vmid, :nicid do
|
919
925
|
nicid = args[1].to_i
|
920
926
|
|
921
|
-
helper.perform_action(args[0], options, '
|
927
|
+
helper.perform_action(args[0], options, 'Detaching NIC') do |vm|
|
922
928
|
vm.nic_detach(nicid)
|
923
929
|
end
|
924
930
|
end
|
@@ -933,7 +939,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
933
939
|
nic_id = args[1].to_i
|
934
940
|
sg_id = args[2].to_i
|
935
941
|
|
936
|
-
helper.perform_action(args[0], options, '
|
942
|
+
helper.perform_action(args[0], options, 'Attaching SG') do |vm|
|
937
943
|
vm.sg_attach(nic_id, sg_id)
|
938
944
|
end
|
939
945
|
end
|
@@ -948,7 +954,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
948
954
|
nic_id = args[1].to_i
|
949
955
|
sg_id = args[2].to_i
|
950
956
|
|
951
|
-
helper.perform_action(args[0], options, '
|
957
|
+
helper.perform_action(args[0], options, 'Detaching SG') do |vm|
|
952
958
|
vm.sg_detach(nic_id, sg_id)
|
953
959
|
end
|
954
960
|
end
|
@@ -981,7 +987,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
981
987
|
|
982
988
|
command :chmod, chmod_desc, [:range, :vmid_list], :octet do
|
983
989
|
helper.perform_actions(args[0], options, 'Permissions changed') do |vm|
|
984
|
-
vm.chmod_octet(args[1])
|
990
|
+
vm.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
985
991
|
end
|
986
992
|
end
|
987
993
|
|
@@ -1041,7 +1047,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1041
1047
|
|
1042
1048
|
helper.schedule_actions(args[0], options, @comm_name)
|
1043
1049
|
else
|
1044
|
-
helper.perform_actions(args[0], options, 'snapshot
|
1050
|
+
helper.perform_actions(args[0], options, 'creating snapshot') do |o|
|
1045
1051
|
o.snapshot_create(args[1])
|
1046
1052
|
end
|
1047
1053
|
end
|
@@ -1065,7 +1071,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1065
1071
|
|
1066
1072
|
helper.schedule_actions([args[0]], options, @comm_name)
|
1067
1073
|
else
|
1068
|
-
helper.perform_action(args[0], options, 'snapshot
|
1074
|
+
helper.perform_action(args[0], options, 'reverting snapshot') do |o|
|
1069
1075
|
o.snapshot_revert(args[1].to_i)
|
1070
1076
|
end
|
1071
1077
|
end
|
@@ -1089,7 +1095,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1089
1095
|
|
1090
1096
|
helper.schedule_actions([args[0]], options, @comm_name)
|
1091
1097
|
else
|
1092
|
-
helper.perform_action(args[0], options, 'snapshot
|
1098
|
+
helper.perform_action(args[0], options, 'deleting snapshot') do |o|
|
1093
1099
|
o.snapshot_delete(args[1])
|
1094
1100
|
end
|
1095
1101
|
end
|
@@ -1117,7 +1123,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1117
1123
|
helper.schedule_actions([args[0]], options, @comm_name)
|
1118
1124
|
else
|
1119
1125
|
helper.perform_action(args[0], options,
|
1120
|
-
'disk snapshot
|
1126
|
+
'creating disk snapshot') do |o|
|
1121
1127
|
o.disk_snapshot_create(args[1].to_i, args[2])
|
1122
1128
|
end
|
1123
1129
|
end
|
@@ -1144,7 +1150,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1144
1150
|
helper.schedule_actions([args[0]], options, @comm_name)
|
1145
1151
|
else
|
1146
1152
|
helper.perform_action(args[0], options,
|
1147
|
-
'disk snapshot
|
1153
|
+
'reverting disk snapshot') do |o|
|
1148
1154
|
o.disk_snapshot_revert(args[1].to_i, args[2].to_i)
|
1149
1155
|
end
|
1150
1156
|
end
|
@@ -1171,7 +1177,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1171
1177
|
helper.schedule_actions([args[0]], options, @comm_name)
|
1172
1178
|
else
|
1173
1179
|
helper.perform_action(args[0], options,
|
1174
|
-
'disk snapshot
|
1180
|
+
'deleting disk snapshot') do |o|
|
1175
1181
|
o.disk_snapshot_delete(args[1].to_i, args[2].to_i)
|
1176
1182
|
end
|
1177
1183
|
end
|
@@ -1207,7 +1213,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1207
1213
|
|
1208
1214
|
command :"disk-resize", disk_resize_desc,
|
1209
1215
|
:vmid, :diskid, :size do
|
1210
|
-
helper.perform_action(args[0], options, 'disk
|
1216
|
+
helper.perform_action(args[0], options, 'resizing disk') do |o|
|
1211
1217
|
o.info
|
1212
1218
|
size = o["/VM/TEMPLATE/DISK[DISK_ID='#{args[1]}']/SIZE"].to_i
|
1213
1219
|
|
@@ -1344,7 +1350,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
1344
1350
|
FEATURES = ["ACPI", "PAE", "APIC", "LOCALTIME", "HYPERV", "GUEST_AGENT", "IOTHREADS"]
|
1345
1351
|
INPUT = ["TYPE", "BUS"]
|
1346
1352
|
GRAPHICS = ["TYPE", "LISTEN", "PASSWD", "KEYMAP" ]
|
1347
|
-
RAW = ["DATA", "DATA_VMX", "TYPE"]
|
1353
|
+
RAW = ["DATA", "DATA_VMX", "TYPE", "VALIDATE"]
|
1348
1354
|
CPU_MODEL = ["MODEL"]
|
1349
1355
|
CONTEXT (any value, **variable substitution will be made**)
|
1350
1356
|
EOT
|
data/bin/onevmgroup
CHANGED
@@ -197,7 +197,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
197
197
|
|
198
198
|
command :chmod, chmod_desc, [:range, :vmgroupid_list], :octet do
|
199
199
|
helper.perform_actions(args[0], options, 'Permissions changed') do |t|
|
200
|
-
t.chmod_octet(args[1])
|
200
|
+
t.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
201
201
|
end
|
202
202
|
end
|
203
203
|
|
data/bin/onevnet
CHANGED
@@ -176,7 +176,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
176
176
|
EOT
|
177
177
|
|
178
178
|
command :delete, delete_desc, [:range, :vnetid_list] do
|
179
|
-
helper.perform_actions(args[0], options, '
|
179
|
+
helper.perform_actions(args[0], options, 'deleting') do |vn|
|
180
180
|
vn.delete
|
181
181
|
end
|
182
182
|
end
|
@@ -187,7 +187,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
187
187
|
|
188
188
|
command :addar, addar_desc, :vnetid, [:file, nil],
|
189
189
|
:options => STD_OPTIONS + OneVNetHelper::ADDAR_OPTIONS do
|
190
|
-
helper.perform_action(args[0], options, '
|
190
|
+
helper.perform_action(args[0], options, 'address range added') do |vn|
|
191
191
|
if args[1]
|
192
192
|
ar = File.read(args[1])
|
193
193
|
else
|
@@ -335,7 +335,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
335
335
|
|
336
336
|
command :chmod, chmod_desc, [:range, :vnetid_list], :octet do
|
337
337
|
helper.perform_actions(args[0], options, 'Permissions changed') do |vn|
|
338
|
-
vn.chmod_octet(args[1])
|
338
|
+
vn.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
339
339
|
end
|
340
340
|
end
|
341
341
|
|
data/bin/onevntemplate
CHANGED
@@ -87,6 +87,14 @@ CommandParser::CmdParser.new(ARGV) do
|
|
87
87
|
:description => 'lock all actions'
|
88
88
|
}
|
89
89
|
|
90
|
+
PREFIX = {
|
91
|
+
:name => 'prefix',
|
92
|
+
:large => '--prefix prefix',
|
93
|
+
:description => 'Prefix to autogenerate name, e.g: 001, 01',
|
94
|
+
:format => String
|
95
|
+
|
96
|
+
}
|
97
|
+
|
90
98
|
########################################################################
|
91
99
|
# Global Options
|
92
100
|
########################################################################
|
@@ -102,7 +110,8 @@ CommandParser::CmdParser.new(ARGV) do
|
|
102
110
|
OneVNTemplateHelper::MULTIPLE,
|
103
111
|
OneVNTemplateHelper::EXTENDED,
|
104
112
|
OpenNebulaHelper::AS_USER,
|
105
|
-
OpenNebulaHelper::AS_GROUP
|
113
|
+
OpenNebulaHelper::AS_GROUP,
|
114
|
+
PREFIX
|
106
115
|
]
|
107
116
|
|
108
117
|
########################################################################
|
@@ -204,10 +213,32 @@ CommandParser::CmdParser.new(ARGV) do
|
|
204
213
|
number = options[:multiple] || 1
|
205
214
|
|
206
215
|
number.times do |i|
|
207
|
-
exit_code = helper.perform_action(
|
208
|
-
|
209
|
-
|
210
|
-
|
216
|
+
exit_code = helper.perform_action(
|
217
|
+
args[0],
|
218
|
+
options,
|
219
|
+
'instantiated'
|
220
|
+
) do |t|
|
221
|
+
name = options[:name]
|
222
|
+
prefix = options[:prefix]
|
223
|
+
c_i = nil
|
224
|
+
p = nil
|
225
|
+
|
226
|
+
if prefix && name
|
227
|
+
# Get leading zeros
|
228
|
+
p = prefix.scan(/^0+/)[0]
|
229
|
+
|
230
|
+
# Get current index
|
231
|
+
c_i = prefix.gsub(p, '') if p
|
232
|
+
|
233
|
+
# Convert it to Integer to check if we can use it
|
234
|
+
begin
|
235
|
+
c_i = Integer(c_i)
|
236
|
+
name = name.gsub('%i', "#{p}#{c_i + index}")
|
237
|
+
rescue StandardError
|
238
|
+
end
|
239
|
+
elsif name
|
240
|
+
name = name.gsub('%i', i.to_s)
|
241
|
+
end
|
211
242
|
|
212
243
|
extra_template = ''
|
213
244
|
rc = t.info
|
@@ -234,6 +265,10 @@ CommandParser::CmdParser.new(ARGV) do
|
|
234
265
|
end
|
235
266
|
end
|
236
267
|
|
268
|
+
if c_i
|
269
|
+
extra_template.gsub!('%i', "#{p}#{c_i + index}")
|
270
|
+
end
|
271
|
+
|
237
272
|
res = t.instantiate(name, extra_template)
|
238
273
|
|
239
274
|
if !OpenNebula.is_error?(res)
|
@@ -279,7 +314,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
279
314
|
recursive = (options[:recursive] == true)
|
280
315
|
|
281
316
|
helper.perform_actions(args[0], options, 'Permissions changed') do |t|
|
282
|
-
t.chmod_octet(args[1], recursive)
|
317
|
+
t.chmod_octet(OpenNebulaHelper.to_octet(args[1]), recursive)
|
283
318
|
end
|
284
319
|
end
|
285
320
|
|
data/bin/onevrouter
CHANGED
@@ -251,7 +251,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
251
251
|
|
252
252
|
command :chmod, chmod_desc, [:range, :vrouterid_list], :octet do
|
253
253
|
helper.perform_actions(args[0], options, 'Permissions changed') do |obj|
|
254
|
-
obj.chmod_octet(args[1])
|
254
|
+
obj.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
@@ -520,59 +520,4 @@ class OneVcenterHelper < OpenNebulaHelper::OneHelper
|
|
520
520
|
opts
|
521
521
|
end
|
522
522
|
|
523
|
-
def clear_tags(vmid)
|
524
|
-
client = Client.new
|
525
|
-
|
526
|
-
vm_pool = VirtualMachinePool.new(client, -1)
|
527
|
-
host_pool = HostPool.new(client)
|
528
|
-
deploy_id = -1
|
529
|
-
host_id = -1
|
530
|
-
hostname = ''
|
531
|
-
|
532
|
-
rc = vm_pool.info
|
533
|
-
raise rc.message if OpenNebula.is_error?(rc)
|
534
|
-
|
535
|
-
rc = host_pool.info
|
536
|
-
raise rc.message if OpenNebula.is_error?(rc)
|
537
|
-
|
538
|
-
vm_pool.each do |vm|
|
539
|
-
next if vm.id.to_s != vmid
|
540
|
-
|
541
|
-
deploy_id = vm.deploy_id
|
542
|
-
vm_history = vm.to_hash['VM']['HISTORY_RECORDS']['HISTORY']
|
543
|
-
hostname = vm_history['HOSTNAME']
|
544
|
-
break
|
545
|
-
end
|
546
|
-
|
547
|
-
host_pool.each do |host|
|
548
|
-
if host.name == hostname
|
549
|
-
host_id = host.id
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
vi_client = VCenterDriver::VIClient.new_from_host(host_id)
|
554
|
-
vm = VCenterDriver::VirtualMachine
|
555
|
-
.new(vi_client, deploy_id, vmid)
|
556
|
-
|
557
|
-
keys_to_remove = []
|
558
|
-
vm['config.extraConfig'].each do |extraconfig|
|
559
|
-
next unless extraconfig.key.include?('opennebula.disk') ||
|
560
|
-
extraconfig.key.include?('opennebula.vm') ||
|
561
|
-
extraconfig.key.downcase.include?('remotedisplay')
|
562
|
-
|
563
|
-
keys_to_remove << extraconfig.key
|
564
|
-
end
|
565
|
-
|
566
|
-
[vm, keys_to_remove]
|
567
|
-
end
|
568
|
-
|
569
|
-
def remove_keys(vm, keys_to_remove)
|
570
|
-
spec_hash = keys_to_remove.map {|key| { :key => key, :value => '' } }
|
571
|
-
|
572
|
-
spec = RbVmomi::VIM.VirtualMachineConfigSpec(
|
573
|
-
:extraConfig => spec_hash
|
574
|
-
)
|
575
|
-
vm.item.ReconfigVM_Task(:spec => spec).wait_for_completion
|
576
|
-
end
|
577
|
-
|
578
523
|
end
|
@@ -297,7 +297,7 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
|
|
297
297
|
vm.info
|
298
298
|
ids = vm.retrieve_elements("/VM/SNAPSHOTS/SNAPSHOT[NAME='#{id}']/ID")
|
299
299
|
|
300
|
-
return [-1, "#{id} not found or duplicated"] \
|
300
|
+
return [-1, "Snapshot #{id} not found or duplicated"] \
|
301
301
|
if ids.nil? || ids.size > 1
|
302
302
|
|
303
303
|
[0, ids[0].to_i]
|
data/lib/one_helper.rb
CHANGED
@@ -747,12 +747,9 @@ EOT
|
|
747
747
|
ppid = start_pager
|
748
748
|
end
|
749
749
|
|
750
|
-
puts "<#{pname}>"
|
751
|
-
|
752
750
|
puts page
|
753
751
|
|
754
752
|
if elements < size
|
755
|
-
puts "</#{pname}>"
|
756
753
|
return 0
|
757
754
|
end
|
758
755
|
|
@@ -2305,4 +2302,55 @@ EOT
|
|
2305
2302
|
end
|
2306
2303
|
end
|
2307
2304
|
|
2305
|
+
# Convert u=rwx,g=rx,o=r to octet
|
2306
|
+
#
|
2307
|
+
# @param perm [String] Permissions in human readbale format
|
2308
|
+
#
|
2309
|
+
# @return [String] Permissions in octet format
|
2310
|
+
def OpenNebulaHelper.to_octet(perm)
|
2311
|
+
begin
|
2312
|
+
Integer(perm)
|
2313
|
+
perm
|
2314
|
+
rescue StandardError
|
2315
|
+
perm = perm.split(',')
|
2316
|
+
ret = 0
|
2317
|
+
|
2318
|
+
perm.each do |p|
|
2319
|
+
p = p.split('=')
|
2320
|
+
|
2321
|
+
next unless p.size == 2
|
2322
|
+
|
2323
|
+
r = p[1].count('r')
|
2324
|
+
w = p[1].count('w')
|
2325
|
+
x = p[1].count('x')
|
2326
|
+
|
2327
|
+
rwx = (2 ** 0) * x + (2 ** 1) * w + (2 ** 2) * r
|
2328
|
+
|
2329
|
+
case p[0]
|
2330
|
+
when 'u'
|
2331
|
+
ret += rwx * 100
|
2332
|
+
when 'g'
|
2333
|
+
ret += rwx * 10
|
2334
|
+
else
|
2335
|
+
ret += rwx * 1
|
2336
|
+
end
|
2337
|
+
end
|
2338
|
+
|
2339
|
+
if ret == 0
|
2340
|
+
STDERR.puts 'Error in permissions format'
|
2341
|
+
exit(-1)
|
2342
|
+
else
|
2343
|
+
ret = ret.to_s
|
2344
|
+
|
2345
|
+
if ret.size == 1
|
2346
|
+
"00#{ret}"
|
2347
|
+
elsif ret.size == 2
|
2348
|
+
"0#{ret}"
|
2349
|
+
else
|
2350
|
+
ret
|
2351
|
+
end
|
2352
|
+
end
|
2353
|
+
end
|
2354
|
+
end
|
2355
|
+
|
2308
2356
|
end
|
data/share/schemas/xsd/host.xsd
CHANGED
@@ -65,9 +65,11 @@
|
|
65
65
|
<xs:element name="DOMAIN" type="xs:string"/>
|
66
66
|
<xs:element name="FUNCTION" type="xs:string"/>
|
67
67
|
<xs:element name="NUMA_NODE" type="xs:string"/>
|
68
|
+
<xs:element name="PROFILES" type="xs:string" minOccurs="0"/>
|
68
69
|
<xs:element name="SHORT_ADDRESS" type="xs:string"/>
|
69
70
|
<xs:element name="SLOT" type="xs:string"/>
|
70
71
|
<xs:element name="TYPE" type="xs:string"/>
|
72
|
+
<xs:element name="UUID" type="xs:string" minOccurs="0"/>
|
71
73
|
<xs:element name="VENDOR" type="xs:string"/>
|
72
74
|
<xs:element name="VENDOR_NAME" type="xs:string"/>
|
73
75
|
<xs:element name="VMID" type="xs:integer"/>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opennebula-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.4.
|
4
|
+
version: 6.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OpenNebula
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opennebula
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.4.
|
19
|
+
version: 6.4.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 6.4.
|
26
|
+
version: 6.4.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|