vcoworkflows 0.1.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/.coveralls.yml +1 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +9 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.md +290 -0
- data/Rakefile +21 -0
- data/bin/vcoworkflows +7 -0
- data/example.rb +45 -0
- data/lib/vcoworkflows.rb +34 -0
- data/lib/vcoworkflows/cli/auth.rb +27 -0
- data/lib/vcoworkflows/cli/execute.rb +109 -0
- data/lib/vcoworkflows/cli/query.rb +106 -0
- data/lib/vcoworkflows/constants.rb +44 -0
- data/lib/vcoworkflows/runner.rb +44 -0
- data/lib/vcoworkflows/vcosession.rb +48 -0
- data/lib/vcoworkflows/version.rb +4 -0
- data/lib/vcoworkflows/workflow.rb +304 -0
- data/lib/vcoworkflows/workflowexecutionlog.rb +40 -0
- data/lib/vcoworkflows/workflowparameter.rb +145 -0
- data/lib/vcoworkflows/workflowpresentation.rb +59 -0
- data/lib/vcoworkflows/workflowservice.rb +110 -0
- data/lib/vcoworkflows/workflowtoken.rb +111 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/vcoworkflows/vcosession_spec.rb +33 -0
- data/spec/vcoworkflows/workflow_spec.rb +144 -0
- data/spec/vcoworkflows/workflowexecutionlog_spec.rb +22 -0
- data/spec/vcoworkflows/workflowparameter_spec.rb +67 -0
- data/spec/vcoworkflows/workflowpresentation_spec.rb +34 -0
- data/spec/vcoworkflows/workflowservice_spec.rb +113 -0
- data/spec/vcoworkflows/workflowtoken_spec.rb +64 -0
- data/vcoworkflows.gemspec +39 -0
- metadata +257 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'constants'
|
2
|
+
require_relative 'workflowservice'
|
3
|
+
require_relative 'workflow'
|
4
|
+
require_relative 'workflowtoken'
|
5
|
+
require_relative 'workflowparameter'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
# VcoWorkflows
|
9
|
+
module VcoWorkflows
|
10
|
+
# rubocop:disable ClassLength
|
11
|
+
|
12
|
+
# WorkflowPresentation is a helper class for Workflow and is primarily used
|
13
|
+
# internally to apply additional constraints to WorkflowParameters. Currently
|
14
|
+
# WorkflowPresentation examines the presentation JSON from vCO to determine
|
15
|
+
# whether input parameters for the workflow are required or not.
|
16
|
+
class WorkflowPresentation
|
17
|
+
attr_reader :presentation_data
|
18
|
+
attr_reader :required
|
19
|
+
|
20
|
+
# rubocop:disable LineLength, MethodLength
|
21
|
+
|
22
|
+
# Create a new WorkflowPresentation
|
23
|
+
# @param [VcoWorkflows::WorkflowService] workflow_service workflow service to use
|
24
|
+
# @param [String] workflow_id workflow GUID
|
25
|
+
# @return [VcoWorkflows::WorkflowPresentation]
|
26
|
+
def initialize(workflow_service, workflow_id)
|
27
|
+
@required = []
|
28
|
+
@presentation_data = JSON.parse(workflow_service.get_presentation(workflow_id))
|
29
|
+
|
30
|
+
# Determine if there are any required input parameters
|
31
|
+
# We're parsing this because we specifically want to know if any of
|
32
|
+
# the input parameters are marked as required. This is very specifically
|
33
|
+
# in the array of hashes in:
|
34
|
+
# presentation_data[:steps][0][:step][:elements][0][:fields]
|
35
|
+
fields = @presentation_data['steps'][0]['step']['elements'][0]['fields']
|
36
|
+
fields.each do |attribute|
|
37
|
+
next unless attribute.key?('constraints')
|
38
|
+
attribute['constraints'].each do |const|
|
39
|
+
if const.key?('@type') && const['@type'].eql?('mandatory')
|
40
|
+
@required << attribute['id']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# String representation of the presentation
|
47
|
+
# @return [String]
|
48
|
+
def to_s
|
49
|
+
@presentation_data.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
# JSON document
|
53
|
+
# @return [String] JSON Document
|
54
|
+
def to_json
|
55
|
+
JSON.pretty_generate(@presentation_data)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
# rubocop:enable ClassLength
|
59
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require_relative 'constants'
|
2
|
+
require_relative 'vcosession'
|
3
|
+
require_relative 'workflow'
|
4
|
+
require_relative 'workflowexecutionlog'
|
5
|
+
require 'json'
|
6
|
+
require 'erb'
|
7
|
+
|
8
|
+
include ERB::Util
|
9
|
+
|
10
|
+
module VcoWorkflows
|
11
|
+
# WorkflowService is the object which acts as the interface to the vCO
|
12
|
+
# API, and is loosely modeled from the vCO API documentation.
|
13
|
+
class WorkflowService
|
14
|
+
# Return the VcoSession
|
15
|
+
attr_reader :session
|
16
|
+
|
17
|
+
# rubocop:disable LineLength
|
18
|
+
|
19
|
+
# Create a new WorkflowService
|
20
|
+
# @param [VcoWorkflows::VcoSession] session Session object for the API endpoint
|
21
|
+
# @return [VcoWorkflows::WorkflowService]
|
22
|
+
def initialize(session)
|
23
|
+
@session = session
|
24
|
+
end
|
25
|
+
# rubocop:enable LineLength
|
26
|
+
|
27
|
+
# Get a workflow by GUID
|
28
|
+
# @param [String] id Workflow GUID
|
29
|
+
# @return [VcoWorkflows::Workflow] the requested workflow
|
30
|
+
def get_workflow_for_id(id)
|
31
|
+
@session.get("/workflows/#{id}").body
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get the presentation for the given workflow GUID
|
35
|
+
# @param [String] workflow_id workflow GUID
|
36
|
+
# @return [String] JSON document representation of Workflow Presentation
|
37
|
+
def get_presentation(workflow_id)
|
38
|
+
@session.get("/workflows/#{workflow_id}/presentation/").body
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get one workflow with a specified name.
|
42
|
+
# @param [String] name Name of the workflow
|
43
|
+
# @return [VcoWorkflows::Workflow] the requested workflow
|
44
|
+
def get_workflow_for_name(name)
|
45
|
+
path = "/workflows?conditions=name=#{url_encode(name)}"
|
46
|
+
response = JSON.parse(@session.get(path).body)
|
47
|
+
|
48
|
+
# barf if we got anything other than a single workflow
|
49
|
+
fail(IOError, ERR[:too_many_workflows]) if response['total'] > 1
|
50
|
+
fail(IOError, ERR[:no_workflow_found]) if response['total'] == 0
|
51
|
+
|
52
|
+
# yank out the workflow id and name from the result attributes
|
53
|
+
workflow_id = nil
|
54
|
+
response['link'][0]['attributes'].each do |a|
|
55
|
+
workflow_id = a['value'] if a['name'].eql?('id')
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get the workflow by GUID
|
59
|
+
get_workflow_for_id(workflow_id)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get a WorkflowToken for the requested workflow_id and execution_id
|
63
|
+
# @param [String] workflow_id Workflow GUID
|
64
|
+
# @param [String] execution_id Execution GUID
|
65
|
+
# @return [String] JSON document for workflow token
|
66
|
+
def get_execution(workflow_id, execution_id)
|
67
|
+
path = "/workflows/#{workflow_id}/executions/#{execution_id}"
|
68
|
+
@session.get(path).body
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get a list of executions for the given workflow GUID
|
72
|
+
# @param [String] workflow_id Workflow GUID
|
73
|
+
# @return [Hash]
|
74
|
+
def get_execution_list(workflow_id)
|
75
|
+
path = "/workflows/#{workflow_id}/executions/"
|
76
|
+
relations = JSON.parse(@session.get(path).body)['relations']
|
77
|
+
# The first two elements of the relations['link'] array are URLS,
|
78
|
+
# so scrap them. Everything else is an execution.
|
79
|
+
executions = {}
|
80
|
+
relations['link'].each do |link|
|
81
|
+
next unless link.key?('attributes')
|
82
|
+
attributes = {}
|
83
|
+
link['attributes'].each { |a| attributes[a['name']] = a['value'] }
|
84
|
+
executions[attributes['id']] = attributes
|
85
|
+
end
|
86
|
+
executions
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get the log for a specific execution
|
90
|
+
# @param [String] workflow_id
|
91
|
+
# @param [String] execution_id
|
92
|
+
# @return [String] JSON log document
|
93
|
+
def get_log(workflow_id, execution_id)
|
94
|
+
path = "/workflows/#{workflow_id}/executions/#{execution_id}/logs/"
|
95
|
+
@session.get(path).body
|
96
|
+
end
|
97
|
+
|
98
|
+
# Submit the given workflow for execution
|
99
|
+
# @param [String] id Workflow GUID for the workflow we want to execute
|
100
|
+
# @param [String] parameter_json JSON document of input parameters
|
101
|
+
# @return [String] Execution ID
|
102
|
+
def execute_workflow(id, parameter_json)
|
103
|
+
path = "/workflows/#{id}/executions/"
|
104
|
+
response = @session.post(path, parameter_json)
|
105
|
+
# Execution ID is the final component in the Location header URL, so
|
106
|
+
# chop off the front, then pull off any trailing /
|
107
|
+
response.headers[:location].gsub(%r{^.*/executions/}, '').gsub(/\/$/, '')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require_relative 'constants'
|
2
|
+
require_relative 'workflow'
|
3
|
+
require_relative 'workflowservice'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module VcoWorkflows
|
7
|
+
# WorkflowToken is used for workflow execution results, and contains as much
|
8
|
+
# data on the given workflow execution instance as vCO can provide.
|
9
|
+
class WorkflowToken
|
10
|
+
attr_reader :id
|
11
|
+
attr_reader :workflow_id
|
12
|
+
attr_reader :name
|
13
|
+
attr_reader :state
|
14
|
+
attr_reader :href
|
15
|
+
attr_reader :start_date
|
16
|
+
attr_reader :end_date
|
17
|
+
attr_reader :started_by
|
18
|
+
attr_reader :current_item_name
|
19
|
+
attr_reader :current_item_state
|
20
|
+
attr_reader :content_exception
|
21
|
+
attr_reader :global_state
|
22
|
+
attr_reader :input_parameters
|
23
|
+
attr_reader :output_parameters
|
24
|
+
attr_reader :json_content
|
25
|
+
|
26
|
+
# rubocop:disable CyclomaticComplexity, PerceivedComplexity, MethodLength, LineLength
|
27
|
+
|
28
|
+
# Create a new workflow token
|
29
|
+
# @param [VcoWorkflows::WorkflowService] workflow_service Workflow service to use
|
30
|
+
# @param [String] workflow_id GUID of the workflow
|
31
|
+
# @param [String] execution_id GUID of execution
|
32
|
+
# @return [VcoWorkflows::WorkflowToken]
|
33
|
+
def initialize(workflow_service, workflow_id, execution_id)
|
34
|
+
@service = workflow_service
|
35
|
+
@workflow_id = workflow_id
|
36
|
+
@json_content = @service.get_execution(workflow_id, execution_id)
|
37
|
+
|
38
|
+
token = JSON.parse(@json_content)
|
39
|
+
|
40
|
+
@id = token.key?('id') ? token['id'] : nil
|
41
|
+
@name = token.key?('name') ? token['name'] : nil
|
42
|
+
@state = token.key?('state') ? token['state'] : nil
|
43
|
+
@href = token.key?('href') ? token['href'] : nil
|
44
|
+
@start_date = token.key?('start-date') ? token['start-date'] : nil
|
45
|
+
@end_date = token.key?('end-date') ? token['end-date'] : nil
|
46
|
+
@started_by = token.key?('started-by') ? token['started-by'] : nil
|
47
|
+
@current_item_name = token.key?('current-item-display-name') ? token['current-item-display-name'] : nil
|
48
|
+
@current_item_state = token.key?('current-item-state') ? token['current-item-state'] : nil
|
49
|
+
@global_state = token.key?('global-state') ? token['global-state'] : nil
|
50
|
+
@content_exception = token.key?('content-exeption') ? token['content-exception'] : nil
|
51
|
+
|
52
|
+
if token.key?('input-parameters')
|
53
|
+
@input_parameters = VcoWorkflows::Workflow.parse_parameters(token['input-parameters'])
|
54
|
+
else
|
55
|
+
@input_parameters = {}
|
56
|
+
end
|
57
|
+
|
58
|
+
if token.key?('output-parameters')
|
59
|
+
@output_parameters = VcoWorkflows::Workflow.parse_parameters(token['output-parameters'])
|
60
|
+
else
|
61
|
+
@output_parameters = {}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
# rubocop:enable CyclomaticComplexity, PerceivedComplexity, MethodLength, LineLength
|
65
|
+
|
66
|
+
# Is the workflow execution still alive?
|
67
|
+
# @return [Boolean]
|
68
|
+
def alive?
|
69
|
+
running? || waiting?
|
70
|
+
end
|
71
|
+
|
72
|
+
# Is the workflow actively running?
|
73
|
+
# @return [Boolean]
|
74
|
+
def running?
|
75
|
+
state.eql?('running')
|
76
|
+
end
|
77
|
+
|
78
|
+
# Is the workflow in a waiting state?
|
79
|
+
# @return [Boolean]
|
80
|
+
def waiting?
|
81
|
+
state.match(/waiting/).nil? ? false : true
|
82
|
+
end
|
83
|
+
|
84
|
+
# rubocop:disable MethodLength, LineLength
|
85
|
+
|
86
|
+
# Convert this object to a string representation
|
87
|
+
# @return [String]
|
88
|
+
def to_s
|
89
|
+
string = "Execution ID: #{@id}\n"
|
90
|
+
string << "Name: #{@name}\n"
|
91
|
+
string << "Workflow ID: #{@workflow_id}\n"
|
92
|
+
string << "State: #{@state}\n"
|
93
|
+
string << "Start Date: #{Time.at(@start_date / 1000)}\n"
|
94
|
+
string << "End Date: #{end_date.nil? ? '' : Time.at(@end_date / 1000)}\n"
|
95
|
+
string << "Started By: #{@started_by}\n"
|
96
|
+
string << "Content Exception: #{@content_exception}\n" unless @content_exception.nil?
|
97
|
+
string << "\nInput Parameters:\n"
|
98
|
+
@input_parameters.each_value { |wf_param| string << " #{wf_param}" if wf_param.set? } if @input_parameters.size > 0
|
99
|
+
string << "\nOutput Parameters:" << "\n"
|
100
|
+
@output_parameters.each_value { |wf_param| string << " #{wf_param}" } if @output_parameters.size > 0
|
101
|
+
string
|
102
|
+
end
|
103
|
+
# rubocop:enable MethodLength, LineLength
|
104
|
+
|
105
|
+
# Convert this object to a JSON document (string)
|
106
|
+
# @return [String] JSON representation of the workflow token
|
107
|
+
def to_json
|
108
|
+
JSON.pretty_generate(JSON.parse(@json_content))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../spec_helper.rb'
|
2
|
+
require 'vcoworkflows'
|
3
|
+
|
4
|
+
# rubocop:disable LineLength
|
5
|
+
|
6
|
+
describe VcoWorkflows::VcoSession, 'VcoSession' do
|
7
|
+
before(:each) do
|
8
|
+
@uri = 'https://vcoserver.example.com:8281'
|
9
|
+
@username = 'johndoe'
|
10
|
+
@password = 's3cr3t'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should set the URL' do
|
14
|
+
vs = VcoWorkflows::VcoSession.new(@uri, user: @username, password: @password)
|
15
|
+
api_url = '/vco/api'
|
16
|
+
|
17
|
+
expect(vs.rest_resource.url).to eql(@uri << api_url)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should set the username' do
|
21
|
+
vs = VcoWorkflows::VcoSession.new(@uri, user: @username, password: @password)
|
22
|
+
|
23
|
+
expect(vs.rest_resource.user).to eql(@username)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should set the password' do
|
27
|
+
vs = VcoWorkflows::VcoSession.new(@uri, user: @username, password: @password)
|
28
|
+
|
29
|
+
expect(vs.rest_resource.password).to eql(@password)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# rubocop:enable LineLength
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require_relative '../spec_helper.rb'
|
2
|
+
require 'vcoworkflows'
|
3
|
+
|
4
|
+
# rubocop:disable LineLength
|
5
|
+
|
6
|
+
describe VcoWorkflows::Workflow, 'Workflow' do
|
7
|
+
before(:each) do
|
8
|
+
# Set up some basic starting data
|
9
|
+
@workflow_name = 'Request Component'
|
10
|
+
@workflow_id = '6e04a460-4a45-4e16-9603-db2922c24462'
|
11
|
+
@execution_id = 'ff8080814a1cb55c014a6481a9927a78'
|
12
|
+
@workflow_json = '''{"output-parameters":[{"name":"result","type":"string","description":"Catalog item request state"},{"name":"requestNumber","type":"number"},{"name":"requestCompletionDetails","type":"string"}],"relations":{"link":[{"rel":"up","href":"https://vco.example.com:8281/vco/api/inventory/System/Workflows/dlinsley%2540vmware.com/vCAC/"},{"rel":"executions","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/executions/"},{"rel":"presentation","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/presentation/"},{"rel":"tasks","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/tasks/"},{"rel":"icon","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/icon/"},{"rel":"schema","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/schema/"},{"rel":"permissions","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/permissions/"},{"rel":"interactions","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/interactions/"}]},"id":"6e04a460-4a45-4e16-9603-db2922c24462","name":"Request Component","version":"0.0.33","description":"","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/","customized-icon":false,"input-parameters":[{"name":"coreCount","type":"string"},{"name":"ramMB","type":"string"},{"name":"onBehalfOf","type":"string"},{"name":"machineCount","type":"string"},{"name":"businessUnit","type":"string"},{"name":"reservation","type":"string"},{"name":"location","type":"string"},{"name":"environment","type":"string"},{"name":"image","type":"string","description":"vCenter template name"},{"name":"runlist","type":"Array/string","description":"Chef Runlist for first run. Leave empty for no Chef"},{"name":"nodename","type":"string","description":"Chef Nodename"},{"name":"component","type":"string"},{"name":"attributesJS","type":"string","description":"JSON object of vCenter Attributes to apply to VM(s)"}]}'''
|
13
|
+
@presentation_json = '''{"output-parameters":[{"name":"machineCount","type":"string"},{"name":"location","type":"string"},{"name":"image","type":"string","description":"vCenter template name"},{"name":"coreCount","type":"string"},{"name":"ramMB","type":"string"},{"name":"onBehalfOf","type":"string"},{"name":"businessUnit","type":"string"},{"name":"environment","type":"string"},{"name":"component","type":"string"},{"name":"reservation","type":"string"},{"name":"runlist","type":"Array/string","description":"Chef Runlist for first run. Leave empty for no Chef"},{"name":"nodename","type":"string","description":"Chef Nodename"},{"name":"attributesJS","type":"string","description":"JSON object of vCenter Attributes to apply to VM(s)"}],"input-parameters":[{"name":"businessUnit","type":"string","description":"businessUnit"},{"name":"environment","type":"string","description":"environment"},{"name":"component","type":"string","description":"component"},{"name":"onBehalfOf","type":"string","description":"On Behalf of User: (user@domain format)"},{"name":"machineCount","type":"string","description":"machineCount"},{"name":"image","type":"string","description":"image"},{"name":"coreCount","type":"string","description":"coreCount"},{"name":"ramMB","type":"string","description":"ramSizeMB"},{"name":"runlist","type":"Array/string","description":"runlist"},{"name":"reservation","type":"string","description":"reservation"},{"name":"location","type":"string","description":"location"},{"name":"attributesJS","type":"string","description":"JSON object of vCenter Attributes to apply to VM(s)"},{"name":"nodename","type":"string","description":"Chef Nodename"}],"href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/presentation/","name":"Request Component","id":"6e04a460-4a45-4e16-9603-db2922c24462","steps":[{"step":{"messages":[],"hidden":false,"elements":[{"fields":[{"display-name":"businessUnit","constraints":[{"@type":"mandatory"}],"@type":"field","fields":[],"id":"businessUnit","description":"businessUnit","hidden":false,"messages":[],"decorators":[{"array":{"elements":[{"string":{"value":"an"}},{"string":{"value":"aw"}},{"string":{"value":"soi"}}]},"@type":"drop-down"}],"type":"string"},{"display-name":"environment","constraints":[{"@type":"mandatory"}],"@type":"field","fields":[],"id":"environment","description":"environment","hidden":false,"messages":[],"decorators":[],"type":"string"},{"display-name":"component","constraints":[{"@type":"mandatory"}],"@type":"field","fields":[],"id":"component","description":"component","hidden":false,"messages":[],"decorators":[],"type":"string"},{"display-name":"On Behalf of User: (user@domain format)","constraints":[],"@type":"field","fields":[],"id":"onBehalfOf","description":"On Behalf of User: (user@domain format)","hidden":false,"messages":[],"decorators":[],"type":"string"},{"display-name":"machineCount","constraints":[],"@type":"field","fields":[],"id":"machineCount","description":"machineCount","hidden":false,"messages":[],"decorators":[{"array":{"elements":[{"string":{"value":"1"}},{"string":{"value":"2"}},{"string":{"value":"3"}},{"string":{"value":"4"}},{"string":{"value":"5"}},{"string":{"value":"6"}},{"string":{"value":"7"}},{"string":{"value":"8"}},{"string":{"value":"9"}},{"string":{"value":"10"}}]},"@type":"drop-down"}],"type":"string"},{"display-name":"image","constraints":[{"@type":"mandatory"}],"@type":"field","fields":[],"id":"image","description":"image","hidden":false,"messages":[],"decorators":[{"array":{"elements":[{"string":{"value":"vcaccentos65v8-agent"}},{"string":{"value":"win2012std"}},{"string":{"value":"vcac2012std"}},{"string":{"value":"centos-6.6-x86_64-20141203-1"}},{"string":{"value":"v8-centos65-agent"}},{"string":{"value":"vcac2008r2std"}},{"string":{"value":"oracle-6.5-x86_64-20141203-1"}},{"string":{"value":"centos65v8"}},{"string":{"value":"w2012r2std_coreservices"}},{"string":{"value":"2008r2std"}}]},"@type":"drop-down"}],"type":"string"},{"display-name":"coreCount","constraints":[{"@type":"mandatory"}],"@type":"field","fields":[],"id":"coreCount","description":"coreCount","hidden":false,"messages":[],"decorators":[{"@type":"refresh-on-change"},{"array":{"elements":[{"string":{"value":"1"}},{"string":{"value":"2"}},{"string":{"value":"4"}},{"string":{"value":"8"}}]},"@type":"drop-down"}],"type":"string"},{"display-name":"ramSizeMB","constraints":[{"@type":"mandatory"}],"@type":"field","fields":[],"id":"ramMB","description":"ramSizeMB","hidden":false,"messages":[],"decorators":[{"array":{"elements":[null]},"@type":"drop-down"}],"type":"string"},{"display-name":"runlist","constraints":[],"@type":"field","fields":[],"id":"runlist","description":"runlist","hidden":false,"messages":[],"decorators":[],"type":"Array/string"},{"display-name":"reservation","constraints":[{"@type":"mandatory"}],"@type":"field","fields":[],"id":"reservation","description":"reservation","hidden":false,"messages":[],"decorators":[],"type":"string"},{"display-name":"location","constraints":[],"@type":"field","fields":[],"id":"location","description":"location","hidden":false,"messages":[],"decorators":[],"type":"string"},{"display-name":"JSON object of vCenter Attributes to apply to VM(s)","constraints":[],"@type":"field","fields":[],"id":"attributesJS","description":"JSON object of vCenter Attributes to apply to VM(s)","hidden":false,"messages":[],"decorators":[{"@type":"multiline"}],"type":"string"},{"display-name":"Chef Nodename","constraints":[],"@type":"field","fields":[],"id":"nodename","description":"Chef Nodename","hidden":false,"messages":[],"decorators":[],"type":"string"}],"messages":[],"hidden":false,"@type":"group"}]}}],"relations":{"link":[{"rel":"up","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/"},{"rel":"instances","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/presentation/instances/"},{"rel":"add","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/presentation/instances/"}]}}'''
|
14
|
+
@param_string_json = '''{"type":"string","name":"stringparam","scope":"local","value":{"string":{"value":"squirrel!"}}}'''
|
15
|
+
@param_array_json = '''{"type":"Array/string","name":"arrayparam","scope":"local","value":{"array":{"elements":[{"string":{"value":"a"}},{"string":{"value":"b"}},{"string":{"value":"c"}}]}}}'''
|
16
|
+
|
17
|
+
# Mock the WorkflowService
|
18
|
+
@service = double('service')
|
19
|
+
allow(@service).to receive(:get_workflow_for_id) { @workflow_json }
|
20
|
+
allow(@service).to receive(:get_workflow_for_name) { @workflow_json }
|
21
|
+
allow(@service).to receive(:get_presentation) { @presentation_json }
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should parse a single string parameter' do
|
25
|
+
param_data = []
|
26
|
+
param_data << JSON.parse(@param_string_json)
|
27
|
+
wfparams = VcoWorkflows::Workflow.parse_parameters(param_data)
|
28
|
+
|
29
|
+
expect(wfparams).to_not eq(nil)
|
30
|
+
expect(wfparams.size).to eq(1)
|
31
|
+
expect(wfparams.key?('stringparam')).to eq(true)
|
32
|
+
expect(wfparams['stringparam'].type).to eql('string')
|
33
|
+
expect(wfparams['stringparam'].subtype).to eq(nil)
|
34
|
+
expect(wfparams['stringparam'].value).to eql('squirrel!')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should parse a single Array parameter' do
|
38
|
+
param_data = []
|
39
|
+
param_data << JSON.parse(@param_array_json)
|
40
|
+
wfparams = VcoWorkflows::Workflow.parse_parameters(param_data)
|
41
|
+
|
42
|
+
expect(wfparams).to_not eq(nil)
|
43
|
+
expect(wfparams.size).to eq(1)
|
44
|
+
expect(wfparams.key?('arrayparam')).to eq(true)
|
45
|
+
expect(wfparams['arrayparam'].type).to eql('Array')
|
46
|
+
expect(wfparams['arrayparam'].subtype).to eql('string')
|
47
|
+
expect(wfparams['arrayparam'].value).to eql(%w(a b c))
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should parse an array of mixed parameters' do
|
51
|
+
param_data = []
|
52
|
+
param_data << JSON.parse(@param_string_json)
|
53
|
+
param_data << JSON.parse(@param_array_json)
|
54
|
+
wfparams = VcoWorkflows::Workflow.parse_parameters(param_data)
|
55
|
+
|
56
|
+
expect(wfparams).to_not eq(nil)
|
57
|
+
expect(wfparams.size).to eq(2)
|
58
|
+
expect(wfparams.key?('stringparam')).to eq(true)
|
59
|
+
expect(wfparams['stringparam'].type).to eql('string')
|
60
|
+
expect(wfparams['stringparam'].subtype).to eq(nil)
|
61
|
+
expect(wfparams['stringparam'].value).to eql('squirrel!')
|
62
|
+
expect(wfparams.key?('arrayparam')).to eq(true)
|
63
|
+
expect(wfparams['arrayparam'].type).to eql('Array')
|
64
|
+
expect(wfparams['arrayparam'].subtype).to eql('string')
|
65
|
+
expect(wfparams['arrayparam'].value).to eql(%w(a b c))
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should not explode' do
|
69
|
+
wf = VcoWorkflows::Workflow.new(@workflow_name, service: @service)
|
70
|
+
|
71
|
+
expect(wf).to_not eq(nil)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should have input and output parameters' do
|
75
|
+
input_param_count = 13
|
76
|
+
output_param_count = 3
|
77
|
+
wf = VcoWorkflows::Workflow.new(@workflow_name, service: @service)
|
78
|
+
|
79
|
+
expect(wf.input_parameters.size).to eq(input_param_count)
|
80
|
+
expect(wf.output_parameters.size).to eq(output_param_count)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should have required parameters' do
|
84
|
+
required_param_count = 7
|
85
|
+
wf = VcoWorkflows::Workflow.new(@workflow_name, service: @service)
|
86
|
+
|
87
|
+
expect(wf.required_parameters.size).to eq(required_param_count)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should set and return a parameter value' do
|
91
|
+
wf = VcoWorkflows::Workflow.new(@workflow_name, service: @service)
|
92
|
+
|
93
|
+
expect(wf.set_parameter('coreCount', 4)).to eq(4)
|
94
|
+
expect(wf.input_parameters['coreCount'].value).to eq(4)
|
95
|
+
expect(wf.get_parameter('coreCount')).to eql(4)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should execute' do
|
99
|
+
allow(@service).to receive(:execute_workflow) { @execution_id }
|
100
|
+
target_parameters = {
|
101
|
+
'coreCount' => 2,
|
102
|
+
'ramMB' => 2048,
|
103
|
+
'businessUnit' => 'aw',
|
104
|
+
'reservation' => 'nonprodlinux',
|
105
|
+
'environment' => 'dev1',
|
106
|
+
'image' => 'centos-6.6-x86_64-20141203-1',
|
107
|
+
'component' => 'api',
|
108
|
+
'onBehalfOf' => 'svcacct@example.com',
|
109
|
+
'location' => 'us_east',
|
110
|
+
'runlist' => %w(role[loc_uswest] role[base] role[api]),
|
111
|
+
'machineCount' => 1
|
112
|
+
}
|
113
|
+
|
114
|
+
wf = VcoWorkflows::Workflow.new(@workflow_name, service: @service)
|
115
|
+
target_parameters.each { |k, v| wf.set_parameter(k, v) }
|
116
|
+
|
117
|
+
expect(wf.execute).to eql(@execution_id)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should provide a WorkflowToken' do
|
121
|
+
token_json = '''{"relations":{"link":[{"href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/executions/","rel":"up"},{"href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/executions/ff8080814a1cb55c014a6481a9927a78/","rel":"remove"},{"href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/executions/ff8080814a1cb55c014a6481a9927a78/logs/","rel":"logs"},{"href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/executions/ff8080814a1cb55c014a6481a9927a78/state/","rel":"state"}]},"id":"ff8080814a1cb55c014a6481a9927a78","state":"completed","name":"Request Component","href":"https://vco.example.com:8281/vco/api/workflows/6e04a460-4a45-4e16-9603-db2922c24462/executions/ff8080814a1cb55c014a6481a9927a78/","start-date":1419025426833,"end-date":1419026124320,"started-by":"someuser@EXAMPLE.COM","input-parameters":[{"value":{"string":{"value":"2"}},"type":"string","name":"coreCount","scope":"local"},{"value":{"string":{"value":"2048"}},"type":"string","name":"ramMB","scope":"local"},{"value":{"string":{"value":"svcacct@example.com"}},"type":"string","name":"onBehalfOf","scope":"local"},{"value":{"string":{"value":"1"}},"type":"string","name":"machineCount","scope":"local"},{"value":{"string":{"value":"aw"}},"type":"string","name":"businessUnit","scope":"local"},{"value":{"string":{"value":"nonprodlinux"}},"type":"string","name":"reservation","scope":"local"},{"value":{"string":{"value":"us_east"}},"type":"string","name":"location","scope":"local"},{"value":{"string":{"value":"dev1"}},"type":"string","name":"environment","scope":"local"},{"value":{"string":{"value":"centos-6.6-x86_64-20141203-1"}},"type":"string","name":"image","scope":"local"},{"value":{"array":{"elements":[{"string":{"value":"role[loc_uswest]"}},{"string":{"value":"role[base]"}},{"string":{"value":"role[api]"}}]}},"type":"Array/string","name":"runlist","scope":"local"},{"value":{"string":{"value":""}},"type":"string","name":"nodename","scope":"local"},{"value":{"string":{"value":"api"}},"type":"string","name":"component","scope":"local"},{"value":{"string":{"value":""}},"type":"string","name":"attributesJS","scope":"local"}],"output-parameters":[{"value":{"string":{"value":"SUCCESSFUL"}},"type":"string","name":"result","scope":"local"},{"value":{"number":{"value":326.0}},"type":"number","name":"requestNumber","scope":"local"},{"value":{"string":{"value":"Request succeeded. Created vm00378."}},"type":"string","name":"requestCompletionDetails","scope":"local"}]}'''
|
122
|
+
allow(@service).to receive(:get_execution) { token_json }
|
123
|
+
|
124
|
+
wf = VcoWorkflows::Workflow.new(@workflow_name, service: @service)
|
125
|
+
wftoken = wf.token(@execution_id)
|
126
|
+
|
127
|
+
expect(wftoken).to_not eq(nil)
|
128
|
+
expect(wftoken.workflow_id).to eq(wf.id)
|
129
|
+
expect(wftoken.id).to eq(@execution_id)
|
130
|
+
expect(wftoken.alive?).to eq(false)
|
131
|
+
expect(wftoken.state).to eql('completed')
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should provide a WorkflowExectionLog' do
|
135
|
+
log_json = '''{"logs":[{"entry":{"severity":"info","time-stamp":1419026124333,"user":"gruiz-ade","short-description":"Workflow \'Request Component\' has completed","long-description":"Workflow \'Request Component\' has completed"}},{"entry":{"severity":"info","time-stamp":1419026123927,"user":"gruiz-ade","short-description":"Workflow \'Request Component\' has resumed","long-description":"Workflow \'Request Component\' has resumed"}},{"entry":{"severity":"info","time-stamp":1419025439183,"user":"gruiz-ade","short-description":"Workflow is paused","long-description":"Workflow \'Request Component\' has paused while waiting on signal"}},{"entry":{"severity":"info","time-stamp":1419025426870,"user":"gruiz-ade","short-description":"Workflow \'Request Component\' has started","long-description":"Workflow \'Request Component\' has started"}}]}'''
|
136
|
+
allow(@service).to receive(:get_log) { log_json }
|
137
|
+
|
138
|
+
wf = VcoWorkflows::Workflow.new(@workflow_name, service: @service)
|
139
|
+
wflog = wf.log(@execution_id)
|
140
|
+
|
141
|
+
expect(wflog).to_not eq(nil)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
# rubocop:enable LineLength
|