opennebula-cli 6.6.1 → 6.6.3
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 +4 -4
- data/bin/oneacl +1 -1
- data/bin/onecluster +1 -1
- data/bin/onedatastore +1 -1
- data/bin/oneflow-template +10 -5
- data/bin/onegroup +1 -1
- data/bin/onehook +1 -1
- data/bin/onehost +1 -1
- data/bin/oneimage +1 -1
- data/bin/onemarket +1 -1
- data/bin/onemarketapp +1 -1
- data/bin/onesecgroup +1 -1
- data/bin/onetemplate +1 -1
- data/bin/oneuser +1 -1
- data/bin/onevdc +1 -1
- data/bin/onevm +24 -8
- data/bin/onevmgroup +1 -1
- data/bin/onevnet +1 -1
- data/bin/onevntemplate +1 -1
- data/bin/onevrouter +1 -1
- data/bin/onezone +1 -1
- data/lib/one_helper/oneflowtemplate_helper.rb +29 -0
- data/lib/one_helper/onetemplate_helper.rb +1 -0
- data/lib/one_helper/onevm_helper.rb +50 -57
- data/lib/one_helper.rb +321 -325
- data/share/schemas/xsd/vm_pool.xsd +1 -0
- metadata +4 -4
data/lib/one_helper.rb
CHANGED
@@ -21,27 +21,28 @@ require 'io/console'
|
|
21
21
|
begin
|
22
22
|
require 'opennebula'
|
23
23
|
rescue Exception => e
|
24
|
-
puts
|
24
|
+
puts 'Error: '+e.message.to_s
|
25
25
|
exit(-1)
|
26
26
|
end
|
27
27
|
|
28
28
|
include OpenNebula
|
29
29
|
|
30
30
|
module OpenNebulaHelper
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
|
32
|
+
ONE_VERSION=<<~EOT
|
33
|
+
OpenNebula #{OpenNebula::VERSION}
|
34
|
+
Copyright 2002-2023, OpenNebula Project, OpenNebula Systems
|
35
|
+
EOT
|
35
36
|
|
36
37
|
if ONE_LOCATION
|
37
|
-
TABLE_CONF_PATH = ONE_LOCATION +
|
38
|
-
VAR_LOCATION = ONE_LOCATION +
|
39
|
-
CLI_ADDONS_LOCATION = ONE_LOCATION +
|
38
|
+
TABLE_CONF_PATH = ONE_LOCATION + '/etc/cli'
|
39
|
+
VAR_LOCATION = ONE_LOCATION + '/var' unless defined?(VAR_LOCATION)
|
40
|
+
CLI_ADDONS_LOCATION = ONE_LOCATION + '/lib/ruby/cli/addons'
|
40
41
|
XSD_PATH = ONE_LOCATION + '/share/schemas/xsd'
|
41
42
|
else
|
42
|
-
TABLE_CONF_PATH =
|
43
|
-
VAR_LOCATION =
|
44
|
-
CLI_ADDONS_LOCATION =
|
43
|
+
TABLE_CONF_PATH = '/etc/one/cli'
|
44
|
+
VAR_LOCATION = '/var/lib/one' unless defined?(VAR_LOCATION)
|
45
|
+
CLI_ADDONS_LOCATION = '/usr/lib/one/ruby/cli/addons'
|
45
46
|
XSD_PATH = '/usr/share/one/schemas/xsd'
|
46
47
|
end
|
47
48
|
|
@@ -51,10 +52,10 @@ EOT
|
|
51
52
|
# Options
|
52
53
|
########################################################################
|
53
54
|
XML={
|
54
|
-
:name =>
|
55
|
-
:short =>
|
56
|
-
:large =>
|
57
|
-
:description =>
|
55
|
+
:name => 'xml',
|
56
|
+
:short => '-x',
|
57
|
+
:large => '--xml',
|
58
|
+
:description => 'Show the resource in xml format'
|
58
59
|
}
|
59
60
|
|
60
61
|
JSON = {
|
@@ -75,30 +76,30 @@ EOT
|
|
75
76
|
}
|
76
77
|
|
77
78
|
NUMERIC={
|
78
|
-
:name =>
|
79
|
-
:short =>
|
80
|
-
:large =>
|
81
|
-
:description =>
|
79
|
+
:name => 'numeric',
|
80
|
+
:short => '-n',
|
81
|
+
:large => '--numeric',
|
82
|
+
:description => 'Do not translate user and group IDs'
|
82
83
|
}
|
83
84
|
|
84
85
|
KILOBYTES={
|
85
|
-
:name =>
|
86
|
-
:short =>
|
87
|
-
:large =>
|
88
|
-
:description =>
|
86
|
+
:name => 'kilobytes',
|
87
|
+
:short => '-k',
|
88
|
+
:large => '--kilobytes',
|
89
|
+
:description => 'Show units in kilobytes'
|
89
90
|
}
|
90
91
|
|
91
92
|
DESCRIBE={
|
92
|
-
:name =>
|
93
|
-
:large =>
|
94
|
-
:description =>
|
93
|
+
:name => 'describe',
|
94
|
+
:large => '--describe',
|
95
|
+
:description => 'Describe list columns'
|
95
96
|
}
|
96
97
|
|
97
98
|
APPEND = {
|
98
|
-
:name =>
|
99
|
-
:short =>
|
100
|
-
:large =>
|
101
|
-
:description =>
|
99
|
+
:name => 'append',
|
100
|
+
:short => '-a',
|
101
|
+
:large => '--append',
|
102
|
+
:description => 'Append new attributes to the current template'
|
102
103
|
}
|
103
104
|
|
104
105
|
# Command line VM template options
|
@@ -122,7 +123,7 @@ EOT
|
|
122
123
|
:large => '--user name',
|
123
124
|
:description => 'User name used to connect to OpenNebula',
|
124
125
|
:format => String,
|
125
|
-
:proc => lambda do |o,
|
126
|
+
:proc => lambda do |o, _options|
|
126
127
|
OneHelper.set_user(o)
|
127
128
|
[0, o]
|
128
129
|
end
|
@@ -132,7 +133,7 @@ EOT
|
|
132
133
|
:large => '--password password',
|
133
134
|
:description => 'Password to authenticate with OpenNebula',
|
134
135
|
:format => String,
|
135
|
-
:proc => lambda do |o,
|
136
|
+
:proc => lambda do |o, _options|
|
136
137
|
OneHelper.set_password(o)
|
137
138
|
[0, o]
|
138
139
|
end
|
@@ -142,7 +143,7 @@ EOT
|
|
142
143
|
:large => '--endpoint endpoint',
|
143
144
|
:description => 'URL of OpenNebula xmlrpc frontend',
|
144
145
|
:format => String,
|
145
|
-
:proc => lambda do |o,
|
146
|
+
:proc => lambda do |o, _options|
|
146
147
|
OneHelper.set_endpoint(o)
|
147
148
|
[0, o]
|
148
149
|
end
|
@@ -153,7 +154,7 @@ EOT
|
|
153
154
|
{
|
154
155
|
:name => 'name',
|
155
156
|
:large => '--name name',
|
156
|
-
:short =>
|
157
|
+
:short => '-n',
|
157
158
|
:description =>
|
158
159
|
'Name for the new group',
|
159
160
|
:format => String
|
@@ -161,7 +162,7 @@ EOT
|
|
161
162
|
{
|
162
163
|
:name => 'admin_user',
|
163
164
|
:large => '--admin_user name',
|
164
|
-
:short =>
|
165
|
+
:short => '-u',
|
165
166
|
:description =>
|
166
167
|
'Creates an admin user for the group with name',
|
167
168
|
:format => String
|
@@ -169,7 +170,7 @@ EOT
|
|
169
170
|
{
|
170
171
|
:name => 'admin_password',
|
171
172
|
:large => '--admin_password pass',
|
172
|
-
:short =>
|
173
|
+
:short => '-p',
|
173
174
|
:description =>
|
174
175
|
'Password for the admin user of the group',
|
175
176
|
:format => String
|
@@ -177,7 +178,7 @@ EOT
|
|
177
178
|
{
|
178
179
|
:name => 'admin_driver',
|
179
180
|
:large => '--admin_driver driver',
|
180
|
-
:short =>
|
181
|
+
:short => '-d',
|
181
182
|
:description =>
|
182
183
|
'Auth driver for the admin user of the group',
|
183
184
|
:format => String
|
@@ -185,43 +186,43 @@ EOT
|
|
185
186
|
{
|
186
187
|
:name => 'resources',
|
187
188
|
:large => '--resources res_str',
|
188
|
-
:short =>
|
189
|
+
:short => '-r',
|
189
190
|
:description =>
|
190
|
-
|
191
|
-
|
191
|
+
'Which resources can be created by group users '<<
|
192
|
+
'(VM+NET+IMAGE+TEMPLATE by default)',
|
192
193
|
:format => String
|
193
194
|
}
|
194
195
|
]
|
195
196
|
|
196
197
|
AS_USER = {
|
197
|
-
|
198
|
+
:name => 'as_uid',
|
198
199
|
:large => '--as_uid uid',
|
199
200
|
:format => Integer,
|
200
201
|
:description => 'The User ID to instantiate the VM'
|
201
202
|
}
|
202
203
|
|
203
204
|
AS_GROUP = {
|
204
|
-
|
205
|
+
:name => 'as_gid',
|
205
206
|
:large => '--as_gid gid',
|
206
207
|
:format => Integer,
|
207
208
|
:description => 'The Group ID to instantiate the VM'
|
208
209
|
}
|
209
210
|
|
210
|
-
#NOTE: Other options defined using this array, add new options at the end
|
211
|
+
# NOTE: Other options defined using this array, add new options at the end
|
211
212
|
TEMPLATE_OPTIONS=[
|
212
213
|
{
|
213
214
|
:name => 'cpu',
|
214
215
|
:large => '--cpu cpu',
|
215
216
|
:description =>
|
216
217
|
"CPU percentage reserved for the VM (1=100% one\n"<<
|
217
|
-
|
218
|
+
' '*31<<'CPU)',
|
218
219
|
:format => Float
|
219
220
|
},
|
220
221
|
{
|
221
222
|
:name => 'vcpu',
|
222
223
|
:large => '--vcpu vcpu',
|
223
224
|
:description =>
|
224
|
-
|
225
|
+
'Number of virtualized CPUs',
|
225
226
|
:format => Integer
|
226
227
|
},
|
227
228
|
{
|
@@ -236,20 +237,20 @@ EOT
|
|
236
237
|
:large => '--memory memory',
|
237
238
|
:description => 'Memory amount given to the VM. By default the '<<
|
238
239
|
"unit is megabytes. To use gigabytes add a 'g', floats "<<
|
239
|
-
|
240
|
+
'can be used: 8g=8192, 0.5g=512',
|
240
241
|
:format => String,
|
241
|
-
:proc => lambda do |o,
|
242
|
+
:proc => lambda do |o, _options|
|
242
243
|
m=o.strip.match(/^(\d+(?:\.\d+)?)(m|mb|g|gb)?$/i)
|
243
244
|
|
244
245
|
if !m
|
245
246
|
[-1, 'Memory value malformed']
|
246
247
|
else
|
247
248
|
multiplier=case m[2]
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
249
|
+
when /(g|gb)/i
|
250
|
+
1024
|
251
|
+
else
|
252
|
+
1
|
253
|
+
end
|
253
254
|
|
254
255
|
value=m[1].to_f*multiplier
|
255
256
|
|
@@ -260,29 +261,29 @@ EOT
|
|
260
261
|
{
|
261
262
|
:name => 'disk',
|
262
263
|
:large => '--disk image0,image1',
|
263
|
-
:description =>
|
264
|
-
|
264
|
+
:description => 'Disks to attach. To use an image owned by'<<
|
265
|
+
' other user use user[disk]. Add any additional'<<
|
265
266
|
" attributes separated by ':' and in the shape of"<<
|
266
|
-
|
267
|
-
|
268
|
-
|
267
|
+
' KEY=VALUE. For example, if the disk must be'<<
|
268
|
+
' resized, use image0:size=1000 . Or'<<
|
269
|
+
' image0:size=1000:target=vda,image1:target=vdb',
|
269
270
|
:format => Array
|
270
271
|
},
|
271
272
|
{
|
272
273
|
:name => 'nic',
|
273
274
|
:large => '--nic network0,network1',
|
274
|
-
:description =>
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
275
|
+
:description => 'Networks to attach. To use a network owned by'<<
|
276
|
+
' other user use user[network]. Additional'<<
|
277
|
+
' attributes are supported like with the --disk'<<
|
278
|
+
' option. Also you can use auto if you want that' <<
|
279
|
+
' OpenNebula select automatically the network',
|
279
280
|
:format => Array
|
280
281
|
},
|
281
282
|
{
|
282
283
|
:name => 'raw',
|
283
284
|
:large => '--raw string',
|
284
285
|
:description => "Raw string to add to the template. Not to be\n"<<
|
285
|
-
|
286
|
+
' '*31<<'confused with the RAW attribute',
|
286
287
|
:format => String
|
287
288
|
},
|
288
289
|
{
|
@@ -338,9 +339,9 @@ EOT
|
|
338
339
|
:large => '--ssh [file]',
|
339
340
|
:description => "Add an ssh public key to the context. If the \n"<<
|
340
341
|
(' '*31) << "file is omited then the user variable \n"<<
|
341
|
-
(' '*31) <<
|
342
|
+
(' '*31) << 'SSH_PUBLIC_KEY will be used.',
|
342
343
|
:format => String,
|
343
|
-
:proc => lambda do |o,
|
344
|
+
:proc => lambda do |o, _options|
|
344
345
|
if !o
|
345
346
|
[0, true]
|
346
347
|
else
|
@@ -393,8 +394,8 @@ EOT
|
|
393
394
|
:name => 'vcenter_vm_folder',
|
394
395
|
:large => '--vcenter_vm_folder path',
|
395
396
|
:format => String,
|
396
|
-
:description =>
|
397
|
-
|
397
|
+
:description => 'In a vCenter environment sets the the VMs and Template folder where the VM will be placed in.' \
|
398
|
+
' The path uses slashes to separate folders. For example: --vcenter_vm_folder "/Management/VMs"'
|
398
399
|
},
|
399
400
|
{
|
400
401
|
:name => 'user_inputs',
|
@@ -442,19 +443,20 @@ EOT
|
|
442
443
|
TEMPLATE_OPTIONS_VM = [TEMPLATE_NAME_VM] + TEMPLATE_OPTIONS + [DRY]
|
443
444
|
|
444
445
|
CAPACITY_OPTIONS_VM = [TEMPLATE_OPTIONS[0], TEMPLATE_OPTIONS[1],
|
445
|
-
|
446
|
+
TEMPLATE_OPTIONS[3]]
|
446
447
|
|
447
448
|
UPDATECONF_OPTIONS_VM = TEMPLATE_OPTIONS[6..15] + [TEMPLATE_OPTIONS[2],
|
448
|
-
|
449
|
+
TEMPLATE_OPTIONS[17], TEMPLATE_OPTIONS[18]]
|
449
450
|
|
450
451
|
FORMAT = [XML, JSON, YAML]
|
451
452
|
|
452
453
|
OPTIONS = FORMAT, EXTENDED, NUMERIC, KILOBYTES
|
453
454
|
|
454
455
|
class OneHelper
|
456
|
+
|
455
457
|
attr_accessor :client
|
456
458
|
|
457
|
-
def self.get_client(options={}, force=false)
|
459
|
+
def self.get_client(options = {}, force = false)
|
458
460
|
if !force && defined?(@@client)
|
459
461
|
@@client
|
460
462
|
else
|
@@ -470,7 +472,7 @@ EOT
|
|
470
472
|
end
|
471
473
|
|
472
474
|
if user
|
473
|
-
password=password||options[:password]||
|
475
|
+
password=password||options[:password]||get_password
|
474
476
|
secret="#{user}:#{password}"
|
475
477
|
end
|
476
478
|
|
@@ -497,7 +499,7 @@ EOT
|
|
497
499
|
if defined?(@@client)
|
498
500
|
@@client
|
499
501
|
else
|
500
|
-
|
502
|
+
get_client
|
501
503
|
end
|
502
504
|
end
|
503
505
|
|
@@ -513,10 +515,10 @@ EOT
|
|
513
515
|
@@endpoint=endpoint
|
514
516
|
end
|
515
517
|
|
516
|
-
if RUBY_VERSION>=
|
518
|
+
if RUBY_VERSION>='1.9.3'
|
517
519
|
require 'io/console'
|
518
520
|
def self.get_password
|
519
|
-
print
|
521
|
+
print 'Password: '
|
520
522
|
pass=nil
|
521
523
|
STDIN.noecho {|io| pass=io.gets }
|
522
524
|
puts
|
@@ -528,25 +530,29 @@ EOT
|
|
528
530
|
else
|
529
531
|
# This function is copied from ruby net/imap.rb
|
530
532
|
def self.get_password
|
531
|
-
print
|
532
|
-
system(
|
533
|
+
print 'Password: '
|
534
|
+
system('stty', '-echo')
|
533
535
|
begin
|
534
536
|
@@password = STDIN.gets.chop
|
535
|
-
|
537
|
+
@@password
|
536
538
|
ensure
|
537
|
-
system(
|
539
|
+
system('stty', 'echo')
|
538
540
|
print "\n"
|
539
541
|
end
|
540
542
|
end
|
541
543
|
end
|
542
544
|
|
543
|
-
def
|
545
|
+
def self.list_layout_help
|
546
|
+
"The default columns and their layout can be configured in #{conf_file}"
|
547
|
+
end
|
548
|
+
|
549
|
+
def initialize(_secret = nil, _endpoint = nil)
|
544
550
|
@client=nil
|
545
551
|
|
546
552
|
@translation_hash = nil
|
547
553
|
end
|
548
554
|
|
549
|
-
def set_client(options, client=nil)
|
555
|
+
def set_client(options, client = nil)
|
550
556
|
if client.nil?
|
551
557
|
@client=OpenNebulaHelper::OneHelper.get_client(options, true)
|
552
558
|
else
|
@@ -554,15 +560,15 @@ EOT
|
|
554
560
|
end
|
555
561
|
end
|
556
562
|
|
557
|
-
def create_resource(
|
563
|
+
def create_resource(_options, &block)
|
558
564
|
resource = factory
|
559
565
|
|
560
566
|
rc = block.call(resource)
|
561
567
|
if OpenNebula.is_error?(rc)
|
562
|
-
|
568
|
+
[-1, rc.message]
|
563
569
|
else
|
564
|
-
puts "ID: #{resource.id
|
565
|
-
|
570
|
+
puts "ID: #{resource.id}"
|
571
|
+
0
|
566
572
|
end
|
567
573
|
end
|
568
574
|
|
@@ -596,7 +602,7 @@ EOT
|
|
596
602
|
p_w.close
|
597
603
|
p_r.close
|
598
604
|
|
599
|
-
|
605
|
+
lpid
|
600
606
|
end
|
601
607
|
|
602
608
|
def stop_pager(lpid)
|
@@ -605,7 +611,7 @@ EOT
|
|
605
611
|
begin
|
606
612
|
Process.wait(lpid)
|
607
613
|
rescue Interrupt
|
608
|
-
Process.kill(
|
614
|
+
Process.kill('TERM', lpid)
|
609
615
|
Process.wait(lpid)
|
610
616
|
rescue Errno::ECHILD
|
611
617
|
end
|
@@ -613,7 +619,7 @@ EOT
|
|
613
619
|
|
614
620
|
def print_page(pool, options)
|
615
621
|
elements = 0
|
616
|
-
page =
|
622
|
+
page = ''
|
617
623
|
|
618
624
|
if options[:xml]
|
619
625
|
elements += 1
|
@@ -640,20 +646,20 @@ EOT
|
|
640
646
|
end
|
641
647
|
end
|
642
648
|
|
643
|
-
|
649
|
+
[elements, page]
|
644
650
|
end
|
645
651
|
|
646
652
|
#-----------------------------------------------------------------------
|
647
653
|
# List the pool in table form, it uses pagination for interactive
|
648
654
|
# output
|
649
655
|
#-----------------------------------------------------------------------
|
650
|
-
def list_pool_table(table, pool, options,
|
651
|
-
if $stdout.isatty and (!options.key
|
656
|
+
def list_pool_table(table, pool, options, _filter_flag)
|
657
|
+
if $stdout.isatty and (!options.key? :no_pager)
|
652
658
|
size = $stdout.winsize[0] - 1
|
653
659
|
|
654
660
|
# ----------- First page, check if pager is needed -------------
|
655
661
|
rc = pool.get_page(size, 0, false, options[:state])
|
656
|
-
ps =
|
662
|
+
ps = ''
|
657
663
|
|
658
664
|
return -1, rc.message if OpenNebula.is_error?(rc)
|
659
665
|
|
@@ -719,21 +725,21 @@ EOT
|
|
719
725
|
table.show(hash, options)
|
720
726
|
end
|
721
727
|
|
722
|
-
|
728
|
+
0
|
723
729
|
end
|
724
730
|
|
725
731
|
#-----------------------------------------------------------------------
|
726
732
|
# List pool in XML format, pagination is used in interactive output
|
727
733
|
#-----------------------------------------------------------------------
|
728
|
-
def list_pool_xml(pool, options,
|
734
|
+
def list_pool_xml(pool, options, _filter_flag)
|
729
735
|
extended = options.include?(:extended) && options[:extended]
|
730
736
|
|
731
|
-
if $stdout.isatty and (!options.key
|
737
|
+
if $stdout.isatty and (!options.key? :no_pager)
|
732
738
|
size = $stdout.winsize[0] - 1
|
733
739
|
|
734
740
|
# ----------- First page, check if pager is needed -------------
|
735
741
|
rc = pool.get_page(size, 0, extended, options[:state])
|
736
|
-
ps =
|
742
|
+
ps = ''
|
737
743
|
|
738
744
|
return -1, rc.message if OpenNebula.is_error?(rc)
|
739
745
|
|
@@ -789,7 +795,7 @@ EOT
|
|
789
795
|
|
790
796
|
stop_pager(ppid)
|
791
797
|
else
|
792
|
-
if pool.pool_name ==
|
798
|
+
if pool.pool_name == 'VM_POOL' && extended
|
793
799
|
rc = pool.info_all_extended
|
794
800
|
else
|
795
801
|
rc = pool.info
|
@@ -800,21 +806,21 @@ EOT
|
|
800
806
|
puts pool.to_xml(true)
|
801
807
|
end
|
802
808
|
|
803
|
-
|
809
|
+
0
|
804
810
|
end
|
805
811
|
|
806
812
|
#-----------------------------------------------------------------------
|
807
813
|
# List pool in JSON format, pagination is used in interactive output
|
808
814
|
#-----------------------------------------------------------------------
|
809
|
-
def list_pool_format(pool, options,
|
815
|
+
def list_pool_format(pool, options, _filter_flag)
|
810
816
|
extended = options.include?(:extended) && options[:extended]
|
811
817
|
|
812
|
-
if $stdout.isatty and (!options.key
|
818
|
+
if $stdout.isatty and (!options.key? :no_pager)
|
813
819
|
size = $stdout.winsize[0] - 1
|
814
820
|
|
815
821
|
# ----------- First page, check if pager is needed -------------
|
816
822
|
rc = pool.get_page(size, 0, extended, options[:state])
|
817
|
-
ps =
|
823
|
+
ps = ''
|
818
824
|
|
819
825
|
return -1, rc.message if OpenNebula.is_error?(rc)
|
820
826
|
|
@@ -865,7 +871,7 @@ EOT
|
|
865
871
|
|
866
872
|
stop_pager(ppid)
|
867
873
|
else
|
868
|
-
if pool.pool_name ==
|
874
|
+
if pool.pool_name == 'VM_POOL' && extended
|
869
875
|
rc = pool.info_all_extended
|
870
876
|
else
|
871
877
|
rc = pool.info
|
@@ -876,26 +882,25 @@ EOT
|
|
876
882
|
yield(pool) if block_given?
|
877
883
|
end
|
878
884
|
|
879
|
-
|
885
|
+
0
|
880
886
|
end
|
881
887
|
|
882
888
|
#-----------------------------------------------------------------------
|
883
889
|
# List pool table in top-like form
|
884
890
|
#-----------------------------------------------------------------------
|
885
891
|
def list_pool_top(table, pool, options)
|
886
|
-
table.top(options)
|
892
|
+
table.top(options) do
|
887
893
|
array = pool.get_hash
|
888
894
|
|
889
895
|
return -1, array.message if OpenNebula.is_error?(array)
|
890
896
|
|
891
897
|
array
|
892
|
-
|
898
|
+
end
|
893
899
|
|
894
|
-
|
900
|
+
0
|
895
901
|
end
|
896
902
|
|
897
|
-
|
898
|
-
def list_pool(options, top=false, filter_flag=nil)
|
903
|
+
def list_pool(options, top = false, filter_flag = nil)
|
899
904
|
# Capture Broken pipe
|
900
905
|
Signal.trap('PIPE', 'EXIT')
|
901
906
|
|
@@ -919,19 +924,19 @@ EOT
|
|
919
924
|
return list_pool_xml(pool, options, filter_flag)
|
920
925
|
elsif options[:json]
|
921
926
|
list_pool_format(pool, options, filter_flag) do |pool|
|
922
|
-
hash
|
927
|
+
hash = check_resource_xsd(pool, pname)
|
923
928
|
puts ::JSON.pretty_generate(hash)
|
924
929
|
end
|
925
930
|
elsif options[:yaml]
|
926
931
|
list_pool_format(pool, options, filter_flag) do |pool|
|
927
|
-
hash
|
932
|
+
hash = check_resource_xsd(pool, pname)
|
928
933
|
puts hash.to_yaml(:indent => 4)
|
929
934
|
end
|
930
935
|
else
|
931
936
|
return list_pool_table(table, pool, options, filter_flag)
|
932
937
|
end
|
933
938
|
|
934
|
-
|
939
|
+
0
|
935
940
|
rescue SystemExit, Interrupt
|
936
941
|
# Rescue ctrl + c when paginated
|
937
942
|
0
|
@@ -972,21 +977,21 @@ EOT
|
|
972
977
|
return -1, rc.message if OpenNebula.is_error?(rc)
|
973
978
|
|
974
979
|
if options[:xml]
|
975
|
-
|
980
|
+
[0, resource.to_xml(true)]
|
976
981
|
elsif options[:json]
|
977
982
|
# If body is set, the resource contains a JSON inside
|
978
983
|
if options[:body]
|
979
|
-
|
984
|
+
[0, check_resource_xsd(resource)]
|
980
985
|
else
|
981
|
-
|
986
|
+
[0, ::JSON.pretty_generate(
|
982
987
|
check_resource_xsd(resource)
|
983
|
-
)
|
988
|
+
)]
|
984
989
|
end
|
985
990
|
elsif options[:yaml]
|
986
|
-
|
991
|
+
[0, check_resource_xsd(resource).to_yaml(:indent => 4)]
|
987
992
|
else
|
988
993
|
format_resource(resource, options)
|
989
|
-
|
994
|
+
0
|
990
995
|
end
|
991
996
|
end
|
992
997
|
|
@@ -995,19 +1000,19 @@ EOT
|
|
995
1000
|
|
996
1001
|
rc = block.call(resource)
|
997
1002
|
if OpenNebula.is_error?(rc)
|
998
|
-
|
1003
|
+
[-1, rc.message]
|
999
1004
|
else
|
1000
1005
|
if options[:verbose]
|
1001
1006
|
puts "#{self.class.rname} #{id}: #{verbose}"
|
1002
1007
|
end
|
1003
|
-
|
1008
|
+
0
|
1004
1009
|
end
|
1005
1010
|
end
|
1006
1011
|
|
1007
|
-
def perform_actions(ids,options,verbose
|
1012
|
+
def perform_actions(ids, options, verbose, &block)
|
1008
1013
|
exit_code = 0
|
1009
1014
|
ids.each do |id|
|
1010
|
-
rc = perform_action(id,options,verbose
|
1015
|
+
rc = perform_action(id, options, verbose, &block)
|
1011
1016
|
|
1012
1017
|
unless rc[0]==0
|
1013
1018
|
STDERR.puts rc[1]
|
@@ -1021,7 +1026,7 @@ EOT
|
|
1021
1026
|
########################################################################
|
1022
1027
|
# Id translation
|
1023
1028
|
########################################################################
|
1024
|
-
def user_name(resource, options={})
|
1029
|
+
def user_name(resource, options = {})
|
1025
1030
|
if options[:numeric]
|
1026
1031
|
resource['UID']
|
1027
1032
|
else
|
@@ -1029,7 +1034,7 @@ EOT
|
|
1029
1034
|
end
|
1030
1035
|
end
|
1031
1036
|
|
1032
|
-
def group_name(resource, options={})
|
1037
|
+
def group_name(resource, options = {})
|
1033
1038
|
if options[:numeric]
|
1034
1039
|
resource['GID']
|
1035
1040
|
else
|
@@ -1053,7 +1058,7 @@ EOT
|
|
1053
1058
|
end
|
1054
1059
|
|
1055
1060
|
def self.to_id_desc
|
1056
|
-
"OpenNebula #{
|
1061
|
+
"OpenNebula #{rname} name or id"
|
1057
1062
|
end
|
1058
1063
|
|
1059
1064
|
def list_to_id(names)
|
@@ -1063,7 +1068,7 @@ EOT
|
|
1063
1068
|
pool = rc[1]
|
1064
1069
|
poolname = self.class.rname
|
1065
1070
|
|
1066
|
-
result = names.split(',').collect
|
1071
|
+
result = names.split(',').collect do |name|
|
1067
1072
|
if name.match(/^[0123456789]+$/)
|
1068
1073
|
name.to_i
|
1069
1074
|
else
|
@@ -1075,76 +1080,70 @@ EOT
|
|
1075
1080
|
|
1076
1081
|
rc[1]
|
1077
1082
|
end
|
1078
|
-
|
1083
|
+
end
|
1079
1084
|
|
1080
|
-
|
1085
|
+
[0, result]
|
1081
1086
|
end
|
1082
1087
|
|
1083
1088
|
def self.list_to_id_desc
|
1084
|
-
"Comma-separated list of OpenNebula #{
|
1089
|
+
"Comma-separated list of OpenNebula #{rname} names or ids"
|
1085
1090
|
end
|
1086
1091
|
|
1087
1092
|
def self.name_to_id(name, pool, ename)
|
1088
|
-
if ename==
|
1089
|
-
return 0,
|
1093
|
+
if ename=='CLUSTER' and name.upcase=='ALL'
|
1094
|
+
return 0, 'ALL'
|
1090
1095
|
end
|
1091
1096
|
|
1092
1097
|
objects=pool.select {|object| object.name==name }
|
1093
1098
|
|
1094
|
-
|
1095
|
-
|
1096
|
-
return -1, "There are multiple #{ename}s with name #{name}."
|
1097
|
-
else
|
1098
|
-
result = objects.first.id
|
1099
|
-
end
|
1100
|
-
else
|
1101
|
-
return -1, "#{ename} named #{name} not found."
|
1102
|
-
end
|
1099
|
+
return -1, "#{ename} named #{name} not found." unless objects.length>0
|
1100
|
+
return -1, "There are multiple #{ename}s with name #{name}." if objects.length>1
|
1103
1101
|
|
1104
|
-
|
1102
|
+
result = objects.first.id
|
1103
|
+
|
1104
|
+
[0, result]
|
1105
1105
|
end
|
1106
1106
|
|
1107
1107
|
def filterflag_to_i(str)
|
1108
1108
|
filter_flag = case str
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
rc[1]
|
1122
|
-
end
|
1123
|
-
end
|
1124
|
-
end
|
1109
|
+
when 'a', 'all' then OpenNebula::Pool::INFO_ALL
|
1110
|
+
when 'm', 'mine' then OpenNebula::Pool::INFO_MINE
|
1111
|
+
when 'g', 'group' then OpenNebula::Pool::INFO_GROUP
|
1112
|
+
when 'G', 'primary group' then OpenNebula::Pool::INFO_PRIMARY_GROUP
|
1113
|
+
else
|
1114
|
+
if str.match(/^[0123456789]+$/)
|
1115
|
+
str.to_i
|
1116
|
+
else
|
1117
|
+
rc = OpenNebulaHelper.rname_to_id(str, 'USER')
|
1118
|
+
return rc if rc.first==-1
|
1119
|
+
|
1120
|
+
rc[1]
|
1125
1121
|
|
1126
|
-
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
[0, filter_flag]
|
1127
1126
|
end
|
1128
1127
|
|
1129
1128
|
def self.filterflag_to_i_desc
|
1130
|
-
desc
|
1131
|
-
a, all all the known #{
|
1132
|
-
m, mine the #{
|
1133
|
-
g, group 'mine' plus the #{
|
1134
|
-
|
1135
|
-
G, primary group the #{
|
1136
|
-
uid #{
|
1137
|
-
user #{
|
1138
|
-
EOT
|
1139
|
-
end
|
1140
|
-
|
1141
|
-
def self.table_conf(conf_file=self.conf_file)
|
1142
|
-
path = "#{ENV[
|
1143
|
-
|
1144
|
-
if File.
|
1145
|
-
|
1129
|
+
desc=<<~EOT
|
1130
|
+
a, all all the known #{rname}s
|
1131
|
+
m, mine the #{rname} belonging to the user in ONE_AUTH
|
1132
|
+
g, group 'mine' plus the #{rname} belonging to the groups
|
1133
|
+
the user is member of
|
1134
|
+
G, primary group the #{rname} owned the user's primary group
|
1135
|
+
uid #{rname} of the user identified by this uid
|
1136
|
+
user #{rname} of the user identified by the username
|
1137
|
+
EOT
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
def self.table_conf(conf_file = self.conf_file)
|
1141
|
+
path = "#{ENV['HOME']}/.one/cli/#{conf_file}"
|
1142
|
+
|
1143
|
+
if File.exist?(path)
|
1144
|
+
path
|
1146
1145
|
else
|
1147
|
-
|
1146
|
+
"#{TABLE_CONF_PATH}/#{conf_file}"
|
1148
1147
|
end
|
1149
1148
|
end
|
1150
1149
|
|
@@ -1171,7 +1170,7 @@ EOT
|
|
1171
1170
|
phash = [phash["#{rname}_POOL"]["#{rname}"]]
|
1172
1171
|
end
|
1173
1172
|
else
|
1174
|
-
phash =
|
1173
|
+
phash = []
|
1175
1174
|
end
|
1176
1175
|
|
1177
1176
|
phash
|
@@ -1183,15 +1182,14 @@ EOT
|
|
1183
1182
|
|
1184
1183
|
rc = pool.info
|
1185
1184
|
if OpenNebula.is_error?(rc)
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
end
|
1185
|
+
return -1, rc.message unless rc.message.empty?
|
1186
|
+
|
1187
|
+
return -1, "OpenNebula #{self.class.rname} name not " <<
|
1188
|
+
'found, use the ID instead'
|
1189
|
+
|
1192
1190
|
end
|
1193
1191
|
|
1194
|
-
|
1192
|
+
[0, pool]
|
1195
1193
|
end
|
1196
1194
|
|
1197
1195
|
def get_format_size(pool, options)
|
@@ -1217,7 +1215,7 @@ EOT
|
|
1217
1215
|
# @return [Object] Hash with correct values
|
1218
1216
|
def check_resource_xsd(resource, ename = nil)
|
1219
1217
|
hash = resource.to_hash
|
1220
|
-
ename
|
1218
|
+
ename ||= hash.keys.first
|
1221
1219
|
xsd = read_xsd(ename)
|
1222
1220
|
|
1223
1221
|
return hash unless xsd
|
@@ -1228,14 +1226,13 @@ EOT
|
|
1228
1226
|
xsd = xsd['element']
|
1229
1227
|
end
|
1230
1228
|
|
1231
|
-
xsd = [
|
1229
|
+
xsd = [xsd] unless xsd.is_a? Array
|
1232
1230
|
|
1233
1231
|
check_xsd(hash[ename], xsd)
|
1234
1232
|
|
1235
1233
|
hash
|
1236
1234
|
end
|
1237
1235
|
|
1238
|
-
|
1239
1236
|
# Replaces refs in xsd definition
|
1240
1237
|
# limited func: only traverse hashes (not arrays), but works well for pools
|
1241
1238
|
#
|
@@ -1248,15 +1245,15 @@ EOT
|
|
1248
1245
|
if h.keys.include? 'ref'
|
1249
1246
|
ref_xsd = read_xsd(h['ref'])
|
1250
1247
|
return ref_xsd unless ref_xsd.nil?
|
1251
|
-
|
1248
|
+
|
1249
|
+
h
|
1252
1250
|
else
|
1253
|
-
h.each do |k,v|
|
1251
|
+
h.each do |k, v|
|
1254
1252
|
h[k] = replace_refs(v)
|
1255
1253
|
end
|
1256
1254
|
end
|
1257
1255
|
end
|
1258
1256
|
|
1259
|
-
|
1260
1257
|
# Read XSD file and parse to XML
|
1261
1258
|
#
|
1262
1259
|
# @param ename [String] Element name to read XSD
|
@@ -1275,16 +1272,14 @@ EOT
|
|
1275
1272
|
|
1276
1273
|
unless File.exist?(file)
|
1277
1274
|
STDERR.puts "WARNING: XSD for #{ename} not found, skipping check"
|
1278
|
-
return
|
1275
|
+
return
|
1279
1276
|
end
|
1280
1277
|
|
1281
1278
|
hash = Hash.from_xml(Nokogiri::XML(File.read(file)).to_s)
|
1282
1279
|
|
1283
1280
|
hash = hash['schema']['element']
|
1284
1281
|
|
1285
|
-
|
1286
|
-
|
1287
|
-
hash
|
1282
|
+
replace_refs(hash)
|
1288
1283
|
end
|
1289
1284
|
|
1290
1285
|
# Decides if given xsd definiton should be array in xml
|
@@ -1298,6 +1293,7 @@ EOT
|
|
1298
1293
|
def is_array?(e)
|
1299
1294
|
return false if e.nil?
|
1300
1295
|
return false unless e.is_a? Hash
|
1296
|
+
|
1301
1297
|
e['maxOccurs'] == 'unbounded' || e['maxOccurs'].to_i > 1
|
1302
1298
|
end
|
1303
1299
|
|
@@ -1338,16 +1334,15 @@ EOT
|
|
1338
1334
|
return unless hash or hash.empty?
|
1339
1335
|
|
1340
1336
|
hash.each do |k, v|
|
1341
|
-
|
1342
1337
|
# find the elem definition in xsd array
|
1343
|
-
xsd_elem = xsd.select {
|
1338
|
+
xsd_elem = xsd.select {|e| e['name'] == k }.first unless xsd.nil?
|
1344
1339
|
|
1345
1340
|
if xsd_complex_sequence?(xsd_elem) || xsd_complex_all?(xsd_elem)
|
1346
1341
|
|
1347
1342
|
# go deeper in xsd, xsd is ehter complex sequence or all
|
1348
1343
|
begin
|
1349
1344
|
inner_xsd = xsd_elem['complexType']['sequence']['element']
|
1350
|
-
rescue
|
1345
|
+
rescue StandardError
|
1351
1346
|
inner_xsd = xsd_elem['complexType']['all']['element']
|
1352
1347
|
end
|
1353
1348
|
|
@@ -1365,81 +1360,82 @@ EOT
|
|
1365
1360
|
end
|
1366
1361
|
|
1367
1362
|
# if XSD requires array, do so in resource if missing
|
1368
|
-
if is_array?(xsd_elem) && (!
|
1369
|
-
hash[k] = [
|
1363
|
+
if is_array?(xsd_elem) && (!v.is_a? Array)
|
1364
|
+
hash[k] = [v]
|
1370
1365
|
end
|
1371
1366
|
end
|
1372
1367
|
end
|
1368
|
+
|
1373
1369
|
end
|
1374
1370
|
|
1375
|
-
def
|
1371
|
+
def self.rname_to_id(name, poolname)
|
1376
1372
|
return 0, name.to_i if name.match(/^[0123456789]+$/)
|
1377
1373
|
|
1378
1374
|
client=OneHelper.client
|
1379
1375
|
|
1380
1376
|
pool = case poolname
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1377
|
+
when 'HOST' then OpenNebula::HostPool.new(client)
|
1378
|
+
when 'HOOK' then OpenNebula::HookPool.new(client)
|
1379
|
+
when 'GROUP' then OpenNebula::GroupPool.new(client)
|
1380
|
+
when 'USER' then OpenNebula::UserPool.new(client)
|
1381
|
+
when 'DATASTORE' then OpenNebula::DatastorePool.new(client)
|
1382
|
+
when 'CLUSTER' then OpenNebula::ClusterPool.new(client)
|
1383
|
+
when 'VNET' then OpenNebula::VirtualNetworkPool.new(client)
|
1384
|
+
when 'IMAGE' then OpenNebula::ImagePool.new(client)
|
1385
|
+
when 'VMTEMPLATE' then OpenNebula::TemplatePool.new(client)
|
1386
|
+
when 'VNTEMPLATES' then OpenNebula::VNTemplatePool.new(client)
|
1387
|
+
when 'VM' then OpenNebula::VirtualMachinePool.new(client)
|
1388
|
+
when 'ZONE' then OpenNebula::ZonePool.new(client)
|
1389
|
+
when 'MARKETPLACE' then OpenNebula::MarketPlacePool.new(client)
|
1390
|
+
when 'FLOWTEMPLATES' then OpenNebula::ServiceTemplatePool.new(client)
|
1391
|
+
end
|
1396
1392
|
|
1397
1393
|
rc = pool.info
|
1398
1394
|
if OpenNebula.is_error?(rc)
|
1399
1395
|
return -1, "OpenNebula #{poolname} name not found," <<
|
1400
|
-
|
1396
|
+
' use the ID instead'
|
1401
1397
|
end
|
1402
1398
|
|
1403
1399
|
OneHelper.name_to_id(name, pool, poolname)
|
1404
1400
|
end
|
1405
1401
|
|
1406
|
-
def
|
1402
|
+
def self.size_in_mb(size)
|
1407
1403
|
m = size.match(/^(\d+(?:\.\d+)?)(t|tb|m|mb|g|gb)?$/i)
|
1408
1404
|
|
1409
1405
|
if !m
|
1410
1406
|
# return OpenNebula::Error.new('Size value malformed')
|
1411
|
-
|
1407
|
+
[-1, 'Size value malformed']
|
1412
1408
|
else
|
1413
1409
|
multiplier=case m[2]
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1410
|
+
when /(t|tb)/i
|
1411
|
+
1024*1024
|
1412
|
+
when /(g|gb)/i
|
1413
|
+
1024
|
1414
|
+
else
|
1415
|
+
1
|
1416
|
+
end
|
1421
1417
|
|
1422
1418
|
value=m[1].to_f*multiplier
|
1423
1419
|
|
1424
1420
|
# return value.ceil
|
1425
|
-
|
1421
|
+
[0, value.ceil]
|
1426
1422
|
end
|
1427
1423
|
end
|
1428
1424
|
|
1429
|
-
def
|
1425
|
+
def self.rname_to_id_desc(poolname)
|
1430
1426
|
"OpenNebula #{poolname} name or id"
|
1431
1427
|
end
|
1432
1428
|
|
1433
|
-
def
|
1429
|
+
def self.boolean_to_str(str)
|
1434
1430
|
if str.to_i == 1
|
1435
|
-
|
1431
|
+
'Yes'
|
1436
1432
|
else
|
1437
|
-
|
1433
|
+
'No'
|
1438
1434
|
end
|
1439
1435
|
end
|
1440
1436
|
|
1441
|
-
def
|
1442
|
-
|
1437
|
+
def self.time_to_str(time, print_seconds = true,
|
1438
|
+
print_hours = true, print_years = false)
|
1443
1439
|
|
1444
1440
|
value = time.to_i
|
1445
1441
|
|
@@ -1449,63 +1445,63 @@ EOT
|
|
1449
1445
|
if print_hours
|
1450
1446
|
if print_seconds
|
1451
1447
|
if print_years
|
1452
|
-
value=Time.at(value).strftime(
|
1448
|
+
value=Time.at(value).strftime('%m/%d/%y %H:%M:%S')
|
1453
1449
|
else
|
1454
|
-
value=Time.at(value).strftime(
|
1450
|
+
value=Time.at(value).strftime('%m/%d %H:%M:%S')
|
1455
1451
|
end
|
1456
1452
|
else
|
1457
1453
|
if print_years
|
1458
|
-
value=Time.at(value).strftime(
|
1454
|
+
value=Time.at(value).strftime('%m/%d/%y %H:%M')
|
1459
1455
|
else
|
1460
|
-
value=Time.at(value).strftime(
|
1456
|
+
value=Time.at(value).strftime('%m/%d %H:%M')
|
1461
1457
|
end
|
1462
1458
|
end
|
1463
1459
|
else
|
1464
1460
|
if print_years
|
1465
|
-
value=Time.at(value).strftime(
|
1461
|
+
value=Time.at(value).strftime('%m/%d/%y')
|
1466
1462
|
else
|
1467
|
-
value=Time.at(value).strftime(
|
1463
|
+
value=Time.at(value).strftime('%m/%d')
|
1468
1464
|
end
|
1469
1465
|
end
|
1470
1466
|
end
|
1471
1467
|
|
1472
|
-
|
1468
|
+
value
|
1473
1469
|
end
|
1474
1470
|
|
1475
|
-
def
|
1471
|
+
def self.period_to_str(time, print_seconds = true)
|
1476
1472
|
seconds=time.to_i
|
1477
1473
|
minutes, seconds=seconds.divmod(60)
|
1478
1474
|
hours, minutes=minutes.divmod(60)
|
1479
1475
|
days, hours=hours.divmod(24)
|
1480
1476
|
|
1481
1477
|
if print_seconds
|
1482
|
-
|
1478
|
+
format('%3dd %02dh%02dm%02ds', days, hours, minutes, seconds)
|
1483
1479
|
else
|
1484
|
-
|
1480
|
+
format('%3dd %02dh%02dm', days, hours, minutes)
|
1485
1481
|
end
|
1486
1482
|
end
|
1487
1483
|
|
1488
|
-
def
|
1484
|
+
def self.short_period_to_str(time, print_seconds = true)
|
1489
1485
|
seconds=time.to_i
|
1490
1486
|
minutes, seconds=seconds.divmod(60)
|
1491
1487
|
hours, minutes=minutes.divmod(60)
|
1492
1488
|
|
1493
1489
|
if print_seconds
|
1494
|
-
|
1490
|
+
format('%3dh%02dm%02ds', hours, minutes, seconds)
|
1495
1491
|
else
|
1496
|
-
|
1492
|
+
format('%3dh%02dm', hours, minutes)
|
1497
1493
|
end
|
1498
1494
|
end
|
1499
1495
|
|
1500
|
-
BinarySufix = [
|
1496
|
+
BinarySufix = ['K', 'M', 'G', 'T']
|
1501
1497
|
|
1502
|
-
def
|
1498
|
+
def self.unit_to_str(value, options, unit = 'K')
|
1503
1499
|
if options[:kilobytes]
|
1504
1500
|
value
|
1505
1501
|
else
|
1506
1502
|
i=BinarySufix.index(unit).to_i
|
1507
1503
|
|
1508
|
-
while value > 1024 && i < 3
|
1504
|
+
while value > 1024 && i < 3
|
1509
1505
|
value /= 1024.0
|
1510
1506
|
i+=1
|
1511
1507
|
end
|
@@ -1517,11 +1513,11 @@ EOT
|
|
1517
1513
|
end
|
1518
1514
|
end
|
1519
1515
|
|
1520
|
-
def
|
1516
|
+
def self.bytes_to_unit(value, unit = 'K')
|
1521
1517
|
j = 0
|
1522
1518
|
i = BinarySufix.index(unit).to_i
|
1523
1519
|
|
1524
|
-
while j < i
|
1520
|
+
while j < i
|
1525
1521
|
value /= 1024.0
|
1526
1522
|
j += 1
|
1527
1523
|
end
|
@@ -1533,51 +1529,50 @@ EOT
|
|
1533
1529
|
#
|
1534
1530
|
# @param str [String || Hash] Cluster name, or empty Hash (when <CLUSTER/>)
|
1535
1531
|
# @return [String] the same Cluster name, or '-' if it is empty
|
1536
|
-
def
|
1537
|
-
if str
|
1532
|
+
def self.cluster_str(str)
|
1533
|
+
if !str.nil? && !str.empty?
|
1538
1534
|
str
|
1539
1535
|
else
|
1540
|
-
|
1536
|
+
'-'
|
1541
1537
|
end
|
1542
1538
|
end
|
1543
1539
|
|
1544
|
-
def
|
1540
|
+
def self.clusters_str(clusters)
|
1545
1541
|
if clusters.nil?
|
1546
|
-
|
1542
|
+
'-'
|
1547
1543
|
else
|
1548
1544
|
[clusters].flatten.join(',')
|
1549
1545
|
end
|
1550
|
-
|
1551
1546
|
end
|
1552
1547
|
|
1553
|
-
def
|
1554
|
-
|
1548
|
+
def self.update_template(id, resource, path = nil, xpath = 'TEMPLATE')
|
1549
|
+
update_template_helper(false, id, resource, path, xpath)
|
1555
1550
|
end
|
1556
1551
|
|
1557
|
-
def
|
1558
|
-
|
1552
|
+
def self.append_template(id, resource, path = nil, xpath = 'TEMPLATE')
|
1553
|
+
update_template_helper(true, id, resource, path, xpath)
|
1559
1554
|
end
|
1560
1555
|
|
1561
|
-
def
|
1556
|
+
def self.update_template_helper(append, _id, resource, path, xpath, update = true)
|
1562
1557
|
if path
|
1563
|
-
|
1558
|
+
File.read(path)
|
1564
1559
|
elsif append
|
1565
|
-
|
1560
|
+
editor_input
|
1566
1561
|
else
|
1567
1562
|
if update
|
1568
1563
|
rc = resource.info
|
1569
1564
|
|
1570
1565
|
if OpenNebula.is_error?(rc)
|
1571
1566
|
puts rc.message
|
1572
|
-
exit
|
1567
|
+
exit(-1)
|
1573
1568
|
end
|
1574
1569
|
end
|
1575
1570
|
|
1576
|
-
|
1571
|
+
editor_input(resource.template_like_str(xpath))
|
1577
1572
|
end
|
1578
1573
|
end
|
1579
1574
|
|
1580
|
-
def
|
1575
|
+
def self.update_obj(obj, file, plain = false)
|
1581
1576
|
rc = obj.info(true)
|
1582
1577
|
|
1583
1578
|
return rc if OpenNebula.is_error?(rc)
|
@@ -1614,28 +1609,27 @@ EOT
|
|
1614
1609
|
end
|
1615
1610
|
end
|
1616
1611
|
|
1617
|
-
def
|
1612
|
+
def self.editor_input(contents = nil)
|
1618
1613
|
require 'tempfile'
|
1619
1614
|
|
1620
|
-
tmp
|
1615
|
+
tmp = Tempfile.new('one_cli')
|
1621
1616
|
|
1622
1617
|
if contents
|
1623
1618
|
tmp << contents
|
1624
1619
|
tmp.flush
|
1625
1620
|
end
|
1626
1621
|
|
1627
|
-
editor_path = ENV[
|
1622
|
+
editor_path = ENV['EDITOR'] ? ENV['EDITOR'] : EDITOR_PATH
|
1628
1623
|
system("#{editor_path} #{tmp.path}")
|
1629
1624
|
|
1630
1625
|
unless $?.exitstatus == 0
|
1631
|
-
puts
|
1632
|
-
exit
|
1626
|
+
puts 'Editor not defined'
|
1627
|
+
exit(-1)
|
1633
1628
|
end
|
1634
1629
|
|
1635
1630
|
tmp.close
|
1636
1631
|
|
1637
|
-
|
1638
|
-
return str
|
1632
|
+
File.read(tmp.path)
|
1639
1633
|
end
|
1640
1634
|
|
1641
1635
|
def self.parse_user_object(user_object)
|
@@ -1643,7 +1637,7 @@ EOT
|
|
1643
1637
|
|
1644
1638
|
m=user_object.match(reg)
|
1645
1639
|
|
1646
|
-
return
|
1640
|
+
return unless m
|
1647
1641
|
|
1648
1642
|
user=nil
|
1649
1643
|
if m[2]
|
@@ -1660,7 +1654,7 @@ EOT
|
|
1660
1654
|
template=''
|
1661
1655
|
|
1662
1656
|
objects.each do |obj|
|
1663
|
-
obj, *extra_attributes = obj.split(
|
1657
|
+
obj, *extra_attributes = obj.split(':')
|
1664
1658
|
|
1665
1659
|
# When extra attributes do not contain = character include
|
1666
1660
|
# them in the previous value. Fixes adding MAC addresses. These
|
@@ -1673,26 +1667,27 @@ EOT
|
|
1673
1667
|
#
|
1674
1668
|
attrs = []
|
1675
1669
|
extra_attributes.each do |str|
|
1676
|
-
if str.include?(
|
1670
|
+
if str.include?('=')
|
1677
1671
|
attrs << str
|
1678
1672
|
else
|
1679
1673
|
attrs.last << ":#{str}"
|
1680
|
-
|
1674
|
+
end
|
1681
1675
|
end
|
1682
1676
|
|
1683
1677
|
extra_attributes = attrs
|
1684
1678
|
|
1685
1679
|
res=parse_user_object(obj)
|
1686
|
-
return [-1, "#{section.capitalize} \"#{obj}\" malformed"]
|
1680
|
+
return [-1, "#{section.capitalize} \"#{obj}\" malformed"] unless res
|
1681
|
+
|
1687
1682
|
user, object=*res
|
1688
1683
|
|
1689
1684
|
template<<"#{section.upcase}=[\n"
|
1690
|
-
if object.downcase ==
|
1685
|
+
if object.downcase == 'auto'
|
1691
1686
|
template<<" NETWORK_MODE=\"#{object}\"\n"
|
1692
1687
|
else
|
1693
1688
|
template<<" #{name.upcase}_UNAME=\"#{user}\",\n" if user
|
1694
1689
|
extra_attributes.each do |extra_attribute|
|
1695
|
-
key, value = extra_attribute.split(
|
1690
|
+
key, value = extra_attribute.split('=')
|
1696
1691
|
template<<" #{key.upcase}=\"#{value}\",\n"
|
1697
1692
|
end
|
1698
1693
|
if object.match(/^\d+$/)
|
@@ -1708,13 +1703,14 @@ EOT
|
|
1708
1703
|
end
|
1709
1704
|
|
1710
1705
|
def self.create_context(options)
|
1711
|
-
context_options = [:ssh, :net_context, :context, :init, :files_ds, :startscript,
|
1706
|
+
context_options = [:ssh, :net_context, :context, :init, :files_ds, :startscript,
|
1707
|
+
:report_ready]
|
1712
1708
|
if !(options.keys & context_options).empty?
|
1713
1709
|
lines=[]
|
1714
1710
|
|
1715
1711
|
if options[:ssh]
|
1716
1712
|
if options[:ssh]==true
|
1717
|
-
lines<<
|
1713
|
+
lines<<'SSH_PUBLIC_KEY="$USER[SSH_PUBLIC_KEY]"'
|
1718
1714
|
else
|
1719
1715
|
begin
|
1720
1716
|
key=File.read(options[:ssh]).strip
|
@@ -1727,7 +1723,7 @@ EOT
|
|
1727
1723
|
end
|
1728
1724
|
|
1729
1725
|
if options[:net_context]
|
1730
|
-
lines <<
|
1726
|
+
lines << 'NETWORK = "YES"'
|
1731
1727
|
end
|
1732
1728
|
|
1733
1729
|
lines+=options[:context] if options[:context]
|
@@ -1735,7 +1731,7 @@ EOT
|
|
1735
1731
|
if options[:files_ds]
|
1736
1732
|
text='FILES_DS="'
|
1737
1733
|
text << options[:files_ds].map do |file|
|
1738
|
-
%
|
1734
|
+
%($FILE[IMAGE=\\"#{file}\\"])
|
1739
1735
|
end.join(' ')
|
1740
1736
|
text << '"'
|
1741
1737
|
|
@@ -1743,7 +1739,7 @@ EOT
|
|
1743
1739
|
end
|
1744
1740
|
|
1745
1741
|
if options[:init]
|
1746
|
-
lines << %
|
1742
|
+
lines << %(INIT_SCRIPTS="#{options[:init].join(' ')}")
|
1747
1743
|
end
|
1748
1744
|
|
1749
1745
|
if options[:startscript]
|
@@ -1754,16 +1750,16 @@ EOT
|
|
1754
1750
|
STDERR.puts e.message
|
1755
1751
|
exit(-1)
|
1756
1752
|
end
|
1757
|
-
script = Base64
|
1753
|
+
script = Base64.strict_encode64(script)
|
1758
1754
|
lines<<"START_SCRIPT_BASE64=\"#{script}\""
|
1759
1755
|
end
|
1760
1756
|
|
1761
1757
|
if options[:report_ready]
|
1762
|
-
lines <<
|
1758
|
+
lines << 'REPORT_READY = "YES"'
|
1763
1759
|
end
|
1764
1760
|
|
1765
1761
|
if !lines.empty?
|
1766
|
-
"CONTEXT=[\n" << lines.map{|l|
|
1762
|
+
"CONTEXT=[\n" << lines.map {|l| ' ' << l }.join(",\n") << "\n]\n"
|
1767
1763
|
else
|
1768
1764
|
nil
|
1769
1765
|
end
|
@@ -1772,7 +1768,7 @@ EOT
|
|
1772
1768
|
end
|
1773
1769
|
end
|
1774
1770
|
|
1775
|
-
def self.create_template(options, template_obj=nil)
|
1771
|
+
def self.create_template(options, template_obj = nil)
|
1776
1772
|
template=''
|
1777
1773
|
|
1778
1774
|
template<<"NAME=\"#{options[:name]}\"\n" if options[:name]
|
@@ -1812,7 +1808,7 @@ EOT
|
|
1812
1808
|
end
|
1813
1809
|
|
1814
1810
|
if options[:vnc]
|
1815
|
-
vnc_listen=options[:vnc_listen] ||
|
1811
|
+
vnc_listen=options[:vnc_listen] || '0.0.0.0'
|
1816
1812
|
template<<"GRAPHICS=[ TYPE=\"vnc\", LISTEN=\"#{vnc_listen}\""
|
1817
1813
|
if options[:vnc_password]
|
1818
1814
|
template << ", PASSWD=\"#{options[:vnc_password]}\""
|
@@ -1824,7 +1820,7 @@ EOT
|
|
1824
1820
|
end
|
1825
1821
|
|
1826
1822
|
if options[:spice]
|
1827
|
-
spice_listen=options[:spice_listen] ||
|
1823
|
+
spice_listen=options[:spice_listen] || '0.0.0.0'
|
1828
1824
|
template<<"GRAPHICS=[ TYPE=\"spice\", LISTEN=\"#{spice_listen}\""
|
1829
1825
|
if options[:spice_password]
|
1830
1826
|
template << ", PASSWD=\"#{options[:spice_password]}\""
|
@@ -1840,15 +1836,15 @@ EOT
|
|
1840
1836
|
context=create_context(options)
|
1841
1837
|
template<<context if context
|
1842
1838
|
|
1843
|
-
if options[:userdata] && !template_obj.nil?
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1839
|
+
if options[:userdata] && !template_obj.nil? && template_obj.has_elements?('TEMPLATE/EC2')
|
1840
|
+
template_obj.add_element(
|
1841
|
+
'TEMPLATE/EC2',
|
1842
|
+
'USERDATA' => options[:userdata]
|
1843
|
+
)
|
1848
1844
|
|
1849
|
-
|
1850
|
-
|
1851
|
-
|
1845
|
+
template << template_obj.template_like_str(
|
1846
|
+
'TEMPLATE', false, 'EC2'
|
1847
|
+
)
|
1852
1848
|
end
|
1853
1849
|
|
1854
1850
|
[0, template]
|
@@ -1946,21 +1942,21 @@ EOT
|
|
1946
1942
|
|
1947
1943
|
def self.sunstone_url
|
1948
1944
|
if (one_sunstone = ENV['ONE_SUNSTONE'])
|
1949
|
-
|
1945
|
+
one_sunstone
|
1950
1946
|
elsif (one_xmlrpc = ENV['ONE_XMLRPC'])
|
1951
1947
|
uri = URI(one_xmlrpc)
|
1952
1948
|
"#{uri.scheme}://#{uri.host}:9869"
|
1953
1949
|
else
|
1954
|
-
|
1950
|
+
'http://localhost:9869'
|
1955
1951
|
end
|
1956
1952
|
end
|
1957
1953
|
|
1958
|
-
def self.download_resource_sunstone(kind, id, path,
|
1954
|
+
def self.download_resource_sunstone(kind, id, path, _force)
|
1959
1955
|
client = OneHelper.client
|
1960
|
-
user, password = client.one_auth.split(
|
1956
|
+
user, password = client.one_auth.split(':', 2)
|
1961
1957
|
|
1962
1958
|
# Step 1: Build Session to get Cookie
|
1963
|
-
uri = URI(File.join(sunstone_url,
|
1959
|
+
uri = URI(File.join(sunstone_url, 'login'))
|
1964
1960
|
|
1965
1961
|
req = Net::HTTP::Post.new(uri)
|
1966
1962
|
req.basic_auth user, password
|
@@ -1969,14 +1965,14 @@ EOT
|
|
1969
1965
|
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
1970
1966
|
http.request(req)
|
1971
1967
|
end
|
1972
|
-
rescue
|
1968
|
+
rescue StandardError
|
1973
1969
|
return OpenNebula::Error.new("Error connecting to '#{uri}'.")
|
1974
1970
|
end
|
1975
1971
|
|
1976
1972
|
cookie = res.response['set-cookie'].split('; ')[0]
|
1977
1973
|
|
1978
1974
|
if cookie.nil?
|
1979
|
-
|
1975
|
+
return OpenNebula::Error.new('Unable to get Cookie. Is OpenNebula running?')
|
1980
1976
|
end
|
1981
1977
|
|
1982
1978
|
# Step 2: Open '/' to get the csrftoken
|
@@ -1989,7 +1985,7 @@ EOT
|
|
1989
1985
|
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
1990
1986
|
http.request(req)
|
1991
1987
|
end
|
1992
|
-
rescue
|
1988
|
+
rescue StandardError
|
1993
1989
|
return OpenNebula::Error.new("Error connecting to '#{uri}'.")
|
1994
1990
|
end
|
1995
1991
|
|
@@ -1997,7 +1993,7 @@ EOT
|
|
1997
1993
|
csrftoken = m[1] rescue nil
|
1998
1994
|
|
1999
1995
|
if csrftoken.nil?
|
2000
|
-
|
1996
|
+
return OpenNebula::Error.new('Unable to get csrftoken.')
|
2001
1997
|
end
|
2002
1998
|
|
2003
1999
|
# Step 3: Download resource
|
@@ -2009,7 +2005,7 @@ EOT
|
|
2009
2005
|
req = Net::HTTP::Get.new(uri)
|
2010
2006
|
|
2011
2007
|
req['Cookie'] = cookie
|
2012
|
-
req['User-Agent'] =
|
2008
|
+
req['User-Agent'] = 'OpenNebula CLI'
|
2013
2009
|
|
2014
2010
|
begin
|
2015
2011
|
File.open(path, 'wb') do |f|
|
@@ -2022,7 +2018,7 @@ EOT
|
|
2022
2018
|
end
|
2023
2019
|
end
|
2024
2020
|
rescue Errno::EACCES
|
2025
|
-
return OpenNebula::Error.new(
|
2021
|
+
return OpenNebula::Error.new('Target file not writable.')
|
2026
2022
|
end
|
2027
2023
|
|
2028
2024
|
error_message = nil
|
@@ -2039,30 +2035,30 @@ EOT
|
|
2039
2035
|
error_message = m[1] if m
|
2040
2036
|
end
|
2041
2037
|
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2038
|
+
return unless error_message
|
2039
|
+
|
2040
|
+
File.unlink(path)
|
2041
|
+
OpenNebula::Error.new("Remote server error: #{error_message}")
|
2046
2042
|
end
|
2047
2043
|
|
2048
|
-
def
|
2044
|
+
def self.level_lock_to_str(str)
|
2049
2045
|
level = str.to_i
|
2050
2046
|
if level == 0
|
2051
|
-
|
2047
|
+
'None'
|
2052
2048
|
elsif level == 1
|
2053
|
-
|
2049
|
+
'Use'
|
2054
2050
|
elsif level == 2
|
2055
|
-
|
2051
|
+
'Manage'
|
2056
2052
|
elsif level == 3
|
2057
|
-
|
2053
|
+
'Admin'
|
2058
2054
|
elsif level == 4
|
2059
|
-
|
2055
|
+
'All'
|
2060
2056
|
else
|
2061
|
-
|
2057
|
+
'-'
|
2062
2058
|
end
|
2063
2059
|
end
|
2064
2060
|
|
2065
|
-
def
|
2061
|
+
def self.parse_user_inputs(inputs, keys = [])
|
2066
2062
|
unless inputs.keys == keys
|
2067
2063
|
puts 'There are some parameters that require user input. ' \
|
2068
2064
|
'Use the string <<EDITOR>> to launch an editor ' \
|
@@ -2132,7 +2128,7 @@ EOT
|
|
2132
2128
|
# use default in case it's empty
|
2133
2129
|
answer = initial if answer.empty?
|
2134
2130
|
|
2135
|
-
unless
|
2131
|
+
unless ['YES', 'NO'].include?(answer)
|
2136
2132
|
STDERR.puts "Invalid boolean '#{answer}'"
|
2137
2133
|
STDERR.puts 'Boolean has to be YES or NO'
|
2138
2134
|
exit(-1)
|
@@ -2160,8 +2156,8 @@ EOT
|
|
2160
2156
|
answer = STDIN.readline.chop
|
2161
2157
|
|
2162
2158
|
answer = initial if answer == ''
|
2163
|
-
|
2164
|
-
end while !noanswer && (answer =~ exp)
|
2159
|
+
noanswer = ((answer == '') && optional)
|
2160
|
+
end while !noanswer && (answer =~ exp).nil?
|
2165
2161
|
|
2166
2162
|
if noanswer
|
2167
2163
|
next
|
@@ -2198,7 +2194,7 @@ EOT
|
|
2198
2194
|
answer = initial if answer == ''
|
2199
2195
|
|
2200
2196
|
noanswer = (answer == '') && optional
|
2201
|
-
end while !noanswer && ((answer =~ exp)
|
2197
|
+
end while !noanswer && ((answer =~ exp).nil? ||
|
2202
2198
|
answer.to_f < min || answer.to_f > max)
|
2203
2199
|
|
2204
2200
|
if noanswer
|
@@ -2257,7 +2253,7 @@ EOT
|
|
2257
2253
|
# @param title [String] Plot title
|
2258
2254
|
#
|
2259
2255
|
# @return Gnuplot plot object
|
2260
|
-
def
|
2256
|
+
def self.get_plot(x, y, attr, title)
|
2261
2257
|
# Require gnuplot gem only here
|
2262
2258
|
begin
|
2263
2259
|
require 'gnuplot'
|
@@ -2307,7 +2303,7 @@ EOT
|
|
2307
2303
|
# @param perm [String] Permissions in human readbale format
|
2308
2304
|
#
|
2309
2305
|
# @return [String] Permissions in octet format
|
2310
|
-
def
|
2306
|
+
def self.to_octet(perm)
|
2311
2307
|
begin
|
2312
2308
|
Integer(perm)
|
2313
2309
|
perm
|