Skip to content
This repository has been archived by the owner on Jan 4, 2021. It is now read-only.

Commit

Permalink
Merge pull request #346 from ripienaar/345
Browse files Browse the repository at this point in the history
(#345) Add bolt support
  • Loading branch information
ripienaar authored Oct 11, 2017
2 parents f043b16 + a33c6c5 commit ac5e603
Show file tree
Hide file tree
Showing 9 changed files with 377 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ AllCops:
Exclude:
- "module/**/*"
- "vendor/**/*"
- "spec/fixtures/**/*"

# restore pre 0.45 behaviour
Style/SingleLineBlockParams:
Expand Down Expand Up @@ -78,7 +79,7 @@ Style/EachWithObject:
Style/GuardClause:
Enabled: false

Style/PredicateName:
Naming/PredicateName:
Enabled: false

Style/DoubleNegation:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
|Date |Issue |Description |
|----------|------|---------------------------------------------------------------------------------------------------------|
|2017/10/10|345 |Support Bolt |
|2017/09/22|341 |Remove the Puppet Application Orchestrator |
|2017/09/21| |Release 0.2.0 |
|2017/09/21|339 |Promote the `mcollective_assert` `pre_sleep` property to one that applies to all task types |
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ source "https://rubygems.org"
gem "nats-pure", "~> 0.2"

group :development, :test do
gem "bolt", "~> 0.5"
gem "coveralls"
gem "diplomat", "~> 1"
gem "etcdv3", "~> 0.6.0"
Expand Down
55 changes: 55 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (2.3.5)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
ast (2.3.0)
bolt (0.5.0)
CFPropertyList (~> 2.2)
concurrent-ruby (~> 1.0)
gettext-setup (>= 0.10, < 1)
locale (~> 2.1)
minitar (~> 0.6.1)
net-sftp (~> 2.0)
net-ssh (~> 4.0)
orchestrator_client (~> 0.2.1)
win32-dir (= 0.4.9)
win32-process (= 0.7.5)
win32-security (= 0.2.5)
win32-service (= 0.8.8)
winrm (~> 2.0)
winrm-fs (~> 1.0)
builder (3.2.3)
coderay (1.1.2)
concurrent-ruby (1.0.5)
coveralls (0.8.21)
json (>= 1.8, < 3)
simplecov (~> 0.14.1)
Expand All @@ -18,6 +36,7 @@ GEM
faraday (~> 0.9)
json
docile (1.1.5)
erubis (2.7.0)
etcdv3 (0.6.0)
faraday (= 0.11.0)
grpc (= 1.2.5)
Expand Down Expand Up @@ -46,6 +65,8 @@ GEM
grpc (1.2.5)
google-protobuf (~> 3.1)
googleauth (~> 0.5.1)
gssapi (1.2.0)
ffi (>= 1.0.1)
guard (2.14.1)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
Expand All @@ -63,8 +84,11 @@ GEM
guard-shell (0.7.1)
guard (>= 2.0.0)
guard-compat (~> 1.0)
gyoku (1.3.1)
builder (>= 2.1.2)
hashdiff (0.3.6)
hiera (3.4.1)
httpclient (2.8.3)
jgrep (1.5.0)
json (2.1.0)
json-schema (2.8.0)
Expand All @@ -90,15 +114,21 @@ GEM
memoist (0.16.0)
metaclass (0.0.4)
method_source (0.8.2)
minitar (0.6.1)
mocha (1.3.0)
metaclass (~> 0.0.1)
multi_json (1.12.2)
multipart-post (2.0.0)
nats-pure (0.2.4)
nenv (0.3.0)
net-sftp (2.1.2)
net-ssh (>= 2.6.5)
net-ssh (4.2.0)
nori (2.6.0)
notiffany (0.1.1)
nenv (~> 0.1)
shellany (~> 0.0)
orchestrator_client (0.2.2)
os (0.9.6)
parallel (1.12.0)
parser (2.4.0.0)
Expand Down Expand Up @@ -142,6 +172,8 @@ GEM
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.3)
ruby_dep (1.5.0)
rubyntlm (0.6.2)
rubyzip (1.2.1)
safe_yaml (1.0.4)
semantic_puppet (1.0.1)
gettext-setup (>= 0.3)
Expand Down Expand Up @@ -169,12 +201,35 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
win32-dir (0.4.9)
ffi (>= 1.0.0)
win32-process (0.7.5)
ffi (>= 1.0.0)
win32-security (0.2.5)
ffi
win32-service (0.8.8)
ffi
winrm (2.2.3)
builder (>= 2.1.2)
erubis (~> 2.7)
gssapi (~> 1.2)
gyoku (~> 1.0)
httpclient (~> 2.2, >= 2.2.0.2)
logging (>= 1.6.1, < 3.0)
nori (~> 2.0)
rubyntlm (~> 0.6.0, >= 0.6.1)
winrm-fs (1.0.2)
erubis (~> 2.7)
logging (>= 1.6.1, < 3.0)
rubyzip (~> 1.1)
winrm (~> 2.0)
yard (0.9.9)

PLATFORMS
ruby

DEPENDENCIES
bolt (~> 0.5)
coveralls
diplomat (~> 1)
etcdv3 (~> 0.6.0)
Expand Down
1 change: 1 addition & 0 deletions lib/mcollective/util/playbook/tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require_relative "tasks/shell_task"
require_relative "tasks/slack_task"
require_relative "tasks/webhook_task"
require_relative "tasks/bolt_task"

module MCollective
module Util
Expand Down
168 changes: 168 additions & 0 deletions lib/mcollective/util/playbook/tasks/bolt_task.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
module MCollective
module Util
class Playbook
class Tasks
class BoltTask < Base
def validate_configuration!
raise("Bolt requires one of task, plan or command") unless @task || @plan || @command
raise("A path to Bolt modules is required") if !@command && !@modules
raise("Bolt requires at least 1 node") if @nodes.empty?
raise("Transports can only be winrm or ssh") unless ["winrm", "ssh"].include?(@transport)

if @task || @plan
@modules = File.expand_path(@modules)
raise("The Bolt module path %s is not a directory" % @modules) unless File.directory?(@modules)
end

require_bolt
end

# Requires Bolt
#
# Done last since things are pretty hairy with this vendored puppet
# I am sure there's issues with this, till Bolt ships built into puppet-agent
# I doubt this will work particularly well.
#
# For sure I expect plan execution to not be possible
def require_bolt
# shuts up constant recreation warnings, can be removed when shipped in puppet-agent
$VERBOSE = nil

require "puppet"
require "puppet/info_service"
require "bolt"
require "bolt/cli"
end

def from_hash(data)
@task = data["task"]
@plan = data["plan"]
@command = data["command"]
@user = data.fetch("user", ENV["USER"])
@password = data["password"]
@modules = data["modules"]
@tty = data.fetch("tty", false)
@parameters = data["parameters"]
@nodes = data.fetch("nodes", [])
@transport = data.fetch("transport", "ssh")
end

def nodes
@nodes.map do |node|
uri = node
uri = "%s://%s" % [@transport, node] unless @transport == "ssh" || uri =~ /^(winrm|ssh):\/\/(.+)/

Bolt::Node.from_uri(uri, @user, @password, :tty => @tty)
end
end

def bolt_options
options = {
:nodes => nodes,
:modules => @modules,
:tty => @tty
}

options[:user] = @user if @user
options[:password] = @password if @password

options
end

def bolt_cli
return @__cli if @__cli

# We would rather pass a configured logger into bolt, see
# https://github.com/puppetlabs/bolt/issues/79
case @playbook.loglevel
when "fatal"
Bolt.log_level = ::Logger::FATAL
when "error"
Bolt.log_level = ::Logger::ERROR
when "warn"
Bolt.log_level = ::Logger::WARN
when "debug"
Bolt.log_level = ::Logger::DEBUG
else
Bolt.log_level = ::Logger::INFO
end

@__cli = Bolt::CLI.new({})
end

def bolt_executor
@__executor ||= Bolt::Executor.new(nodes)
end

def run_command
bolt_executor.run_command(@command)
end

def run_task
path = @task
input_method = nil

unless File.exist?(path)
path, metadata = bolt_cli.load_task_data(path, @modules)
input_method = metadata["input_method"]
end

input_method ||= "both"

bolt_executor.run_task(path, input_method, @parameters)
end

def log_results(results, elapsed)
pass = []
failed = []

results.each_pair do |node, result|
if result.success?
Log.info("Success on node %s: %s" % [node.host, result.message.chomp])
pass << result
else
Log.error("Failure on node %s: %s" % [node.host, result.message.chomp])
failed << result
end
end

if failed.empty?
[true, "Successful Bolt run on %d nodes in %d seconds" % [@nodes.size, elapsed], results]
else
[false, "Failed Bolt run on %d / %d nodes in %d seconds" % [failed.size, @nodes.size, elapsed], results]
end
end

def current_time
Time.now
end

def run
results = []
start = current_time

begin
if @task
results = run_task
elsif @command
results = run_command
elsif @plan
raise("Executing Bolt plans is not currently supported")
else
raise("Did not receive a task, command or plan to execute")
end

log_results(results, Integer(Time.now - start))
rescue
msg = "Could not create Bolt action: %s: %s" % [$!.class, $!.to_s]
Log.debug(msg)
Log.debug($!.backtrace.join("\t\n"))

[false, msg, {}]
end
end
end
end
end
end
end
13 changes: 13 additions & 0 deletions spec/fixtures/bolt/tasks/mymod/tasks/sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"description": "Retrieve a value from a hash",
"params": {
"data": {
"description": "The Hash to get data from.",
"type": "Hash"
},
"key": {
"description": "The key to lookup.",
"type": "String"
}
}
}
7 changes: 7 additions & 0 deletions spec/fixtures/bolt/tasks/mymod/tasks/sample.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/opt/puppetlabs/puppet/bin/ruby

require "json"

params = JSON.parse(STDIN.read)

puts({"value" => params["data"], "key" => params["key"]}).to_json
Loading

0 comments on commit ac5e603

Please sign in to comment.