joyent-provisioner 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build status](https://secure.travis-ci.org/wanelo/joyent-provisioner.png)](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
|