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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: de760b1ee988f72565a9792c838e90b0ad0c4727
|
4
|
+
data.tar.gz: ed687f1f53abfcd0e81ab380ba319b61b0eb4442
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bd81cf062bed911b6f06f04ee005c328cc90cb535ef987a33d895caea05b3007684cab923fe8907aa32c8ca174cc430991ea8dc3841da869a67673918dbe38c6
|
7
|
+
data.tar.gz: 0ef5e2082449ab75e5c3b12f033948c7782866a37ff5a3e24671b312c0a3d4fb431ec1e62d77a6f0276a8a9c5a52ea9ad55453c050aa7f34ffc98314bba595e9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.3
|
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/CONTRIBUTION.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#Contributing to OpsManagerCLI
|
2
|
+
|
3
|
+
OpsManagerCLI is an open source project and we welcome all contributions!
|
4
|
+
|
5
|
+
We use GitHub to manage reviews of pull requests.
|
6
|
+
|
7
|
+
## Making changes
|
8
|
+
- Fork the OpsManagerCLI repository. For developing new features and bug fixes, the `master` branch should be pulled and built upon.
|
9
|
+
- Create a topic branch where you want to base your work `git checkout -b fix/master/my_contribution master`.
|
10
|
+
- Make commits of logical units in the correct format.
|
11
|
+
- Do **not** make commits through the GitHub web interface due to issues with the automated CLA management.
|
12
|
+
- Check for uncecessary whitespace with `git diff --check` before committing.
|
13
|
+
- Ensure tests have been added for your changes.
|
14
|
+
- Use `git rebase` (not `git merge`) to sync your work with the latest version: `git fetch upstream` `git rebase upstream/master`.
|
15
|
+
- Run **all** the tests to assure nothing else was accidentally broken.
|
16
|
+
- Create a pull request and include the platform team `@compozed/platform` in the description.
|
17
|
+
- Ensure all pull request checks (such as continuous integration) are passing.
|
18
|
+
- [Sign our Contributing License Agreement] (https://compozed-cla.cfapps.io/agreements/compozed/ops_manager_cli "Compozed CLA") if this is your first contribution.
|
19
|
+
|
20
|
+
|
21
|
+
## Adding Features
|
22
|
+
- If you plan to do something more involved, first discuss your ideas using [Waffle](https://waffle.io/compozed/ops_manager_cli). This will avoid unnecessary work and will surely give you and us a good deal of inspiration.
|
data/Dockerfile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
FROM ruby:2.3.0
|
2
|
+
|
3
|
+
ENV GEM_NAME ops_manager_cli
|
4
|
+
ENV GEM_VERSION 0.3.2
|
5
|
+
ENV OVFTOOL_VERSION 4.1.0-2459827
|
6
|
+
ENV OVFTOOL_INSTALLER vmware-ovftool-${OVFTOOL_VERSION}-lin.x86_64.bundle
|
7
|
+
ARG DOWNLOAD_URL=https://storage.googleapis.com/mortarchive/pub/ovftool/${OVFTOOL_INSTALLER}
|
8
|
+
ENV DOWNLOAD_URL ${DOWNLOAD_URL}
|
9
|
+
|
10
|
+
# ================== Installs OVF tools ==============
|
11
|
+
RUN echo $DOWNLOAD_URL
|
12
|
+
RUN wget -q ${DOWNLOAD_URL} \
|
13
|
+
&& wget -q ${DOWNLOAD_URL}.sha256 \
|
14
|
+
&& sha256sum -c ${OVFTOOL_INSTALLER}.sha256 \
|
15
|
+
&& sh ${OVFTOOL_INSTALLER} -p /usr/local --eulas-agreed --required \
|
16
|
+
&& rm -f ${OVFTOOL_INSTALLER}*
|
17
|
+
|
18
|
+
# ================== Installs Spruce ==============
|
19
|
+
RUN wget --no-check-certificate -q https://github.com/geofffranks/spruce/releases/download/v1.0.1/spruce_1.0.1_linux_amd64.tar.gz \
|
20
|
+
&& tar -xvf spruce_1.0.1_linux_amd64.tar.gz \
|
21
|
+
&& chmod +x /spruce_1.0.1_linux_amd64/spruce \
|
22
|
+
&& ln -s /spruce_1.0.1_linux_amd64/spruce /usr/bin/.
|
23
|
+
|
24
|
+
# ================== Installs JQ ==============
|
25
|
+
RUN wget -q -O /usr/local/bin/jq --no-check-certificate https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64
|
26
|
+
RUN chmod +x /usr/local/bin/jq
|
27
|
+
|
28
|
+
# ================== Installs ops_manager_cli gem ==============
|
29
|
+
COPY pkg/${GEM_NAME}-${GEM_VERSION}.gem /tmp/
|
30
|
+
|
31
|
+
RUN gem install /tmp/${GEM_NAME}-${GEM_VERSION}.gem
|
32
|
+
|
33
|
+
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
ARITY OPEN SOURCE PROJECT TERMS OF USE
|
4
|
+
|
5
|
+
Copyright (c) 2016 ARITY INTERNATIONAL LIMITED, AN ALLSTATE COMPANY
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of [this software] and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
8
|
+
|
9
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
10
|
+
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# OpsManagerCli
|
2
|
+
|
3
|
+
Command line tool to interact with Pivotal Operations Manager through its API, because GUIs are evil.
|
4
|
+
|
5
|
+
Questions? Pop in our [slack channel](https://cloudfoundry.slack.com/messages/ops_manager_cli/)!
|
6
|
+
|
7
|
+
*Please note that the APIs of Ops Manager is experimental at this point. Changes to the APIs with new Ops Manager releases may break functionality. The project also does not offer any support for the usage of this in any environments.*
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
### Core features
|
12
|
+
|
13
|
+
- Support for deploying on vSphere infrastructure only
|
14
|
+
- Deploy/Upgrade Ops Manager appliance
|
15
|
+
- Deploy/Upgrade product tiles
|
16
|
+
- Generate config settings templates for product tiles deployments
|
17
|
+
|
18
|
+
### Other features:
|
19
|
+
|
20
|
+
- Show installation settings
|
21
|
+
- Show installation logs
|
22
|
+
- Get UAA token
|
23
|
+
- Uploads stemcell to Ops Manager
|
24
|
+
- Delete unused products
|
25
|
+
|
26
|
+
### Limitations:
|
27
|
+
|
28
|
+
- No support for enabling and running errands (future work)
|
29
|
+
|
30
|
+
### Test with Ops Manager Version
|
31
|
+
|
32
|
+
- up to 1.7.11.0
|
33
|
+
|
34
|
+
## Dependencies
|
35
|
+
|
36
|
+
- [ovftool](https://www.vmware.com/support/developer/ovf/) (version 4.1.0 or higher)
|
37
|
+
- [spruce](https://github.com/geofffranks/spruce#installation)
|
38
|
+
|
39
|
+
All dependencies must be installed and available in user PATH
|
40
|
+
|
41
|
+
## Installing
|
42
|
+
|
43
|
+
gem install ops_manager_cli
|
44
|
+
|
45
|
+
## Usage
|
46
|
+
|
47
|
+
### List available commands
|
48
|
+
|
49
|
+
ops_manager
|
50
|
+
|
51
|
+
### Target
|
52
|
+
|
53
|
+
ops_manager target OPSMAN_URL
|
54
|
+
|
55
|
+
|
56
|
+
### Login
|
57
|
+
|
58
|
+
ops_manager login USERNAME PASSWORD
|
59
|
+
|
60
|
+
|
61
|
+
### Deploy/Upgrade Ops Manager appliance
|
62
|
+
|
63
|
+
**config example:** [ops_manager_deployment.yml](spec/dummy/ops_manager_deployment.yml)
|
64
|
+
|
65
|
+
ops_manager deploy-appliance ops_manager_deployment.yml
|
66
|
+
|
67
|
+
|
68
|
+
### Deploy/Upgrade product tile
|
69
|
+
|
70
|
+
**Before running:** `target` and `login`. You can do this through through config file too.
|
71
|
+
|
72
|
+
**config example:** [product_deployment.yml](spec/dummy/product_deployment.yml)
|
73
|
+
|
74
|
+
./ops_manager deploy-product product_deployment.yml
|
75
|
+
|
76
|
+
## Using with Docker
|
77
|
+
|
78
|
+
The ops_manager_cli tool can be installed in a docker container typically in conjunction with [Concourse CI](http://concourse.ci/). This allows users to build concourse pipelines to deploy and manage their Pivotal Cloud Foundry deployments.
|
79
|
+
|
80
|
+
### Building Docker image
|
81
|
+
|
82
|
+
bundle exec rake build
|
83
|
+
docker build -t compozed/ops_manager_cli # Optional: --build-arg DOWNLOAD_URL=http://your_blobstore.com/ovftool.bundle
|
84
|
+
|
85
|
+
|
86
|
+
### Provisioning docker image to private registry
|
87
|
+
|
88
|
+
docker tag -f compozed/ops_manager_cli PRI_REGISTRY:PORT/compozed/ops_manager_cli
|
89
|
+
docker push PRI_REGISTRY:PORT/compozed/ops_manager_cli
|
90
|
+
|
91
|
+
|
92
|
+
## Contributing
|
93
|
+
|
94
|
+
See our [CONTRUBUTING](CONTRIBUTING.md) section for more information.
|
95
|
+
|
96
|
+
|
97
|
+
## License
|
98
|
+
|
99
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/clean_tapes
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
echo 'Replacing sensitive data in the source file with dummy data'
|
4
|
+
|
5
|
+
USAGE="Usage ./clean_tapes SENSITIVE_INFO DUMMY_INFO"
|
6
|
+
|
7
|
+
if [[ $# -ne 2 ]]; then
|
8
|
+
echo "Illegal number of parameters"
|
9
|
+
echo $USAGE
|
10
|
+
exit
|
11
|
+
fi
|
12
|
+
|
13
|
+
pattern=$1
|
14
|
+
replacement=$2
|
15
|
+
|
16
|
+
pushd spec/fixtures/vcr_cassettes/
|
17
|
+
ack -l $pattern | xargs perl -pi -E "s/$pattern/$replacement/g"
|
18
|
+
popd
|
19
|
+
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "ops_manager"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/exe/ops_manager
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
class OpsManager
|
2
|
+
module Api
|
3
|
+
class Base
|
4
|
+
include OpsManager::Logging
|
5
|
+
|
6
|
+
def get(endpoint, opts = {})
|
7
|
+
uri = uri_for(endpoint)
|
8
|
+
http = http_for(uri)
|
9
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
10
|
+
|
11
|
+
if opts.has_key?(:basic_auth)
|
12
|
+
request.basic_auth( opts[:basic_auth][:username], opts[:basic_auth][:password])
|
13
|
+
end
|
14
|
+
|
15
|
+
if opts.has_key?(:headers)
|
16
|
+
opts.delete(:headers).each_pair do |k,v|
|
17
|
+
request[k] = v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if opts[:write_to]
|
22
|
+
begin
|
23
|
+
f = open(opts.fetch(:write_to), "wb")
|
24
|
+
http.request(request) do |res|
|
25
|
+
res.read_body do |segment|
|
26
|
+
f.write(segment)
|
27
|
+
end
|
28
|
+
logger.info("performing get to #{uri} with opts: #{opts.inspect} res.code: #{res.code}")
|
29
|
+
logger.info("get response body #{res.body}")
|
30
|
+
end
|
31
|
+
ensure
|
32
|
+
f.close
|
33
|
+
end
|
34
|
+
else
|
35
|
+
http.request(request).tap do |res|
|
36
|
+
logger.info("performing get to #{uri} with opts: #{opts.inspect} res.code: #{res.code}")
|
37
|
+
logger.info("get response body #{res.body}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def post(endpoint, opts= {})
|
43
|
+
uri = uri_for(endpoint)
|
44
|
+
http = http_for(uri)
|
45
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
46
|
+
|
47
|
+
if opts.has_key?(:headers)
|
48
|
+
opts.delete(:headers).each_pair do |k,v|
|
49
|
+
request[k] = v
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
body = opts[:body] || ''
|
55
|
+
request.body= body
|
56
|
+
|
57
|
+
res = http.request(request).tap do |res|
|
58
|
+
logger.info("performing post to #{uri} with opts: #{opts.inspect} res.code: #{res.code}")
|
59
|
+
logger.info("post response body #{res.body}")
|
60
|
+
end
|
61
|
+
|
62
|
+
if res.code == '302'
|
63
|
+
get(res[ 'Location' ], opts)
|
64
|
+
else
|
65
|
+
res
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def put(endpoint, opts ={})
|
70
|
+
uri = uri_for(endpoint)
|
71
|
+
http = http_for(uri)
|
72
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
73
|
+
request.set_form_data(opts)
|
74
|
+
|
75
|
+
request.basic_auth(username, password) if self.respond_to?(:username)
|
76
|
+
|
77
|
+
if opts.has_key?(:headers)
|
78
|
+
opts.delete(:headers).each_pair do |k,v|
|
79
|
+
request[k] = v
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# body = opts.fetch( :body )
|
83
|
+
http.request(request).tap do |res|
|
84
|
+
logger.info("performing put to #{uri} with opts: #{opts.inspect} res.code: #{res.code}")
|
85
|
+
logger.info("put response body #{res.body}")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def multipart_post(endpoint, opts = {})
|
90
|
+
uri = uri_for(endpoint)
|
91
|
+
http = http_for(uri)
|
92
|
+
|
93
|
+
request = Net::HTTP::Post::Multipart.new(uri.request_uri, opts)
|
94
|
+
|
95
|
+
request.basic_auth(username, password) if self.respond_to?(:username)
|
96
|
+
|
97
|
+
if opts.has_key?(:headers)
|
98
|
+
opts.delete(:headers).each_pair do |k,v|
|
99
|
+
request[k] = v
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
http.request(request).tap do |res|
|
104
|
+
logger.info("performing multipart_post to #{uri} with opts: #{opts.inspect} res.code: #{res.code}")
|
105
|
+
logger.info("post response body #{res.body}")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def delete(endpoint, opts = {})
|
110
|
+
uri = uri_for(endpoint)
|
111
|
+
http = http_for(uri)
|
112
|
+
request = Net::HTTP::Delete.new(uri.request_uri)
|
113
|
+
|
114
|
+
request.basic_auth(username, password) if self.respond_to?(:username)
|
115
|
+
|
116
|
+
if opts.has_key?(:headers)
|
117
|
+
opts.delete(:headers).each_pair do |k,v|
|
118
|
+
request[k] = v
|
119
|
+
end
|
120
|
+
end
|
121
|
+
http.request(request)
|
122
|
+
end
|
123
|
+
|
124
|
+
def uri_for(endpoint)
|
125
|
+
if endpoint =~/^http/
|
126
|
+
URI.parse(endpoint)
|
127
|
+
else
|
128
|
+
URI.parse("https://#{target}#{endpoint}")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def http_for(uri)
|
133
|
+
Net::HTTP.new(uri.host, uri.port).tap do |http|
|
134
|
+
http.use_ssl = true
|
135
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
136
|
+
http.read_timeout = 1200
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require "ops_manager/logging"
|
2
|
+
require "ops_manager/api/base"
|
3
|
+
require "net/http/post/multipart"
|
4
|
+
require "uaa"
|
5
|
+
|
6
|
+
class OpsManager
|
7
|
+
module Api
|
8
|
+
class Opsman < OpsManager::Api::Base
|
9
|
+
attr_reader :silent
|
10
|
+
|
11
|
+
def initialize(opts = {})
|
12
|
+
@silent = opts[:silent]
|
13
|
+
end
|
14
|
+
|
15
|
+
def say_green(str)
|
16
|
+
puts str.green unless silent
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_green(str)
|
20
|
+
print str.green unless silent
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_user
|
24
|
+
body= "setup[decryption_passphrase]=#{password}&setup[decryption_passphrase_confirmation]=#{password}&setup[eula_accepted]=true&setup[identity_provider]=internal&setup[admin_user_name]=#{username}&setup[admin_password]=#{password}&setup[admin_password_confirmation]=#{password}"
|
25
|
+
post("/api/v0/setup" , body: body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def upload_installation_settings(filepath = 'installation_settings.json')
|
29
|
+
say_green( '====> Uploading installation settings...')
|
30
|
+
yaml = UploadIO.new(filepath, 'text/yaml')
|
31
|
+
opts = { "installation[file]" => yaml}
|
32
|
+
res = authenticated_multipart_post("/api/installation_settings", opts)
|
33
|
+
raise OpsManager::InstallationSettingsError.new(res.body) unless res.code == '200'
|
34
|
+
res
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_staged_products(opts = {})
|
38
|
+
authenticated_get("/api/v0/staged/products", opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_installation_settings(opts = {})
|
42
|
+
say_green( '====> Downloading installation settings...')
|
43
|
+
authenticated_get("/api/installation_settings", opts)
|
44
|
+
end
|
45
|
+
|
46
|
+
def upload_installation_assets
|
47
|
+
say_green( '====> Uploading installation assets...')
|
48
|
+
zip = UploadIO.new("#{Dir.pwd}/installation_assets.zip", 'application/x-zip-compressed')
|
49
|
+
opts = {:passphrase => @password, "installation[file]" => zip }
|
50
|
+
multipart_post( "/api/v0/installation_asset_collection", opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_installation_assets
|
54
|
+
opts = { write_to: "installation_assets.zip" }
|
55
|
+
say_green( '====> Download installation assets...')
|
56
|
+
authenticated_get("/api/v0/installation_asset_collection", opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete_products(opts = {})
|
60
|
+
say_green( '====> Deleating unused products...')
|
61
|
+
opts = add_authentication(opts)
|
62
|
+
delete('/api/v0/products', opts)
|
63
|
+
end
|
64
|
+
|
65
|
+
def trigger_installation(opts = {})
|
66
|
+
print_green('====> Applying changes...')
|
67
|
+
authenticated_post('/api/v0/installations', opts)
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_staged_products(name, version)
|
71
|
+
print_green( "====> Adding available product to the installation...")
|
72
|
+
body = "name=#{name}&product_version=#{version}"
|
73
|
+
res = authenticated_post('/api/v0/staged/products', body: body)
|
74
|
+
raise OpsManager::ProductDeploymentError.new(res.body) if res.code == '404'
|
75
|
+
say_green('done')
|
76
|
+
res
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_installation(id)
|
80
|
+
res = authenticated_get("/api/v0/installations/#{id}")
|
81
|
+
raise OpsManager::InstallationError.new(res.body) if res.body =~ /failed/
|
82
|
+
res
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_installation_logs(id)
|
86
|
+
authenticated_get("/api/v0/installations/#{id}/logs")
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_staged_products_errands(product_guid)
|
90
|
+
authenticated_get("/api/v0/staged/products/#{product_guid}/errands" )
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_installations(opts = {})
|
94
|
+
authenticated_get('/api/v0/installations')
|
95
|
+
end
|
96
|
+
|
97
|
+
def upgrade_product_installation(guid, product_version)
|
98
|
+
say_green( "====> Bumping product installation #{guid} product_version to #{product_version}...")
|
99
|
+
opts = { to_version: product_version }
|
100
|
+
opts = add_authentication(opts)
|
101
|
+
res = put("/api/v0/staged/products/#{guid}", opts)
|
102
|
+
raise OpsManager::UpgradeError.new(res.body) unless res.code == '200'
|
103
|
+
res
|
104
|
+
end
|
105
|
+
|
106
|
+
def upload_product(filepath)
|
107
|
+
file = "#{filepath}"
|
108
|
+
cmd = "curl -k \"https://#{target}/api/v0/available_products\" -F 'product[file]=@#{file}' -X POST -H 'Authorization: Bearer #{access_token}'"
|
109
|
+
logger.info "running cmd: #{cmd}"
|
110
|
+
body = `#{cmd}`
|
111
|
+
logger.info "Upload product response: #{body}"
|
112
|
+
raise OpsManager::ProductUploadError if body.include? "error"
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_available_products
|
116
|
+
authenticated_get("/api/v0/available_products")
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_current_version
|
120
|
+
products = JSON.parse(get_available_products.body)
|
121
|
+
directors = products.select{ |i| i.fetch('name') =~/p-bosh|microbosh/ }
|
122
|
+
versions = directors.inject([]){ |r, i| r << OpsManager::Semver.new(i.fetch('product_version')) }
|
123
|
+
versions.sort.last.to_s.gsub(/.0$/,'')
|
124
|
+
|
125
|
+
rescue Errno::ETIMEDOUT , Errno::EHOSTUNREACH, Net::HTTPFatalError, Net::OpenTimeout
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def import_stemcell(filepath)
|
131
|
+
return unless filepath
|
132
|
+
say_green('====> Uploading stemcell...')
|
133
|
+
tar = UploadIO.new(filepath, 'multipart/form-data')
|
134
|
+
opts = { "stemcell[file]" => tar }
|
135
|
+
res = authenticated_multipart_post("/api/v0/stemcells", opts)
|
136
|
+
raise OpsManager::StemcellUploadError.new(res.body) unless res.code == '200'
|
137
|
+
res
|
138
|
+
end
|
139
|
+
|
140
|
+
def username
|
141
|
+
@username ||= OpsManager.get_conf(:username)
|
142
|
+
end
|
143
|
+
|
144
|
+
def password
|
145
|
+
@password ||= OpsManager.get_conf(:password)
|
146
|
+
end
|
147
|
+
|
148
|
+
def target
|
149
|
+
@target ||= OpsManager.get_conf(:target)
|
150
|
+
end
|
151
|
+
|
152
|
+
def get_token
|
153
|
+
token_issuer.owner_password_grant('admin', password, 'opsman.admin').tap do |token|
|
154
|
+
logger.info "UAA Token: #{token.inspect}"
|
155
|
+
end
|
156
|
+
rescue CF::UAA::TargetError
|
157
|
+
nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def authenticated_get(endpoint, opts = {})
|
161
|
+
get(endpoint, add_authentication(opts))
|
162
|
+
end
|
163
|
+
|
164
|
+
def authenticated_post(endpoint, opts = {})
|
165
|
+
post(endpoint, add_authentication(opts))
|
166
|
+
end
|
167
|
+
|
168
|
+
def authenticated_multipart_post(endpoint, opts = {})
|
169
|
+
multipart_post(endpoint, add_authentication(opts))
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
def token_issuer
|
174
|
+
@token_issuer ||= CF::UAA::TokenIssuer.new(
|
175
|
+
"https://#{target}/uaa", 'opsman', nil, skip_ssl_validation: true )
|
176
|
+
end
|
177
|
+
|
178
|
+
def access_token
|
179
|
+
@access_token ||= get_token.info['access_token']
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
def add_authentication(opts={})
|
184
|
+
opts[:headers] ||= {}
|
185
|
+
opts[:headers]['Authorization'] ||= "Bearer #{access_token}"
|
186
|
+
opts
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|