opennebula-cli 3.8.0.beta1
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.
- data/bin/oneacct +113 -0
- data/bin/oneacl +97 -0
- data/bin/onecluster +189 -0
- data/bin/onedatastore +165 -0
- data/bin/onegroup +137 -0
- data/bin/onehost +205 -0
- data/bin/oneimage +311 -0
- data/bin/onetemplate +277 -0
- data/bin/oneuser +404 -0
- data/bin/onevm +532 -0
- data/bin/onevnet +227 -0
- data/lib/cli_helper.rb +294 -0
- data/lib/command_parser.rb +719 -0
- data/lib/one_helper/oneacct_helper.rb +179 -0
- data/lib/one_helper/oneacl_helper.rb +130 -0
- data/lib/one_helper/onecluster_helper.rb +129 -0
- data/lib/one_helper/onedatastore_helper.rb +131 -0
- data/lib/one_helper/onegroup_helper.rb +134 -0
- data/lib/one_helper/onehost_helper.rb +196 -0
- data/lib/one_helper/oneimage_helper.rb +327 -0
- data/lib/one_helper/onequota_helper.rb +256 -0
- data/lib/one_helper/onetemplate_helper.rb +123 -0
- data/lib/one_helper/oneuser_helper.rb +242 -0
- data/lib/one_helper/onevm_helper.rb +266 -0
- data/lib/one_helper/onevnet_helper.rb +156 -0
- data/lib/one_helper.rb +609 -0
- metadata +93 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
# -------------------------------------------------------------------------- #
|
2
|
+
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
|
3
|
+
# #
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
5
|
+
# not use this file except in compliance with the License. You may obtain #
|
6
|
+
# a copy of the License at #
|
7
|
+
# #
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0 #
|
9
|
+
# #
|
10
|
+
# Unless required by applicable law or agreed to in writing, software #
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, #
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
13
|
+
# See the License for the specific language governing permissions and #
|
14
|
+
# limitations under the License. #
|
15
|
+
#--------------------------------------------------------------------------- #
|
16
|
+
|
17
|
+
require 'one_helper'
|
18
|
+
|
19
|
+
class OneVMHelper < OpenNebulaHelper::OneHelper
|
20
|
+
MULTIPLE={
|
21
|
+
:name => "multiple",
|
22
|
+
:short => "-m x",
|
23
|
+
:large => "--multiple x",
|
24
|
+
:format => Integer,
|
25
|
+
:description => "Instance multiple VMs"
|
26
|
+
}
|
27
|
+
|
28
|
+
IMAGE = {
|
29
|
+
:name => "image",
|
30
|
+
:short => "-i id|name",
|
31
|
+
:large => "--image id|name" ,
|
32
|
+
:description => "Selects the image",
|
33
|
+
:format => String,
|
34
|
+
:proc => lambda { |o, options|
|
35
|
+
OpenNebulaHelper.rname_to_id(o, "IMAGE")
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
FILE = {
|
40
|
+
:name => "file",
|
41
|
+
:short => "-f file",
|
42
|
+
:large => "--file file" ,
|
43
|
+
:description => "Selects the template file",
|
44
|
+
:format => String,
|
45
|
+
:proc => lambda { |o, options|
|
46
|
+
if File.file?(o)
|
47
|
+
options[:file] = o
|
48
|
+
else
|
49
|
+
exit -1
|
50
|
+
end
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
def self.rname
|
55
|
+
"VM"
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.conf_file
|
59
|
+
"onevm.yaml"
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.state_to_str(id, lcm_id)
|
63
|
+
id = id.to_i
|
64
|
+
state_str = VirtualMachine::VM_STATE[id]
|
65
|
+
short_state_str = VirtualMachine::SHORT_VM_STATES[state_str]
|
66
|
+
|
67
|
+
if short_state_str=="actv"
|
68
|
+
lcm_id = lcm_id.to_i
|
69
|
+
lcm_state_str = VirtualMachine::LCM_STATE[lcm_id]
|
70
|
+
return VirtualMachine::SHORT_LCM_STATES[lcm_state_str]
|
71
|
+
end
|
72
|
+
|
73
|
+
return short_state_str
|
74
|
+
end
|
75
|
+
|
76
|
+
def format_pool(options)
|
77
|
+
config_file = self.class.table_conf
|
78
|
+
|
79
|
+
table = CLIHelper::ShowTable.new(config_file, self) do
|
80
|
+
column :ID, "ONE identifier for Virtual Machine", :size=>6 do |d|
|
81
|
+
d["ID"]
|
82
|
+
end
|
83
|
+
|
84
|
+
column :NAME, "Name of the Virtual Machine", :left,
|
85
|
+
:size=>15 do |d|
|
86
|
+
if d["RESCHED"] == "1"
|
87
|
+
"*#{d["NAME"]}"
|
88
|
+
else
|
89
|
+
d["NAME"]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
column :USER, "Username of the Virtual Machine owner", :left,
|
94
|
+
:size=>8 do |d|
|
95
|
+
helper.user_name(d, options)
|
96
|
+
end
|
97
|
+
|
98
|
+
column :GROUP, "Group of the Virtual Machine", :left,
|
99
|
+
:size=>8 do |d|
|
100
|
+
helper.group_name(d, options)
|
101
|
+
end
|
102
|
+
|
103
|
+
column :STAT, "Actual status", :size=>4 do |d,e|
|
104
|
+
OneVMHelper.state_to_str(d["STATE"], d["LCM_STATE"])
|
105
|
+
end
|
106
|
+
|
107
|
+
column :UCPU, "CPU percentage used by the VM", :size=>4 do |d|
|
108
|
+
d["CPU"]
|
109
|
+
end
|
110
|
+
|
111
|
+
column :UMEM, "Memory used by the VM", :size=>7 do |d|
|
112
|
+
OpenNebulaHelper.unit_to_str(d["MEMORY"].to_i, options)
|
113
|
+
end
|
114
|
+
|
115
|
+
column :HOST, "Host where the VM is running", :left, :size=>10 do |d|
|
116
|
+
if d['HISTORY_RECORDS'] && d['HISTORY_RECORDS']['HISTORY']
|
117
|
+
state_str = VirtualMachine::VM_STATE[d['STATE'].to_i]
|
118
|
+
if %w{ACTIVE SUSPENDED}.include? state_str
|
119
|
+
d['HISTORY_RECORDS']['HISTORY']['HOSTNAME']
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
column :TIME, "Time since the VM was submitted", :size=>10 do |d|
|
125
|
+
stime = d["STIME"].to_i
|
126
|
+
etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i
|
127
|
+
dtime = etime-stime
|
128
|
+
OpenNebulaHelper.period_to_str(dtime, false)
|
129
|
+
end
|
130
|
+
|
131
|
+
default :ID, :USER, :GROUP, :NAME, :STAT, :UCPU, :UMEM, :HOST,
|
132
|
+
:TIME
|
133
|
+
end
|
134
|
+
|
135
|
+
table
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def factory(id=nil)
|
141
|
+
if id
|
142
|
+
OpenNebula::VirtualMachine.new_with_id(id, @client)
|
143
|
+
else
|
144
|
+
xml=OpenNebula::VirtualMachine.build_xml
|
145
|
+
OpenNebula::VirtualMachine.new(xml, @client)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def factory_pool(user_flag=-2)
|
150
|
+
OpenNebula::VirtualMachinePool.new(@client, user_flag)
|
151
|
+
end
|
152
|
+
|
153
|
+
def format_resource(vm)
|
154
|
+
str_h1="%-80s"
|
155
|
+
str="%-20s: %-20s"
|
156
|
+
|
157
|
+
CLIHelper.print_header(
|
158
|
+
str_h1 % "VIRTUAL MACHINE #{vm['ID']} INFORMATION")
|
159
|
+
puts str % ["ID", vm.id.to_s]
|
160
|
+
puts str % ["NAME", vm.name]
|
161
|
+
puts str % ["USER", vm['UNAME']]
|
162
|
+
puts str % ["GROUP", vm['GNAME']]
|
163
|
+
puts str % ["STATE", vm.state_str]
|
164
|
+
puts str % ["LCM_STATE", vm.lcm_state_str]
|
165
|
+
puts str % ["RESCHED", OpenNebulaHelper.boolean_to_str(vm['RESCHED'])]
|
166
|
+
puts str % ["HOST",
|
167
|
+
vm['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']] if
|
168
|
+
%w{ACTIVE SUSPENDED}.include? vm.state_str
|
169
|
+
puts str % ["START TIME",
|
170
|
+
OpenNebulaHelper.time_to_str(vm['/VM/STIME'])]
|
171
|
+
puts str % ["END TIME",
|
172
|
+
OpenNebulaHelper.time_to_str(vm['/VM/ETIME'])]
|
173
|
+
value=vm['DEPLOY_ID']
|
174
|
+
puts str % ["DEPLOY ID", value=="" ? "-" : value]
|
175
|
+
|
176
|
+
puts
|
177
|
+
|
178
|
+
CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE MONITORING",false)
|
179
|
+
poll_attrs = {
|
180
|
+
"USED MEMORY" => "MEMORY",
|
181
|
+
"USED CPU" => "CPU",
|
182
|
+
"NET_TX" => "NET_TX",
|
183
|
+
"NET_RX" => "NET_RX"
|
184
|
+
}
|
185
|
+
|
186
|
+
poll_attrs.each { |k,v|
|
187
|
+
if k == "USED CPU"
|
188
|
+
puts str % [k,vm[v]]
|
189
|
+
elsif k == "USED MEMORY"
|
190
|
+
puts str % [k, OpenNebulaHelper.unit_to_str(vm[v].to_i, {})]
|
191
|
+
else
|
192
|
+
puts str % [k, OpenNebulaHelper.unit_to_str(vm[v].to_i/1024, {})]
|
193
|
+
end
|
194
|
+
}
|
195
|
+
puts
|
196
|
+
|
197
|
+
CLIHelper.print_header(str_h1 % "PERMISSIONS",false)
|
198
|
+
|
199
|
+
["OWNER", "GROUP", "OTHER"].each { |e|
|
200
|
+
mask = "---"
|
201
|
+
mask[0] = "u" if vm["PERMISSIONS/#{e}_U"] == "1"
|
202
|
+
mask[1] = "m" if vm["PERMISSIONS/#{e}_M"] == "1"
|
203
|
+
mask[2] = "a" if vm["PERMISSIONS/#{e}_A"] == "1"
|
204
|
+
|
205
|
+
puts str % [e, mask]
|
206
|
+
}
|
207
|
+
puts
|
208
|
+
|
209
|
+
CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE TEMPLATE",false)
|
210
|
+
puts vm.template_str
|
211
|
+
|
212
|
+
if vm.has_elements?("/VM/HISTORY_RECORDS")
|
213
|
+
puts
|
214
|
+
|
215
|
+
|
216
|
+
CLIHelper.print_header(str_h1 % "VIRTUAL MACHINE HISTORY",false)
|
217
|
+
format_history(vm)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def format_history(vm)
|
222
|
+
table=CLIHelper::ShowTable.new(nil, self) do
|
223
|
+
column :SEQ, "Sequence number", :size=>4 do |d|
|
224
|
+
d["SEQ"]
|
225
|
+
end
|
226
|
+
|
227
|
+
column :HOST, "Host name of the VM container", :left, :size=>15 do |d|
|
228
|
+
d["HOSTNAME"]
|
229
|
+
end
|
230
|
+
|
231
|
+
column :REASON, "VM state change reason", :left, :size=>6 do |d|
|
232
|
+
VirtualMachine.get_reason d["REASON"]
|
233
|
+
end
|
234
|
+
|
235
|
+
column :START, "Time when the state changed", :size=>15 do |d|
|
236
|
+
OpenNebulaHelper.time_to_str(d['STIME'])
|
237
|
+
end
|
238
|
+
|
239
|
+
column :TIME, "Total time in this state", :size=>15 do |d|
|
240
|
+
stime = d["STIME"].to_i
|
241
|
+
etime = d["ETIME"]=="0" ? Time.now.to_i : d["ETIME"].to_i
|
242
|
+
dtime = etime-stime
|
243
|
+
OpenNebulaHelper.period_to_str(dtime)
|
244
|
+
end
|
245
|
+
|
246
|
+
column :PROLOG_TIME, "Prolog time for this state", :size=>15 do |d|
|
247
|
+
stime = d["PSTIME"].to_i
|
248
|
+
if d["PSTIME"]=="0"
|
249
|
+
etime=0
|
250
|
+
else
|
251
|
+
etime = d["PETIME"]=="0" ? Time.now.to_i: d["PETIME"].to_i
|
252
|
+
end
|
253
|
+
dtime = etime-stime
|
254
|
+
OpenNebulaHelper.period_to_str(dtime)
|
255
|
+
end
|
256
|
+
|
257
|
+
default :SEQ, :HOST, :REASON, :START, :TIME, :PROLOG_TIME
|
258
|
+
end
|
259
|
+
|
260
|
+
vm_hash=vm.to_hash
|
261
|
+
|
262
|
+
history=[vm_hash['VM']['HISTORY_RECORDS']['HISTORY']].flatten
|
263
|
+
|
264
|
+
table.show(history)
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# -------------------------------------------------------------------------- #
|
2
|
+
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
|
3
|
+
# #
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
5
|
+
# not use this file except in compliance with the License. You may obtain #
|
6
|
+
# a copy of the License at #
|
7
|
+
# #
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0 #
|
9
|
+
# #
|
10
|
+
# Unless required by applicable law or agreed to in writing, software #
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, #
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
13
|
+
# See the License for the specific language governing permissions and #
|
14
|
+
# limitations under the License. #
|
15
|
+
#--------------------------------------------------------------------------- #
|
16
|
+
|
17
|
+
require 'one_helper'
|
18
|
+
|
19
|
+
class OneVNetHelper < OpenNebulaHelper::OneHelper
|
20
|
+
def self.rname
|
21
|
+
"VNET"
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.conf_file
|
25
|
+
"onevnet.yaml"
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.type_to_str(id)
|
29
|
+
id = id.to_i
|
30
|
+
type_str = VirtualNetwork::VN_TYPES[id]
|
31
|
+
return VirtualNetwork::SHORT_VN_TYPES[type_str]
|
32
|
+
end
|
33
|
+
|
34
|
+
def format_pool(options)
|
35
|
+
config_file = self.class.table_conf
|
36
|
+
|
37
|
+
table = CLIHelper::ShowTable.new(config_file, self) do
|
38
|
+
column :ID, "ONE identifier for Virtual Network", :size=>4 do |d|
|
39
|
+
d["ID"]
|
40
|
+
end
|
41
|
+
|
42
|
+
column :USER, "Username of the Virtual Network owner", :left,
|
43
|
+
:size=>12 do |d|
|
44
|
+
helper.user_name(d, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
column :GROUP, "Group of the Virtual Network", :left,
|
48
|
+
:size=>12 do |d|
|
49
|
+
helper.group_name(d, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
column :NAME, "Name of the Virtual Network", :left,
|
53
|
+
:size=>15 do |d|
|
54
|
+
d["NAME"]
|
55
|
+
end
|
56
|
+
|
57
|
+
column :CLUSTER, "Name of the Cluster", :left, :size=>10 do |d|
|
58
|
+
OpenNebulaHelper.cluster_str(d["CLUSTER"])
|
59
|
+
end
|
60
|
+
|
61
|
+
column :TYPE, "Type of Virtual Network", :size=>6 do |d|
|
62
|
+
OneVNetHelper.type_to_str(d["TYPE"])
|
63
|
+
end
|
64
|
+
|
65
|
+
column :SIZE, "Size of the Virtual Network", :size=>5 do |d|
|
66
|
+
d["SIZE"]
|
67
|
+
end
|
68
|
+
|
69
|
+
column :BRIDGE, "Bridge associated to the Virtual Network", :left,
|
70
|
+
:size=>8 do |d|
|
71
|
+
d["BRIDGE"]
|
72
|
+
end
|
73
|
+
|
74
|
+
column :LEASES, "Number of this Virtual Network's given leases",
|
75
|
+
:size=>6 do |d|
|
76
|
+
d["TOTAL_LEASES"]
|
77
|
+
end
|
78
|
+
|
79
|
+
default :ID, :USER, :GROUP, :NAME, :CLUSTER, :TYPE, :BRIDGE, :LEASES
|
80
|
+
end
|
81
|
+
|
82
|
+
table
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def factory(id=nil)
|
88
|
+
if id
|
89
|
+
OpenNebula::VirtualNetwork.new_with_id(id, @client)
|
90
|
+
else
|
91
|
+
xml=OpenNebula::VirtualNetwork.build_xml
|
92
|
+
OpenNebula::VirtualNetwork.new(xml, @client)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def factory_pool(user_flag=-2)
|
97
|
+
OpenNebula::VirtualNetworkPool.new(@client, user_flag)
|
98
|
+
end
|
99
|
+
|
100
|
+
def format_resource(vn)
|
101
|
+
str_h1="%-80s"
|
102
|
+
CLIHelper.print_header(str_h1 %
|
103
|
+
["VIRTUAL NETWORK #{vn.id.to_s} INFORMATION"])
|
104
|
+
|
105
|
+
str="%-15s: %-20s"
|
106
|
+
puts str % ["ID", vn.id.to_s]
|
107
|
+
puts str % ["NAME", vn['NAME']]
|
108
|
+
puts str % ["USER", vn['UNAME']]
|
109
|
+
puts str % ["GROUP", vn['GNAME']]
|
110
|
+
puts str % ["CLUSTER", OpenNebulaHelper.cluster_str(vn['CLUSTER'])]
|
111
|
+
puts str % ["TYPE", vn.type_str]
|
112
|
+
puts str % ["BRIDGE", vn["BRIDGE"]]
|
113
|
+
puts str % ["VLAN", OpenNebulaHelper.boolean_to_str(vn['VLAN'])]
|
114
|
+
puts str % ["PHYSICAL DEVICE", vn["PHYDEV"]] if vn["PHYDEV"]
|
115
|
+
puts str % ["VLAN ID", vn["VLAN_ID"]] if vn["VLAN_ID"]
|
116
|
+
puts str % ["USED LEASES", vn['TOTAL_LEASES']]
|
117
|
+
puts
|
118
|
+
|
119
|
+
CLIHelper.print_header(str_h1 % "PERMISSIONS",false)
|
120
|
+
|
121
|
+
["OWNER", "GROUP", "OTHER"].each { |e|
|
122
|
+
mask = "---"
|
123
|
+
mask[0] = "u" if vn["PERMISSIONS/#{e}_U"] == "1"
|
124
|
+
mask[1] = "m" if vn["PERMISSIONS/#{e}_M"] == "1"
|
125
|
+
mask[2] = "a" if vn["PERMISSIONS/#{e}_A"] == "1"
|
126
|
+
|
127
|
+
puts str % [e, mask]
|
128
|
+
}
|
129
|
+
puts
|
130
|
+
|
131
|
+
CLIHelper.print_header(str_h1 % ["VIRTUAL NETWORK TEMPLATE"], false)
|
132
|
+
|
133
|
+
puts vn.template_str(false)
|
134
|
+
|
135
|
+
if vn.type_str == "RANGED"
|
136
|
+
puts
|
137
|
+
CLIHelper.print_header(str_h1 % ["RANGE"], false)
|
138
|
+
puts str % ["IP_START", vn['RANGE/IP_START']]
|
139
|
+
puts str % ["IP_END", vn['RANGE/IP_END']]
|
140
|
+
end
|
141
|
+
|
142
|
+
lease_types = [ ["LEASES ON HOLD", 'LEASE[USED=1 and VID=-1]'],
|
143
|
+
["USED LEASES", 'LEASE[USED=1 and VID>-1]'],
|
144
|
+
["FREE LEASES", 'LEASE[USED=0]'] ]
|
145
|
+
|
146
|
+
lease_types.each { |pair|
|
147
|
+
leases_str = vn.template_like_str('/VNET/LEASES', false, pair[1])
|
148
|
+
|
149
|
+
if !leases_str.empty?
|
150
|
+
puts
|
151
|
+
CLIHelper.print_header(str_h1 % [pair[0]], false)
|
152
|
+
puts leases_str
|
153
|
+
end
|
154
|
+
}
|
155
|
+
end
|
156
|
+
end
|
data/lib/one_helper.rb
ADDED
@@ -0,0 +1,609 @@
|
|
1
|
+
# -------------------------------------------------------------------------- #
|
2
|
+
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
|
3
|
+
# #
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
5
|
+
# not use this file except in compliance with the License. You may obtain #
|
6
|
+
# a copy of the License at #
|
7
|
+
# #
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0 #
|
9
|
+
# #
|
10
|
+
# Unless required by applicable law or agreed to in writing, software #
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, #
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
13
|
+
# See the License for the specific language governing permissions and #
|
14
|
+
# limitations under the License. #
|
15
|
+
#--------------------------------------------------------------------------- #
|
16
|
+
|
17
|
+
require 'cli_helper'
|
18
|
+
|
19
|
+
require 'OpenNebula'
|
20
|
+
include OpenNebula
|
21
|
+
|
22
|
+
module OpenNebulaHelper
|
23
|
+
ONE_VERSION=<<-EOT
|
24
|
+
OpenNebula #{OpenNebula::VERSION}
|
25
|
+
Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org)
|
26
|
+
|
27
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
28
|
+
not use this file except in compliance with the License. You may obtain
|
29
|
+
a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
30
|
+
EOT
|
31
|
+
|
32
|
+
if ONE_LOCATION
|
33
|
+
TABLE_CONF_PATH=ONE_LOCATION+"/etc/cli"
|
34
|
+
else
|
35
|
+
TABLE_CONF_PATH="/etc/one/cli"
|
36
|
+
end
|
37
|
+
|
38
|
+
EDITOR_PATH='/usr/bin/vi'
|
39
|
+
|
40
|
+
########################################################################
|
41
|
+
# Options
|
42
|
+
########################################################################
|
43
|
+
XML={
|
44
|
+
:name => "xml",
|
45
|
+
:short => "-x",
|
46
|
+
:large => "--xml",
|
47
|
+
:description => "Show the resource in xml format"
|
48
|
+
}
|
49
|
+
|
50
|
+
NUMERIC={
|
51
|
+
:name => "numeric",
|
52
|
+
:short => "-n",
|
53
|
+
:large => "--numeric",
|
54
|
+
:description => "Do not translate user and group IDs"
|
55
|
+
}
|
56
|
+
|
57
|
+
KILOBYTES={
|
58
|
+
:name => "kilobytes",
|
59
|
+
:short => "-k",
|
60
|
+
:large => "--kilobytes",
|
61
|
+
:description => "Show units in kilobytes"
|
62
|
+
}
|
63
|
+
|
64
|
+
DESCRIBE={
|
65
|
+
:name => "describe",
|
66
|
+
:large => "--describe",
|
67
|
+
:description => "Describe list columns"
|
68
|
+
}
|
69
|
+
|
70
|
+
# Command line VM template options
|
71
|
+
TEMPLATE_NAME_VM={
|
72
|
+
:name => 'name',
|
73
|
+
:large => '--name name',
|
74
|
+
:description =>
|
75
|
+
'Name for the new VM',
|
76
|
+
:format => String
|
77
|
+
}
|
78
|
+
|
79
|
+
TEMPLATE_OPTIONS=[
|
80
|
+
{
|
81
|
+
:name => 'cpu',
|
82
|
+
:large => '--cpu cpu',
|
83
|
+
:description =>
|
84
|
+
'CPU percentage reserved for the VM (1=100% one CPU)',
|
85
|
+
:format => Float
|
86
|
+
},
|
87
|
+
{
|
88
|
+
:name => 'arch',
|
89
|
+
:large => '--arch arch',
|
90
|
+
:description =>
|
91
|
+
'Architecture of the VM, e.g.: i386 or x86_64',
|
92
|
+
:format => String
|
93
|
+
},
|
94
|
+
{
|
95
|
+
:name => 'memory',
|
96
|
+
:large => '--memory memory',
|
97
|
+
:description => 'Memory ammount given to the VM',
|
98
|
+
:format => String,
|
99
|
+
:proc => lambda do |o,options|
|
100
|
+
m=o.strip.match(/^(\d+(?:\.\d+)?)(m|mb|g|gb)?$/i)
|
101
|
+
|
102
|
+
if !m
|
103
|
+
[-1, 'Memory value malformed']
|
104
|
+
else
|
105
|
+
multiplier=case m[2]
|
106
|
+
when /(g|gb)/i
|
107
|
+
1024
|
108
|
+
else
|
109
|
+
1
|
110
|
+
end
|
111
|
+
|
112
|
+
value=m[1].to_f*multiplier
|
113
|
+
|
114
|
+
[0, value.floor]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
},
|
118
|
+
{
|
119
|
+
:name => 'disk',
|
120
|
+
:large => '--disk disk0,disk1',
|
121
|
+
:description => 'Disks to attach. To use a disk owned by other user use user[disk]',
|
122
|
+
:format => Array
|
123
|
+
},
|
124
|
+
{
|
125
|
+
:name => 'network',
|
126
|
+
:large => '--network network0,network1',
|
127
|
+
:description => 'Networks to attach. To use a network owned by other user use user[network]',
|
128
|
+
:format => Array
|
129
|
+
},
|
130
|
+
{
|
131
|
+
:name => 'raw',
|
132
|
+
:large => '--raw string',
|
133
|
+
:description => 'Raw string to add to the template. Not to be confused with the RAW attribute',
|
134
|
+
:format => String
|
135
|
+
}
|
136
|
+
]
|
137
|
+
|
138
|
+
TEMPLATE_OPTIONS_VM=[TEMPLATE_NAME_VM]+TEMPLATE_OPTIONS
|
139
|
+
|
140
|
+
OPTIONS = XML, NUMERIC, KILOBYTES
|
141
|
+
|
142
|
+
class OneHelper
|
143
|
+
def initialize(secret=nil, endpoint=nil)
|
144
|
+
begin
|
145
|
+
@client = OpenNebula::Client.new(secret,endpoint)
|
146
|
+
rescue Exception => e
|
147
|
+
puts e.message
|
148
|
+
exit -1
|
149
|
+
end
|
150
|
+
|
151
|
+
@translation_hash = nil
|
152
|
+
end
|
153
|
+
|
154
|
+
def create_resource(options, &block)
|
155
|
+
resource = factory
|
156
|
+
|
157
|
+
rc = block.call(resource)
|
158
|
+
if OpenNebula.is_error?(rc)
|
159
|
+
return -1, rc.message
|
160
|
+
else
|
161
|
+
puts "ID: #{resource.id.to_s}"
|
162
|
+
return 0
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def list_pool(options, top=false, filter_flag=nil)
|
167
|
+
if options[:describe]
|
168
|
+
table = format_pool(options)
|
169
|
+
|
170
|
+
table.describe_columns
|
171
|
+
return 0
|
172
|
+
end
|
173
|
+
|
174
|
+
filter_flag ||= OpenNebula::Pool::INFO_ALL
|
175
|
+
|
176
|
+
pool = factory_pool(filter_flag)
|
177
|
+
|
178
|
+
rc = pool.info
|
179
|
+
return -1, rc.message if OpenNebula.is_error?(rc)
|
180
|
+
|
181
|
+
if options[:xml]
|
182
|
+
return 0, pool.to_xml(true)
|
183
|
+
else
|
184
|
+
table = format_pool(options)
|
185
|
+
|
186
|
+
if top
|
187
|
+
table.top(options) {
|
188
|
+
pool.info
|
189
|
+
pool_to_array(pool)
|
190
|
+
}
|
191
|
+
else
|
192
|
+
table.show(pool_to_array(pool), options)
|
193
|
+
end
|
194
|
+
|
195
|
+
return 0
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def show_resource(id, options)
|
200
|
+
resource = retrieve_resource(id)
|
201
|
+
|
202
|
+
rc = resource.info
|
203
|
+
return -1, rc.message if OpenNebula.is_error?(rc)
|
204
|
+
|
205
|
+
if options[:xml]
|
206
|
+
return 0, resource.to_xml(true)
|
207
|
+
else
|
208
|
+
format_resource(resource)
|
209
|
+
return 0
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def perform_action(id, options, verbose, &block)
|
214
|
+
resource = retrieve_resource(id)
|
215
|
+
|
216
|
+
rc = block.call(resource)
|
217
|
+
if OpenNebula.is_error?(rc)
|
218
|
+
return -1, rc.message
|
219
|
+
else
|
220
|
+
if options[:verbose]
|
221
|
+
puts "#{self.class.rname} #{id}: #{verbose}"
|
222
|
+
end
|
223
|
+
return 0
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def perform_actions(ids,options,verbose,&block)
|
228
|
+
exit_code = 0
|
229
|
+
ids.each do |id|
|
230
|
+
rc = perform_action(id,options,verbose,&block)
|
231
|
+
|
232
|
+
unless rc[0]==0
|
233
|
+
puts rc[1]
|
234
|
+
exit_code=rc[0]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
exit_code
|
239
|
+
end
|
240
|
+
|
241
|
+
########################################################################
|
242
|
+
# Id translation
|
243
|
+
########################################################################
|
244
|
+
def user_name(resource, options={})
|
245
|
+
if options[:numeric]
|
246
|
+
resource['UID']
|
247
|
+
else
|
248
|
+
resource['UNAME']
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def group_name(resource, options={})
|
253
|
+
if options[:numeric]
|
254
|
+
resource['GID']
|
255
|
+
else
|
256
|
+
resource['GNAME']
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
########################################################################
|
261
|
+
# Formatters for arguments
|
262
|
+
########################################################################
|
263
|
+
def to_id(name)
|
264
|
+
return 0, name.to_i if name.match(/^[0123456789]+$/)
|
265
|
+
|
266
|
+
rc = get_pool
|
267
|
+
return rc if rc.first != 0
|
268
|
+
|
269
|
+
pool = rc[1]
|
270
|
+
poolname = self.class.rname
|
271
|
+
|
272
|
+
OneHelper.name_to_id(name, pool, poolname)
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.to_id_desc
|
276
|
+
"OpenNebula #{self.rname} name or id"
|
277
|
+
end
|
278
|
+
|
279
|
+
def list_to_id(names)
|
280
|
+
rc = get_pool
|
281
|
+
return rc if rc.first != 0
|
282
|
+
|
283
|
+
pool = rc[1]
|
284
|
+
poolname = self.class.rname
|
285
|
+
|
286
|
+
result = names.split(',').collect { |name|
|
287
|
+
if name.match(/^[0123456789]+$/)
|
288
|
+
name.to_i
|
289
|
+
else
|
290
|
+
rc = OneHelper.name_to_id(name, pool, poolname)
|
291
|
+
|
292
|
+
if rc.first == -1
|
293
|
+
return rc[0], rc[1]
|
294
|
+
end
|
295
|
+
|
296
|
+
rc[1]
|
297
|
+
end
|
298
|
+
}
|
299
|
+
|
300
|
+
return 0, result
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.list_to_id_desc
|
304
|
+
"Comma-separated list of OpenNebula #{self.rname} names or ids"
|
305
|
+
end
|
306
|
+
|
307
|
+
def self.name_to_id(name, pool, ename)
|
308
|
+
objects=pool.select {|object| object.name==name }
|
309
|
+
|
310
|
+
if objects.length>0
|
311
|
+
if objects.length>1
|
312
|
+
return -1, "There are multiple #{ename}s with name #{name}."
|
313
|
+
else
|
314
|
+
result = objects.first.id
|
315
|
+
end
|
316
|
+
else
|
317
|
+
return -1, "#{ename} named #{name} not found."
|
318
|
+
end
|
319
|
+
|
320
|
+
return 0, result
|
321
|
+
end
|
322
|
+
|
323
|
+
def filterflag_to_i(str)
|
324
|
+
filter_flag = case str
|
325
|
+
when "a", "all" then OpenNebula::Pool::INFO_ALL
|
326
|
+
when "m", "mine" then OpenNebula::Pool::INFO_MINE
|
327
|
+
when "g", "group" then OpenNebula::Pool::INFO_GROUP
|
328
|
+
else
|
329
|
+
if str.match(/^[0123456789]+$/)
|
330
|
+
str.to_i
|
331
|
+
else
|
332
|
+
rc = OpenNebulaHelper.rname_to_id(str, "USER")
|
333
|
+
if rc.first==-1
|
334
|
+
return rc
|
335
|
+
else
|
336
|
+
rc[1]
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
return 0, filter_flag
|
342
|
+
end
|
343
|
+
|
344
|
+
def self.filterflag_to_i_desc
|
345
|
+
desc=<<-EOT
|
346
|
+
a, all all the known #{self.rname}s
|
347
|
+
m, mine the #{self.rname} belonging to the user in ONE_AUTH
|
348
|
+
g, group 'mine' plus the #{self.rname} belonging to the groups
|
349
|
+
the user is member of
|
350
|
+
uid #{self.rname} of the user identified by this uid
|
351
|
+
user #{self.rname} of the user identified by the username
|
352
|
+
EOT
|
353
|
+
end
|
354
|
+
|
355
|
+
def self.table_conf
|
356
|
+
path = "#{ENV["HOME"]}/.one/cli/#{self.conf_file}"
|
357
|
+
|
358
|
+
if File.exists?(path)
|
359
|
+
return path
|
360
|
+
else
|
361
|
+
return "#{TABLE_CONF_PATH}/#{self.conf_file}"
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
private
|
366
|
+
|
367
|
+
def retrieve_resource(id)
|
368
|
+
factory(id)
|
369
|
+
end
|
370
|
+
|
371
|
+
def pool_to_array(pool)
|
372
|
+
if !pool.instance_of?(Hash)
|
373
|
+
phash = pool.to_hash
|
374
|
+
else
|
375
|
+
phash = pool
|
376
|
+
end
|
377
|
+
|
378
|
+
rname = self.class.rname
|
379
|
+
|
380
|
+
if phash["#{rname}_POOL"] &&
|
381
|
+
phash["#{rname}_POOL"]["#{rname}"]
|
382
|
+
if phash["#{rname}_POOL"]["#{rname}"].instance_of?(Array)
|
383
|
+
phash = phash["#{rname}_POOL"]["#{rname}"]
|
384
|
+
else
|
385
|
+
phash = [phash["#{rname}_POOL"]["#{rname}"]]
|
386
|
+
end
|
387
|
+
else
|
388
|
+
phash = Array.new
|
389
|
+
end
|
390
|
+
|
391
|
+
phash
|
392
|
+
end
|
393
|
+
|
394
|
+
def get_pool
|
395
|
+
user_flag = OpenNebula::Pool::INFO_ALL
|
396
|
+
pool = factory_pool(user_flag)
|
397
|
+
|
398
|
+
rc = pool.info
|
399
|
+
if OpenNebula.is_error?(rc)
|
400
|
+
return -1, "OpenNebula #{self.class.rname} name not " <<
|
401
|
+
"found, use the ID instead"
|
402
|
+
end
|
403
|
+
|
404
|
+
return 0, pool
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def OpenNebulaHelper.rname_to_id(name, poolname)
|
409
|
+
return 0, name.to_i if name.match(/^[0123456789]+$/)
|
410
|
+
|
411
|
+
client = OpenNebula::Client.new
|
412
|
+
|
413
|
+
pool = case poolname
|
414
|
+
when "HOST" then OpenNebula::HostPool.new(client)
|
415
|
+
when "GROUP" then OpenNebula::GroupPool.new(client)
|
416
|
+
when "USER" then OpenNebula::UserPool.new(client)
|
417
|
+
when "DATASTORE" then OpenNebula::DatastorePool.new(client)
|
418
|
+
when "CLUSTER" then OpenNebula::ClusterPool.new(client)
|
419
|
+
when "VNET" then OpenNebula::VirtualNetworkPool.new(client)
|
420
|
+
when "IMAGE" then OpenNebula::ImagePool.new(client)
|
421
|
+
when "VMTEMPLATE" then OpenNebula::TemplatePool.new(client)
|
422
|
+
when "VM" then OpenNebula::VirtualMachinePool.new(client)
|
423
|
+
end
|
424
|
+
|
425
|
+
rc = pool.info
|
426
|
+
if OpenNebula.is_error?(rc)
|
427
|
+
return -1, "OpenNebula #{poolname} name not found," <<
|
428
|
+
" use the ID instead"
|
429
|
+
end
|
430
|
+
|
431
|
+
OneHelper.name_to_id(name, pool, poolname)
|
432
|
+
end
|
433
|
+
|
434
|
+
def OpenNebulaHelper.rname_to_id_desc(poolname)
|
435
|
+
"OpenNebula #{poolname} name or id"
|
436
|
+
end
|
437
|
+
|
438
|
+
def OpenNebulaHelper.boolean_to_str(str)
|
439
|
+
if str.to_i == 1
|
440
|
+
"Yes"
|
441
|
+
else
|
442
|
+
"No"
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
def OpenNebulaHelper.time_to_str(time)
|
447
|
+
value=time.to_i
|
448
|
+
if value==0
|
449
|
+
value='-'
|
450
|
+
else
|
451
|
+
value=Time.at(value).strftime("%m/%d %H:%M:%S")
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
def OpenNebulaHelper.period_to_str(time, print_seconds=true)
|
456
|
+
seconds=time.to_i
|
457
|
+
minutes, seconds=seconds.divmod(60)
|
458
|
+
hours, minutes=minutes.divmod(60)
|
459
|
+
days, hours=hours.divmod(24)
|
460
|
+
|
461
|
+
if print_seconds
|
462
|
+
"%3dd %02dh%02dm%02ds" % [days, hours, minutes, seconds]
|
463
|
+
else
|
464
|
+
"%3dd %02dh%02dm" % [days, hours, minutes]
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
BinarySufix = ["K", "M", "G", "T" ]
|
469
|
+
|
470
|
+
def OpenNebulaHelper.unit_to_str(value, options, unit="K")
|
471
|
+
if options[:kilobytes]
|
472
|
+
value
|
473
|
+
else
|
474
|
+
i=BinarySufix.index(unit).to_i
|
475
|
+
|
476
|
+
while value > 1024 && i < 3 do
|
477
|
+
value /= 1024.0
|
478
|
+
i+=1
|
479
|
+
end
|
480
|
+
|
481
|
+
value = (value * 10).round / 10.0
|
482
|
+
|
483
|
+
value = value.to_i if value - value.round == 0
|
484
|
+
st = value.to_s + BinarySufix[i]
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
# If the cluster name is empty, returns a '-' char.
|
489
|
+
#
|
490
|
+
# @param str [String || Hash] Cluster name, or empty Hash (when <CLUSTER/>)
|
491
|
+
# @return [String] the same Cluster name, or '-' if it is empty
|
492
|
+
def OpenNebulaHelper.cluster_str(str)
|
493
|
+
if str != nil && !str.empty?
|
494
|
+
str
|
495
|
+
else
|
496
|
+
"-"
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
def OpenNebulaHelper.update_template(id, resource, path=nil)
|
501
|
+
unless path
|
502
|
+
require 'tempfile'
|
503
|
+
|
504
|
+
tmp = Tempfile.new(id.to_s)
|
505
|
+
path = tmp.path
|
506
|
+
|
507
|
+
rc = resource.info
|
508
|
+
|
509
|
+
if OpenNebula.is_error?(rc)
|
510
|
+
puts rc.message
|
511
|
+
exit -1
|
512
|
+
end
|
513
|
+
|
514
|
+
tmp << resource.template_str
|
515
|
+
tmp.flush
|
516
|
+
|
517
|
+
editor_path = ENV["EDITOR"] ? ENV["EDITOR"] : EDITOR_PATH
|
518
|
+
system("#{editor_path} #{path}")
|
519
|
+
|
520
|
+
unless $?.exitstatus == 0
|
521
|
+
puts "Editor not defined"
|
522
|
+
exit -1
|
523
|
+
end
|
524
|
+
|
525
|
+
tmp.close
|
526
|
+
end
|
527
|
+
|
528
|
+
str = File.read(path)
|
529
|
+
str
|
530
|
+
end
|
531
|
+
|
532
|
+
def self.parse_user_object(user_object)
|
533
|
+
reg=/^([^\[]+)(?:\[([^\]]+)\])?$/
|
534
|
+
|
535
|
+
m=user_object.match(reg)
|
536
|
+
|
537
|
+
return nil if !m
|
538
|
+
|
539
|
+
user=nil
|
540
|
+
if m[2]
|
541
|
+
user=m[1]
|
542
|
+
object=m[2]
|
543
|
+
else
|
544
|
+
object=m[1]
|
545
|
+
end
|
546
|
+
|
547
|
+
[user, object]
|
548
|
+
end
|
549
|
+
|
550
|
+
def self.create_disk_net(objects, section, name)
|
551
|
+
template=''
|
552
|
+
|
553
|
+
objects.each do |obj|
|
554
|
+
res=parse_user_object(obj)
|
555
|
+
return [-1, "#{section.capitalize} \"#{obj}\" malformed"] if !res
|
556
|
+
user, object=*res
|
557
|
+
|
558
|
+
template<<"#{section.upcase}=[\n"
|
559
|
+
template<<" #{name.upcase}_UNAME=\"#{user}\",\n" if user
|
560
|
+
if object.match(/^\d$/)
|
561
|
+
template<<" #{name.upcase}_ID=#{object}\n"
|
562
|
+
else
|
563
|
+
template<<" #{name.upcase}=\"#{object}\"\n"
|
564
|
+
end
|
565
|
+
template<<"]\n"
|
566
|
+
end if objects
|
567
|
+
|
568
|
+
[0, template]
|
569
|
+
end
|
570
|
+
|
571
|
+
def self.create_template(options)
|
572
|
+
template=''
|
573
|
+
|
574
|
+
template<<"NAME=\"#{options[:name]}\"\n" if options[:name]
|
575
|
+
template<<"OS = [ ARCH = \"#{options[:arch]}\" ]\n" if options[:arch]
|
576
|
+
template<<"CPU=#{options[:cpu]}\n" if options[:cpu]
|
577
|
+
template<<"MEMORY=#{options[:memory]}\n" if options[:memory]
|
578
|
+
template<<"#{options[:raw]}\n" if options[:raw]
|
579
|
+
|
580
|
+
if options[:disk]
|
581
|
+
res=create_disk_net(options[:disk], 'DISK', 'IMAGE')
|
582
|
+
return res if res.first!=0
|
583
|
+
|
584
|
+
template<<res.last
|
585
|
+
end
|
586
|
+
|
587
|
+
if options[:network]
|
588
|
+
res=create_disk_net(options[:network], 'NIC', 'NETWORK')
|
589
|
+
return res if res.first!=0
|
590
|
+
|
591
|
+
template<<res.last
|
592
|
+
end
|
593
|
+
|
594
|
+
|
595
|
+
[0, template]
|
596
|
+
end
|
597
|
+
|
598
|
+
def self.create_template_options_used?(options)
|
599
|
+
# Get the template options names as symbols. options hash
|
600
|
+
# uses symbols
|
601
|
+
template_options=OpenNebulaHelper::TEMPLATE_OPTIONS.map do |o|
|
602
|
+
o[:name].to_sym
|
603
|
+
end
|
604
|
+
|
605
|
+
# Check if one at least one of the template options is
|
606
|
+
# in options hash
|
607
|
+
(template_options-options.keys)!=template_options
|
608
|
+
end
|
609
|
+
end
|