ops_manager_cli 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTION.md +22 -0
- data/Dockerfile +33 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +11 -0
- data/README.md +99 -0
- data/Rakefile +6 -0
- data/bin/clean_tapes +19 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/ops_manager +4 -0
- data/lib/ops_manager/api/base.rb +141 -0
- data/lib/ops_manager/api/opsman.rb +190 -0
- data/lib/ops_manager/api/pivnet.rb +68 -0
- data/lib/ops_manager/appliance_deployment.rb +123 -0
- data/lib/ops_manager/cli.rb +159 -0
- data/lib/ops_manager/configs/base.rb +27 -0
- data/lib/ops_manager/configs/opsman_deployment.rb +12 -0
- data/lib/ops_manager/configs/product_deployment.rb +16 -0
- data/lib/ops_manager/deployments/vsphere.rb +43 -0
- data/lib/ops_manager/director_template_generator.rb +59 -0
- data/lib/ops_manager/errors.rb +9 -0
- data/lib/ops_manager/installation.rb +38 -0
- data/lib/ops_manager/installation_runner.rb +75 -0
- data/lib/ops_manager/installation_settings.rb +16 -0
- data/lib/ops_manager/logging.rb +17 -0
- data/lib/ops_manager/product_deployment.rb +106 -0
- data/lib/ops_manager/product_installation.rb +43 -0
- data/lib/ops_manager/product_template_generator.rb +147 -0
- data/lib/ops_manager/semver.rb +24 -0
- data/lib/ops_manager/version.rb +3 -0
- data/lib/ops_manager.rb +94 -0
- data/ops_manager.gemspec +32 -0
- metadata +249 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
class OpsManager
|
2
|
+
module Api
|
3
|
+
class Pivnet < OpsManager::Api::Base
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
get_authentication
|
7
|
+
end
|
8
|
+
|
9
|
+
def download_stemcell(stemcell_version, stemcell_path, filename_regex)
|
10
|
+
puts "====> Downloading stemcell #{ stemcell_path }...".green
|
11
|
+
|
12
|
+
release_id = get_release_for(stemcell_version).fetch('id')
|
13
|
+
product_file = get_product_file_for(release_id, filename_regex)
|
14
|
+
product_file_id = product_file.fetch('id')
|
15
|
+
|
16
|
+
accept_release_eula(release_id)
|
17
|
+
download_product(release_id, product_file_id, stemcell_path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_authentication
|
21
|
+
puts "====> Authentication to Pivnet".green
|
22
|
+
opts = { headers: { 'Authorization' => "Token #{pivnet_token}" } }
|
23
|
+
res = get("/api/v2/authentication", opts)
|
24
|
+
raise OpsManager::PivnetAuthenticationError.new(res.body) unless res.code == '200'
|
25
|
+
res
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def accept_release_eula(release_id)
|
31
|
+
puts "====> Accepting stemcell eula ...".green
|
32
|
+
opts = { headers: { 'Authorization' => "Token #{pivnet_token}" } }
|
33
|
+
post("/api/v2/products/stemcells/releases/#{release_id}/eula_acceptance", opts)
|
34
|
+
end
|
35
|
+
|
36
|
+
def download_product(release_id, product_file_id, stemcell_path)
|
37
|
+
opts = { write_to: stemcell_path, headers: { 'Authorization' => "Token #{pivnet_token}" } }
|
38
|
+
post("/api/v2/products/stemcells/releases/#{release_id}/product_files/#{product_file_id}/download", opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_stemcell_releases(opts = {})
|
42
|
+
get("/api/v2/products/stemcells/releases", opts)
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_product_files(release_id, opts = {})
|
46
|
+
get("/api/v2/products/stemcells/releases/#{release_id}/product_files",opts)
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_release_for(stemcell_version)
|
50
|
+
releases = JSON.parse(get_stemcell_releases.body).fetch('releases')
|
51
|
+
releases.select{ |r| r.fetch('version') == stemcell_version }.first
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_product_file_for(release_id, filename_regex)
|
55
|
+
products = JSON.parse(get_product_files(release_id).body).fetch('product_files')
|
56
|
+
products.select{ |r| r.fetch('aws_object_key') =~ filename_regex }.first
|
57
|
+
end
|
58
|
+
|
59
|
+
def target
|
60
|
+
@target ||= "network.pivotal.io"
|
61
|
+
end
|
62
|
+
|
63
|
+
def pivnet_token
|
64
|
+
@pivnet_token ||= OpsManager.get_conf(:pivnet_token)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require "ops_manager/api/opsman"
|
2
|
+
require "ops_manager/api/pivnet"
|
3
|
+
require "ops_manager/installation_settings"
|
4
|
+
require 'ops_manager/configs/opsman_deployment'
|
5
|
+
|
6
|
+
class OpsManager::ApplianceDeployment
|
7
|
+
extend Forwardable
|
8
|
+
def_delegators :pivnet_api, :download_stemcell
|
9
|
+
def_delegators :opsman_api, :create_user, :trigger_installation, :get_installation_assets,
|
10
|
+
:get_installation_settings, :upload_installation_assets, :import_stemcell, :target,
|
11
|
+
:password, :username, :get_current_version ,:ops_manager_version=
|
12
|
+
|
13
|
+
attr_reader :config_file
|
14
|
+
|
15
|
+
def initialize(config_file)
|
16
|
+
@config_file = config_file
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
OpsManager.set_conf(:target, config.ip)
|
21
|
+
OpsManager.set_conf(:username, config.username)
|
22
|
+
OpsManager.set_conf(:password, config.password)
|
23
|
+
OpsManager.set_conf(:pivnet_token, config.pivnet_token)
|
24
|
+
|
25
|
+
self.extend(OpsManager::Deployments::Vsphere)
|
26
|
+
|
27
|
+
case
|
28
|
+
when current_version.empty?
|
29
|
+
puts "No OpsManager deployed at #{target}. Deploying ...".green
|
30
|
+
deploy
|
31
|
+
create_first_user
|
32
|
+
when current_version < desired_version then
|
33
|
+
puts "OpsManager at #{target} version is #{current_version}. Upgrading to #{desired_version}.../".green
|
34
|
+
upgrade
|
35
|
+
when current_version == desired_version then
|
36
|
+
puts "OpsManager at #{target} version is already #{config.desired_version}. Skiping ...".green
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def deploy
|
41
|
+
deploy_vm(desired_vm_name , config.ip)
|
42
|
+
end
|
43
|
+
|
44
|
+
%w{ stop_current_vm deploy_vm }.each do |m|
|
45
|
+
define_method(m) do
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_first_user
|
51
|
+
puts '====> Creating initial user...'.green
|
52
|
+
until( create_user.code.to_i == 200) do
|
53
|
+
print '.'.green ; sleep 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def upgrade
|
58
|
+
get_installation_assets
|
59
|
+
get_installation_settings(write_to: 'installation_settings.json')
|
60
|
+
stop_current_vm(current_vm_name)
|
61
|
+
deploy
|
62
|
+
upload_installation_assets
|
63
|
+
provision_missing_stemcells
|
64
|
+
OpsManager::InstallationRunner.trigger!.wait_for_result
|
65
|
+
|
66
|
+
puts "====> Finish!".green
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def new_vm_name
|
71
|
+
@new_vm_name ||= "#{config.name}-#{config.desired_version}"
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def current_version
|
76
|
+
@current_version ||= OpsManager::Semver.new(get_current_version)
|
77
|
+
end
|
78
|
+
|
79
|
+
def desired_version
|
80
|
+
@desired_version ||= OpsManager::Semver.new(config.desired_version)
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_vm_name
|
84
|
+
@current_vm_name ||= "#{config.name}-#{current_version}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def desired_vm_name
|
88
|
+
@desired_vm_name ||= "#{config.name}-#{config.desired_version}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def provision_missing_stemcells
|
92
|
+
puts '====> Reprovisioning missing stemcells...'.green
|
93
|
+
installation_settings.stemcells.each do |s|
|
94
|
+
download_stemcell(s.fetch(:version), s.fetch(:file), /vsphere/)
|
95
|
+
import_stemcell(s.fetch(:file))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def pivnet_api
|
100
|
+
@pivnet_api ||= OpsManager::Api::Pivnet.new
|
101
|
+
end
|
102
|
+
|
103
|
+
def opsman_api
|
104
|
+
@opsman_api ||= OpsManager::Api::Opsman.new
|
105
|
+
end
|
106
|
+
|
107
|
+
def config
|
108
|
+
parsed_yml = ::YAML.load_file(@config_file)
|
109
|
+
@config ||= OpsManager::Configs::OpsmanDeployment.new(parsed_yml)
|
110
|
+
end
|
111
|
+
|
112
|
+
def installation_settings
|
113
|
+
@installation_settings ||= OpsManager::InstallationSettings.new(parsed_installation_settings)
|
114
|
+
end
|
115
|
+
|
116
|
+
def parsed_installation_settings
|
117
|
+
JSON.parse(File.read('installation_settings.json'))
|
118
|
+
end
|
119
|
+
|
120
|
+
def desired_version?(version)
|
121
|
+
!!(desired_version.to_s =~/#{version}/)
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require "clamp"
|
2
|
+
require "ops_manager/product_deployment"
|
3
|
+
require "ops_manager/appliance_deployment"
|
4
|
+
require "ops_manager/product_template_generator"
|
5
|
+
require "ops_manager/director_template_generator"
|
6
|
+
require "ops_manager/installation"
|
7
|
+
|
8
|
+
class OpsManager
|
9
|
+
class Cli < Clamp::Command
|
10
|
+
|
11
|
+
class Target < Clamp::Command
|
12
|
+
parameter "OPS_MANAGER_IP", "OpsManager url", required: true
|
13
|
+
|
14
|
+
def execute
|
15
|
+
OpsManager.set_target(@ops_manager_ip)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Status < Clamp::Command
|
20
|
+
def execute
|
21
|
+
puts OpsManager.show_status
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Login < Clamp::Command
|
26
|
+
parameter "USERNAME", "OpsManager username", required: true
|
27
|
+
parameter "PASSWORD", "OpsManager password", required: true
|
28
|
+
|
29
|
+
def execute
|
30
|
+
OpsManager.login(@username, @password)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class DeployAppliance < Clamp::Command
|
35
|
+
parameter "OPS_MANAGER_CONFIG", "OpsManager appliance config file", required: true
|
36
|
+
|
37
|
+
def execute
|
38
|
+
OpsManager::ApplianceDeployment.new(ops_manager_config).run
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class DeployProduct < Clamp::Command
|
43
|
+
parameter "PRODUCT_CONFIG", "OpsManager product config file", required: true
|
44
|
+
option "--force", :flag, "force deployment"
|
45
|
+
|
46
|
+
def execute
|
47
|
+
OpsManager::ProductDeployment.new(product_config, force?).run
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class GetInstallationSettings < Clamp::Command
|
52
|
+
def execute
|
53
|
+
puts parsed_response.to_yaml
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def parsed_response
|
58
|
+
response = opsman.get_installation_settings
|
59
|
+
JSON.parse(response.body)
|
60
|
+
end
|
61
|
+
|
62
|
+
def opsman
|
63
|
+
OpsManager::Api::Opsman.new(silent: true)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class ImportStemcell < Clamp::Command
|
68
|
+
parameter "STEMCELL_FILEPATH", "Stemcell file path", required: true
|
69
|
+
|
70
|
+
def execute
|
71
|
+
OpsManager::Api::Opsman.new.import_stemcell(@stemcell_filepath)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class DeleteUnusedProducts < Clamp::Command
|
76
|
+
|
77
|
+
def execute
|
78
|
+
OpsManager.new.delete_products
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class GetUaaToken < Clamp::Command
|
83
|
+
def execute
|
84
|
+
puts OpsManager::Api::Opsman.new.get_token.info.fetch('access_token')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class SSH < Clamp::Command
|
89
|
+
def execute
|
90
|
+
`ssh ubuntu@#{OpsManager.get_conf(:target)}`
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class GetProductTemplate < Clamp::Command
|
95
|
+
parameter "PRODUCT_NAME", "Product tile name. Example: p-cf", required: true
|
96
|
+
|
97
|
+
def execute
|
98
|
+
puts OpsManager::ProductTemplateGenerator.new(@product_name).generate_yml
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class GetInstallationLogs < Clamp::Command
|
103
|
+
parameter "INSTALLATION_ID", "Installation ID. Use 'last' to retrive the latest", required: true
|
104
|
+
|
105
|
+
def execute
|
106
|
+
if @installation_id == "last"
|
107
|
+
puts OpsManager::Installation.all.last.logs
|
108
|
+
else
|
109
|
+
puts OpsManager::Installation.new(@installation_id).logs
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class GetDirectorTemplate < Clamp::Command
|
115
|
+
def execute
|
116
|
+
puts OpsManager::DirectorTemplateGenerator.new.generate_yml
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Curl < Clamp::Command
|
121
|
+
option ['-X', '--http-method'], "HTTP_METHOD", "HTTP Method (GET,POST)", default: 'GET'
|
122
|
+
parameter "ENDPOINT", "OpsManager api endpoint. eg: /v0/installation_settings", required: true
|
123
|
+
|
124
|
+
def execute
|
125
|
+
puts case http_method.strip
|
126
|
+
when 'GET'
|
127
|
+
opsman.authenticated_get(@endpoint).body
|
128
|
+
when 'POST'
|
129
|
+
opsman.authenticated_post(@endpoint).body
|
130
|
+
else
|
131
|
+
"Unsupported method: #{http_method.strip}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
def opsman
|
137
|
+
OpsManager::Api::Opsman.new(silent: true)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Core commands
|
142
|
+
subcommand "status", "Test credentials and shows status", Status
|
143
|
+
subcommand "target", "Target an OpsManager appliance", Target
|
144
|
+
subcommand "login", "Login to OpsManager" , Login
|
145
|
+
subcommand "deploy-appliance", "Deploys/Upgrades OpsManager", DeployAppliance
|
146
|
+
subcommand "deploy-product", "Deploys/Upgrades product tiles", DeployProduct
|
147
|
+
subcommand "get-director-template", "Generates Director installation template", GetDirectorTemplate
|
148
|
+
subcommand "get-product-template", "Generates Product tile installation template", GetProductTemplate
|
149
|
+
|
150
|
+
# Other commands
|
151
|
+
subcommand "curl", "Authenticated curl requests(POST/GET)", Curl
|
152
|
+
subcommand "get-installation-settings", "Gets installation settings", GetInstallationSettings
|
153
|
+
subcommand "get-installation-logs", "Gets installation logs", GetInstallationLogs
|
154
|
+
subcommand "get-uaa-token", "Gets uaa token from OpsManager", GetUaaToken
|
155
|
+
subcommand "import-stemcell", "Uploads stemcell to OpsManager", ImportStemcell
|
156
|
+
subcommand "delete-unused-products", "Deletes unused product tiles", DeleteUnusedProducts
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
class OpsManager
|
4
|
+
class Configs
|
5
|
+
class Base < OpenStruct
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
super(config)
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate_presence_of!(*present_attrs)
|
12
|
+
present_attrs.map!(&:to_s).each do |attr|
|
13
|
+
raise "missing #{attr} on config" unless @config.has_key?(attr)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def filepath
|
18
|
+
find_full_path(@config['filepath'])
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_full_path(filepath)
|
22
|
+
return unless filepath
|
23
|
+
`find #{filepath}`.split("\n").first
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'ops_manager/configs/base'
|
2
|
+
|
3
|
+
class OpsManager
|
4
|
+
class Configs
|
5
|
+
class OpsmanDeployment < Base
|
6
|
+
def initialize(config)
|
7
|
+
super(config)
|
8
|
+
validate_presence_of!(:name, :desired_version, :provider, :username, :password, :pivnet_token, :ip, :opts)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'ops_manager/configs/base'
|
2
|
+
|
3
|
+
class OpsManager
|
4
|
+
class Configs
|
5
|
+
class ProductDeployment < Base
|
6
|
+
def initialize(config)
|
7
|
+
super(config)
|
8
|
+
validate_presence_of!(:name, :desired_version)
|
9
|
+
end
|
10
|
+
|
11
|
+
def stemcell
|
12
|
+
find_full_path(@config['stemcell'])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rbvmomi'
|
2
|
+
require "uri"
|
3
|
+
require "ops_manager/logging"
|
4
|
+
|
5
|
+
class OpsManager
|
6
|
+
module Deployments
|
7
|
+
module Vsphere
|
8
|
+
include OpsManager::Logging
|
9
|
+
include OpsManager::Logging
|
10
|
+
|
11
|
+
def deploy_vm(name, ip)
|
12
|
+
puts '====> Starts ova deployment'.green
|
13
|
+
vcenter_target= "vi://#{vcenter_username}:#{vcenter_password}@#{config.opts['vcenter']['host']}/#{config.opts['vcenter']['datacenter']}/host/#{config.opts['vcenter']['cluster']}"
|
14
|
+
cmd = "echo yes | ovftool --acceptAllEulas --noSSLVerify --powerOn --X:waitForIp --net:\"Network 1=#{config.opts['portgroup']}\" --name=#{name} -ds=#{config.opts['datastore']} --prop:ip0=#{ip} --prop:netmask0=#{config.opts['netmask']} --prop:gateway=#{config.opts['gateway']} --prop:DNS=#{config.opts['dns']} --prop:ntp_servers=#{config.opts['ntp_servers'].join(',')} --prop:admin_password=#{config.password} #{config.opts['ova_path']} #{vcenter_target}"
|
15
|
+
logger.info cmd
|
16
|
+
puts `#{cmd}`
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop_current_vm(name)
|
20
|
+
puts "====> Stopping vm #{name}...".green
|
21
|
+
dc = vim.serviceInstance.find_datacenter(config.opts['vcenter']['datacenter'])
|
22
|
+
logger.info "finding vm: #{name}"
|
23
|
+
vm = dc.find_vm(name) or fail "VM not found"
|
24
|
+
vm.PowerOffVM_Task.wait_for_completion
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def vim
|
29
|
+
RbVmomi::VIM.connect host: config.opts['vcenter']['host'], user: URI.unescape(config.opts['vcenter']['username']), password: URI.unescape(config.opts['vcenter']['password']), insecure: true
|
30
|
+
end
|
31
|
+
|
32
|
+
def vcenter_username
|
33
|
+
URI.encode(config.opts['vcenter']['username'])
|
34
|
+
end
|
35
|
+
|
36
|
+
def vcenter_password
|
37
|
+
URI.encode(config.opts['vcenter']['password'])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class OpsManager
|
2
|
+
class DirectorTemplateGenerator
|
3
|
+
def generate
|
4
|
+
merge_director_template_products
|
5
|
+
delete_schema_version
|
6
|
+
delete_director_ssl
|
7
|
+
delete_uaa_ssl
|
8
|
+
delete_guid
|
9
|
+
delete_ip_assignments
|
10
|
+
installation_settings.to_h
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate_yml
|
14
|
+
generate.to_yaml
|
15
|
+
.gsub('"(( merge on guid ))"', '(( merge on guid ))')
|
16
|
+
.gsub('"(( merge on identifier ))"', '(( merge on identifier ))')
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def installation_settings
|
21
|
+
return @installation_settings if @installation_settings
|
22
|
+
parsed_installation_settings = JSON.parse(installation_settings_response.body)
|
23
|
+
@installation_settings = OpsManager::InstallationSettings.new(parsed_installation_settings)
|
24
|
+
end
|
25
|
+
|
26
|
+
def merge_director_template_products
|
27
|
+
installation_settings.merge!('products' => director_product_template.fetch('products'))
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete_schema_version
|
31
|
+
@installation_settings.delete('installation_schema_version')
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete_ip_assignments
|
35
|
+
@installation_settings.delete('ip_assignments')
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete_guid
|
39
|
+
@installation_settings.delete('guid')
|
40
|
+
end
|
41
|
+
|
42
|
+
def delete_director_ssl
|
43
|
+
director_product_template["products"][1].delete("director_ssl")
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_uaa_ssl
|
47
|
+
director_product_template["products"][1].delete("uaa_ssl")
|
48
|
+
end
|
49
|
+
|
50
|
+
def director_product_template
|
51
|
+
@director_product_template ||= OpsManager::ProductTemplateGenerator.new('p-bosh').generate
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def installation_settings_response
|
56
|
+
OpsManager::Api::Opsman.new(silent: true).get_installation_settings
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class OpsManager
|
2
|
+
class UpgradeError < RuntimeError ; end
|
3
|
+
class InstallationError < RuntimeError ; end
|
4
|
+
class ProductDeploymentError < RuntimeError ; end
|
5
|
+
class InstallationSettingsError < RuntimeError ; end
|
6
|
+
class PivnetAuthenticationError < RuntimeError ; end
|
7
|
+
class StemcellUploadError < RuntimeError ; end
|
8
|
+
class ProductUploadError < RuntimeError ; end
|
9
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class OpsManager
|
2
|
+
class Installation
|
3
|
+
attr_reader :id
|
4
|
+
|
5
|
+
def initialize(id)
|
6
|
+
@id = id
|
7
|
+
end
|
8
|
+
|
9
|
+
def logs
|
10
|
+
parsed_logs.fetch('logs')
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def all
|
15
|
+
parsed_installations.fetch('installations').collect{ |i| new(i.fetch('id')) }.reverse
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def parsed_installations
|
21
|
+
JSON.parse(opsman_api.get_installations.body)
|
22
|
+
end
|
23
|
+
|
24
|
+
def opsman_api
|
25
|
+
OpsManager::Api::Opsman.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def parsed_logs
|
31
|
+
JSON.parse(opsman_api.get_installation_logs(id).body)
|
32
|
+
end
|
33
|
+
|
34
|
+
def opsman_api
|
35
|
+
@opsman_api ||= OpsManager::Api::Opsman.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class OpsManager
|
2
|
+
class InstallationRunner
|
3
|
+
extend Forwardable
|
4
|
+
def_delegators :opsman_api, :trigger_installation, :get_installation, :get_current_version,
|
5
|
+
:get_staged_products, :get_staged_products_errands
|
6
|
+
attr_reader :id
|
7
|
+
|
8
|
+
def trigger!
|
9
|
+
res = trigger_installation( body: body.join('&') )
|
10
|
+
@id = JSON.parse(res.body).fetch('install').fetch('id').to_i
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.trigger!
|
15
|
+
new.trigger!
|
16
|
+
end
|
17
|
+
|
18
|
+
def wait_for_result
|
19
|
+
while JSON.parse(get_installation(id).body).fetch('status') == 'running'
|
20
|
+
print '.'.green
|
21
|
+
sleep 10
|
22
|
+
end
|
23
|
+
puts ''
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def body
|
28
|
+
@body ||= [ 'ignore_warnings=true' ]
|
29
|
+
@body << errands_body
|
30
|
+
|
31
|
+
@body
|
32
|
+
end
|
33
|
+
|
34
|
+
def opsman_api
|
35
|
+
@opsman_api ||= OpsManager::Api::Opsman.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def errands_body
|
39
|
+
staged_products_guids.collect do |product_guid|
|
40
|
+
post_deploy_errands_body_for(product_guid)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def post_deploy_errands_body_for(product_guid)
|
45
|
+
post_deploy_errands = post_deploy_errands_for(product_guid)
|
46
|
+
|
47
|
+
unless post_deploy_errands.empty?
|
48
|
+
post_deploy_errands.collect{ |e| "enabled_errands[#{product_guid}][post_deploy_errands][]=#{e}" }
|
49
|
+
else
|
50
|
+
"enabled_errands[#{product_guid}]{}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def staged_products_guids
|
55
|
+
staged_products.collect {|product| product.fetch('guid') }
|
56
|
+
end
|
57
|
+
|
58
|
+
def staged_products
|
59
|
+
JSON.parse(get_staged_products.body)
|
60
|
+
end
|
61
|
+
|
62
|
+
def post_deploy_errands_for(product_guid)
|
63
|
+
errands_for(product_guid).keep_if{ |errand| errand['post_deploy'] }.map{ |o| o['name']}
|
64
|
+
end
|
65
|
+
|
66
|
+
def errands_for(product_guid)
|
67
|
+
res = get_staged_products_errands(product_guid)
|
68
|
+
if res.code == 200
|
69
|
+
JSON.parse(res.body)['errands']
|
70
|
+
else
|
71
|
+
[]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class OpsManager
|
2
|
+
class InstallationSettings < Hash
|
3
|
+
def initialize(parsed_installation_settings)
|
4
|
+
super.merge!(parsed_installation_settings)
|
5
|
+
end
|
6
|
+
|
7
|
+
def stemcells
|
8
|
+
self.fetch('products').inject([]) do |a, p|
|
9
|
+
a << {
|
10
|
+
version: p['stemcell'].fetch('version'),
|
11
|
+
file: p['stemcell'].fetch('file'),
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
class OpsManager
|
4
|
+
module Logging
|
5
|
+
def logger
|
6
|
+
Logging.logger
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.logger
|
10
|
+
@logger ||= Logger.new( ENV['DEBUG'].nil? ? 'ops_manager.log' : STDOUT)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.logger=(logger)
|
14
|
+
@logger = logger
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|