knife-xapi 0.2.2 → 0.3.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.
- data/lib/chef/knife/xapi_base.rb +16 -14
- data/lib/chef/knife/xapi_guest_create.rb +65 -51
- data/lib/knife-xapi/version.rb +1 -1
- metadata +2 -4
- data/README.rdoc +0 -58
data/lib/chef/knife/xapi_base.rb
CHANGED
@@ -42,24 +42,25 @@ class Chef::Knife
|
|
42
42
|
require 'readline'
|
43
43
|
end
|
44
44
|
|
45
|
-
option :
|
45
|
+
option :xapi_host,
|
46
46
|
:short => "-h SERVER_URL",
|
47
47
|
:long => "--host SERVER_URL",
|
48
48
|
:description => "The url to the xenserver, http://somehost.local.lan/",
|
49
|
-
:proc => Proc.new { |host| Chef::Config[:knife][:
|
49
|
+
:proc => Proc.new { |host| Chef::Config[:knife][:xapi_host] = host }
|
50
50
|
|
51
|
-
option :
|
51
|
+
option :xapi_password,
|
52
52
|
:short => "-K PASSWORD",
|
53
|
-
:long => "--
|
53
|
+
:long => "--xapi-password PASSWORD",
|
54
54
|
:description => "Your xenserver password",
|
55
|
-
:proc => Proc.new { |key| Chef::Config[:knife][:
|
55
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:xapi_password] = key }
|
56
56
|
|
57
|
-
option :
|
57
|
+
option :xapi_username,
|
58
58
|
:short => "-A USERNAME",
|
59
|
-
:long => "--
|
59
|
+
:long => "--xapi-username USERNAME",
|
60
60
|
:description => "Your xenserver username",
|
61
|
-
:proc => Proc.new { |username| Chef::Config[:knife][:
|
61
|
+
:proc => Proc.new { |username| Chef::Config[:knife][:xapi_username] = username }
|
62
62
|
end
|
63
|
+
|
63
64
|
end
|
64
65
|
|
65
66
|
# highline setup
|
@@ -71,11 +72,12 @@ class Chef::Knife
|
|
71
72
|
def xapi
|
72
73
|
@xapi ||= begin
|
73
74
|
|
74
|
-
|
75
|
+
ui.fatal "Must provide a xapi host with --host "unless locate_config_value(:xapi_host)
|
76
|
+
session = XenApi::Client.new( locate_config_value(:xapi_host) )
|
75
77
|
|
76
78
|
# get the password from the user
|
77
|
-
password =
|
78
|
-
username =
|
79
|
+
password = locate_config_value(:xapi_password) || nil
|
80
|
+
username = locate_config_value(:xapi_username) || "root"
|
79
81
|
if password.nil? or password.empty?
|
80
82
|
password = h.ask("Enter password for user #{username}: " ) { |input| input.echo = "*" }
|
81
83
|
end
|
@@ -132,7 +134,7 @@ class Chef::Knife
|
|
132
134
|
|
133
135
|
# ensure return values
|
134
136
|
if found
|
135
|
-
|
137
|
+
ui.msg "Using Template: #{h.color(found["name_label"], :cyan)}"
|
136
138
|
return get_template(found["name_label"]) # get the ref to this one
|
137
139
|
end
|
138
140
|
return nil
|
@@ -162,7 +164,7 @@ class Chef::Knife
|
|
162
164
|
|
163
165
|
# add a new vif
|
164
166
|
def add_vif_by_name(vm_ref, dev_num, net_name)
|
165
|
-
|
167
|
+
Chef::Log.debug "Looking up vif for: #{h.color(net_name, :cyan)}"
|
166
168
|
network_ref = xapi.network.get_by_name_label(net_name).first
|
167
169
|
if network_ref.nil?
|
168
170
|
ui.warn "#{h.color(net_name,:red)} not found, moving on"
|
@@ -170,7 +172,7 @@ class Chef::Knife
|
|
170
172
|
end
|
171
173
|
|
172
174
|
mac = generate_mac
|
173
|
-
|
175
|
+
Chef::Log.debug "Provisioning: #{h.color(net_name, :cyan)}, #{h.color(mac,:green)}, #{h.color(network_ref, :yellow)}"
|
174
176
|
|
175
177
|
vif = {
|
176
178
|
'device' => dev_num.to_s,
|
@@ -38,21 +38,23 @@ class Chef
|
|
38
38
|
:short => "-T Template Name Label",
|
39
39
|
:long => "--xapi-vm-template",
|
40
40
|
:description => "xapi template name to create from. accepts an string or regex",
|
41
|
-
:proc => Proc.new { |template| Chef::Config[:knife][:
|
41
|
+
:proc => Proc.new { |template| Chef::Config[:knife][:vm_template] = template }
|
42
42
|
|
43
43
|
option :domain,
|
44
44
|
:short => "-f Name",
|
45
45
|
:long => "--domain Name",
|
46
46
|
:description => "the domain name for the guest",
|
47
|
-
:proc => Proc.new { |domain| Chef::Config[:knife][:
|
47
|
+
:proc => Proc.new { |domain| Chef::Config[:knife][:domain] = domain },
|
48
|
+
:default => ""
|
48
49
|
|
49
50
|
option :install_repo,
|
50
51
|
:short => "-R If you're using a builtin template you will need to specify a repo url",
|
51
52
|
:long => "--xapi-install-repo",
|
52
53
|
:description => "Install repo for this template (if needed)",
|
53
|
-
:proc => Proc.new { |repo| Chef::Config[:knife][:
|
54
|
+
:proc => Proc.new { |repo| Chef::Config[:knife][:install_repo] = repo },
|
55
|
+
:default => "http://isoredirect.centos.org/centos/6/os/x86_64/"
|
54
56
|
|
55
|
-
option :
|
57
|
+
option :xapi_sr,
|
56
58
|
:short => "-S Storage repo to provision VM from",
|
57
59
|
:long => "--xapi-sr",
|
58
60
|
:description => "The Xen SR to use, If blank will use pool/hypervisor default",
|
@@ -62,25 +64,29 @@ class Chef
|
|
62
64
|
:short => "-B Set of kernel boot params to pass to the vm",
|
63
65
|
:long => "--xapi-kernel-params",
|
64
66
|
:description => "You can add more boot options to the vm e.g.: \"ks='http://foo.local/ks'\"",
|
65
|
-
:proc => Proc.new {|kernel| Chef::Config[:knife][:xapi_kernel_params] = kernel }
|
67
|
+
:proc => Proc.new {|kernel| Chef::Config[:knife][:xapi_kernel_params] = kernel },
|
68
|
+
:default => "graphical utf8"
|
66
69
|
|
67
|
-
option :
|
70
|
+
option :xapi_disk_size,
|
68
71
|
:short => "-D Size of disk. 1g 512m etc",
|
69
72
|
:long => "--xapi-disk-size",
|
70
73
|
:description => "The size of the root disk, use 'm' 'g' 't' if no unit specified assumes g",
|
71
|
-
:proc => Proc.new {|disk| Chef::Config[:knife][:xapi_disk_size] = disk }
|
74
|
+
:proc => Proc.new {|disk| Chef::Config[:knife][:xapi_disk_size] = disk },
|
75
|
+
:default => "8g"
|
72
76
|
|
73
|
-
option :
|
77
|
+
option :xapi_cpus,
|
74
78
|
:short => "-C Number of VCPUs to provision",
|
75
79
|
:long => "--xapi-cpus",
|
76
80
|
:description => "Number of VCPUS this vm should have 1 4 8 etc",
|
81
|
+
:default => 2,
|
77
82
|
:proc => Proc.new {|cpu| Chef::Config[:knife][:xapi_cpus] = cpu }
|
78
83
|
|
79
|
-
option :
|
84
|
+
option :xapi_mem,
|
80
85
|
:short => "-M Ammount of memory to provision",
|
81
86
|
:long => "--xapi-mem",
|
82
87
|
:description => "Ammount of memory the VM should have specify with m g etc 512m, 2g if no unit spcified it assumes gigabytes",
|
83
|
-
:proc => Proc.new {|mem| Chef::Config[:knife][:xapi_mem] = mem }
|
88
|
+
:proc => Proc.new {|mem| Chef::Config[:knife][:xapi_mem] = mem },
|
89
|
+
:default => "1g"
|
84
90
|
|
85
91
|
option :chef_node_name,
|
86
92
|
:short => "-N NAME",
|
@@ -91,7 +97,8 @@ class Chef
|
|
91
97
|
:short => "-S KEY",
|
92
98
|
:long => "--ssh-key KEY",
|
93
99
|
:description => "The SSH key id",
|
94
|
-
:proc => Proc.new { |key| Chef::Config[:knife][:
|
100
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_key_name] = key }
|
101
|
+
|
95
102
|
|
96
103
|
option :ssh_user,
|
97
104
|
:short => "-x USERNAME",
|
@@ -108,19 +115,19 @@ class Chef
|
|
108
115
|
:short => "-p PORT",
|
109
116
|
:long => "--ssh-port PORT",
|
110
117
|
:description => "The ssh port",
|
111
|
-
:
|
112
|
-
:
|
118
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key },
|
119
|
+
:default => "22"
|
113
120
|
|
114
121
|
option :bootstrap_version,
|
115
122
|
:long => "--bootstrap-version VERSION",
|
116
123
|
:description => "The version of Chef to install",
|
117
124
|
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
|
118
125
|
|
119
|
-
option :
|
120
|
-
:short => "-d
|
121
|
-
:long => "--
|
122
|
-
:description => "Bootstrap
|
123
|
-
:proc => Proc.new { |d| Chef::Config[:knife][:
|
126
|
+
option :bootstrap_template,
|
127
|
+
:short => "-d Template Name",
|
128
|
+
:long => "--bootstrap-template Template Name",
|
129
|
+
:description => "Bootstrap using a specific template",
|
130
|
+
:proc => Proc.new { |d| Chef::Config[:knife][:bootstrap_template] = d },
|
124
131
|
:default => "ubuntu10.04-gems"
|
125
132
|
|
126
133
|
option :template_file,
|
@@ -212,41 +219,40 @@ class Chef
|
|
212
219
|
$stdout.sync = true
|
213
220
|
|
214
221
|
# get the template vm we are going to build from
|
215
|
-
template_ref = find_template(
|
222
|
+
template_ref = find_template( locate_config_value(:vm_template) )
|
216
223
|
|
217
|
-
|
224
|
+
Chef::Log.debug "Cloning Guest from Template: #{h.color(template_ref, :bold, :cyan )}"
|
218
225
|
vm_ref = xapi.VM.clone(template_ref, server_name)
|
219
226
|
|
227
|
+
# TODO: lift alot of this
|
220
228
|
begin
|
221
|
-
xapi.VM.set_name_description(vm_ref, "VM
|
229
|
+
xapi.VM.set_name_description(vm_ref, "VM from knife-xapi as #{server_name}")
|
222
230
|
|
223
231
|
# configure the install repo
|
224
|
-
repo =
|
225
|
-
ui.msg "Setting Install Repo: #{h.color(repo,:bold, :cyan)}"
|
232
|
+
repo = locate_config_value(:install_repo)
|
226
233
|
xapi.VM.set_other_config(vm_ref, { "install-repository" => repo } )
|
227
|
-
|
228
|
-
|
234
|
+
|
235
|
+
|
236
|
+
cpus = locate_config_value( :xapi_cpus ).to_s
|
237
|
+
|
229
238
|
xapi.VM.set_VCPUs_max( vm_ref, cpus )
|
230
239
|
xapi.VM.set_VCPUs_at_startup( vm_ref, cpus )
|
231
240
|
|
232
|
-
memory_size = input_to_bytes(
|
233
|
-
ui.msg "Mem size: #{ h.color( memory_size, :cyan)}"
|
234
|
-
|
241
|
+
memory_size = input_to_bytes( locate_config_value(:xapi_mem) ).to_s
|
235
242
|
# static-min <= dynamic-min = dynamic-max = static-max
|
236
243
|
xapi.VM.set_memory_limits(vm_ref, memory_size, memory_size, memory_size, memory_size)
|
237
244
|
|
238
245
|
#
|
239
246
|
# setup the Boot args
|
240
247
|
#
|
241
|
-
boot_args =
|
242
|
-
domainname =
|
248
|
+
boot_args = locate_config_value(:kernel_params)
|
249
|
+
domainname = locate_config_value(:domain)
|
243
250
|
|
244
251
|
# if no hostname param set hostname to given vm name
|
245
252
|
boot_args << " hostname=#{server_name}" unless boot_args.match(/hostname=.+\s?/)
|
246
253
|
# if domainname is supplied we put that in there as well
|
247
254
|
boot_args << " domainname=#{domainname}" unless boot_args.match(/domainname=.+\s?/)
|
248
255
|
|
249
|
-
ui.msg "Setting Boot Args: #{h.color boot_args, :cyan}"
|
250
256
|
xapi.VM.set_PV_args( vm_ref, boot_args )
|
251
257
|
|
252
258
|
# TODO: validate that the vm gets a network here
|
@@ -259,23 +265,23 @@ class Chef
|
|
259
265
|
end
|
260
266
|
end
|
261
267
|
|
262
|
-
|
263
|
-
|
264
|
-
|
268
|
+
if locate_config_value(:xapi_sr)
|
269
|
+
sr_ref = get_sr_by_name( locate_config_value(:xapi_sr) )
|
270
|
+
else
|
271
|
+
sr_ref = find_default_sr
|
265
272
|
end
|
266
273
|
|
267
274
|
if sr_ref.nil?
|
268
275
|
ui.error "SR specified not found or can't be used Aborting"
|
269
276
|
cleanup(vm_ref)
|
270
277
|
end
|
271
|
-
|
278
|
+
Chef::Log.debug "SR: #{h.color sr_ref, :cyan}"
|
272
279
|
|
273
280
|
# Create the VDI
|
274
|
-
|
275
|
-
vdi_ref = create_vdi("#{server_name}-root", sr_ref, disk_size )
|
281
|
+
vdi_ref = create_vdi("#{server_name}-root", sr_ref, locate_config_value(:xapi_disk_size) )
|
276
282
|
# if vdi_ref is nill we need to bail/cleanup
|
277
283
|
cleanup(vm_ref) unless vdi_ref
|
278
|
-
ui.msg( "#{ h.color "OK", :green}"
|
284
|
+
ui.msg( "#{ h.color "OK", :green} ")
|
279
285
|
|
280
286
|
# Attach the VDI to the VM
|
281
287
|
vbd_ref = create_vbd(vm_ref, vdi_ref, 0)
|
@@ -283,13 +289,17 @@ class Chef
|
|
283
289
|
ui.msg( "#{ h.color "OK", :green}" )
|
284
290
|
|
285
291
|
ui.msg "Provisioning new Guest: #{h.color(vm_ref, :bold, :cyan )}"
|
292
|
+
ui.msg "Boot Args: #{h.color boot_args,:bold, :cyan}"
|
293
|
+
ui.msg "Install Repo: #{ h.color(repo,:bold, :cyan)}"
|
294
|
+
ui.msg "Memory: #{ h.color( locate_config_value(:xapi_mem).to_s, :bold, :cyan)}"
|
295
|
+
ui.msg "CPUs: #{ h.color( locate_config_value(:xapi_cpus).to_s, :bold, :cyan)}"
|
296
|
+
ui.msg "Disk: #{ h.color( locate_config_value(:xapi_disk_size).to_s, :bold, :cyan)}"
|
286
297
|
provisioned = xapi.VM.provision(vm_ref)
|
287
298
|
|
288
299
|
ui.msg "Starting new Guest #{h.color( provisioned, :cyan)} "
|
289
|
-
|
290
300
|
task = xapi.Async.VM.start(vm_ref, false, true)
|
291
301
|
wait_on_task(task)
|
292
|
-
ui.msg( "#{ h.color "
|
302
|
+
ui.msg( "#{ h.color "OK!", :green}" )
|
293
303
|
|
294
304
|
exit 0 unless locate_config_value(:run_list)
|
295
305
|
rescue Exception => e
|
@@ -312,7 +322,7 @@ class Chef
|
|
312
322
|
timeout(480) do
|
313
323
|
print(".") until tcp_test_ssh(guest_addr) {
|
314
324
|
sleep @initial_sleep_delay ||= 10
|
315
|
-
|
325
|
+
ui.msg( "#{ h.color "OK!", :green}" )
|
316
326
|
}
|
317
327
|
end
|
318
328
|
rescue Timeout::Error
|
@@ -321,8 +331,12 @@ class Chef
|
|
321
331
|
end
|
322
332
|
|
323
333
|
|
324
|
-
|
325
|
-
|
334
|
+
# begin
|
335
|
+
if domainname.empty?
|
336
|
+
server = server_name
|
337
|
+
else
|
338
|
+
server = "#{server_name}.#{domainname}"
|
339
|
+
end
|
326
340
|
bootstrap = Chef::Knife::Bootstrap.new
|
327
341
|
bootstrap.name_args = [ guest_addr ]
|
328
342
|
bootstrap.config[:run_list] = config[:run_list]
|
@@ -330,9 +344,9 @@ class Chef
|
|
330
344
|
bootstrap.config[:ssh_port] = config[:ssh_port]
|
331
345
|
bootstrap.config[:ssh_password] = config[:ssh_password]
|
332
346
|
bootstrap.config[:identity_file] = config[:identity_file]
|
333
|
-
bootstrap.config[:chef_node_name] = config[:chef_node_name] ||
|
347
|
+
bootstrap.config[:chef_node_name] = config[:chef_node_name] || server
|
334
348
|
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
335
|
-
bootstrap.config[:distro] = locate_config_value(:
|
349
|
+
bootstrap.config[:distro] = locate_config_value(:bootstrap_template)
|
336
350
|
bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
|
337
351
|
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
338
352
|
bootstrap.config[:environment] = config[:environment]
|
@@ -340,12 +354,12 @@ class Chef
|
|
340
354
|
bootstrap.config[:run_list] = config[:run_list]
|
341
355
|
|
342
356
|
bootstrap.run
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
357
|
+
# rescue Exception => e
|
358
|
+
# ui.msg "#{h.color 'ERROR:'} #{h.color( e.message, :red )}"
|
359
|
+
# puts "Nested backtrace:"
|
360
|
+
# ui.msg "#{h.color( e.backtrace.join("\n"), :yellow)}"
|
361
|
+
# cleanup(vm_ref)
|
362
|
+
# end
|
349
363
|
|
350
364
|
end
|
351
365
|
|
data/lib/knife-xapi/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-xapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05
|
12
|
+
date: 2012-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chef
|
@@ -81,10 +81,8 @@ executables: []
|
|
81
81
|
extensions: []
|
82
82
|
extra_rdoc_files:
|
83
83
|
- LICENSE
|
84
|
-
- README.rdoc
|
85
84
|
files:
|
86
85
|
- LICENSE
|
87
|
-
- README.rdoc
|
88
86
|
- lib/chef/knife/xapi_base.rb
|
89
87
|
- lib/chef/knife/xapi_guest_create.rb
|
90
88
|
- lib/chef/knife/xapi_guest_delete.rb
|
data/README.rdoc
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
=Knife Xapi
|
2
|
-
This plugin gives knife the ability to create guests on a XAPI compatable hyper visor
|
3
|
-
|
4
|
-
==Installation
|
5
|
-
This plugin is distributed as a Ruby Gem. To install it, run:
|
6
|
-
gem install knife-xapi
|
7
|
-
|
8
|
-
==Configuration
|
9
|
-
Config options are extenable in the knife.rb the folowing k/v pairs are implemented
|
10
|
-
|
11
|
-
Chef::Config[:knife][:xenserver_host] :: The API Host to connect to
|
12
|
-
Chef::Config[:knife][:xenserver_username] :: The User name to connect to the api with
|
13
|
-
Chef::Config[:knife][:xenserver_password] :: The Password (if not set will prompt on commandline)
|
14
|
-
Chef::Config[:knife][:xapi_vm_template] :: Set a default template to be used when creating Guests
|
15
|
-
Chef::Config[:knife][:xapi_install_repo] :: The install repo config option to set when using Xen builtin templates
|
16
|
-
Chef::Config[:knife][:xapi_sr] :: The Storage Repository to provision from, uses pool/hypervisor default when not set
|
17
|
-
Chef::Config[:knife][:xapi_disk_size] :: Default VM disk size (8g if not specified)
|
18
|
-
Chef::Config[:knife][:xapi_cpus] :: The Default CPUs to provision for guests (2 if not specified)
|
19
|
-
Chef::Config[:knife][:xapi_mem] = mem :: The Defaul ammount of Memory for guests (1g if not specified)
|
20
|
-
Chef::Config[:knife][:xapi_kernel_params] :: Optional Boot paramaters to pass to the guest
|
21
|
-
Chef::Config[:knife][:xapi_bootstrap] :: Not implemented yet, but will be the bootstrap script to execute after guest create
|
22
|
-
|
23
|
-
==Usage
|
24
|
-
=Create
|
25
|
-
Basic usage to create a VM from existing VM template:
|
26
|
-
knife xapi guest create "NewBox" "public" --xapi-vm-template "MyBaseBox" --host http://sandbox/
|
27
|
-
|
28
|
-
|
29
|
-
More verbose example using a kickstart file and booting the Centos 5 default template:
|
30
|
-
knife xapi guest create "MySpiffyBox" "pub_network" --host http://sandbox/ \
|
31
|
-
-B "dns=8.8.8.8 ks=http://192.168.6.4/repo/ks/default.ks ip=192.168.6.7 netmask=255.255.255.0 gateway=192.168.6.1" \
|
32
|
-
-R http://192.168.6.5/repo/centos/5/os/x86_64 -C 4 -M 4g -D 5g
|
33
|
-
*-B Boot args where i am assigning all the centos/rhel boot args for Ip setup and kickstart file
|
34
|
-
*-R Repo URL used by xenserver to start the net install
|
35
|
-
*-C Number of cpus for this guest
|
36
|
-
*-M Memory size
|
37
|
-
*-D Disk size
|
38
|
-
|
39
|
-
Use Knife builtin help schematic for more info
|
40
|
-
knife xapi guest create --help
|
41
|
-
|
42
|
-
=Delete
|
43
|
-
Delete is pretty simple. When there are multiple vms with a name label you should be prompted to select one
|
44
|
-
knife xapi guest delete testing
|
45
|
-
|
46
|
-
If you know the UUID of the VM you can specify --uuid
|
47
|
-
knife xapi guest delete b461c0d2-d24d-bc02-3231-711101f57b8e --uuid
|
48
|
-
|
49
|
-
=List
|
50
|
-
List shows the vm's on the pool/host Ignoring Controll domains and templates. VM OpaqueRef and UUID are displayed which can be
|
51
|
-
knife xapi guest list
|
52
|
-
Name Label Ref UUID
|
53
|
-
test-server OpaqueRef:82065b80-55ff-63ce-ef89-6b33fb5fd272 9b0a0afa-5573-7875-b787-47fbfa2548a4
|
54
|
-
tester OpaqueRef:2d239fbd-bff6-4e60-f675-e1d2530199d2 de760651-2db8-6f81-0783-7b8364f591fd
|
55
|
-
test-client OpaqueRef:e4bbd801-c9be-e355-2a22-2ca468a90a81 35156957-45f4-02f8-6de9-6adbcd5e0c6d
|
56
|
-
test-client OpaqueRef:f5b562f8-a493-f535-335e-ae70b3177869 f46e4d6b-bd9e-e47b-5f0d-b849ff75c5ef
|
57
|
-
|
58
|
-
|