opennebula-cli 7.1.80.pre → 7.2.1
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/oneacct +1 -1
- data/bin/oneacl +1 -1
- data/bin/onebackupjob +1 -1
- data/bin/onecluster +1 -1
- data/bin/onedatastore +1 -1
- data/bin/oneflow +1 -1
- data/bin/oneflow-template +1 -1
- data/bin/oneform +1 -1
- data/bin/onegroup +1 -1
- data/bin/onehook +1 -1
- data/bin/onehost +1 -1
- data/bin/oneimage +1 -1
- data/bin/oneirb +1 -1
- data/bin/onelog +1 -1
- data/bin/onemarket +1 -1
- data/bin/onemarketapp +1 -1
- data/bin/onesecgroup +1 -1
- data/bin/oneshowback +1 -1
- data/bin/onetemplate +1 -1
- data/bin/oneuser +1 -1
- data/bin/onevdc +1 -1
- data/bin/onevm +2 -2
- 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/cli_helper.rb +1 -1
- data/lib/command_parser.rb +135 -126
- data/lib/load_opennebula_paths.rb +5 -0
- data/lib/ods_helper.rb +541 -0
- data/lib/one_helper/oneacct_helper.rb +117 -109
- data/lib/one_helper/oneacl_helper.rb +1 -1
- data/lib/one_helper/onebackupjob_helper.rb +1 -1
- data/lib/one_helper/onecluster_helper.rb +1 -1
- data/lib/one_helper/onedatastore_helper.rb +87 -80
- data/lib/one_helper/oneflow_helper.rb +1 -1
- data/lib/one_helper/oneflowtemplate_helper.rb +1 -1
- data/lib/one_helper/oneform_helper.rb +1 -1
- data/lib/one_helper/onegroup_helper.rb +1 -1
- data/lib/one_helper/onehook_helper.rb +1 -1
- data/lib/one_helper/onehost_helper.rb +1 -1
- data/lib/one_helper/oneimage_helper.rb +1 -1
- data/lib/one_helper/onemarket_helper.rb +59 -58
- data/lib/one_helper/onemarketapp_helper.rb +1 -1
- data/lib/one_helper/onequota_helper.rb +240 -190
- data/lib/one_helper/onesecgroup_helper.rb +87 -85
- data/lib/one_helper/onetemplate_helper.rb +64 -64
- data/lib/one_helper/oneuser_helper.rb +2 -2
- data/lib/one_helper/onevdc_helper.rb +45 -45
- data/lib/one_helper/onevm_helper.rb +6 -8
- data/lib/one_helper/onevmgroup_helper.rb +65 -63
- data/lib/one_helper/onevnet_helper.rb +1 -1
- data/lib/one_helper/onevntemplate_helper.rb +43 -40
- data/lib/one_helper/onevrouter_helper.rb +86 -87
- data/lib/one_helper/onezone_helper.rb +98 -101
- data/lib/one_helper.rb +90 -71
- data/share/schemas/xsd/acct.xsd +3 -104
- data/share/schemas/xsd/cluster.xsd +4 -21
- data/share/schemas/xsd/datastore.xsd +4 -29
- data/share/schemas/xsd/document.xsd +3 -25
- data/share/schemas/xsd/group.xsd +2 -14
- data/share/schemas/xsd/group_pool.xsd +2 -14
- data/share/schemas/xsd/hook.xsd +2 -0
- data/share/schemas/xsd/host.xsd +5 -7
- data/share/schemas/xsd/image.xsd +2 -25
- data/share/schemas/xsd/marketplace.xsd +3 -22
- data/share/schemas/xsd/marketplaceapp.xsd +3 -25
- data/share/schemas/xsd/opennebula_configuration.xsd +3 -2
- data/share/schemas/xsd/requirements.xsd +3 -21
- data/share/schemas/xsd/security_group.xsd +6 -43
- data/share/schemas/xsd/shared.xsd +3 -3
- data/share/schemas/xsd/vdc.xsd +2 -7
- data/share/schemas/xsd/vm_group.xsd +3 -25
- data/share/schemas/xsd/vm_pool.xsd +2 -0
- data/share/schemas/xsd/vmtemplate.xsd +3 -25
- data/share/schemas/xsd/vnet.xsd +9 -67
- data/share/schemas/xsd/vnet_pool.xsd +8 -57
- data/share/schemas/xsd/vntemplate.xsd +3 -25
- data/share/schemas/xsd/vrouter.xsd +4 -32
- metadata +8 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -------------------------------------------------------------------------- #
|
|
2
|
-
# Copyright 2002-
|
|
2
|
+
# Copyright 2002-2026, OpenNebula Project, OpenNebula Systems #
|
|
3
3
|
# #
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
|
5
5
|
# not use this file except in compliance with the License. You may obtain #
|
|
@@ -19,242 +19,249 @@ require 'optparse/time'
|
|
|
19
19
|
require 'opennebula/virtual_machine'
|
|
20
20
|
require 'opennebula/virtual_machine_pool'
|
|
21
21
|
|
|
22
|
+
# Helper class for accounting commands
|
|
22
23
|
class AcctHelper < OpenNebulaHelper::OneHelper
|
|
24
|
+
|
|
23
25
|
TIME_ZONE_CUR = {
|
|
24
|
-
:name =>
|
|
25
|
-
:short =>
|
|
26
|
-
:large =>
|
|
27
|
-
:description =>
|
|
26
|
+
:name => 'timezone',
|
|
27
|
+
:short => '-t TZ',
|
|
28
|
+
:large => '--timezone TZ',
|
|
29
|
+
:description => 'User defined Time Zone',
|
|
28
30
|
:format => String
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
START_TIME_ACCT = {
|
|
32
|
-
:name =>
|
|
33
|
-
:short =>
|
|
34
|
-
:large =>
|
|
35
|
-
:description =>
|
|
34
|
+
:name => 'start_time',
|
|
35
|
+
:short => '-s TIME',
|
|
36
|
+
:large => '--start TIME',
|
|
37
|
+
:description => 'First day of the data to retrieve',
|
|
36
38
|
:format => Time
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
END_TIME_ACCT = {
|
|
40
|
-
:name =>
|
|
41
|
-
:short =>
|
|
42
|
-
:large =>
|
|
43
|
-
:description =>
|
|
42
|
+
:name => 'end_time',
|
|
43
|
+
:short => '-e TIME',
|
|
44
|
+
:large => '--end TIME',
|
|
45
|
+
:description => 'Last day of the data to retrieve',
|
|
44
46
|
:format => Time
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
START_TIME_SHOWBACK = {
|
|
48
|
-
:name =>
|
|
49
|
-
:short =>
|
|
50
|
-
:large =>
|
|
51
|
-
:description =>
|
|
50
|
+
:name => 'start_time',
|
|
51
|
+
:short => '-s TIME',
|
|
52
|
+
:large => '--start TIME',
|
|
53
|
+
:description => 'First month of the data',
|
|
52
54
|
:format => Time
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
END_TIME_SHOWBACK = {
|
|
56
|
-
:name =>
|
|
57
|
-
:short =>
|
|
58
|
-
:large =>
|
|
59
|
-
:description =>
|
|
58
|
+
:name => 'end_time',
|
|
59
|
+
:short => '-e TIME',
|
|
60
|
+
:large => '--end TIME',
|
|
61
|
+
:description => 'Last month of the data',
|
|
60
62
|
:format => Time
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
USERFILTER = {
|
|
64
|
-
:name =>
|
|
65
|
-
:short =>
|
|
66
|
-
:large =>
|
|
67
|
-
:description =>
|
|
66
|
+
:name => 'userfilter',
|
|
67
|
+
:short => '-u user',
|
|
68
|
+
:large => '--userfilter user',
|
|
69
|
+
:description => 'User name or id to filter the results',
|
|
68
70
|
:format => String,
|
|
69
|
-
:proc => lambda {
|
|
70
|
-
OpenNebulaHelper.rname_to_id(o,
|
|
71
|
+
:proc => lambda {|o, _options|
|
|
72
|
+
OpenNebulaHelper.rname_to_id(o, 'USER')
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
GROUP = {
|
|
75
|
-
:name =>
|
|
76
|
-
:short =>
|
|
77
|
-
:large =>
|
|
78
|
-
:description =>
|
|
77
|
+
:name => 'group',
|
|
78
|
+
:short => '-g group',
|
|
79
|
+
:large => '--group group',
|
|
80
|
+
:description => 'Group name or id to filter the results',
|
|
79
81
|
:format => String,
|
|
80
|
-
:proc => lambda {
|
|
81
|
-
OpenNebulaHelper.rname_to_id(o,
|
|
82
|
+
:proc => lambda {|o, _options|
|
|
83
|
+
OpenNebulaHelper.rname_to_id(o, 'GROUP')
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
HOST = {
|
|
86
|
-
:name =>
|
|
87
|
-
:short =>
|
|
88
|
-
:large =>
|
|
89
|
-
:description =>
|
|
88
|
+
:name => 'host',
|
|
89
|
+
:short => '-H HOST',
|
|
90
|
+
:large => '--host HOST',
|
|
91
|
+
:description => 'Host name or id to filter the results',
|
|
90
92
|
:format => String,
|
|
91
|
-
:proc => lambda {
|
|
92
|
-
OpenNebulaHelper.rname_to_id(o,
|
|
93
|
+
:proc => lambda {|o, _options|
|
|
94
|
+
OpenNebulaHelper.rname_to_id(o, 'HOST')
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
XPATH = {
|
|
97
|
-
:name =>
|
|
98
|
-
:large =>
|
|
99
|
+
:name => 'xpath',
|
|
100
|
+
:large => '--xpath XPATH_EXPRESSION',
|
|
99
101
|
:description => "Xpath expression to filter the results. \
|
|
100
102
|
For example: oneacct --xpath 'HISTORY[ETIME>0]'",
|
|
101
103
|
:format => String
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
SPLIT={
|
|
105
|
-
:name =>
|
|
106
|
-
:large =>
|
|
107
|
-
:description =>
|
|
107
|
+
:name => 'split',
|
|
108
|
+
:large => '--split',
|
|
109
|
+
:description => 'Split the output in a table for each VM'
|
|
108
110
|
}
|
|
109
111
|
|
|
110
|
-
ACCT_OPTIONS = [TIME_ZONE_CUR, START_TIME_ACCT, END_TIME_ACCT, USERFILTER, GROUP, HOST,
|
|
112
|
+
ACCT_OPTIONS = [TIME_ZONE_CUR, START_TIME_ACCT, END_TIME_ACCT, USERFILTER, GROUP, HOST,
|
|
113
|
+
XPATH, SPLIT]
|
|
111
114
|
SHOWBACK_OPTIONS = [START_TIME_SHOWBACK, END_TIME_SHOWBACK, USERFILTER, GROUP, OpenNebulaHelper::FORMAT]
|
|
112
115
|
|
|
113
116
|
ACCT_OPTIONS << OpenNebulaHelper::XML
|
|
114
117
|
ACCT_OPTIONS << OpenNebulaHelper::JSON
|
|
115
118
|
|
|
116
|
-
ACCT_TABLE = CLIHelper::ShowTable.new(
|
|
117
|
-
column :UID,
|
|
118
|
-
d[
|
|
119
|
+
ACCT_TABLE = CLIHelper::ShowTable.new(table_conf('oneacct.yaml'), nil) do
|
|
120
|
+
column :UID, 'User ID', :size=>4 do |d|
|
|
121
|
+
d['UID']
|
|
119
122
|
end
|
|
120
123
|
|
|
121
|
-
column :VID,
|
|
122
|
-
d[
|
|
124
|
+
column :VID, 'Virtual Machine ID', :size=>4 do |d|
|
|
125
|
+
d['OID']
|
|
123
126
|
end
|
|
124
127
|
|
|
125
|
-
column :SEQ,
|
|
126
|
-
d[
|
|
128
|
+
column :SEQ, 'History record sequence number', :size=>3 do |d|
|
|
129
|
+
d['SEQ']
|
|
127
130
|
end
|
|
128
131
|
|
|
129
|
-
column :HOSTNAME,
|
|
130
|
-
d[
|
|
132
|
+
column :HOSTNAME, 'Host name', :left, :size=>15 do |d|
|
|
133
|
+
d['HOSTNAME']
|
|
131
134
|
end
|
|
132
135
|
|
|
133
|
-
column :
|
|
134
|
-
VirtualMachine.get_history_action d[
|
|
136
|
+
column :ACTION, 'VM state change action', :left, :size=>16 do |d|
|
|
137
|
+
VirtualMachine.get_history_action d['ACTION']
|
|
135
138
|
end
|
|
136
139
|
|
|
137
|
-
column :START_TIME,
|
|
140
|
+
column :START_TIME, 'Start time', :size=>14 do |d|
|
|
138
141
|
OpenNebulaHelper.time_to_str(d['STIME'])
|
|
139
142
|
end
|
|
140
143
|
|
|
141
|
-
column :END_TIME,
|
|
144
|
+
column :END_TIME, 'End time', :size=>14 do |d|
|
|
142
145
|
OpenNebulaHelper.time_to_str(d['ETIME'])
|
|
143
146
|
end
|
|
144
147
|
|
|
145
|
-
column :MEMORY,
|
|
146
|
-
OpenNebulaHelper.unit_to_str(d[
|
|
148
|
+
column :MEMORY, 'Assigned memory', :size=>6 do |d|
|
|
149
|
+
OpenNebulaHelper.unit_to_str(d['VM']['TEMPLATE']['MEMORY'].to_i, {}, 'M') rescue '-'
|
|
147
150
|
end
|
|
148
151
|
|
|
149
|
-
column :CPU,
|
|
150
|
-
d[
|
|
152
|
+
column :CPU, 'Number of CPUs', :size=>3 do |d|
|
|
153
|
+
d['VM']['TEMPLATE']['CPU'] rescue '-'
|
|
151
154
|
end
|
|
152
155
|
|
|
153
|
-
column :NETRX,
|
|
156
|
+
column :NETRX, 'Data received from the network', :size=>6 do |d|
|
|
154
157
|
# NET is measured in bytes, unit_to_str expects KBytes
|
|
155
|
-
OpenNebulaHelper.unit_to_str(d[
|
|
158
|
+
OpenNebulaHelper.unit_to_str(d['VM']['MONITORING']['NETRX'].to_i / 1024.0,
|
|
159
|
+
{}) rescue '-'
|
|
156
160
|
end
|
|
157
161
|
|
|
158
|
-
column :NETTX,
|
|
162
|
+
column :NETTX, 'Data sent to the network', :size=>6 do |d|
|
|
159
163
|
# NET is measured in bytes, unit_to_str expects KBytes
|
|
160
|
-
OpenNebulaHelper.unit_to_str(d[
|
|
164
|
+
OpenNebulaHelper.unit_to_str(d['VM']['MONITORING']['NETTX'].to_i / 1024.0,
|
|
165
|
+
{}) rescue '-'
|
|
161
166
|
end
|
|
162
167
|
|
|
163
|
-
column :DISK,
|
|
168
|
+
column :DISK, 'Total disk size used', :size=>6 do |d|
|
|
164
169
|
# DISK size is measured in mb, unit_to_str expects KBytes
|
|
165
170
|
begin
|
|
166
171
|
total_disk_size = 0
|
|
167
172
|
|
|
168
|
-
|
|
173
|
+
d['VM']['ID'].to_i
|
|
169
174
|
|
|
170
|
-
disks_all = [d[
|
|
175
|
+
disks_all = [d['VM']['TEMPLATE']['DISK']].flatten.compact rescue []
|
|
171
176
|
disks_all.each do |disk|
|
|
172
|
-
total_disk_size += disk[
|
|
177
|
+
total_disk_size += disk['SIZE'].to_i
|
|
173
178
|
end
|
|
174
179
|
|
|
175
|
-
snapshots_all = [d[
|
|
180
|
+
snapshots_all = [d['VM']['SNAPSHOTS']].flatten.compact rescue []
|
|
176
181
|
snapshots_all.each do |snapshot|
|
|
177
|
-
snapshot_disk = [snapshot[
|
|
178
|
-
snapshot_disk.each do |
|
|
179
|
-
total_disk_size +=
|
|
182
|
+
snapshot_disk = [snapshot['SNAPSHOT']].flatten.compact rescue []
|
|
183
|
+
snapshot_disk.each do |s|
|
|
184
|
+
total_disk_size += s['SIZE'].to_i
|
|
180
185
|
end
|
|
181
186
|
end
|
|
182
187
|
|
|
183
188
|
OpenNebulaHelper.unit_to_str(total_disk_size * 1024.0, {})
|
|
184
|
-
rescue
|
|
185
|
-
|
|
189
|
+
rescue StandardError
|
|
190
|
+
'-'
|
|
186
191
|
end
|
|
187
192
|
end
|
|
188
193
|
|
|
189
|
-
default :VID, :HOSTNAME, :ACTION, :START_TIME, :END_TIME, :MEMORY, :CPU, :NETRX, :NETTX,
|
|
194
|
+
default :VID, :HOSTNAME, :ACTION, :START_TIME, :END_TIME, :MEMORY, :CPU, :NETRX, :NETTX,
|
|
195
|
+
:DISK
|
|
190
196
|
end
|
|
191
197
|
|
|
192
|
-
SHOWBACK_TABLE = CLIHelper::ShowTable.new(
|
|
193
|
-
column :UID,
|
|
194
|
-
d[
|
|
198
|
+
SHOWBACK_TABLE = CLIHelper::ShowTable.new(table_conf('oneshowback.yaml'), nil) do
|
|
199
|
+
column :UID, 'User ID', :size=>4 do |d|
|
|
200
|
+
d['UID']
|
|
195
201
|
end
|
|
196
202
|
|
|
197
|
-
column :USER_NAME,
|
|
198
|
-
d[
|
|
203
|
+
column :USER_NAME, 'User name', :left, :size=>12 do |d|
|
|
204
|
+
d['UNAME']
|
|
199
205
|
end
|
|
200
206
|
|
|
201
|
-
column :GID,
|
|
202
|
-
d[
|
|
207
|
+
column :GID, 'Group ID', :size=>4 do |d|
|
|
208
|
+
d['GID']
|
|
203
209
|
end
|
|
204
210
|
|
|
205
|
-
column :GROUP_NAME,
|
|
206
|
-
d[
|
|
211
|
+
column :GROUP_NAME, 'Group name', :left, :size=>12 do |d|
|
|
212
|
+
d['GNAME']
|
|
207
213
|
end
|
|
208
214
|
|
|
209
|
-
column :VM_ID,
|
|
210
|
-
d[
|
|
215
|
+
column :VM_ID, 'Virtual Machine ID', :size=>6 do |d|
|
|
216
|
+
d['VMID']
|
|
211
217
|
end
|
|
212
218
|
|
|
213
|
-
column :VM_NAME,
|
|
214
|
-
d[
|
|
219
|
+
column :VM_NAME, 'Virtual Machine name', :left, :size=>12 do |d|
|
|
220
|
+
d['VMNAME']
|
|
215
221
|
end
|
|
216
222
|
|
|
217
|
-
column :MONTH,
|
|
218
|
-
d[
|
|
223
|
+
column :MONTH, 'Month', :size=>5 do |d|
|
|
224
|
+
d['MONTH']
|
|
219
225
|
end
|
|
220
226
|
|
|
221
|
-
column :YEAR,
|
|
222
|
-
d[
|
|
227
|
+
column :YEAR, 'Year', :size=>5 do |d|
|
|
228
|
+
d['YEAR']
|
|
223
229
|
end
|
|
224
230
|
|
|
225
|
-
column :HOURS,
|
|
226
|
-
d[
|
|
231
|
+
column :HOURS, 'Hours', :size=>6 do |d|
|
|
232
|
+
d['HOURS']
|
|
227
233
|
end
|
|
228
234
|
|
|
229
|
-
column :RUNNING_HOURS,
|
|
230
|
-
d[
|
|
235
|
+
column :RUNNING_HOURS, 'Running hours', :size=>7 do |d|
|
|
236
|
+
d['RHOURS'] || '-'
|
|
231
237
|
end
|
|
232
238
|
|
|
233
|
-
column :COST,
|
|
234
|
-
d[
|
|
239
|
+
column :COST, 'Cost', :size=>15 do |d|
|
|
240
|
+
d['TOTAL_COST']
|
|
235
241
|
end
|
|
236
242
|
|
|
237
|
-
default :USER_NAME, :GROUP_NAME, :VM_ID, :VM_NAME, :MONTH, :YEAR, :HOURS, :RUNNING_HOURS,
|
|
243
|
+
default :USER_NAME, :GROUP_NAME, :VM_ID, :VM_NAME, :MONTH, :YEAR, :HOURS, :RUNNING_HOURS,
|
|
244
|
+
:COST
|
|
238
245
|
end
|
|
239
246
|
|
|
240
247
|
def self.print_start_end_time_header(start_time, end_time)
|
|
241
|
-
print
|
|
248
|
+
print 'Showing active history records from '
|
|
242
249
|
|
|
243
250
|
CLIHelper.scr_bold
|
|
244
|
-
if
|
|
245
|
-
print Time.at(start_time)
|
|
251
|
+
if start_time != -1
|
|
252
|
+
print Time.at(start_time)
|
|
246
253
|
else
|
|
247
|
-
print
|
|
254
|
+
print '-'
|
|
248
255
|
end
|
|
249
256
|
|
|
250
257
|
CLIHelper.scr_restore
|
|
251
|
-
print
|
|
258
|
+
print ' to '
|
|
252
259
|
|
|
253
260
|
CLIHelper.scr_bold
|
|
254
|
-
if
|
|
255
|
-
print Time.at(end_time)
|
|
261
|
+
if end_time != -1
|
|
262
|
+
print Time.at(end_time)
|
|
256
263
|
else
|
|
257
|
-
print
|
|
264
|
+
print '-'
|
|
258
265
|
end
|
|
259
266
|
|
|
260
267
|
CLIHelper.scr_restore
|
|
@@ -277,4 +284,5 @@ class AcctHelper < OpenNebulaHelper::OneHelper
|
|
|
277
284
|
CLIHelper.scr_restore
|
|
278
285
|
puts
|
|
279
286
|
end
|
|
287
|
+
|
|
280
288
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -------------------------------------------------------------------------- #
|
|
2
|
-
# Copyright 2002-
|
|
2
|
+
# Copyright 2002-2026, OpenNebula Project, OpenNebula Systems #
|
|
3
3
|
# #
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
|
5
5
|
# not use this file except in compliance with the License. You may obtain #
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -------------------------------------------------------------------------- #
|
|
2
|
-
# Copyright 2002-
|
|
2
|
+
# Copyright 2002-2026, OpenNebula Project, OpenNebula Systems #
|
|
3
3
|
# #
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
|
5
5
|
# not use this file except in compliance with the License. You may obtain #
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -------------------------------------------------------------------------- #
|
|
2
|
-
# Copyright 2002-
|
|
2
|
+
# Copyright 2002-2026, OpenNebula Project, OpenNebula Systems #
|
|
3
3
|
# #
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
|
5
5
|
# not use this file except in compliance with the License. You may obtain #
|