joyent-provisioner 0.1.0
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/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +5 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +130 -0
- data/Rakefile +1 -0
- data/bin/provisioner +8 -0
- data/conf/configuration.yml.example +16 -0
- data/joyent-provisioner.gemspec +32 -0
- data/lib/joyent-provisioner.rb +12 -0
- data/lib/provisioner/cli.rb +107 -0
- data/lib/provisioner/cli/bootstrap.rb +25 -0
- data/lib/provisioner/cli/provision.rb +25 -0
- data/lib/provisioner/command/base.rb +60 -0
- data/lib/provisioner/command/bootstrap.rb +45 -0
- data/lib/provisioner/command/provision.rb +26 -0
- data/lib/provisioner/configuration.rb +36 -0
- data/lib/provisioner/helper.rb +6 -0
- data/lib/provisioner/helper/exit.rb +9 -0
- data/lib/provisioner/host_ip.rb +25 -0
- data/lib/provisioner/logger.rb +47 -0
- data/lib/provisioner/usage.rb +11 -0
- data/lib/provisioner/version.rb +3 -0
- data/spec/fixtures/test.yml +16 -0
- data/spec/provisioner/cli/bootstrap_spec.rb +12 -0
- data/spec/provisioner/cli/host_spec.rb +32 -0
- data/spec/provisioner/command/bootstrap_spec.rb +44 -0
- data/spec/provisioner/command/provision_spec.rb +63 -0
- data/spec/provisioner/configuration_spec.rb +20 -0
- data/spec/provisioner/host_ip_spec.rb +15 -0
- data/spec/spec_helper.rb +20 -0
- metadata +258 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 TODO: Write your name
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# Joyent Cloud Provisioner
|
2
|
+
|
3
|
+
[](http://travis-ci.org/wanelo/joyent-provisioner)
|
4
|
+
|
5
|
+
This gem provides a ruby class and a command line tool to simplify provisioning of clusters of hosts in the
|
6
|
+
cloud environment, based on rules defined in a convenient yml file. It specifically supports Joyent Cloud,
|
7
|
+
but can be easily extended to support other clouds.
|
8
|
+
|
9
|
+
The idea behind it is that working software is better than any documentation. But defining your templates
|
10
|
+
in the YML file you not only documenting how to build various types of hosts in your infrastructure,
|
11
|
+
you are also then able to use this configuration/documentation to actually provision or bootstrap these hosts
|
12
|
+
with ease.
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'joyent-provisioner'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it into your ruby environment as follows:
|
25
|
+
|
26
|
+
$ gem install joyent-provisioner
|
27
|
+
|
28
|
+
## Configuration
|
29
|
+
|
30
|
+
Provisioner uses a YAML file to define templates of various types of hosts in your application, and
|
31
|
+
link them with a particular type of Joyent flavors, packages and networks. Please see 'knife joyent' for
|
32
|
+
definition of these terms.
|
33
|
+
|
34
|
+
Below YAML file defines a single template 'memcached-sessions' within the 'test' environment. It
|
35
|
+
links the template with a UUID of an appropriate Joyent image, flavor, distribution, and list of
|
36
|
+
networks. It also specifies Chef run_list to configure these hosts, as well as the host sequence
|
37
|
+
which is used to provision many hosts in a cluster.
|
38
|
+
|
39
|
+
Host sequence can be overridden by command line option --number, which can pass a single number, a ruby
|
40
|
+
range, or a ruby array as a string.
|
41
|
+
|
42
|
+
```yaml
|
43
|
+
global:
|
44
|
+
environment: test
|
45
|
+
host_suffix: test
|
46
|
+
log_dir: ./tmp
|
47
|
+
ssh_user: ops
|
48
|
+
|
49
|
+
templates:
|
50
|
+
memcached-sessions:
|
51
|
+
image: 9ec5c0c-a941-11e2-a7dc-57a6b041988f
|
52
|
+
flavor: "g3-highmemory-17.125-smartos"
|
53
|
+
distro: smartos-base64
|
54
|
+
networks: "42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f"
|
55
|
+
run_list: "role[joyent]"
|
56
|
+
host_sequence: 1..2
|
57
|
+
host_prefix: memcached-sessions
|
58
|
+
```
|
59
|
+
|
60
|
+
After provisioning all hosts in the memcached-sessions template, you should end up with two hosts, like so:
|
61
|
+
|
62
|
+
* memcached-sessions001.test
|
63
|
+
* memcached-sessions002.test
|
64
|
+
|
65
|
+
The intention is that each environment, such as production or staging, will have it's own YAML file.
|
66
|
+
|
67
|
+
## Usage
|
68
|
+
|
69
|
+
```bash
|
70
|
+
Usage:
|
71
|
+
[bundle exec] provisioner command ...
|
72
|
+
|
73
|
+
Where the command is one of the following:
|
74
|
+
provision, bootstrap
|
75
|
+
```
|
76
|
+
|
77
|
+
### Provisioning Hosts
|
78
|
+
|
79
|
+
```bash
|
80
|
+
Usage: provisioner provision --config <path-to-config>.yml [options]
|
81
|
+
-c, --config CONFIG_FILE Path to the config file (YML) (required)
|
82
|
+
-g, --debug Log status to STDOUT
|
83
|
+
--dry-run Dry runs and prints all commands without executing them
|
84
|
+
-n, --number NUMBER Ruby range or a number for the host, ie 3 or 1..3 or [2,4,6]
|
85
|
+
-t, --template TEMPLATE Template name (required)
|
86
|
+
-h, --help Show this message
|
87
|
+
```
|
88
|
+
|
89
|
+
To provision a specific host
|
90
|
+
|
91
|
+
```bash
|
92
|
+
provisioner provision -n 3 -t redis-cluster -c production.yml
|
93
|
+
```
|
94
|
+
|
95
|
+
To provision all hosts defined by host_sequence in a template
|
96
|
+
|
97
|
+
```bash
|
98
|
+
provisioner provision -t redis-cluster -c production.yml
|
99
|
+
```
|
100
|
+
|
101
|
+
Only show the commands that should be run without actually running them:
|
102
|
+
|
103
|
+
```bash
|
104
|
+
provisioner provision -t redis-cluster -c production.yml --dry-run
|
105
|
+
```
|
106
|
+
|
107
|
+
### Bootstrapping Hosts
|
108
|
+
|
109
|
+
Bootstrapping hosts skips the provisioning step, and assumes that the host is already provisioned.
|
110
|
+
It runs 'knife joyent server list' in order to determine host's IP address, and then proceeds
|
111
|
+
to bootrap the host when the IP is found.
|
112
|
+
|
113
|
+
```bash
|
114
|
+
Usage: provisioner bootstrap --config <path-to-config>.yml [options]
|
115
|
+
-c, --config CONFIG_FILE Path to the config file (YML) (required)
|
116
|
+
-g, --debug Log status to STDOUT
|
117
|
+
--dry-run Dry runs and prints all commands without executing them
|
118
|
+
-n, --number NUMBER Ruby range or a number for the host, ie 3 or 1..3 or [2,4,6]
|
119
|
+
-t, --template TEMPLATE Template name (required)
|
120
|
+
-h, --help Show this message
|
121
|
+
```
|
122
|
+
|
123
|
+
## Contributing
|
124
|
+
|
125
|
+
1. Fork it
|
126
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
127
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
128
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
129
|
+
5. Create new Pull Request
|
130
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/provisioner
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
global:
|
2
|
+
environment: test
|
3
|
+
host_suffix: test
|
4
|
+
log_dir: ./tmp
|
5
|
+
ssh_user: ops
|
6
|
+
|
7
|
+
templates:
|
8
|
+
memcached-sessions:
|
9
|
+
image: 9ec5c0c-a941-11e2-a7dc-57a6b041988f
|
10
|
+
flavor: "g3-highmemory-17.125-smartos"
|
11
|
+
distro: smartos-base64
|
12
|
+
networks: "42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f"
|
13
|
+
run_list: "role[joyent]"
|
14
|
+
host_sequence: 1..2
|
15
|
+
host_prefix: memcached-sessions
|
16
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'provisioner/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "joyent-provisioner"
|
8
|
+
spec.version = Provisioner::VERSION
|
9
|
+
spec.authors = ["Konstantin Gredeskoul", "Blake Irvin", "Richard Millan"]
|
10
|
+
spec.email = ["kig@wanelo.com", "bixu@wanelo.com", "richard@wanelo.com"]
|
11
|
+
spec.description = %q{Wrapper gem around provisioning clusters of servers on Joyent cloud}
|
12
|
+
spec.summary = %q{Wrapper gem around provisioning clusters of servers on Joyent cloud}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
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 'mixlib-cli'
|
22
|
+
spec.add_dependency 'chef'
|
23
|
+
spec.add_dependency 'knife-joyent'
|
24
|
+
spec.add_dependency 'colorize'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
27
|
+
spec.add_development_dependency 'rake'
|
28
|
+
spec.add_development_dependency 'guard'
|
29
|
+
spec.add_development_dependency 'guard-rspec'
|
30
|
+
spec.add_development_dependency 'rspec'
|
31
|
+
spec.add_development_dependency 'pry-debugger'
|
32
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Provisioner
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'colorize'
|
5
|
+
|
6
|
+
require_relative 'provisioner/usage'
|
7
|
+
require_relative 'provisioner/logger'
|
8
|
+
require_relative 'provisioner/helper'
|
9
|
+
require_relative 'provisioner/configuration'
|
10
|
+
require_relative 'provisioner/host_ip'
|
11
|
+
require_relative 'provisioner/cli'
|
12
|
+
require_relative 'provisioner/command/base'
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'mixlib/cli'
|
2
|
+
|
3
|
+
module Provisioner
|
4
|
+
class CLI
|
5
|
+
include Mixlib::CLI
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :commands
|
9
|
+
|
10
|
+
# Returns a command class by it's name
|
11
|
+
def command name
|
12
|
+
@commands[name]
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns array of registered command names
|
16
|
+
def supported_commands
|
17
|
+
commands.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
def inherited subclass
|
21
|
+
@commands ||= {}
|
22
|
+
@commands[subclass.name.split("::").last.downcase] = subclass
|
23
|
+
|
24
|
+
subclass.instance_eval do
|
25
|
+
option :config_file,
|
26
|
+
short: '-c CONFIG_FILE',
|
27
|
+
long: '--config CONFIG_FILE',
|
28
|
+
description: 'Path to the config file (YML)',
|
29
|
+
required: true
|
30
|
+
|
31
|
+
option :debug,
|
32
|
+
short: '-g',
|
33
|
+
long: '--debug',
|
34
|
+
description: 'Log status to STDOUT',
|
35
|
+
boolean: true,
|
36
|
+
required: false,
|
37
|
+
default: false
|
38
|
+
|
39
|
+
option :template,
|
40
|
+
short: '-t TEMPLATE',
|
41
|
+
long: '--template TEMPLATE',
|
42
|
+
description: 'Template name',
|
43
|
+
required: true
|
44
|
+
|
45
|
+
option :number,
|
46
|
+
short: '-n NUMBER',
|
47
|
+
long: '--number NUMBER',
|
48
|
+
description: 'Ruby range or a number for the host, ie 3 or 1..3 or [2,4,6]',
|
49
|
+
required: false
|
50
|
+
|
51
|
+
option :dry,
|
52
|
+
long: '--dry-run',
|
53
|
+
description: 'Dry runs and prints all commands without executing them',
|
54
|
+
boolean: true,
|
55
|
+
required: false
|
56
|
+
|
57
|
+
option :help,
|
58
|
+
short: '-h',
|
59
|
+
long: '--help',
|
60
|
+
description: 'Show this message',
|
61
|
+
on: :tail,
|
62
|
+
boolean: true,
|
63
|
+
show_options: true,
|
64
|
+
exit: 0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_reader :args
|
70
|
+
|
71
|
+
def run args = ARGV
|
72
|
+
@args = args
|
73
|
+
validate!
|
74
|
+
command_name = args.shift
|
75
|
+
command_class = Provisioner::CLI.command(command_name)
|
76
|
+
Provisioner::Exit.with_message("Command '#{command_name}' not found.") if command_class.nil?
|
77
|
+
command_class.new.run(args)
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
def template_configuration
|
83
|
+
Provisioner::Configuration.from_path(config[:config_file])
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def validate!
|
89
|
+
Provisioner::Exit.with_message('No command given') if args.empty?
|
90
|
+
@command = args.first
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_config argv = []
|
94
|
+
parse_options argv
|
95
|
+
config[:configuration] = Provisioner::Configuration.from_path(config[:config_file])
|
96
|
+
end
|
97
|
+
|
98
|
+
def enable_logger
|
99
|
+
STDOUT.sync = true
|
100
|
+
Provisioner::Logger.enable
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
require 'provisioner/cli/provision'
|
107
|
+
require 'provisioner/cli/bootstrap'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'mixlib/cli'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
class Provisioner::CLI::Bootstrap < Provisioner::CLI
|
5
|
+
|
6
|
+
banner 'Usage: provisioner bootstrap --config <path-to-config>.yml [options] '
|
7
|
+
|
8
|
+
def run(argv = ARGV)
|
9
|
+
parse_options argv
|
10
|
+
enable_logger if config[:debug]
|
11
|
+
|
12
|
+
if config[:dry]
|
13
|
+
provisioner_command.shell_commands.each do |command|
|
14
|
+
puts command.colorize(:green)
|
15
|
+
end
|
16
|
+
else
|
17
|
+
provisioner_command.run
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def provisioner_command
|
22
|
+
Provisioner::Command::Bootstrap.new(template_configuration.for_template(config[:template]), config[:number])
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'mixlib/cli'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
class Provisioner::CLI::Provision < Provisioner::CLI
|
5
|
+
|
6
|
+
banner 'Usage: provisioner provision --config <path-to-config>.yml [options] '
|
7
|
+
|
8
|
+
def run(argv = ARGV)
|
9
|
+
parse_options argv
|
10
|
+
enable_logger if config[:debug]
|
11
|
+
|
12
|
+
if config[:dry]
|
13
|
+
provisioner_command.shell_commands.each do |command|
|
14
|
+
puts command.colorize(:green)
|
15
|
+
end
|
16
|
+
else
|
17
|
+
provisioner_command.run
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def provisioner_command
|
22
|
+
Provisioner::Command::Provision.new(template_configuration.for_template(config[:template]), config[:number])
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Provisioner
|
2
|
+
module Command
|
3
|
+
class Base
|
4
|
+
attr_accessor :image, :flavor, :distro, :networks, :run_list,
|
5
|
+
:host_sequence, :host_prefix, :environment, :host_suffix,
|
6
|
+
:host_presuffix, :log_dir, :host_number, :ssh_user
|
7
|
+
|
8
|
+
def initialize(template_configuration, host_number=nil)
|
9
|
+
@host_number = host_number
|
10
|
+
template_configuration.each_pair do |key, value|
|
11
|
+
self.send("#{key}=", value)
|
12
|
+
end
|
13
|
+
raise "Log path is required" unless @log_dir
|
14
|
+
Dir.mkdir(log_dir) unless Dir.exists?(log_dir)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
shell_commands.each do |command|
|
19
|
+
shellout command
|
20
|
+
sleep 0.5
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def shell_commands_for host_number
|
25
|
+
raise 'Abstract method, implement in subclasses'
|
26
|
+
end
|
27
|
+
|
28
|
+
def shell_commands
|
29
|
+
host_numbers.map do |i|
|
30
|
+
shell_commands_for(i.to_i)
|
31
|
+
end.flatten
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def host_numbers
|
37
|
+
@host_numbers ||= begin
|
38
|
+
return [host_number] if host_number
|
39
|
+
eval "(#{host_sequence}).to_a"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def host_name(number)
|
44
|
+
host_name = sprintf('%s%03d', host_prefix, number)
|
45
|
+
host_name += ".#{host_presuffix}" if host_presuffix
|
46
|
+
host_name += ".#{host_suffix}" if host_suffix
|
47
|
+
host_name
|
48
|
+
end
|
49
|
+
|
50
|
+
def shellout(command)
|
51
|
+
puts "Running provision command:"
|
52
|
+
puts command.colorize(:green)
|
53
|
+
system(command)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
require_relative 'provision'
|
60
|
+
require_relative 'bootstrap'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Provisioner
|
2
|
+
module Command
|
3
|
+
class Bootstrap < Base
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def shell_commands_for(number)
|
8
|
+
host = HostCommand.new(host_name(number), self)
|
9
|
+
|
10
|
+
[host.reset_command, host.bootstrap_command]
|
11
|
+
end
|
12
|
+
|
13
|
+
class HostCommand
|
14
|
+
attr_accessor :name, :context
|
15
|
+
def initialize(name, context)
|
16
|
+
@name = name
|
17
|
+
@context = context
|
18
|
+
end
|
19
|
+
|
20
|
+
def ip_for_host
|
21
|
+
Provisioner::HostIP.ip_for name
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset_command
|
25
|
+
"ssh #{ip_for_host} -l #{context.ssh_user} 'sudo rm -rf /etc/chef'"
|
26
|
+
end
|
27
|
+
|
28
|
+
def bootstrap_command
|
29
|
+
bootstrap_command = [
|
30
|
+
'knife bootstrap',
|
31
|
+
ip_for_host,
|
32
|
+
"--distro #{context.distro}",
|
33
|
+
"--environment #{context.environment}",
|
34
|
+
"--node-name #{name}",
|
35
|
+
]
|
36
|
+
|
37
|
+
bootstrap_command << "--run-list #{context.run_list}" if context.run_list
|
38
|
+
bootstrap_command << "--ssh-user #{context.ssh_user}"
|
39
|
+
bootstrap_command << "2>&1 > #{context.log_dir}/#{name}_provision.log &"
|
40
|
+
bootstrap_command.join(' ')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Provisioner
|
2
|
+
module Command
|
3
|
+
class Provision < Base
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def shell_commands_for(number)
|
8
|
+
host_name = host_name(number)
|
9
|
+
command = [
|
10
|
+
"knife joyent server create",
|
11
|
+
"--image #{image}",
|
12
|
+
"--flavor #{flavor}",
|
13
|
+
"--distro #{distro}",
|
14
|
+
"--networks #{networks}",
|
15
|
+
"--environment #{environment}",
|
16
|
+
"--node-name #{host_name}",
|
17
|
+
].join(' ')
|
18
|
+
|
19
|
+
log_path = "#{log_dir}/#{host_name}_provision.log"
|
20
|
+
command << " --run-list #{run_list}" if run_list
|
21
|
+
command << " 2>&1 > #{log_path} &"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module Provisioner
|
5
|
+
class Configuration < OpenStruct
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def from_path(path)
|
9
|
+
self.new(YAML.load_file(path))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def for_template(name)
|
14
|
+
validate_template(name)
|
15
|
+
|
16
|
+
templates[name].merge(global)
|
17
|
+
end
|
18
|
+
|
19
|
+
def all
|
20
|
+
templates.map { |k, v| {k => v.merge(global)} }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def validate_template(name)
|
26
|
+
error_message = "Can't find configuration for template '#{name}'\nAvailable templates: #{template_names}\n\n"
|
27
|
+
Provisioner::Exit.with_message(error_message) unless templates[name]
|
28
|
+
end
|
29
|
+
|
30
|
+
def template_names
|
31
|
+
return '' unless templates.keys
|
32
|
+
templates.keys.join(', ')
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Provisioner
|
4
|
+
class HostIP
|
5
|
+
def self.ip_for(host)
|
6
|
+
Provisioner::Exit.with_message("Unable to find IP for host: #{host}\nMake sure 'knife joyent server list' runs successfully\n\n") unless ips[host]
|
7
|
+
ips[host]
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def self.ips
|
13
|
+
@ips = {}
|
14
|
+
server_list.each do |server|
|
15
|
+
hostname, ip = server.split(' ')
|
16
|
+
@ips[hostname] = ip
|
17
|
+
end
|
18
|
+
@ips
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.server_list
|
22
|
+
@server_list ||= `knife joyent server list | awk '{print $2 " " $6}' | tail +2`.split("\n")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Provisioner
|
2
|
+
module Logger
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def enable
|
6
|
+
class << self
|
7
|
+
self.send(:define_method, :log, proc { |msg| _log(msg) })
|
8
|
+
self.send(:define_method, :logging, proc { |msg, &block| _logging(msg, &block) })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def disable
|
13
|
+
class << self
|
14
|
+
self.send(:define_method, :log, proc { |msg|})
|
15
|
+
self.send(:define_method, :logging, proc { |msg, &block| block.call })
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def log(msg)
|
20
|
+
end
|
21
|
+
|
22
|
+
def logging(msg, &block)
|
23
|
+
block.call
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def _log(msg)
|
29
|
+
puts "#{Time.now}: #{sprintf("%-20s", Thread.current[:name])} - #{msg}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def _logging(message, &block)
|
33
|
+
start = Time.now
|
34
|
+
returned_from_block = yield
|
35
|
+
elapsed_time = Time.now - start
|
36
|
+
if returned_from_block.is_a?(String) && returned_from_block != ""
|
37
|
+
message += " - #{returned_from_block}"
|
38
|
+
end
|
39
|
+
log "(#{"%9.2f" % (1000 * elapsed_time)}ms) #{message}"
|
40
|
+
returned_from_block
|
41
|
+
rescue Exception => e
|
42
|
+
elapsed_time = Time.now - start
|
43
|
+
log "(#{"%9.2f" % (1000 * elapsed_time)}ms) error: #{e.message} for #{message} "
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
global:
|
2
|
+
environment: test
|
3
|
+
host_suffix: test
|
4
|
+
log_dir: ./tmp
|
5
|
+
ssh_user: ops
|
6
|
+
|
7
|
+
templates:
|
8
|
+
memcached-sessions:
|
9
|
+
image: 9ec5c0c-a941-11e2-a7dc-57a6b041988f
|
10
|
+
flavor: "g3-highmemory-17.125-smartos"
|
11
|
+
distro: smartos-base64
|
12
|
+
networks: "42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f"
|
13
|
+
run_list: "role[joyent]"
|
14
|
+
host_sequence: 1..2
|
15
|
+
host_prefix: memcached-sessions
|
16
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'provision cli' do
|
4
|
+
let(:provision_path) { 'bin' }
|
5
|
+
|
6
|
+
def execute(command)
|
7
|
+
`#{provision_path}/#{command} --dry-run`.strip
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'host number is provided' do
|
11
|
+
let(:expected_command) {'knife joyent server create --image 9ec5c0c-a941-11e2-a7dc-57a6b041988f --flavor g3-highmemory-17.125-smartos --distro smartos-base64 --networks 42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f --environment test --node-name memcached-sessions545.test --run-list role[joyent] 2>&1 > ./tmp/memcached-sessions545.test_provision.log &'}
|
12
|
+
it 'reads the configuration and generates command' do
|
13
|
+
result = execute('provisioner provision --number 545 --config conf/configuration.yml.example --template memcached-sessions')
|
14
|
+
expect(result).to eq(expected_command)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'accepts short options' do
|
18
|
+
result = execute('provisioner provision -n 545 -c conf/configuration.yml.example -t memcached-sessions')
|
19
|
+
expect(result).to eq(expected_command)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'host number is not provided' do
|
24
|
+
it 'returns a command per host' do
|
25
|
+
result = execute('provisioner provision --config conf/configuration.yml.example --template memcached-sessions')
|
26
|
+
commands = result.split("\n")
|
27
|
+
expect(commands.size).to eq(2)
|
28
|
+
expect(commands[0]).to include('memcached-sessions001.test')
|
29
|
+
expect(commands[1]).to include('memcached-sessions002.test')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Provisioner::Command::Bootstrap do
|
4
|
+
describe '#shell_commands' do
|
5
|
+
context 'host is specified' do
|
6
|
+
|
7
|
+
let(:subject) { Provisioner::Command::Bootstrap.new(template_configuration, '1') }
|
8
|
+
|
9
|
+
let(:template_configuration) { {
|
10
|
+
image: '9ec5c0c-a941-11e2-a7dc-57a6b041988f',
|
11
|
+
flavor: 'g3-highmemory-17.125-smartos',
|
12
|
+
distro: 'smartos-base64',
|
13
|
+
networks: '42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f',
|
14
|
+
host_sequence: '1..2',
|
15
|
+
host_suffix: 'test',
|
16
|
+
host_presuffix: 'c1',
|
17
|
+
host_prefix: 'memcached-sessions',
|
18
|
+
environment: 'test',
|
19
|
+
log_dir: './tmp',
|
20
|
+
run_list: 'role[joyent]',
|
21
|
+
ssh_user: 'ops'
|
22
|
+
} }
|
23
|
+
|
24
|
+
let(:expected_bootstrap_command) { [
|
25
|
+
'knife bootstrap 1.2.3.4',
|
26
|
+
'--distro smartos-base64',
|
27
|
+
'--environment test',
|
28
|
+
'--node-name memcached-sessions001.c1.test',
|
29
|
+
'--run-list role[joyent]',
|
30
|
+
'--ssh-user ops',
|
31
|
+
'2>&1 > ./tmp/memcached-sessions001.c1.test_provision.log &'
|
32
|
+
].join(' ') }
|
33
|
+
|
34
|
+
it 'returns command string' do
|
35
|
+
Provisioner::Command::Bootstrap::HostCommand.any_instance.stub(:ip_for_host) { '1.2.3.4' }
|
36
|
+
shell_commands = subject.shell_commands
|
37
|
+
|
38
|
+
expect(shell_commands[0]).to eq("ssh 1.2.3.4 -l ops 'sudo rm -rf /etc/chef'")
|
39
|
+
expect(shell_commands[1]).to eq(expected_bootstrap_command)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Provisioner::Command::Provision do
|
4
|
+
let(:configuration) { Provisioner::Configuration.from_path('spec/fixtures/test.yml') }
|
5
|
+
|
6
|
+
describe '#shell_commands' do
|
7
|
+
|
8
|
+
context 'host is specified' do
|
9
|
+
|
10
|
+
let(:subject) { Provisioner::Command::Provision.new(template_configuration, '1') }
|
11
|
+
let(:expected_command) { [
|
12
|
+
'knife joyent server create',
|
13
|
+
'--image 9ec5c0c-a941-11e2-a7dc-57a6b041988f',
|
14
|
+
'--flavor g3-highmemory-17.125-smartos',
|
15
|
+
'--distro smartos-base64',
|
16
|
+
'--networks 42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f',
|
17
|
+
'--environment test',
|
18
|
+
'--node-name memcached-sessions001.test',
|
19
|
+
'--run-list role[joyent]',
|
20
|
+
'2>&1 > ./tmp/memcached-sessions001.test_provision.log &'
|
21
|
+
].join(' ') }
|
22
|
+
|
23
|
+
context 'passing options directly' do
|
24
|
+
let(:template_configuration) { {
|
25
|
+
image: '9ec5c0c-a941-11e2-a7dc-57a6b041988f',
|
26
|
+
flavor: 'g3-highmemory-17.125-smartos',
|
27
|
+
distro: 'smartos-base64',
|
28
|
+
networks: '42325ea0-eb62-44c1-8eb6-0af3e2f83abc,c8cde927-6277-49ca-82a3-741e8b23b02f',
|
29
|
+
host_sequence: '1..2',
|
30
|
+
host_suffix: 'test',
|
31
|
+
host_prefix: 'memcached-sessions',
|
32
|
+
environment: 'test',
|
33
|
+
log_dir: './tmp',
|
34
|
+
run_list: 'role[joyent]'
|
35
|
+
} }
|
36
|
+
it 'returns expected command string' do
|
37
|
+
expect(subject.shell_commands).to eq([expected_command])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'using the template from yaml configuration' do
|
42
|
+
let(:template_configuration) { configuration.for_template('memcached-sessions') }
|
43
|
+
|
44
|
+
it 'returns expected command string' do
|
45
|
+
expect(subject.shell_commands).to eq([expected_command])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'host number is not specified' do
|
51
|
+
let(:subject) { Provisioner::Command::Provision.new(template_configuration) }
|
52
|
+
let(:template_configuration) { configuration.for_template('memcached-sessions') }
|
53
|
+
|
54
|
+
it 'returns an array of commands based on the configuration' do
|
55
|
+
commands = subject.shell_commands
|
56
|
+
expect(commands).to be_an(Array)
|
57
|
+
expect(commands.size).to be(2)
|
58
|
+
expect(commands[0]).to include('--node-name memcached-sessions001.test')
|
59
|
+
expect(commands[1]).to include('--node-name memcached-sessions002.test')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Provisioner::Configuration do
|
4
|
+
|
5
|
+
let(:config) { Provisioner::Configuration.from_path('spec/fixtures/test.yml') }
|
6
|
+
|
7
|
+
describe '#for_template' do
|
8
|
+
let(:template_configuration) { config.for_template('memcached-sessions') }
|
9
|
+
it 'returns a configuration for a template' do
|
10
|
+
expect(template_configuration['image']).to eq('9ec5c0c-a941-11e2-a7dc-57a6b041988f')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'includes global configuration' do
|
14
|
+
expect(template_configuration['environment']).to eq('test')
|
15
|
+
expect(template_configuration['host_suffix']).to eq('test')
|
16
|
+
expect(template_configuration['log_dir']).to eq('./tmp')
|
17
|
+
expect(template_configuration['ssh_user']).to eq('ops')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Provisioner::HostIP do
|
4
|
+
|
5
|
+
before do
|
6
|
+
Provisioner::HostIP.stub(:server_list){ ['app001.stage 1.1.1.1', 'app002.stage 1.1.1.2']}
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
describe '.ip_for' do
|
11
|
+
it 'returns the IP address given a hostname' do
|
12
|
+
expect(Provisioner::HostIP.ip_for('app001.stage')).to eq('1.1.1.1')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
require 'joyent-provisioner'
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.filter_run :focus
|
14
|
+
|
15
|
+
# Run specs in random order to surface order dependencies. If you find an
|
16
|
+
# order dependency and want to debug it, you can fix the order by providing
|
17
|
+
# the seed, which is printed after each run.
|
18
|
+
# --seed 1234
|
19
|
+
config.order = 'random'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,258 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: joyent-provisioner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Konstantin Gredeskoul
|
9
|
+
- Blake Irvin
|
10
|
+
- Richard Millan
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2013-08-15 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: mixlib-cli
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ! '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0'
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: chef
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: knife-joyent
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: colorize
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
type: :runtime
|
73
|
+
prerelease: false
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: bundler
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '1.3'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ~>
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '1.3'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: rake
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: guard
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
type: :development
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
- !ruby/object:Gem::Dependency
|
129
|
+
name: guard-rspec
|
130
|
+
requirement: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ! '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
type: :development
|
137
|
+
prerelease: false
|
138
|
+
version_requirements: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
- !ruby/object:Gem::Dependency
|
145
|
+
name: rspec
|
146
|
+
requirement: !ruby/object:Gem::Requirement
|
147
|
+
none: false
|
148
|
+
requirements:
|
149
|
+
- - ! '>='
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
none: false
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
- !ruby/object:Gem::Dependency
|
161
|
+
name: pry-debugger
|
162
|
+
requirement: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ! '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
type: :development
|
169
|
+
prerelease: false
|
170
|
+
version_requirements: !ruby/object:Gem::Requirement
|
171
|
+
none: false
|
172
|
+
requirements:
|
173
|
+
- - ! '>='
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
description: Wrapper gem around provisioning clusters of servers on Joyent cloud
|
177
|
+
email:
|
178
|
+
- kig@wanelo.com
|
179
|
+
- bixu@wanelo.com
|
180
|
+
- richard@wanelo.com
|
181
|
+
executables:
|
182
|
+
- provisioner
|
183
|
+
extensions: []
|
184
|
+
extra_rdoc_files: []
|
185
|
+
files:
|
186
|
+
- .gitignore
|
187
|
+
- .rspec
|
188
|
+
- .travis.yml
|
189
|
+
- Gemfile
|
190
|
+
- Guardfile
|
191
|
+
- LICENSE.txt
|
192
|
+
- README.md
|
193
|
+
- Rakefile
|
194
|
+
- bin/provisioner
|
195
|
+
- conf/configuration.yml.example
|
196
|
+
- joyent-provisioner.gemspec
|
197
|
+
- lib/joyent-provisioner.rb
|
198
|
+
- lib/provisioner/cli.rb
|
199
|
+
- lib/provisioner/cli/bootstrap.rb
|
200
|
+
- lib/provisioner/cli/provision.rb
|
201
|
+
- lib/provisioner/command/base.rb
|
202
|
+
- lib/provisioner/command/bootstrap.rb
|
203
|
+
- lib/provisioner/command/provision.rb
|
204
|
+
- lib/provisioner/configuration.rb
|
205
|
+
- lib/provisioner/helper.rb
|
206
|
+
- lib/provisioner/helper/exit.rb
|
207
|
+
- lib/provisioner/host_ip.rb
|
208
|
+
- lib/provisioner/logger.rb
|
209
|
+
- lib/provisioner/usage.rb
|
210
|
+
- lib/provisioner/version.rb
|
211
|
+
- spec/fixtures/test.yml
|
212
|
+
- spec/provisioner/cli/bootstrap_spec.rb
|
213
|
+
- spec/provisioner/cli/host_spec.rb
|
214
|
+
- spec/provisioner/command/bootstrap_spec.rb
|
215
|
+
- spec/provisioner/command/provision_spec.rb
|
216
|
+
- spec/provisioner/configuration_spec.rb
|
217
|
+
- spec/provisioner/host_ip_spec.rb
|
218
|
+
- spec/spec_helper.rb
|
219
|
+
homepage: ''
|
220
|
+
licenses:
|
221
|
+
- MIT
|
222
|
+
post_install_message:
|
223
|
+
rdoc_options: []
|
224
|
+
require_paths:
|
225
|
+
- lib
|
226
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
227
|
+
none: false
|
228
|
+
requirements:
|
229
|
+
- - ! '>='
|
230
|
+
- !ruby/object:Gem::Version
|
231
|
+
version: '0'
|
232
|
+
segments:
|
233
|
+
- 0
|
234
|
+
hash: 3329166401206121639
|
235
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
236
|
+
none: false
|
237
|
+
requirements:
|
238
|
+
- - ! '>='
|
239
|
+
- !ruby/object:Gem::Version
|
240
|
+
version: '0'
|
241
|
+
segments:
|
242
|
+
- 0
|
243
|
+
hash: 3329166401206121639
|
244
|
+
requirements: []
|
245
|
+
rubyforge_project:
|
246
|
+
rubygems_version: 1.8.24
|
247
|
+
signing_key:
|
248
|
+
specification_version: 3
|
249
|
+
summary: Wrapper gem around provisioning clusters of servers on Joyent cloud
|
250
|
+
test_files:
|
251
|
+
- spec/fixtures/test.yml
|
252
|
+
- spec/provisioner/cli/bootstrap_spec.rb
|
253
|
+
- spec/provisioner/cli/host_spec.rb
|
254
|
+
- spec/provisioner/command/bootstrap_spec.rb
|
255
|
+
- spec/provisioner/command/provision_spec.rb
|
256
|
+
- spec/provisioner/configuration_spec.rb
|
257
|
+
- spec/provisioner/host_ip_spec.rb
|
258
|
+
- spec/spec_helper.rb
|