vcoworkflows-ruby2 0.2.3

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.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+ require 'cucumber/rake/task'
4
+ require 'coveralls/rake/task'
5
+ require 'yard'
6
+
7
+ Bundler::GemHelper.install_tasks
8
+ RSpec::Core::RakeTask.new(:spec)
9
+ Cucumber::Rake::Task.new(:features)
10
+ Coveralls::RakeTask.new
11
+
12
+ task :style do
13
+ sh 'rubocop'
14
+ end
15
+
16
+ task :doc do
17
+ sh 'yard'
18
+ end
19
+
20
+ # task default: [:spec, :features, :style, :doc, 'coveralls:push']
21
+ task default: [:style, :spec, :doc, 'coveralls:push']
data/bin/vcoworkflows ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # require 'vcoworkflows'
4
+ require 'vcoworkflows/runner'
5
+
6
+ VcoWorkflows::Runner.new(ARGV.dup).execute!
7
+ # VcoWorkflows::CLI.start(ARGV.dup)
data/example.rb ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vcoworkflows'
4
+
5
+ # What am I connecting to?
6
+ url = 'https://myvco.example.com:8281/vco/api'
7
+ username = 'myuser'
8
+ password = 'secret!'
9
+
10
+ # What's the workflow I want to work with?
11
+ workflow_name = 'Do Something Cool'
12
+
13
+ # Define the parameters for the workflow which we need to supply.
14
+ # The 'Do Something Cool' workflow needs a name, version, and words (an array
15
+ # of strings).
16
+ input_parameters = { 'name' => 'a string value',
17
+ 'version' => '2',
18
+ 'words' => %w(fe fi fo fum) }
19
+
20
+ # Fetch the workflow from vCO
21
+ workflow = VcoWorkflows::Workflow.new(workflow_name,
22
+ url: url,
23
+ username: username,
24
+ password: password,
25
+ verify_ssl: false)
26
+
27
+ # Set the parameters in the workflow
28
+ workflow.parameters = input_parameters
29
+
30
+ # Execute the workflow. This will also save the execution id in our
31
+ # workflow object.
32
+ workflow.execute
33
+
34
+ # We're going to wait around until the execution is done, so we'll check
35
+ # on it every 5 seconds until we see whether it completed or failed.
36
+ finished = false
37
+ until finished
38
+ sleep 5
39
+ # Fetch a new workflow token to check the status of the workflow execution
40
+ wftoken = workflow.token
41
+ # If the execution is no longer alive, exit the loop and report the results.
42
+ unless wftoken.alive?
43
+ finished = true
44
+ wftoken.output_parameters.each { |k, v| puts " #{k}: #{v}" }
45
+ end
46
+ end
@@ -0,0 +1,33 @@
1
+ require 'thor'
2
+
3
+ require File.dirname(__FILE__) + '/vcoworkflows/version'
4
+ require File.dirname(__FILE__) + '/vcoworkflows/constants'
5
+ require File.dirname(__FILE__) + '/vcoworkflows/config'
6
+ require File.dirname(__FILE__) + '/vcoworkflows/vcosession'
7
+ require File.dirname(__FILE__) + '/vcoworkflows/workflowservice'
8
+ require File.dirname(__FILE__) + '/vcoworkflows/workflow'
9
+ require File.dirname(__FILE__) + '/vcoworkflows/workflowparameter'
10
+ require File.dirname(__FILE__) + '/vcoworkflows/workflowtoken'
11
+ require File.dirname(__FILE__) + '/vcoworkflows/cli/execute'
12
+ require File.dirname(__FILE__) + '/vcoworkflows/cli/query'
13
+
14
+ # Refer to README.md for use instructions
15
+ module VcoWorkflows
16
+ # Start of main CLI processing
17
+ class CLI < Thor
18
+ package_name 'vcoworkflows'
19
+ map '--version' => :version
20
+ map '-v' => :version
21
+
22
+ desc 'version', DESC_VERSION
23
+
24
+ # Display the version of `vcoworkflows`
25
+ def version
26
+ puts VERSION
27
+ end
28
+
29
+ register(VcoWorkflows::Cli::Execute, 'execute', 'execute <WORKFLOW>', DESC_CLI_EXECUTE)
30
+ register(VcoWorkflows::Cli::Query, 'query', 'query <WORKFLOW>', DESC_CLI_QUERY)
31
+ end
32
+ end
33
+ # rubocop:enable LineLength
@@ -0,0 +1,109 @@
1
+ require 'vcoworkflows'
2
+ require 'thor/group'
3
+
4
+ # rubocop:disable MethodLength
5
+
6
+ # VcoWorkflows
7
+ module VcoWorkflows
8
+ # Cli
9
+ module Cli
10
+ # Execute a workflow with the given options.
11
+ class Execute < Thor::Group
12
+ include Thor::Actions
13
+
14
+ argument :workflow, type: :string, desc: DESC_CLI_WORKFLOW
15
+ class_option :server, type: :string, aliases: '-s', required: true, desc: DESC_CLI_SERVER
16
+ class_option :username, type: :string, aliases: '-u', desc: DESC_CLI_USERNAME
17
+ class_option :password, type: :string, aliases: '-p', desc: DESC_CLI_PASSWORD
18
+ class_option :id, type: :string, aliases: '-i', desc: DESC_CLI_WORKFLOW_ID
19
+ class_option :verify_ssl, type: :boolean, default: true, desc: DESC_CLI_VERIFY_SSL
20
+ class_option :dry_run, type: :boolean, default: false, desc: DESC_CLI_DRY_RUN
21
+ class_option :verbose, type: :boolean, default: true, desc: DESC_CLI_VERBOSE
22
+ class_option :watch, type: :boolean, default: true, desc: DESC_CLI_EXECUTE_WATCH
23
+
24
+ class_option :parameters, type: :string, required: true, desc: DESC_CLI_EXECUTE_PARAMETERS
25
+
26
+ # Thor
27
+ def self.source_root
28
+ File.dirname(__FILE__)
29
+ end
30
+
31
+ # rubocop:disable CyclomaticComplexity, PerceivedComplexity
32
+ def execute
33
+ config = VcoWorkflows::Config.new(url: options[:server],
34
+ username: options[:username],
35
+ password: options[:password],
36
+ verify_ssl: options[:verify_ssl])
37
+
38
+ # Parse out the parameters
39
+ parameters = {}
40
+ options[:parameters].split(/,/).each do |p|
41
+ k, v = p.split(/=/)
42
+ parameters[k] = v
43
+ end
44
+ if parameters.key?('runlist')
45
+ parameters['runlist'] = parameters['runlist'].split(/:/)
46
+ end
47
+
48
+ puts "Executing against vCO REST endpoint: #{options[:server]}"
49
+ puts "Requested execution of workflow: '#{workflow}'"
50
+ puts "Will call workflow by GUID (#{options[:id]})" if options[:id]
51
+ if options[:verbose] || options[:dry_run]
52
+ puts 'Parameters:'
53
+ parameters.each do |k, v|
54
+ v = v.join(',') if v.is_a?(Array)
55
+ puts " - #{k}: #{v}"
56
+ end
57
+ puts ''
58
+ end
59
+
60
+ return if options[:dry_run]
61
+
62
+ # Get the workflow
63
+ puts "Retrieving workflow '#{workflow}' ..."
64
+ wf = VcoWorkflows::Workflow.new(workflow,
65
+ id: options[:id],
66
+ config: config)
67
+
68
+ # List out mandatory parameters
69
+ puts "Required parameters:\n #{wf.required_parameters.keys.join(', ')}"
70
+
71
+ # Set the input parameters
72
+ puts 'Setting workflow input parameters...' if options[:verbose]
73
+ parameters.each do |k, v|
74
+ puts "setting #{k} to #{v}" if options[:verbose]
75
+ wf.set_parameter(k, v)
76
+ end
77
+
78
+ # Execute the workflow
79
+ puts 'Executing workflow...'
80
+ wf.execute
81
+
82
+ # Fetch the results
83
+ wftoken = wf.token
84
+ puts "#{wftoken.id} started at #{Time.at(wftoken.start_date / 1000)}"
85
+
86
+ # If we don't care about the results, move on.
87
+ return unless options[:watch]
88
+
89
+ # Check for update results until we get one who's state
90
+ # is not "running" or "waiting"
91
+ puts "\nChecking status...\n"
92
+ while wftoken.alive?
93
+ sleep 10
94
+ wftoken = wf.token
95
+ puts "#{Time.now} state: #{wftoken.state}"
96
+ end
97
+ puts "\nFinal status of execution:"
98
+ puts wftoken
99
+
100
+ # Print out the execution log
101
+ puts "\nWorkflow #{wf.name} log for execution #{wftoken.id}:"
102
+ log = wf.log(wftoken.id)
103
+ puts "\n#{log}"
104
+ end
105
+ # rubocop:enable CyclomaticComplexity, PerceivedComplexity
106
+ end
107
+ end
108
+ end
109
+ # rubocop:enable MethodLength, LineLength
@@ -0,0 +1,106 @@
1
+ require 'vcoworkflows'
2
+ require 'thor/group'
3
+
4
+ # rubocop:disable MethodLength, LineLength
5
+
6
+ # VcoWorkflows
7
+ module VcoWorkflows
8
+ # Cli
9
+ module Cli
10
+ # Query
11
+ class Query < Thor::Group
12
+ include Thor::Actions
13
+
14
+ argument :workflow, type: :string, desc: DESC_CLI_WORKFLOW
15
+ class_option :server, type: :string, aliases: '-s', required: true, desc: DESC_CLI_SERVER
16
+ class_option :username, type: :string, aliases: '-u', desc: DESC_CLI_USERNAME
17
+ class_option :password, type: :string, aliases: '-p', desc: DESC_CLI_PASSWORD
18
+ class_option :id, type: :string, aliases: '-i', desc: DESC_CLI_WORKFLOW_ID
19
+ class_option :verify_ssl, type: :boolean, default: true, desc: DESC_CLI_VERIFY_SSL
20
+ class_option :dry_run, type: :boolean, default: false, desc: DESC_CLI_DRY_RUN
21
+
22
+ class_option :executions, type: :boolean, aliases: '-e', default: false, desc: DESC_CLI_QUERY_EXECS
23
+ class_option :last, type: :numeric, aliases: '-l', default: 0, desc: DESC_CLI_QUERY_EXEC_LIM
24
+ class_option :execution_id, type: :string, aliases: ['-I', '--execution'], desc: DESC_CLI_QUERY_EXEC_ID
25
+ class_option :state, type: :boolean, aliases: '-r', desc: DESC_CLI_QUERY_EXEC_STATE
26
+ class_option :logs, type: :boolean, aliases: ['-L', '--log'], desc: DESC_CLI_QUERY_EXEC_LOG
27
+ class_option :show_json, type: :boolean, default: false, desc: DESC_CLI_QUERY_JSON
28
+
29
+ # Thor
30
+ def self.source_root
31
+ File.dirname(__FILE__)
32
+ end
33
+
34
+ # Process the subcommand
35
+ # rubocop:disable CyclomaticComplexity, PerceivedComplexity
36
+ def query
37
+ config = VcoWorkflows::Config.new(url: options[:server],
38
+ username: options[:username],
39
+ password: options[:password],
40
+ verify_ssl: options[:verify_ssl])
41
+
42
+ if options[:dry_run]
43
+ puts "\nQuerying against vCO REST endpoint:\n #{options[:server]}"
44
+ puts "Will search for workflow: '#{workflow}'"
45
+ puts "Will query workflow by GUID (#{options[:id]})" if options[:id]
46
+ return
47
+ end
48
+
49
+ # Get the workflow
50
+ puts "\nRetrieving workflow '#{workflow}' ..."
51
+ wf = VcoWorkflows::Workflow.new(workflow,
52
+ id: options[:id],
53
+ config: config)
54
+
55
+ puts ''
56
+ if options[:execution_id]
57
+ puts "Fetching data for execution #{options[:execution_id]}..."
58
+ execution = wf.token(options[:execution_id])
59
+ if options[:state]
60
+ puts "Execution started at #{Time.at(execution.start_date / 1000)}"
61
+ puts "Execution #{execution.state} at #{Time.at(execution.end_date / 1000)}"
62
+ else
63
+ puts ''
64
+ if options[:show_json]
65
+ puts execution.to_json
66
+ else
67
+ puts execution
68
+ end
69
+ end
70
+
71
+ if options[:logs]
72
+ puts ''
73
+ wflog = wf.log(options[:execution_id])
74
+ if options[:show_json]
75
+ puts wflog.to_json
76
+ else
77
+ puts wflog
78
+ end
79
+ end
80
+ else
81
+ puts wf unless options[:executions]
82
+ end
83
+
84
+ # Last thing we're checking for, so if it's not wanted, just return
85
+ return unless options[:executions]
86
+ puts "\nWorkflow: #{wf.name}"
87
+ puts "ID: #{wf.id}"
88
+ puts "Description: #{wf.description}"
89
+ puts "Version: #{wf.version}"
90
+ puts "\nExecutions: "
91
+ executions = {}
92
+ wf.executions.each_value { |attrs| executions[attrs['startDate']] = attrs }
93
+ keys = executions.keys.sort
94
+ keys = keys.slice(keys.size - options[:last], keys.size) if options[:last] > 0
95
+ keys.each do |timestamp|
96
+ dataline = timestamp.to_s
97
+ dataline << " [#{executions[timestamp]['id']}]"
98
+ dataline << " #{executions[timestamp]['state']}"
99
+ puts dataline
100
+ end
101
+ end
102
+ # rubocop:enable CyclomaticComplexity, PerceivedComplexity
103
+ end
104
+ end
105
+ end
106
+ # rubocop:enable MethodLength, LineLength
@@ -0,0 +1,91 @@
1
+ require 'vcoworkflows/constants'
2
+ require 'uri'
3
+
4
+ # VcoWorkflows
5
+ module VcoWorkflows
6
+ # Class Config
7
+ class Config
8
+ # URL for the vCenter Orchestrator REST API
9
+ attr_reader :url
10
+
11
+ # User name to authenticate to vCenter Orchestrator
12
+ attr_accessor :username
13
+
14
+ # Password to authenticate to vCenter Orchestrator
15
+ attr_accessor :password
16
+
17
+ # Whether or not to do SSL/TLS Certificate verification
18
+ attr_accessor :verify_ssl
19
+
20
+ # rubocop:disable MethodLength, CyclomaticComplexity, PerceivedComplexity
21
+
22
+ # Constructor
23
+ # @param [String] config_file Path to config file to load
24
+ # @param [String] url URL for vCO server
25
+ # @param [String] username Username for vCO server
26
+ # @param [String] password Password for vCO server
27
+ # @param [Boolean] verify_ssl Verify SSL Certificates?
28
+ # @return [VcoWorkflows::Config]
29
+ def initialize(config_file: nil, url: nil, username: nil, password: nil, verify_ssl: true)
30
+ # If we're given a URL and no config_file, then build the configuration
31
+ # from the values we're given (or can scrape from the environment).
32
+ # Otherwise, load the given config file or the default config file if no
33
+ # config file was given.
34
+ if url && config_file.nil?
35
+ self.url = url
36
+ @username = username.nil? ? ENV['VCO_USER'] : username
37
+ @password = password.nil? ? ENV['VCO_PASSWD'] : password
38
+ @verify_ssl = verify_ssl
39
+ else
40
+ # First, check if an explicit config file was given
41
+ config_file = DEFAULT_CONFIG_FILE if config_file.nil?
42
+ load_config(config_file)
43
+ end
44
+
45
+ # Fail if we don't have both a username and a password.
46
+ raise(IOError, ERR[:url_unset]) if @url.nil?
47
+ raise(IOError, ERR[:username_unset]) if @username.nil?
48
+ raise(IOError, ERR[:password_unset]) if @password.nil?
49
+ end
50
+ # rubocop:enable LineLength, MethodLength, CyclomaticComplexity, PerceivedComplexity
51
+
52
+ # Set the URL for the vCO server, force the path component.
53
+ # @param [String] vco_url
54
+ def url=(vco_url)
55
+ url = URI.parse(vco_url)
56
+ url.path = '/vco/api'
57
+ @url = url.to_s
58
+ end
59
+ # rubocop:enable LineLength
60
+
61
+ # load config file
62
+ # @param [String] config_file Path for the configuration file to load
63
+ def load_config(config_file)
64
+ config_data = JSON.parse(File.read(config_file))
65
+ return if config_data.nil?
66
+ self.url = config_data['url']
67
+ @username = config_data['username']
68
+ @password = config_data['password']
69
+ @verify_ssl = config_data['verify_ssl']
70
+ end
71
+
72
+ # Return a String representation of this object
73
+ # @return [String]
74
+ def to_s
75
+ puts "url: #{@url}"
76
+ puts "username: #{@username}"
77
+ puts "password: #{@password}"
78
+ puts "verify_ssl: #{@verify_ssl}"
79
+ end
80
+
81
+ # Return a JSON document for this object
82
+ def to_json
83
+ config = {}
84
+ config['url'] = @url
85
+ config['username'] = @username
86
+ config['password'] = @password
87
+ config['verify_ssl'] = @verify_ssl
88
+ puts JSON.pretty_generate(config)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,94 @@
1
+ # VcoWorkflows
2
+ module VcoWorkflows
3
+ # rubocop:disable LineLength
4
+
5
+ #
6
+ class Config
7
+ # Where we nominally expect configuration files to be
8
+ DEFAULT_CONFIG_DIR = File.join((ENV['HOME'] || ENV['HOMEDRIVE']), '.vcoworkflows')
9
+
10
+ # Default configuration file
11
+ DEFAULT_CONFIG_FILE = File.join(DEFAULT_CONFIG_DIR, 'config.json')
12
+ end
13
+
14
+ # Options description messages
15
+
16
+ # Version
17
+ DESC_VERSION = 'Display the installed version of the VcoWorkflows gem'.freeze
18
+
19
+ # Execute
20
+ DESC_CLI_EXECUTE = 'Execute the specified workflow'.freeze
21
+
22
+ # Query
23
+ DESC_CLI_QUERY = 'Query vCO for a workflow'.freeze
24
+
25
+ # Workflow
26
+ DESC_CLI_WORKFLOW = 'Name of the workflow'.freeze
27
+
28
+ # ID
29
+ DESC_CLI_WORKFLOW_ID = 'GUID of the workflow'.freeze
30
+
31
+ # dry-run
32
+ DESC_CLI_DRY_RUN = 'Dry run; do not actually perform operations against vCO'.freeze
33
+
34
+ # verbose
35
+ DESC_CLI_VERBOSE = 'Show extra information'.freeze
36
+
37
+ # name
38
+ DESC_CLI_NAME = 'Name of the workflow to execute'.freeze
39
+
40
+ # server
41
+ DESC_CLI_SERVER = 'VMware vCenter Orchestrator server URL'.freeze
42
+
43
+ # username
44
+ DESC_CLI_USERNAME = 'vCO user name'.freeze
45
+
46
+ # password
47
+ DESC_CLI_PASSWORD = 'vCO password'.freeze
48
+
49
+ # verify certificates
50
+ DESC_CLI_VERIFY_SSL = 'Perform TSL Certificate verification'.freeze
51
+
52
+ # watch execution
53
+ DESC_CLI_EXECUTE_WATCH = 'Wait around for workflow results'.freeze
54
+
55
+ # execution parameter list
56
+ DESC_CLI_EXECUTE_PARAMETERS = 'Comma-separated list of key=value parameters for workflow'.freeze
57
+
58
+ # query exeuction list
59
+ DESC_CLI_QUERY_EXECS = 'Fetch a list of executions for the workflow'.freeze
60
+
61
+ # limit queried execution list size
62
+ DESC_CLI_QUERY_EXEC_LIM = 'Limit the number of returned executions to the most recent N'.freeze
63
+
64
+ # exeuction id
65
+ DESC_CLI_QUERY_EXEC_ID = 'Fetch the execution data for this execution GUID'.freeze
66
+
67
+ # execution state
68
+ DESC_CLI_QUERY_EXEC_STATE = 'Fetch the state of the specified workflow execution'.freeze
69
+
70
+ # execution log
71
+ DESC_CLI_QUERY_EXEC_LOG = 'In addition to execution data, show the execution log'.freeze
72
+
73
+ # show JSON
74
+ DESC_CLI_QUERY_JSON = 'Show the JSON document for the requested information'.freeze
75
+
76
+ # What do all the vCO REST URIs start with?
77
+ API_URL_BASE = '/vco/api'.freeze
78
+
79
+ # error messages
80
+ ERR = {
81
+ wtf: 'vcoworkflows: I have no idea what just went wrong.',
82
+ no_workflow_found: 'vcoworkflows: no workflow found!',
83
+ too_many_workflows: 'vcoworkflows: more than one workflow found for given name!',
84
+ wrong_workflow_wtf: 'vcoworkflows: search returned the wrong workflow! (?)',
85
+ no_workflow_service_defined: 'vcoworkflows: Attempted to execute a workflow with a nil workflow service!',
86
+ param_verify_failed: 'vcoworkflows: Attempt to verify required parameter failed!',
87
+ no_such_parameter: 'Attempted to set a parameter that does not exist!',
88
+ url_unset: 'No URL was configured, nothing to connect to!',
89
+ username_unset: 'No username was specified, either by $VCO_USER or --username',
90
+ password_unset: 'No password was specified, either by $VCO_PASSWD or --password'
91
+ }.freeze
92
+
93
+ # rubocop:enable LineLength
94
+ end