vcoworkflows-ruby2 0.2.3

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