morpheus-cli 7.0.4.3 → 7.0.6
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/Dockerfile +1 -1
- data/lib/morpheus/api/servers_interface.rb +21 -0
- data/lib/morpheus/cli/commands/clusters.rb +6 -2
- data/lib/morpheus/cli/commands/hosts.rb +228 -66
- data/lib/morpheus/cli/commands/provisioning_licenses_command.rb +0 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -0
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cbee8120b32418f3b60a0b82950f9a3fc1eb2ad2101a905aea6ba6ca4cc67eb
|
4
|
+
data.tar.gz: 98038ba726c03fa7aeb3af77efdedcb535e6f4506fb26f0ccd5cb70456dd55f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68c0c1c2c18173314f6d8fe73a184631609ad8b9a55d95bf35a2b797814ba5a65f2037b6638917c5c09640d7e91674a0356825849b04c375c4c88a35b715e5a3
|
7
|
+
data.tar.gz: 776cc9c571fac5fec546836d4ff6fd06e55c7635c7c63f8ed529e0880c96efa21c2d087fa7baac1bdf90c16b40ef4eaa847c7bc3fcf13c5092d4ebe3afcec303
|
data/Dockerfile
CHANGED
@@ -191,5 +191,26 @@ class Morpheus::ServersInterface < Morpheus::APIClient
|
|
191
191
|
execute(opts)
|
192
192
|
end
|
193
193
|
|
194
|
+
def maintenance(serverId, payload = {}, params = {})
|
195
|
+
url = "#{@base_url}/api/servers/#{serverId}/maintenance"
|
196
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
197
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
198
|
+
execute(opts)
|
199
|
+
end
|
200
|
+
|
201
|
+
def leave_maintenance(serverId, payload = {}, params = {})
|
202
|
+
url = "#{@base_url}/api/servers/#{serverId}/leave-maintenance"
|
203
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
204
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
205
|
+
execute(opts)
|
206
|
+
end
|
207
|
+
|
208
|
+
def placement(serverId, payload = {}, params = {})
|
209
|
+
url = "#{@base_url}/api/servers/#{serverId}/placement"
|
210
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
211
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
212
|
+
execute(opts)
|
213
|
+
end
|
214
|
+
|
194
215
|
|
195
216
|
end
|
@@ -626,8 +626,10 @@ class Morpheus::Cli::Clusters
|
|
626
626
|
service_plan = prompt_service_plan(api_params, options)
|
627
627
|
|
628
628
|
if service_plan
|
629
|
-
server_payload['plan'] = {'id' => service_plan['id'], 'code' => service_plan['code']
|
629
|
+
server_payload['plan'] = {'id' => service_plan['id'], 'code' => service_plan['code']}
|
630
630
|
api_params['planId'] = service_plan['id']
|
631
|
+
plan_opts = prompt_service_plan_options(service_plan, provision_type, options)
|
632
|
+
server_payload['servicePlanOptions'] = plan_opts if plan_opts && !plan_opts.empty?
|
631
633
|
end
|
632
634
|
|
633
635
|
# Multi-disk / prompt for volumes
|
@@ -1289,7 +1291,9 @@ class Morpheus::Cli::Clusters
|
|
1289
1291
|
service_plan = prompt_service_plan({zoneId: cloud_id, siteId: cluster['site']['id'], provisionTypeId: server_type['provisionType']['id'], groupTypeId: cluster_type['id'], }, options)
|
1290
1292
|
|
1291
1293
|
if service_plan
|
1292
|
-
server_payload['plan'] = {'code' => service_plan['code']
|
1294
|
+
server_payload['plan'] = {'code' => service_plan['code']}
|
1295
|
+
plan_opts = prompt_service_plan_options(service_plan, nil, options)
|
1296
|
+
server_payload['servicePlanOptions'] = plan_opts if plan_opts && !plan_opts.empty?
|
1293
1297
|
end
|
1294
1298
|
|
1295
1299
|
if resource_pool = prompt_resource_pool(cluster, cloud, service_plan, server_type['provisionType'], options)
|
@@ -11,7 +11,8 @@ class Morpheus::Cli::Hosts
|
|
11
11
|
:run_workflow, :make_managed, :upgrade_agent, :snapshots, :software, :software_sync, :update_network_label,
|
12
12
|
{:'types' => :list_types},
|
13
13
|
{:exec => :execution_request},
|
14
|
-
:wiki, :update_wiki
|
14
|
+
:wiki, :update_wiki,
|
15
|
+
:maintenance, :leave_maintenance, :placement
|
15
16
|
alias_subcommand :details, :get
|
16
17
|
set_default_subcommand :list
|
17
18
|
|
@@ -2149,6 +2150,232 @@ EOT
|
|
2149
2150
|
end
|
2150
2151
|
end
|
2151
2152
|
|
2153
|
+
def update_network_label(args)
|
2154
|
+
options = {}
|
2155
|
+
params = {}
|
2156
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
2157
|
+
opts.banner = subcommand_usage("[server] [options]")
|
2158
|
+
opts.on('--network NETWORK', "Network Interface ID" ) do |val|
|
2159
|
+
options[:network] = val
|
2160
|
+
end
|
2161
|
+
opts.on('--label LABEL', "label") do |val|
|
2162
|
+
options[:label] = val
|
2163
|
+
end
|
2164
|
+
opts.footer = "Change the label of a Network Interface.\n" +
|
2165
|
+
"Editing an Interface will not apply changes to the physical hardware. The purpose is for a manual override or data correction (mostly for self managed or baremetal servers where cloud sync is not available)\n" +
|
2166
|
+
"[name or id] is required. The name or the id of the server.\n" +
|
2167
|
+
"[network] ID of the Network Interface. (optional).\n" +
|
2168
|
+
"[label] New Label name for the Network Interface (optional)"
|
2169
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
2170
|
+
end
|
2171
|
+
optparse.parse!(args)
|
2172
|
+
if args.count != 1
|
2173
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
|
2174
|
+
return 1
|
2175
|
+
end
|
2176
|
+
connect(options)
|
2177
|
+
|
2178
|
+
begin
|
2179
|
+
host = find_host_by_name_or_id(args[0])
|
2180
|
+
return 1 if host.nil?
|
2181
|
+
|
2182
|
+
network_id = options[:network]
|
2183
|
+
if network_id != nil && network_id.to_i == 0
|
2184
|
+
print_red_alert "network must be an ID/integer above 0, not a name/string value."
|
2185
|
+
network_id = nil
|
2186
|
+
end
|
2187
|
+
|
2188
|
+
|
2189
|
+
if !network_id
|
2190
|
+
available_networks = get_available_networks(host)
|
2191
|
+
network_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'network', 'fieldLabel' => 'Network', 'type' => 'select', 'selectOptions' => available_networks, 'required' => true, 'defaultValue' => available_networks[0], 'description' => "The networks available for relabeling"}], options[:options])
|
2192
|
+
network_id = network_prompt['network']
|
2193
|
+
end
|
2194
|
+
|
2195
|
+
label = options[:label]
|
2196
|
+
while label.nil? do
|
2197
|
+
label_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'label', 'fieldLabel' => 'Label', 'type' => 'text', 'required' => true}], options[:options])
|
2198
|
+
label = label_prompt['label']
|
2199
|
+
end
|
2200
|
+
payload = { "name" => label }
|
2201
|
+
if options[:dry_run]
|
2202
|
+
print_dry_run @servers_interface.dry.update_network_label(network_id, host["id"], payload)
|
2203
|
+
return
|
2204
|
+
end
|
2205
|
+
json_response = @servers_interface.update_network_label(network_id, host["id"], payload)
|
2206
|
+
if options[:json]
|
2207
|
+
puts as_json(json_response, options)
|
2208
|
+
else
|
2209
|
+
print_green_success "Updated label for host #{host['name']} network #{network_id} to #{label}"
|
2210
|
+
end
|
2211
|
+
return 0
|
2212
|
+
rescue RestClient::Exception => e
|
2213
|
+
print_rest_exception(e, options)
|
2214
|
+
exit 1
|
2215
|
+
end
|
2216
|
+
end
|
2217
|
+
|
2218
|
+
|
2219
|
+
def maintenance(args)
|
2220
|
+
options = {}
|
2221
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
2222
|
+
opts.banner = subcommand_usage("[host]")
|
2223
|
+
build_standard_update_options(opts, options, [:auto_confirm])
|
2224
|
+
opts.footer = <<-EOT
|
2225
|
+
Enable maintenance mode for a host.
|
2226
|
+
[host] is required. This is the name or id of a host.
|
2227
|
+
EOT
|
2228
|
+
end
|
2229
|
+
optparse.parse!(args)
|
2230
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
2231
|
+
connect(options)
|
2232
|
+
|
2233
|
+
server = find_host_by_name_or_id(args[0])
|
2234
|
+
return 1 if server.nil?
|
2235
|
+
|
2236
|
+
# Just let the API return this error instead
|
2237
|
+
|
2238
|
+
# # load server type to determine if maintenance mode is supported
|
2239
|
+
# server_type_id = server['computeServerType']['id']
|
2240
|
+
# server_type = @server_types_interface.get(server_type_id)['serverType']
|
2241
|
+
# if !server_type['hasMaintenanceMode']
|
2242
|
+
# raise_command_error "Server type does not support maintenance mode"
|
2243
|
+
# end
|
2244
|
+
|
2245
|
+
payload = {}
|
2246
|
+
if options[:payload]
|
2247
|
+
payload = options[:payload]
|
2248
|
+
payload.deep_merge!(parse_passed_options(options))
|
2249
|
+
else
|
2250
|
+
payload.deep_merge!(parse_passed_options(options))
|
2251
|
+
end
|
2252
|
+
params = {}
|
2253
|
+
params.merge!(parse_query_options(options))
|
2254
|
+
|
2255
|
+
confirm!("Are you sure you would like to enable maintenance mode on host '#{server['name']}'?", options)
|
2256
|
+
|
2257
|
+
@servers_interface.setopts(options)
|
2258
|
+
if options[:dry_run]
|
2259
|
+
print_dry_run @servers_interface.dry.maintenance(server['id'], payload, params)
|
2260
|
+
return
|
2261
|
+
end
|
2262
|
+
json_response = @servers_interface.maintenance(server['id'], payload, params)
|
2263
|
+
render_response(json_response, options) do
|
2264
|
+
print_green_success "Maintenance mode enabled for host #{server['name']}"
|
2265
|
+
#get([server['id']])
|
2266
|
+
end
|
2267
|
+
return 0, nil
|
2268
|
+
end
|
2269
|
+
|
2270
|
+
def leave_maintenance(args)
|
2271
|
+
options = {}
|
2272
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
2273
|
+
opts.banner = subcommand_usage("[host]")
|
2274
|
+
build_standard_update_options(opts, options, [:auto_confirm])
|
2275
|
+
opts.footer = <<-EOT
|
2276
|
+
Disable maintenance mode for a host.
|
2277
|
+
[host] is required. This is the name or id of a host.
|
2278
|
+
EOT
|
2279
|
+
end
|
2280
|
+
optparse.parse!(args)
|
2281
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
2282
|
+
connect(options)
|
2283
|
+
|
2284
|
+
server = find_host_by_name_or_id(args[0])
|
2285
|
+
return 1 if server.nil?
|
2286
|
+
|
2287
|
+
# Just let the API return this error instead
|
2288
|
+
|
2289
|
+
# # load server type to determine if maintenance mode is supported
|
2290
|
+
# server_type_id = server['computeServerType']['id']
|
2291
|
+
# server_type = @server_types_interface.get(server_type_id)['serverType']
|
2292
|
+
# if !server_type['hasMaintenanceMode']
|
2293
|
+
# raise_command_error "Server type does not support maintenance mode"
|
2294
|
+
# end
|
2295
|
+
|
2296
|
+
payload = {}
|
2297
|
+
if options[:payload]
|
2298
|
+
payload = options[:payload]
|
2299
|
+
payload.deep_merge!(parse_passed_options(options))
|
2300
|
+
else
|
2301
|
+
payload.deep_merge!(parse_passed_options(options))
|
2302
|
+
end
|
2303
|
+
params = {}
|
2304
|
+
params.merge!(parse_query_options(options))
|
2305
|
+
|
2306
|
+
confirm!("Are you sure you would like to leave maintenance mode on host '#{server['name']}'?", options)
|
2307
|
+
|
2308
|
+
@servers_interface.setopts(options)
|
2309
|
+
if options[:dry_run]
|
2310
|
+
print_dry_run @servers_interface.dry.leave_maintenance(server['id'], payload, params)
|
2311
|
+
return
|
2312
|
+
end
|
2313
|
+
json_response = @servers_interface.leave_maintenance(server['id'], payload, params)
|
2314
|
+
render_response(json_response, options) do
|
2315
|
+
print_green_success "Maintenance mode enabled for host #{server['name']}"
|
2316
|
+
#get([server['id']])
|
2317
|
+
end
|
2318
|
+
return 0, nil
|
2319
|
+
end
|
2320
|
+
|
2321
|
+
def placement(args)
|
2322
|
+
options = {}
|
2323
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
2324
|
+
opts.banner = subcommand_usage("[host]")
|
2325
|
+
build_standard_update_options(opts, options, [:auto_confirm])
|
2326
|
+
opts.footer = <<-EOT
|
2327
|
+
Update placement for a host.
|
2328
|
+
[host] is required. This is the name or id of a host.
|
2329
|
+
EOT
|
2330
|
+
end
|
2331
|
+
optparse.parse!(args)
|
2332
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
2333
|
+
connect(options)
|
2334
|
+
|
2335
|
+
server = find_host_by_name_or_id(args[0])
|
2336
|
+
return 1 if server.nil?
|
2337
|
+
payload = {}
|
2338
|
+
if options[:payload]
|
2339
|
+
payload = options[:payload]
|
2340
|
+
payload.deep_merge!({'server' => parse_passed_options(options)})
|
2341
|
+
else
|
2342
|
+
payload.deep_merge!({'server' => parse_passed_options(options)})
|
2343
|
+
# prompt
|
2344
|
+
# Host (preferredParentServer.id)
|
2345
|
+
if payload['server']['host']
|
2346
|
+
options[:options] = payload['server'].remove('host')
|
2347
|
+
end
|
2348
|
+
default_host = (server['preferredParentServer'] ? server['preferredParentServer']['id'] : (server['parentServer'] ? server['parentServer']['id'] : nil))
|
2349
|
+
host = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'host', 'type' => 'select', 'fieldLabel' => 'Host', 'optionSource' => 'parentServers', 'required' => false, 'description' => 'Choose the preferred parent host for this virtual machine to be placed on.', 'defaultValue' => default_host}],options[:options],@api_client,{'serverId' => server['id']})['host']
|
2350
|
+
if !host.to_s.empty?
|
2351
|
+
payload['server']['preferredParentServer'] = {'id' => host}
|
2352
|
+
end
|
2353
|
+
|
2354
|
+
|
2355
|
+
# Placement Strategy (placementStrategy)
|
2356
|
+
placement_strategy = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'placementStrategy', 'type' => 'select', 'fieldLabel' => 'Placement Strategy', 'optionSource' => 'placementStrategies', 'required' => false, 'description' => 'Choose the placement strategy for this virtual machine.', 'defaultValue' => server['placementStrategy']}],options[:options],@api_client,{'serverId' => server['id']})['placementStrategy']
|
2357
|
+
if !placement_strategy.to_s.empty?
|
2358
|
+
payload['server']['placementStrategy'] = placement_strategy
|
2359
|
+
end
|
2360
|
+
end
|
2361
|
+
params = {}
|
2362
|
+
params.merge!(parse_query_options(options))
|
2363
|
+
|
2364
|
+
confirm!("Are you sure you would like to update placement for host '#{server['name']}'?", options)
|
2365
|
+
|
2366
|
+
@servers_interface.setopts(options)
|
2367
|
+
if options[:dry_run]
|
2368
|
+
print_dry_run @servers_interface.dry.placement(server['id'], payload, params)
|
2369
|
+
return
|
2370
|
+
end
|
2371
|
+
json_response = @servers_interface.placement(server['id'], payload, params)
|
2372
|
+
render_response(json_response, options) do
|
2373
|
+
print_green_success "Maintenance mode enabled for host #{server['name']}"
|
2374
|
+
#get([server['id']])
|
2375
|
+
end
|
2376
|
+
return 0, nil
|
2377
|
+
end
|
2378
|
+
|
2152
2379
|
private
|
2153
2380
|
|
2154
2381
|
def find_host_by_id(id)
|
@@ -2297,71 +2524,6 @@ EOT
|
|
2297
2524
|
out
|
2298
2525
|
end
|
2299
2526
|
|
2300
|
-
def update_network_label(args)
|
2301
|
-
options = {}
|
2302
|
-
params = {}
|
2303
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
2304
|
-
opts.banner = subcommand_usage("[server] [options]")
|
2305
|
-
opts.on('--network NETWORK', "Network Interface ID" ) do |val|
|
2306
|
-
options[:network] = val
|
2307
|
-
end
|
2308
|
-
opts.on('--label LABEL', "label") do |val|
|
2309
|
-
options[:label] = val
|
2310
|
-
end
|
2311
|
-
opts.footer = "Change the label of a Network Interface.\n" +
|
2312
|
-
"Editing an Interface will not apply changes to the physical hardware. The purpose is for a manual override or data correction (mostly for self managed or baremetal servers where cloud sync is not available)\n" +
|
2313
|
-
"[name or id] is required. The name or the id of the server.\n" +
|
2314
|
-
"[network] ID of the Network Interface. (optional).\n" +
|
2315
|
-
"[label] New Label name for the Network Interface (optional)"
|
2316
|
-
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
2317
|
-
end
|
2318
|
-
optparse.parse!(args)
|
2319
|
-
if args.count != 1
|
2320
|
-
puts_error "#{Morpheus::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
|
2321
|
-
return 1
|
2322
|
-
end
|
2323
|
-
connect(options)
|
2324
|
-
|
2325
|
-
begin
|
2326
|
-
host = find_host_by_name_or_id(args[0])
|
2327
|
-
return 1 if host.nil?
|
2328
|
-
|
2329
|
-
network_id = options[:network]
|
2330
|
-
if network_id != nil && network_id.to_i == 0
|
2331
|
-
print_red_alert "network must be an ID/integer above 0, not a name/string value."
|
2332
|
-
network_id = nil
|
2333
|
-
end
|
2334
|
-
|
2335
|
-
|
2336
|
-
if !network_id
|
2337
|
-
available_networks = get_available_networks(host)
|
2338
|
-
network_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'network', 'fieldLabel' => 'Network', 'type' => 'select', 'selectOptions' => available_networks, 'required' => true, 'defaultValue' => available_networks[0], 'description' => "The networks available for relabeling"}], options[:options])
|
2339
|
-
network_id = network_prompt['network']
|
2340
|
-
end
|
2341
|
-
|
2342
|
-
label = options[:label]
|
2343
|
-
while label.nil? do
|
2344
|
-
label_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'label', 'fieldLabel' => 'Label', 'type' => 'text', 'required' => true}], options[:options])
|
2345
|
-
label = label_prompt['label']
|
2346
|
-
end
|
2347
|
-
payload = { "name" => label }
|
2348
|
-
if options[:dry_run]
|
2349
|
-
print_dry_run @servers_interface.dry.update_network_label(network_id, host["id"], payload)
|
2350
|
-
return
|
2351
|
-
end
|
2352
|
-
json_response = @servers_interface.update_network_label(network_id, host["id"], payload)
|
2353
|
-
if options[:json]
|
2354
|
-
puts as_json(json_response, options)
|
2355
|
-
else
|
2356
|
-
print_green_success "Updated label for host #{host['name']} network #{network_id} to #{label}"
|
2357
|
-
end
|
2358
|
-
return 0
|
2359
|
-
rescue RestClient::Exception => e
|
2360
|
-
print_rest_exception(e, options)
|
2361
|
-
exit 1
|
2362
|
-
end
|
2363
|
-
end
|
2364
|
-
|
2365
2527
|
def get_available_networks(host)
|
2366
2528
|
results = @options_interface.options_for_source('availableNetworksForHost',{serverId: host['id'].to_i})
|
2367
2529
|
available_networks = results['data'].collect {|it|
|
@@ -127,7 +127,6 @@ class Morpheus::Cli::ProvisioningLicensesCommand
|
|
127
127
|
{"Copies" => lambda {|license|
|
128
128
|
"#{license['reservationCount']}/#{license['copies']}"
|
129
129
|
} },
|
130
|
-
{"Description" => lambda {|license| license['description'] } },
|
131
130
|
{"Virtual Images" => lambda {|it| it['virtualImages'] ? it['virtualImages'].collect {|v| v['name']}.join(', ') : '' } },
|
132
131
|
{"Tenants" => lambda {|it| it['tenants'] ? it['tenants'].collect {|acnt| acnt['name']}.join(', ') : '' } },
|
133
132
|
]
|
@@ -1722,6 +1722,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1722
1722
|
|
1723
1723
|
if ip_required == false && network_interface['ipAddress'] == nil && selected_network['dhcpServer'] == true
|
1724
1724
|
network_interface['ipMode'] = 'dhcp'
|
1725
|
+
elsif network_interface['ipAddress']
|
1726
|
+
network_interface['ipMode'] = 'static'
|
1725
1727
|
end
|
1726
1728
|
|
1727
1729
|
network_interfaces << network_interface
|
data/lib/morpheus/cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.
|
4
|
+
version: 7.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2024-
|
14
|
+
date: 2024-09-11 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: public_suffix
|