opsmgr-cgfrost 0.35.9

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/LEGAL.txt +13 -0
  3. data/README.md +123 -0
  4. data/lib/opsmgr.rb +12 -0
  5. data/lib/opsmgr/api/client.rb +116 -0
  6. data/lib/opsmgr/api/http_client.rb +399 -0
  7. data/lib/opsmgr/api/results.rb +280 -0
  8. data/lib/opsmgr/api/version20/endpoints.rb +121 -0
  9. data/lib/opsmgr/bosh_command_runner.rb +84 -0
  10. data/lib/opsmgr/cmd/bosh_command.rb +189 -0
  11. data/lib/opsmgr/cmd/ops_manager.rb +142 -0
  12. data/lib/opsmgr/environments.rb +106 -0
  13. data/lib/opsmgr/errand_runner.rb +62 -0
  14. data/lib/opsmgr/log.rb +70 -0
  15. data/lib/opsmgr/product_upload_wrapper.rb +71 -0
  16. data/lib/opsmgr/renderer.rb +23 -0
  17. data/lib/opsmgr/renderer/aws.rb +148 -0
  18. data/lib/opsmgr/renderer/noop.rb +21 -0
  19. data/lib/opsmgr/settings/microbosh/installation_settings.rb +84 -0
  20. data/lib/opsmgr/settings/microbosh/job.rb +56 -0
  21. data/lib/opsmgr/settings/microbosh/job_list.rb +27 -0
  22. data/lib/opsmgr/settings/microbosh/network.rb +21 -0
  23. data/lib/opsmgr/settings/microbosh/product.rb +90 -0
  24. data/lib/opsmgr/settings/microbosh/product_list.rb +27 -0
  25. data/lib/opsmgr/settings/microbosh/property.rb +33 -0
  26. data/lib/opsmgr/settings/microbosh/property_list.rb +27 -0
  27. data/lib/opsmgr/tasks.rb +16 -0
  28. data/lib/opsmgr/tasks/bosh.rake +104 -0
  29. data/lib/opsmgr/tasks/destroy.rake +42 -0
  30. data/lib/opsmgr/tasks/info.rake +19 -0
  31. data/lib/opsmgr/tasks/opsmgr.rake +205 -0
  32. data/lib/opsmgr/tasks/product.rake +82 -0
  33. data/lib/opsmgr/ui_helpers/add_first_user_spec.rb +25 -0
  34. data/lib/opsmgr/ui_helpers/config_helper.rb +38 -0
  35. data/lib/opsmgr/ui_helpers/delete_installation_spec.rb +41 -0
  36. data/lib/opsmgr/ui_helpers/delete_product_if_present_spec.rb +37 -0
  37. data/lib/opsmgr/ui_helpers/delete_product_spec.rb +39 -0
  38. data/lib/opsmgr/ui_helpers/export_installation_spec.rb +31 -0
  39. data/lib/opsmgr/ui_helpers/get_latest_install_log_spec.rb +29 -0
  40. data/lib/opsmgr/ui_helpers/import_stemcell_spec.rb +30 -0
  41. data/lib/opsmgr/ui_helpers/microbosh/configure_microbosh_spec.rb +32 -0
  42. data/lib/opsmgr/ui_helpers/post_import_configuration_spec.rb +31 -0
  43. data/lib/opsmgr/ui_helpers/revert_staged_changes_spec.rb +39 -0
  44. data/lib/opsmgr/ui_helpers/settings_helper.rb +132 -0
  45. data/lib/opsmgr/ui_helpers/trigger_install_spec.rb +35 -0
  46. data/lib/opsmgr/ui_helpers/ui_spec_runner.rb +122 -0
  47. data/lib/opsmgr/ui_helpers/uncheck_errands_spec.rb +29 -0
  48. data/lib/opsmgr/ui_helpers/upload_and_add_product_spec.rb +27 -0
  49. data/lib/opsmgr/ui_helpers/upload_and_upgrade_product_spec.rb +36 -0
  50. data/lib/opsmgr/version.rb +11 -0
  51. data/sample_env_files/aws.yml +95 -0
  52. data/sample_env_files/vsphere.yml +87 -0
  53. metadata +392 -0
@@ -0,0 +1,189 @@
1
+ require 'backport_refinements'
2
+ using OpsManagerUiDrivers::BackportRefinements
3
+
4
+ require 'opsmgr/ui_helpers/ui_spec_runner'
5
+ require 'opsmgr/environments'
6
+ require 'opsmgr/api/client'
7
+ require 'ops_manager_ui_drivers'
8
+ require 'capybara'
9
+ require 'capybara/dsl'
10
+ require 'capybara/webkit'
11
+
12
+ module Opsmgr
13
+ module Cmd
14
+ class BoshCommand
15
+ include Capybara::DSL
16
+
17
+ def initialize(env_name:, om_version:)
18
+ @env_settings = Opsmgr::Environments.for(env_name).settings
19
+ configure_capybara
20
+
21
+ @env_name = env_name
22
+ @om_version = om_version
23
+ @current_ops_manager = setup_or_login
24
+
25
+ configure_client_credentials
26
+ end
27
+
28
+ def command
29
+ ip = ENV['DIRECTOR_IP_OVERRIDE'] || director_ip
30
+
31
+ if Gem::Version.new(om_version) >= Gem::Version.new('1.7')
32
+ return "BOSH_CLIENT=#{@bosh_client} BOSH_CLIENT_SECRET=#{@bosh_client_secret} bosh -t #{ip} --ca-cert #{root_cert_file}"
33
+ end
34
+
35
+ %W(
36
+ bosh
37
+ -t #{ip}
38
+ -u director
39
+ -p #{director_password}
40
+ ).join(' ')
41
+ end
42
+
43
+ def director_ip
44
+ status_page = current_ops_manager.product_status_for(director_tile_name)
45
+
46
+ partitioned_job_name = 'director-partition-null-az'
47
+ availability_zones = env_settings['ops_manager']['availability_zones']
48
+ if availability_zones
49
+ az_name = availability_zones.first['iaas_identifier'] || 'first-az'
50
+ partitioned_job_name = "director-partition-#{current_ops_manager.availability_zone_guid_for_name(az_name)}"
51
+ end
52
+
53
+ if Gem::Version.new(om_version) >= Gem::Version.new('1.8')
54
+ partitioned_job_name = 'director'
55
+ end
56
+
57
+ director_status = status_page.job_status(partitioned_job_name)
58
+
59
+ director_status.ips.first
60
+ end
61
+
62
+ private
63
+
64
+ def configure_client_credentials
65
+ return unless Gem::Version.new(om_version) >= Gem::Version.new('1.7')
66
+
67
+ installation_settings = api_client.installation_settings.as_hash
68
+ uaa_credentials = installation_settings['products'].find { |p| p['identifier'] == 'p-bosh' }['uaa_credentials']
69
+
70
+
71
+ @bosh_client = uaa_credentials['identity']
72
+ @bosh_client_secret = uaa_credentials['password']
73
+ end
74
+
75
+ def api_client
76
+ @api_client ||= Opsmgr::Api::Client.new(Opsmgr::Environments.for(@env_name), @om_version)
77
+ end
78
+
79
+ def root_cert_file
80
+ return @file_path if @file_path
81
+ tmp_dir = ENV.fetch('TMPDIR', '/tmp')
82
+ FileUtils.mkpath(tmp_dir)
83
+ @file_path = tmp_dir + '/root_ca_certificate'
84
+
85
+ result = api_client.root_ca_certificate
86
+ fail result.message if result.is_a?(Api::Error)
87
+ File.write(@file_path, result)
88
+
89
+ @file_path
90
+ end
91
+
92
+ def setup_or_login
93
+ driver = ops_manager_driver(om_version)
94
+
95
+ driver.setup_page.setup_or_login(
96
+ user: env_settings['ops_manager']['username'],
97
+ password: env_settings['ops_manager']['password'],
98
+ )
99
+ driver
100
+ end
101
+
102
+ def configure_capybara
103
+ Capybara.configure do |c|
104
+ c.default_driver = :webkit
105
+ c.run_server = false
106
+ c.app_host = env_settings['ops_manager']['url']
107
+ end
108
+
109
+ Capybara::Webkit.configure do |c|
110
+ c.ignore_ssl_errors = true
111
+ c.allow_url(env_settings['ops_manager']['url'])
112
+ end
113
+
114
+ page.current_window.resize_to(1024, 1600) # avoid overlapping footer spec failures
115
+ end
116
+
117
+ def director_password
118
+ browser = self
119
+
120
+ browser.visit '/'
121
+ browser.click_on "show-#{director_tile_name}-configure-action"
122
+ browser.click_on 'show-credentials-action'
123
+
124
+ credentials = ''
125
+
126
+ browser.within "#installations_credentials" do
127
+ credentials = browser.find(:xpath, ".//td[@class='with-table']/table[@class='table']/tbody/tr[4]/td[@class='value value-col']").text
128
+ end
129
+
130
+ credentials.split(' / ')[1]
131
+ end
132
+
133
+ def director_tile_name
134
+ om_version.to_f >= 1.6 ? 'p-bosh' : 'microbosh'
135
+ end
136
+
137
+ def ops_manager_driver(om_version)
138
+ case om_version
139
+ when '1.4'
140
+ om_1_4
141
+ when '1.5'
142
+ om_1_5
143
+ when '1.6'
144
+ om_1_6
145
+ when '1.7'
146
+ om_1_7
147
+ when '1.8'
148
+ om_1_8
149
+ else
150
+ fail "Unsupported Ops Manager Version #{om_version.inspect}"
151
+ end
152
+ end
153
+
154
+ def om_1_4
155
+ @om_1_4 ||= create_web_ui(OpsManagerUiDrivers::Version14)
156
+ end
157
+
158
+ def om_1_5
159
+ @om_1_5 ||= create_web_ui(OpsManagerUiDrivers::Version15)
160
+ end
161
+
162
+ def om_1_6
163
+ @om_1_6 ||= create_web_ui(OpsManagerUiDrivers::Version16)
164
+ end
165
+
166
+ def om_1_7
167
+ @om_1_7 ||= create_web_ui(OpsManagerUiDrivers::Version17)
168
+ end
169
+
170
+ def om_1_8
171
+ @om_1_8 ||= create_web_ui(OpsManagerUiDrivers::Version18)
172
+ end
173
+
174
+ def create_web_ui(version_module)
175
+ version_module::WebUi.new(browser: self)
176
+ end
177
+
178
+ attr_reader :env_settings, :om_version, :current_ops_manager
179
+ end
180
+ end
181
+ end
182
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
183
+ # All rights reserved.
184
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
185
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
186
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
187
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
188
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
189
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,142 @@
1
+ require 'backport_refinements'
2
+ using OpsManagerUiDrivers::BackportRefinements
3
+
4
+ require 'opsmgr/log'
5
+
6
+ module Opsmgr
7
+ module Cmd
8
+ class OpsManager
9
+ include Loggable
10
+
11
+ def initialize(target_environment)
12
+ @environment = target_environment
13
+ end
14
+
15
+ def configure_microbosh_infrastructure(client)
16
+ result = client.installation_settings
17
+ return unless result.success?
18
+
19
+ result = result.as_hash
20
+ return if result.fetch('installation_version', '') != '1.4'
21
+ return if result['infrastructure']['type'] != 'vsphere'
22
+
23
+ result['infrastructure']['file_system'] = {
24
+ 'microbosh_vm_folder' => environment.settings.dig('name'),
25
+ 'microbosh_template_folder' => environment.settings.dig('name'),
26
+ 'microbosh_disk_path' => environment.settings.dig('name'),
27
+ }
28
+
29
+ file = Tempfile.new('om_install_settings')
30
+ file.write(YAML.dump(result))
31
+ file.close
32
+
33
+ client.upload_product_installation_settings(file.path)
34
+ end
35
+
36
+ def delete_unused_products(client)
37
+ result = client.delete_unused_products
38
+ if result.success?
39
+ log.info 'Successfully deleted unused products'
40
+ else
41
+ fail result.message
42
+ end
43
+ end
44
+
45
+ def upload_product(client, path)
46
+ result = client.upload_component(path)
47
+ if result.success?
48
+ log.info 'Successfully uploaded product'
49
+ else
50
+ fail result.message
51
+ end
52
+ end
53
+
54
+ def list_products(client)
55
+ result = client.list_products
56
+ if result.success?
57
+ result
58
+ else
59
+ fail result.message
60
+ end
61
+ end
62
+
63
+ def add_product(client, name, version)
64
+ result = client.add_product(name, version)
65
+ if result.success?
66
+ log.info 'Successfully added product'
67
+ else
68
+ fail result.message
69
+ end
70
+ end
71
+
72
+ def upgrade_product(client, guid, version)
73
+ result = client.upgrade_product(guid, version)
74
+ if result.success?
75
+ log.info 'Successfully upgraded product'
76
+ else
77
+ fail result.message
78
+ end
79
+ end
80
+
81
+ def installed_products(client)
82
+ result = client.installed_products
83
+ if result.success?
84
+ result
85
+ else
86
+ fail result.message
87
+ end
88
+ end
89
+
90
+ def import_installation(client, path)
91
+ result = client.import_installation(path, environment.settings.dig('ops_manager', 'password'))
92
+ if result.success?
93
+ log.info 'Successfully imported installation'
94
+ else
95
+ fail result.message
96
+ end
97
+ end
98
+
99
+ def import_stemcell(client, path)
100
+ result = client.import_stemcell(path)
101
+ if result.success?
102
+ log.info 'Successfully imported stemcell'
103
+ else
104
+ fail result.message
105
+ end
106
+ end
107
+
108
+ def download_staged_manifest(client, guid, manifest_filepath)
109
+ result = client.download_staged_manifest(guid)
110
+ if result.success?
111
+ File.open(manifest_filepath, 'w') do |mf|
112
+ mf.write(result.manifest)
113
+ end
114
+ log.info 'Successfully downloaded staged manifest for product'
115
+ else
116
+ fail result.message
117
+ end
118
+ end
119
+
120
+ def revert_staged_changes(client)
121
+ result = client.revert_staged_changes
122
+ if result.success?
123
+ log.info 'Successfully reverted staged changes'
124
+ else
125
+ fail result.message
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ attr_reader :environment
132
+ end
133
+ end
134
+ end
135
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
136
+ # All rights reserved.
137
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
138
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
139
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
140
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
141
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
142
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,106 @@
1
+ require 'backport_refinements'
2
+ using OpsManagerUiDrivers::BackportRefinements
3
+
4
+ require 'active_support'
5
+ require 'active_support/core_ext'
6
+ require 'erb'
7
+ require 'yaml'
8
+ require 'opsmgr/renderer'
9
+
10
+ module Opsmgr
11
+ class Environments
12
+ def self.for(name = '')
13
+ env_config = config_file(directory, config_filename(name))
14
+ unless File.exist?(env_config)
15
+ raise "No environments config found in #{env_config}. Specify path using ENV_DIRECTORY or ENV_CONFIG_FILE."
16
+ end
17
+
18
+ new(env_config, name)
19
+ end
20
+
21
+ def self.list
22
+ Dir.glob(config_file(directory, '*')).map do |path|
23
+ fname = File.basename(path, '.*')
24
+ if fname == 'metadata'
25
+ string_keyed_hash = YAML.load(File.read(path))
26
+ string_keyed_hash['name'].to_sym
27
+ else
28
+ fname.to_sym
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.directory
34
+ ENV.fetch('ENV_DIRECTORY', File.join(Dir.pwd, '../environment/'))
35
+ end
36
+
37
+ def self.config_filename(name)
38
+ ENV.key?('ENV_DIRECTORY') ? "#{name}.yml" : 'metadata'
39
+ end
40
+
41
+ def self.config_file(dir, name)
42
+ ENV.fetch('ENV_CONFIG_FILE', File.join(dir, name))
43
+ end
44
+
45
+ def initialize(config_path, env_name = '')
46
+ @config_path = config_path
47
+ @env_name = env_name
48
+ end
49
+
50
+ def settings_with_merged_folders(installation_settings)
51
+ return settings unless installation_settings['infrastructure']['file_system']
52
+ file_system = installation_settings['infrastructure']['file_system']
53
+
54
+ settings_to_modify = settings
55
+ settings_to_modify.dig('vm_shepherd', 'vm_configs', 0, 'cleanup', 'datacenter_folders_to_clean') << file_system['microbosh_vm_folder']
56
+ settings_to_modify.dig('vm_shepherd', 'vm_configs', 0, 'cleanup', 'datacenter_folders_to_clean') << file_system['microbosh_template_folder']
57
+ settings_to_modify.dig('vm_shepherd', 'vm_configs', 0, 'cleanup', 'datastore_folders_to_clean') << file_system['microbosh_disk_path']
58
+ settings_to_modify
59
+ end
60
+
61
+ def settings
62
+ string_keyed_hash = YAML.load(Renderer.for(File.read(@config_path)).rendered_settings)
63
+ unless @env_name == '' || string_keyed_hash['name'] == @env_name
64
+ raise "Specified name #{@env_name} does not match name in #{@config_path}"
65
+ end
66
+
67
+ fix_subnets(string_keyed_hash)
68
+ end
69
+
70
+ private
71
+
72
+ def fix_subnets(settings)
73
+ settings['ops_manager']['networks'].each do |n|
74
+ next if n['subnets']
75
+ availability_zones = settings['ops_manager']['availability_zones'] || []
76
+ n['subnets'] = [
77
+ {
78
+ 'identifier' => n['identifier'],
79
+ 'cidr' => n['subnet'],
80
+ 'dns' => n['dns'],
81
+ 'gateway' => n['gateway'],
82
+ 'reserved_ips' => n['reserved_ips'],
83
+ 'availability_zones' => availability_zones.map { |z| z['name'] }
84
+ }
85
+ ]
86
+ end
87
+
88
+ if settings['vm_shepherd']['env_config']
89
+ outputs = settings['vm_shepherd']['env_config']['outputs']
90
+ unless outputs['subnets']
91
+ outputs['subnets'] = [outputs['public_subnet_id'], outputs['private_subnet_id']]
92
+ end
93
+ end
94
+
95
+ settings
96
+ end
97
+ end
98
+ end
99
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
100
+ # All rights reserved.
101
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
102
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
103
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
104
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
105
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
106
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,62 @@
1
+ require 'opsmgr/bosh_command_runner'
2
+ require 'open3'
3
+
4
+ module Opsmgr
5
+ class ErrandRunner
6
+ def initialize(bosh_command:, environment_name:, logger:, product_name:, errand_name:, download_logs:)
7
+ @bosh_command = bosh_command
8
+ @environment_name = environment_name
9
+ @logger = logger
10
+ @product_name = product_name
11
+ @errand_name = errand_name
12
+ @download_logs = download_logs ? "--download-logs" : ""
13
+
14
+ @bosh_command_runner = Opsmgr::BoshCommandRunner.new(
15
+ bosh_command: @bosh_command,
16
+ logger: @logger
17
+ )
18
+ end
19
+
20
+ def run_errand
21
+ deployments_output = begin
22
+ @bosh_command_runner.run_and_capture_output('deployments')
23
+ rescue RuntimeError
24
+ raise 'bosh deployments failed'
25
+ end
26
+
27
+ bosh_deployment = deployments_output[/#{@product_name}-[0-9a-f]{8,}/]
28
+
29
+ fail 'Deployment not found' if bosh_deployment.nil?
30
+
31
+ deployment_file = "#{ENV.fetch('TMPDIR', '/tmp')}/#{environment_name}.yml"
32
+
33
+ begin
34
+ @bosh_command_runner.run(
35
+ "-n download manifest #{bosh_deployment} #{deployment_file}"
36
+ )
37
+ rescue RuntimeError
38
+ raise 'bosh download manifest failed'
39
+ end
40
+
41
+ begin
42
+ @bosh_command_runner.run(
43
+ "-d #{deployment_file} run errand #{@errand_name} #{@download_logs}"
44
+ )
45
+ rescue RuntimeError
46
+ raise "Errand #{@errand_name} failed"
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :bosh_command, :environment_name, :logger, :product_name, :errand_name, :download_logs
53
+ end
54
+ end
55
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
56
+ # All rights reserved.
57
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
58
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
59
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
60
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
61
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
62
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.