morpheus-cli 5.3.0 → 5.3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/README.md +1 -3
  4. data/lib/morpheus/api/account_groups_interface.rb +0 -6
  5. data/lib/morpheus/api/accounts_interface.rb +1 -7
  6. data/lib/morpheus/api/api_client.rb +155 -119
  7. data/lib/morpheus/api/appliance_settings_interface.rb +6 -9
  8. data/lib/morpheus/api/approvals_interface.rb +5 -8
  9. data/lib/morpheus/api/apps_interface.rb +0 -7
  10. data/lib/morpheus/api/archive_buckets_interface.rb +9 -16
  11. data/lib/morpheus/api/archive_files_interface.rb +0 -6
  12. data/lib/morpheus/api/auth_interface.rb +4 -4
  13. data/lib/morpheus/api/backup_settings_interface.rb +5 -8
  14. data/lib/morpheus/api/blueprints_interface.rb +1 -7
  15. data/lib/morpheus/api/budgets_interface.rb +0 -6
  16. data/lib/morpheus/api/certificate_types_interface.rb +14 -0
  17. data/lib/morpheus/api/certificates_interface.rb +9 -0
  18. data/lib/morpheus/api/cloud_datastores_interface.rb +0 -6
  19. data/lib/morpheus/api/cloud_folders_interface.rb +1 -7
  20. data/lib/morpheus/api/cloud_policies_interface.rb +0 -6
  21. data/lib/morpheus/api/cloud_resource_pools_interface.rb +0 -6
  22. data/lib/morpheus/api/clouds_interface.rb +0 -6
  23. data/lib/morpheus/api/clusters_interface.rb +39 -42
  24. data/lib/morpheus/api/containers_interface.rb +0 -6
  25. data/lib/morpheus/api/custom_instance_types_interface.rb +0 -6
  26. data/lib/morpheus/api/cypher_interface.rb +0 -6
  27. data/lib/morpheus/api/datastores_interface.rb +4 -7
  28. data/lib/morpheus/api/deploy_interface.rb +1 -6
  29. data/lib/morpheus/api/environments_interface.rb +0 -6
  30. data/lib/morpheus/api/execute_schedules_interface.rb +0 -6
  31. data/lib/morpheus/api/execution_request_interface.rb +0 -6
  32. data/lib/morpheus/api/file_copy_request_interface.rb +2 -9
  33. data/lib/morpheus/api/group_policies_interface.rb +0 -6
  34. data/lib/morpheus/api/groups_interface.rb +0 -7
  35. data/lib/morpheus/api/guidance_interface.rb +9 -12
  36. data/lib/morpheus/api/health_interface.rb +0 -6
  37. data/lib/morpheus/api/image_builder_boot_scripts_interface.rb +0 -6
  38. data/lib/morpheus/api/image_builder_image_builds_interface.rb +0 -6
  39. data/lib/morpheus/api/image_builder_interface.rb +3 -9
  40. data/lib/morpheus/api/image_builder_preseed_scripts_interface.rb +0 -6
  41. data/lib/morpheus/api/instance_types_interface.rb +0 -7
  42. data/lib/morpheus/api/instances_interface.rb +8 -19
  43. data/lib/morpheus/api/integration_types_interface.rb +14 -0
  44. data/lib/morpheus/api/integrations_interface.rb +36 -21
  45. data/lib/morpheus/api/invoice_line_items_interface.rb +4 -9
  46. data/lib/morpheus/api/jobs_interface.rb +11 -14
  47. data/lib/morpheus/api/key_pairs_interface.rb +0 -6
  48. data/lib/morpheus/api/library_cluster_layouts_interface.rb +0 -6
  49. data/lib/morpheus/api/library_container_scripts_interface.rb +0 -6
  50. data/lib/morpheus/api/library_container_templates_interface.rb +0 -6
  51. data/lib/morpheus/api/library_container_types_interface.rb +0 -6
  52. data/lib/morpheus/api/library_container_upgrades_interface.rb +0 -6
  53. data/lib/morpheus/api/library_instance_types_interface.rb +0 -6
  54. data/lib/morpheus/api/library_layouts_interface.rb +0 -6
  55. data/lib/morpheus/api/library_spec_template_types_interface.rb +0 -6
  56. data/lib/morpheus/api/library_spec_templates_interface.rb +0 -6
  57. data/lib/morpheus/api/license_interface.rb +0 -6
  58. data/lib/morpheus/api/load_balancers_interface.rb +0 -6
  59. data/lib/morpheus/api/log_settings_interface.rb +9 -12
  60. data/lib/morpheus/api/logs_interface.rb +0 -6
  61. data/lib/morpheus/api/monitoring_alerts_interface.rb +0 -6
  62. data/lib/morpheus/api/monitoring_apps_interface.rb +0 -6
  63. data/lib/morpheus/api/monitoring_checks_interface.rb +0 -6
  64. data/lib/morpheus/api/monitoring_contacts_interface.rb +0 -6
  65. data/lib/morpheus/api/monitoring_groups_interface.rb +0 -6
  66. data/lib/morpheus/api/monitoring_incidents_interface.rb +0 -6
  67. data/lib/morpheus/api/monitoring_interface.rb +6 -12
  68. data/lib/morpheus/api/network_domain_records_interface.rb +0 -6
  69. data/lib/morpheus/api/network_domains_interface.rb +0 -6
  70. data/lib/morpheus/api/network_groups_interface.rb +0 -6
  71. data/lib/morpheus/api/network_pool_ips_interface.rb +0 -6
  72. data/lib/morpheus/api/network_pool_servers_interface.rb +0 -6
  73. data/lib/morpheus/api/network_pools_interface.rb +0 -6
  74. data/lib/morpheus/api/network_proxies_interface.rb +0 -6
  75. data/lib/morpheus/api/network_routers_interface.rb +0 -6
  76. data/lib/morpheus/api/network_security_servers_interface.rb +6 -9
  77. data/lib/morpheus/api/network_services_interface.rb +14 -14
  78. data/lib/morpheus/api/network_subnets_interface.rb +0 -6
  79. data/lib/morpheus/api/network_types_interface.rb +1 -7
  80. data/lib/morpheus/api/networks_interface.rb +0 -6
  81. data/lib/morpheus/api/option_type_lists_interface.rb +0 -6
  82. data/lib/morpheus/api/option_types_interface.rb +0 -6
  83. data/lib/morpheus/api/options_interface.rb +0 -6
  84. data/lib/morpheus/api/packages_interface.rb +0 -6
  85. data/lib/morpheus/api/policies_interface.rb +1 -8
  86. data/lib/morpheus/api/power_schedules_interface.rb +0 -6
  87. data/lib/morpheus/api/price_sets_interface.rb +8 -11
  88. data/lib/morpheus/api/prices_interface.rb +12 -15
  89. data/lib/morpheus/api/processes_interface.rb +0 -6
  90. data/lib/morpheus/api/provision_types_interface.rb +0 -6
  91. data/lib/morpheus/api/provisioning_license_types_interface.rb +0 -6
  92. data/lib/morpheus/api/provisioning_licenses_interface.rb +0 -6
  93. data/lib/morpheus/api/provisioning_settings_interface.rb +6 -9
  94. data/lib/morpheus/api/read_interface.rb +23 -0
  95. data/lib/morpheus/api/reports_interface.rb +0 -6
  96. data/lib/morpheus/api/rest_interface.rb +12 -10
  97. data/lib/morpheus/api/roles_interface.rb +7 -6
  98. data/lib/morpheus/api/security_group_rules_interface.rb +0 -7
  99. data/lib/morpheus/api/security_groups_interface.rb +0 -6
  100. data/lib/morpheus/api/server_types_interface.rb +0 -6
  101. data/lib/morpheus/api/servers_interface.rb +7 -6
  102. data/lib/morpheus/api/service_plans_interface.rb +11 -14
  103. data/lib/morpheus/api/storage_providers_interface.rb +9 -16
  104. data/lib/morpheus/api/subnet_types_interface.rb +1 -7
  105. data/lib/morpheus/api/subnets_interface.rb +0 -6
  106. data/lib/morpheus/api/task_sets_interface.rb +0 -6
  107. data/lib/morpheus/api/tasks_interface.rb +0 -6
  108. data/lib/morpheus/api/user_groups_interface.rb +0 -6
  109. data/lib/morpheus/api/user_settings_interface.rb +38 -18
  110. data/lib/morpheus/api/user_sources_interface.rb +0 -6
  111. data/lib/morpheus/api/users_interface.rb +0 -6
  112. data/lib/morpheus/api/vdi_allocations_interface.rb +9 -0
  113. data/lib/morpheus/api/vdi_apps_interface.rb +9 -0
  114. data/lib/morpheus/api/vdi_gateways_interface.rb +9 -0
  115. data/lib/morpheus/api/vdi_interface.rb +28 -0
  116. data/lib/morpheus/api/vdi_pools_interface.rb +19 -0
  117. data/lib/morpheus/api/virtual_images_interface.rb +0 -6
  118. data/lib/morpheus/api/whitelabel_settings_interface.rb +8 -11
  119. data/lib/morpheus/api/wiki_interface.rb +0 -6
  120. data/lib/morpheus/cli.rb +9 -2
  121. data/lib/morpheus/cli/access_token_command.rb +1 -1
  122. data/lib/morpheus/cli/account_groups_command.rb +4 -4
  123. data/lib/morpheus/cli/apps.rb +68 -84
  124. data/lib/morpheus/cli/archives_command.rb +5 -5
  125. data/lib/morpheus/cli/blueprints_command.rb +5 -5
  126. data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
  127. data/lib/morpheus/cli/catalog_item_types_command.rb +13 -13
  128. data/lib/morpheus/cli/certificates_command.rb +575 -0
  129. data/lib/morpheus/cli/change_password_command.rb +4 -4
  130. data/lib/morpheus/cli/cli_command.rb +63 -7
  131. data/lib/morpheus/cli/clouds.rb +3 -2
  132. data/lib/morpheus/cli/clusters.rb +7 -4
  133. data/lib/morpheus/cli/commands/standard/history_command.rb +4 -5
  134. data/lib/morpheus/cli/commands/standard/man_command.rb +4 -5
  135. data/lib/morpheus/cli/credentials.rb +4 -11
  136. data/lib/morpheus/cli/environments_command.rb +1 -1
  137. data/lib/morpheus/cli/execute_schedules_command.rb +3 -3
  138. data/lib/morpheus/cli/hosts.rb +253 -232
  139. data/lib/morpheus/cli/image_builder_command.rb +6 -6
  140. data/lib/morpheus/cli/instance_types.rb +1 -1
  141. data/lib/morpheus/cli/instances.rb +196 -186
  142. data/lib/morpheus/cli/integrations_command.rb +1155 -42
  143. data/lib/morpheus/cli/invoices_command.rb +75 -67
  144. data/lib/morpheus/cli/key_pairs.rb +2 -2
  145. data/lib/morpheus/cli/library_container_scripts_command.rb +1 -1
  146. data/lib/morpheus/cli/library_container_templates_command.rb +1 -1
  147. data/lib/morpheus/cli/library_container_types_command.rb +6 -6
  148. data/lib/morpheus/cli/library_instance_types_command.rb +4 -4
  149. data/lib/morpheus/cli/library_layouts_command.rb +5 -5
  150. data/lib/morpheus/cli/library_option_lists_command.rb +4 -4
  151. data/lib/morpheus/cli/library_option_types_command.rb +4 -4
  152. data/lib/morpheus/cli/library_upgrades_command.rb +6 -6
  153. data/lib/morpheus/cli/license.rb +2 -2
  154. data/lib/morpheus/cli/load_balancers.rb +1 -1
  155. data/lib/morpheus/cli/login.rb +10 -1
  156. data/lib/morpheus/cli/mixins/option_source_helper.rb +15 -16
  157. data/lib/morpheus/cli/mixins/print_helper.rb +33 -18
  158. data/lib/morpheus/cli/mixins/provisioning_helper.rb +4 -4
  159. data/lib/morpheus/cli/mixins/vdi_helper.rb +246 -0
  160. data/lib/morpheus/cli/network_domains_command.rb +2 -2
  161. data/lib/morpheus/cli/network_routers_command.rb +22 -9
  162. data/lib/morpheus/cli/networks_command.rb +2 -2
  163. data/lib/morpheus/cli/option_types.rb +39 -34
  164. data/lib/morpheus/cli/policies_command.rb +0 -1
  165. data/lib/morpheus/cli/power_schedules_command.rb +3 -3
  166. data/lib/morpheus/cli/preseed_scripts_command.rb +1 -1
  167. data/lib/morpheus/cli/remote.rb +2 -2
  168. data/lib/morpheus/cli/reports_command.rb +5 -2
  169. data/lib/morpheus/cli/roles.rb +224 -64
  170. data/lib/morpheus/cli/security_group_rules.rb +1 -1
  171. data/lib/morpheus/cli/service_plans_command.rb +4 -1
  172. data/lib/morpheus/cli/setup.rb +0 -1
  173. data/lib/morpheus/cli/subnets_command.rb +11 -2
  174. data/lib/morpheus/cli/tenants_command.rb +3 -3
  175. data/lib/morpheus/cli/user_groups_command.rb +3 -3
  176. data/lib/morpheus/cli/user_settings_command.rb +268 -57
  177. data/lib/morpheus/cli/user_sources_command.rb +3 -3
  178. data/lib/morpheus/cli/users.rb +3 -3
  179. data/lib/morpheus/cli/vdi_allocations_command.rb +159 -0
  180. data/lib/morpheus/cli/vdi_apps_command.rb +317 -0
  181. data/lib/morpheus/cli/vdi_command.rb +359 -0
  182. data/lib/morpheus/cli/vdi_gateways_command.rb +290 -0
  183. data/lib/morpheus/cli/vdi_pools_command.rb +571 -0
  184. data/lib/morpheus/cli/version.rb +1 -1
  185. data/lib/morpheus/cli/virtual_images.rb +1 -1
  186. data/lib/morpheus/cli/whoami.rb +0 -15
  187. data/lib/morpheus/cli/wiki_command.rb +1 -1
  188. data/lib/morpheus/rest_client.rb +30 -0
  189. data/lib/morpheus/terminal.rb +15 -7
  190. metadata +18 -2
@@ -48,9 +48,9 @@ class Morpheus::Cli::ArchivesCommand
48
48
 
49
49
  def connect(opts)
50
50
  @api_client = establish_remote_appliance_connection(opts)
51
- @archive_buckets_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).archive_buckets
52
- @archive_files_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).archive_files
53
- @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
51
+ @archive_buckets_interface = @api_client.archive_buckets
52
+ @archive_files_interface = @api_client.archive_files
53
+ @options_interface = @api_client.options
54
54
  # @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
55
55
  end
56
56
 
@@ -979,10 +979,10 @@ class Morpheus::Cli::ArchivesCommand
979
979
 
980
980
 
981
981
  print_h2 "Download URLs"
982
- private_download_url = "#{@appliance_url}/api/archives/download/#{URI.escape(bucket_id)}" + "/#{URI.escape(archive_file['filePath'])}".squeeze('/')
982
+ private_download_url = "#{@appliance_url}/api/archives/download/#{CGI::escape(bucket_id)}" + "/#{CGI::escape(archive_file['filePath'])}".squeeze('/')
983
983
  public_download_url = nil
984
984
  if archive_file['archiveBucket'] && archive_file['archiveBucket']['isPublic']
985
- public_download_url = "#{@appliance_url}/public-archives/download/#{URI.escape(bucket_id)}" + "/#{URI.escape(archive_file['filePath'])}".squeeze('/')
985
+ public_download_url = "#{@appliance_url}/public-archives/download/#{CGI::escape(bucket_id)}" + "/#{CGI::escape(archive_file['filePath'])}".squeeze('/')
986
986
  end
987
987
  print cyan
988
988
  puts "Private URL: #{private_download_url}"
@@ -29,11 +29,11 @@ class Morpheus::Cli::BlueprintsCommand
29
29
 
30
30
  def connect(opts)
31
31
  @api_client = establish_remote_appliance_connection(opts)
32
- @blueprints_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).blueprints
33
- @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
34
- @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
35
- @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
36
- @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
32
+ @blueprints_interface = @api_client.blueprints
33
+ @groups_interface = @api_client.groups
34
+ @instances_interface = @api_client.instances
35
+ @instance_types_interface = @api_client.instance_types
36
+ @options_interface = @api_client.options
37
37
  @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
38
38
  @clouds_interface = @api_client.clouds
39
39
  @users_interface = @api_client.users
@@ -24,7 +24,7 @@ class Morpheus::Cli::BootScriptsCommand
24
24
 
25
25
  def connect(opts)
26
26
  @api_client = establish_remote_appliance_connection(opts)
27
- @image_builder_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).image_builder
27
+ @image_builder_interface = @api_client.image_builder
28
28
  @boot_scripts_interface = @image_builder_interface.boot_scripts
29
29
  end
30
30
 
@@ -532,22 +532,22 @@ EOT
532
532
 
533
533
  def add_catalog_item_type_option_types
534
534
  [
535
- {'code' => 'catalogItemType.type', 'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true},
536
- {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
537
- {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
538
- {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true},
539
- {'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false},
540
- {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true},
541
- {'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList'},
542
- #{'fieldName' => 'optionTypes', 'fieldLabel' => 'Option Types', 'type' => 'text', 'description' => 'Option Types to include, comma separated list of names or IDs.'},
543
- {'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true},
544
- {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true},
545
- {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true},
546
- {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'noParams' => true},
535
+ {'code' => 'catalogItemType.type', 'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true, 'displayOrder' => 1},
536
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 2},
537
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 3},
538
+ {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true, 'displayOrder' => 4},
539
+ {'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 5},
540
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true, 'displayOrder' => 6},
541
+ {'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList', 'displayOrder' => 7},
542
+ #{'fieldName' => 'optionTypes', 'fieldLabel' => 'Option Types', 'type' => 'text', 'description' => 'Option Types to include, comma separated list of names or IDs.', 'displayOrder' => 8},
543
+ {'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true, 'displayOrder' => 9},
544
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true, 'displayOrder' => 10},
545
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true, 'displayOrder' => 11},
546
+ {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'noParams' => true, 'displayOrder' => 12},
547
547
  {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
548
548
  [{'name' => "Select", 'value' => ""}, {'name' => "None", 'value' => "appliance"}, {'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
549
549
  }, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'Select', 'required' => false},
550
- {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item'}
550
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item', 'displayOrder' => 13}
551
551
  ]
552
552
  end
553
553
 
@@ -0,0 +1,575 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::CertificatesCommand
4
+ include Morpheus::Cli::CliCommand
5
+
6
+ set_command_name :'certificates'
7
+ set_command_description "Certificates: View and manage SSL certificates."
8
+
9
+ register_subcommands :list, :get, :add, :update, :remove
10
+ register_subcommands :list_types, :get_type
11
+
12
+ def connect(opts)
13
+ @api_client = establish_remote_appliance_connection(opts)
14
+ @certificates_interface = @api_client.certificates
15
+ @certificate_types_interface = @api_client.certificate_types
16
+ end
17
+
18
+ def handle(args)
19
+ handle_subcommand(args)
20
+ end
21
+
22
+ def list(args)
23
+ options = {}
24
+ params = {}
25
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
26
+ opts.banner = subcommand_usage("[search]")
27
+ build_standard_list_options(opts, options)
28
+ opts.footer = "List certificates."
29
+ end
30
+ optparse.parse!(args)
31
+ if args.count > 0
32
+ options[:phrase] = args.join(" ")
33
+ end
34
+ connect(options)
35
+ params.merge!(parse_list_options(options))
36
+ @certificates_interface.setopts(options)
37
+ if options[:dry_run]
38
+ print_dry_run @certificates_interface.dry.list(params)
39
+ return
40
+ end
41
+ json_response = @certificates_interface.list(params)
42
+ render_response(json_response, options, certificate_list_key) do
43
+ certificates = json_response[certificate_list_key]
44
+ print_h1 "Morpheus Certificates", parse_list_subtitles(options), options
45
+ if certificates.empty?
46
+ print cyan,"No certificates found.",reset,"\n"
47
+ else
48
+ list_columns = {
49
+ "ID" => 'id',
50
+ "Name" => 'name',
51
+ "Issued To" => lambda {|it| it['commonName'] },
52
+ "Cert Type" => lambda {|it| it['certType'] },
53
+ "Domain Name" => lambda {|it| it['domainName'] },
54
+ }.upcase_keys!
55
+ print as_pretty_table(certificates, list_columns, options)
56
+ print_results_pagination(json_response)
57
+ end
58
+ print reset,"\n"
59
+ end
60
+ return 0, nil
61
+ end
62
+
63
+ def get(args)
64
+ params = {}
65
+ options = {}
66
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
67
+ opts.banner = subcommand_usage("[certificate]")
68
+ build_standard_get_options(opts, options)
69
+ opts.footer = <<-EOT
70
+ Get details about a specific certificate.
71
+ [certificate] is required. This is the name or id of a certificate.
72
+ EOT
73
+ end
74
+ optparse.parse!(args)
75
+ verify_args!(args:args, optparse:optparse, min:1)
76
+ connect(options)
77
+ params.merge!(parse_query_options(options))
78
+ id_list = parse_id_list(args)
79
+ return run_command_for_each_arg(id_list) do |arg|
80
+ _get(arg, params, options)
81
+ end
82
+ end
83
+
84
+ def _get(id, params, options)
85
+ certificate = nil
86
+ if id.to_s !~ /\A\d{1,}\Z/
87
+ certificate = find_certificate_by_name_or_id(id)
88
+ return 1, "certificate not found for #{id}" if certificate.nil?
89
+ id = certificate['id']
90
+ end
91
+ @certificates_interface.setopts(options)
92
+ if options[:dry_run]
93
+ print_dry_run @certificates_interface.dry.get(id, params)
94
+ return
95
+ end
96
+ json_response = @certificates_interface.get(id, params)
97
+ certificate = json_response[certificate_object_key]
98
+ render_response(json_response, options, certificate_object_key) do
99
+ print_h1 "Certificate Details", [], options
100
+ print cyan
101
+ show_columns = {
102
+ "ID" => 'id',
103
+ "Name" => 'name',
104
+ "Description" => 'description',
105
+ "Issued To" => lambda {|it| it['commonName'] },
106
+ "Cert Type" => lambda {|it| it['certType'] },
107
+ "Domain Name" => lambda {|it| it['domainName'] },
108
+ "Wildcard" => lambda {|it| format_boolean(it['wildcard']) },
109
+ }
110
+ print_description_list(show_columns, certificate, options)
111
+ print reset,"\n"
112
+ end
113
+ return 0, nil
114
+ end
115
+
116
+ def add(args)
117
+ options = {}
118
+ params = {}
119
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
120
+ opts.banner = subcommand_usage("[name] -t CODE [options]")
121
+ # opts.on('-t', '--type CODE', "Certificate Type code, see `#{command_name} list-types` for available type codes") do |val|
122
+ # options[:options]['type'] = val
123
+ # end
124
+ build_option_type_options(opts, options, add_certificate_option_types)
125
+ build_option_type_options(opts, options, add_certificate_advanced_option_types)
126
+ build_standard_add_options(opts, options)
127
+ opts.footer = <<-EOT
128
+ Create a new certificate.
129
+ [name] is required. This is the name of the new certificate
130
+ Configuration options vary by certificate type.
131
+ EOT
132
+ end
133
+ optparse.parse!(args)
134
+ verify_args!(args:args, optparse:optparse, min:0, max:1)
135
+ options[:options]['name'] = args[0] if args[0]
136
+ connect(options)
137
+ payload = {}
138
+ if options[:payload]
139
+ payload = options[:payload]
140
+ payload.deep_merge!({certificate_object_key => parse_passed_options(options)})
141
+ else
142
+ payload.deep_merge!({certificate_object_key => parse_passed_options(options)})
143
+ # Type prompt first
144
+ #params['type'] = Morpheus::Cli::OptionTypes.no_prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true}], options[:options], @api_client, options[:params])['type']
145
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(add_certificate_option_types(), options[:options], @api_client, options[:params])
146
+ params.deep_merge!(v_prompt)
147
+ advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_certificate_advanced_option_types, options[:options], @api_client, options[:params])
148
+ advanced_config.deep_compact!
149
+ params.deep_merge!(advanced_config)
150
+
151
+ # lookup type by name or code to validate it exists and to prompt for its optionTypes
152
+ # set certificate.type=code because the api expects it that way.
153
+ if params['type'].to_s.empty?
154
+ raise_command_error "missing required option: --type TYPE", args, optparse
155
+ end
156
+ certificate_type = find_certificate_type_by_name_or_code_id(params['type'])
157
+ if certificate_type.nil?
158
+ print_red_alert "certificate type not found for #{params['type']}"
159
+ return 1, "certificate type not found for #{params['type']}"
160
+ end
161
+ params['type'] = certificate_type['code']
162
+ config_option_types = certificate_type['optionTypes']
163
+ if config_option_types.nil?
164
+ config_option_types = @certificate_types_interface.option_types(certificate_type['id'])['optionTypes']
165
+ end
166
+ if config_option_types.nil?
167
+ print yellow,"No option types found for certificate type: #{certificate_type['name']} (#{certificate_type['code']})", reset, "\n"
168
+ end
169
+ if config_option_types && config_option_types.size > 0
170
+ # optionTypes do not need fieldContext: 'certificate'
171
+ config_option_types.each do |opt|
172
+ if opt['fieldContext'] == 'certificate' || opt['fieldContext'] == 'domain'
173
+ opt['fieldContext'] = nil
174
+ end
175
+ end
176
+ # reject hardcoded optionTypes
177
+ config_option_types = config_option_types.reject {|it| it['fieldName'] == 'name' || it['fieldName'] == 'description' || it['fieldName'] == 'domainName' }
178
+ config_prompt = Morpheus::Cli::OptionTypes.prompt(config_option_types, options[:options], @api_client, options[:params])
179
+ config_prompt.deep_compact!
180
+ params.deep_merge!(config_prompt)
181
+ end
182
+ # convert checkbox "on" and "off" to true and false
183
+ params.booleanize!
184
+ payload[certificate_object_key].deep_merge!(params)
185
+ end
186
+ @certificates_interface.setopts(options)
187
+ if options[:dry_run]
188
+ print_dry_run @certificates_interface.dry.create(payload)
189
+ return 0, nil
190
+ end
191
+ json_response = @certificates_interface.create(payload)
192
+ certificate = json_response[certificate_object_key]
193
+ render_response(json_response, options, certificate_object_key) do
194
+ print_green_success "Added certificate #{certificate['name']}"
195
+ return _get(certificate["id"], {}, options)
196
+ end
197
+ return 0, nil
198
+ end
199
+
200
+ def update(args)
201
+ options = {}
202
+ params = {}
203
+ payload = {}
204
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
205
+ opts.banner = subcommand_usage("[certificate] [options]")
206
+ build_option_type_options(opts, options, update_certificate_option_types)
207
+ build_option_type_options(opts, options, update_certificate_advanced_option_types)
208
+ opts.on(nil, '--no-refresh', "Skip refresh on update.") do
209
+ payload['refresh'] = 'false'
210
+ end
211
+ build_standard_update_options(opts, options)
212
+ opts.footer = <<-EOT
213
+ Update a certificate.
214
+ [certificate] is required. This is the name or id of a certificate.
215
+ EOT
216
+ end
217
+ optparse.parse!(args)
218
+ verify_args!(args:args, optparse:optparse, count:1)
219
+ connect(options)
220
+ certificate = find_certificate_by_name_or_id(args[0])
221
+ return 1 if certificate.nil?
222
+ payload = {}
223
+ if options[:payload]
224
+ payload = options[:payload]
225
+ payload.deep_merge!({certificate_object_key => parse_passed_options(options)})
226
+ else
227
+ payload.deep_merge!({certificate_object_key => parse_passed_options(options)})
228
+ # do not prompt on update
229
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_certificate_option_types, options[:options], @api_client, options[:params])
230
+ v_prompt.deep_compact!
231
+ params.deep_merge!(v_prompt)
232
+ advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_certificate_advanced_option_types, options[:options], @api_client, options[:params])
233
+ advanced_config.deep_compact!
234
+ params.deep_merge!(advanced_config)
235
+ # convert checkbox "on" and "off" to true and false
236
+ params.booleanize!
237
+ payload.deep_merge!({certificate_object_key => params})
238
+ if payload[certificate_object_key].empty? # || options[:no_prompt]
239
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
240
+ end
241
+ end
242
+ @certificates_interface.setopts(options)
243
+ if options[:dry_run]
244
+ print_dry_run @certificates_interface.dry.update(certificate['id'], payload)
245
+ return
246
+ end
247
+ json_response = @certificates_interface.update(certificate['id'], payload)
248
+ certificate = json_response[certificate_object_key]
249
+ render_response(json_response, options, certificate_object_key) do
250
+ print_green_success "Updated certificate #{certificate['name']}"
251
+ return _get(certificate["id"], {}, options)
252
+ end
253
+ return 0, nil
254
+ end
255
+
256
+ def remove(args)
257
+ options = {}
258
+ params = {}
259
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
260
+ opts.banner = subcommand_usage("[certificate] [options]")
261
+ build_standard_remove_options(opts, options)
262
+ opts.footer = <<-EOT
263
+ Delete a certificate.
264
+ [certificate] is required. This is the name or id of a certificate.
265
+ EOT
266
+ end
267
+ optparse.parse!(args)
268
+ verify_args!(args:args, optparse:optparse, count:1)
269
+ connect(options)
270
+ certificate = find_certificate_by_name_or_id(args[0])
271
+ return 1 if certificate.nil?
272
+ @certificates_interface.setopts(options)
273
+ if options[:dry_run]
274
+ print_dry_run @certificates_interface.dry.destroy(certificate['id'], params)
275
+ return
276
+ end
277
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the certificate #{certificate['name']}?")
278
+ return 9, "aborted command"
279
+ end
280
+ json_response = @certificates_interface.destroy(certificate['id'], params)
281
+ render_response(json_response, options) do
282
+ print_green_success "Removed certificate #{certificate['name']}"
283
+ end
284
+ return 0, nil
285
+ end
286
+
287
+
288
+ def list_types(args)
289
+ options = {}
290
+ params = {}
291
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
292
+ opts.banner = subcommand_usage("[search]")
293
+ opts.on('--optionTypes [true|false]', String, "Include optionTypes in the response. Default is false.") do |val|
294
+ params['optionTypes'] = (val.to_s == '' || val.to_s == 'on' || val.to_s == 'true')
295
+ end
296
+ build_standard_list_options(opts, options)
297
+ opts.footer = "List certificate types."
298
+ end
299
+ optparse.parse!(args)
300
+ connect(options)
301
+ # verify_args!(args:args, optparse:optparse, count:0)
302
+ if args.count > 0
303
+ options[:phrase] = args.join(" ")
304
+ end
305
+ params.merge!(parse_list_options(options))
306
+ @certificate_types_interface.setopts(options)
307
+ if options[:dry_run]
308
+ print_dry_run @certificate_types_interface.dry.list(params)
309
+ return
310
+ end
311
+ json_response = @certificate_types_interface.list(params)
312
+ render_response(json_response, options, certificate_type_list_key) do
313
+ certificate_types = json_response[certificate_type_list_key]
314
+ print_h1 "Morpheus Certificate Types", parse_list_subtitles(options), options
315
+ if certificate_types.empty?
316
+ print cyan,"No certificate types found.",reset,"\n"
317
+ else
318
+ list_columns = certificate_type_column_definitions.upcase_keys!
319
+ print as_pretty_table(certificate_types, list_columns, options)
320
+ print_results_pagination(json_response)
321
+ end
322
+ print reset,"\n"
323
+ end
324
+ return 0, nil
325
+ end
326
+
327
+ def get_type(args)
328
+ params = {'optionTypes' => true}
329
+ options = {}
330
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
331
+ opts.banner = subcommand_usage("[type]")
332
+ opts.on('--optionTypes [true|false]', String, "Include optionTypes in the response. Default is true.") do |val|
333
+ params['optionTypes'] = (val.to_s == '' || val.to_s == 'on' || val.to_s == 'true')
334
+ end
335
+ build_standard_get_options(opts, options)
336
+ opts.footer = <<-EOT
337
+ Get details about a specific certificate type.
338
+ [type] is required. This is the name or id of a certificate type.
339
+ EOT
340
+ end
341
+ optparse.parse!(args)
342
+ verify_args!(args:args, optparse:optparse, min:1)
343
+ connect(options)
344
+ params.merge!(parse_query_options(options))
345
+ id_list = parse_id_list(args)
346
+ return run_command_for_each_arg(id_list) do |arg|
347
+ _get_type(arg, params, options)
348
+ end
349
+ end
350
+
351
+ def _get_type(id, params, options)
352
+ certificate_type = nil
353
+ if id.to_s !~ /\A\d{1,}\Z/
354
+ certificate_type = find_certificate_type_by_name_or_code(id)
355
+ return 1, "certificate type not found for name or code '#{id}'" if certificate_type.nil?
356
+ id = certificate_type['id']
357
+ end
358
+ # /api/certificate-types does not return optionTypes by default, use ?optionTypes=true
359
+ @certificate_types_interface.setopts(options)
360
+ if options[:dry_run]
361
+ print_dry_run @certificate_types_interface.dry.get(id, params)
362
+ return
363
+ end
364
+ json_response = @certificate_types_interface.get(id, params)
365
+ certificate_type = json_response[certificate_type_object_key]
366
+ render_response(json_response, options, certificate_type_object_key) do
367
+ print_h1 "Certificate Type Details", [], options
368
+ print cyan
369
+ show_columns = certificate_type_column_definitions
370
+ print_description_list(show_columns, certificate_type)
371
+
372
+ if certificate_type['optionTypes'] && certificate_type['optionTypes'].size > 0
373
+ print_h2 "Option Types"
374
+ opt_columns = [
375
+ # {"ID" => lambda {|it| it['id'] } },
376
+ {"FIELD NAME" => lambda {|it| (it['fieldContext'] && it['fieldContext'] != 'certificate') ? [it['fieldContext'], it['fieldName']].join('.') : it['fieldName'] } },
377
+ {"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
378
+ {"TYPE" => lambda {|it| it['type'] } },
379
+ {"DEFAULT" => lambda {|it| it['defaultValue'] } },
380
+ {"REQUIRED" => lambda {|it| format_boolean it['required'] } },
381
+ # {"DESCRIPTION" => lambda {|it| it['description'] }, # do it!
382
+ ]
383
+ print as_pretty_table(certificate_type['optionTypes'], opt_columns)
384
+ else
385
+ # print cyan,"No option types found for this certificate type.","\n",reset
386
+ end
387
+
388
+ print reset,"\n"
389
+ end
390
+ return 0, nil
391
+ end
392
+
393
+ private
394
+
395
+ def format_certificate_type(certificate)
396
+ (certificate['certificateType']['name'] || certificate['certificateType']['code']) rescue certificate['certificateType'].to_s
397
+ end
398
+
399
+ def add_certificate_option_types
400
+ [
401
+ {'code' => 'certificate.type', 'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
402
+ # @certificate_types_interface.list(max:-1)[certificate_list_key].collect {|it|
403
+ get_available_certificate_types().collect {|it|
404
+ {'name' => it['code'], 'value' => it['id']}
405
+ } }, 'required' => true, 'description' => "Certificate Type code, see `#{command_name} list-types` for available type codes", 'defaultValue' => "internal"},
406
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Name of the certificate'},
407
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'description' => 'Description of the certificate'},
408
+ {'fieldName' => 'domainName', 'fieldLabel' => 'Domain Name', 'type' => 'text', 'required' => false, 'description' => 'Domain Name of the certificate'},
409
+ # {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true, 'description' => 'Can be used to disable a certificate'}
410
+ ]
411
+ end
412
+
413
+ def add_certificate_advanced_option_types
414
+ []
415
+ end
416
+
417
+ def update_certificate_option_types
418
+ list = add_certificate_option_types.collect {|it|
419
+ it.delete('required')
420
+ it.delete('defaultValue')
421
+ it
422
+ }
423
+ list = list.reject {|it| ["type"].include? it['fieldName'] }
424
+ list
425
+ end
426
+
427
+ def update_certificate_advanced_option_types
428
+ add_certificate_advanced_option_types.collect {|it|
429
+ it.delete('required')
430
+ it.delete('defaultValue')
431
+ it
432
+ }
433
+ end
434
+
435
+ def certificate_object_key
436
+ 'certificate'
437
+ end
438
+
439
+ def certificate_list_key
440
+ 'certificates'
441
+ end
442
+
443
+ def find_certificate_by_name_or_id(val)
444
+ if val.to_s =~ /\A\d{1,}\Z/
445
+ return find_certificate_by_id(val)
446
+ else
447
+ return find_certificate_by_name(val)
448
+ end
449
+ end
450
+
451
+ def find_certificate_by_id(id)
452
+ begin
453
+ json_response = @certificates_interface.get(id.to_i)
454
+ return json_response[certificate_object_key]
455
+ rescue RestClient::Exception => e
456
+ if e.response && e.response.code == 404
457
+ print_red_alert "certificate not found by id '#{id}'"
458
+ else
459
+ raise e
460
+ end
461
+ end
462
+ end
463
+
464
+ def find_certificate_by_name(name)
465
+ json_response = @certificates_interface.list({name: name.to_s})
466
+ certificates = json_response[certificate_list_key]
467
+ if certificates.empty?
468
+ print_red_alert "certificate not found by name '#{name}'"
469
+ return nil
470
+ elsif certificates.size > 1
471
+ print_red_alert "#{certificates.size} certificates found by name '#{name}'"
472
+ puts_error as_pretty_table(certificates, [:id, :name], {color:red})
473
+ print_red_alert "Try using ID instead"
474
+ print reset,"\n"
475
+ return nil
476
+ else
477
+ return certificates[0]
478
+ end
479
+ end
480
+
481
+ def format_certificate_status(certificate, return_color=cyan)
482
+ out = ""
483
+ status_string = certificate['status']
484
+ if status_string.nil? || status_string.empty? || status_string == "unknown"
485
+ out << "#{white}UNKNOWN#{certificate['statusMessage'] ? "#{return_color} - #{certificate['statusMessage']}" : ''}#{return_color}"
486
+ # elsif certificate['enabled'] == false
487
+ # out << "#{red}DISABLED#{certificate['statusMessage'] ? "#{return_color} - #{certificate['statusMessage']}" : ''}#{return_color}"
488
+ elsif status_string == 'ok'
489
+ out << "#{green}#{status_string.upcase}#{return_color}"
490
+ elsif status_string == 'error' || status_string == 'offline'
491
+ out << "#{red}#{status_string ? status_string.upcase : 'N/A'}#{certificate['statusMessage'] ? "#{return_color} - #{certificate['statusMessage']}" : ''}#{return_color}"
492
+ else
493
+ out << "#{yellow}#{status_string.upcase}#{return_color}"
494
+ end
495
+ out
496
+ end
497
+
498
+
499
+ def certificate_type_column_definitions()
500
+ {
501
+ "ID" => 'id',
502
+ "Code" => 'code',
503
+ "Name" => 'name',
504
+ # "Description" => 'description',
505
+ # "Enabled" => lambda {|it| format_boolean(it['enabled']) },
506
+ "Creatable" => lambda {|it| format_boolean(it['creatable']) },
507
+ }
508
+ end
509
+
510
+ def certificate_type_object_key
511
+ 'certificateType'
512
+ end
513
+
514
+ def certificate_type_list_key
515
+ 'certificateTypes'
516
+ end
517
+
518
+ def find_certificate_type_by_name_or_code_id(val, params={})
519
+ if val.to_s =~ /\A\d{1,}\Z/
520
+ return find_certificate_type_by_id(val, params)
521
+ else
522
+ return find_certificate_type_by_name_or_code(val)
523
+ end
524
+ end
525
+
526
+ def find_certificate_type_by_id(id, params={})
527
+ begin
528
+ json_response = @certificate_types_interface.get(id.to_i, params)
529
+ return json_response[certificate_type_object_key]
530
+ rescue RestClient::Exception => e
531
+ if e.response && e.response.code == 404
532
+ print_red_alert "certificate not found by id '#{id}'"
533
+ else
534
+ raise e
535
+ end
536
+ end
537
+ end
538
+
539
+ def find_certificate_type_by_name(name, params={})
540
+ json_response = @certificate_types_interface.list(params.merge({name: name.to_s}))
541
+ certificate_types = json_response[certificate_type_list_key]
542
+ if certificate_types.empty?
543
+ print_red_alert "certificate type not found by name '#{name}'"
544
+ return nil
545
+ elsif certificate_types.size > 1
546
+ print_red_alert "#{certificate_types.size} certificate types found by name '#{name}'"
547
+ puts_error as_pretty_table(certificate_types, [:id, :code, :name], {color:red})
548
+ print_red_alert "Try using ID instead"
549
+ print reset,"\n"
550
+ return nil
551
+ else
552
+ return certificate_types[0]
553
+ end
554
+ end
555
+
556
+ def get_available_certificate_types(refresh=false)
557
+ if !@available_certificate_types || refresh
558
+ @available_certificate_types = @certificate_types_interface.list(max:10000)[certificate_type_list_key]
559
+ end
560
+ return @available_certificate_types
561
+ end
562
+
563
+ def find_certificate_type_by_name_or_code(name)
564
+ records = get_available_certificate_types()
565
+ record = records.find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
566
+ record = record ? record : records.find { |z| z['id'].to_s == name.to_s }
567
+ if record
568
+ return record
569
+ else
570
+ print_red_alert "certificate type not found by '#{name}'"
571
+ return nil
572
+ end
573
+ end
574
+
575
+ end