opennebula-cli 7.0.2 → 7.1.80.pre
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/oneform +150 -0
- data/bin/onemarketapp +3 -0
- data/bin/onetemplate +15 -4
- data/bin/oneuser +2 -1
- data/bin/onevm +50 -5
- data/bin/onevntemplate +2 -1
- data/bin/onezone +11 -5
- data/lib/cli_helper.rb +152 -0
- data/lib/one_helper/oneacct_helper.rb +2 -0
- data/lib/one_helper/oneacl_helper.rb +2 -0
- data/lib/one_helper/onebackupjob_helper.rb +2 -0
- data/lib/one_helper/onecluster_helper.rb +3 -0
- data/lib/one_helper/onedatastore_helper.rb +3 -0
- data/lib/one_helper/oneform_helper.rb +255 -0
- data/lib/one_helper/onegroup_helper.rb +132 -97
- data/lib/one_helper/onehook_helper.rb +4 -1
- data/lib/one_helper/onehost_helper.rb +5 -2
- data/lib/one_helper/oneimage_helper.rb +2 -0
- data/lib/one_helper/onemarket_helper.rb +2 -0
- data/lib/one_helper/onemarketapp_helper.rb +3 -0
- data/lib/one_helper/onequota_helper.rb +104 -21
- data/lib/one_helper/onesecgroup_helper.rb +2 -0
- data/lib/one_helper/onetemplate_helper.rb +2 -1
- data/lib/one_helper/oneuser_helper.rb +164 -155
- data/lib/one_helper/onevdc_helper.rb +2 -0
- data/lib/one_helper/onevm_helper.rb +5 -1
- data/lib/one_helper/onevmgroup_helper.rb +2 -0
- data/lib/one_helper/onevnet_helper.rb +15 -4
- data/lib/one_helper/onevntemplate_helper.rb +2 -1
- data/lib/one_helper/onevrouter_helper.rb +2 -0
- data/lib/one_helper/onezone_helper.rb +15 -4
- data/lib/one_helper.rb +51 -16
- data/share/schemas/xsd/group.xsd +8 -0
- data/share/schemas/xsd/group_pool.xsd +8 -0
- data/share/schemas/xsd/opennebula_configuration.xsd +4 -8
- data/share/schemas/xsd/shared.xsd +8 -0
- data/share/schemas/xsd/user.xsd +8 -0
- data/share/schemas/xsd/user_pool.xsd +8 -0
- data/share/schemas/xsd/vm.xsd +20 -0
- data/share/schemas/xsd/vnet.xsd +2 -1
- data/share/schemas/xsd/vnet_pool.xsd +1 -0
- metadata +9 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e0a75e568244920c5ad5f5ef5c91d27a059240c29290bdbcadc12825689f7ff
|
|
4
|
+
data.tar.gz: 8b999e8828e35f872fc7c98b81d4a2643c84e0731a135c5bf76b141a8581aeec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c4713fa611ccaad4a2b733056c749b8ef77a0b6cfddcdae0bc54b3638b9c84e945c44a173114515104f80e2b5cc34de31aba637a870ea7cdb2d5c40b37b2e5fd
|
|
7
|
+
data.tar.gz: 1fca59489877e11016777870efe98bc8d3a58099ec2cb24d1717a4cc8a1c6e16ec2024d7f88760ed5732e49d3f16e508e37d7582f3b230b7f259211c3075c62e
|
data/bin/oneform
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# -------------------------------------------------------------------------- #
|
|
4
|
+
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems #
|
|
5
|
+
# #
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
|
7
|
+
# not use this file except in compliance with the License. You may obtain #
|
|
8
|
+
# a copy of the License at #
|
|
9
|
+
# #
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0 #
|
|
11
|
+
# #
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software #
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, #
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
|
15
|
+
# See the License for the specific language governing permissions and #
|
|
16
|
+
# limitations under the License. #
|
|
17
|
+
#--------------------------------------------------------------------------- #
|
|
18
|
+
|
|
19
|
+
ONE_LOCATION = ENV['ONE_LOCATION']
|
|
20
|
+
|
|
21
|
+
if !ONE_LOCATION
|
|
22
|
+
LIB_LOCATION = '/usr/lib/one'
|
|
23
|
+
RUBY_LIB_LOCATION = '/usr/lib/one/ruby'
|
|
24
|
+
GEMS_LOCATION = '/usr/share/one/gems'
|
|
25
|
+
else
|
|
26
|
+
LIB_LOCATION = ONE_LOCATION + '/lib'
|
|
27
|
+
RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
|
|
28
|
+
GEMS_LOCATION = ONE_LOCATION + '/share/gems'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
require 'load_opennebula_paths'
|
|
32
|
+
|
|
33
|
+
$LOAD_PATH << RUBY_LIB_LOCATION
|
|
34
|
+
$LOAD_PATH << RUBY_LIB_LOCATION + '/cli'
|
|
35
|
+
|
|
36
|
+
USER_AGENT = 'CLI'
|
|
37
|
+
|
|
38
|
+
require 'command_parser'
|
|
39
|
+
require 'one_helper'
|
|
40
|
+
require 'opennebula/oneform_client'
|
|
41
|
+
require 'tempfile'
|
|
42
|
+
|
|
43
|
+
require 'one_helper/oneform_helper'
|
|
44
|
+
|
|
45
|
+
CommandParser::CmdParser.new(ARGV) do
|
|
46
|
+
FORMAT = [OpenNebulaHelper::JSON, OpenNebulaHelper::YAML]
|
|
47
|
+
|
|
48
|
+
usage '`oneform` <command> [<args>] [<options>]'
|
|
49
|
+
version OpenNebulaHelper::ONE_VERSION
|
|
50
|
+
|
|
51
|
+
set :option, OneForm::Client::DEFAULT_OPTIONS
|
|
52
|
+
set :option, CommandParser::VERSION
|
|
53
|
+
set :option, CommandParser::HELP
|
|
54
|
+
|
|
55
|
+
ENABLED = {
|
|
56
|
+
:name => 'enabled',
|
|
57
|
+
:short => '-e',
|
|
58
|
+
:large => '--enabled',
|
|
59
|
+
:description => 'Show only enabled providers',
|
|
60
|
+
:default => false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
helper = OneFormHelper.new
|
|
64
|
+
|
|
65
|
+
########################################################################
|
|
66
|
+
# Commands for interacting with oneform drivers
|
|
67
|
+
########################################################################
|
|
68
|
+
|
|
69
|
+
list_desc = <<-EOT.unindent
|
|
70
|
+
List all drivers installed on the system.
|
|
71
|
+
EOT
|
|
72
|
+
|
|
73
|
+
command :list,
|
|
74
|
+
list_desc,
|
|
75
|
+
:options => FORMAT + CLIHelper::OPTIONS + [OpenNebulaHelper::DESCRIBE, ENABLED] do
|
|
76
|
+
enabled = options[:enabled] || false
|
|
77
|
+
helper.list_driver_pool(helper.client(options), options, :enabled => enabled)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
top_desc = <<-EOT.unindent
|
|
81
|
+
List the available drivers continuously.
|
|
82
|
+
EOT
|
|
83
|
+
|
|
84
|
+
command :top,
|
|
85
|
+
top_desc,
|
|
86
|
+
:options => FORMAT + [CLIHelper::DELAY, ENABLED] do
|
|
87
|
+
Signal.trap('INT') { exit(-1) }
|
|
88
|
+
enabled = options[:enabled] || false
|
|
89
|
+
helper.top_driver_pool(helper.client(options), options, :enabled => enabled)
|
|
90
|
+
|
|
91
|
+
0
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
show_desc = <<-EOT.unindent
|
|
95
|
+
Show details of a specific driver.
|
|
96
|
+
EOT
|
|
97
|
+
|
|
98
|
+
command :show, show_desc, :driver_name, :options => FORMAT do
|
|
99
|
+
driver_name = args[0]
|
|
100
|
+
|
|
101
|
+
helper.format_resource(helper.client(options), driver_name, options)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
sync_desc = <<-EOT.unindent
|
|
105
|
+
Synchronize OneForm drivers, refreshing and update available drivers
|
|
106
|
+
EOT
|
|
107
|
+
|
|
108
|
+
command :sync, sync_desc do
|
|
109
|
+
client = helper.client(options)
|
|
110
|
+
|
|
111
|
+
response = client.sync_drivers
|
|
112
|
+
|
|
113
|
+
return [response[:err_code], response[:message]] \
|
|
114
|
+
if CloudClient.is_error?(response)
|
|
115
|
+
|
|
116
|
+
0
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
enable_desc = <<-EOT.unindent
|
|
120
|
+
Enable a driver in OneForm to permit the creation of new resources based on it.
|
|
121
|
+
EOT
|
|
122
|
+
|
|
123
|
+
command :enable, enable_desc, :driver_name do
|
|
124
|
+
client = helper.client(options)
|
|
125
|
+
driver_name = args[0]
|
|
126
|
+
|
|
127
|
+
response = client.enable_driver(driver_name)
|
|
128
|
+
|
|
129
|
+
return [response[:err_code], response[:message]] \
|
|
130
|
+
if CloudClient.is_error?(response)
|
|
131
|
+
|
|
132
|
+
0
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
disable_desc = <<-EOT.unindent
|
|
136
|
+
Disables a driver in OneForm, avoiding creation of new resources based on it.
|
|
137
|
+
EOT
|
|
138
|
+
|
|
139
|
+
command :disable, disable_desc, :driver_name do
|
|
140
|
+
client = helper.client(options)
|
|
141
|
+
driver_name = args[0]
|
|
142
|
+
|
|
143
|
+
response = client.disable_driver(driver_name)
|
|
144
|
+
|
|
145
|
+
return [response[:err_code], response[:message]] \
|
|
146
|
+
if CloudClient.is_error?(response)
|
|
147
|
+
|
|
148
|
+
0
|
|
149
|
+
end
|
|
150
|
+
end
|
data/bin/onemarketapp
CHANGED
|
@@ -39,6 +39,9 @@ require 'command_parser'
|
|
|
39
39
|
require 'one_helper/onemarketapp_helper'
|
|
40
40
|
require 'one_helper/onemarket_helper'
|
|
41
41
|
require 'one_helper/onedatastore_helper'
|
|
42
|
+
require 'opennebula/template_pool'
|
|
43
|
+
require 'opennebula/virtual_machine_pool'
|
|
44
|
+
require 'opennebula/flow'
|
|
42
45
|
|
|
43
46
|
CommandParser::CmdParser.new(ARGV) do
|
|
44
47
|
usage '`onemarket` <command> [<args>] [<options>]'
|
data/bin/onetemplate
CHANGED
|
@@ -203,7 +203,8 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
203
203
|
if !OpenNebula.is_error?(res)
|
|
204
204
|
puts "ID: #{res}"
|
|
205
205
|
else
|
|
206
|
-
puts res.message
|
|
206
|
+
STDERR.puts res.message
|
|
207
|
+
exit(-1)
|
|
207
208
|
end
|
|
208
209
|
end
|
|
209
210
|
end
|
|
@@ -253,6 +254,18 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
253
254
|
|
|
254
255
|
number = options[:multiple] || 1
|
|
255
256
|
user_inputs = options[:user_inputs]
|
|
257
|
+
persistent = !options[:persistent].nil?
|
|
258
|
+
flag = nil
|
|
259
|
+
|
|
260
|
+
if persistent && (number > 1)
|
|
261
|
+
if options[:name] && !options[:name].include?('%i')
|
|
262
|
+
flag = '-%i'
|
|
263
|
+
elsif !options[:name]
|
|
264
|
+
STDERR.puts 'Persistent template cannot be instantiated multiple times ' <<
|
|
265
|
+
"without including a name (use '%i' to chose where to insert the index)."
|
|
266
|
+
next -1
|
|
267
|
+
end
|
|
268
|
+
end
|
|
256
269
|
|
|
257
270
|
number.times.each_with_index do |i, index|
|
|
258
271
|
exit_code = helper.perform_action(
|
|
@@ -260,7 +273,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
260
273
|
options,
|
|
261
274
|
'instantiated'
|
|
262
275
|
) do |t|
|
|
263
|
-
name = options[:name]
|
|
276
|
+
name = "#{options[:name]}#{flag}" if options[:name]
|
|
264
277
|
prefix = options[:prefix]
|
|
265
278
|
c_i = nil
|
|
266
279
|
p = nil
|
|
@@ -325,8 +338,6 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
325
338
|
|
|
326
339
|
extra_template.strip!
|
|
327
340
|
|
|
328
|
-
persistent = !options[:persistent].nil?
|
|
329
|
-
|
|
330
341
|
res = t.instantiate(name, on_hold, extra_template, persistent)
|
|
331
342
|
|
|
332
343
|
if !OpenNebula.is_error?(res)
|
data/bin/oneuser
CHANGED
|
@@ -52,7 +52,8 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
52
52
|
rescue StandardError => e
|
|
53
53
|
STDERR.puts e.message
|
|
54
54
|
|
|
55
|
-
if e.message != OpenNebula::Client::NO_ONE_AUTH_ERROR
|
|
55
|
+
if e.message != OpenNebula::Client::NO_ONE_AUTH_ERROR &&
|
|
56
|
+
e.message != OpenNebula::Client::GRPC_NOT_SUPPORTED
|
|
56
57
|
STDERR.puts e.backtrace
|
|
57
58
|
end
|
|
58
59
|
|
data/bin/onevm
CHANGED
|
@@ -41,6 +41,8 @@ require 'one_helper/onevm_helper'
|
|
|
41
41
|
require 'one_helper/onedatastore_helper'
|
|
42
42
|
require 'opennebula/virtual_machine_ext'
|
|
43
43
|
|
|
44
|
+
require 'base64'
|
|
45
|
+
|
|
44
46
|
CommandParser::CmdParser.new(ARGV) do
|
|
45
47
|
usage '`onevm` <command> [<args>] [<options>]'
|
|
46
48
|
version OpenNebulaHelper::ONE_VERSION
|
|
@@ -256,6 +258,13 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
256
258
|
:description => 'Use only selected disk ID'
|
|
257
259
|
}
|
|
258
260
|
|
|
261
|
+
CMD_STDIN = {
|
|
262
|
+
:name => 'stdin',
|
|
263
|
+
:large => '--stdin stdin',
|
|
264
|
+
:format => String,
|
|
265
|
+
:description => 'Data to pass to the command executed on the VM'
|
|
266
|
+
}
|
|
267
|
+
|
|
259
268
|
OpenNebulaHelper::TEMPLATE_OPTIONS_VM.delete_if do |v|
|
|
260
269
|
['as_gid', 'as_uid'].include?(v[:name])
|
|
261
270
|
end
|
|
@@ -647,8 +656,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
647
656
|
|
|
648
657
|
migrate_desc = <<-EOT.unindent
|
|
649
658
|
Migrates the given running VM to another Host. If used with --live
|
|
650
|
-
parameter the migration is done without downtime.
|
|
651
|
-
not supported for --live flag.
|
|
659
|
+
parameter the migration is done without downtime.
|
|
652
660
|
|
|
653
661
|
States: RUNNING
|
|
654
662
|
EOT
|
|
@@ -1272,7 +1280,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
1272
1280
|
)
|
|
1273
1281
|
|
|
1274
1282
|
if !rc.nil?
|
|
1275
|
-
puts rc.message
|
|
1283
|
+
STDERR.puts rc.message
|
|
1276
1284
|
exit(-1)
|
|
1277
1285
|
end
|
|
1278
1286
|
|
|
@@ -1517,6 +1525,43 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
1517
1525
|
end
|
|
1518
1526
|
end
|
|
1519
1527
|
|
|
1528
|
+
exec_desc = <<-EOT.unindent
|
|
1529
|
+
Execute a command inside a Virtual Machine.
|
|
1530
|
+
|
|
1531
|
+
States: RUNNING.
|
|
1532
|
+
EOT
|
|
1533
|
+
|
|
1534
|
+
command :exec, exec_desc, [:range, :vmid_list], :cmd,
|
|
1535
|
+
:options => [CMD_STDIN] do
|
|
1536
|
+
helper.perform_actions(args[0], options, 'Executing a command') do |vm|
|
|
1537
|
+
vm.exec(args[1], Base64.strict_encode64(options[:stdin] || ''))
|
|
1538
|
+
end
|
|
1539
|
+
end
|
|
1540
|
+
|
|
1541
|
+
exec_retry_desc = <<-EOT.unindent
|
|
1542
|
+
Retries to execute the last command executed inside a Virtual Machine.
|
|
1543
|
+
|
|
1544
|
+
States: RUNNING.
|
|
1545
|
+
EOT
|
|
1546
|
+
|
|
1547
|
+
command :"exec-retry", exec_retry_desc, [:range, :vmid_list] do
|
|
1548
|
+
helper.perform_actions(args[0], options, 'Retrying last command') do |vm|
|
|
1549
|
+
vm.exec_retry
|
|
1550
|
+
end
|
|
1551
|
+
end
|
|
1552
|
+
|
|
1553
|
+
exec_cancel_desc = <<-EOT.unindent
|
|
1554
|
+
Cancel the command being executed inside a Virtual Machine.
|
|
1555
|
+
|
|
1556
|
+
States: RUNNING.
|
|
1557
|
+
EOT
|
|
1558
|
+
|
|
1559
|
+
command :"exec-cancel", exec_cancel_desc, [:range, :vmid_list] do
|
|
1560
|
+
helper.perform_actions(args[0], options, 'Canceling last command') do |vm|
|
|
1561
|
+
vm.exec_cancel
|
|
1562
|
+
end
|
|
1563
|
+
end
|
|
1564
|
+
|
|
1520
1565
|
########################### Charters Management ############################
|
|
1521
1566
|
|
|
1522
1567
|
create_chart_desc = <<-EOT.unindent
|
|
@@ -1685,7 +1730,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
1685
1730
|
You can specify the PCI device with --pci (short_address) or
|
|
1686
1731
|
--pci_device (device ID), --pci_class (class ID) and/or --pci_vendor (vendor ID).
|
|
1687
1732
|
|
|
1688
|
-
States: POWEROFF
|
|
1733
|
+
States: POWEROFF, UNDEPLOYED
|
|
1689
1734
|
EOT
|
|
1690
1735
|
|
|
1691
1736
|
command :"pci-attach", pci_attach_desc, :vmid,
|
|
@@ -1730,7 +1775,7 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
1730
1775
|
pci_detach_desc = <<-EOT.unindent
|
|
1731
1776
|
Detaches a PCI device from a VM
|
|
1732
1777
|
|
|
1733
|
-
States: POWEROFF
|
|
1778
|
+
States: POWEROFF, UNDEPLOYED
|
|
1734
1779
|
EOT
|
|
1735
1780
|
|
|
1736
1781
|
command :"pci-detach", pci_detach_desc, :vmid, :pciid do
|
data/bin/onevntemplate
CHANGED
data/bin/onezone
CHANGED
|
@@ -130,15 +130,20 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
130
130
|
EOT
|
|
131
131
|
|
|
132
132
|
command :"server-add", addserver_desc, :zoneid, :options =>
|
|
133
|
-
[OneZoneHelper::SERVER_NAME, OneZoneHelper::SERVER_ENDPOINT
|
|
134
|
-
|
|
133
|
+
[OneZoneHelper::SERVER_NAME, OneZoneHelper::SERVER_ENDPOINT,
|
|
134
|
+
OneZoneHelper::SERVER_ENDPOINT_GRPC] do
|
|
135
|
+
if options[:server_name].nil? || (options[:server_rpc].nil? && options[:server_grpc].nil?)
|
|
135
136
|
STDERR.puts 'To add a server set:'
|
|
136
137
|
STDERR.puts "\t-n <server name>"
|
|
137
|
-
STDERR.puts "\t-r <RPC endpoint>"
|
|
138
|
+
STDERR.puts "\t-r <XML-RPC endpoint>"
|
|
139
|
+
STDERR.puts "\t-g <gRPC endpoint>"
|
|
138
140
|
exit(-1)
|
|
139
141
|
end
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
puts "#{options[:server_rpc]}:#{options[:server_grpc]}"
|
|
144
|
+
|
|
145
|
+
if !options[:server_rpc].nil? && !options[:server_rpc].empty? &&
|
|
146
|
+
!%r{^(http|https):\/\/}.match(options[:server_rpc])
|
|
142
147
|
puts 'Wrong protocol specified. Only http or https allowed!'
|
|
143
148
|
exit(-1)
|
|
144
149
|
end
|
|
@@ -146,7 +151,8 @@ CommandParser::CmdParser.new(ARGV) do
|
|
|
146
151
|
template = <<-EOT
|
|
147
152
|
SERVER = [
|
|
148
153
|
NAME="#{options[:server_name]}",
|
|
149
|
-
ENDPOINT="#{options[:server_rpc]}"
|
|
154
|
+
ENDPOINT="#{options[:server_rpc]}",
|
|
155
|
+
ENDPOINT_GRPC="#{options[:server_grpc]}"
|
|
150
156
|
]
|
|
151
157
|
EOT
|
|
152
158
|
|
data/lib/cli_helper.rb
CHANGED
|
@@ -265,6 +265,158 @@ module CLIHelper
|
|
|
265
265
|
exit(-1)
|
|
266
266
|
end
|
|
267
267
|
|
|
268
|
+
# Render a small HTML subset for terminal output
|
|
269
|
+
# Supports: p, br, ul/ol/li, strong/b, em/i, code, a[href]
|
|
270
|
+
def self.render_html(text)
|
|
271
|
+
return '' if text.nil? || text.empty?
|
|
272
|
+
|
|
273
|
+
use_ansi = $stdout.tty?
|
|
274
|
+
|
|
275
|
+
bold_on = use_ansi ? "\33[1m" : ''
|
|
276
|
+
faint_on = use_ansi ? "\33[2m" : ''
|
|
277
|
+
reset = use_ansi ? "\33[0m" : ''
|
|
278
|
+
mono_on = use_ansi ? "\33[36m" : ''
|
|
279
|
+
bullet = use_ansi ? '•' : '*'
|
|
280
|
+
|
|
281
|
+
# OSC 8 hyperlink escape (clickable links)
|
|
282
|
+
osc8_link = lambda do |label, url|
|
|
283
|
+
return "#{label} (#{url})" unless use_ansi
|
|
284
|
+
|
|
285
|
+
"\e]8;;#{url}\a#{label}\e]8;;\a"
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
s = text.to_s.gsub("\r\n", "\n")
|
|
289
|
+
|
|
290
|
+
# Block tags -> newlines
|
|
291
|
+
s = s.gsub(%r{<\s*br\s*/?\s*>}i, "\n")
|
|
292
|
+
s = s.gsub(%r{<\s*/\s*p\s*>}i, "\n")
|
|
293
|
+
s = s.gsub(/<\s*p\b[^>]*>/i, '')
|
|
294
|
+
s = s.gsub(%r{<\s*/\s*(div|section|article)\s*>}i, "\n\n")
|
|
295
|
+
s = s.gsub(/<\s*(div|section|article)\b[^>]*>/i, '')
|
|
296
|
+
|
|
297
|
+
# Links: <a href="url">label</a>
|
|
298
|
+
s = s.gsub(%r{<\s*a\b[^>]*href\s*=\s*["']([^"']+)["'][^>]*>(.*?)<\s*/\s*a\s*>}im) do
|
|
299
|
+
url = Regexp.last_match(1).strip
|
|
300
|
+
label = Regexp.last_match(2).to_s
|
|
301
|
+
osc8_link.call(label, url)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Lists
|
|
305
|
+
s = s.gsub(/<\s*li\b[^>]*>/i, "#{bullet} ")
|
|
306
|
+
|
|
307
|
+
# Inline formatting
|
|
308
|
+
if use_ansi
|
|
309
|
+
s = s.gsub(%r{<\s*/\s*(strong|b)\s*>}i, reset)
|
|
310
|
+
s = s.gsub(/<\s*(strong|b)\b[^>]*>/i, bold_on)
|
|
311
|
+
|
|
312
|
+
s = s.gsub(%r{<\s*/\s*(em|i)\s*>}i, reset)
|
|
313
|
+
s = s.gsub(/<\s*(em|i)\b[^>]*>/i, faint_on)
|
|
314
|
+
|
|
315
|
+
# <code>
|
|
316
|
+
s = s.gsub(%r{<\s*code\b[^>]*>(.*?)<\s*/\s*code\s*>}im) do
|
|
317
|
+
"#{faint_on}#{mono_on}#{Regexp.last_match(1)}#{reset}"
|
|
318
|
+
end
|
|
319
|
+
else
|
|
320
|
+
s = s.gsub(%r{<\s*/?\s*(strong|b|em|i|code)\b[^>]*>}i, '')
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Remove any remaining tags
|
|
324
|
+
s = s.gsub(/<[^>]+>/, '')
|
|
325
|
+
|
|
326
|
+
# Decode minimal HTML entities
|
|
327
|
+
s = s.gsub('&', '&')
|
|
328
|
+
.gsub('<', '<')
|
|
329
|
+
.gsub('>', '>')
|
|
330
|
+
.gsub('"', '"')
|
|
331
|
+
.gsub(''', "'")
|
|
332
|
+
.gsub(' ', ' ')
|
|
333
|
+
|
|
334
|
+
# Normalize whitespace
|
|
335
|
+
s = s.lines.map(&:rstrip).join("\n")
|
|
336
|
+
s.gsub(/\n{3,}/, "\n\n").strip
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Render a small Markdown subset for terminal output. Supports headings,
|
|
340
|
+
# bold, italic, inline code, and unordered lists.
|
|
341
|
+
def self.render_md(text)
|
|
342
|
+
return '' if text.nil? || text.empty?
|
|
343
|
+
|
|
344
|
+
use_ansi = $stdout.tty?
|
|
345
|
+
|
|
346
|
+
bold_on = use_ansi ? "\33[1m" : ''
|
|
347
|
+
reset = use_ansi ? "\33[0m" : ''
|
|
348
|
+
faint_on = use_ansi ? "\33[2m" : ''
|
|
349
|
+
mono_on = use_ansi ? "\33[36m" : ''
|
|
350
|
+
bullet = use_ansi ? '•' : '*'
|
|
351
|
+
|
|
352
|
+
# OSC 8 hyperlink sequences
|
|
353
|
+
osc8_link = lambda do |label, url|
|
|
354
|
+
return "#{label} (#{url})" unless use_ansi
|
|
355
|
+
|
|
356
|
+
"\e]8;;#{url}\a#{label}\e]8;;\a"
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
lines = text.to_s.gsub("\r\n", "\n").split("\n", -1)
|
|
360
|
+
|
|
361
|
+
out = lines.map do |line|
|
|
362
|
+
# Preserve empty lines
|
|
363
|
+
if line.strip.empty?
|
|
364
|
+
''
|
|
365
|
+
# Headings (#, ##, ###)
|
|
366
|
+
elsif (m = line.match(/\A\s{0,3}(\#{1,3})\s+(.*)\z/))
|
|
367
|
+
title = m[2].strip
|
|
368
|
+
"#{bold_on}#{title}#{reset}"
|
|
369
|
+
# Unordered list items (*, -, +)
|
|
370
|
+
elsif (m = line.match(/\A(\s*)[*+-]\s+(.*)\z/))
|
|
371
|
+
indent = m[1]
|
|
372
|
+
item = m[2]
|
|
373
|
+
"#{indent}#{bullet} #{item}"
|
|
374
|
+
else
|
|
375
|
+
line
|
|
376
|
+
end
|
|
377
|
+
end.join("\n")
|
|
378
|
+
|
|
379
|
+
# Links [label](url)
|
|
380
|
+
out = out.gsub(/\[([^\]]+)\]\(([^)]+)\)/) do
|
|
381
|
+
label = Regexp.last_match(1)
|
|
382
|
+
url = Regexp.last_match(2).strip
|
|
383
|
+
osc8_link.call(label, url)
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Autolinks <https://example.com>
|
|
387
|
+
out = out.gsub(/<((?:https?|mailto):[^>\s]+)>/) do
|
|
388
|
+
url = Regexp.last_match(1)
|
|
389
|
+
osc8_link.call(url, url)
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# Inline formatting (simple, non-nested)
|
|
393
|
+
if use_ansi
|
|
394
|
+
# Inline code: `code`
|
|
395
|
+
out = out.gsub(/`([^`]+)`/) do
|
|
396
|
+
m = Regexp.last_match(1)
|
|
397
|
+
"#{faint_on}#{mono_on}#{m}#{reset}"
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# Bold: **text**
|
|
401
|
+
out = out.gsub(/\*\*([^\*]+)\*\*/) do
|
|
402
|
+
m = Regexp.last_match(1)
|
|
403
|
+
"#{bold_on}#{m}#{reset}"
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
# Italic: *text*
|
|
407
|
+
out = out.gsub(/(^|[^*])\*([^*\n]+)\*(?!\*)/) do
|
|
408
|
+
m1 = Regexp.last_match(1)
|
|
409
|
+
m2 = Regexp.last_match(2)
|
|
410
|
+
"#{m1}#{faint_on}#{m2}#{reset}"
|
|
411
|
+
end
|
|
412
|
+
else
|
|
413
|
+
# Non-tty, keep markdown mostly as-is, but normalize list bullets
|
|
414
|
+
out = out.gsub(/\A(\s*)[*+-]\s+/m, "\\1#{bullet} ")
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
out
|
|
418
|
+
end
|
|
419
|
+
|
|
268
420
|
# Check if value is in base64
|
|
269
421
|
#
|
|
270
422
|
# @param value [String] Value to check
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
#--------------------------------------------------------------------------- #
|
|
16
16
|
|
|
17
17
|
require 'one_helper'
|
|
18
|
+
require 'opennebula/backupjob'
|
|
19
|
+
require 'opennebula/backupjob_pool'
|
|
18
20
|
|
|
19
21
|
# Helper for onebackupjob command
|
|
20
22
|
class OneBackupJobHelper < OpenNebulaHelper::OneHelper
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
#--------------------------------------------------------------------------- #
|
|
16
16
|
|
|
17
17
|
require 'one_helper'
|
|
18
|
+
require 'opennebula/cluster'
|
|
19
|
+
require 'opennebula/cluster_pool'
|
|
20
|
+
require 'opennebula/host'
|
|
18
21
|
|
|
19
22
|
# OneCluster CLI command helper
|
|
20
23
|
class OneClusterHelper < OpenNebulaHelper::OneHelper
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
#--------------------------------------------------------------------------- #
|
|
16
16
|
|
|
17
17
|
require 'one_helper'
|
|
18
|
+
require 'opennebula/datastore'
|
|
19
|
+
require 'opennebula/datastore_pool'
|
|
20
|
+
require 'opennebula/image'
|
|
18
21
|
|
|
19
22
|
class OneDatastoreHelper < OpenNebulaHelper::OneHelper
|
|
20
23
|
DATASTORE = {
|