morpheus-cli 5.3.1 → 5.3.1.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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/account_groups_interface.rb +0 -6
  4. data/lib/morpheus/api/accounts_interface.rb +1 -7
  5. data/lib/morpheus/api/api_client.rb +108 -106
  6. data/lib/morpheus/api/appliance_settings_interface.rb +6 -9
  7. data/lib/morpheus/api/approvals_interface.rb +5 -8
  8. data/lib/morpheus/api/apps_interface.rb +0 -7
  9. data/lib/morpheus/api/archive_buckets_interface.rb +9 -16
  10. data/lib/morpheus/api/archive_files_interface.rb +0 -6
  11. data/lib/morpheus/api/auth_interface.rb +4 -4
  12. data/lib/morpheus/api/backup_settings_interface.rb +5 -8
  13. data/lib/morpheus/api/blueprints_interface.rb +1 -7
  14. data/lib/morpheus/api/budgets_interface.rb +0 -6
  15. data/lib/morpheus/api/cloud_datastores_interface.rb +0 -6
  16. data/lib/morpheus/api/cloud_folders_interface.rb +1 -7
  17. data/lib/morpheus/api/cloud_policies_interface.rb +0 -6
  18. data/lib/morpheus/api/cloud_resource_pools_interface.rb +0 -6
  19. data/lib/morpheus/api/clouds_interface.rb +0 -6
  20. data/lib/morpheus/api/clusters_interface.rb +39 -42
  21. data/lib/morpheus/api/containers_interface.rb +0 -6
  22. data/lib/morpheus/api/custom_instance_types_interface.rb +0 -6
  23. data/lib/morpheus/api/cypher_interface.rb +0 -6
  24. data/lib/morpheus/api/datastores_interface.rb +4 -7
  25. data/lib/morpheus/api/deploy_interface.rb +1 -6
  26. data/lib/morpheus/api/environments_interface.rb +0 -6
  27. data/lib/morpheus/api/execute_schedules_interface.rb +0 -6
  28. data/lib/morpheus/api/execution_request_interface.rb +0 -6
  29. data/lib/morpheus/api/file_copy_request_interface.rb +2 -9
  30. data/lib/morpheus/api/group_policies_interface.rb +0 -6
  31. data/lib/morpheus/api/groups_interface.rb +0 -7
  32. data/lib/morpheus/api/guidance_interface.rb +9 -12
  33. data/lib/morpheus/api/health_interface.rb +0 -6
  34. data/lib/morpheus/api/image_builder_boot_scripts_interface.rb +0 -6
  35. data/lib/morpheus/api/image_builder_image_builds_interface.rb +0 -6
  36. data/lib/morpheus/api/image_builder_interface.rb +3 -9
  37. data/lib/morpheus/api/image_builder_preseed_scripts_interface.rb +0 -6
  38. data/lib/morpheus/api/instance_types_interface.rb +0 -7
  39. data/lib/morpheus/api/instances_interface.rb +8 -19
  40. data/lib/morpheus/api/integrations_interface.rb +30 -0
  41. data/lib/morpheus/api/invoice_line_items_interface.rb +4 -9
  42. data/lib/morpheus/api/jobs_interface.rb +11 -14
  43. data/lib/morpheus/api/key_pairs_interface.rb +0 -6
  44. data/lib/morpheus/api/library_cluster_layouts_interface.rb +0 -6
  45. data/lib/morpheus/api/library_container_scripts_interface.rb +0 -6
  46. data/lib/morpheus/api/library_container_templates_interface.rb +0 -6
  47. data/lib/morpheus/api/library_container_types_interface.rb +0 -6
  48. data/lib/morpheus/api/library_container_upgrades_interface.rb +0 -6
  49. data/lib/morpheus/api/library_instance_types_interface.rb +0 -6
  50. data/lib/morpheus/api/library_layouts_interface.rb +0 -6
  51. data/lib/morpheus/api/library_spec_template_types_interface.rb +0 -6
  52. data/lib/morpheus/api/library_spec_templates_interface.rb +0 -6
  53. data/lib/morpheus/api/license_interface.rb +0 -6
  54. data/lib/morpheus/api/load_balancers_interface.rb +0 -6
  55. data/lib/morpheus/api/log_settings_interface.rb +9 -12
  56. data/lib/morpheus/api/logs_interface.rb +0 -6
  57. data/lib/morpheus/api/monitoring_alerts_interface.rb +0 -6
  58. data/lib/morpheus/api/monitoring_apps_interface.rb +0 -6
  59. data/lib/morpheus/api/monitoring_checks_interface.rb +0 -6
  60. data/lib/morpheus/api/monitoring_contacts_interface.rb +0 -6
  61. data/lib/morpheus/api/monitoring_groups_interface.rb +0 -6
  62. data/lib/morpheus/api/monitoring_incidents_interface.rb +0 -6
  63. data/lib/morpheus/api/monitoring_interface.rb +6 -12
  64. data/lib/morpheus/api/network_domain_records_interface.rb +0 -6
  65. data/lib/morpheus/api/network_domains_interface.rb +0 -6
  66. data/lib/morpheus/api/network_groups_interface.rb +0 -6
  67. data/lib/morpheus/api/network_pool_ips_interface.rb +0 -6
  68. data/lib/morpheus/api/network_pool_servers_interface.rb +0 -6
  69. data/lib/morpheus/api/network_pools_interface.rb +0 -6
  70. data/lib/morpheus/api/network_proxies_interface.rb +0 -6
  71. data/lib/morpheus/api/network_routers_interface.rb +0 -6
  72. data/lib/morpheus/api/network_security_servers_interface.rb +6 -9
  73. data/lib/morpheus/api/network_services_interface.rb +0 -14
  74. data/lib/morpheus/api/network_subnets_interface.rb +0 -6
  75. data/lib/morpheus/api/network_types_interface.rb +1 -7
  76. data/lib/morpheus/api/networks_interface.rb +0 -6
  77. data/lib/morpheus/api/option_type_lists_interface.rb +0 -6
  78. data/lib/morpheus/api/option_types_interface.rb +0 -6
  79. data/lib/morpheus/api/options_interface.rb +0 -6
  80. data/lib/morpheus/api/packages_interface.rb +0 -6
  81. data/lib/morpheus/api/policies_interface.rb +1 -8
  82. data/lib/morpheus/api/power_schedules_interface.rb +0 -6
  83. data/lib/morpheus/api/price_sets_interface.rb +8 -11
  84. data/lib/morpheus/api/prices_interface.rb +12 -15
  85. data/lib/morpheus/api/processes_interface.rb +0 -6
  86. data/lib/morpheus/api/provision_types_interface.rb +0 -6
  87. data/lib/morpheus/api/provisioning_license_types_interface.rb +0 -6
  88. data/lib/morpheus/api/provisioning_licenses_interface.rb +0 -6
  89. data/lib/morpheus/api/provisioning_settings_interface.rb +6 -9
  90. data/lib/morpheus/api/reports_interface.rb +0 -6
  91. data/lib/morpheus/api/roles_interface.rb +0 -6
  92. data/lib/morpheus/api/security_group_rules_interface.rb +0 -7
  93. data/lib/morpheus/api/security_groups_interface.rb +0 -6
  94. data/lib/morpheus/api/server_types_interface.rb +0 -6
  95. data/lib/morpheus/api/servers_interface.rb +0 -6
  96. data/lib/morpheus/api/service_plans_interface.rb +11 -14
  97. data/lib/morpheus/api/storage_providers_interface.rb +9 -16
  98. data/lib/morpheus/api/subnet_types_interface.rb +1 -7
  99. data/lib/morpheus/api/subnets_interface.rb +0 -6
  100. data/lib/morpheus/api/task_sets_interface.rb +0 -6
  101. data/lib/morpheus/api/tasks_interface.rb +0 -6
  102. data/lib/morpheus/api/user_groups_interface.rb +0 -6
  103. data/lib/morpheus/api/user_sources_interface.rb +0 -6
  104. data/lib/morpheus/api/users_interface.rb +0 -6
  105. data/lib/morpheus/api/virtual_images_interface.rb +0 -6
  106. data/lib/morpheus/api/whitelabel_settings_interface.rb +8 -11
  107. data/lib/morpheus/api/wiki_interface.rb +0 -6
  108. data/lib/morpheus/cli/access_token_command.rb +1 -1
  109. data/lib/morpheus/cli/account_groups_command.rb +4 -4
  110. data/lib/morpheus/cli/apps.rb +9 -9
  111. data/lib/morpheus/cli/archives_command.rb +5 -5
  112. data/lib/morpheus/cli/blueprints_command.rb +5 -5
  113. data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
  114. data/lib/morpheus/cli/change_password_command.rb +4 -4
  115. data/lib/morpheus/cli/cli_command.rb +2 -1
  116. data/lib/morpheus/cli/clouds.rb +2 -2
  117. data/lib/morpheus/cli/clusters.rb +2 -2
  118. data/lib/morpheus/cli/credentials.rb +4 -11
  119. data/lib/morpheus/cli/environments_command.rb +1 -1
  120. data/lib/morpheus/cli/execute_schedules_command.rb +3 -3
  121. data/lib/morpheus/cli/hosts.rb +8 -8
  122. data/lib/morpheus/cli/image_builder_command.rb +6 -6
  123. data/lib/morpheus/cli/instance_types.rb +1 -1
  124. data/lib/morpheus/cli/instances.rb +54 -27
  125. data/lib/morpheus/cli/integrations_command.rb +567 -1
  126. data/lib/morpheus/cli/invoices_command.rb +75 -67
  127. data/lib/morpheus/cli/key_pairs.rb +2 -2
  128. data/lib/morpheus/cli/library_container_scripts_command.rb +1 -1
  129. data/lib/morpheus/cli/library_container_templates_command.rb +1 -1
  130. data/lib/morpheus/cli/library_container_types_command.rb +6 -6
  131. data/lib/morpheus/cli/library_instance_types_command.rb +4 -4
  132. data/lib/morpheus/cli/library_layouts_command.rb +5 -5
  133. data/lib/morpheus/cli/library_option_lists_command.rb +4 -4
  134. data/lib/morpheus/cli/library_option_types_command.rb +4 -4
  135. data/lib/morpheus/cli/library_upgrades_command.rb +6 -6
  136. data/lib/morpheus/cli/license.rb +2 -2
  137. data/lib/morpheus/cli/load_balancers.rb +1 -1
  138. data/lib/morpheus/cli/login.rb +3 -1
  139. data/lib/morpheus/cli/mixins/provisioning_helper.rb +1 -1
  140. data/lib/morpheus/cli/option_types.rb +5 -1
  141. data/lib/morpheus/cli/policies_command.rb +0 -1
  142. data/lib/morpheus/cli/power_schedules_command.rb +3 -3
  143. data/lib/morpheus/cli/preseed_scripts_command.rb +1 -1
  144. data/lib/morpheus/cli/remote.rb +1 -1
  145. data/lib/morpheus/cli/roles.rb +9 -9
  146. data/lib/morpheus/cli/security_group_rules.rb +1 -1
  147. data/lib/morpheus/cli/setup.rb +0 -1
  148. data/lib/morpheus/cli/tenants_command.rb +3 -3
  149. data/lib/morpheus/cli/user_groups_command.rb +3 -3
  150. data/lib/morpheus/cli/user_sources_command.rb +3 -3
  151. data/lib/morpheus/cli/users.rb +3 -3
  152. data/lib/morpheus/cli/version.rb +1 -1
  153. data/lib/morpheus/cli/virtual_images.rb +1 -1
  154. data/lib/morpheus/cli/whoami.rb +0 -15
  155. data/lib/morpheus/cli/wiki_command.rb +1 -1
  156. metadata +2 -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
 
@@ -19,10 +19,10 @@ class Morpheus::Cli::ChangePasswordCommand
19
19
 
20
20
  def connect(opts)
21
21
  @api_client = establish_remote_appliance_connection(opts)
22
- @whoami_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).whoami
23
- @users_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).users
24
- @accounts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).accounts
25
- @roles_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).roles
22
+ @whoami_interface = @api_client.whoami
23
+ @users_interface = @api_client.users
24
+ @accounts_interface = @api_client.accounts
25
+ @roles_interface = @api_client.roles
26
26
  end
27
27
 
28
28
  def handle(args)
@@ -1124,6 +1124,7 @@ module Morpheus
1124
1124
  if options[:insecure] || appliance[:insecure] || Morpheus::Cli::Shell.insecure
1125
1125
  allow_insecure = true
1126
1126
  end
1127
+ @verify_ssl = !allow_insecure
1127
1128
  # Morpheus::RestClient.enable_ssl_verification = allow_insecure != true
1128
1129
  if allow_insecure && Morpheus::RestClient.ssl_verification_enabled?
1129
1130
  Morpheus::RestClient.enable_ssl_verification = false
@@ -1189,7 +1190,7 @@ module Morpheus
1189
1190
  end
1190
1191
 
1191
1192
  # ok, connect to the appliance.. actually this just instantiates an ApiClient
1192
- api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
1193
+ api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url, @verify_ssl)
1193
1194
  @api_client = api_client # meh, just return w/o setting instance attrs
1194
1195
  return api_client
1195
1196
  end
@@ -24,8 +24,8 @@ class Morpheus::Cli::Clouds
24
24
 
25
25
  def connect(opts)
26
26
  @api_client = establish_remote_appliance_connection(opts)
27
- @clouds_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).clouds
28
- @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
27
+ @clouds_interface = @api_client.clouds
28
+ @groups_interface = @api_client.groups
29
29
  @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
30
30
  # preload stuff
31
31
  get_available_cloud_types()
@@ -45,8 +45,8 @@ class Morpheus::Cli::Clusters
45
45
  @provision_types_interface = @api_client.provision_types
46
46
  @service_plans_interface = @api_client.service_plans
47
47
  @user_groups_interface = @api_client.user_groups
48
- @accounts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).accounts
49
- @logs_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).logs
48
+ @accounts_interface = @api_client.accounts
49
+ @logs_interface = @api_client.logs
50
50
  #@active_security_group = ::Morpheus::Cli::SecurityGroups.load_security_group_file
51
51
  end
52
52
 
@@ -56,8 +56,7 @@ module Morpheus
56
56
  # OR whoami should return other wallet info like access token or maybe just the expiration date
57
57
  # for now, it just stores the access token without other wallet info
58
58
  begin
59
- # @setup_interface = Morpheus::SetupInterface.new({url:@appliance_url,access_token:@access_token})
60
- whoami_interface = Morpheus::WhoamiInterface.new({url: @appliance_url, access_token: options[:remote_token]})
59
+ whoami_interface = Morpheus::WhoamiInterface.new({url: @appliance_url, access_token: options[:remote_token], verify_ssl: !options[:insecure]})
61
60
  whoami_interface.setopts(options)
62
61
  if options[:dry_run]
63
62
  print_dry_run whoami_interface.dry.get()
@@ -104,13 +103,7 @@ module Morpheus
104
103
  end
105
104
  if wallet.nil?
106
105
  unless options[:quiet] || options[:no_prompt]
107
- # if username.empty? || password.empty?
108
- if options[:test_only]
109
- print "Test Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}", "\n", reset
110
- else
111
- print "Enter Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}", "\n", reset
112
- end
113
- # end
106
+ print "Enter Morpheus Credentials for #{display_appliance(@appliance_name, @appliance_url)}", "\n", reset
114
107
  if options[:client_id].empty?
115
108
  # print "Client ID: #{required_blue_prompt} #{options[:client_id]}", "\n", reset
116
109
  else
@@ -138,7 +131,7 @@ module Morpheus
138
131
  return nil
139
132
  end
140
133
  begin
141
- auth_interface = Morpheus::AuthInterface.new({url:@appliance_url, client_id: options[:client_id]})
134
+ auth_interface = Morpheus::AuthInterface.new({url:@appliance_url, client_id: options[:client_id], verify_ssl: !options[:insecure]})
142
135
  auth_interface.setopts(options)
143
136
  if options[:dry_run]
144
137
  print_dry_run auth_interface.dry.login(username, password)
@@ -276,7 +269,7 @@ module Morpheus
276
269
  username = wallet['username']
277
270
 
278
271
  begin
279
- auth_interface = Morpheus::AuthInterface.new({url:@appliance_url})
272
+ auth_interface = Morpheus::AuthInterface.new({url:@appliance_url, client_id: options[:client_id], verify_ssl: !options[:insecure]})
280
273
  auth_interface.setopts(options)
281
274
  if options[:dry_run]
282
275
  print_dry_run auth_interface.dry.use_refresh_token(refresh_token_value)
@@ -16,7 +16,7 @@ class Morpheus::Cli::EnvironmentsCommand
16
16
 
17
17
  def connect(opts)
18
18
  @api_client = establish_remote_appliance_connection(opts)
19
- @environments_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).environments
19
+ @environments_interface = @api_client.environments
20
20
  end
21
21
 
22
22
  def handle(args)
@@ -13,9 +13,9 @@ class Morpheus::Cli::ExecuteSchedulesCommand
13
13
 
14
14
  def connect(opts)
15
15
  @api_client = establish_remote_appliance_connection(opts)
16
- @execute_schedules_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).execute_schedules
17
- @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
18
- @servers_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).servers
16
+ @execute_schedules_interface = @api_client.execute_schedules
17
+ @instances_interface = @api_client.instances
18
+ @servers_interface = @api_client.servers
19
19
  end
20
20
 
21
21
  def handle(args)
@@ -32,14 +32,14 @@ class Morpheus::Cli::Hosts
32
32
  @api_client = establish_remote_appliance_connection(opts)
33
33
  @accounts_interface = @api_client.accounts
34
34
  @users_interface = @api_client.users
35
- @clouds_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).clouds
36
- @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
37
- @tasks_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).tasks
38
- @task_sets_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).task_sets
39
- @servers_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).servers
40
- @server_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).server_types
41
- @logs_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).logs
42
- @accounts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).accounts
35
+ @clouds_interface = @api_client.clouds
36
+ @options_interface = @api_client.options
37
+ @tasks_interface = @api_client.tasks
38
+ @task_sets_interface = @api_client.task_sets
39
+ @servers_interface = @api_client.servers
40
+ @server_types_interface = @api_client.server_types
41
+ @logs_interface = @api_client.logs
42
+ @accounts_interface = @api_client.accounts
43
43
  @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
44
44
  @execution_request_interface = @api_client.execution_request
45
45
  @clusters_interface = @api_client.clusters
@@ -30,15 +30,15 @@ class Morpheus::Cli::ImageBuilderCommand
30
30
 
31
31
  def connect(opts)
32
32
  @api_client = establish_remote_appliance_connection(opts)
33
- @image_builder_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).image_builder
33
+ @image_builder_interface = @api_client.image_builder
34
34
  @image_builds_interface = @image_builder_interface.image_builds
35
35
  @boot_scripts_interface = @image_builder_interface.boot_scripts
36
36
  @preseed_scripts_interface = @image_builder_interface.preseed_scripts
37
- @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
38
- @clouds_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).clouds
39
- @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
40
- @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
41
- @options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
37
+ @groups_interface = @api_client.groups
38
+ @clouds_interface = @api_client.clouds
39
+ @instances_interface = @api_client.instances
40
+ @instance_types_interface = @api_client.instance_types
41
+ @options_interface = @api_client.options
42
42
  @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
43
43
  end
44
44
 
@@ -17,7 +17,7 @@ class Morpheus::Cli::InstanceTypes
17
17
 
18
18
  def connect(opts)
19
19
  @api_client = establish_remote_appliance_connection(opts)
20
- @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
20
+ @instance_types_interface = @api_client.instance_types
21
21
  end
22
22
 
23
23
  def handle(args)
@@ -130,6 +130,7 @@ class Morpheus::Cli::Instances
130
130
  end
131
131
  opts.on('-a', '--details', "Display all details: plan, stats, etc" ) do
132
132
  options[:details] = true
133
+ params['details'] = true # get more data from server this way
133
134
  end
134
135
  build_standard_list_options(opts, options)
135
136
  opts.footer = "List instances."
@@ -1201,7 +1202,15 @@ class Morpheus::Cli::Instances
1201
1202
  options[:details] = true
1202
1203
  options[:include_containers] = true
1203
1204
  options[:include_scaling] = true
1205
+ options[:include_costs]
1204
1206
  end
1207
+ opts.on(nil, '--details', "Alias for --all" ) do
1208
+ options[:details] = true
1209
+ options[:include_containers] = true
1210
+ options[:include_scaling] = true
1211
+ options[:include_costs]
1212
+ end
1213
+ opts.add_hidden_option('--details')
1205
1214
  opts.on( nil, '--containers', "Display Instance Containers" ) do
1206
1215
  options[:include_containers] = true
1207
1216
  end
@@ -1216,9 +1225,6 @@ class Morpheus::Cli::Instances
1216
1225
  opts.on( nil, '--scaling', "Display Instance Scaling Settings" ) do
1217
1226
  options[:include_scaling] = true
1218
1227
  end
1219
- opts.on( nil, '--costs', "Display Cost and Price" ) do
1220
- options[:include_costs] = true
1221
- end
1222
1228
  opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
1223
1229
  options[:refresh_until_status] ||= "running,failed"
1224
1230
  if !val.to_s.empty?
@@ -1250,22 +1256,29 @@ class Morpheus::Cli::Instances
1250
1256
  end
1251
1257
  end
1252
1258
 
1253
- def _get(arg, options={})
1254
-
1259
+ def _get(id, options={})
1260
+ params = {}
1261
+ params.merge!(parse_query_options(options))
1262
+ # Use details=true to get more details from the appliance
1263
+ # if options[:details] || options[:include_containers] || options[:include_scaling]
1264
+ if options[:details] || options[:include_containers] || options[:include_scaling]
1265
+ params['details'] = true
1266
+ end
1267
+ instance = nil
1268
+ if id.to_s !~ /\A\d{1,}\Z/
1269
+ instance = find_instance_by_name_or_id(id)
1270
+ return 1, "Instance not found by name #{id}" if instance.nil?
1271
+ id = instance['id']
1272
+ end
1255
1273
  if options[:dry_run]
1256
- @instances_interface.setopts(options)
1257
- if arg.to_s =~ /\A\d{1,}\Z/
1258
- print_dry_run @instances_interface.dry.get(arg.to_i)
1259
- else
1260
- print_dry_run @instances_interface.dry.get({name:arg})
1261
- end
1262
- return
1274
+ print_dry_run @instances_interface.dry.get(id, params)
1275
+ return 0, nil
1263
1276
  end
1264
- instance = find_instance_by_name_or_id(arg =~ /\A\d{1,}\Z/ ? arg.to_i : arg)
1265
1277
  @instances_interface.setopts(options)
1266
- json_response = @instances_interface.get(instance['id'])
1278
+ json_response = @instances_interface.get(id, params)
1267
1279
  render_response(json_response, options, "instance") do
1268
1280
  instance = json_response['instance']
1281
+ pricing = instance['instancePrice']
1269
1282
  stats = instance['stats'] || json_response['stats'] || {}
1270
1283
  # load_balancers = json_response['loadBalancers'] || {}
1271
1284
  # metadata tags used to be returned as metadata and are now returned as tags
@@ -1283,7 +1296,12 @@ class Morpheus::Cli::Instances
1283
1296
  # containers are fetched via separate api call
1284
1297
  containers = nil
1285
1298
  if options[:include_containers]
1286
- containers = @instances_interface.containers(instance['id'])['containers']
1299
+ # todo: can use instance['containerDetails'] in api 5.2.7/5.3.2
1300
+ if instance['containerDetails']
1301
+ containers = instance['containerDetails']
1302
+ else
1303
+ containers = @instances_interface.containers(instance['id'])['containers']
1304
+ end
1287
1305
  end
1288
1306
 
1289
1307
  # threshold is fetched via separate api call too
@@ -1317,8 +1335,20 @@ class Morpheus::Cli::Instances
1317
1335
  "Layout" => lambda {|it| it['layout'] ? it['layout']['name'] : '' },
1318
1336
  "Version" => lambda {|it| it['instanceVersion'] },
1319
1337
  "Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
1320
- # "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1321
- # "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1338
+ "Price" => lambda {|it|
1339
+ if pricing
1340
+ pricing['price'] ? format_money(pricing['price'], (pricing['currency'] || 'USD')).to_s + ' per ' + pricing['unit'].to_s : ''
1341
+ elsif it['hourlyPrice']
1342
+ format_money(it['hourlyPrice'], (it['currency'] || 'USD')).to_s + ' per hour'
1343
+ end
1344
+ },
1345
+ "Cost" => lambda {|it|
1346
+ if pricing
1347
+ pricing['cost'] ? format_money(pricing['cost'], (pricing['currency'] || 'USD')).to_s + ' per ' + pricing['unit'].to_s : ''
1348
+ elsif it['hourlyCost']
1349
+ format_money(it['hourlyCost'], (it['currency'] || 'USD')).to_s + ' per hour'
1350
+ end
1351
+ },
1322
1352
  "Environment" => 'instanceContext',
1323
1353
  "Labels" => lambda {|it| labels ? labels.join(',') : '' },
1324
1354
  "Tags" => lambda {|it| tags ? tags.collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
@@ -1330,6 +1360,7 @@ class Morpheus::Cli::Instances
1330
1360
  end
1331
1361
  },
1332
1362
  #"Tenant" => lambda {|it| it['tenant'] ? it['tenant']['name'] : '' },
1363
+ "Apps" => lambda {|it| anded_list(it['apps'] ? it['apps'].collect {|app| app['name'] } : [])},
1333
1364
  "Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
1334
1365
  # "Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
1335
1366
  "Power Schedule" => lambda {|it| (it['powerSchedule'] && it['powerSchedule']['type']) ? it['powerSchedule']['type']['name'] : '' },
@@ -1343,12 +1374,17 @@ class Morpheus::Cli::Instances
1343
1374
  }
1344
1375
  description_cols.delete("Labels") if labels.nil? || labels.empty?
1345
1376
  description_cols.delete("Tags") if tags.nil? || tags.empty?
1377
+ description_cols.delete("Apps") if instance['apps'].nil? || instance['apps'].empty?
1346
1378
  description_cols.delete("Power Schedule") if instance['powerSchedule'].nil?
1347
1379
  description_cols.delete("Expire Date") if instance['expireDate'].nil?
1348
1380
  description_cols.delete("Shutdown Date") if instance['shutdownDate'].nil?
1349
1381
  description_cols["Removal Date"] = lambda {|it| format_local_dt(it['removalDate'])} if instance['status'] == 'pendingRemoval'
1350
1382
  description_cols.delete("Last Deployment") if instance['lastDeploy'].nil?
1351
1383
  description_cols.delete("Locked") if instance['locked'] != true
1384
+ price_value = (pricing ? pricing['price'] : instance['hourlyPrice']).to_i
1385
+ cost_value = (pricing ? pricing['cost'] : instance['hourlyCost']).to_i
1386
+ description_cols.delete("Price") if price_value == 0
1387
+ description_cols.delete("Cost") if cost_value == 0 || cost_value == price_value
1352
1388
  #description_cols.delete("Environment") if instance['instanceContext'].nil?
1353
1389
  print_description_list(description_cols, instance)
1354
1390
 
@@ -1380,15 +1416,6 @@ class Morpheus::Cli::Instances
1380
1416
  print_stats_usage(stats)
1381
1417
  end
1382
1418
 
1383
- if options[:include_costs]
1384
- print_h2 "Instance Cost"
1385
- cost_columns = {
1386
- "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1387
- "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1388
- }
1389
- print_description_list(cost_columns, instance)
1390
- end
1391
-
1392
1419
  print reset, "\n"
1393
1420
 
1394
1421
  # if options[:include_lb]
@@ -1478,7 +1505,7 @@ class Morpheus::Cli::Instances
1478
1505
  print cyan, "Refreshing in #{options[:refresh_interval] > 1 ? options[:refresh_interval].to_i : options[:refresh_interval]} seconds"
1479
1506
  sleep_with_dots(options[:refresh_interval])
1480
1507
  print "\n"
1481
- _get(arg, options)
1508
+ _get(instance['id'], options)
1482
1509
  end
1483
1510
  end
1484
1511
  end
@@ -2,12 +2,12 @@ require 'morpheus/cli/cli_command'
2
2
 
3
3
  class Morpheus::Cli::IntegrationsCommand
4
4
  include Morpheus::Cli::CliCommand
5
- include Morpheus::Cli::AccountsHelper
6
5
 
7
6
  set_command_name :'integrations'
8
7
  set_command_description "Integrations: View and manage integrations"
9
8
 
10
9
  register_subcommands :list, :get, :add, :update, :remove, :refresh
10
+ register_subcommands :list_objects, :get_object, :add_object, :remove_object
11
11
  register_subcommands :list_types, :get_type
12
12
 
13
13
  def connect(opts)
@@ -78,6 +78,9 @@ class Morpheus::Cli::IntegrationsCommand
78
78
  options = {}
79
79
  optparse = Morpheus::Cli::OptionParser.new do |opts|
80
80
  opts.banner = subcommand_usage("[integration]")
81
+ opts.on('--objects', 'Display exposed objects for the integration.') do
82
+ options[:show_objects] = true
83
+ end
81
84
  build_standard_get_options(opts, options)
82
85
  opts.footer = <<-EOT
83
86
  Get details about a specific integration.
@@ -101,6 +104,9 @@ EOT
101
104
  return 1, "integration not found for #{id}" if integration.nil?
102
105
  id = integration['id']
103
106
  end
107
+ if options[:show_objects]
108
+ params['objects'] = true
109
+ end
104
110
  @integrations_interface.setopts(options)
105
111
  if options[:dry_run]
106
112
  print_dry_run @integrations_interface.dry.get(id, params)
@@ -137,6 +143,74 @@ EOT
137
143
  show_columns.delete("Service Key") if integration['serviceKey'].nil?
138
144
  show_columns.delete("Auth Key") if integration['authKey'].nil?
139
145
  print_description_list(show_columns, integration, options)
146
+
147
+ if options[:show_objects]
148
+ # they are loaded above with ?objects=true
149
+ integration_objects = integration['objects']
150
+ if integration_objects.nil?
151
+ objects_json_response = @integrations_interface.list_objects(integration['id'], {})
152
+ integration_objects = objects_json_response[integration_object_list_key]
153
+ end
154
+ cloud_objects = integration_objects.select {|it| it['refType'] == "ComputeZone" }
155
+ library_objects = integration_objects.select {|it| it['refType'] == "InstanceTypeLayout" || it['refType'] == "InstanceType" }
156
+ blueprint_objects = integration_objects.select {|it| it['refType'] == "AppTemplate" }
157
+ catalog_objects = integration_objects.select {|it| it['refType'] == "CatalogItemType" }
158
+ if integration_objects.empty?
159
+ print reset,"\n"
160
+ print cyan,"No objects found.",reset,"\n"
161
+ else
162
+ # Exposed Clouds
163
+ if !cloud_objects.empty?
164
+ print_h2 "Exposed Clouds", [], options
165
+ list_columns = {
166
+ # "ID" => 'id',
167
+ "Name" => 'name',
168
+ # "Category" => 'category',
169
+ # "Ref Type" => 'refType',
170
+ # "Cloud ID" => 'refId',
171
+ "Group" => lambda {|it| it['group']['name'] rescue nil },
172
+ }.upcase_keys!
173
+ print as_pretty_table(cloud_objects, list_columns, options)
174
+ end
175
+
176
+ # Exposed Libraries
177
+ if !library_objects.empty?
178
+ # print_h2 "Exposed Libraries", [], options
179
+ print_h2 "Exposed Layouts", [], options
180
+ list_columns = {
181
+ # "ID" => 'id',
182
+ "Name" => 'name',
183
+ "Version" => lambda {|it| it['layout']['instanceVersion'] rescue nil },
184
+ "Instance Type" => lambda {|it| it['layout']['instanceType']['name'] rescue nil },
185
+ "Provision Type" => lambda {|it| it['layout']['provisionType']['name'] rescue nil },
186
+ }.upcase_keys!
187
+ print as_pretty_table(library_objects, list_columns, options)
188
+ end
189
+
190
+ # Exposed Blueprints
191
+ if !blueprint_objects.empty?
192
+ print_h2 "Exposed Blueprints", [], options
193
+ list_columns = {
194
+ # "ID" => 'id',
195
+ "Name" => 'name',
196
+ # "Type" => lambda {|it| it['blueprint']['type'] rescue nil },
197
+ "Blueprint" => lambda {|it| it['blueprint']['name'] rescue nil },
198
+ "Group" => lambda {|it| it['group']['name'] rescue nil },
199
+ }.upcase_keys!
200
+ print as_pretty_table(blueprint_objects, list_columns, options)
201
+ end
202
+
203
+ # Exposed Catalog Items
204
+ if !catalog_objects.empty?
205
+ print_h2 "Exposed Catalog Items", [], options
206
+ list_columns = {
207
+ # "ID" => 'id',
208
+ "Name" => 'name',
209
+ }.upcase_keys!
210
+ print as_pretty_table(catalog_objects, list_columns, options)
211
+ end
212
+ end
213
+ end
140
214
  print reset,"\n"
141
215
  end
142
216
  return 0, nil
@@ -459,6 +533,409 @@ EOT
459
533
  return 0, nil
460
534
  end
461
535
 
536
+ ## Integration Objects
537
+
538
+ def list_objects(args)
539
+ options = {}
540
+ params = {}
541
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
542
+ opts.banner = subcommand_usage("[integration] [search]")
543
+ opts.on('-t', '--type CODE', "Filter by types: cloud, layout, blueprint, catalog") do |val|
544
+ params['type'] = [params['type'], val].compact.flatten.collect {|it| it.to_s.strip.split(",") }.flatten.collect {|it| it.to_s.strip }
545
+ end
546
+ build_standard_list_options(opts, options)
547
+ opts.footer = <<-EOT
548
+ List integration objects.
549
+ [integration] is required. This is the name or id of an integration.
550
+ EOT
551
+ end
552
+ optparse.parse!(args)
553
+ verify_args!(args:args, optparse:optparse, min:1)
554
+ connect(options)
555
+
556
+ integration = find_integration_by_name_or_id(args[0])
557
+ return 1, "integration not found for #{args[0]}" if integration.nil?
558
+
559
+ if args.count > 1
560
+ options[:phrase] = args[1..-1].join(" ")
561
+ end
562
+ params.merge!(parse_list_options(options))
563
+ @integrations_interface.setopts(options)
564
+ if options[:dry_run]
565
+ print_dry_run @integrations_interface.dry.list_objects(integration['id'], params)
566
+ return 0, nil
567
+ end
568
+ json_response = @integrations_interface.list_objects(integration['id'], params)
569
+ render_response(json_response, options, integration_list_key) do
570
+ integration_objects = json_response[integration_object_list_key]
571
+ print_h1 "Integration Objects [#{integration['name']}]", parse_list_subtitles(options), options
572
+ if integration_objects.empty?
573
+ print cyan,"No objects found.",reset,"\n"
574
+ else
575
+ list_columns = {
576
+ "ID" => 'id',
577
+ "Name" => 'name',
578
+ # "Category" => 'category',
579
+ # "Ref Type" => 'refType',
580
+ # "Ref ID" => 'refId',
581
+ # "Type" => lambda {|it| it['type'] },
582
+ "Type" => lambda {|it| it['type'].to_s.capitalize },
583
+ "Ref ID" => 'refId',
584
+ }.upcase_keys!
585
+ print as_pretty_table(integration_objects, list_columns, options)
586
+ print_results_pagination(json_response)
587
+ end
588
+ print reset,"\n"
589
+ end
590
+ return 0, nil
591
+ end
592
+
593
+ def get_object(args)
594
+ params = {}
595
+ options = {}
596
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
597
+ opts.banner = subcommand_usage("[integration] [object]")
598
+ opts.on( '-c', '--config', "Display config only, for blueprint objects" ) do
599
+ options[:show_config] = true
600
+ end
601
+ build_standard_get_options(opts, options)
602
+ opts.footer = <<-EOT
603
+ Get details about a specific integration object.
604
+ [integration] is required. This is the name or id of an integration.
605
+ [object] is required. This is the name or id of an integration object.
606
+ EOT
607
+ end
608
+ optparse.parse!(args)
609
+ verify_args!(args:args, optparse:optparse, min:1)
610
+ connect(options)
611
+ optparse.parse!(args)
612
+ verify_args!(args:args, optparse:optparse, min:2)
613
+ connect(options)
614
+ integration = find_integration_by_name_or_id(args[0])
615
+ return 1, "integration not found for #{args[0]}" if integration.nil?
616
+ params.merge!(parse_query_options(options))
617
+ id_list = parse_id_list(args[1..-1])
618
+ return run_command_for_each_arg(id_list) do |arg|
619
+ _get_object(integration, arg, params, options)
620
+ end
621
+ end
622
+
623
+ def _get_object(integration, id, params, options)
624
+ integration_object = nil
625
+ if id.to_s !~ /\A\d{1,}\Z/
626
+ integration_object = find_integration_object_by_name_or_id(integration['id'], id)
627
+ return 1, "integration object not found for #{id}" if integration_object.nil?
628
+ id = integration_object['id']
629
+ end
630
+ @integrations_interface.setopts(options)
631
+ if options[:dry_run]
632
+ print_dry_run @integrations_interface.dry.get_object(integration['id'], id, params)
633
+ return
634
+ end
635
+ json_response = @integrations_interface.get_object(integration['id'], id, params)
636
+ integration_object = json_response[integration_object_object_key]
637
+ config = integration_object['config']
638
+ # export just the config as json (default) or yaml
639
+ if options[:show_config]
640
+ unless options[:json] || options[:yaml] || options[:csv]
641
+ options[:json] = :true
642
+ end
643
+ return render_with_format(config, options)
644
+ end
645
+ render_response(json_response, options, integration_object_object_key) do
646
+ print_h1 "Integration Object Details", [], options
647
+ print cyan
648
+ if integration_object['type'] == 'cloud'
649
+ show_columns = {
650
+ "Integration" => lambda {|it| integration['name'] },
651
+ "Object ID" => 'id',
652
+ "Name" => 'name',
653
+ "Type" => lambda {|it| it['type'].to_s.capitalize },
654
+ # "Cloud" => lambda {|it| it['cloud']['name'] rescue nil },
655
+ # "Ref Type" => 'refType',
656
+ "Ref ID" => 'refId',
657
+ # "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
658
+ "Group" => lambda {|it| it['group']['name'] rescue nil },
659
+ }
660
+ print_description_list(show_columns, integration_object, options)
661
+ print reset,"\n"
662
+ elsif integration_object['type'] == 'layout'
663
+ show_columns = {
664
+ "Integration" => lambda {|it| integration['name'] },
665
+ "Object ID" => 'id',
666
+ "Name" => 'name',
667
+ "Type" => lambda {|it| it['type'].to_s.capitalize },
668
+ # "Layout" => lambda {|it| it['layout']['name'] rescue nil },
669
+ # "Ref Type" => 'refType',
670
+ "Ref ID" => 'refId',
671
+ # "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
672
+ "Provision Type" => lambda {|it| it['layout']['provisionType']['name'] rescue nil },
673
+ "Instance Type" => lambda {|it| it['layout']['instanceType']['name'] rescue nil },
674
+ "Version" => lambda {|it| it['layout']['instanceVersion'] rescue nil },
675
+ }
676
+ print_description_list(show_columns, integration_object, options)
677
+ print reset,"\n"
678
+ elsif integration_object['type'] == 'blueprint'
679
+ show_columns = {
680
+ "Integration" => lambda {|it| integration['name'] },
681
+ "Object ID" => 'id',
682
+ "Name" => 'name',
683
+ "Type" => lambda {|it| it['type'].to_s.capitalize },
684
+ # "Ref Type" => 'refType',
685
+ "Ref ID" => 'refId',
686
+ # "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
687
+ # "Blueprint Type" => lambda {|it| it['blueprint']['type'] rescue nil },
688
+ "Blueprint" => lambda {|it| it['blueprint']['name'] rescue nil },
689
+ "Group" => lambda {|it| it['group']['name'] rescue nil },
690
+ "Default Cloud" => lambda {|it| it['defaultCloud']['name'] rescue nil },
691
+ "Environment" => lambda {|it| it['environment'] rescue nil },
692
+ }
693
+ print_description_list(show_columns, integration_object, options)
694
+ # print reset,"\n"
695
+ # print_h2 "App Spec"
696
+ print_h2 "Config"
697
+ if config
698
+ # config_string = integration_object['config'] || ""
699
+ config_string = config.is_a?(Hash) ? JSON.pretty_generate(config) : config.to_s
700
+ #print reset,config_string,"\n",reset
701
+ config_lines = config_string.split("\n")
702
+ config_line_count = config_lines.size
703
+ max_lines = 10
704
+ if config_lines.size > max_lines
705
+ config_string = config_lines.first(max_lines).join("\n")
706
+ config_string << "\n\n"
707
+ config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
708
+ #config_string << "\n"
709
+ end
710
+ # strip --- yaml header
711
+ if config_string[0..3] == "---\n"
712
+ config_string = config_string[4..-1]
713
+ end
714
+ print reset,config_string.chomp("\n"),"\n",reset
715
+ else
716
+ print reset,"(blank)","\n",reset
717
+ end
718
+ print reset,"\n"
719
+ elsif integration_object['type'] == 'catalog'
720
+ show_columns = {
721
+ "Integration" => lambda {|it| integration['name'] },
722
+ "Object ID" => 'id',
723
+ "Name" => 'name',
724
+ "Type" => lambda {|it| it['type'].to_s.capitalize },
725
+ "Catalog Item" => lambda {|it| it['catalogItemType']['name'] rescue nil },
726
+ # "Ref Type" => 'refType',
727
+ # "Ref ID" => 'refId',
728
+ # "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
729
+ }
730
+ print_description_list(show_columns, integration_object, options)
731
+ print reset,"\n"
732
+ else
733
+ # Unknown type?
734
+ show_columns = {
735
+ "Integration" => lambda {|it| integration['name'] },
736
+ "Object ID" => 'id',
737
+ "Name" => 'name',
738
+ "Type" => lambda {|it| it['type'].to_s.capitalize },
739
+ "Ref Type" => 'refType',
740
+ "Ref ID" => 'refId',
741
+ }
742
+ print_description_list(show_columns, integration_object, options)
743
+ print reset,"\n"
744
+ end
745
+ end
746
+ return 0, nil
747
+ end
748
+
749
+ def add_object(args)
750
+ options = {}
751
+ params = {}
752
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
753
+ opts.banner = subcommand_usage("[integration] [name] -t CODE [options]")
754
+ # opts.on('-t', '--type CODE', "Integration ObjectType code, see `#{command_name} list-types` for available type codes") do |val|
755
+ # options[:options]['type'] = val
756
+ # end
757
+ build_option_type_options(opts, options, add_integration_object_option_types)
758
+ opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
759
+ options[:config_file] = val.to_s
760
+ file_content = nil
761
+ full_filename = File.expand_path(options[:config_file])
762
+ if File.exists?(full_filename)
763
+ file_content = File.read(full_filename)
764
+ else
765
+ print_red_alert "File not found: #{full_filename}"
766
+ return 1
767
+ end
768
+ parse_result = parse_json_or_yaml(file_content)
769
+ config_map = parse_result[:data]
770
+ if config_map.nil?
771
+ # todo: bubble up JSON.parse error message
772
+ raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
773
+ #raise_command_error "Failed to parse config as valid YAML or JSON."
774
+ else
775
+ params['config'] = config_map
776
+ options[:options]['config'] = params['config'] # or file_content
777
+ end
778
+ end
779
+ # build_option_type_options(opts, options, add_integration_object_advanced_option_types)
780
+ build_standard_add_options(opts, options)
781
+ opts.footer = <<-EOT
782
+ Create a new integration object.
783
+ [integration] is required. This is the name or id of an integration.
784
+ [name] is required. This is the name of the new integration
785
+ Configuration options vary by integration type.
786
+ EOT
787
+ end
788
+ optparse.parse!(args)
789
+ verify_args!(args:args, optparse:optparse, min:1, max:2)
790
+ options[:options]['name'] = args[1] if args[1]
791
+ connect(options)
792
+ integration = find_integration_by_name_or_id(args[0])
793
+ return 1, "integration not found for #{args[0]}" if integration.nil?
794
+ payload = {}
795
+ if options[:payload]
796
+ payload = options[:payload]
797
+ payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
798
+ else
799
+ payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
800
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(add_integration_object_option_types(), options[:options], @api_client, options[:params])
801
+ v_prompt.deep_compact!
802
+ params.deep_merge!(v_prompt)
803
+ advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_integration_object_advanced_option_types, options[:options], @api_client, options[:params])
804
+ advanced_config.deep_compact!
805
+ params.deep_merge!(advanced_config)
806
+ params.booleanize!
807
+
808
+ # convert config string to a map
809
+ # config = params['config']
810
+ # if config && config.is_a?(String)
811
+ # parse_result = parse_json_or_yaml(config)
812
+ # config_map = parse_result[:data]
813
+ # if config_map.nil?
814
+ # # todo: bubble up JSON.parse error message
815
+ # raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
816
+ # #raise_command_error "Failed to parse config as valid YAML or JSON."
817
+ # else
818
+ # params['config'] = config_map
819
+ # end
820
+ # end
821
+ # if params['config']
822
+ # config_map = params.delete('config')
823
+ # params['config'] = as_json(config_map, {:pretty_json => true})
824
+ # end
825
+ # if options[:interactive_config]
826
+ # print_h2 "App Config"
827
+ # config_map = prompt_app_config(options)
828
+ # params['config'] = config_map
829
+ # end
830
+
831
+ payload[integration_object_object_key].deep_merge!(params)
832
+ end
833
+ @integrations_interface.setopts(options)
834
+ if options[:dry_run]
835
+ print_dry_run @integrations_interface.dry.create_object(integration['id'], payload)
836
+ return 0, nil
837
+ end
838
+ json_response = @integrations_interface.create_object(integration['id'], payload)
839
+ integration_object = json_response[integration_object_object_key]
840
+ render_response(json_response, options, integration_object_object_key) do
841
+ print_green_success "Added integration_object #{integration_object['name']}"
842
+ return _get_object(integration, integration_object["id"], {}, options)
843
+ end
844
+ return 0, nil
845
+ end
846
+
847
+ # def update_object(args)
848
+ # options = {}
849
+ # params = {}
850
+ # optparse = Morpheus::Cli::OptionParser.new do |opts|
851
+ # opts.banner = subcommand_usage("[integration] [object] [options]")
852
+ # build_option_type_options(opts, options, update_integration_option_types)
853
+ # build_option_type_options(opts, options, update_integration_advanced_option_types)
854
+ # build_standard_update_options(opts, options)
855
+ # opts.footer = <<-EOT
856
+ # Update an integration.
857
+ # [integration] is required. This is the name or id of an integration.
858
+ # [object] is required. This is the name or id of an integration object.
859
+ # EOT
860
+ # end
861
+ # optparse.parse!(args)
862
+ # verify_args!(args:args, optparse:optparse, count:2)
863
+ # connect(options)
864
+ # integration = find_integration_by_name_or_id(args[0])
865
+ # return 1, "integration not found for #{args[0]}" if integration.nil?
866
+ # integration_object = find_integration_object_by_name_or_id(integration['id'], args[1])
867
+ # return 1, "integration object not found for #{args[1]}" if integration_object.nil?
868
+ # payload = {}
869
+ # if options[:payload]
870
+ # payload = options[:payload]
871
+ # payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
872
+ # else
873
+ # payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
874
+ # # do not prompt on update
875
+ # v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_integration_object_option_types, options[:options], @api_client, options[:params])
876
+ # v_prompt.deep_compact!
877
+ # params.deep_merge!(v_prompt)
878
+ # advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_integration_object_advanced_option_types, options[:options], @api_client, options[:params])
879
+ # advanced_config.deep_compact!
880
+ # params.deep_merge!(advanced_config)
881
+ # # convert checkbox "on" and "off" to true and false
882
+ # params.booleanize!
883
+ # # massage association params a bit
884
+
885
+ # payload.deep_merge!({integration_object_object_key => params})
886
+ # if payload[integration_object_object_key].empty? # || options[:no_prompt]
887
+ # raise_command_error "Specify at least one option to update.\n#{optparse}"
888
+ # end
889
+ # end
890
+ # @integrations_interface.setopts(options)
891
+ # if options[:dry_run]
892
+ # print_dry_run @integrations_interface.dry.update_object(integration['id'], integration_object['id'], payload)
893
+ # return
894
+ # end
895
+ # json_response = @integrations_interface.update_object(integration['id'], integration_object['id'], payload)
896
+ # integration_object = json_response[integration_object_object_key]
897
+ # render_response(json_response, options, integration_object_object_key) do
898
+ # print_green_success "Updated integration object #{integration_object['name']}"
899
+ # return _get_object(integration, integration_object["id"], {}, options)
900
+ # end
901
+ # return 0, nil
902
+ # end
903
+
904
+ def remove_object(args)
905
+ options = {}
906
+ params = {}
907
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
908
+ opts.banner = subcommand_usage("[integration] [options]")
909
+ build_standard_remove_options(opts, options)
910
+ opts.footer = <<-EOT
911
+ Delete an integration object.
912
+ [integration] is required. This is the name or id of an integration.
913
+ [object] is required. This is the name or id of an integration object.
914
+ EOT
915
+ end
916
+ optparse.parse!(args)
917
+ verify_args!(args:args, optparse:optparse, count:2)
918
+ connect(options)
919
+ integration = find_integration_by_name_or_id(args[0])
920
+ return 1, "integration not found for #{args[0]}" if integration.nil?
921
+ integration_object = find_integration_object_by_name_or_id(integration['id'], args[1])
922
+ return 1, "integration object not found for #{args[1]}" if integration_object.nil?
923
+ params.merge!(parse_query_options(options))
924
+ @integrations_interface.setopts(options)
925
+ if options[:dry_run]
926
+ print_dry_run @integrations_interface.dry.destroy_object(integration['id'], integration_object['id'], params)
927
+ return
928
+ end
929
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the integration object #{integration_object['name']}?")
930
+ return 9, "aborted command"
931
+ end
932
+ json_response = @integrations_interface.destroy_object(integration['id'], integration_object['id'], params)
933
+ render_response(json_response, options) do
934
+ print_green_success "Removed integration object #{integration_object['name']}"
935
+ end
936
+ return 0, nil
937
+ end
938
+
462
939
  private
463
940
 
464
941
  def format_integration_type(integration)
@@ -641,4 +1118,93 @@ EOT
641
1118
  end
642
1119
  end
643
1120
 
1121
+ ## Integration Object helpers
1122
+
1123
+ def add_integration_object_option_types
1124
+ [
1125
+ {'code' => 'integrationObject.type', 'shorthand' => '-t', 'switch' => 'type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => 'integrationObjectTypes', 'required' => true, 'description' => "Integration Object Type eg. cloud, layout, blueprint, catalog", 'displayOrder' => 1},
1126
+ # {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'description' => 'Display Name of the integration object, default is the name of the referenced object', 'displayOrder' => 2},
1127
+ {'dependsOnCode' => 'integrationObject.type:cloud', 'switch' => 'group', 'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => 'groups', 'required' => true, 'description' => 'Group', 'displayOrder' => 3},
1128
+ {'dependsOnCode' => 'integrationObject.type:cloud', 'switch' => 'cloud', 'fieldName' => 'cloud', 'fieldLabel' => 'Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Cloud', 'displayOrder' => 4},
1129
+ {'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'instance-type', 'fieldName' => 'instanceType', 'fieldLabel' => 'Instance Type', 'type' => 'select', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Instance Type', 'displayOrder' => 5},
1130
+ {'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'technology', 'fieldName' => 'zoneType', 'fieldLabel' => 'Cloud Type', 'type' => 'select', 'optionSource' => 'zoneTypes', 'required' => true, 'description' => 'Cloud Type (Technology)', 'displayOrder' => 5},
1131
+ {'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'layout', 'fieldName' => 'layout', 'fieldLabel' => 'Layout', 'type' => 'select', 'optionSource' => 'layouts', 'required' => true, 'description' => 'Layout', 'displayOrder' => 6},
1132
+ {'dependsOnCode' => 'integrationObject.type:blueprint', 'fieldName' => 'name', 'fieldLabel' => 'Catalog Item Name', 'type' => 'text', 'required' => true, 'description' => 'Display Name of the integration object', 'displayOrder' => 7},
1133
+ {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'required' => true, 'description' => 'Blueprint', 'displayOrder' => 8, 'noParams' => true},
1134
+ {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'group', 'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => 'groups', 'required' => true, 'description' => 'Group', 'displayOrder' => 9},
1135
+ {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'default-cloud', 'fieldName' => 'defaultCloud', 'fieldLabel' => 'Default Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => false, 'description' => 'Default Cloud', 'displayOrder' => 10},
1136
+ {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'environment', 'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'optionSource' => 'environments', 'required' => false, 'description' => 'Environment', 'displayOrder' => 11},
1137
+ {'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'config', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'required' => true, 'description' => 'Config JSON', 'displayOrder' => 12},
1138
+ {'dependsOnCode' => 'integrationObject.type:catalog', 'switch' => 'catalog', 'fieldName' => 'catalog', 'fieldLabel' => 'Catalog Item', 'type' => 'select', 'optionSource' => 'catalogItemTypes', 'required' => true, 'description' => 'Catalog Item', 'displayOrder' => 13},
1139
+ ]
1140
+ end
1141
+
1142
+ def add_integration_object_advanced_option_types
1143
+ []
1144
+ end
1145
+
1146
+ def update_integration_object_option_types
1147
+ list = add_integration_object_option_types.collect {|it|
1148
+ it.delete('required')
1149
+ it.delete('defaultValue')
1150
+ it
1151
+ }
1152
+ list = list.reject {|it| ["type"].include? it['fieldName'] }
1153
+ list
1154
+ end
1155
+
1156
+ def update_integration_object_advanced_option_types
1157
+ add_integration_advanced_option_types.collect {|it|
1158
+ it.delete('required')
1159
+ it.delete('defaultValue')
1160
+ it
1161
+ }
1162
+ end
1163
+
1164
+ def integration_object_object_key
1165
+ 'object'
1166
+ end
1167
+
1168
+ def integration_object_list_key
1169
+ 'objects'
1170
+ end
1171
+
1172
+ def find_integration_object_by_name_or_id(integration_id, val)
1173
+ if val.to_s =~ /\A\d{1,}\Z/
1174
+ return find_integration_object_by_id(integration_id, val)
1175
+ else
1176
+ return find_integration_object_by_name(integration_id, val)
1177
+ end
1178
+ end
1179
+
1180
+ def find_integration_object_by_id(integration_id, id)
1181
+ begin
1182
+ json_response = @integrations_interface.get_object(integration_id, id.to_i)
1183
+ return json_response[integration_object_object_key]
1184
+ rescue RestClient::Exception => e
1185
+ if e.response && e.response.code == 404
1186
+ print_red_alert "integration object not found by id '#{id}'"
1187
+ else
1188
+ raise e
1189
+ end
1190
+ end
1191
+ end
1192
+
1193
+ def find_integration_object_by_name(integration_id, name)
1194
+ json_response = @integrations_interface.list_objects(integration_id, {name: name.to_s})
1195
+ integration_objects = json_response[integration_object_list_key]
1196
+ if integration_objects.empty?
1197
+ print_red_alert "integration object not found by name '#{name}'"
1198
+ return nil
1199
+ elsif integration_objects.size > 1
1200
+ print_red_alert "#{integration_objects.size} integration object found by name '#{name}'"
1201
+ puts_error as_pretty_table(integration_objects, [:id, :name], {color:red})
1202
+ print_red_alert "Try using ID instead"
1203
+ print reset,"\n"
1204
+ return nil
1205
+ else
1206
+ return integration_objects[0]
1207
+ end
1208
+ end
1209
+
644
1210
  end