paknife 0.0.6

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bca870d53bfd6d690e0e82382be3cbc60829adc8
4
+ data.tar.gz: f8d3ac0dfe5d9c3cf50fc82f99e2b0a67f655d2a
5
+ SHA512:
6
+ metadata.gz: bca71ede71f52a8834b84af345566e3c6b25556c8a625eba1a81b03f652f13170b277ce599b000a3e264409d67e949f22e4a813e204a028dfd78ca90c8436641
7
+ data.tar.gz: e31008fbfd8a20d8539767642f96ecffc9b5fdf612a317b50b2be99068fd85e7a8f560da1aa1ab041c0437d6cb5026ba61eda8ad036dcd09d4e67f268b90dfa9
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /sample/.vagrant
11
+ /sample/Gemfile.lock
12
+ *.bundle
13
+ *.so
14
+ *.o
15
+ *.a
16
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in paknife.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Masato Ikeda
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ # Paknife
2
+
3
+ Run knife-solo in parallel.
4
+
5
+ $ paknife [<options>] <backend> <subcommand> <nodes> [<knife_options>]
6
+
7
+ ## Requirements
8
+
9
+ - Ruby >= 2.1
10
+ - [knife-solo](http://rubygems.org/gems/knife-solo) (or [knife-zero](http://rubygems.org/gems/knife-zero))
11
+
12
+ ## Installation
13
+
14
+ ```ruby
15
+ gem 'paknife'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install paknife
25
+
26
+ ## Usage
27
+
28
+ You can run `knife solo cook` in parallel like:
29
+
30
+ $ paknife solo cook node1 node2 node3 node4
31
+
32
+ By default, it runs `bundle exec knife solo cook node1` and so on in two threads.
33
+
34
+ paknife may work with knife-zero like below, but isn't well tested yet:
35
+
36
+ $ paknife zero cook node1 node2
37
+
38
+ ### Knife's original options
39
+
40
+ You can pass knife-solo's (or knife-zero's) original options after nodes arguments like:
41
+
42
+ $ paknife solo cook node1 node2 -i /path/to/your/pem
43
+
44
+
45
+ ### Number of threads
46
+
47
+ You can specify the number of threads with `--threads VALUE` and `-t VALUE` options like:
48
+
49
+ $ paknife --threads 4 solo cook node1 node2 node3 node4
50
+
51
+ or
52
+
53
+ $ paknife --threads max solo cook node1 node2 nod3 node4
54
+
55
+ where `max` means "the number of nodes".
56
+
57
+ This feature is also available with `PARAKNIFE_THREADS` environment variable like:
58
+
59
+ $ export PARAKNIFE_THREADS=max
60
+ $ paknife solo cook node1 node2 node3 node4
61
+
62
+ ### Knife command
63
+
64
+ You can specify knife command with `--knife VALUE` and `-k VALUE` options like:
65
+
66
+ $ paknife --knife="/path/to/your/knife" solo cook node1 node2
67
+
68
+ This feature is also available with `PARAKNIFE_KNIFE` environment variable like:
69
+
70
+ $ export PARAKNIFE_KNIFE=/path/to/your/knife
71
+ $ paknife solo cook node1 node2
72
+
73
+ ## Contributing
74
+
75
+ 1. Fork it ( https://github.com/a2ikm/paknife/fork )
76
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
77
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
78
+ 4. Push to the branch (`git push origin my-new-feature`)
79
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "paknife"
4
+
5
+ Paknife::Cli.run(ARGV)
@@ -0,0 +1,32 @@
1
+ #compdef paknife
2
+
3
+ _knife() {
4
+ local curcontext="$curcontext" state line
5
+ typeset -A opt_args
6
+ _arguments \
7
+ '(-k --knife)'{-k,--knife=}':knife: '\
8
+ '(-q --quiet)'{-q,--quiet}''\
9
+ '(-t --threads)'{-t,--threads=}':threads: '\
10
+ '(-h --help)'{-h,--help}''\
11
+ '(-v --version)'{-v,--version}''\
12
+ '1: :->backend'\
13
+ '2: :->subcommand'\
14
+ '(-)*:nodes:->nodes'
15
+
16
+ case $state in
17
+ backend)
18
+ compadd -Q "$@" solo zero
19
+ ;;
20
+ subcommand)
21
+ compadd -Q "$@" bootstrap clean cook prepare
22
+ ;;
23
+ nodes)
24
+ for node_file in $(ls -1 nodes/* | egrep "\.(rb|json)\$"); do
25
+ compadd "$@" $(basename $node_file | sed 's/.json$//' | sed 's/.rb$//')
26
+ done
27
+ ;;
28
+ *)
29
+ esac
30
+ }
31
+
32
+ _knife "$@"
@@ -0,0 +1,5 @@
1
+ require "paknife/version"
2
+ require "paknife/cli"
3
+
4
+ module Paknife
5
+ end
@@ -0,0 +1,146 @@
1
+ require "optparse"
2
+ require "parallel"
3
+ require "paknife/context"
4
+
5
+ module Paknife
6
+ class Cli
7
+ BACKENDS = %w(solo zero)
8
+ SUBCOMMANDS = %w(bootstrap clean cook prepare)
9
+
10
+ DEFAULT_KNIFE = "bundle exec knife"
11
+ DEFAULT_THREADS = 2
12
+
13
+ DEFAULT_OPTIONS = {
14
+ knife: nil,
15
+ quiet: false,
16
+ threads: nil,
17
+ }
18
+
19
+ def self.run(argv)
20
+ new(argv).run
21
+ end
22
+
23
+ attr_reader :contexts
24
+
25
+ def initialize(argv)
26
+ @options, backend, subcommand, nodes, knife_options = parse_argv(argv)
27
+ @contexts = build_contexts(backend, subcommand, nodes, knife_options)
28
+ end
29
+
30
+ def run
31
+ Parallel.each(contexts, in_threads: determine_threads) do |context|
32
+ context.run
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def parse_argv(argv)
39
+ [parse_options(argv), *parse_knife_argv(argv)]
40
+ end
41
+
42
+ def parse_options(argv)
43
+ opts = {}
44
+
45
+ OptionParser.new do |op|
46
+ op.banner = <<-USAGE
47
+ Usage:
48
+ #{op.program_name} [<options>] <backend> <subcommand> <nodes> [<knife_options>]
49
+
50
+ Backend:
51
+ solo : run knife-solo
52
+ zero : run knffe-zero (Not well tested)
53
+
54
+ Options:
55
+ USAGE
56
+ op.version = VERSION
57
+
58
+ op.on("-k", "--knife VALUE") do |v|
59
+ opts[:knife] = v
60
+ end
61
+
62
+ op.on("-q", "--[no-]quiet") do |v|
63
+ opts[:quiet] = v
64
+ end
65
+
66
+ op.on("-t", "--threads VALUE") do |v|
67
+ if v == "max"
68
+ opts[:threads] = :max
69
+ elsif v.to_i > 0
70
+ opts[:threads] = v.to_i
71
+ else
72
+ abort "Invalid value for `--thread` option: #{v}"
73
+ end
74
+ end
75
+
76
+ op.on_tail("-h", "--help") do
77
+ puts op.help
78
+ exit
79
+ end
80
+
81
+ op.on_tail("-v", "--version") do
82
+ puts "#{op.program_name} #{op.version}"
83
+ exit
84
+ end
85
+ end.order!
86
+
87
+ DEFAULT_OPTIONS.merge(opts)
88
+ end
89
+
90
+ def parse_knife_argv(argv)
91
+ backend = argv.shift # solo or zero
92
+ abort "Invalid backend: `#{backend}`" unless BACKENDS.include?(backend)
93
+
94
+ subcommand = argv.shift
95
+ abort "Invalid subcommand: `#{subcommand}`" unless SUBCOMMANDS.include?(subcommand)
96
+
97
+ nodes = []
98
+ knife_options = []
99
+ knife_options_section = false
100
+
101
+ argv.each do |arg|
102
+ knife_options_section ||= arg.start_with?("-")
103
+ if knife_options_section
104
+ knife_options << arg
105
+ else
106
+ nodes << arg
107
+ end
108
+ end
109
+
110
+ [backend, subcommand, nodes, knife_options]
111
+ end
112
+
113
+ def build_contexts(backend, subcommand, nodes, knife_options)
114
+ opts = {
115
+ log_level: determine_log_level,
116
+ knife: determine_knife,
117
+ }
118
+
119
+ nodes.map.with_index do |node, index|
120
+ Context.new(index, backend, subcommand, node, knife_options, opts)
121
+ end
122
+ end
123
+
124
+ def determine_knife
125
+ @options[:knife] || ENV["PARAKNIFE_KNIFE"] || DEFAULT_KNIFE
126
+ end
127
+
128
+ def determine_threads
129
+ threads = @options[:threads] || ENV["PARAKNIFE_THREADS"] || DEFAULT_THREADS
130
+
131
+ if threads.to_s.downcase == "max"
132
+ @contexts.count
133
+ else
134
+ [@contexts.count, threads.to_i].min
135
+ end
136
+ end
137
+
138
+ def determine_log_level
139
+ if @options[:quiet]
140
+ :warn
141
+ else
142
+ :info
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,73 @@
1
+ require "logger"
2
+ require "open3"
3
+ require "term/ansicolor"
4
+
5
+ module Paknife
6
+ class Context
7
+ attr_reader :logger, :index, :backend, :subcommand, :node, :knife_options
8
+
9
+ def initialize(index, backend, subcommand, node, knife_options, options = {})
10
+ @index = index
11
+ @backend = backend
12
+ @subcommand = subcommand
13
+ @node = node
14
+ @knife_options = knife_options
15
+ @options = options
16
+
17
+ setup_logger
18
+ end
19
+
20
+ def run
21
+ logger.info command
22
+ Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
23
+ stdin.close_write
24
+
25
+ begin
26
+ loop do
27
+ IO.select([stdout, stderr]).flatten.compact.each do |io|
28
+ io.each do |line|
29
+ next if line.nil? || line.empty?
30
+
31
+ if io == stdout
32
+ logger.info line
33
+ elsif io == stderr
34
+ logger.warn line
35
+ end
36
+ end
37
+ end
38
+ break if stdout.eof? && stderr.eof?
39
+ end
40
+ rescue EOFError
41
+ end
42
+ end
43
+ end
44
+
45
+ def command
46
+ [
47
+ @options[:knife],
48
+ backend,
49
+ subcommand,
50
+ node,
51
+ knife_options,
52
+ ].flatten.compact.join(" ")
53
+ end
54
+
55
+ private
56
+
57
+ COLOR_CODES = (1..15).to_a
58
+
59
+ def setup_logger
60
+ color = COLOR_CODES[index % COLOR_CODES.length]
61
+ colored_node = Term::ANSIColor.color(color, node)
62
+
63
+ @logger = Logger.new(STDOUT)
64
+ @logger.formatter = proc { |severity, datetime, progname, msg| "[#{colored_node}] #{msg.chomp}\n" }
65
+ @logger.level =
66
+ if @options[:log_level]
67
+ Logger.const_get(@options[:log_level].upcase)
68
+ else
69
+ Logger::INFO
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module Paknife
2
+ VERSION = "0.0.6"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'paknife/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "paknife"
8
+ spec.version = Paknife::VERSION
9
+ spec.authors = ["Masato Ikeda"]
10
+ spec.email = ["masato.ikeda@gmail.com"]
11
+ spec.summary = %q{Run knife-solo in parallel}
12
+ spec.description = %q{Run knife-solo in parallel}
13
+ spec.homepage = "https://github.com/a2ikm/paknife"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "parallel", "~> 1.3"
22
+ spec.add_dependency "term-ansicolor", "~> 1.3"
23
+ spec.add_development_dependency "bundler", "~> 1.7"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ end
@@ -0,0 +1,8 @@
1
+ cookbook_path ["cookbooks", "site-cookbooks"]
2
+ node_path "nodes"
3
+ role_path "roles"
4
+ environment_path "environments"
5
+ data_bag_path "data_bags"
6
+ #encrypted_data_bag_secret "data_bag_key"
7
+
8
+ knife[:berkshelf_path] = "cookbooks"
@@ -0,0 +1 @@
1
+ PATH=./bin:$PATH
@@ -0,0 +1 @@
1
+ /cookbooks/
@@ -0,0 +1 @@
1
+ site :opscode
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "chef"
4
+ gem "berkshelf"
5
+ gem "knife-solo"
6
+
7
+ gem "paknife", path: ".."
@@ -0,0 +1,17 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ VAGRANTFILE_API_VERSION = "2"
5
+
6
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
7
+ config.vm.box = "paknife-centos-6.6"
8
+ config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.6_chef-provisionerless.box"
9
+
10
+ config.vm.define "s1" do |s1|
11
+ s1.vm.network "private_network", ip: "192.168.33.55"
12
+ end
13
+
14
+ config.vm.define "s2" do |s2|
15
+ s2.vm.network "private_network", ip: "192.168.33.56"
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'chef-apply' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('chef', 'chef-apply')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'chef-client' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('chef', 'chef-client')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'chef-service-manager' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('chef', 'chef-service-manager')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'chef-shell' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('chef', 'chef-shell')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'chef-solo' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('chef', 'chef-solo')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'knife' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('chef', 'knife')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'paknife' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('paknife', 'paknife')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'shef' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('chef', 'shef')
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+
3
+ prefix=${1:-paknife}
4
+
5
+ vagrant ssh-config s1 --host ${prefix}-s1
6
+ vagrant ssh-config s2 --host ${prefix}-s2
File without changes
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "paknife-s1",
3
+ "runlist": [
4
+ ]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "paknife-s1",
3
+ "runlist": [
4
+ ]
5
+ }
File without changes
File without changes
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paknife
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Masato Ikeda
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: parallel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: term-ansicolor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ description: Run knife-solo in parallel
70
+ email:
71
+ - masato.ikeda@gmail.com
72
+ executables:
73
+ - paknife
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/paknife
83
+ - completions/paknife.zsh
84
+ - lib/paknife.rb
85
+ - lib/paknife/cli.rb
86
+ - lib/paknife/context.rb
87
+ - lib/paknife/version.rb
88
+ - paknife.gemspec
89
+ - sample/.chef/knife.rb
90
+ - sample/.envrc
91
+ - sample/.gitignore
92
+ - sample/Berksfile
93
+ - sample/Gemfile
94
+ - sample/Vagrantfile
95
+ - sample/bin/chef-apply
96
+ - sample/bin/chef-client
97
+ - sample/bin/chef-service-manager
98
+ - sample/bin/chef-shell
99
+ - sample/bin/chef-solo
100
+ - sample/bin/knife
101
+ - sample/bin/paraknife
102
+ - sample/bin/shef
103
+ - sample/bin/ssh-config
104
+ - sample/data_bags/.gitkeep
105
+ - sample/environments/.gitkeep
106
+ - sample/nodes/.gitkeep
107
+ - sample/nodes/paknife-s1.json
108
+ - sample/nodes/paknife-s2.json
109
+ - sample/roles/.gitkeep
110
+ - sample/site-cookbooks/.gitkeep
111
+ homepage: https://github.com/a2ikm/paknife
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.2.2
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Run knife-solo in parallel
135
+ test_files: []
136
+ has_rdoc: