knife-vrealize 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +62 -19
- data/knife-vrealize.gemspec +2 -1
- data/lib/chef/knife/cloud/vra_service_helpers.rb +1 -1
- data/lib/chef/knife/vra_server_create.rb +2 -2
- data/lib/chef/knife/vro_workflow_execute.rb +185 -0
- data/lib/knife-vrealize/version.rb +1 -1
- data/spec/unit/vro_workflow_execute_spec.rb +365 -0
- metadata +22 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18b5c642ccb473d7df715d34eee5b7c3c3790533
|
4
|
+
data.tar.gz: 175681a883e7c62be2153dd76340620046ac69ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd6bd2398f4839db9f58f176649eaa440a7fec2839c710ff211d20816b6a82661c787a0b5c9157cb4257ea354f80dcab91ace31260f517fc96087b26889bd2e4
|
7
|
+
data.tar.gz: 8214624f133a68cc1e44f25eeb7d1c01b307d1c58d058d9ec315d2d790afdbd41015af3c770ede4361b950d1ce1b582da1468ad2666288323d4b13a3f645c1f5
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# knife-vrealize Change Log
|
2
|
+
|
3
|
+
## Release: v1.1.0
|
4
|
+
* new "vro workflow execute" command to allow arbitrary workflow executions via knife
|
5
|
+
|
6
|
+
## Release: v1.0.1
|
7
|
+
* remove release-candidate restriction from the version pin for the vmware-vra gem
|
8
|
+
|
9
|
+
## Release: v1.0.0
|
10
|
+
* Initial release with support for vRA
|
data/README.md
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# knife-vrealize
|
2
2
|
|
3
|
-
This is a Knife plugin that will allow you to interact with
|
3
|
+
This is a Knife plugin that will allow you to interact with
|
4
4
|
VMware vRealize products, such as vRA and vRO, from Chef's Knife command.
|
5
5
|
|
6
|
-
The initial release of this plugin supports vRA.
|
7
|
-
|
8
6
|
## Installation
|
9
7
|
|
10
8
|
Add this line to your application's Gemfile:
|
@@ -25,7 +23,9 @@ Or install it yourself as:
|
|
25
23
|
|
26
24
|
$ chef gem install knife-vrealize
|
27
25
|
|
28
|
-
##
|
26
|
+
## vRealize Automation (vRA)
|
27
|
+
|
28
|
+
### Configuration
|
29
29
|
|
30
30
|
In order to communicate with vRA, you must specify your user credentials. You can specify them in your knife.rb:
|
31
31
|
|
@@ -34,7 +34,7 @@ knife[:vra_username] = 'myuser'
|
|
34
34
|
knife[:vra_password] = 'mypassword'
|
35
35
|
knife[:vra_base_url] = 'https://vra.corp.local'
|
36
36
|
knife[:vra_tenant] = 'mytenant'
|
37
|
-
```
|
37
|
+
```
|
38
38
|
|
39
39
|
... or you can supply them on the command-line:
|
40
40
|
|
@@ -42,11 +42,11 @@ knife[:vra_tenant] = 'mytenant'
|
|
42
42
|
knife vra command --vra-username myuser --vra-tenant mytenant ...
|
43
43
|
```
|
44
44
|
|
45
|
-
|
45
|
+
### Usage
|
46
46
|
|
47
|
-
|
47
|
+
#### knife vra catalog list
|
48
48
|
|
49
|
-
Lists catalog items that can be used to submit machine requests.
|
49
|
+
Lists catalog items that can be used to submit machine requests. By default, it will list all catalog items that your user has permission to see. To limit it to only items to which you are entitled, supply the `--entitled` flag.
|
50
50
|
|
51
51
|
```
|
52
52
|
$ knife vra catalog list
|
@@ -56,9 +56,9 @@ a9cd6148-6e0b-4a80-ac47-f5255c52b43d CentOS 6.6 Blueprint for
|
|
56
56
|
d29efd6b-3cd6-4f8d-b1d8-da4ddd4e52b1 WindowsServer2012 Windows Server 2012 with the latest updates and patches. published
|
57
57
|
```
|
58
58
|
|
59
|
-
|
59
|
+
#### knife vra server list
|
60
60
|
|
61
|
-
Lists all machine resources that your user has permission to see.
|
61
|
+
Lists all machine resources that your user has permission to see. The "resource ID" is needed for other commands, such as `knife vra server show` and `knife vra server destroy`
|
62
62
|
|
63
63
|
```
|
64
64
|
$ knife vra server list
|
@@ -68,7 +68,7 @@ Resource ID Name Status Catalog Name
|
|
68
68
|
0977f98b-d927-4e71-8b5b-b27c7deda097 hol-dev-45 active CentOS 6.6
|
69
69
|
```
|
70
70
|
|
71
|
-
|
71
|
+
#### knife vra server show RESOURCE_ID
|
72
72
|
|
73
73
|
Displays additional information about an individual server, such as its IP addresses.
|
74
74
|
|
@@ -81,11 +81,11 @@ Status: ACTIVE
|
|
81
81
|
Catalog Name: CentOS 6.6
|
82
82
|
```
|
83
83
|
|
84
|
-
|
84
|
+
#### knife vra server create CATALOG_ID (options)
|
85
85
|
|
86
|
-
Creates a server from a catalog blueprint.
|
86
|
+
Creates a server from a catalog blueprint. Find the catalog ID with the `knife vra catalog list` command. After the resource is created, knife will attempt to bootstrap it (install chef, run chef-client for the first time, etc.).
|
87
87
|
|
88
|
-
Each blueprint may require different parameters to successfully complete provisioning.
|
88
|
+
Each blueprint may require different parameters to successfully complete provisioning. See your vRA administrator with questions. We'll do our best to give you any helpful error messages from vRA if they're available to us.
|
89
89
|
|
90
90
|
Common parameters to specify are:
|
91
91
|
|
@@ -94,7 +94,7 @@ Common parameters to specify are:
|
|
94
94
|
* `--requested-for`: vRA login that should be listed as the owner
|
95
95
|
* `--lease-days`: number of days for the resource lease
|
96
96
|
* `--notes`: any optional notes you'd like to be logged with your request
|
97
|
-
* `--subtenant-id`: all resources must be tied back to a Business Group, or "subtenant." If your catalog item is tied to a specific Business Group, you do not need to specify this.
|
97
|
+
* `--subtenant-id`: all resources must be tied back to a Business Group, or "subtenant." If your catalog item is tied to a specific Business Group, you do not need to specify this. However, if your catalog item is a global catalog item, then the subtenant ID is not available to us; you will need to provide it. It usually looks like a UUID. See your vRA administrator for assistance in determining your subtenant ID.
|
98
98
|
* `--ssh-password`: if a linux host, the password to use during bootstrap
|
99
99
|
* `--winrm-password`: if a windows host, the password to use during bootstrap
|
100
100
|
|
@@ -107,12 +107,12 @@ Current request status: IN_PROGRESS..
|
|
107
107
|
...
|
108
108
|
```
|
109
109
|
|
110
|
-
|
110
|
+
#### knife vra server delete RESOURCE_ID
|
111
111
|
|
112
|
-
Deletes a server from vRA.
|
112
|
+
Deletes a server from vRA. If you supply `--purge`, the server will also be removed from the Chef Server.
|
113
113
|
|
114
114
|
```
|
115
|
-
$
|
115
|
+
$ knife vra server delete 2e1f6632-1613-41d1-a07c-6137c9639609 --purge
|
116
116
|
Server ID: 2e1f6632-1613-41d1-a07c-6137c9639609
|
117
117
|
Server Name: hol-dev-43
|
118
118
|
IP Addresses: 192.168.110.203
|
@@ -127,9 +127,52 @@ Current request status: IN_PROGRESS...
|
|
127
127
|
...
|
128
128
|
```
|
129
129
|
|
130
|
+
## vRealize Orchestrator (vRO)
|
131
|
+
|
132
|
+
### Configuration
|
133
|
+
|
134
|
+
In order to communicate with vRA, you must specify your user credentials. You can specify them in your knife.rb:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
knife[:vro_username] = 'myuser'
|
138
|
+
knife[:vro_password] = 'mypassword'
|
139
|
+
knife[:vro_base_url] = 'https://vra.corp.local:8281'
|
140
|
+
```
|
141
|
+
|
142
|
+
... or you can supply them on the command-line:
|
143
|
+
|
144
|
+
```
|
145
|
+
knife vro command --vro-username myuser ...
|
146
|
+
```
|
147
|
+
|
148
|
+
### Usage
|
149
|
+
|
150
|
+
### knife vro workflow execute
|
151
|
+
|
152
|
+
Executes a vRO workflow. Requires the workflow name. You may supply any input parameters, as well.
|
153
|
+
|
154
|
+
```
|
155
|
+
$ knife vro workflow execute "knife testing" key1=value1
|
156
|
+
Starting workflow execution...
|
157
|
+
Workflow execution 4028eece4effc046014f27da864d0187 started. Waiting for it to complete...
|
158
|
+
Workflow execution complete.
|
159
|
+
|
160
|
+
Output Parameters:
|
161
|
+
outkey1: some value (string)
|
162
|
+
|
163
|
+
Workflow Execution Log:
|
164
|
+
2015-08-13 09:17:57 -0700 info: cloudadmin: Workflow 'Knife Testing' has started
|
165
|
+
2015-08-13 09:17:58 -0700 info: cloudadmin: Workflow 'Knife Testing' has completed
|
166
|
+
```
|
167
|
+
|
168
|
+
If your workflow name is not unique in your vRO workflow list, you can specify
|
169
|
+
a specific workflow to use with `--vro-workflow-id ID`. You can find the
|
170
|
+
workflow ID from within the vRO UI. However, a workflow name is still required
|
171
|
+
by the API.
|
172
|
+
|
130
173
|
## Contributing
|
131
174
|
|
132
|
-
We'd love to hear from you if you find this isn't working in your VMware vRA environment.
|
175
|
+
We'd love to hear from you if you find this isn't working in your VMware vRA/vRO environment. Please submit a GitHub issue with any problems you encounter.
|
133
176
|
|
134
177
|
Additionally, contributions are welcome! If you'd like to send up any fixes or changes:
|
135
178
|
|
data/knife-vrealize.gemspec
CHANGED
@@ -21,7 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_dependency 'chef', '~> 12.0'
|
23
23
|
spec.add_dependency 'knife-cloud', '~> 1.2.0'
|
24
|
-
spec.add_dependency 'vmware-vra', '~> 1.0
|
24
|
+
spec.add_dependency 'vmware-vra', '~> 1.0'
|
25
|
+
spec.add_dependency 'vcoworkflows', '~> 0.2'
|
25
26
|
|
26
27
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
27
28
|
spec.add_development_dependency 'rake', '~> 10.0'
|
@@ -44,7 +44,7 @@ class Chef
|
|
44
44
|
|
45
45
|
option :requested_for,
|
46
46
|
long: '--requested-for LOGIN',
|
47
|
-
description: 'The login to list as the owner of this resource.
|
47
|
+
description: 'The login to list as the owner of this resource. Will default to the vra_username parameter'
|
48
48
|
|
49
49
|
option :subtenant_id,
|
50
50
|
long: '--subtenant-id ID',
|
@@ -61,7 +61,7 @@ class Chef
|
|
61
61
|
|
62
62
|
option :extra_params,
|
63
63
|
long: '--extra-param KEY=TYPE:VALUE',
|
64
|
-
description: 'Additional parameters to pass to vRA for this catalog request.
|
64
|
+
description: 'Additional parameters to pass to vRA for this catalog request. TYPE must be "string" or "integer". ' \
|
65
65
|
'Can be used multiple times.',
|
66
66
|
default: {},
|
67
67
|
proc: proc { |param|
|
@@ -0,0 +1,185 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2015 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/knife'
|
20
|
+
require 'vcoworkflows'
|
21
|
+
|
22
|
+
class Chef
|
23
|
+
class Knife
|
24
|
+
# rubocop:disable Metrics/ClassLength
|
25
|
+
# rubocop:disable Style/AlignParameters
|
26
|
+
class VroWorkflowExecute < Chef::Knife
|
27
|
+
attr_accessor :workflow_id, :workflow_name, :parameters
|
28
|
+
|
29
|
+
include Chef::Knife::Cloud::Helpers
|
30
|
+
|
31
|
+
banner 'knife vro workflow execute WORKFLOW_NAME [KEY=VALUE] [KEY=VALUE] (options)'
|
32
|
+
|
33
|
+
option :vro_base_url,
|
34
|
+
long: '--vro-base-url API_URL',
|
35
|
+
description: 'URL for the vro server'
|
36
|
+
|
37
|
+
option :vro_username,
|
38
|
+
long: '--vro-username USERNAME',
|
39
|
+
description: 'Username to use with the vro API'
|
40
|
+
|
41
|
+
option :vro_password,
|
42
|
+
long: '--vro-password PASSWORD',
|
43
|
+
description: 'Password to use with the vro API'
|
44
|
+
|
45
|
+
option :vro_disable_ssl_verify,
|
46
|
+
long: '--vro-disable-ssl-verify',
|
47
|
+
description: 'Skip any SSL verification for the vro API',
|
48
|
+
boolean: true,
|
49
|
+
default: false
|
50
|
+
|
51
|
+
option :vro_workflow_id,
|
52
|
+
long: '--vro-workflow-id WORKFLOW_ID',
|
53
|
+
description: 'ID of the workflow to execute'
|
54
|
+
|
55
|
+
option :request_timeout,
|
56
|
+
long: '--request-timeout SECONDS',
|
57
|
+
description: 'number of seconds to wait for the workflow to complete',
|
58
|
+
default: 300
|
59
|
+
|
60
|
+
def verify_ssl?
|
61
|
+
!locate_config_value(:vro_disable_ssl_verify)
|
62
|
+
end
|
63
|
+
|
64
|
+
def vro_config
|
65
|
+
@vro_config ||= VcoWorkflows::Config.new(
|
66
|
+
url: locate_config_value(:vro_base_url),
|
67
|
+
username: locate_config_value(:vro_username),
|
68
|
+
password: locate_config_value(:vro_password),
|
69
|
+
verify_ssl: verify_ssl?
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def vro_client
|
74
|
+
@client ||= VcoWorkflows::Workflow.new(
|
75
|
+
workflow_name,
|
76
|
+
id: workflow_id,
|
77
|
+
config: vro_config
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse_and_validate_params!(args)
|
82
|
+
args.each_with_object({}) do |arg, memo|
|
83
|
+
key, value = arg.split('=')
|
84
|
+
raise "Invalid parameter, must be in KEY=VALUE format: #{arg}" if key.nil? || value.nil?
|
85
|
+
|
86
|
+
memo[key] = value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def execute_workflow
|
91
|
+
parameters.each do |key, value|
|
92
|
+
vro_client.parameter(key, value)
|
93
|
+
end
|
94
|
+
begin
|
95
|
+
vro_client.execute
|
96
|
+
rescue RestClient::BadRequest => e
|
97
|
+
ui.error("The workflow execution request failed: #{e.response}")
|
98
|
+
raise
|
99
|
+
rescue => e
|
100
|
+
ui.error("The workflow execution request failed: #{e.message}")
|
101
|
+
raise
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def wait_for_workflow
|
106
|
+
wait_time = locate_config_value(:request_timeout)
|
107
|
+
Timeout.timeout(wait_time) do
|
108
|
+
loop do
|
109
|
+
token = vro_client.token
|
110
|
+
break unless token.alive?
|
111
|
+
|
112
|
+
sleep 2
|
113
|
+
end
|
114
|
+
end
|
115
|
+
rescue Timeout::Error
|
116
|
+
raise Timeout::Error, "Workflow did not complete in #{wait_time} seconds. Please check the vRO UI for more information."
|
117
|
+
end
|
118
|
+
|
119
|
+
def missing_config_parameters
|
120
|
+
[:vro_username, :vro_password, :vro_base_url].each_with_object([]) do |param, memo|
|
121
|
+
memo << param if locate_config_value(param).nil?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate!
|
126
|
+
print_error_and_exit('The following parameters are missing but required:' \
|
127
|
+
"#{missing_config_parameters.join(', ')}") unless missing_config_parameters.empty?
|
128
|
+
|
129
|
+
print_error_and_exit('You must supply a workflow name.') if @name_args.empty?
|
130
|
+
end
|
131
|
+
|
132
|
+
def print_error_and_exit(msg)
|
133
|
+
ui.error(msg)
|
134
|
+
exit(1)
|
135
|
+
end
|
136
|
+
|
137
|
+
def print_results
|
138
|
+
ui.msg('')
|
139
|
+
print_output_parameters
|
140
|
+
print_execution_log
|
141
|
+
end
|
142
|
+
|
143
|
+
def print_output_parameters
|
144
|
+
token = vro_client.token
|
145
|
+
return if token.output_parameters.empty?
|
146
|
+
|
147
|
+
ui.msg(ui.color('Output Parameters:', :bold))
|
148
|
+
token.output_parameters.each do |k, v|
|
149
|
+
msg_pair(k, "#{v.value} (#{v.type})") unless v.value.nil? || (v.value.respond_to?(:empty?) && v.value.empty?)
|
150
|
+
end
|
151
|
+
ui.msg('')
|
152
|
+
end
|
153
|
+
|
154
|
+
def print_execution_log
|
155
|
+
log = vro_client.log.to_s
|
156
|
+
return if log.nil? || log.empty?
|
157
|
+
|
158
|
+
ui.msg(ui.color('Workflow Execution Log:', :bold))
|
159
|
+
ui.msg(log)
|
160
|
+
end
|
161
|
+
|
162
|
+
def set_parameters
|
163
|
+
self.workflow_name = @name_args.shift
|
164
|
+
self.workflow_id = locate_config_value(:vro_workflow_id)
|
165
|
+
self.parameters = parse_and_validate_params!(@name_args)
|
166
|
+
end
|
167
|
+
|
168
|
+
def run
|
169
|
+
validate!
|
170
|
+
|
171
|
+
set_parameters
|
172
|
+
|
173
|
+
ui.msg('Starting workflow execution...')
|
174
|
+
execution_id = execute_workflow
|
175
|
+
|
176
|
+
ui.msg("Workflow execution #{execution_id} started. Waiting for it to complete...")
|
177
|
+
wait_for_workflow
|
178
|
+
|
179
|
+
ui.msg('Workflow execution complete.')
|
180
|
+
|
181
|
+
print_results
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -0,0 +1,365 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2015 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'spec_helper'
|
20
|
+
require 'chef/knife/vro_workflow_execute'
|
21
|
+
|
22
|
+
describe Chef::Knife::VroWorkflowExecute do
|
23
|
+
let(:workflow_name) { 'test workflow' }
|
24
|
+
let(:workflow_id) { '1d335f85-5328-42fc-a842-a956d1ccdf08' }
|
25
|
+
let(:vro_username) { 'myuser' }
|
26
|
+
let(:vro_password) { 'mypassword' }
|
27
|
+
let(:vro_base_url) { 'https://vro.corp.local' }
|
28
|
+
let(:vro_disable_ssl_verify) { true }
|
29
|
+
let(:key1) { 'value1' }
|
30
|
+
let(:key2) { '2' }
|
31
|
+
|
32
|
+
let(:argv) do
|
33
|
+
[ workflow_name,
|
34
|
+
"key1=#{key1}",
|
35
|
+
"key2=#{key2}",
|
36
|
+
'--vro-workflow-id', workflow_id
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
subject { described_class.new(argv) }
|
41
|
+
|
42
|
+
before(:each) do
|
43
|
+
Chef::Config[:knife][:vro_username] = vro_username
|
44
|
+
Chef::Config[:knife][:vro_password] = vro_password
|
45
|
+
Chef::Config[:knife][:vro_base_url] = vro_base_url
|
46
|
+
Chef::Config[:knife][:vro_disable_ssl_verify] = vro_disable_ssl_verify
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#verify_ssl?' do
|
50
|
+
context 'when vro_disable_ssl_verify is set to true' do
|
51
|
+
let(:vro_disable_ssl_verify) { true }
|
52
|
+
it 'returns false' do
|
53
|
+
expect(subject.verify_ssl?).to eq(false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when vro_disable_ssl_verify is set to false' do
|
58
|
+
let(:vro_disable_ssl_verify) { false }
|
59
|
+
it 'returns true' do
|
60
|
+
expect(subject.verify_ssl?).to eq(true)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#vro_config' do
|
66
|
+
it 'creates a config object' do
|
67
|
+
expect(VcoWorkflows::Config).to receive(:new).with(url: vro_base_url,
|
68
|
+
username: vro_username,
|
69
|
+
password: vro_password,
|
70
|
+
verify_ssl: false)
|
71
|
+
subject.vro_config
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#vro_client' do
|
76
|
+
it 'creates a client object' do
|
77
|
+
config = double('config')
|
78
|
+
allow(subject).to receive(:vro_config).and_return(config)
|
79
|
+
expect(VcoWorkflows::Workflow).to receive(:new).with(workflow_name,
|
80
|
+
id: workflow_id,
|
81
|
+
config: config)
|
82
|
+
|
83
|
+
subject.set_parameters
|
84
|
+
subject.vro_client
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#parse_and_validate_params' do
|
89
|
+
context 'when proper parameters are supplied' do
|
90
|
+
let(:args) { %w(key1=value1 key2=value2) }
|
91
|
+
it 'returns a hash of parameters' do
|
92
|
+
expect(subject.parse_and_validate_params!(args)).to eq('key1' => 'value1',
|
93
|
+
'key2' => 'value2')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when a parameter is malformed' do
|
98
|
+
let(:args) { %w(key1=value1 key2) }
|
99
|
+
it 'raises an exception' do
|
100
|
+
expect { subject.parse_and_validate_params!(args) }.to raise_error(RuntimeError)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'execute_workflow' do
|
106
|
+
before do
|
107
|
+
config = double('config')
|
108
|
+
client = double('client')
|
109
|
+
allow(subject).to receive(:vro_config).and_return(config)
|
110
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
111
|
+
allow(client).to receive(:parameter)
|
112
|
+
allow(client).to receive(:execute)
|
113
|
+
subject.set_parameters
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'sets the workflow parameters' do
|
117
|
+
expect(subject.vro_client).to receive(:parameter).with('key1', key1)
|
118
|
+
expect(subject.vro_client).to receive(:parameter).with('key2', key2)
|
119
|
+
|
120
|
+
subject.execute_workflow
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'executes the workflow' do
|
124
|
+
expect(subject.vro_client).to receive(:execute)
|
125
|
+
subject.execute_workflow
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when execute fails with a RestClient::BadRequest' do
|
129
|
+
it 'prints an error with the HTTP response' do
|
130
|
+
HTTPResponse = Struct.new(:code, :to_s)
|
131
|
+
response = HTTPResponse.new(400, 'an HTTP error occurred')
|
132
|
+
exception = RestClient::BadRequest.new
|
133
|
+
exception.response = response
|
134
|
+
allow(subject.vro_client).to receive(:execute).and_raise(exception)
|
135
|
+
expect(subject.ui).to receive(:error).with('The workflow execution request failed: an HTTP error occurred')
|
136
|
+
expect { subject.execute_workflow }.to raise_error(RestClient::BadRequest)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when execute fails with any other exception' do
|
141
|
+
it 'prints an error with the exception message' do
|
142
|
+
allow(subject.vro_client).to receive(:execute).and_raise(RuntimeError, 'a non-HTTP error occurred')
|
143
|
+
expect(subject.ui).to receive(:error).with('The workflow execution request failed: a non-HTTP error occurred')
|
144
|
+
expect { subject.execute_workflow }.to raise_error(RuntimeError)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe '#wait_for_workflow' do
|
150
|
+
before(:each) do
|
151
|
+
# don't actually sleep
|
152
|
+
allow(subject).to receive(:sleep)
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when the requests completes normally, 3 loops' do
|
156
|
+
it 'only fetches the token 3 times' do
|
157
|
+
client = double('client')
|
158
|
+
token = double('token')
|
159
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
160
|
+
allow(client).to receive(:token).and_return(token)
|
161
|
+
allow(token).to receive(:alive?).exactly(3).times.and_return(true, true, false)
|
162
|
+
|
163
|
+
expect(subject.vro_client).to receive(:token).exactly(3).times
|
164
|
+
subject.wait_for_workflow
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'when the request is completed on the first loop' do
|
169
|
+
it 'only refreshes the request 1 time' do
|
170
|
+
client = double('client')
|
171
|
+
token = double('token')
|
172
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
173
|
+
allow(client).to receive(:token).and_return(token)
|
174
|
+
expect(token).to receive(:alive?).once.and_return(false)
|
175
|
+
|
176
|
+
subject.wait_for_workflow
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the timeout is exceeded' do
|
181
|
+
before do
|
182
|
+
Chef::Config[:knife][:request_timeout] = 600
|
183
|
+
end
|
184
|
+
it 'raises a Timeout exception' do
|
185
|
+
allow(Timeout).to receive(:timeout).and_raise(Timeout::Error)
|
186
|
+
expect { subject.wait_for_workflow }.to raise_error(
|
187
|
+
Timeout::Error, 'Workflow did not complete in 600 seconds. ' \
|
188
|
+
'Please check the vRO UI for more information.')
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context 'when a non-timeout exception is raised' do
|
193
|
+
it 'raises the original exception' do
|
194
|
+
client = double('client')
|
195
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
196
|
+
allow(client).to receive(:token).and_raise(RuntimeError, 'an error occurred')
|
197
|
+
expect { subject.wait_for_workflow }.to raise_error(RuntimeError, 'an error occurred')
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe '#missing_config_parameters' do
|
203
|
+
context 'when all parameters are supplied' do
|
204
|
+
it 'returns an empty array' do
|
205
|
+
expect(subject.missing_config_parameters).to eq([])
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'when a parameter is missing' do
|
210
|
+
before do
|
211
|
+
Chef::Config[:knife][:vro_username] = nil
|
212
|
+
end
|
213
|
+
it 'returns an array with that parameter' do
|
214
|
+
expect(subject.missing_config_parameters).to eq([ :vro_username ])
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe '#validate!' do
|
220
|
+
context 'when a config parameter is missing' do
|
221
|
+
it 'calls #print_error_and_exit' do
|
222
|
+
allow(subject).to receive(:missing_config_parameters).and_return([ :parameter ])
|
223
|
+
expect(subject).to receive(:print_error_and_exit)
|
224
|
+
|
225
|
+
subject.validate!
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'when no workflow name is provided' do
|
230
|
+
let(:knife) { Chef::Knife::VroWorkflowExecute.new }
|
231
|
+
it 'calls #print_error_and_exit' do
|
232
|
+
expect(knife).to receive(:print_error_and_exit)
|
233
|
+
|
234
|
+
knife.validate!
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
describe '#print_error_and_exit' do
|
240
|
+
it 'prints an error and exits' do
|
241
|
+
expect(subject.ui).to receive(:error).with('an error occurred')
|
242
|
+
expect { subject.print_error_and_exit('an error occurred') }.to raise_error(SystemExit)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe '#print_results' do
|
247
|
+
it 'prints a blank line and calls the other print methods' do
|
248
|
+
expect(subject.ui).to receive(:msg).with('')
|
249
|
+
expect(subject).to receive(:print_output_parameters)
|
250
|
+
expect(subject).to receive(:print_execution_log)
|
251
|
+
|
252
|
+
subject.print_results
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe '#print_output_parameters' do
|
257
|
+
context 'when there are no output parameters' do
|
258
|
+
before do
|
259
|
+
client = double('client')
|
260
|
+
token = double('token')
|
261
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
262
|
+
allow(client).to receive(:token).and_return(token)
|
263
|
+
allow(token).to receive(:output_parameters).and_return({})
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'does not print any output' do
|
267
|
+
expect(subject.ui).not_to receive(:msg)
|
268
|
+
|
269
|
+
subject.print_output_parameters
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
context 'when output parameters exist' do
|
274
|
+
before do
|
275
|
+
client = double('client')
|
276
|
+
token = double('token')
|
277
|
+
param1 = double('param1', value: 'value1', type: 'string')
|
278
|
+
param2 = double('param2', value: 2.0, type: 'number')
|
279
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
280
|
+
allow(client).to receive(:token).and_return(token)
|
281
|
+
allow(token).to receive(:output_parameters).and_return(
|
282
|
+
'key1' => param1,
|
283
|
+
'key2' => param2
|
284
|
+
)
|
285
|
+
|
286
|
+
# squelch output during testing
|
287
|
+
allow(subject.ui).to receive(:msg)
|
288
|
+
allow(subject).to receive(:msg_pair)
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'prints a header and a blank line' do
|
292
|
+
header = subject.ui.color('Output Parameters:', :bold)
|
293
|
+
expect(subject.ui).to receive(:msg).with(header)
|
294
|
+
expect(subject.ui).to receive(:msg).with('')
|
295
|
+
|
296
|
+
subject.print_output_parameters
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'prints out the output parameters' do
|
300
|
+
expect(subject).to receive(:msg_pair).with('key1', 'value1 (string)')
|
301
|
+
expect(subject).to receive(:msg_pair).with('key2', '2.0 (number)')
|
302
|
+
|
303
|
+
subject.print_output_parameters
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
describe '#print_execution_log' do
|
309
|
+
context 'when the log is empty' do
|
310
|
+
before do
|
311
|
+
client = double('client', log: nil)
|
312
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'does not print any information' do
|
316
|
+
expect(subject.ui).not_to receive(:msg)
|
317
|
+
|
318
|
+
subject.print_execution_log
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
context 'when the log exists' do
|
323
|
+
before do
|
324
|
+
client = double('client', log: 'log entries go here')
|
325
|
+
allow(subject).to receive(:vro_client).and_return(client)
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'prints a header and the log entry' do
|
329
|
+
header = subject.ui.color('Workflow Execution Log:', :bold)
|
330
|
+
expect(subject.ui).to receive(:msg).with(header)
|
331
|
+
expect(subject.ui).to receive(:msg).with('log entries go here')
|
332
|
+
|
333
|
+
subject.print_execution_log
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
describe '#set_parameters' do
|
339
|
+
it 'sets the instance variables correctly' do
|
340
|
+
subject.set_parameters
|
341
|
+
|
342
|
+
expect(subject.workflow_name).to eq(workflow_name)
|
343
|
+
expect(subject.workflow_id).to eq(workflow_id)
|
344
|
+
expect(subject.parameters).to eq(
|
345
|
+
'key1' => 'value1',
|
346
|
+
'key2' => '2'
|
347
|
+
)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
describe '#run' do
|
352
|
+
it 'calls the correct methods' do
|
353
|
+
expect(subject).to receive(:validate!)
|
354
|
+
expect(subject).to receive(:set_parameters)
|
355
|
+
expect(subject.ui).to receive(:msg).with('Starting workflow execution...')
|
356
|
+
expect(subject).to receive(:execute_workflow).and_return('12345')
|
357
|
+
expect(subject.ui).to receive(:msg).with('Workflow execution 12345 started. Waiting for it to complete...')
|
358
|
+
expect(subject).to receive(:wait_for_workflow)
|
359
|
+
expect(subject.ui).to receive(:msg).with('Workflow execution complete.')
|
360
|
+
expect(subject).to receive(:print_results)
|
361
|
+
|
362
|
+
subject.run
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-vrealize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chef Partner Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
@@ -44,14 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.0
|
47
|
+
version: '1.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.0
|
54
|
+
version: '1.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: vcoworkflows
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.2'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,6 +103,7 @@ extra_rdoc_files: []
|
|
89
103
|
files:
|
90
104
|
- ".gitignore"
|
91
105
|
- ".rubocop.yml"
|
106
|
+
- CHANGELOG.md
|
92
107
|
- Gemfile
|
93
108
|
- LICENSE.txt
|
94
109
|
- README.md
|
@@ -101,6 +116,7 @@ files:
|
|
101
116
|
- lib/chef/knife/vra_server_delete.rb
|
102
117
|
- lib/chef/knife/vra_server_list.rb
|
103
118
|
- lib/chef/knife/vra_server_show.rb
|
119
|
+
- lib/chef/knife/vro_workflow_execute.rb
|
104
120
|
- lib/knife-vrealize/version.rb
|
105
121
|
- spec/spec_helper.rb
|
106
122
|
- spec/unit/cloud/vra_service_helpers_spec.rb
|
@@ -110,6 +126,7 @@ files:
|
|
110
126
|
- spec/unit/vra_server_delete_spec.rb
|
111
127
|
- spec/unit/vra_server_list_spec.rb
|
112
128
|
- spec/unit/vra_server_show_spec.rb
|
129
|
+
- spec/unit/vro_workflow_execute_spec.rb
|
113
130
|
homepage: https://gihub.com/chef-partners/knife-vrealize
|
114
131
|
licenses:
|
115
132
|
- Apache 2.0
|
@@ -143,4 +160,5 @@ test_files:
|
|
143
160
|
- spec/unit/vra_server_delete_spec.rb
|
144
161
|
- spec/unit/vra_server_list_spec.rb
|
145
162
|
- spec/unit/vra_server_show_spec.rb
|
163
|
+
- spec/unit/vro_workflow_execute_spec.rb
|
146
164
|
has_rdoc:
|