morpheus-cli 5.3.2.3 → 5.4.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.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/account_users_interface.rb +68 -0
  4. data/lib/morpheus/api/api_client.rb +75 -8
  5. data/lib/morpheus/api/audit_interface.rb +9 -0
  6. data/lib/morpheus/api/clouds_interface.rb +4 -11
  7. data/lib/morpheus/api/health_interface.rb +37 -3
  8. data/lib/morpheus/api/instances_interface.rb +39 -5
  9. data/lib/morpheus/api/load_balancer_monitors_interface.rb +9 -0
  10. data/lib/morpheus/api/load_balancer_profiles_interface.rb +9 -0
  11. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +9 -0
  12. data/lib/morpheus/api/load_balancers_interface.rb +5 -0
  13. data/lib/morpheus/api/network_dhcp_relays_interface.rb +36 -0
  14. data/lib/morpheus/api/network_dhcp_servers_interface.rb +36 -0
  15. data/lib/morpheus/api/network_edge_clusters_interface.rb +26 -0
  16. data/lib/morpheus/api/network_routers_interface.rb +30 -0
  17. data/lib/morpheus/api/network_servers_interface.rb +98 -0
  18. data/lib/morpheus/api/network_static_routes_interface.rb +36 -0
  19. data/lib/morpheus/api/read_interface.rb +4 -3
  20. data/lib/morpheus/api/rest_interface.rb +5 -4
  21. data/lib/morpheus/api/roles_interface.rb +7 -0
  22. data/lib/morpheus/api/secondary_read_interface.rb +1 -1
  23. data/lib/morpheus/api/secondary_rest_interface.rb +19 -19
  24. data/lib/morpheus/api/storage_server_types_interface.rb +14 -0
  25. data/lib/morpheus/api/storage_servers_interface.rb +9 -0
  26. data/lib/morpheus/api/storage_volume_types_interface.rb +9 -0
  27. data/lib/morpheus/api/storage_volumes_interface.rb +9 -0
  28. data/lib/morpheus/api/users_interface.rb +16 -63
  29. data/lib/morpheus/api/virtual_images_interface.rb +23 -2
  30. data/lib/morpheus/api/virtual_servers_interface.rb +9 -0
  31. data/lib/morpheus/cli/cli_command.rb +274 -19
  32. data/lib/morpheus/cli/cli_registry.rb +56 -2
  33. data/lib/morpheus/cli/{access_token_command.rb → commands/access_token_command.rb} +1 -1
  34. data/lib/morpheus/cli/{account_groups_command.rb → commands/account_groups_command.rb} +0 -8
  35. data/lib/morpheus/cli/{activity_command.rb → commands/activity_command.rb} +0 -0
  36. data/lib/morpheus/cli/commands/{standard/alias_command.rb → alias_command.rb} +1 -4
  37. data/lib/morpheus/cli/{appliance_settings_command.rb → commands/appliance_settings_command.rb} +0 -0
  38. data/lib/morpheus/cli/{approvals_command.rb → commands/approvals_command.rb} +0 -0
  39. data/lib/morpheus/cli/{apps.rb → commands/apps.rb} +17 -89
  40. data/lib/morpheus/cli/{archives_command.rb → commands/archives_command.rb} +0 -6
  41. data/lib/morpheus/cli/commands/audit.rb +188 -0
  42. data/lib/morpheus/cli/{backup_jobs_command.rb → commands/backup_jobs_command.rb} +0 -0
  43. data/lib/morpheus/cli/{backup_settings_command.rb → commands/backup_settings_command.rb} +0 -0
  44. data/lib/morpheus/cli/{backups_command.rb → commands/backups_command.rb} +0 -0
  45. data/lib/morpheus/cli/commands/{standard/benchmark_command.rb → benchmark_command.rb} +0 -3
  46. data/lib/morpheus/cli/{blueprints_command.rb → commands/blueprints_command.rb} +1 -1
  47. data/lib/morpheus/cli/{boot_scripts_command.rb → commands/boot_scripts_command.rb} +0 -3
  48. data/lib/morpheus/cli/{budgets_command.rb → commands/budgets_command.rb} +0 -0
  49. data/lib/morpheus/cli/commands/{standard/cat_command.rb → cat_command.rb} +0 -0
  50. data/lib/morpheus/cli/{catalog_item_types_command.rb → commands/catalog_item_types_command.rb} +0 -0
  51. data/lib/morpheus/cli/{certificates_command.rb → commands/certificates_command.rb} +0 -0
  52. data/lib/morpheus/cli/commands/change_password_command.rb +132 -0
  53. data/lib/morpheus/cli/{cloud_datastores_command.rb → commands/cloud_datastores_command.rb} +0 -4
  54. data/lib/morpheus/cli/{cloud_folders_command.rb → commands/cloud_folders_command.rb} +0 -4
  55. data/lib/morpheus/cli/{cloud_resource_pools_command.rb → commands/cloud_resource_pools_command.rb} +170 -138
  56. data/lib/morpheus/cli/{clouds.rb → commands/clouds.rb} +22 -47
  57. data/lib/morpheus/cli/{clusters.rb → commands/clusters.rb} +86 -49
  58. data/lib/morpheus/cli/commands/{standard/coloring_command.rb → coloring_command.rb} +0 -2
  59. data/lib/morpheus/cli/{containers_command.rb → commands/containers_command.rb} +0 -7
  60. data/lib/morpheus/cli/commands/{standard/curl_command.rb → curl_command.rb} +0 -3
  61. data/lib/morpheus/cli/{cypher_command.rb → commands/cypher_command.rb} +0 -1
  62. data/lib/morpheus/cli/{dashboard_command.rb → commands/dashboard_command.rb} +0 -2
  63. data/lib/morpheus/cli/commands/{standard/debug_command.rb → debug_command.rb} +0 -1
  64. data/lib/morpheus/cli/{deploy.rb → commands/deploy.rb} +0 -1
  65. data/lib/morpheus/cli/{deployments.rb → commands/deployments.rb} +0 -0
  66. data/lib/morpheus/cli/{deploys.rb → commands/deploys.rb} +0 -1
  67. data/lib/morpheus/cli/{doc.rb → commands/doc.rb} +1 -1
  68. data/lib/morpheus/cli/commands/{standard/echo_command.rb → echo_command.rb} +0 -2
  69. data/lib/morpheus/cli/commands/{standard/edit_profile_command.rb → edit_profile_command.rb} +15 -4
  70. data/lib/morpheus/cli/commands/{standard/edit_rc_command.rb → edit_rc_command.rb} +19 -3
  71. data/lib/morpheus/cli/{environments_command.rb → commands/environments_command.rb} +0 -5
  72. data/lib/morpheus/cli/{execute_schedules_command.rb → commands/execute_schedules_command.rb} +0 -0
  73. data/lib/morpheus/cli/{execution_request_command.rb → commands/execution_request_command.rb} +0 -2
  74. data/lib/morpheus/cli/commands/{standard/exit_command.rb → exit_command.rb} +0 -2
  75. data/lib/morpheus/cli/{file_copy_request_command.rb → commands/file_copy_request_command.rb} +0 -4
  76. data/lib/morpheus/cli/{forgot_password.rb → commands/forgot_password.rb} +0 -0
  77. data/lib/morpheus/cli/commands/{standard/get_prompt_command.rb → get_prompt_command.rb} +0 -3
  78. data/lib/morpheus/cli/{groups.rb → commands/groups.rb} +0 -7
  79. data/lib/morpheus/cli/{guidance_command.rb → commands/guidance_command.rb} +1 -1
  80. data/lib/morpheus/cli/{health_command.rb → commands/health_command.rb} +104 -19
  81. data/lib/morpheus/cli/commands/{standard/history_command.rb → history_command.rb} +0 -3
  82. data/lib/morpheus/cli/{hosts.rb → commands/hosts.rb} +15 -25
  83. data/lib/morpheus/cli/{image_builder_command.rb → commands/image_builder_command.rb} +2 -8
  84. data/lib/morpheus/cli/{instance_types.rb → commands/instance_types.rb} +0 -3
  85. data/lib/morpheus/cli/{instances.rb → commands/instances.rb} +473 -150
  86. data/lib/morpheus/cli/{integrations_command.rb → commands/integrations_command.rb} +0 -0
  87. data/lib/morpheus/cli/{invoices_command.rb → commands/invoices_command.rb} +118 -134
  88. data/lib/morpheus/cli/{jobs_command.rb → commands/jobs_command.rb} +0 -0
  89. data/lib/morpheus/cli/{key_pairs.rb → commands/key_pairs.rb} +0 -6
  90. data/lib/morpheus/cli/{library_cluster_layouts_command.rb → commands/library_cluster_layouts_command.rb} +20 -4
  91. data/lib/morpheus/cli/{library_container_scripts_command.rb → commands/library_container_scripts_command.rb} +0 -0
  92. data/lib/morpheus/cli/{library_container_templates_command.rb → commands/library_container_templates_command.rb} +0 -1
  93. data/lib/morpheus/cli/{library_container_types_command.rb → commands/library_container_types_command.rb} +0 -4
  94. data/lib/morpheus/cli/{library_instance_types_command.rb → commands/library_instance_types_command.rb} +0 -4
  95. data/lib/morpheus/cli/{library_layouts_command.rb → commands/library_layouts_command.rb} +0 -4
  96. data/lib/morpheus/cli/{library_option_lists_command.rb → commands/library_option_lists_command.rb} +3 -7
  97. data/lib/morpheus/cli/{library_option_types_command.rb → commands/library_option_types_command.rb} +0 -4
  98. data/lib/morpheus/cli/{library_spec_templates_command.rb → commands/library_spec_templates_command.rb} +0 -1
  99. data/lib/morpheus/cli/{library_upgrades_command.rb → commands/library_upgrades_command.rb} +0 -4
  100. data/lib/morpheus/cli/{license.rb → commands/license.rb} +0 -3
  101. data/lib/morpheus/cli/commands/load_balancer_monitors.rb +71 -0
  102. data/lib/morpheus/cli/commands/load_balancer_pools.rb +91 -0
  103. data/lib/morpheus/cli/commands/load_balancer_profiles.rb +65 -0
  104. data/lib/morpheus/cli/{load_balancer_types.rb → commands/load_balancer_types.rb} +9 -8
  105. data/lib/morpheus/cli/commands/load_balancer_virtual_servers.rb +156 -0
  106. data/lib/morpheus/cli/commands/load_balancers.rb +176 -0
  107. data/lib/morpheus/cli/commands/{standard/log_level_command.rb → log_level_command.rb} +0 -3
  108. data/lib/morpheus/cli/{log_settings_command.rb → commands/log_settings_command.rb} +0 -0
  109. data/lib/morpheus/cli/{login.rb → commands/login.rb} +0 -5
  110. data/lib/morpheus/cli/commands/logout.rb +63 -0
  111. data/lib/morpheus/cli/{logs_command.rb → commands/logs_command.rb} +0 -3
  112. data/lib/morpheus/cli/commands/{standard/man_command.rb → man_command.rb} +0 -2
  113. data/lib/morpheus/cli/{monitoring_alerts_command.rb → commands/monitoring_alerts_command.rb} +0 -7
  114. data/lib/morpheus/cli/{monitoring_apps_command.rb → commands/monitoring_apps_command.rb} +0 -1
  115. data/lib/morpheus/cli/{monitoring_checks_command.rb → commands/monitoring_checks_command.rb} +2 -1
  116. data/lib/morpheus/cli/{monitoring_contacts_command.rb → commands/monitoring_contacts_command.rb} +0 -7
  117. data/lib/morpheus/cli/{monitoring_groups_command.rb → commands/monitoring_groups_command.rb} +0 -1
  118. data/lib/morpheus/cli/{monitoring_incidents_command.rb → commands/monitoring_incidents_command.rb} +0 -1
  119. data/lib/morpheus/cli/commands/network_dhcp_relays_command.rb +416 -0
  120. data/lib/morpheus/cli/commands/network_dhcp_servers_command.rb +407 -0
  121. data/lib/morpheus/cli/{network_domains_command.rb → commands/network_domains_command.rb} +0 -4
  122. data/lib/morpheus/cli/commands/network_edge_clusters_command.rb +329 -0
  123. data/lib/morpheus/cli/commands/network_firewalls_command.rb +823 -0
  124. data/lib/morpheus/cli/{network_groups_command.rb → commands/network_groups_command.rb} +0 -4
  125. data/lib/morpheus/cli/{network_pool_servers_command.rb → commands/network_pool_servers_command.rb} +0 -4
  126. data/lib/morpheus/cli/{network_pools_command.rb → commands/network_pools_command.rb} +0 -4
  127. data/lib/morpheus/cli/{network_proxies_command.rb → commands/network_proxies_command.rb} +0 -4
  128. data/lib/morpheus/cli/{network_routers_command.rb → commands/network_routers_command.rb} +387 -57
  129. data/lib/morpheus/cli/{network_services_command.rb → commands/network_services_command.rb} +0 -4
  130. data/lib/morpheus/cli/commands/network_static_routes_command.rb +446 -0
  131. data/lib/morpheus/cli/commands/network_transport_zones_command.rb +452 -0
  132. data/lib/morpheus/cli/{networks_command.rb → commands/networks_command.rb} +21 -21
  133. data/lib/morpheus/cli/commands/open_command.rb +30 -0
  134. data/lib/morpheus/cli/commands/options.rb +98 -0
  135. data/lib/morpheus/cli/{packages_command.rb → commands/packages_command.rb} +0 -2
  136. data/lib/morpheus/cli/{ping.rb → commands/ping.rb} +0 -7
  137. data/lib/morpheus/cli/{policies_command.rb → commands/policies_command.rb} +1 -8
  138. data/lib/morpheus/cli/{power_schedules_command.rb → commands/power_schedules_command.rb} +0 -0
  139. data/lib/morpheus/cli/{preseed_scripts_command.rb → commands/preseed_scripts_command.rb} +0 -3
  140. data/lib/morpheus/cli/{price_sets_command.rb → commands/price_sets_command.rb} +0 -0
  141. data/lib/morpheus/cli/{prices_command.rb → commands/prices_command.rb} +7 -7
  142. data/lib/morpheus/cli/{processes_command.rb → commands/processes_command.rb} +0 -1
  143. data/lib/morpheus/cli/{projects_command.rb → commands/projects_command.rb} +0 -0
  144. data/lib/morpheus/cli/{provisioning_licenses_command.rb → commands/provisioning_licenses_command.rb} +0 -0
  145. data/lib/morpheus/cli/{provisioning_settings_command.rb → commands/provisioning_settings_command.rb} +0 -0
  146. data/lib/morpheus/cli/{recent_activity_command.rb → commands/recent_activity_command.rb} +0 -0
  147. data/lib/morpheus/cli/{remote.rb → commands/remote.rb} +5 -9
  148. data/lib/morpheus/cli/{reports_command.rb → commands/reports_command.rb} +0 -2
  149. data/lib/morpheus/cli/commands/{standard/rm_command.rb → rm_command.rb} +0 -0
  150. data/lib/morpheus/cli/{roles.rb → commands/roles.rb} +245 -40
  151. data/lib/morpheus/cli/{search_command.rb → commands/search_command.rb} +0 -0
  152. data/lib/morpheus/cli/{security_group_rules.rb → commands/security_group_rules.rb} +0 -5
  153. data/lib/morpheus/cli/{security_groups.rb → commands/security_groups.rb} +0 -6
  154. data/lib/morpheus/cli/{service_catalog_command.rb → commands/service_catalog_command.rb} +0 -0
  155. data/lib/morpheus/cli/{service_plans_command.rb → commands/service_plans_command.rb} +0 -0
  156. data/lib/morpheus/cli/commands/{standard/set_prompt_command.rb → set_prompt_command.rb} +0 -3
  157. data/lib/morpheus/cli/{setup.rb → commands/setup.rb} +0 -0
  158. data/lib/morpheus/cli/{shell.rb → commands/shell.rb} +4 -105
  159. data/lib/morpheus/cli/commands/{standard/sleep_command.rb → sleep_command.rb} +0 -2
  160. data/lib/morpheus/cli/commands/{standard/source_command.rb → source_command.rb} +0 -2
  161. data/lib/morpheus/cli/commands/{standard/ssl_verification_command.rb → ssl_verification_command.rb} +0 -3
  162. data/lib/morpheus/cli/{storage_providers_command.rb → commands/storage_providers_command.rb} +0 -4
  163. data/lib/morpheus/cli/commands/storage_server_types.rb +50 -0
  164. data/lib/morpheus/cli/commands/storage_servers.rb +122 -0
  165. data/lib/morpheus/cli/commands/storage_volume_types.rb +50 -0
  166. data/lib/morpheus/cli/commands/storage_volumes.rb +103 -0
  167. data/lib/morpheus/cli/{subnets_command.rb → commands/subnets_command.rb} +7 -6
  168. data/lib/morpheus/cli/{tasks.rb → commands/tasks.rb} +25 -6
  169. data/lib/morpheus/cli/commands/{standard/tee_command.rb → tee_command.rb} +0 -0
  170. data/lib/morpheus/cli/{tenants_command.rb → commands/tenants_command.rb} +1 -8
  171. data/lib/morpheus/cli/commands/{standard/update_command.rb → update_command.rb} +0 -1
  172. data/lib/morpheus/cli/{usage_command.rb → commands/usage_command.rb} +0 -0
  173. data/lib/morpheus/cli/{user_groups_command.rb → commands/user_groups_command.rb} +1 -2
  174. data/lib/morpheus/cli/{user_settings_command.rb → commands/user_settings_command.rb} +2 -1
  175. data/lib/morpheus/cli/{user_sources_command.rb → commands/user_sources_command.rb} +1 -2
  176. data/lib/morpheus/cli/{users.rb → commands/users.rb} +28 -35
  177. data/lib/morpheus/cli/{vdi_allocations_command.rb → commands/vdi_allocations_command.rb} +0 -0
  178. data/lib/morpheus/cli/{vdi_apps_command.rb → commands/vdi_apps_command.rb} +0 -0
  179. data/lib/morpheus/cli/{vdi_command.rb → commands/vdi_command.rb} +0 -0
  180. data/lib/morpheus/cli/{vdi_gateways_command.rb → commands/vdi_gateways_command.rb} +0 -0
  181. data/lib/morpheus/cli/{vdi_pools_command.rb → commands/vdi_pools_command.rb} +4 -1
  182. data/lib/morpheus/cli/commands/{standard/version_command.rb → version_command.rb} +0 -0
  183. data/lib/morpheus/cli/commands/view.rb +102 -0
  184. data/lib/morpheus/cli/{virtual_images.rb → commands/virtual_images.rb} +251 -33
  185. data/lib/morpheus/cli/{whitelabel_settings_command.rb → commands/whitelabel_settings_command.rb} +0 -1
  186. data/lib/morpheus/cli/{whoami.rb → commands/whoami.rb} +0 -4
  187. data/lib/morpheus/cli/{wiki_command.rb → commands/wiki_command.rb} +0 -5
  188. data/lib/morpheus/cli/{workflows.rb → commands/workflows.rb} +0 -3
  189. data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -5
  190. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +26 -6
  191. data/lib/morpheus/cli/mixins/logs_helper.rb +1 -1
  192. data/lib/morpheus/cli/mixins/print_helper.rb +51 -18
  193. data/lib/morpheus/cli/mixins/processes_helper.rb +1 -2
  194. data/lib/morpheus/cli/mixins/provisioning_helper.rb +167 -110
  195. data/lib/morpheus/cli/mixins/rest_command.rb +268 -94
  196. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +668 -0
  197. data/lib/morpheus/cli/mixins/storage_servers_helper.rb +156 -0
  198. data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +119 -0
  199. data/lib/morpheus/cli/option_parser.rb +25 -17
  200. data/lib/morpheus/cli/option_types.rb +137 -52
  201. data/lib/morpheus/cli/version.rb +1 -1
  202. data/lib/morpheus/cli.rb +6 -128
  203. data/lib/morpheus/ext/string.rb +29 -6
  204. data/lib/morpheus/routes.rb +238 -0
  205. data/lib/morpheus/terminal.rb +5 -6
  206. data/lib/morpheus/util.rb +6 -1
  207. data/morpheus-cli.gemspec +1 -1
  208. metadata +183 -149
  209. data/lib/morpheus/cli/change_password_command.rb +0 -147
  210. data/lib/morpheus/cli/library.rb +0 -1
  211. data/lib/morpheus/cli/load_balancers.rb +0 -245
  212. data/lib/morpheus/cli/logout.rb +0 -81
@@ -0,0 +1,668 @@
1
+ # SecondaryRestCommand is a mixin for Morpheus::Cli command classes.
2
+ # for resources that are secondary to some parent resource.
3
+ # Provides basic CRUD commands: list, get, add, update, remove
4
+ # The parent resource is specified as the first argument for all the comments.
5
+ #
6
+ # Example of a SecondaryRestCommand for `morpheus load-balancer-virtual-servers`.
7
+ #
8
+ # class Morpheus::Cli::LoadBalancerVirtualServers
9
+ #
10
+ # include Morpheus::Cli::CliCommand
11
+ # include Morpheus::Cli::RestCommand
12
+ # include Morpheus::Cli::SecondaryRestCommand
13
+ # include Morpheus::Cli::LoadBalancersHelper
14
+ #
15
+ # set_command_name :'load-balancer-virtual-servers'
16
+ # register_subcommands :list, :get, :add, :update, :remove
17
+ #
18
+ # register_interfaces :load_balancer_virtual_servers,
19
+ # :load_balancers, :load_balancer_types
20
+ #
21
+ # set_rest_parent_name :load_balancers
22
+ #
23
+ # end
24
+ #
25
+ module Morpheus::Cli::SecondaryRestCommand
26
+ def self.included(base)
27
+ base.extend ClassMethods
28
+ end
29
+
30
+ module ClassMethods
31
+
32
+ ## duplicated the rest_* settings with rest_parent_*, for defining the parent resource
33
+
34
+ # rest_parent_name is the rest_name for the parent
35
+ def rest_parent_name
36
+ @rest_parent_name || default_rest_parent_name
37
+ end
38
+
39
+ def default_rest_parent_name
40
+ words = rest_name.split("_")
41
+ if words.size > 1
42
+ words.pop
43
+ return words.join("_") + "s"
44
+ else
45
+ # this wont happen, default wont make sense in this scenario
46
+ # "parent_" + rest_name
47
+ raise "Unable to determine default_rest_parent_name for rest_name: #{rest_name}, class: #{self}"
48
+ end
49
+ end
50
+
51
+ def rest_parent_name=(v)
52
+ @rest_parent_name = v.to_s
53
+ end
54
+
55
+ alias :set_rest_parent_name :rest_parent_name=
56
+ alias :set_rest_parent :rest_parent_name=
57
+ #alias :rest_parent= :rest_parent_name=
58
+
59
+ # rest_parent_key is the singular name of the resource eg. "neat_thing"
60
+ def rest_parent_key
61
+ @rest_parent_key || default_rest_parent_key
62
+ end
63
+
64
+ def default_rest_parent_key
65
+ rest_parent_name.chomp("s")
66
+ end
67
+
68
+ def rest_parent_key=(v)
69
+ @rest_parent_key = v.to_s
70
+ end
71
+
72
+ alias :set_rest_parent_key :rest_parent_key=
73
+
74
+ def rest_parent_arg
75
+ @rest_parent_arg || default_rest_parent_arg
76
+ end
77
+
78
+ def default_rest_parent_arg
79
+ rest_parent_key.to_s.gsub("_", " ")
80
+ end
81
+
82
+ def rest_parent_arg=(v)
83
+ @rest_parent_arg = v.to_s
84
+ end
85
+
86
+ alias :set_rest_parent_arg :rest_parent_arg=
87
+
88
+ def rest_parent_param
89
+ @rest_parent_param || default_rest_parent_param
90
+ end
91
+
92
+ def default_rest_parent_param
93
+ param = rest_parent_key.to_s.split('_').collect(&:capitalize).join
94
+ "#{param[0].downcase}#{param[1..-1]}Id"
95
+ end
96
+
97
+ def rest_parent_param=(v)
98
+ @rest_parent_param = v.to_s
99
+ end
100
+
101
+ alias :set_rest_parent_param :rest_parent_param=
102
+
103
+ # rest_parent_has_name indicates a resource has a name and can be retrieved by name or id
104
+ # true by default, set to false for lookups by only id
105
+ def rest_parent_has_name
106
+ @rest_parent_has_name != nil ? @rest_parent_has_name : default_rest_parent_has_name
107
+ end
108
+
109
+ def default_rest_parent_has_name
110
+ true
111
+ end
112
+
113
+ def rest_parent_has_name=(v)
114
+ @rest_parent_has_name = !!v
115
+ end
116
+
117
+ alias :set_rest_parent_has_name :rest_parent_has_name=
118
+
119
+ # rest_parent_label is the capitalized resource label eg. "Neat Thing"
120
+ def rest_parent_label
121
+ @rest_parent_label || default_rest_parent_label
122
+ end
123
+
124
+ def default_rest_parent_label
125
+ rest_parent_key.to_s.split("_").collect {|it| it.to_s.capitalize }.join(" ")
126
+ end
127
+
128
+ def rest_parent_label=(v)
129
+ @rest_parent_label = v.to_s
130
+ end
131
+
132
+ alias :set_rest_parent_label :rest_parent_label=
133
+
134
+ # the plural version of the label eg. "Neat Things"
135
+ def rest_parent_label_plural
136
+ @rest_parent_label_plural || default_rest_parent_label_plural
137
+ end
138
+
139
+ def default_rest_parent_label_plural
140
+ #rest_parent_name.to_s.split("_").collect {|it| it.to_s.capitalize }.join(" ")
141
+ rest_parent_label.to_s.pluralize
142
+ end
143
+
144
+ def rest_parent_label_plural=(v)
145
+ @rest_parent_label_plural = v.to_s
146
+ end
147
+
148
+ alias :set_rest_parent_label_plural :rest_parent_label_plural=
149
+
150
+ # the name of the default interface, matches the rest name eg. "neat_things"
151
+ def rest_parent_interface_name
152
+ @rest_parent_interface_name || default_rest_parent_interface_name
153
+ end
154
+
155
+ def default_rest_parent_interface_name
156
+ rest_parent_name
157
+ end
158
+
159
+ def rest_parent_interface_name=(v)
160
+ @rest_parent_interface_name = v.to_s
161
+ end
162
+
163
+ alias :set_rest_parent_interface_name :rest_parent_interface_name=
164
+
165
+ end
166
+
167
+ ## duplicated the rest_* settings with rest_parent, for the parents resource
168
+
169
+ def rest_parent_name
170
+ self.class.rest_parent_name
171
+ end
172
+
173
+ def rest_parent_key
174
+ self.class.rest_parent_key
175
+ end
176
+
177
+ def rest_parent_arg
178
+ self.class.rest_parent_arg
179
+ end
180
+
181
+ def rest_parent_param
182
+ self.class.rest_parent_param
183
+ end
184
+
185
+ def rest_parent_has_name
186
+ self.class.rest_parent_has_name
187
+ end
188
+
189
+ def rest_parent_label
190
+ self.class.rest_parent_label
191
+ end
192
+
193
+ def rest_parent_label_plural
194
+ self.class.rest_parent_label_plural
195
+ end
196
+
197
+ def rest_parent_interface_name
198
+ self.class.rest_parent_interface_name # || "@#{rest_parent_name}_interface"
199
+ end
200
+
201
+ def rest_parent_interface
202
+ instance_variable_get("@#{rest_parent_interface_name}_interface")
203
+ end
204
+
205
+ def rest_parent_object_key
206
+ send("#{rest_parent_key}_object_key")
207
+ end
208
+
209
+ def rest_parent_list_key
210
+ send("#{rest_parent_key}_list_key")
211
+ end
212
+
213
+ def rest_parent_column_definitions(options)
214
+ send("#{rest_parent_key}_column_definitions", options)
215
+ end
216
+
217
+ def rest_parent_list_column_definitions(options)
218
+ send("#{rest_parent_key}_list_column_definitions", options)
219
+ end
220
+
221
+ def rest_parent_find_by_name_or_id(val)
222
+ # use explicitly defined finders
223
+ # else default to new generic CliCommand find_by methods
224
+ if rest_parent_has_name
225
+ if respond_to?("find_#{rest_parent_key}_by_name_or_id", true)
226
+ send("find_#{rest_parent_key}_by_name_or_id", val)
227
+ else
228
+ find_by_name_or_id(rest_parent_key, val)
229
+ end
230
+ else
231
+ if respond_to?("find_#{rest_parent_key}_by_id", true)
232
+ send("find_#{rest_parent_key}_by_id", val)
233
+ else
234
+ find_by_id(rest_parent_key, val)
235
+ end
236
+ end
237
+ end
238
+
239
+ # override RestCommand method to include parent_id parameter
240
+ def rest_find_by_name_or_id(parent_id, val)
241
+ # use explicitly defined finders
242
+ # else default to new generic CliCommand find_by methods
243
+ if rest_has_name
244
+ if respond_to?("find_#{rest_key}_by_name_or_id", true)
245
+ send("find_#{rest_key}_by_name_or_id", parent_id, val)
246
+ else
247
+ find_by_name_or_id(rest_key, parent_id, val)
248
+ end
249
+ else
250
+ if respond_to?("find_#{rest_key}_by_id", true)
251
+ send("find_#{rest_key}_by_id", parent_id, val)
252
+ else
253
+ find_by_id(rest_key, parent_id, val)
254
+ end
255
+ end
256
+ end
257
+
258
+ def registered_interfaces
259
+ self.class.registered_interfaces
260
+ end
261
+
262
+ def list(args)
263
+ parent_id, parent_record = nil, nil
264
+ params = {}
265
+ options = {}
266
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
267
+ opts.banner = subcommand_usage("[#{rest_parent_arg}] [search]")
268
+ parse_list_options!(args, options, params)
269
+ opts.footer = <<-EOT
270
+ List #{rest_label_plural.downcase}.
271
+ [#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
272
+ [search] is optional. This is a search phrase to filter the results.
273
+ EOT
274
+ end
275
+ optparse.parse!(args)
276
+ verify_args!(args:args, optparse:optparse, min:1)
277
+ connect(options)
278
+ parent_id = args[0]
279
+ parent_record = rest_parent_find_by_name_or_id(parent_id)
280
+ if parent_record.nil?
281
+ return 1, "#{rest_parent_label} not found for '#{parent_id}"
282
+ end
283
+ parent_id = parent_record['id']
284
+ parse_list_options!(args.count > 1 ? args[1..-1] : [], options, params)
285
+ rest_interface.setopts(options)
286
+ if options[:dry_run]
287
+ print_dry_run rest_interface.dry.list(parent_id, params)
288
+ return
289
+ end
290
+ json_response = rest_interface.list(parent_id, params)
291
+ render_response(json_response, options, rest_list_key) do
292
+ records = json_response[rest_list_key]
293
+ print_h1 "Morpheus #{rest_label_plural}"
294
+ if records.nil? || records.empty?
295
+ print cyan,"No #{rest_label_plural.downcase} found.",reset,"\n"
296
+ else
297
+ print as_pretty_table(records, rest_list_column_definitions(options).upcase_keys!, options)
298
+ print_results_pagination(json_response) if json_response['meta']
299
+ end
300
+ print reset,"\n"
301
+ end
302
+ return 0, nil
303
+ end
304
+
305
+ def get(args)
306
+ params = {}
307
+ options = {}
308
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
309
+ opts.banner = subcommand_usage("[#{rest_parent_arg}] [#{rest_arg}]")
310
+ build_get_options(opts, options, params)
311
+ opts.footer = <<-EOT
312
+ Get details about #{a_or_an(rest_label)} #{rest_label.downcase}.
313
+ [#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
314
+ [#{rest_arg}] is required. This is the #{rest_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_label)} #{rest_label.downcase}.
315
+ EOT
316
+ end
317
+ optparse.parse!(args)
318
+ verify_args!(args:args, optparse:optparse, min:2)
319
+ connect(options)
320
+ parse_get_options!(args.count > 1 ? args[1..-1] : [], options, params)
321
+ parent_id = args[0]
322
+ parent_record = rest_parent_find_by_name_or_id(parent_id)
323
+ if parent_record.nil?
324
+ return 1, "#{rest_parent_label} not found for '#{parent_id}"
325
+ end
326
+ parent_id = parent_record['id']
327
+ id = args[1..-1].join(" ")
328
+ _get(parent_id, id, params, options)
329
+ end
330
+
331
+ def _get(parent_id, id, params, options)
332
+ if id !~ /\A\d{1,}\Z/
333
+ record = rest_find_by_name_or_id(parent_id, id)
334
+ if record.nil?
335
+ return 1, "#{rest_label} not found for '#{id}"
336
+ end
337
+ id = record['id']
338
+ end
339
+ rest_interface.setopts(options)
340
+ if options[:dry_run]
341
+ print_dry_run rest_interface.dry.get(parent_id, id, params)
342
+ return
343
+ end
344
+ json_response = rest_interface.get(parent_id, id, params)
345
+ render_response_for_get(json_response, options)
346
+ return 0, nil
347
+ end
348
+
349
+ def render_response_for_get(json_response, options)
350
+ render_response(json_response, options, rest_object_key) do
351
+ record = json_response[rest_object_key]
352
+ print_h1 rest_label, [], options
353
+ print cyan
354
+ print_description_list(rest_column_definitions(options), record, options)
355
+ # show config settings...
356
+ if record['optionTypes'] && record['optionTypes'].size > 0
357
+ print_h2 "Option Types", options
358
+ print format_option_types_table(record['optionTypes'], options, rest_object_key)
359
+ end
360
+ print reset,"\n"
361
+ end
362
+ end
363
+
364
+ def add(args)
365
+ parent_id, parent_record = nil, nil
366
+ record_type_id = nil
367
+ options = {}
368
+ option_types = respond_to?("add_#{rest_key}_option_types", true) ? send("add_#{rest_key}_option_types") : []
369
+ advanced_option_types = respond_to?("add_#{rest_key}_advanced_option_types", true) ? send("add_#{rest_key}_advanced_option_types") : []
370
+ type_option_type = option_types.find {|it| it['fieldName'] == 'type'}
371
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
372
+ opts.banner = subcommand_usage("[#{rest_parent_arg}] [#{rest_arg}]")
373
+ if rest_has_type && type_option_type.nil?
374
+ opts.on( '-t', "--#{rest_type_arg} TYPE", "#{rest_type_label}" ) do |val|
375
+ record_type_id = val
376
+ end
377
+ end
378
+ build_option_type_options(opts, options, option_types)
379
+ build_option_type_options(opts, options, advanced_option_types)
380
+ build_standard_add_options(opts, options)
381
+ opts.footer = <<-EOT
382
+ Create a new #{rest_label.downcase}.
383
+ [#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
384
+ [#{rest_arg}] is required. This is the name of the new #{rest_label.downcase}.
385
+ EOT
386
+ end
387
+ optparse.parse!(args)
388
+ verify_args!(args:args, optparse:optparse, min:1, max: 2)
389
+ # todo: make supporting args[0] optional and more flexible
390
+ # for now args[0] is assumed to be the 'name'
391
+ record_name = nil
392
+ parent_id = args[0]
393
+ if rest_has_name
394
+ if args[1]
395
+ record_name = args[1]
396
+ end
397
+ verify_args!(args:args, optparse:optparse, min:1, max: 2)
398
+ else
399
+ verify_args!(args:args, optparse:optparse, count: 1)
400
+ end
401
+ connect(options)
402
+ # load parent record
403
+ # todo: prompt instead of error
404
+ parent_record = rest_parent_find_by_name_or_id(parent_id)
405
+ if parent_record.nil?
406
+ return 1, "#{rest_parent_label} not found for '#{parent_id}"
407
+ end
408
+ parent_id = parent_record['id']
409
+ # load or prompt for type
410
+ if rest_has_type && type_option_type.nil?
411
+ if record_type_id.nil?
412
+ #raise_command_error "#{rest_type_label} is required.\n#{optparse}"
413
+ type_list = rest_type_interface.list({max:10000, creatable: true})[rest_type_list_key]
414
+ type_dropdown_options = type_list.collect {|it| {'name' => it['name'], 'value' => it['code']} }
415
+ record_type_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => rest_type_label, 'type' => 'select', 'selectOptions' => type_dropdown_options, 'required' => true}], options[:options], @api_client)['type']
416
+ end
417
+ record_type = rest_type_find_by_name_or_id(record_type_id)
418
+ if record_type.nil?
419
+ return 1, "#{rest_type_label} not found for '#{record_type_id}"
420
+ end
421
+ end
422
+ passed_options = parse_passed_options(options)
423
+ options[:params] ||= {}
424
+ options[:params][rest_parent_param] = parent_id
425
+ options[:options]['_object_key'] = rest_object_key
426
+ payload = {}
427
+ if options[:payload]
428
+ payload = options[:payload]
429
+ payload.deep_merge!({rest_object_key => passed_options})
430
+ else
431
+ record_payload = {}
432
+ if record_name
433
+ record_payload['name'] = record_name
434
+ options[:options]['name'] = record_name # injected for prompt
435
+ options[:options][rest_arg] = record_name
436
+ end
437
+ if rest_has_type && record_type
438
+ # record_payload['type'] = {'code' => record_type['code']}
439
+ record_payload['type'] = record_type['code']
440
+ options[:options]['type'] = record_type['code'] # injected for prompt
441
+ # initialize params for loading optionSource data
442
+ options[:params]['type'] = record_type['code']
443
+ end
444
+ record_payload.deep_merge!(passed_options)
445
+ if option_types && !option_types.empty?
446
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
447
+ v_prompt.deep_compact!
448
+ v_prompt.booleanize! # 'on' => true
449
+ record_payload.deep_merge!(v_prompt)
450
+ end
451
+ # options by type
452
+ if rest_has_type && record_type.nil?
453
+ type_value = record_payload['type'].is_a?(Hash) ? record_payload['type']['id'] : record_payload['type']
454
+ if type_value
455
+ record_type = rest_type_find_by_name_or_id(type_value)
456
+ if record_type.nil?
457
+ return 1, "#{rest_type_label} not found for '#{type_value}"
458
+ end
459
+ end
460
+ # reload the type by id to get all the details ie. optionTypes
461
+ if record_type && record_type['optionTypes'].nil?
462
+ record_type = rest_type_find_by_name_or_id(record_type['id'])
463
+ end
464
+ end
465
+ if respond_to?("load_option_types_for_#{rest_key}", true)
466
+ my_option_types = send("load_option_types_for_#{rest_key}", record_type, parent_record)
467
+ else
468
+ my_option_types = record_type ? record_type['optionTypes'] : nil
469
+ end
470
+ if my_option_types && !my_option_types.empty?
471
+ # remove redundant fieldContext
472
+ my_option_types.each do |option_type|
473
+ if option_type['fieldContext'] == rest_object_key
474
+ option_type['fieldContext'] = nil
475
+ end
476
+ end
477
+ api_params = (options[:params] || {}).merge(record_payload)
478
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, api_params)
479
+ v_prompt.deep_compact!
480
+ v_prompt.booleanize! # 'on' => true
481
+ record_payload.deep_merge!(v_prompt)
482
+ end
483
+ # advanced options (uses no_prompt)
484
+ if advanced_option_types && !advanced_option_types.empty?
485
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(advanced_option_types, options[:options], @api_client, options[:params])
486
+ v_prompt.deep_compact!
487
+ v_prompt.booleanize! # 'on' => true
488
+ record_payload.deep_merge!(v_prompt)
489
+ end
490
+ payload[rest_object_key] = record_payload
491
+ end
492
+ rest_interface.setopts(options)
493
+ if options[:dry_run]
494
+ print_dry_run rest_interface.dry.create(parent_id, payload)
495
+ return
496
+ end
497
+ json_response = rest_interface.create(parent_id, payload)
498
+ render_response(json_response, options, rest_object_key) do
499
+ record = json_response[rest_object_key]
500
+ print_green_success "Added #{rest_label.downcase} #{record['name'] || record['id']}"
501
+ return _get(parent_id, record["id"], {}, options)
502
+ end
503
+ return 0, nil
504
+ end
505
+
506
+ def update(args)
507
+ parent_id = args[0]
508
+ id = args[1]
509
+ record_type = nil
510
+ record_type_id = nil
511
+ options = {}
512
+ option_types = respond_to?("update_#{rest_key}_option_types", true) ? send("update_#{rest_key}_option_types") : []
513
+ advanced_option_types = respond_to?("update_#{rest_key}_advanced_option_types", true) ? send("update_#{rest_key}_advanced_option_types") : []
514
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
515
+ opts.banner = subcommand_usage("[#{rest_parent_arg}] [#{rest_arg}] [options]")
516
+
517
+ build_standard_update_options(opts, options)
518
+ opts.footer = <<-EOT
519
+ Update an existing #{rest_label.downcase}.
520
+ [#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
521
+ [#{rest_arg}] is required. This is the #{rest_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_label)} #{rest_label.downcase}.
522
+ EOT
523
+ end
524
+ optparse.parse!(args)
525
+ verify_args!(args:args, optparse:optparse, count:2)
526
+ connect(options)
527
+ parent_record = rest_parent_find_by_name_or_id(parent_id)
528
+ if parent_record.nil?
529
+ return 1, "#{rest_parent_label} not found for '#{parent_id}"
530
+ end
531
+ parent_id = parent_record['id']
532
+ connect(options)
533
+ record = rest_find_by_name_or_id(parent_id, id)
534
+ if record.nil?
535
+ return 1, "#{rest_name} not found for '#{id}'"
536
+ end
537
+ # load type so we can prompt for those option types
538
+ if rest_has_type
539
+ record_type_id = record['type']['id']
540
+ record_type = rest_type_find_by_name_or_id(record_type_id)
541
+ if record_type.nil?
542
+ return 1, "#{rest_type_label} not found for '#{record_type_id}"
543
+ end
544
+ # reload the type by id to get all the details ie. optionTypes
545
+ if record_type['optionTypes'].nil?
546
+ record_type = rest_type_find_by_name_or_id(record_type['id'])
547
+ end
548
+ end
549
+ passed_options = parse_passed_options(options)
550
+ payload = {}
551
+ if options[:payload]
552
+ payload = options[:payload]
553
+ payload.deep_merge!({rest_object_key => passed_options}) unless passed_options.empty?
554
+ else
555
+ record_payload = passed_options
556
+ if rest_has_type && record_type
557
+ # inject type to options for prompting
558
+ # record_payload['type'] = record_type['code']
559
+ # options[:options]['type'] = record_type['code']
560
+ # initialize params for loading optionSource data
561
+ options[:params] ||= {}
562
+ options[:params]['type'] = record_type['code']
563
+ end
564
+ # update options without prompting by default
565
+ if option_types && !option_types.empty?
566
+ api_params = (options[:params] || {}).merge(record_payload) # need to merge in values from record too, ughhh
567
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(option_types, options[:options], @api_client, api_params)
568
+ v_prompt.deep_compact!
569
+ v_prompt.booleanize! # 'on' => true
570
+ record_payload.deep_merge!(v_prompt)
571
+ end
572
+ # options by type
573
+ my_option_types = nil
574
+ if respond_to?("load_option_types_for_#{rest_key}", true)
575
+ my_option_types = send("load_option_types_for_#{rest_key}", record_type, parent_record)
576
+ else
577
+ my_option_types = record_type ? record_type['optionTypes'] : nil
578
+ end
579
+ if my_option_types && !my_option_types.empty?
580
+ # remove redundant fieldContext
581
+ # make them optional for updates
582
+ # todo: use current value as default instead of just making things optioanl
583
+ # maybe new prompt() options like {:mode => :edit, :object => storage_server} or something
584
+ my_option_types.each do |option_type|
585
+ if option_type['fieldContext'] == rest_object_key
586
+ option_type['fieldContext'] = nil
587
+ end
588
+ option_type.delete('required')
589
+ option_type.delete('defaultValue')
590
+ end
591
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(my_option_types, options[:options], @api_client, options[:params])
592
+ v_prompt.deep_compact!
593
+ v_prompt.booleanize! # 'on' => true
594
+ record_payload.deep_merge!(v_prompt)
595
+ end
596
+ # advanced options
597
+ if advanced_option_types && !advanced_option_types.empty?
598
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(advanced_option_types, options[:options], @api_client, options[:params])
599
+ v_prompt.deep_compact!
600
+ v_prompt.booleanize! # 'on' => true
601
+ record_payload.deep_merge!(v_prompt)
602
+ end
603
+ # remove empty config, compact could hanlde this
604
+ if record_payload['config'] && record_payload['config'].empty?
605
+ record_payload.delete('config')
606
+ end
607
+ # prevent updating with empty payload
608
+ if record_payload.empty?
609
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
610
+ end
611
+ payload[rest_object_key] = record_payload
612
+ end
613
+ rest_interface.setopts(options)
614
+ if options[:dry_run]
615
+ print_dry_run rest_interface.dry.update(parent_id, record['id'], payload)
616
+ return
617
+ end
618
+ json_response = rest_interface.update(parent_id, record['id'], payload)
619
+ render_response(json_response, options, rest_object_key) do
620
+ print_green_success "Updated #{rest_label.downcase} #{record['name'] || record['id']}"
621
+ _get(parent_id, record["id"], {}, options)
622
+ end
623
+ return 0, nil
624
+ end
625
+
626
+ def remove(args)
627
+ parent_id = args[0]
628
+ id = args[1]
629
+ params = {}
630
+ options = {}
631
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
632
+ opts.banner = subcommand_usage("[#{rest_parent_arg}] [#{rest_arg}]")
633
+ build_standard_remove_options(opts, options)
634
+ opts.footer = <<-EOT
635
+ Delete an existing #{rest_label.downcase}.
636
+ [#{rest_parent_arg}] is required. This is the #{rest_parent_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_parent_label)} #{rest_parent_label.downcase}.
637
+ [#{rest_arg}] is required. This is the #{rest_has_name ? 'name or id' : 'id'} of #{a_or_an(rest_label)} #{rest_label.downcase}.
638
+ EOT
639
+ end
640
+ optparse.parse!(args)
641
+ verify_args!(args:args, optparse:optparse, count:2)
642
+ connect(options)
643
+ parent_record = rest_parent_find_by_name_or_id(parent_id)
644
+ if parent_record.nil?
645
+ return 1, "#{rest_parent_label} not found for '#{parent_id}"
646
+ end
647
+ record = rest_find_by_name_or_id(parent_id, id)
648
+ if record.nil?
649
+ return 1, "#{rest_name} not found for '#{id}'"
650
+ end
651
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the #{rest_label.downcase} #{record['name'] || record['id']}?")
652
+ return 9, "aborted"
653
+ end
654
+ params.merge!(parse_query_options(options))
655
+ rest_interface.setopts(options)
656
+ if options[:dry_run]
657
+ print_dry_run rest_interface.dry.destroy(parent_id, record['id'], params)
658
+ return 0, nil
659
+ end
660
+ json_response = rest_interface.destroy(parent_id, record['id'], params)
661
+ render_response(json_response, options) do
662
+ print_green_success "Removed #{rest_label.downcase} #{record['name'] || record['id']}"
663
+ end
664
+ return 0, nil
665
+ end
666
+
667
+ end
668
+