ops_manager_cli 0.5.4 → 0.7.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 +4 -4
- data/CHANGELOG.md +16 -1
- data/Dockerfile +1 -1
- data/lib/ops_manager/api/base.rb +3 -0
- data/lib/ops_manager/api/opsman.rb +38 -1
- data/lib/ops_manager/appliance/aws.rb +89 -0
- data/lib/ops_manager/appliance/base.rb +23 -0
- data/lib/ops_manager/appliance/vsphere.rb +47 -0
- data/lib/ops_manager/appliance_deployment.rb +48 -28
- data/lib/ops_manager/cli.rb +7 -0
- data/lib/ops_manager/config/base.rb +42 -0
- data/lib/ops_manager/{configs → config}/opsman_deployment.rb +2 -2
- data/lib/ops_manager/config/product_deployment.rb +13 -0
- data/lib/ops_manager/configs/base.rb +1 -1
- data/lib/ops_manager/installation_runner.rb +8 -19
- data/lib/ops_manager/product_deployment.rb +16 -14
- data/lib/ops_manager/version.rb +1 -1
- data/lib/ops_manager.rb +4 -3
- data/ops_manager.gemspec +1 -0
- metadata +22 -5
- data/lib/ops_manager/configs/product_deployment.rb +0 -16
- data/lib/ops_manager/deployments/vsphere.rb +0 -45
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8992b156cebae9e672d078b6da9b8657a650b093
|
|
4
|
+
data.tar.gz: 70fab26214ffab2248756aa0e281fb287acd0e5e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c2e769b03f59448e5e415f141d2dac8d6009ae272c748c20aabb98b8c6ea6b70d38ada89d20c335e13daafe79fbb9ec9a44be775a7ca3750d69396a20459606e
|
|
7
|
+
data.tar.gz: 3ef3595a66344221983bdde63e1c770a3422453286656bdf572f2d8b4f66c6e8a4e01ed8549e2bd4672246c4f508e3d789fcee5542fd5f67acc69f138f07d201
|
data/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## [v0.5.4](https://github.com/compozed/ops_manager_cli/tree/v0.5.4) (2017-06-27)
|
|
4
|
+
[Full Changelog](https://github.com/compozed/ops_manager_cli/compare/v0.5.3...v0.5.4)
|
|
5
|
+
|
|
6
|
+
## [v0.5.3](https://github.com/compozed/ops_manager_cli/tree/v0.5.3) (2017-06-27)
|
|
7
|
+
[Full Changelog](https://github.com/compozed/ops_manager_cli/compare/v0.5.2...v0.5.3)
|
|
8
|
+
|
|
3
9
|
## [v0.5.2](https://github.com/compozed/ops_manager_cli/tree/v0.5.2) (2017-06-27)
|
|
4
10
|
[Full Changelog](https://github.com/compozed/ops_manager_cli/compare/v0.5.1...v0.5.2)
|
|
5
11
|
|
|
6
12
|
**Closed issues:**
|
|
7
13
|
|
|
14
|
+
- CLI should check that UAA is available after Ops Manager upgrades [\#29](https://github.com/compozed/ops_manager_cli/issues/29)
|
|
15
|
+
- When upgrading opsman the token does not reset [\#27](https://github.com/compozed/ops_manager_cli/issues/27)
|
|
8
16
|
- Support refresh tokens for re-authentication with UAA [\#24](https://github.com/compozed/ops_manager_cli/issues/24)
|
|
9
|
-
- Upgrading product does not work with opsman\_cli 0.5.0 on opsman 1.9 [\#23](https://github.com/compozed/ops_manager_cli/issues/23)
|
|
10
17
|
- Allow toggling ops\_manager.log [\#21](https://github.com/compozed/ops_manager_cli/issues/21)
|
|
11
18
|
|
|
12
19
|
## [v0.5.1](https://github.com/compozed/ops_manager_cli/tree/v0.5.1) (2017-01-25)
|
|
13
20
|
[Full Changelog](https://github.com/compozed/ops_manager_cli/compare/v0.5.0...v0.5.1)
|
|
14
21
|
|
|
22
|
+
**Closed issues:**
|
|
23
|
+
|
|
24
|
+
- Upgrading product does not work with opsman\_cli 0.5.0 on opsman 1.9 [\#23](https://github.com/compozed/ops_manager_cli/issues/23)
|
|
25
|
+
|
|
15
26
|
## [v0.5.0](https://github.com/compozed/ops_manager_cli/tree/v0.5.0) (2017-01-24)
|
|
16
27
|
[Full Changelog](https://github.com/compozed/ops_manager_cli/compare/v0.4.1...v0.5.0)
|
|
17
28
|
|
|
@@ -21,6 +32,7 @@
|
|
|
21
32
|
|
|
22
33
|
**Closed issues:**
|
|
23
34
|
|
|
35
|
+
- Upgrade does not merge product installation settings [\#22](https://github.com/compozed/ops_manager_cli/issues/22)
|
|
24
36
|
- ops\_manager curl -x PUT not working [\#17](https://github.com/compozed/ops_manager_cli/issues/17)
|
|
25
37
|
- When uploading stemcell it does not show the correct output [\#15](https://github.com/compozed/ops_manager_cli/issues/15)
|
|
26
38
|
|
|
@@ -30,6 +42,7 @@
|
|
|
30
42
|
**Fixed bugs:**
|
|
31
43
|
|
|
32
44
|
- Director template generator does not delete UAA sensitive data [\#13](https://github.com/compozed/ops_manager_cli/issues/13)
|
|
45
|
+
- Product template generator does not delete stemcell metadata properties [\#12](https://github.com/compozed/ops_manager_cli/issues/12)
|
|
33
46
|
|
|
34
47
|
## [v0.4.0](https://github.com/compozed/ops_manager_cli/tree/v0.4.0) (2016-10-20)
|
|
35
48
|
[Full Changelog](https://github.com/compozed/ops_manager_cli/compare/v0.3.0...v0.4.0)
|
|
@@ -37,12 +50,14 @@
|
|
|
37
50
|
**Implemented enhancements:**
|
|
38
51
|
|
|
39
52
|
- Improve output for appliance deploy/upgrade [\#11](https://github.com/compozed/ops_manager_cli/issues/11)
|
|
53
|
+
- Improve output for product deploy/upgrade [\#10](https://github.com/compozed/ops_manager_cli/issues/10)
|
|
40
54
|
- Run errands when applying changes [\#9](https://github.com/compozed/ops_manager_cli/issues/9)
|
|
41
55
|
- 1.8 support [\#5](https://github.com/compozed/ops_manager_cli/pull/5) ([bonzofenix](https://github.com/bonzofenix))
|
|
42
56
|
|
|
43
57
|
**Fixed bugs:**
|
|
44
58
|
|
|
45
59
|
- delete-unused-products command not working [\#8](https://github.com/compozed/ops_manager_cli/issues/8)
|
|
60
|
+
- Hardcoded user name admin when logging agains ops\_manager [\#2](https://github.com/compozed/ops_manager_cli/issues/2)
|
|
46
61
|
|
|
47
62
|
**Closed issues:**
|
|
48
63
|
|
data/Dockerfile
CHANGED
data/lib/ops_manager/api/base.rb
CHANGED
|
@@ -25,6 +25,10 @@ class OpsManager
|
|
|
25
25
|
authenticated_get("/api/v0/staged/products", opts)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
def get_pending_changes(opts = {})
|
|
29
|
+
authenticated_get("/api/v0/staged/pending_changes", opts)
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
def get_installation_settings(opts = {})
|
|
29
33
|
print_green '====> Downloading installation settings ...'
|
|
30
34
|
res = authenticated_get("/api/installation_settings", opts)
|
|
@@ -117,7 +121,7 @@ class OpsManager
|
|
|
117
121
|
|
|
118
122
|
def get_diagnostic_report
|
|
119
123
|
authenticated_get("/api/v0/diagnostic_report")
|
|
120
|
-
rescue Errno::ETIMEDOUT , Errno::EHOSTUNREACH, Net::HTTPFatalError, Net::OpenTimeout
|
|
124
|
+
rescue Errno::ETIMEDOUT , Errno::EHOSTUNREACH, Net::HTTPFatalError, Net::OpenTimeout, HTTPClient::ConnectTimeoutError
|
|
121
125
|
nil
|
|
122
126
|
end
|
|
123
127
|
|
|
@@ -153,6 +157,23 @@ class OpsManager
|
|
|
153
157
|
nil
|
|
154
158
|
end
|
|
155
159
|
|
|
160
|
+
def pending_changes(opts = {})
|
|
161
|
+
print_green '====> Getting pending changes ...'
|
|
162
|
+
res = authenticated_get('/api/v0/staged/pending_changes')
|
|
163
|
+
pendingChanges = JSON.parse(res.body)
|
|
164
|
+
|
|
165
|
+
if pendingChanges['product_changes'].count == 0
|
|
166
|
+
puts "\nNo pending changes"
|
|
167
|
+
else
|
|
168
|
+
pendingChanges['product_changes'].each do |product|
|
|
169
|
+
puts "\n#{product['guid']}"
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
say_green 'done'
|
|
174
|
+
res
|
|
175
|
+
end
|
|
176
|
+
|
|
156
177
|
def username
|
|
157
178
|
@username ||= OpsManager.get_conf(:username)
|
|
158
179
|
end
|
|
@@ -174,7 +195,23 @@ class OpsManager
|
|
|
174
195
|
@access_token ||= get_token.info['access_token']
|
|
175
196
|
end
|
|
176
197
|
|
|
198
|
+
def wait_for_https_alive(limit)
|
|
199
|
+
@retry_counter = 0
|
|
200
|
+
res = nil
|
|
201
|
+
until(@retry_counter >= limit or (res = check_alive).code.to_i < 400) do
|
|
202
|
+
sleep 1
|
|
203
|
+
@retry_counter += 1
|
|
204
|
+
end
|
|
205
|
+
res
|
|
206
|
+
end
|
|
207
|
+
|
|
177
208
|
private
|
|
209
|
+
def check_alive
|
|
210
|
+
get("/")
|
|
211
|
+
rescue Net::OpenTimeout, Net::HTTPError, Net::HTTPFatalError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET => e
|
|
212
|
+
Net::HTTPInternalServerError.new(1.0, 500, e.inspect)
|
|
213
|
+
end
|
|
214
|
+
|
|
178
215
|
def token_issuer
|
|
179
216
|
@token_issuer ||= CF::UAA::TokenIssuer.new(
|
|
180
217
|
"https://#{target}/uaa", 'opsman', nil, skip_ssl_validation: true )
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'fog/aws'
|
|
2
|
+
require 'ops_manager/appliance/base'
|
|
3
|
+
|
|
4
|
+
class OpsManager
|
|
5
|
+
module Appliance
|
|
6
|
+
class AWS < Base
|
|
7
|
+
|
|
8
|
+
def deploy_vm
|
|
9
|
+
image_id = ::YAML.load_file(ami_mapping_file)[config[:opts][:region]]
|
|
10
|
+
|
|
11
|
+
server = connection.servers.create(
|
|
12
|
+
block_device_mapping: [{
|
|
13
|
+
'DeviceName' => '/dev/xvda',
|
|
14
|
+
'Ebs.VolumeSize' => config[:opts][:disk_size_in_gb],
|
|
15
|
+
}],
|
|
16
|
+
key_name: config[:opts][:ssh_keypair_name],
|
|
17
|
+
flavor_id: config[:opts][:instance_type],
|
|
18
|
+
subnet_id: config[:opts][:subnet_id],
|
|
19
|
+
image_id: image_id,
|
|
20
|
+
private_ip_address: config[:ip],
|
|
21
|
+
security_group_ids: security_group_ids,
|
|
22
|
+
availability_zone: config[:opts][:availability_zone],
|
|
23
|
+
iam_instance_profile_name: config[:opts][:instance_profile_name],
|
|
24
|
+
tags: {
|
|
25
|
+
'Name' => vm_name,
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
server.wait_for { ready? }
|
|
29
|
+
return server
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def stop_current_vm(name)
|
|
33
|
+
server = connection.servers.all("private-ip-address" => config[:ip], "tag:Name" => name).first
|
|
34
|
+
if ! server
|
|
35
|
+
fail "VM not found matching IP '#{config[:ip]}', named '#{name}'"
|
|
36
|
+
end
|
|
37
|
+
server.stop
|
|
38
|
+
server.wait_for { server.state == "stopped" }
|
|
39
|
+
|
|
40
|
+
# Create ami of stopped server
|
|
41
|
+
response = connection.create_image(server.id, "#{name}-backup", "Backup of #{name}")
|
|
42
|
+
image = connection.images.get( response.data[:body]['imageId'])
|
|
43
|
+
image.wait_for { image.state == "available" }
|
|
44
|
+
if image.state != "available"
|
|
45
|
+
fail "Error creating backup AMI, bailing out before destroying the VM"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
puts "Saved #{name} to AMI #{image.id} (#{name}-backup) for safe-keeping"
|
|
49
|
+
|
|
50
|
+
server.destroy
|
|
51
|
+
if !Fog.mocking?
|
|
52
|
+
server.wait_for { server.state == 'terminated' }
|
|
53
|
+
else
|
|
54
|
+
# Fog's mock doesn't support transitioning state from terminating -> terminated
|
|
55
|
+
# so we have to hack this here
|
|
56
|
+
server.wait_for { server.state == 'terminating' }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
def ami_mapping_file
|
|
62
|
+
Dir.glob(config[:opts][:ami_mapping_file]).first
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def security_group_ids
|
|
66
|
+
config[:opts][:security_groups].collect do |sg|
|
|
67
|
+
connection.security_groups.get(sg).group_id
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def connection
|
|
72
|
+
if config[:opts][:use_iam_profile]
|
|
73
|
+
@connection ||= Fog::Compute.new({
|
|
74
|
+
provider: config[:provider],
|
|
75
|
+
use_iam_profile: config[:opts][:use_iam_profile],
|
|
76
|
+
aws_access_key_id: "",
|
|
77
|
+
aws_secret_access_key: "",
|
|
78
|
+
})
|
|
79
|
+
else
|
|
80
|
+
@connection ||= Fog::Compute.new({
|
|
81
|
+
provider: config[:provider],
|
|
82
|
+
aws_access_key_id: config[:opts][:access_key],
|
|
83
|
+
aws_secret_access_key: config[:opts][:secret_key],
|
|
84
|
+
})
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
class OpsManager
|
|
3
|
+
module Appliance
|
|
4
|
+
class Base
|
|
5
|
+
attr_reader :config
|
|
6
|
+
|
|
7
|
+
def initialize(config)
|
|
8
|
+
@config = config
|
|
9
|
+
end
|
|
10
|
+
def deploy_vm
|
|
11
|
+
raise NotImplementedError.new("You must implement deploy_vm.")
|
|
12
|
+
end
|
|
13
|
+
def stop_current_vm(name)
|
|
14
|
+
raise NotImplementedError.new("You must implement stop_current_vm.")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
def vm_name
|
|
19
|
+
@vm_name ||= "#{config[:name]}-#{config[:desired_version]}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'rbvmomi'
|
|
2
|
+
require "uri"
|
|
3
|
+
require 'shellwords'
|
|
4
|
+
require "ops_manager/logging"
|
|
5
|
+
require 'ops_manager/appliance/base'
|
|
6
|
+
|
|
7
|
+
class OpsManager
|
|
8
|
+
module Appliance
|
|
9
|
+
class Vsphere < Base
|
|
10
|
+
include OpsManager::Logging
|
|
11
|
+
attr_reader :config
|
|
12
|
+
|
|
13
|
+
def deploy_vm
|
|
14
|
+
print '====> Deploying ova ...'.green
|
|
15
|
+
vcenter_target= "vi://#{vcenter_username}:#{vcenter_password}@#{config[:opts][:vcenter][:host]}/#{config[:opts][:vcenter][:datacenter]}/host/#{config[:opts][:vcenter][:cluster]}"
|
|
16
|
+
cmd = "echo yes | ovftool --acceptAllEulas --noSSLVerify --powerOn --X:waitForIp --net:\"Network 1=#{config[:opts][:portgroup]}\" --name=#{vm_name} -ds=#{config[:opts][:datastore]} --prop:ip0=#{config[: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}"
|
|
17
|
+
logger.info "Running: #{cmd}"
|
|
18
|
+
logger.info `#{cmd}`
|
|
19
|
+
puts 'done'.green
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def stop_current_vm(name)
|
|
23
|
+
print "====> Stopping vm #{name} ...".green
|
|
24
|
+
dc = vim.serviceInstance.find_datacenter(config[:opts][:vcenter][:datacenter])
|
|
25
|
+
logger.info "finding vm: #{name}"
|
|
26
|
+
vm = dc.find_vm(name) or fail "VM not found"
|
|
27
|
+
vm.PowerOffVM_Task.wait_for_completion
|
|
28
|
+
puts 'done'.green
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
def vim
|
|
33
|
+
RbVmomi::VIM.connect host: config[:opts][:vcenter][:host], user: URI.unescape(config[:opts][:vcenter][:username]), password: URI.unescape(config[:opts][:vcenter][:password]), insecure: true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def vcenter_username
|
|
37
|
+
Shellwords.escape(URI.encode(config[:opts][:vcenter][:username]))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def vcenter_password
|
|
41
|
+
Shellwords.escape(URI.encode(config[:opts][:vcenter][:password]))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
require "ops_manager/api/opsman"
|
|
2
2
|
require "ops_manager/api/pivnet"
|
|
3
|
-
require 'ops_manager/
|
|
3
|
+
require 'ops_manager/config/opsman_deployment'
|
|
4
4
|
require 'fileutils'
|
|
5
5
|
|
|
6
6
|
class OpsManager::ApplianceDeployment
|
|
7
7
|
extend Forwardable
|
|
8
|
+
attr_reader :config
|
|
9
|
+
|
|
8
10
|
def_delegators :pivnet_api, :get_product_releases, :accept_product_release_eula,
|
|
9
11
|
:get_product_release_files, :download_product_release_file
|
|
10
|
-
def_delegators :opsman_api, :create_user, :
|
|
12
|
+
def_delegators :opsman_api, :create_user, :get_installation_assets,
|
|
11
13
|
:get_installation_settings, :get_diagnostic_report, :upload_installation_assets, :get_ensure_availability,
|
|
12
|
-
:import_stemcell, :target, :password, :username, :ops_manager_version= , :reset_access_token
|
|
14
|
+
:import_stemcell, :target, :password, :username, :ops_manager_version= , :reset_access_token, :get_pending_changes,
|
|
15
|
+
:wait_for_https_alive
|
|
13
16
|
|
|
14
17
|
attr_reader :config_file
|
|
15
18
|
|
|
@@ -18,35 +21,37 @@ class OpsManager::ApplianceDeployment
|
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
def run
|
|
21
|
-
OpsManager.set_conf(:target, config
|
|
22
|
-
OpsManager.set_conf(:username, config
|
|
23
|
-
OpsManager.set_conf(:password, config
|
|
24
|
-
OpsManager.set_conf(:pivnet_token, config
|
|
24
|
+
OpsManager.set_conf(:target, config[:ip])
|
|
25
|
+
OpsManager.set_conf(:username, config[:username])
|
|
26
|
+
OpsManager.set_conf(:password, config[:password])
|
|
27
|
+
OpsManager.set_conf(:pivnet_token, config[:pivnet_token])
|
|
25
28
|
|
|
26
|
-
self.extend(OpsManager::Deployments::Vsphere)
|
|
27
29
|
|
|
28
30
|
case
|
|
29
31
|
when current_version.empty?
|
|
30
|
-
puts "No OpsManager deployed at #{config
|
|
32
|
+
puts "No OpsManager deployed at #{config[:ip]}. Deploying ...".green
|
|
31
33
|
deploy
|
|
32
34
|
create_first_user
|
|
33
35
|
when current_version < desired_version then
|
|
34
|
-
puts "OpsManager at #{config
|
|
36
|
+
puts "OpsManager at #{config[:ip]} version is #{current_version}. Upgrading to #{desired_version} .../".green
|
|
35
37
|
upgrade
|
|
36
38
|
when current_version == desired_version then
|
|
37
|
-
|
|
39
|
+
if pending_changes?
|
|
40
|
+
puts "OpsManager at #{config[:ip]} version has pending changes. Applying changes...".green
|
|
41
|
+
OpsManager::InstallationRunner.trigger!.wait_for_result
|
|
42
|
+
else
|
|
43
|
+
puts "OpsManager at #{config[:ip]} version is already #{config[:desired_version]}. Skiping ...".green
|
|
44
|
+
end
|
|
38
45
|
end
|
|
39
46
|
|
|
40
47
|
puts '====> Finish!'.green
|
|
41
48
|
end
|
|
42
49
|
|
|
43
|
-
def
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
define_method(m) do
|
|
49
|
-
raise NotImplementedError
|
|
50
|
+
def appliance
|
|
51
|
+
@appliance ||= if config[:provider] =~/vsphere/i
|
|
52
|
+
OpsManager::Appliance::Vsphere.new(config)
|
|
53
|
+
else
|
|
54
|
+
OpsManager::Appliance::AWS.new(config)
|
|
50
55
|
end
|
|
51
56
|
end
|
|
52
57
|
|
|
@@ -57,10 +62,15 @@ class OpsManager::ApplianceDeployment
|
|
|
57
62
|
end
|
|
58
63
|
end
|
|
59
64
|
|
|
65
|
+
def deploy
|
|
66
|
+
appliance.deploy_vm
|
|
67
|
+
wait_for_https_alive 300
|
|
68
|
+
end
|
|
69
|
+
|
|
60
70
|
def upgrade
|
|
61
71
|
get_installation_assets
|
|
62
72
|
download_current_stemcells
|
|
63
|
-
stop_current_vm(
|
|
73
|
+
appliance.stop_current_vm(current_name)
|
|
64
74
|
deploy
|
|
65
75
|
upload_installation_assets
|
|
66
76
|
wait_for_uaa
|
|
@@ -113,21 +123,30 @@ class OpsManager::ApplianceDeployment
|
|
|
113
123
|
list_current_stemcells.each do |stemcell_version|
|
|
114
124
|
release_id = find_stemcell_release(stemcell_version)
|
|
115
125
|
accept_product_release_eula('stemcells', release_id )
|
|
116
|
-
|
|
126
|
+
stemcell_regex = /vsphere/
|
|
127
|
+
if config[:provider] == "AWS"
|
|
128
|
+
stemcell_regex = /aws/
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
file_id, file_name = find_stemcell_file(release_id, stemcell_regex)
|
|
117
132
|
download_product_release_file('stemcells', release_id, file_id, write_to: "#{current_stemcell_dir}/#{file_name}")
|
|
118
133
|
end
|
|
119
134
|
end
|
|
120
135
|
|
|
121
136
|
def new_vm_name
|
|
122
|
-
@new_vm_name ||= "#{config
|
|
137
|
+
@new_vm_name ||= "#{config[:name]}-#{config[:desired_version]}"
|
|
123
138
|
end
|
|
124
139
|
|
|
125
140
|
def current_version
|
|
126
141
|
@current_version ||= OpsManager::Semver.new(version_from_diagnostic_report)
|
|
127
142
|
end
|
|
128
143
|
|
|
144
|
+
def current_name
|
|
145
|
+
@current_name ||= "#{config[:name]}-#{current_version}"
|
|
146
|
+
end
|
|
147
|
+
|
|
129
148
|
def desired_version
|
|
130
|
-
@desired_version ||= OpsManager::Semver.new(config
|
|
149
|
+
@desired_version ||= OpsManager::Semver.new(config[:desired_version])
|
|
131
150
|
end
|
|
132
151
|
|
|
133
152
|
def provision_stemcells
|
|
@@ -167,12 +186,9 @@ class OpsManager::ApplianceDeployment
|
|
|
167
186
|
end
|
|
168
187
|
|
|
169
188
|
def current_vm_name
|
|
170
|
-
@current_vm_name ||= "#{config
|
|
189
|
+
@current_vm_name ||= "#{config[:name]}-#{current_version}"
|
|
171
190
|
end
|
|
172
191
|
|
|
173
|
-
def desired_vm_name
|
|
174
|
-
@desired_vm_name ||= "#{config.name}-#{config.desired_version}"
|
|
175
|
-
end
|
|
176
192
|
|
|
177
193
|
def pivnet_api
|
|
178
194
|
@pivnet_api ||= OpsManager::Api::Pivnet.new
|
|
@@ -183,10 +199,10 @@ class OpsManager::ApplianceDeployment
|
|
|
183
199
|
end
|
|
184
200
|
|
|
185
201
|
def config
|
|
186
|
-
|
|
187
|
-
@config ||= OpsManager::Configs::OpsmanDeployment.new(parsed_yml)
|
|
202
|
+
@config ||= OpsManager::Config::OpsmanDeployment.new(YAML.load_file(@config_file))
|
|
188
203
|
end
|
|
189
204
|
|
|
205
|
+
|
|
190
206
|
def desired_version?(version)
|
|
191
207
|
!!(desired_version.to_s =~/#{version}/)
|
|
192
208
|
end
|
|
@@ -206,4 +222,8 @@ class OpsManager::ApplianceDeployment
|
|
|
206
222
|
def current_stemcell_dir
|
|
207
223
|
"/tmp/current_stemcells"
|
|
208
224
|
end
|
|
225
|
+
|
|
226
|
+
def pending_changes?
|
|
227
|
+
!JSON.parse(get_pending_changes.body).fetch('product_changes').empty?
|
|
228
|
+
end
|
|
209
229
|
end
|
data/lib/ops_manager/cli.rb
CHANGED
|
@@ -72,6 +72,12 @@ class OpsManager
|
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
class PendingChanges < Clamp::Command
|
|
76
|
+
def execute
|
|
77
|
+
OpsManager::Api::Opsman.new.pending_changes
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
75
81
|
class DeleteUnusedProducts < Clamp::Command
|
|
76
82
|
|
|
77
83
|
def execute
|
|
@@ -158,6 +164,7 @@ class OpsManager
|
|
|
158
164
|
subcommand "get-installation-settings", "Gets installation settings", GetInstallationSettings
|
|
159
165
|
subcommand "get-installation-logs", "Gets installation logs", GetInstallationLogs
|
|
160
166
|
subcommand "import-stemcell", "Uploads stemcell to OpsManager", ImportStemcell
|
|
167
|
+
subcommand "pending-changes", "View pending changes in OpsManager", PendingChanges
|
|
161
168
|
|
|
162
169
|
end
|
|
163
170
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'ostruct'
|
|
2
|
+
|
|
3
|
+
class OpsManager
|
|
4
|
+
module Config
|
|
5
|
+
class Base < OpenStruct
|
|
6
|
+
def initialize(config)
|
|
7
|
+
super(config.to_symbolize)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def validate_presence_of!(*attrs)
|
|
11
|
+
attrs.each do |attr|
|
|
12
|
+
raise "missing #{attr} on config" unless self.to_h.has_key?(attr)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def expand_path_for!(*attrs)
|
|
17
|
+
attrs.each do |attr|
|
|
18
|
+
path = self[attr]
|
|
19
|
+
self[attr] = if path =~ %r{^file://}
|
|
20
|
+
path = Dir.glob(path.gsub!('file://','')).first
|
|
21
|
+
"file://#{path}"
|
|
22
|
+
else
|
|
23
|
+
Dir.glob(path).first
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Hash
|
|
32
|
+
def to_symbolize
|
|
33
|
+
Hash[self.map do |k, v|
|
|
34
|
+
if v.kind_of?(Hash)
|
|
35
|
+
[k.to_sym, v.to_symbolize]
|
|
36
|
+
else
|
|
37
|
+
[k.to_sym, v]
|
|
38
|
+
end
|
|
39
|
+
end]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
@@ -6,7 +6,7 @@ class OpsManager
|
|
|
6
6
|
attr_reader :id
|
|
7
7
|
|
|
8
8
|
def trigger!
|
|
9
|
-
res = trigger_installation(
|
|
9
|
+
res = trigger_installation( :headers => {"Content-Type"=>"application/json"}, :body => body )
|
|
10
10
|
@id = JSON.parse(res.body).fetch('install').fetch('id').to_i
|
|
11
11
|
self
|
|
12
12
|
end
|
|
@@ -25,27 +25,19 @@ class OpsManager
|
|
|
25
25
|
|
|
26
26
|
private
|
|
27
27
|
def body
|
|
28
|
-
@body ||=
|
|
29
|
-
@body << errands_body
|
|
30
|
-
@body.join('&')
|
|
28
|
+
@body ||= {'errands' => errands, 'ignore_warnings' => true }.to_json
|
|
31
29
|
end
|
|
32
|
-
|
|
33
30
|
def opsman_api
|
|
34
31
|
@opsman_api ||= OpsManager::Api::Opsman.new
|
|
35
32
|
end
|
|
36
33
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
post_deploy_errands = post_deploy_errands_for(product_guid)
|
|
43
|
-
|
|
44
|
-
if post_deploy_errands.empty?
|
|
45
|
-
"enabled_errands[#{product_guid}]{}"
|
|
46
|
-
else
|
|
47
|
-
post_deploy_errands.collect{ |e| "enabled_errands[#{product_guid}][post_deploy_errands][]=#{e}" }
|
|
34
|
+
def errands
|
|
35
|
+
res = { }
|
|
36
|
+
staged_products_guids.each do |product_guid|
|
|
37
|
+
errands = errands_for(product_guid).keep_if { |an_errand| an_errand['post_deploy'] }
|
|
38
|
+
errands.each { |e| res[product_guid] = {'run_post_deploy' => { e['name'] => true}}}
|
|
48
39
|
end
|
|
40
|
+
res
|
|
49
41
|
end
|
|
50
42
|
|
|
51
43
|
def staged_products_guids
|
|
@@ -56,9 +48,6 @@ class OpsManager
|
|
|
56
48
|
JSON.parse(get_staged_products.body)
|
|
57
49
|
end
|
|
58
50
|
|
|
59
|
-
def post_deploy_errands_for(product_guid)
|
|
60
|
-
errands_for(product_guid).keep_if{ |errand| errand['post_deploy'] }.map{ |o| o['name']}
|
|
61
|
-
end
|
|
62
51
|
|
|
63
52
|
def errands_for(product_guid)
|
|
64
53
|
res = get_staged_products_errands(product_guid)
|
|
@@ -7,6 +7,8 @@ require "ops_manager/semver"
|
|
|
7
7
|
class OpsManager
|
|
8
8
|
class ProductDeployment
|
|
9
9
|
extend Forwardable
|
|
10
|
+
attr_reader :config
|
|
11
|
+
|
|
10
12
|
def_delegators :opsman_api, :current_version, :upload_product, :get_installation_settings,
|
|
11
13
|
:upgrade_product_installation, :get_installation, :get_available_products, :upload_installation_settings,
|
|
12
14
|
:trigger_installation, :import_stemcell, :add_staged_products
|
|
@@ -19,12 +21,12 @@ class OpsManager
|
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def installation
|
|
22
|
-
OpsManager::ProductInstallation.find(config
|
|
24
|
+
OpsManager::ProductInstallation.find(config[:name])
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def run
|
|
26
|
-
OpsManager.target_and_login(config
|
|
27
|
-
import_stemcell(config
|
|
28
|
+
OpsManager.target_and_login(config[:target], config[:username], config[:password])
|
|
29
|
+
import_stemcell(config[:stemcell])
|
|
28
30
|
|
|
29
31
|
case
|
|
30
32
|
when installation.nil? || forced_deployment?
|
|
@@ -37,15 +39,15 @@ class OpsManager
|
|
|
37
39
|
end
|
|
38
40
|
|
|
39
41
|
def desired_version
|
|
40
|
-
Semver.new(config
|
|
42
|
+
Semver.new(config[:desired_version])
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def upload
|
|
44
46
|
print "====> Uploading product ...".green
|
|
45
|
-
if ProductDeployment.exists?(config
|
|
47
|
+
if ProductDeployment.exists?(config[:name], config[:desired_version])
|
|
46
48
|
puts "product already exists".green
|
|
47
|
-
elsif config
|
|
48
|
-
upload_product(config
|
|
49
|
+
elsif config[:filepath]
|
|
50
|
+
upload_product(config[:filepath])
|
|
49
51
|
puts "done".green
|
|
50
52
|
else
|
|
51
53
|
puts "no filepath provided, skipping product upload.".green
|
|
@@ -57,9 +59,9 @@ class OpsManager
|
|
|
57
59
|
puts "====> Skipping as this product has a pending installation!".red
|
|
58
60
|
return
|
|
59
61
|
end
|
|
60
|
-
puts "====> Upgrading #{config
|
|
62
|
+
puts "====> Upgrading #{config[:name]} version from #{installation.current_version.to_s} to #{config[:desired_version]}...".green
|
|
61
63
|
upload
|
|
62
|
-
upgrade_product_installation(installation.guid, config
|
|
64
|
+
upgrade_product_installation(installation.guid, config[:desired_version])
|
|
63
65
|
merge_product_installation_settings
|
|
64
66
|
OpsManager::InstallationRunner.trigger!.wait_for_result
|
|
65
67
|
|
|
@@ -68,12 +70,12 @@ class OpsManager
|
|
|
68
70
|
|
|
69
71
|
def add_to_installation
|
|
70
72
|
unless installation
|
|
71
|
-
add_staged_products(config
|
|
73
|
+
add_staged_products(config[:name], config[:desired_version])
|
|
72
74
|
end
|
|
73
75
|
end
|
|
74
76
|
|
|
75
77
|
def deploy
|
|
76
|
-
puts "====> Deploying #{config
|
|
78
|
+
puts "====> Deploying #{config[:name]} version #{config[:desired_version]}...".green
|
|
77
79
|
upload
|
|
78
80
|
add_to_installation
|
|
79
81
|
merge_product_installation_settings
|
|
@@ -85,7 +87,7 @@ class OpsManager
|
|
|
85
87
|
|
|
86
88
|
def merge_product_installation_settings
|
|
87
89
|
get_installation_settings({write_to: '/tmp/is.yml'})
|
|
88
|
-
puts `DEBUG=false spruce merge /tmp/is.yml #{config
|
|
90
|
+
puts `DEBUG=false spruce merge /tmp/is.yml #{config[:installation_settings_file]} > /tmp/new_is.yml`
|
|
89
91
|
upload_installation_settings('/tmp/new_is.yml')
|
|
90
92
|
end
|
|
91
93
|
|
|
@@ -96,7 +98,7 @@ class OpsManager
|
|
|
96
98
|
|
|
97
99
|
private
|
|
98
100
|
def desired_version
|
|
99
|
-
@desired_version ||= OpsManager::Semver.new(config
|
|
101
|
+
@desired_version ||= OpsManager::Semver.new(config[:desired_version])
|
|
100
102
|
end
|
|
101
103
|
|
|
102
104
|
def forced_deployment?
|
|
@@ -108,7 +110,7 @@ class OpsManager
|
|
|
108
110
|
end
|
|
109
111
|
|
|
110
112
|
def config
|
|
111
|
-
OpsManager::
|
|
113
|
+
OpsManager::Config::ProductDeployment.new(::YAML.load_file(@config_file))
|
|
112
114
|
end
|
|
113
115
|
end
|
|
114
116
|
end
|
data/lib/ops_manager/version.rb
CHANGED
data/lib/ops_manager.rb
CHANGED
|
@@ -83,9 +83,10 @@ end
|
|
|
83
83
|
|
|
84
84
|
require "ops_manager/version"
|
|
85
85
|
require "ops_manager/semver"
|
|
86
|
-
require "ops_manager/
|
|
87
|
-
require
|
|
88
|
-
require 'ops_manager/
|
|
86
|
+
require "ops_manager/appliance/vsphere"
|
|
87
|
+
require "ops_manager/appliance/aws"
|
|
88
|
+
require 'ops_manager/config/product_deployment'
|
|
89
|
+
require 'ops_manager/config/opsman_deployment'
|
|
89
90
|
require "ops_manager/cli"
|
|
90
91
|
require "ops_manager/errors"
|
|
91
92
|
require "net/https"
|
data/ops_manager.gemspec
CHANGED
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
spec.add_dependency "rbvmomi"
|
|
27
27
|
spec.add_dependency "multipart-post"
|
|
28
28
|
spec.add_dependency "clamp"
|
|
29
|
+
spec.add_dependency "fog-aws"
|
|
29
30
|
spec.add_dependency "net-ping"
|
|
30
31
|
spec.add_dependency "cf-uaa-lib"
|
|
31
32
|
spec.add_dependency "session_config"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ops_manager_cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- CompoZed
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-
|
|
11
|
+
date: 2017-10-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -136,6 +136,20 @@ dependencies:
|
|
|
136
136
|
- - ">="
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
138
|
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: fog-aws
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :runtime
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
139
153
|
- !ruby/object:Gem::Dependency
|
|
140
154
|
name: net-ping
|
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -218,12 +232,15 @@ files:
|
|
|
218
232
|
- lib/ops_manager/api/base.rb
|
|
219
233
|
- lib/ops_manager/api/opsman.rb
|
|
220
234
|
- lib/ops_manager/api/pivnet.rb
|
|
235
|
+
- lib/ops_manager/appliance/aws.rb
|
|
236
|
+
- lib/ops_manager/appliance/base.rb
|
|
237
|
+
- lib/ops_manager/appliance/vsphere.rb
|
|
221
238
|
- lib/ops_manager/appliance_deployment.rb
|
|
222
239
|
- lib/ops_manager/cli.rb
|
|
240
|
+
- lib/ops_manager/config/base.rb
|
|
241
|
+
- lib/ops_manager/config/opsman_deployment.rb
|
|
242
|
+
- lib/ops_manager/config/product_deployment.rb
|
|
223
243
|
- lib/ops_manager/configs/base.rb
|
|
224
|
-
- lib/ops_manager/configs/opsman_deployment.rb
|
|
225
|
-
- lib/ops_manager/configs/product_deployment.rb
|
|
226
|
-
- lib/ops_manager/deployments/vsphere.rb
|
|
227
244
|
- lib/ops_manager/director_template_generator.rb
|
|
228
245
|
- lib/ops_manager/errors.rb
|
|
229
246
|
- lib/ops_manager/installation.rb
|
|
@@ -1,16 +0,0 @@
|
|
|
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
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require 'rbvmomi'
|
|
2
|
-
require "uri"
|
|
3
|
-
require 'shellwords'
|
|
4
|
-
require "ops_manager/logging"
|
|
5
|
-
|
|
6
|
-
class OpsManager
|
|
7
|
-
module Deployments
|
|
8
|
-
module Vsphere
|
|
9
|
-
include OpsManager::Logging
|
|
10
|
-
|
|
11
|
-
def deploy_vm(name, ip)
|
|
12
|
-
print '====> Deploying ova ...'.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 "Running: #{cmd}"
|
|
16
|
-
logger.info `#{cmd}`
|
|
17
|
-
puts 'done'.green
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def stop_current_vm(name)
|
|
21
|
-
print "====> Stopping vm #{name} ...".green
|
|
22
|
-
dc = vim.serviceInstance.find_datacenter(config.opts['vcenter']['datacenter'])
|
|
23
|
-
logger.info "finding vm: #{name}"
|
|
24
|
-
vm = dc.find_vm(name) or fail "VM not found"
|
|
25
|
-
vm.PowerOffVM_Task.wait_for_completion
|
|
26
|
-
puts 'done'.green
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
def vim
|
|
31
|
-
RbVmomi::VIM.connect host: config.opts['vcenter']['host'], user: URI.unescape(config.opts['vcenter']['username']), password: URI.unescape(config.opts['vcenter']['password']), insecure: true
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def vcenter_username
|
|
35
|
-
Shellwords.escape(URI.encode(config.opts['vcenter']['username']))
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def vcenter_password
|
|
39
|
-
Shellwords.escape(URI.encode(config.opts['vcenter']['password']))
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
|