vcoworkflows 0.1.1

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: [:spec, :style, :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,45 @@
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
+ input_parameters.each { |k, v| workflow.set_parameter(k, v) }
29
+
30
+ # Execute the workflow.
31
+ workflow.execute
32
+
33
+ # We're going to wait around until the execution is done, so we'll check
34
+ # on it every 5 seconds until we see whether it completed or failed.
35
+ finished = false
36
+ until finished
37
+ sleep 5
38
+ # Fetch a new workflow token to check the status of the workflow execution
39
+ wftoken = workflow.token
40
+ # If the execution is no longer alive, exit the loop and report the results.
41
+ unless wftoken.alive?
42
+ finished = true
43
+ wftoken.output_parameters.each { |k, v| puts " #{k}: #{v}" }
44
+ end
45
+ end
@@ -0,0 +1,34 @@
1
+ require 'thor'
2
+
3
+ require File.dirname(__FILE__) + '/vcoworkflows/version'
4
+ require File.dirname(__FILE__) + '/vcoworkflows/constants'
5
+ require File.dirname(__FILE__) + '/vcoworkflows/vcosession'
6
+ require File.dirname(__FILE__) + '/vcoworkflows/workflowservice'
7
+ require File.dirname(__FILE__) + '/vcoworkflows/workflow'
8
+ require File.dirname(__FILE__) + '/vcoworkflows/workflowparameter'
9
+ require File.dirname(__FILE__) + '/vcoworkflows/workflowtoken'
10
+ require File.dirname(__FILE__) + '/vcoworkflows/cli/execute'
11
+ require File.dirname(__FILE__) + '/vcoworkflows/cli/query'
12
+
13
+ # rubocop:disable LineLength
14
+
15
+ # Refer to README.md for use instructions
16
+ module VcoWorkflows
17
+ # Start of main CLI processing
18
+ class CLI < Thor
19
+ package_name 'vcoworkflows'
20
+ map '--version' => :version
21
+ map '-v' => :version
22
+
23
+ desc 'version', DESC_VERSION
24
+
25
+ # Display the version of `vcoworkflows`
26
+ def version
27
+ puts VERSION
28
+ end
29
+
30
+ register(VcoWorkflows::Cli::Execute, 'execute', 'execute <WORKFLOW>', DESC_CLI_EXECUTE)
31
+ register(VcoWorkflows::Cli::Query, 'query', 'query <WORKFLOW>', DESC_CLI_QUERY)
32
+ end
33
+ end
34
+ # rubocop:enable LineLength
@@ -0,0 +1,27 @@
1
+ require 'vcoworkflows/constants'
2
+
3
+ # VcoWorkflows
4
+ module VcoWorkflows
5
+ # Cli
6
+ module Cli
7
+ # Auth
8
+ class Auth
9
+ attr_reader :username
10
+ attr_reader :password
11
+
12
+ # Initialize the Auth object
13
+ # @param [String] username
14
+ # @param [String] password
15
+ def initialize(username: nil, password: nil)
16
+ # Set username and password from parameters, if provided, or
17
+ # environment variables $VCO_USER and $VCO_PASSWD, if not.
18
+ @username = username.nil? ? ENV['VCO_USER'] : username
19
+ @password = password.nil? ? ENV['VCO_PASSWD'] : password
20
+
21
+ # Fail if we don't have both a username and a password.
22
+ fail(IOError, ERR[:username_unset]) if @username.nil?
23
+ fail(IOError, ERR[:password_unset]) if @password.nil?
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,109 @@
1
+ require 'vcoworkflows'
2
+ require_relative 'auth'
3
+ require 'thor/group'
4
+
5
+ # rubocop:disable MethodLength, LineLength
6
+
7
+ # VcoWorkflows
8
+ module VcoWorkflows
9
+ # Cli
10
+ module Cli
11
+ # Execute
12
+ class Execute < Thor::Group
13
+ include Thor::Actions
14
+
15
+ argument :workflow, type: :string, desc: DESC_CLI_WORKFLOW
16
+ class_option :server, type: :string, aliases: '-s', required: true, desc: DESC_CLI_SERVER
17
+ class_option :username, type: :string, aliases: '-u', desc: DESC_CLI_USERNAME
18
+ class_option :password, type: :string, aliases: '-p', desc: DESC_CLI_PASSWORD
19
+ class_option :id, type: :string, aliases: '-i', desc: DESC_CLI_WORKFLOW_ID
20
+ class_option :verify_ssl, type: :boolean, default: true, desc: DESC_CLI_VERIFY_SSL
21
+ class_option :dry_run, type: :boolean, default: false, desc: DESC_CLI_DRY_RUN
22
+ class_option :verbose, type: :boolean, default: true, desc: DESC_CLI_VERBOSE
23
+ class_option :watch, type: :boolean, default: true, desc: DESC_CLI_EXECUTE_WATCH
24
+
25
+ class_option :parameters, type: :string, required: true, desc: DESC_CLI_EXECUTE_PARAMETERS
26
+
27
+ def self.source_root
28
+ File.dirname(__FILE__)
29
+ end
30
+
31
+ # rubocop:disable CyclomaticComplexity, PerceivedComplexity
32
+ def execute
33
+ auth = VcoWorkflows::Cli::Auth.new(username: options[:username], password: options[:password])
34
+
35
+ # Parse out the parameters
36
+ parameters = {}
37
+ options[:parameters].split(/,/).each do |p|
38
+ k, v = p.split(/=/)
39
+ parameters[k] = v
40
+ end
41
+ if parameters.key?('runlist')
42
+ parameters['runlist'] = parameters['runlist'].split(/:/)
43
+ end
44
+
45
+ puts "Executing against vCO REST endpoint: #{options[:server]}"
46
+ puts "Requested execution of workflow: '#{workflow}'"
47
+ puts "Will call workflow by GUID (#{options[:id]})" if options[:id]
48
+ if options[:verbose] || options[:dry_run]
49
+ puts 'Parameters:'
50
+ parameters.each do |k, v|
51
+ v = v.join(',') if v.is_a?(Array)
52
+ puts " - #{k}: #{v}"
53
+ end
54
+ puts ''
55
+ end
56
+
57
+ return if options[:dry_run]
58
+
59
+ # Get the workflow
60
+ puts "Retrieving workflow '#{workflow}' ..."
61
+ wf = VcoWorkflows::Workflow.new(workflow,
62
+ url: options[:server],
63
+ username: auth.username,
64
+ password: auth.password,
65
+ verify_ssl: options[:verify_ssl],
66
+ id: options[:id])
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_relative 'auth'
3
+ require 'thor/group'
4
+
5
+ # rubocop:disable MethodLength, LineLength
6
+
7
+ # VcoWorkflows
8
+ module VcoWorkflows
9
+ # Cli
10
+ module Cli
11
+ # Query
12
+ class Query < Thor::Group
13
+ include Thor::Actions
14
+
15
+ argument :workflow, type: :string, desc: DESC_CLI_WORKFLOW
16
+ class_option :server, type: :string, aliases: '-s', required: true, desc: DESC_CLI_SERVER
17
+ class_option :username, type: :string, aliases: '-u', desc: DESC_CLI_USERNAME
18
+ class_option :password, type: :string, aliases: '-p', desc: DESC_CLI_PASSWORD
19
+ class_option :id, type: :string, aliases: '-i', desc: DESC_CLI_WORKFLOW_ID
20
+ class_option :verify_ssl, type: :boolean, default: true, desc: DESC_CLI_VERIFY_SSL
21
+ class_option :dry_run, type: :boolean, default: false, desc: DESC_CLI_DRY_RUN
22
+
23
+ class_option :executions, type: :boolean, aliases: '-e', default: false, desc: DESC_CLI_QUERY_EXECS
24
+ class_option :last, type: :numeric, aliases: '-l', default: 0, desc: DESC_CLI_QUERY_EXEC_LIM
25
+ class_option :execution_id, type: :string, aliases: ['-I', '--execution'], desc: DESC_CLI_QUERY_EXEC_ID
26
+ class_option :state, type: :boolean, aliases: '-r', desc: DESC_CLI_QUERY_EXEC_STATE
27
+ class_option :logs, type: :boolean, aliases: ['-L', '--log'], desc: DESC_CLI_QUERY_EXEC_LOG
28
+ class_option :show_json, type: :boolean, default: false, desc: DESC_CLI_QUERY_JSON
29
+
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
+ auth = VcoWorkflows::Cli::Auth.new(username: options[:username], password: options[:password])
38
+
39
+ if options[:dry_run]
40
+ puts "\nQuerying against vCO REST endpoint:\n #{options[:server]}"
41
+ puts "Will search for workflow: '#{workflow}'"
42
+ puts "Will query workflow by GUID (#{options[:id]})" if options[:id]
43
+ return
44
+ end
45
+
46
+ # Get the workflow
47
+ puts "\nRetrieving workflow '#{workflow}' ..."
48
+ wf = VcoWorkflows::Workflow.new(workflow,
49
+ url: options[:server],
50
+ username: auth.username,
51
+ password: auth.password,
52
+ verify_ssl: options[:verify_ssl],
53
+ id: options[:id])
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}"
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,44 @@
1
+ # VcoWorkflows
2
+ module VcoWorkflows
3
+ # rubocop:disable LineLength
4
+
5
+ # Options description messages
6
+ DESC_VERSION = 'Display the installed version of the VcoWorkflows gem'
7
+ DESC_CLI_EXECUTE = 'Execute the specified workflow'
8
+ DESC_CLI_QUERY = 'Query vCO for a workflow'
9
+ DESC_CLI_WORKFLOW = 'Name of the workflow'
10
+ DESC_CLI_WORKFLOW_ID = 'GUID of the workflow'
11
+ DESC_CLI_DRY_RUN = 'Dry run; do not actually perform operations against vCO'
12
+ DESC_CLI_VERBOSE = 'Show extra information'
13
+ DESC_CLI_NAME = 'Name of the workflow to execute'
14
+ DESC_CLI_SERVER = 'VMware vCenter Orchestrator server URL'
15
+ DESC_CLI_USERNAME = 'vCO user name'
16
+ DESC_CLI_PASSWORD = 'vCO password'
17
+ DESC_CLI_VERIFY_SSL = 'Perform TSL Certificate verification'
18
+ DESC_CLI_EXECUTE_WATCH = 'Wait around for workflow results'
19
+ DESC_CLI_EXECUTE_PARAMETERS = 'Comma-separated list of key=value parameters for workflow'
20
+ DESC_CLI_QUERY_EXECS = 'Fetch a list of executions for the workflow'
21
+ DESC_CLI_QUERY_EXEC_LIM = 'Limit the number of returned executions to the most recent N'
22
+ DESC_CLI_QUERY_EXEC_ID = 'Fetch the execution data for this execution GUID'
23
+ DESC_CLI_QUERY_EXEC_STATE = 'Fetch the state of the specified workflow execution'
24
+ DESC_CLI_QUERY_EXEC_LOG = 'In addition to execution data, show the execution log'
25
+ DESC_CLI_QUERY_JSON = 'Show the JSON document for the requested information'
26
+
27
+ # What do all the vCO REST URIs start with?
28
+ API_URL_BASE = '/vco/api'
29
+
30
+ # error messages
31
+ ERR = {
32
+ wtf: 'vcoworkflows: I have no idea what just went wrong.',
33
+ no_workflow_found: 'vcoworkflows: no workflow found!',
34
+ too_many_workflows: 'vcoworkflows: more than one workflow found for given name!',
35
+ wrong_workflow_wtf: 'vcoworkflows: search returned the wrong workflow! (?)',
36
+ no_workflow_service_defined: 'vcoworkflows: Attempted to execute a workflow with a nil workflow service!',
37
+ param_verify_failed: 'vcoworkflows: Attempt to verify required parameter failed!',
38
+ no_such_parameter: 'Attempted to set a parameter that does not exist!',
39
+ username_unset: 'No username was specified, either by $VCO_USER or --username',
40
+ password_unset: 'No password was specified, either by $VCO_PASSWD or --password'
41
+ }
42
+
43
+ # rubocop:enable LineLength
44
+ end
@@ -0,0 +1,44 @@
1
+ require 'vcoworkflows'
2
+
3
+ # rubocop:disable all
4
+ module VcoWorkflows
5
+ # wrapper to assist aruba in single process execution
6
+ class Runner
7
+ # Allow everything fun to be injected from the outside while defaulting to normal implementations.
8
+ def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
9
+ @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
10
+ end
11
+
12
+ # Do the things!
13
+ def execute!
14
+ exit_code = begin
15
+ # Thor accesses these streams directly rather than letting them be
16
+ # injected, so we replace them...
17
+ $stderr = @stderr
18
+ $stdin = @stdin
19
+ $stdout = @stdout
20
+
21
+ VcoWorkflows::CLI.start(@argv)
22
+
23
+ # Thor::Base#start does not have a return value, assume success if no
24
+ # exception is raised.
25
+ 0
26
+ rescue StandardError => e
27
+ # The ruby interpreter would pipe this to STDERR and exit 1 in the
28
+ # case of an unhandled exception
29
+ b = e.backtrace
30
+ b.unshift("#{b.shift}: #{e.message} (#{e.class})")
31
+ @stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n"))
32
+ 1
33
+ ensure
34
+ # put them back.
35
+ $stderr = STDERR
36
+ $stdin = STDIN
37
+ $stdout = STDOUT
38
+ end
39
+ # Proxy exit code back to the injected kernel.
40
+ @kernel.exit(exit_code)
41
+ end
42
+ end
43
+ end
44
+ # rubocop:enable all