prof 0.29.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/LEGAL +13 -0
  3. data/lib/prof/cloud_foundry.rb +145 -0
  4. data/lib/prof/environment/cloud_foundry.rb +150 -0
  5. data/lib/prof/environment/pcf_drinks.rb +156 -0
  6. data/lib/prof/environment_manager.rb +93 -0
  7. data/lib/prof/external_spec/helpers/capybara.rb +58 -0
  8. data/lib/prof/external_spec/helpers/debug.rb +53 -0
  9. data/lib/prof/external_spec/helpers/file_helper.rb +35 -0
  10. data/lib/prof/external_spec/helpers/product_path.rb +23 -0
  11. data/lib/prof/external_spec/shared_examples/deployment.rb +23 -0
  12. data/lib/prof/external_spec/shared_examples/ops_manager_upgrade.rb +32 -0
  13. data/lib/prof/external_spec/shared_examples/service.rb +105 -0
  14. data/lib/prof/external_spec/shared_examples/service_broker.rb +25 -0
  15. data/lib/prof/external_spec/spec_helper.rb +35 -0
  16. data/lib/prof/marketplace_service.rb +20 -0
  17. data/lib/prof/matchers/metadata.rb +180 -0
  18. data/lib/prof/matchers/only_support_ssl_with_cipher_set.rb +102 -0
  19. data/lib/prof/matchers/ssl.rb +67 -0
  20. data/lib/prof/matchers/tile_configuration.rb +47 -0
  21. data/lib/prof/ops_manager/rails_500_error.rb +15 -0
  22. data/lib/prof/ops_manager/web_app_internals/page/checkbox_field.rb +38 -0
  23. data/lib/prof/ops_manager/web_app_internals/page/click_field.rb +40 -0
  24. data/lib/prof/ops_manager/web_app_internals/page/dashboard.rb +100 -0
  25. data/lib/prof/ops_manager/web_app_internals/page/flash_message.rb +53 -0
  26. data/lib/prof/ops_manager/web_app_internals/page/form.rb +130 -0
  27. data/lib/prof/ops_manager/web_app_internals/page/form_error.rb +43 -0
  28. data/lib/prof/ops_manager/web_app_internals/page/form_field.rb +51 -0
  29. data/lib/prof/ops_manager/web_app_internals/page/form_fields.rb +35 -0
  30. data/lib/prof/ops_manager/web_app_internals/page/installation_progress.rb +149 -0
  31. data/lib/prof/ops_manager/web_app_internals/page/login.rb +53 -0
  32. data/lib/prof/ops_manager/web_app_internals/page/modal.rb +85 -0
  33. data/lib/prof/ops_manager/web_app_internals/page/rails_500.rb +41 -0
  34. data/lib/prof/ops_manager/web_app_internals/page/select_field.rb +27 -0
  35. data/lib/prof/ops_manager/web_app_internals/page/tile_settings.rb +105 -0
  36. data/lib/prof/ops_manager/web_app_internals.rb +63 -0
  37. data/lib/prof/ops_manager.rb +141 -0
  38. data/lib/prof/ops_manager_log_fetcher.rb +30 -0
  39. data/lib/prof/product.rb +59 -0
  40. data/lib/prof/pushed_test_app.rb +40 -0
  41. data/lib/prof/service_instance.rb +21 -0
  42. data/lib/prof/ssh_gateway.rb +104 -0
  43. data/lib/prof/ssl/check.rb +79 -0
  44. data/lib/prof/ssl/cipher_set.rb +56 -0
  45. data/lib/prof/ssl/result.rb +27 -0
  46. data/lib/prof/ssl/results.rb +74 -0
  47. data/lib/prof/test_app.rb +19 -0
  48. data/lib/prof/tile.rb +25 -0
  49. data/lib/prof/uaa_client.rb +66 -0
  50. data/lib/prof/version.rb +13 -0
  51. metadata +403 -0
@@ -0,0 +1,149 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ require 'prof/ops_manager/web_app_internals/page/modal'
12
+ require 'prof/ops_manager/web_app_internals/page/flash_message'
13
+ require 'prof/ops_manager/web_app_internals/page/rails_500'
14
+
15
+ require 'nokogiri'
16
+
17
+ module Prof
18
+ class OpsManager
19
+
20
+ class InstallationError < StandardError; end
21
+
22
+ class WebAppInternals
23
+ module Page
24
+ class InstallationProgress
25
+ MAX_INSTALL_STEP_SECONDS = 60 * 45
26
+
27
+ class TimeoutWaitingForStep < InstallationError; end
28
+
29
+ def initialize(page:, output: STDOUT)
30
+ @page = page
31
+ @output = output
32
+
33
+ if flash_message.icmp_error?
34
+ flash_message.ignore_warnings
35
+ end
36
+
37
+ raise InstallationError, flash_message.text if flash_message.error?
38
+ end
39
+
40
+ def install_successful?
41
+ install_steps.each do |step|
42
+ wait_until_completed step
43
+ end
44
+
45
+ if modal.success?
46
+ modal.confirm
47
+ return true
48
+ else
49
+ output.puts modal.message
50
+ modal.confirm
51
+ return false
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ attr_reader :page, :output
58
+
59
+ def log(dt, _step)
60
+ elapsed_time = sprintf('%02i:%02i:%02i', dt / 3600, dt / 60, dt % 60)
61
+ output.puts " done. [#{elapsed_time}]"
62
+ end
63
+
64
+ def wait_until_completed(step)
65
+ start = Time.now
66
+ output.print "Running step [#{step.index}/#{step.total}]: #{step}..."
67
+ page.document.synchronize(MAX_INSTALL_STEP_SECONDS, errors: [TimeoutWaitingForStep]) do
68
+ raise TimeoutWaitingForStep, "Timed out after #{MAX_INSTALL_STEP_SECONDS} seconds waiting for #{step.name} to finish.\n\n#{verbose_output}" unless step.finished?
69
+ end
70
+ duration = Time.now - start
71
+
72
+ log(duration, step)
73
+ end
74
+
75
+ def modal
76
+ Modal.new(page: page)
77
+ end
78
+
79
+ def flash_message
80
+ FlashMessage.new(page: page)
81
+ end
82
+
83
+ def install_steps
84
+ @install_steps ||= begin
85
+ step_nodes = page.all('#install-steps .step')
86
+ raise rails_500.error if rails_500?
87
+ raise 'No install steps found' if step_nodes.empty?
88
+
89
+ step_nodes.map.with_index(1) do |node, index|
90
+ InstallStep.new(node: node, page: page, index: index, total: step_nodes.size)
91
+ end
92
+ end
93
+ end
94
+
95
+ def verbose_output
96
+ Nokogiri::HTML(page.html).css('.output').text
97
+ end
98
+
99
+ def rails_500?
100
+ rails_500.matches?
101
+ end
102
+
103
+ def rails_500
104
+ Rails500.new(page: page)
105
+ end
106
+
107
+ class InstallStep
108
+ class InstallStepNotPresent < InstallationError; end
109
+
110
+ def initialize(node:, page:, index: index, total: total)
111
+ @id = node['data-step-id']
112
+ @page = page
113
+ @index = index
114
+ @total = total
115
+ end
116
+
117
+ def name
118
+ node.text
119
+ end
120
+
121
+ def finished?
122
+ state == 'finished'
123
+ end
124
+
125
+ def state
126
+ node['data-step-state']
127
+ end
128
+
129
+ def to_s
130
+ name
131
+ end
132
+
133
+ attr_reader :index, :total
134
+
135
+ private
136
+
137
+ attr_reader :page, :id
138
+
139
+ def node
140
+ page.find("[data-step-id='#{id}']")
141
+ rescue Capybara::ElementNotFound
142
+ raise InstallStepNotPresent, "The install step '#{id}'' is no longer on the page - has Ops Manager crashed?"
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ require 'uri'
12
+
13
+ require 'prof/ops_manager/web_app_internals/page/dashboard'
14
+
15
+ module Prof
16
+ class OpsManager
17
+ class WebAppInternals
18
+ module Page
19
+ class Login
20
+ def initialize(page:, url:, username:, password:)
21
+ @page = page
22
+ @url = url
23
+ @username = username
24
+ @password = password
25
+
26
+ resp = page.visit login_url
27
+
28
+ if resp['status'] == 'fail'
29
+ raise StandardError.new("Failed to fetch url: #{login_url}")
30
+ end
31
+ end
32
+
33
+ def login
34
+ puts "Logging into tempest at #{login_url}"
35
+ page.fill_in 'login[user_name]', with: username
36
+ page.fill_in 'login[password]', with: password
37
+ page.click_on 'login-action'
38
+
39
+ Dashboard.new(page: page)
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :page, :url, :username, :password
45
+
46
+ def login_url
47
+ URI.join(url, 'login')
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,85 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ module Prof
12
+ class OpsManager
13
+ class WebAppInternals
14
+ module Page
15
+ class Modal
16
+
17
+ ModalStillPresent = Class.new(StandardError)
18
+
19
+ def initialize(page:)
20
+ @page = page
21
+ end
22
+
23
+ def confirm
24
+ # We have spent a long time trying to debug unreliable clicking of confirm
25
+ # in both Selenium and Poltegeist. The box is animated which we think is causing
26
+ # issues with where the browser is clicking. A sleep will resolve this, and has
27
+ # lowest complexity.
28
+ Kernel.sleep(3)
29
+
30
+ confirm_button.click
31
+
32
+ await_modal_disappearance!
33
+ true
34
+ end
35
+
36
+ def success?
37
+ /success/ =~ modal['id']
38
+ end
39
+
40
+ def failure?
41
+ /failure/ =~ modal['id']
42
+ end
43
+
44
+ def message
45
+ modal.find('.modal-body').text
46
+ end
47
+
48
+ def present?
49
+ page.all(modal_css_selector).any? || page.all('.modal-backdrop').any?
50
+ rescue Capybara::Poltergeist::ObsoleteNode
51
+ false
52
+ end
53
+
54
+ private
55
+
56
+ attr_reader :page
57
+
58
+ def await_modal_disappearance!
59
+ # Modal takes a long time to disappear as the next page can take a
60
+ # long time to load
61
+ page.document.synchronize(60, errors: [ModalStillPresent]) do
62
+ raise ModalStillPresent if present?
63
+ end
64
+ end
65
+
66
+ def modal_css_selector
67
+ '.modal.in'
68
+ end
69
+
70
+ def modal
71
+ page.find(modal_css_selector)
72
+ end
73
+
74
+ def confirm_button
75
+ modal.find('.modal-footer .btn-primary')
76
+ end
77
+
78
+ def poltergeist?
79
+ page.driver.class.to_s == 'Capybara::Poltergeist::Driver'
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,41 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ require 'prof/ops_manager/rails_500_error'
12
+
13
+ module Prof
14
+ class OpsManager
15
+ class WebAppInternals
16
+ module Page
17
+ class Rails500
18
+ def initialize(page:)
19
+ @page = page
20
+ end
21
+
22
+ def matches?
23
+ page.all('.error-page.rails-env-production').any?
24
+ end
25
+
26
+ def error
27
+ Rails500Error.new(message)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :page
33
+
34
+ def message
35
+ page.all('.error').map(&:text).join("\n")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ require 'prof/ops_manager/web_app_internals/page/form_field'
12
+
13
+ module Prof
14
+ class OpsManager
15
+ class WebAppInternals
16
+ module Page
17
+ class SelectField < FormField
18
+ private
19
+
20
+ def set_value(field)
21
+ field.find(:option, value).select_option
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,105 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ require 'prof/ops_manager/web_app_internals/page/dashboard'
12
+ require 'prof/ops_manager/web_app_internals/page/form'
13
+ require 'uri'
14
+
15
+ module Prof
16
+ class OpsManager
17
+ class WebAppInternals
18
+ module Page
19
+ class TileSettings
20
+ def initialize(opts = {})
21
+ @page = opts.fetch(:page)
22
+
23
+ check_on_settings!
24
+ end
25
+
26
+ def setting_names
27
+ page.all('.sidebar li').map(&:text)
28
+ end
29
+
30
+ def set_field_value(setting_name, field_name, field_value)
31
+ sidebar(setting_name)
32
+ update(field_name => field_value)
33
+ end
34
+
35
+ def settings_for(setting_name)
36
+ sidebar(setting_name)
37
+
38
+ config = {}
39
+ page.all(".content #{fields_selector}").each do |input|
40
+ config[input['name']] = if config[input['name']]
41
+ [input.value] + Array(config[input['name']])
42
+ else
43
+ input.value
44
+ end
45
+ end
46
+ config
47
+ end
48
+
49
+ def configure(configuration)
50
+ configuration.each { |sidebar_name, config| sidebar(sidebar_name).update(config) }
51
+ return_to_dashboard
52
+ end
53
+
54
+ def update(config = {}, &block)
55
+ form.update config, &block
56
+ self
57
+ end
58
+
59
+ def sidebar(next_settings_name, &_block)
60
+ return self if next_settings_name == current_setting_name
61
+
62
+ page.find('li a', text: /^\s*#{next_settings_name}\s*$/).click
63
+
64
+ if block_given?
65
+ yield page
66
+ return_to_dashboard
67
+ else
68
+ TileSettings.new(page: page)
69
+ end
70
+ end
71
+
72
+ def return_to_dashboard
73
+ page.click_on 'Installation Dashboard'
74
+ Dashboard.new(page: page)
75
+ end
76
+
77
+ def current_uri
78
+ URI(page.current_url)
79
+ end
80
+
81
+ private
82
+
83
+ attr_reader :page
84
+
85
+ def current_setting_name
86
+ page.find('.sidebar li.active').text
87
+ end
88
+
89
+ def fields_selector
90
+ 'input[type="text"],textarea,input[type="checkbox"][checked],input[type="radio"][selected],select'
91
+ end
92
+
93
+ def form
94
+ @form ||= Form.new(page: page, form_element: page.find('.content form'))
95
+ end
96
+
97
+ def check_on_settings!
98
+ return if current_uri.path.end_with?('edit')
99
+ raise "Expected to be on a settings page, but am on #{page.current_url}"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,63 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ require 'prof/ops_manager/web_app_internals/page/dashboard'
12
+ require 'prof/ops_manager/web_app_internals/page/flash_message'
13
+ require 'prof/ops_manager/web_app_internals/page/login'
14
+ require 'prof/tile'
15
+
16
+ module Prof
17
+ class OpsManager
18
+ class WebAppInternals
19
+ def initialize(dashboard, opsmanager_client, page, url)
20
+ @dashboard = dashboard
21
+ @page = page
22
+ @opsmanager_client = opsmanager_client
23
+ @url = url
24
+ end
25
+
26
+ def apply_changes
27
+ visit
28
+ check_nothing_in_progress!
29
+ return unless dashboard.pending_changes?
30
+ raise 'Could not apply changes' unless dashboard.apply_changes.install_successful?
31
+ end
32
+
33
+ def tile_uninstall(tile)
34
+ return unless opsmanager_client.product_type_installed?(tile)
35
+ visit
36
+ check_nothing_in_progress!
37
+ raise 'Uninstall was not successful' unless dashboard.tile_uninstall(tile)
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :dashboard, :page, :opsmanager_client, :url
43
+
44
+ def visit
45
+ page.visit(url) unless page.current_url == url
46
+ end
47
+
48
+ def flash_message
49
+ Page::FlashMessage.new(page: page)
50
+ end
51
+
52
+ def check_nothing_in_progress!
53
+ raise 'Installation already in progress' if flash_message.installation_in_progress?
54
+ end
55
+
56
+ def add_cf_tile_if_needed
57
+ unless page.has_selector?("a[id='show-cf-configure-action']")
58
+ page.find('#add-cf', visible: false).trigger('click')
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,141 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ require 'capybara'
12
+ require 'opsmanager_client/client'
13
+ require 'forwardable'
14
+
15
+ require 'prof/ops_manager/web_app_internals'
16
+ require 'prof/ops_manager/rails_500_error'
17
+ require 'prof/tile'
18
+ require 'json'
19
+
20
+ module Prof
21
+ class OpsManager
22
+ extend Forwardable
23
+
24
+ def initialize(url:, username:, password:, page: default_capybara_session, log_fetcher: null_log_fetcher)
25
+ @url = url
26
+ @username = username
27
+ @password = password
28
+ @page = page
29
+ @log_fetcher = log_fetcher
30
+ end
31
+
32
+ attr_reader :url
33
+
34
+ def_delegators :web_app_internals,
35
+ :apply_changes
36
+
37
+ def_delegators :opsmanager_client,
38
+ :cc_client_credentials,
39
+ :cf_admin_credentials,
40
+ :cf_installed?,
41
+ :delete_unused_products,
42
+ :system_domain,
43
+ :upgrade_product,
44
+ :vms_for_job_type
45
+
46
+ def_delegators :dashboard,
47
+ :apply_setting,
48
+ :tile,
49
+ :tile_configuration,
50
+ :tile_configure
51
+
52
+ # Add ability to get hold of the capybara session
53
+ # while transitioning code over to page objects
54
+ def browser(&_block)
55
+ yield page, url
56
+ end
57
+
58
+ def uninstall_tile(*tile_or_tiles)
59
+ tiles = Array(tile_or_tiles).flatten
60
+ return if tiles.empty?
61
+
62
+ tiles.each { |t| web_app_internals.tile_uninstall(t) }
63
+ web_app_internals.apply_changes
64
+ end
65
+ alias_method :uninstall_tiles, :uninstall_tile
66
+
67
+ def setup_tile(tile)
68
+ puts "Adding #{tile.name}"
69
+ add_tile(tile)
70
+
71
+ puts "Installing update"
72
+ apply_changes
73
+ rescue Rails500Error => e
74
+ puts "FAILED: '#{e.message}'\n"
75
+ logs = log_fetcher.fetch_logs('production.log', 500)
76
+ raise Rails500Error, "#{e.message}\n---------------\n#{logs}"
77
+ end
78
+
79
+ def add_tile(tile)
80
+ opsmanager_client.add_product(tile)
81
+ end
82
+
83
+ def upload_product(product)
84
+ puts "Uploading product #{product.name}"
85
+ opsmanager_client.upload_product(product)
86
+ Tile.new(name: product.name, version: product.version)
87
+ end
88
+
89
+ def product_tiles
90
+ tiles.reject{|t| ['cf', 'microbosh', 'p-bosh'].include?(t.name) }
91
+ end
92
+
93
+ def tiles
94
+ opsmanager_client.send(:installed_products).map {|tempest_product|
95
+ Tile.new(
96
+ name: tempest_product.type,
97
+ version: tempest_product.version,
98
+ guid: tempest_product.guid
99
+ )
100
+ }
101
+ end
102
+
103
+ def vms_for_job_type(job_type)
104
+ opsmanager_client.vms_for_job_type(job_type)
105
+ end
106
+
107
+ private
108
+
109
+ attr_reader :username, :password, :page, :log_fetcher
110
+
111
+ def default_capybara_session
112
+ Capybara::Session.new(Capybara.default_driver)
113
+ end
114
+
115
+ def web_app_internals
116
+ @web_app_internals ||= WebAppInternals.new(dashboard, opsmanager_client, page, url)
117
+ end
118
+
119
+ def opsmanager_client
120
+ @opsmanager_client ||= ::OpsmanagerClient::Client.new(url, username, password)
121
+ end
122
+
123
+ def dashboard
124
+ @dashboard ||= login_page.login.tap { page.visit(url) unless page.current_url == url }
125
+ end
126
+
127
+ def login_page
128
+ @login_page ||= WebAppInternals::Page::Login.new(page: page, url: url, username: username, password: password)
129
+ end
130
+
131
+ def null_log_fetcher
132
+ NullLogFetcher.new
133
+ end
134
+
135
+ class NullLogFetcher
136
+ def fetch_logs(_, _)
137
+ return 'No Log fetcher configured.'
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,30 @@
1
+ # Copyright (c) 2014-2015 Pivotal Software, Inc.
2
+ # All rights reserved.
3
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
4
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
5
+ # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
6
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
8
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ #
10
+
11
+ module Prof
12
+ class OpsManagerLogFetcher
13
+ def initialize(ssh_gateway:, host:, username:, password:)
14
+ @ssh_gateway = ssh_gateway
15
+ @host = host
16
+ @username = username
17
+ @password = password
18
+ end
19
+
20
+ def fetch_logs(log_name, lines_from_tail = 0)
21
+ read_command = lines_from_tail > 0 ? "tail -n #{lines_from_tail}" : 'cat'
22
+ command = "#{read_command} /tmp/logs/#{log_name}"
23
+ ssh_gateway.execute_on(host, command, user: username, password: password)
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :ssh_gateway, :host, :username, :password
29
+ end
30
+ end