prof 0.29.3

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 (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