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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 956a5ab3b8332ded3eb216b2c08091153ebf0b34
4
- data.tar.gz: da95d3c16ea538d076f4f886b5c808d3e3139bfa
3
+ metadata.gz: 18b5c642ccb473d7df715d34eee5b7c3c3790533
4
+ data.tar.gz: 175681a883e7c62be2153dd76340620046ac69ff
5
5
  SHA512:
6
- metadata.gz: ca60191e77286caff2493431f0e65f4b3d49d2d277472d57fa0bc67d079ff033883a4fc6dfbee5bc4197f4156fae1b41748517b6f2e444a7c8f19b34b25b0545
7
- data.tar.gz: 17c37268428ebd782499bf80e8c8e8cf8c7895f1aa88bb36162922806ae6374f1d76d82049334c1126059b2afa83a5b868842f294ca254fe07b713bef66b9f02
6
+ metadata.gz: dd6bd2398f4839db9f58f176649eaa440a7fec2839c710ff211d20816b6a82661c787a0b5c9157cb4257ea354f80dcab91ace31260f517fc96087b26889bd2e4
7
+ data.tar.gz: 8214624f133a68cc1e44f25eeb7d1c01b307d1c58d058d9ec315d2d790afdbd41015af3c770ede4361b950d1ce1b582da1468ad2666288323d4b13a3f645c1f5
@@ -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
- ## Configuration
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
- ## Usage
45
+ ### Usage
46
46
 
47
- ### knife vra catalog list
47
+ #### knife vra catalog list
48
48
 
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.
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
- ### knife vra server list
59
+ #### knife vra server list
60
60
 
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`
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
- ### knife vra server show RESOURCE_ID
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
- ### knife vra server create CATALOG_ID (options)
84
+ #### knife vra server create CATALOG_ID (options)
85
85
 
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.).
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. 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.
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. 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.
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
- ### knife vra server delete RESOURCE_ID
110
+ #### knife vra server delete RESOURCE_ID
111
111
 
112
- Deletes a server from vRA. If you supply `--purge`, the server will also be removed from the Chef Server.
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
- $ bundle exec knife vra server delete 2e1f6632-1613-41d1-a07c-6137c9639609 --purge
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. Please submit a GitHub issue with any problems you encounter.
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
 
@@ -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.0.rc2'
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'
@@ -39,7 +39,7 @@ class Chef
39
39
  def wait_for_request(request, wait_time=600, refresh_rate=2)
40
40
  print 'Waiting for request to complete.'
41
41
 
42
- last_status = ''
42
+ last_status = ''
43
43
 
44
44
  begin
45
45
  Timeout.timeout(wait_time) do
@@ -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. Will default to the vra_username parameter'
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. TYPE must be "string" or "integer". ' \
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
@@ -17,5 +17,5 @@
17
17
  #
18
18
 
19
19
  module KnifeVrealize
20
- VERSION = '1.0.0'
20
+ VERSION = '1.1.0'
21
21
  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.0.0
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-07 00:00:00.000000000 Z
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.0.rc2
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.0.rc2
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: