opennebula-cli 4.6.1 → 4.7.80.beta
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/bin/oneflow-template +11 -5
- data/bin/oneimage +4 -2
- data/bin/onevnet +129 -13
- data/lib/cli_helper.rb +1 -1
- data/lib/one_helper.rb +7 -5
- data/lib/one_helper/onegroup_helper.rb +24 -10
- data/lib/one_helper/onequota_helper.rb +63 -22
- data/lib/one_helper/oneuser_helper.rb +30 -10
- data/lib/one_helper/onevm_helper.rb +4 -4
- data/lib/one_helper/onevnet_helper.rb +143 -40
- metadata +32 -36
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 585883a7bcb4f9ac918ccb674a77e40dc14b7883
|
4
|
+
data.tar.gz: ab8c5c867a236d9a78aa65ff4679a85077cf93eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 504217b07bc07ee8802598b4090b903f63866ffef10bd24dd76d599bacaab7b292bcad92799dfee336fa5b22b582d6b346ca784b9edb7f6e3e4fac076f8e33ca
|
7
|
+
data.tar.gz: 6de0113350a2d42d773f8b14d009dec444eff62e62820d9ab08e2ecbbc943252656cc251c88855853214c4d7502a807dec3493dda6b6e68aa78d4f966a7a2a3b
|
data/bin/oneflow-template
CHANGED
@@ -165,7 +165,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
165
165
|
OpenNebulaHelper.rname_to_id(arg, "USER")
|
166
166
|
end
|
167
167
|
|
168
|
-
set :format, :
|
168
|
+
set :format, :templateid, Service.rname_to_id_desc("SERVICE TEMPLATE") do |arg|
|
169
169
|
Service.rname_to_id(arg, "SERVICE TEMPLATE")
|
170
170
|
end
|
171
171
|
|
@@ -266,7 +266,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
266
266
|
Show detailed information of a given Service Template
|
267
267
|
EOT
|
268
268
|
|
269
|
-
command :show, show_desc, :
|
269
|
+
command :show, show_desc, :templateid, :options => Service::JSON_FORMAT do
|
270
270
|
client = Service::Client.new(
|
271
271
|
:username => options[:username],
|
272
272
|
:password => options[:password],
|
@@ -304,7 +304,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
304
304
|
Instantiate a Service Template
|
305
305
|
EOT
|
306
306
|
|
307
|
-
command :instantiate, instantiate_desc, :
|
307
|
+
command :instantiate, instantiate_desc, :templateid, [:file, nil],
|
308
308
|
:options => [Service::JSON_FORMAT, Service::TOP] do
|
309
309
|
client = Service::Client.new(
|
310
310
|
:username => options[:username],
|
@@ -312,7 +312,13 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
312
312
|
:url => options[:server],
|
313
313
|
:user_agent => USER_AGENT)
|
314
314
|
|
315
|
-
|
315
|
+
params = Hash.new
|
316
|
+
|
317
|
+
if(args[1])
|
318
|
+
params['merge_template'] = JSON.parse(File.read(args[1]))
|
319
|
+
end
|
320
|
+
|
321
|
+
json_str = Service.build_json_action('instantiate', params)
|
316
322
|
|
317
323
|
response = client.post("#{RESOURCE_PATH}/#{args[0]}/action", json_str)
|
318
324
|
|
@@ -448,4 +454,4 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
448
454
|
|
449
455
|
exit_code
|
450
456
|
end
|
451
|
-
end
|
457
|
+
end
|
data/bin/oneimage
CHANGED
@@ -161,9 +161,11 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
161
161
|
Creates a new Image from an existing one
|
162
162
|
EOT
|
163
163
|
|
164
|
-
command :clone, clone_desc, :imageid, :name
|
164
|
+
command :clone, clone_desc, :imageid, :name,
|
165
|
+
:options=>[OneDatastoreHelper::DATASTORE] do
|
165
166
|
helper.perform_action(args[0],options,"cloned") do |image|
|
166
|
-
|
167
|
+
ds_id = options[:datastore] || -1 # -1 clones to self
|
168
|
+
res = image.clone(args[1], ds_id)
|
167
169
|
|
168
170
|
if !OpenNebula.is_error?(res)
|
169
171
|
puts "ID: #{res}"
|
data/bin/onevnet
CHANGED
@@ -47,6 +47,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
47
47
|
set :option, CommandParser::OPTIONS+OpenNebulaHelper::CLIENT_OPTIONS
|
48
48
|
|
49
49
|
CREATE_OPTIONS = [OneClusterHelper::CLUSTER]
|
50
|
+
STD_OPTIONS = CommandParser::OPTIONS + OpenNebulaHelper::CLIENT_OPTIONS
|
50
51
|
|
51
52
|
########################################################################
|
52
53
|
# Formatters for arguments
|
@@ -71,6 +72,10 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
71
72
|
helper.filterflag_to_i(arg)
|
72
73
|
end
|
73
74
|
|
75
|
+
set :format, :ar_id, "Integer" do |arg|
|
76
|
+
format_int(arg)
|
77
|
+
end
|
78
|
+
|
74
79
|
########################################################################
|
75
80
|
# Commands
|
76
81
|
########################################################################
|
@@ -103,23 +108,65 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
103
108
|
end
|
104
109
|
end
|
105
110
|
|
106
|
-
|
107
|
-
Adds
|
111
|
+
addar_desc = <<-EOT.unindent
|
112
|
+
Adds an address range to the Virtual Network
|
108
113
|
EOT
|
109
114
|
|
110
|
-
command :
|
115
|
+
command :addar, addar_desc, :vnetid, :options=>STD_OPTIONS + [OneVNetHelper::AR_SIZE,
|
116
|
+
OneVNetHelper::AR_MAC, OneVNetHelper::AR_IP, OneVNetHelper::AR_IP6_GLOBAL,
|
117
|
+
OneVNetHelper::AR_IP6_ULA ] do
|
111
118
|
helper.perform_action(args[0],options,"lease added") do |vn|
|
112
|
-
|
119
|
+
ar = "AR = [ "
|
120
|
+
|
121
|
+
if options[:ip]
|
122
|
+
if options[:ip6_global] || options[:ip6_ula]
|
123
|
+
ar << "TYPE=\"IP4_6\""
|
124
|
+
else
|
125
|
+
ar << "TYPE=\"IP4\""
|
126
|
+
end
|
127
|
+
else
|
128
|
+
if options[:ip6_global] || options[:ip6_ula]
|
129
|
+
ar << "TYPE=\"IP6\""
|
130
|
+
else
|
131
|
+
ar << "TYPE=\"ETHER\""
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
if options[:size]
|
136
|
+
ar << ", SIZE = " << options[:size]
|
137
|
+
else
|
138
|
+
STDERR.puts "Address range needs to specify size (-s size)"
|
139
|
+
exit -1
|
140
|
+
end
|
141
|
+
|
142
|
+
ar << ", IP = " << options[:ip] if options[:ip]
|
143
|
+
ar << ", MAC = " << options[:mac] if options[:mac]
|
144
|
+
ar << ", GLOBAL_PREFIX = " << options[:ip6_global] if options[:ip6_global]
|
145
|
+
ar << ", ULA_PREFIX = " << options[:ip6_ula] if options[:ip6_ula]
|
146
|
+
|
147
|
+
ar << "]"
|
148
|
+
|
149
|
+
vn.add_ar(ar)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
rmar_desc = <<-EOT.unindent
|
154
|
+
Removes an address range from the Virtual Network
|
155
|
+
EOT
|
156
|
+
|
157
|
+
command :rmar, rmar_desc, :vnetid, :ar_id do
|
158
|
+
helper.perform_action(args[0],options,"address range removed") do |vn|
|
159
|
+
vn.rm_ar(args[1])
|
113
160
|
end
|
114
161
|
end
|
115
162
|
|
116
|
-
|
117
|
-
|
163
|
+
free_desc = <<-EOT.unindent
|
164
|
+
Frees a reserved address range from the Virtual Network
|
118
165
|
EOT
|
119
166
|
|
120
|
-
command :
|
121
|
-
helper.perform_action(args[0],options,"
|
122
|
-
vn.
|
167
|
+
command :free, free_desc, :vnetid, :ar_id do
|
168
|
+
helper.perform_action(args[0],options,"address range freed") do |vn|
|
169
|
+
vn.free(args[1])
|
123
170
|
end
|
124
171
|
end
|
125
172
|
|
@@ -127,9 +174,12 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
127
174
|
Holds a Virtual Network lease, marking it as used
|
128
175
|
EOT
|
129
176
|
|
130
|
-
command :hold, hold_desc, :vnetid, :ip
|
177
|
+
command :hold, hold_desc, :vnetid, :ip,
|
178
|
+
:options=>STD_OPTIONS + [OneVNetHelper::AR] do
|
131
179
|
helper.perform_action(args[0],options,"lease on hold") do |vn|
|
132
|
-
|
180
|
+
ar = options[:ar_id] || -1
|
181
|
+
|
182
|
+
vn.hold(args[1], ar)
|
133
183
|
end
|
134
184
|
end
|
135
185
|
|
@@ -137,12 +187,48 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
137
187
|
Releases a Virtual Network lease on hold
|
138
188
|
EOT
|
139
189
|
|
140
|
-
command :release, release_desc, :vnetid, :ip
|
190
|
+
command :release, release_desc, :vnetid, :ip,
|
191
|
+
:options=>STD_OPTIONS + [OneVNetHelper::AR] do
|
141
192
|
helper.perform_action(args[0],options,"lease released") do |vn|
|
142
|
-
|
193
|
+
ar = options[:ar_id] || -1
|
194
|
+
|
195
|
+
vn.release(args[1], ar)
|
143
196
|
end
|
144
197
|
end
|
145
198
|
|
199
|
+
reserve_desc = <<-EOT.unindent
|
200
|
+
Reserve addresses from the Virtual Network. A new virtual network will
|
201
|
+
be created to hold the reservation. Optionally the reservation can be
|
202
|
+
put on an exisiting VNET, as long as it contains a valid reservation
|
203
|
+
from the same VNET
|
204
|
+
EOT
|
205
|
+
|
206
|
+
command :reserve, reserve_desc, :vnetid, [:vnetid, nil],
|
207
|
+
:options=>STD_OPTIONS + [OneVNetHelper::AR, OneVNetHelper::R_NAME,
|
208
|
+
OneVNetHelper::R_SIZE, OneVNetHelper::AR_MAC, OneVNetHelper::AR_IP] do
|
209
|
+
helper.perform_action(args[0],options,"reservation made") do |vn|
|
210
|
+
rsize = options[:rsize] || -1
|
211
|
+
rname = options[:rname] || -1
|
212
|
+
|
213
|
+
addr = nil
|
214
|
+
addr = options[:mac] if options[:mac]
|
215
|
+
addr = options[:ip] if options[:ip]
|
216
|
+
|
217
|
+
if rsize == -1
|
218
|
+
STDERR.puts "Specify a size (-s size) for the reservation"
|
219
|
+
exit -1
|
220
|
+
end
|
221
|
+
|
222
|
+
if rname == -1 && args[1].nil?
|
223
|
+
STDERR.puts "Specify a name (-n name) for the reservation"
|
224
|
+
exit -1
|
225
|
+
end
|
226
|
+
|
227
|
+
vn.reserve(rname, rsize, options[:ar_id], addr, args[1])
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
|
146
232
|
chgrp_desc = <<-EOT.unindent
|
147
233
|
Changes the Virtual Network group
|
148
234
|
EOT
|
@@ -212,6 +298,36 @@ cmd=CommandParser::CmdParser.new(ARGV) do
|
|
212
298
|
end
|
213
299
|
end
|
214
300
|
|
301
|
+
update_ar_desc = <<-EOT.unindent
|
302
|
+
Update Address Range variables. SIZE, IP, MAC and TYPE cannot be updated
|
303
|
+
EOT
|
304
|
+
|
305
|
+
command :updatear, update_ar_desc, :vnetid, :ar_id, [:file, nil] do
|
306
|
+
helper.perform_action(args[0],options,"modified") do |obj|
|
307
|
+
rc = obj.info
|
308
|
+
|
309
|
+
if OpenNebula.is_error?(rc)
|
310
|
+
puts rc.message
|
311
|
+
exit -1
|
312
|
+
end
|
313
|
+
|
314
|
+
obj.delete_element("AR_POOL/AR[AR_ID!=#{args[1]}]")
|
315
|
+
obj.delete_element("AR_POOL/AR/LEASES")
|
316
|
+
obj.delete_element("AR_POOL/AR/USED_LEASES")
|
317
|
+
|
318
|
+
if obj.template_like_str("AR_POOL").empty?
|
319
|
+
puts "Address Range #{args[1]} does not exit for "<<
|
320
|
+
"Virtual Network #{args[0]}"
|
321
|
+
exit -1
|
322
|
+
end
|
323
|
+
|
324
|
+
str = OpenNebulaHelper.update_template_helper(false, args[0], obj,
|
325
|
+
args[2], "AR_POOL", false)
|
326
|
+
|
327
|
+
obj.update_ar(str)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
215
331
|
rename_desc = <<-EOT.unindent
|
216
332
|
Renames the Virtual Network
|
217
333
|
EOT
|
data/lib/cli_helper.rb
CHANGED
data/lib/one_helper.rb
CHANGED
@@ -821,7 +821,7 @@ EOT
|
|
821
821
|
return update_template_helper(true, id, resource, path, xpath)
|
822
822
|
end
|
823
823
|
|
824
|
-
def OpenNebulaHelper.update_template_helper(append, id, resource, path, xpath)
|
824
|
+
def OpenNebulaHelper.update_template_helper(append, id, resource, path, xpath, update=true)
|
825
825
|
unless path
|
826
826
|
require 'tempfile'
|
827
827
|
|
@@ -829,11 +829,13 @@ EOT
|
|
829
829
|
path = tmp.path
|
830
830
|
|
831
831
|
if !append
|
832
|
-
|
832
|
+
if update
|
833
|
+
rc = resource.info
|
833
834
|
|
834
|
-
|
835
|
-
|
836
|
-
|
835
|
+
if OpenNebula.is_error?(rc)
|
836
|
+
puts rc.message
|
837
|
+
exit -1
|
838
|
+
end
|
837
839
|
end
|
838
840
|
|
839
841
|
tmp << resource.template_like_str(xpath)
|
@@ -110,12 +110,16 @@ class OneGroupHelper < OpenNebulaHelper::OneHelper
|
|
110
110
|
q = quotas[d['ID']]
|
111
111
|
limit = q['VM_QUOTA']['VM']["VMS"]
|
112
112
|
|
113
|
-
if limit ==
|
113
|
+
if limit == OneQuotaHelper::LIMIT_DEFAULT
|
114
114
|
limit = pool_default_quotas("VM_QUOTA/VM/VMS")
|
115
|
-
limit =
|
115
|
+
limit = OneQuotaHelper::LIMIT_UNLIMITED if limit.nil? || limit == ""
|
116
116
|
end
|
117
117
|
|
118
|
-
|
118
|
+
if limit == OneQuotaHelper::LIMIT_UNLIMITED
|
119
|
+
"%3d / -" % [q['VM_QUOTA']['VM']["VMS_USED"]]
|
120
|
+
else
|
121
|
+
"%3d / %3d" % [q['VM_QUOTA']['VM']["VMS_USED"], limit]
|
122
|
+
end
|
119
123
|
|
120
124
|
rescue NoMethodError
|
121
125
|
"-"
|
@@ -127,13 +131,19 @@ class OneGroupHelper < OpenNebulaHelper::OneHelper
|
|
127
131
|
q = quotas[d['ID']]
|
128
132
|
limit = q['VM_QUOTA']['VM']["MEMORY"]
|
129
133
|
|
130
|
-
if limit ==
|
134
|
+
if limit == OneQuotaHelper::LIMIT_DEFAULT
|
131
135
|
limit = pool_default_quotas("VM_QUOTA/VM/MEMORY")
|
132
|
-
limit =
|
136
|
+
limit = OneQuotaHelper::LIMIT_UNLIMITED if limit.nil? || limit == ""
|
133
137
|
end
|
134
138
|
|
135
|
-
|
136
|
-
|
139
|
+
if limit == OneQuotaHelper::LIMIT_UNLIMITED
|
140
|
+
"%7s / -" % [
|
141
|
+
OpenNebulaHelper.unit_to_str(q['VM_QUOTA']['VM']["MEMORY_USED"].to_i,{},"M")]
|
142
|
+
else
|
143
|
+
"%7s / %7s" % [
|
144
|
+
OpenNebulaHelper.unit_to_str(q['VM_QUOTA']['VM']["MEMORY_USED"].to_i,{},"M"),
|
145
|
+
OpenNebulaHelper.unit_to_str(limit.to_i,{},"M")]
|
146
|
+
end
|
137
147
|
|
138
148
|
rescue NoMethodError
|
139
149
|
"-"
|
@@ -145,12 +155,16 @@ class OneGroupHelper < OpenNebulaHelper::OneHelper
|
|
145
155
|
q = quotas[d['ID']]
|
146
156
|
limit = q['VM_QUOTA']['VM']["CPU"]
|
147
157
|
|
148
|
-
if limit ==
|
158
|
+
if limit == OneQuotaHelper::LIMIT_DEFAULT
|
149
159
|
limit = pool_default_quotas("VM_QUOTA/VM/CPU")
|
150
|
-
limit =
|
160
|
+
limit = OneQuotaHelper::LIMIT_UNLIMITED if limit.nil? || limit == ""
|
151
161
|
end
|
152
162
|
|
153
|
-
|
163
|
+
if limit == OneQuotaHelper::LIMIT_UNLIMITED
|
164
|
+
"%3.1f / -" % [q['VM_QUOTA']['VM']["CPU_USED"]]
|
165
|
+
else
|
166
|
+
"%3.1f / %3.1f" % [q['VM_QUOTA']['VM']["CPU_USED"], limit]
|
167
|
+
end
|
154
168
|
|
155
169
|
rescue NoMethodError
|
156
170
|
"-"
|
@@ -18,6 +18,9 @@ require 'cli_helper'
|
|
18
18
|
|
19
19
|
class OneQuotaHelper
|
20
20
|
|
21
|
+
LIMIT_DEFAULT = "-1"
|
22
|
+
LIMIT_UNLIMITED = "-2"
|
23
|
+
|
21
24
|
EDITOR_PATH='/usr/bin/vi'
|
22
25
|
|
23
26
|
HELP_QUOTA = <<-EOT.unindent
|
@@ -52,7 +55,7 @@ class OneQuotaHelper
|
|
52
55
|
#
|
53
56
|
# In any quota:
|
54
57
|
# -1 means use the default limit (set with the 'defaultquota' command)
|
55
|
-
#
|
58
|
+
# -2 means unlimited.
|
56
59
|
#
|
57
60
|
# The usage counters "*_USED" are shown for information
|
58
61
|
# purposes and will NOT be modified.
|
@@ -62,7 +65,7 @@ class OneQuotaHelper
|
|
62
65
|
HELP_DEFAULT_QUOTA_FOOTER = <<-EOT.unindent
|
63
66
|
#
|
64
67
|
# In any quota:
|
65
|
-
#
|
68
|
+
# -2 means unlimited.
|
66
69
|
#
|
67
70
|
# The usage counters "*_USED" will always be 0 for the default
|
68
71
|
# quotas, and can be ignored.
|
@@ -209,7 +212,11 @@ class OneQuotaHelper
|
|
209
212
|
limit = helper.get_default_limit(
|
210
213
|
limit, "VM_QUOTA/VM/#{elem}")
|
211
214
|
|
212
|
-
|
215
|
+
if limit == LIMIT_UNLIMITED
|
216
|
+
"%7d / -" % [d["VMS_USED"]]
|
217
|
+
else
|
218
|
+
"%7d / %7d" % [d["VMS_USED"], limit]
|
219
|
+
end
|
213
220
|
end
|
214
221
|
end
|
215
222
|
|
@@ -220,10 +227,16 @@ class OneQuotaHelper
|
|
220
227
|
limit = helper.get_default_limit(
|
221
228
|
limit, "VM_QUOTA/VM/#{elem}")
|
222
229
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
230
|
+
if limit == LIMIT_UNLIMITED
|
231
|
+
"%8s / -" % [
|
232
|
+
OpenNebulaHelper.unit_to_str(d["MEMORY_USED"].to_i,{},"M")
|
233
|
+
]
|
234
|
+
else
|
235
|
+
"%8s / %8s" % [
|
236
|
+
OpenNebulaHelper.unit_to_str(d["MEMORY_USED"].to_i,{},"M"),
|
237
|
+
OpenNebulaHelper.unit_to_str(limit.to_i,{},"M")
|
238
|
+
]
|
239
|
+
end
|
227
240
|
end
|
228
241
|
end
|
229
242
|
|
@@ -234,7 +247,11 @@ class OneQuotaHelper
|
|
234
247
|
limit = helper.get_default_limit(
|
235
248
|
limit, "VM_QUOTA/VM/#{elem}")
|
236
249
|
|
237
|
-
|
250
|
+
if limit == LIMIT_UNLIMITED
|
251
|
+
"%8.2f / -" % [d["CPU_USED"]]
|
252
|
+
else
|
253
|
+
"%8.2f / %8.2f" % [d["CPU_USED"], limit]
|
254
|
+
end
|
238
255
|
end
|
239
256
|
end
|
240
257
|
|
@@ -245,10 +262,16 @@ class OneQuotaHelper
|
|
245
262
|
limit = helper.get_default_limit(
|
246
263
|
limit, "VM_QUOTA/VM/#{elem}")
|
247
264
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
265
|
+
if limit == LIMIT_UNLIMITED
|
266
|
+
"%8s / -" % [
|
267
|
+
OpenNebulaHelper.unit_to_str(d["VOLATILE_SIZE_USED"].to_i,{},"M")
|
268
|
+
]
|
269
|
+
else
|
270
|
+
"%8s / %8s" % [
|
271
|
+
OpenNebulaHelper.unit_to_str(d["VOLATILE_SIZE_USED"].to_i,{},"M"),
|
272
|
+
OpenNebulaHelper.unit_to_str(limit.to_i,{},"M")
|
273
|
+
]
|
274
|
+
end
|
252
275
|
end
|
253
276
|
end
|
254
277
|
end.show(vm_quotas, {})
|
@@ -271,7 +294,11 @@ class OneQuotaHelper
|
|
271
294
|
limit = helper.get_default_limit(
|
272
295
|
limit, "DATASTORE_QUOTA/DATASTORE[ID=#{d['ID']}]/#{elem}")
|
273
296
|
|
274
|
-
|
297
|
+
if limit == LIMIT_UNLIMITED
|
298
|
+
"%8d / -" % [d["IMAGES_USED"]]
|
299
|
+
else
|
300
|
+
"%8d / %8d" % [d["IMAGES_USED"], limit]
|
301
|
+
end
|
275
302
|
end
|
276
303
|
end
|
277
304
|
|
@@ -282,10 +309,16 @@ class OneQuotaHelper
|
|
282
309
|
limit = helper.get_default_limit(
|
283
310
|
limit, "DATASTORE_QUOTA/DATASTORE[ID=#{d['ID']}]/#{elem}")
|
284
311
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
312
|
+
if limit == LIMIT_UNLIMITED
|
313
|
+
"%8s / -" % [
|
314
|
+
OpenNebulaHelper.unit_to_str(d["SIZE_USED"].to_i,{},"M")
|
315
|
+
]
|
316
|
+
else
|
317
|
+
"%8s / %8s" % [
|
318
|
+
OpenNebulaHelper.unit_to_str(d["SIZE_USED"].to_i,{},"M"),
|
319
|
+
OpenNebulaHelper.unit_to_str(limit.to_i,{},"M")
|
320
|
+
]
|
321
|
+
end
|
289
322
|
end
|
290
323
|
end
|
291
324
|
end.show(ds_quotas, {})
|
@@ -308,7 +341,11 @@ class OneQuotaHelper
|
|
308
341
|
limit = helper.get_default_limit(
|
309
342
|
limit, "NETWORK_QUOTA/NETWORK[ID=#{d['ID']}]/#{elem}")
|
310
343
|
|
311
|
-
|
344
|
+
if limit == LIMIT_UNLIMITED
|
345
|
+
"%8d / -" % [d["LEASES_USED"]]
|
346
|
+
else
|
347
|
+
"%8d / %8d" % [d["LEASES_USED"], limit]
|
348
|
+
end
|
312
349
|
end
|
313
350
|
end
|
314
351
|
end.show(net_quotas, {})
|
@@ -331,7 +368,11 @@ class OneQuotaHelper
|
|
331
368
|
limit = helper.get_default_limit(
|
332
369
|
limit, "IMAGE_QUOTA/IMAGE[ID=#{d['ID']}]/RVMS")
|
333
370
|
|
334
|
-
|
371
|
+
if limit == LIMIT_UNLIMITED
|
372
|
+
"%8d / -" % [d["RVMS_USED"]]
|
373
|
+
else
|
374
|
+
"%8d / %8d" % [d["RVMS_USED"], limit]
|
375
|
+
end
|
335
376
|
end
|
336
377
|
end
|
337
378
|
end.show(image_quotas, {})
|
@@ -339,13 +380,13 @@ class OneQuotaHelper
|
|
339
380
|
end
|
340
381
|
|
341
382
|
def get_default_limit(limit, xpath)
|
342
|
-
if limit ==
|
383
|
+
if limit == LIMIT_DEFAULT
|
343
384
|
if !@default_quotas.nil?
|
344
385
|
limit = @default_quotas[xpath]
|
345
386
|
|
346
|
-
limit =
|
387
|
+
limit = LIMIT_UNLIMITED if limit.nil? || limit == ""
|
347
388
|
else
|
348
|
-
limit =
|
389
|
+
limit = LIMIT_UNLIMITED
|
349
390
|
end
|
350
391
|
end
|
351
392
|
|
@@ -190,12 +190,18 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
|
|
190
190
|
q = quotas[d['ID']]
|
191
191
|
limit = q['VM_QUOTA']['VM']["VMS"]
|
192
192
|
|
193
|
-
if limit ==
|
193
|
+
if limit == OneQuotaHelper::LIMIT_DEFAULT
|
194
194
|
limit = pool_default_quotas("VM_QUOTA/VM/VMS")
|
195
|
-
|
195
|
+
if limit.nil? || limit == ""
|
196
|
+
limit = OneQuotaHelper::LIMIT_UNLIMITED
|
197
|
+
end
|
196
198
|
end
|
197
199
|
|
198
|
-
|
200
|
+
if limit == OneQuotaHelper::LIMIT_UNLIMITED
|
201
|
+
"%3d / -" % [q['VM_QUOTA']['VM']["VMS_USED"]]
|
202
|
+
else
|
203
|
+
"%3d / %3d" % [q['VM_QUOTA']['VM']["VMS_USED"], limit]
|
204
|
+
end
|
199
205
|
|
200
206
|
rescue NoMethodError
|
201
207
|
"-"
|
@@ -207,13 +213,21 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
|
|
207
213
|
q = quotas[d['ID']]
|
208
214
|
limit = q['VM_QUOTA']['VM']["MEMORY"]
|
209
215
|
|
210
|
-
if limit ==
|
216
|
+
if limit == OneQuotaHelper::LIMIT_DEFAULT
|
211
217
|
limit = pool_default_quotas("VM_QUOTA/VM/MEMORY")
|
212
|
-
|
218
|
+
if limit.nil? || limit == ""
|
219
|
+
limit = OneQuotaHelper::LIMIT_UNLIMITED
|
220
|
+
end
|
213
221
|
end
|
214
222
|
|
215
|
-
|
216
|
-
|
223
|
+
if limit == OneQuotaHelper::LIMIT_UNLIMITED
|
224
|
+
"%7s / -" % [
|
225
|
+
OpenNebulaHelper.unit_to_str(q['VM_QUOTA']['VM']["MEMORY_USED"].to_i,{},"M")]
|
226
|
+
else
|
227
|
+
"%7s / %7s" % [
|
228
|
+
OpenNebulaHelper.unit_to_str(q['VM_QUOTA']['VM']["MEMORY_USED"].to_i,{},"M"),
|
229
|
+
OpenNebulaHelper.unit_to_str(limit.to_i,{},"M")]
|
230
|
+
end
|
217
231
|
|
218
232
|
rescue NoMethodError
|
219
233
|
"-"
|
@@ -225,12 +239,18 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
|
|
225
239
|
q = quotas[d['ID']]
|
226
240
|
limit = q['VM_QUOTA']['VM']["CPU"]
|
227
241
|
|
228
|
-
if limit ==
|
242
|
+
if limit == OneQuotaHelper::LIMIT_DEFAULT
|
229
243
|
limit = pool_default_quotas("VM_QUOTA/VM/CPU")
|
230
|
-
|
244
|
+
if limit.nil? || limit == ""
|
245
|
+
limit = OneQuotaHelper::LIMIT_UNLIMITED
|
246
|
+
end
|
231
247
|
end
|
232
248
|
|
233
|
-
|
249
|
+
if limit == OneQuotaHelper::LIMIT_UNLIMITED
|
250
|
+
"%3.1f / -" % [q['VM_QUOTA']['VM']["CPU_USED"]]
|
251
|
+
else
|
252
|
+
"%3.1f / %3.1f" % [q['VM_QUOTA']['VM']["CPU_USED"], limit]
|
253
|
+
end
|
234
254
|
|
235
255
|
rescue NoMethodError
|
236
256
|
"-"
|
@@ -248,8 +248,8 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
|
|
248
248
|
puts str % ["HOST",
|
249
249
|
vm['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']] if
|
250
250
|
%w{ACTIVE SUSPENDED POWEROFF}.include? vm.state_str
|
251
|
-
puts str % ["CLUSTER ID",
|
252
|
-
vm['/VM/HISTORY_RECORDS/HISTORY[last()]/CID'] ] if
|
251
|
+
puts str % ["CLUSTER ID",
|
252
|
+
vm['/VM/HISTORY_RECORDS/HISTORY[last()]/CID'] ] if
|
253
253
|
%w{ACTIVE SUSPENDED POWEROFF}.include? vm.state_str
|
254
254
|
puts str % ["START TIME",
|
255
255
|
OpenNebulaHelper.time_to_str(vm['/VM/STIME'])]
|
@@ -380,8 +380,8 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
|
|
380
380
|
array_id += 1
|
381
381
|
end
|
382
382
|
|
383
|
-
if nic.has_key?("
|
384
|
-
ip6_link = {"IP" => nic.delete("
|
383
|
+
if nic.has_key?("IP6_ULA")
|
384
|
+
ip6_link = {"IP" => nic.delete("IP6_ULA"),
|
385
385
|
"CLI_DONE" => true,
|
386
386
|
"DOUBLE_ENTRY" => true}
|
387
387
|
vm_nics.insert(array_id+1,ip6_link)
|
@@ -18,6 +18,70 @@ require 'one_helper'
|
|
18
18
|
require 'one_helper/onevm_helper'
|
19
19
|
|
20
20
|
class OneVNetHelper < OpenNebulaHelper::OneHelper
|
21
|
+
AR = {
|
22
|
+
:name => "ar_id",
|
23
|
+
:short => "-a ar_id",
|
24
|
+
:large => "--address_range ar_id",
|
25
|
+
:format => Integer,
|
26
|
+
:description => "ID of the address range"
|
27
|
+
}
|
28
|
+
|
29
|
+
AR_MAC = {
|
30
|
+
:name => "mac",
|
31
|
+
:short => "-m mac",
|
32
|
+
:large => "--address_range_mac mac",
|
33
|
+
:format => String,
|
34
|
+
:description => "First MAC address in : notation"
|
35
|
+
}
|
36
|
+
|
37
|
+
AR_IP = {
|
38
|
+
:name => "ip",
|
39
|
+
:short => "-i ip",
|
40
|
+
:large => "--address_range_ip ip",
|
41
|
+
:format => String,
|
42
|
+
:description => "First IP address in . notation"
|
43
|
+
}
|
44
|
+
|
45
|
+
AR_SIZE = {
|
46
|
+
:name => "size",
|
47
|
+
:short => "-s size",
|
48
|
+
:large => "--address_range_size size",
|
49
|
+
:format => String,
|
50
|
+
:description => "Number of addresses in the range"
|
51
|
+
}
|
52
|
+
|
53
|
+
AR_IP6_GLOBAL = {
|
54
|
+
:name => "ip6_global",
|
55
|
+
:short => "-g ip6_pref",
|
56
|
+
:large => "--address_range_ip6g ip6_pref",
|
57
|
+
:format => String,
|
58
|
+
:description => "IP6 global prefix"
|
59
|
+
}
|
60
|
+
|
61
|
+
AR_IP6_ULA = {
|
62
|
+
:name => "ip6_ula",
|
63
|
+
:short => "-u ip6_pref",
|
64
|
+
:large => "--address_range_ip6u ip6_pref",
|
65
|
+
:format => String,
|
66
|
+
:description => "IP6 ula prefix"
|
67
|
+
}
|
68
|
+
|
69
|
+
R_NAME = {
|
70
|
+
:name => "rname",
|
71
|
+
:short => "-n reservation name",
|
72
|
+
:large => "--name reservation name",
|
73
|
+
:format => String,
|
74
|
+
:description => "Name of the address reservation"
|
75
|
+
}
|
76
|
+
|
77
|
+
R_SIZE = {
|
78
|
+
:name => "rsize",
|
79
|
+
:short => "-s reservation size",
|
80
|
+
:large => "--size reservation size",
|
81
|
+
:format => String,
|
82
|
+
:description => "Number of addresses to reserve"
|
83
|
+
}
|
84
|
+
|
21
85
|
def self.rname
|
22
86
|
"VNET"
|
23
87
|
end
|
@@ -26,12 +90,6 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
|
|
26
90
|
"onevnet.yaml"
|
27
91
|
end
|
28
92
|
|
29
|
-
def self.type_to_str(id)
|
30
|
-
id = id.to_i
|
31
|
-
type_str = VirtualNetwork::VN_TYPES[id]
|
32
|
-
return VirtualNetwork::SHORT_VN_TYPES[type_str]
|
33
|
-
end
|
34
|
-
|
35
93
|
def format_pool(options)
|
36
94
|
config_file = self.class.table_conf
|
37
95
|
|
@@ -57,10 +115,6 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
|
|
57
115
|
|
58
116
|
column :CLUSTER, "Name of the Cluster", :left, :size=>10 do |d|
|
59
117
|
OpenNebulaHelper.cluster_str(d["CLUSTER"])
|
60
|
-
end
|
61
|
-
|
62
|
-
column :TYPE, "Type of Virtual Network", :size=>6 do |d|
|
63
|
-
OneVNetHelper.type_to_str(d["TYPE"])
|
64
118
|
end
|
65
119
|
|
66
120
|
column :SIZE, "Size of the Virtual Network", :size=>5 do |d|
|
@@ -74,7 +128,7 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
|
|
74
128
|
|
75
129
|
column :LEASES, "Number of this Virtual Network's given leases",
|
76
130
|
:size=>6 do |d|
|
77
|
-
d["
|
131
|
+
d["USED_LEASES"]
|
78
132
|
end
|
79
133
|
|
80
134
|
default :ID, :USER, :GROUP, :NAME, :CLUSTER, :TYPE, :BRIDGE, :LEASES
|
@@ -109,14 +163,11 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
|
|
109
163
|
puts str % ["USER", vn['UNAME']]
|
110
164
|
puts str % ["GROUP", vn['GNAME']]
|
111
165
|
puts str % ["CLUSTER", OpenNebulaHelper.cluster_str(vn['CLUSTER'])]
|
112
|
-
puts str % ["TYPE", vn.type_str]
|
113
166
|
puts str % ["BRIDGE", vn["BRIDGE"]]
|
114
167
|
puts str % ["VLAN", OpenNebulaHelper.boolean_to_str(vn['VLAN'])]
|
115
168
|
puts str % ["PHYSICAL DEVICE", vn["PHYDEV"]] if !vn["PHYDEV"].empty?
|
116
169
|
puts str % ["VLAN ID", vn["VLAN_ID"]] if !vn["VLAN_ID"].empty?
|
117
|
-
puts str % ["
|
118
|
-
puts str % ["SITE PREFIX", vn["SITE_PREFIX"]] if !vn["SITE_PREFIX"].empty?
|
119
|
-
puts str % ["USED LEASES", vn['TOTAL_LEASES']]
|
170
|
+
puts str % ["USED LEASES", vn['USED_LEASES']]
|
120
171
|
puts
|
121
172
|
|
122
173
|
CLIHelper.print_header(str_h1 % "PERMISSIONS",false)
|
@@ -129,45 +180,97 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
|
|
129
180
|
|
130
181
|
puts str % [e, mask]
|
131
182
|
}
|
183
|
+
|
132
184
|
puts
|
133
185
|
|
134
186
|
CLIHelper.print_header(str_h1 % ["VIRTUAL NETWORK TEMPLATE"], false)
|
135
187
|
|
136
188
|
puts vn.template_str(false)
|
137
189
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
190
|
+
puts
|
191
|
+
|
192
|
+
CLIHelper.print_header(str_h1 % ["ADDRESS RANGE POOL"], false)
|
193
|
+
|
194
|
+
if !vn.to_hash['VNET']['AR_POOL']['AR'].nil?
|
195
|
+
arlist = [vn.to_hash['VNET']['AR_POOL']['AR']].flatten
|
143
196
|
end
|
144
197
|
|
145
|
-
|
146
|
-
|
147
|
-
|
198
|
+
CLIHelper::ShowTable.new(nil, self) do
|
199
|
+
column :AR, "", :size=>3 do |d|
|
200
|
+
d["AR_ID"]
|
201
|
+
end
|
148
202
|
|
149
|
-
|
150
|
-
|
203
|
+
column :TYPE, "", :left, :size=>5 do |d|
|
204
|
+
d["TYPE"]
|
205
|
+
end
|
151
206
|
|
152
|
-
|
153
|
-
|
154
|
-
CLIHelper.print_header(str_h1 % [pair[0]], false)
|
155
|
-
puts leases_str
|
207
|
+
column :SIZE, "", :size=>6 do |d|
|
208
|
+
d["SIZE"]
|
156
209
|
end
|
157
|
-
}
|
158
210
|
|
159
|
-
|
160
|
-
|
161
|
-
|
211
|
+
column :LEASES, "", :size=>6 do |d|
|
212
|
+
d["USED_LEASES"]
|
213
|
+
end
|
214
|
+
|
215
|
+
column :MAC, "", :size=>17 do |d|
|
216
|
+
d["MAC"]
|
217
|
+
end
|
162
218
|
|
163
|
-
|
219
|
+
column :IP, "", :size=>15 do |d|
|
220
|
+
d["IP"]||"-"
|
221
|
+
end
|
164
222
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
223
|
+
column :GLOBAL_PREFIX, "", :right, :size=>22 do |d|
|
224
|
+
d["GLOBAL_PREFIX"]||"-"
|
225
|
+
end
|
226
|
+
|
227
|
+
end.show(arlist, {})
|
228
|
+
|
229
|
+
puts
|
230
|
+
CLIHelper.print_header(str_h1 % ["LEASES"], false)
|
231
|
+
|
232
|
+
if !vn.to_hash['VNET']['AR_POOL']['AR'].nil?
|
233
|
+
lease_list = [vn.to_hash['VNET']['AR_POOL']['AR']].flatten
|
234
|
+
leases = Array.new
|
235
|
+
|
236
|
+
lease_list.each do |ar|
|
237
|
+
id = ar['AR_ID']
|
238
|
+
if ar['LEASES'] && !ar['LEASES']['LEASE'].nil?
|
239
|
+
lease = [ar['LEASES']['LEASE']].flatten
|
240
|
+
lease.each do |l|
|
241
|
+
l['AR_ID'] = id
|
242
|
+
end
|
243
|
+
leases << lease
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
leases.flatten!
|
171
248
|
end
|
249
|
+
|
250
|
+
CLIHelper::ShowTable.new(nil, self) do
|
251
|
+
column :AR, "", :left, :size=>3 do |d|
|
252
|
+
d['AR_ID']
|
253
|
+
end
|
254
|
+
|
255
|
+
column :OWNER, "", :left, :size=>10 do |d|
|
256
|
+
if d['VM']
|
257
|
+
"VM : #{d['VM']}"
|
258
|
+
elsif d['VNET']
|
259
|
+
"NET: #{d['VNET']}"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
column :MAC, "", :size=>17 do |d|
|
264
|
+
d["MAC"]
|
265
|
+
end
|
266
|
+
|
267
|
+
column :IP, "", :size=>15 do |d|
|
268
|
+
d["IP"]||"-"
|
269
|
+
end
|
270
|
+
|
271
|
+
column :IP6_GLOBAL, "", :size=>31 do |d|
|
272
|
+
d["IP6_GLOBAL"]||"-"
|
273
|
+
end
|
274
|
+
end.show(leases, {})
|
172
275
|
end
|
173
276
|
end
|
metadata
CHANGED
@@ -1,32 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opennebula-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
5
|
-
prerelease:
|
4
|
+
version: 4.7.80.beta
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- OpenNebula
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2014-
|
11
|
+
date: 2014-07-17 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: opennebula
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - '='
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 4.
|
19
|
+
version: 4.7.80.beta
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - '='
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: 4.
|
26
|
+
version: 4.7.80.beta
|
30
27
|
description: Commands used to talk to OpenNebula
|
31
28
|
email: contact@opennebula.org
|
32
29
|
executables:
|
@@ -47,61 +44,60 @@ executables:
|
|
47
44
|
extensions: []
|
48
45
|
extra_rdoc_files: []
|
49
46
|
files:
|
47
|
+
- LICENSE
|
48
|
+
- NOTICE
|
49
|
+
- bin/oneacct
|
50
50
|
- bin/oneacl
|
51
|
-
- bin/
|
52
|
-
- bin/oneflow-template
|
53
|
-
- bin/onevnet
|
54
|
-
- bin/oneimage
|
51
|
+
- bin/onecluster
|
55
52
|
- bin/onedatastore
|
56
|
-
- bin/
|
53
|
+
- bin/oneflow
|
54
|
+
- bin/oneflow-template
|
57
55
|
- bin/onegroup
|
58
|
-
- bin/
|
56
|
+
- bin/onehost
|
57
|
+
- bin/oneimage
|
59
58
|
- bin/onetemplate
|
60
|
-
- bin/oneflow
|
61
59
|
- bin/oneuser
|
60
|
+
- bin/onevm
|
61
|
+
- bin/onevnet
|
62
62
|
- bin/onezone
|
63
|
-
- bin/oneacct
|
64
|
-
- lib/one_helper.rb
|
65
|
-
- lib/command_parser.rb
|
66
63
|
- lib/cli_helper.rb
|
64
|
+
- lib/command_parser.rb
|
65
|
+
- lib/one_helper.rb
|
66
|
+
- lib/one_helper/oneacct_helper.rb
|
67
|
+
- lib/one_helper/oneacl_helper.rb
|
68
|
+
- lib/one_helper/onecluster_helper.rb
|
69
|
+
- lib/one_helper/onedatastore_helper.rb
|
70
|
+
- lib/one_helper/onegroup_helper.rb
|
71
|
+
- lib/one_helper/onehost_helper.rb
|
72
|
+
- lib/one_helper/oneimage_helper.rb
|
67
73
|
- lib/one_helper/onequota_helper.rb
|
68
74
|
- lib/one_helper/onetemplate_helper.rb
|
69
|
-
- lib/one_helper/onegroup_helper.rb
|
70
|
-
- lib/one_helper/onezone_helper.rb
|
71
|
-
- lib/one_helper/onevnet_helper.rb
|
72
|
-
- lib/one_helper/onevm_helper.rb
|
73
75
|
- lib/one_helper/oneuser_helper.rb
|
74
|
-
- lib/one_helper/
|
75
|
-
- lib/one_helper/
|
76
|
-
- lib/one_helper/
|
77
|
-
- lib/one_helper/oneacl_helper.rb
|
78
|
-
- lib/one_helper/oneacct_helper.rb
|
79
|
-
- lib/one_helper/onehost_helper.rb
|
80
|
-
- NOTICE
|
81
|
-
- LICENSE
|
76
|
+
- lib/one_helper/onevm_helper.rb
|
77
|
+
- lib/one_helper/onevnet_helper.rb
|
78
|
+
- lib/one_helper/onezone_helper.rb
|
82
79
|
homepage: http://opennebula.org
|
83
80
|
licenses: []
|
81
|
+
metadata: {}
|
84
82
|
post_install_message:
|
85
83
|
rdoc_options: []
|
86
84
|
require_paths:
|
87
85
|
- lib
|
88
86
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
87
|
requirements:
|
91
|
-
- -
|
88
|
+
- - ">="
|
92
89
|
- !ruby/object:Gem::Version
|
93
90
|
version: '0'
|
94
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
92
|
requirements:
|
97
|
-
- -
|
93
|
+
- - ">"
|
98
94
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
95
|
+
version: 1.3.1
|
100
96
|
requirements: []
|
101
97
|
rubyforge_project:
|
102
|
-
rubygems_version:
|
98
|
+
rubygems_version: 2.2.2
|
103
99
|
signing_key:
|
104
|
-
specification_version:
|
100
|
+
specification_version: 4
|
105
101
|
summary: OpenNebula Command Line Interface
|
106
102
|
test_files: []
|
107
103
|
has_rdoc:
|