vcoworkflows 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|