morpheus-cli 5.3.1 → 5.3.1.1

Sign up to get free protection for your applications and to get access to all the features.
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