sunzi 1.5.2 → 2.0.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.
- checksums.yaml +5 -5
- data/.travis.yml +1 -1
- data/CHANGELOG.md +7 -0
- data/README.md +14 -37
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/{bin → exe}/sunzi +0 -0
- data/lib/sunzi.rb +18 -22
- data/lib/sunzi/actions.rb +35 -0
- data/lib/sunzi/cli.rb +6 -139
- data/lib/sunzi/command.rb +113 -0
- data/lib/sunzi/core_ext.rb +10 -0
- data/lib/sunzi/dependency.rb +26 -29
- data/lib/sunzi/endpoint.rb +17 -0
- data/lib/sunzi/plugin.rb +17 -0
- data/sunzi.gemspec +9 -9
- data/{lib/templates → templates}/create/.gitignore +0 -0
- data/{lib/templates → templates}/create/files/.gitkeep +0 -0
- data/{lib/templates → templates}/create/install.sh +13 -7
- data/{lib/templates → templates}/create/recipes/sunzi.sh +0 -0
- data/{lib/templates → templates}/create/roles/db.sh +0 -0
- data/{lib/templates → templates}/create/roles/web.sh +0 -0
- data/templates/create/sunzi.yml +27 -0
- data/templates/dependency/gemfile.erb +6 -0
- data/templates/dependency/install.erb +6 -0
- metadata +45 -36
- data/lib/sunzi/cloud.rb +0 -24
- data/lib/sunzi/cloud/base.rb +0 -98
- data/lib/sunzi/cloud/digital_ocean.rb +0 -78
- data/lib/sunzi/cloud/linode.rb +0 -154
- data/lib/sunzi/dns.rb +0 -25
- data/lib/sunzi/dns/base.rb +0 -7
- data/lib/sunzi/dns/linode.rb +0 -26
- data/lib/sunzi/dns/route53.rb +0 -25
- data/lib/sunzi/logger.rb +0 -17
- data/lib/sunzi/utility.rb +0 -17
- data/lib/templates/create/sunzi.yml +0 -30
- data/lib/templates/setup/digital_ocean/digital_ocean.yml +0 -28
- data/lib/templates/setup/linode/linode.yml +0 -42
- data/test/test_cli.rb +0 -40
@@ -1,78 +0,0 @@
|
|
1
|
-
Sunzi::Dependency.load('digital_ocean')
|
2
|
-
|
3
|
-
module Sunzi
|
4
|
-
class Cloud
|
5
|
-
class DigitalOcean < Base
|
6
|
-
def do_setup
|
7
|
-
choose(:size, @api.sizes.list.sizes)
|
8
|
-
choose(:region, @api.regions.list.regions)
|
9
|
-
|
10
|
-
# Choose an image
|
11
|
-
result = @api.images.list({'filter' => 'global'}).images
|
12
|
-
if @config['distributions_filter']
|
13
|
-
result = result.select{|i| i.distribution.match Regexp.new(@config['distributions_filter'], Regexp::IGNORECASE) }
|
14
|
-
end
|
15
|
-
choose(:image, result)
|
16
|
-
|
17
|
-
# Go ahead?
|
18
|
-
proceed?
|
19
|
-
|
20
|
-
ssh_key_ids = @api.ssh_keys.list.ssh_keys.map(&:id).join(',')
|
21
|
-
|
22
|
-
# Create
|
23
|
-
say "creating a new droplets..."
|
24
|
-
result = @api.droplets.create(:name => @name,
|
25
|
-
:size_id => @attributes[:size_id],
|
26
|
-
:image_id => @attributes[:image_id],
|
27
|
-
:region_id => @attributes[:region_id],
|
28
|
-
:ssh_key_ids => ssh_key_ids)
|
29
|
-
|
30
|
-
@droplet_id = result.droplet.id
|
31
|
-
say "Created a new droplet (id: #{@droplet_id}). Booting..."
|
32
|
-
|
33
|
-
# Boot - we need this before getting public IP
|
34
|
-
while @api.droplets.show(@droplet_id).droplet.status.downcase != 'active'
|
35
|
-
sleep 3
|
36
|
-
end
|
37
|
-
|
38
|
-
@public_ip = @api.droplets.show(@droplet_id).droplet.ip_address
|
39
|
-
say "Done. ip address = #{@public_ip}"
|
40
|
-
|
41
|
-
@instance = {
|
42
|
-
:droplet_id => @droplet_id,
|
43
|
-
:env => @env,
|
44
|
-
:host => @host,
|
45
|
-
:fqdn => @fqdn,
|
46
|
-
:name => @name,
|
47
|
-
:ip_address => @public_ip,
|
48
|
-
:size_id => @attributes[:size_id],
|
49
|
-
:size_name => @attributes[:size_name],
|
50
|
-
:region_id => @attributes[:region_id],
|
51
|
-
:region_name => @attributes[:region_name],
|
52
|
-
:image_id => @attributes[:image_id],
|
53
|
-
:image_name => @attributes[:image_name],
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
|
-
def choose(key, result)
|
58
|
-
abort "no #{key} found!" if result.first.nil?
|
59
|
-
result.each{|i| say "#{i.id}: #{i.name}" }
|
60
|
-
@attributes[:"#{key}_id"] = ask("which #{key}?: ", Integer) {|q| q.in = result.map(&:id); q.default = result.first.id }
|
61
|
-
@attributes[:"#{key}_name"] = result.find{|i| i.id == @attributes[:"#{key}_id"] }.name
|
62
|
-
end
|
63
|
-
|
64
|
-
def do_teardown
|
65
|
-
say 'deleting droplet...'
|
66
|
-
@api.droplets.delete(@instance[:droplet_id])
|
67
|
-
end
|
68
|
-
|
69
|
-
def assign_api
|
70
|
-
@api = ::DigitalOcean::API.new :api_key => @config['api_key'], :client_id => @config['client_id']
|
71
|
-
end
|
72
|
-
|
73
|
-
def ip_key
|
74
|
-
:ip_address
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
data/lib/sunzi/cloud/linode.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
Sunzi::Dependency.load('linode')
|
2
|
-
|
3
|
-
module Sunzi
|
4
|
-
class Cloud
|
5
|
-
class Linode < Base
|
6
|
-
def do_setup
|
7
|
-
@sshkey = File.read(File.expand_path(@config['root_sshkey_path'])).chomp
|
8
|
-
if @sshkey.match(/\n/)
|
9
|
-
abort_with "RootSSHKey #{@sshkey.inspect} must not be multi-line! Check inside \"#{@config['root_sshkey_path']}\""
|
10
|
-
end
|
11
|
-
|
12
|
-
choose(:plan, @api.avail.linodeplans)
|
13
|
-
choose(:datacenter, @api.avail.datacenters, :label_method => :location)
|
14
|
-
choose(:distribution, @api.avail.distributions, :filter => 'distributions_filter')
|
15
|
-
choose(:kernel, @api.avail.kernels, :filter => 'kernels_filter')
|
16
|
-
|
17
|
-
# Choose swap size
|
18
|
-
@swap_size = ask('swap size in MB? (default: 256MB): ', Integer) { |q| q.default = 256 }
|
19
|
-
|
20
|
-
# Go ahead?
|
21
|
-
proceed?
|
22
|
-
|
23
|
-
# Create
|
24
|
-
say "creating a new linode..."
|
25
|
-
result = @api.linode.create(
|
26
|
-
:DatacenterID => @attributes[:datacenterid],
|
27
|
-
:PlanID => @attributes[:planid],
|
28
|
-
:PaymentTerm => @config['payment_term'])
|
29
|
-
@linodeid = result.linodeid
|
30
|
-
say "created a new instance: linodeid = #{@linodeid}"
|
31
|
-
|
32
|
-
result = @api.linode.list.select{|i| i.linodeid == @linodeid }.first
|
33
|
-
@totalhd = result.totalhd
|
34
|
-
|
35
|
-
# Update settings
|
36
|
-
say "Updating settings..."
|
37
|
-
@group = @config['group'][@env]
|
38
|
-
settings = { :LinodeID => @linodeid, :Label => @name, :lpm_displayGroup => @group }
|
39
|
-
settings.update(@config['settings']) if @config['settings']
|
40
|
-
@api.linode.update(settings)
|
41
|
-
|
42
|
-
# Create a root disk
|
43
|
-
say "Creating a root disk..."
|
44
|
-
result = @api.linode.disk.createfromdistribution(
|
45
|
-
:LinodeID => @linodeid,
|
46
|
-
:DistributionID => @attributes[:distributionid],
|
47
|
-
:Label => "#{@attributes[:distribution_label]} Image",
|
48
|
-
:Size => @totalhd - @swap_size,
|
49
|
-
:rootPass => @config['root_pass'],
|
50
|
-
:rootSSHKey => @sshkey
|
51
|
-
)
|
52
|
-
@root_diskid = result.diskid
|
53
|
-
|
54
|
-
# Create a swap disk
|
55
|
-
say "Creating a swap disk..."
|
56
|
-
result = @api.linode.disk.create(
|
57
|
-
:LinodeID => @linodeid,
|
58
|
-
:Label => "#{@swap_size}MB Swap Image",
|
59
|
-
:Type => 'swap',
|
60
|
-
:Size => @swap_size
|
61
|
-
)
|
62
|
-
@swap_diskid = result.diskid
|
63
|
-
|
64
|
-
# Create a config profiile
|
65
|
-
say "Creating a config profile..."
|
66
|
-
result = @api.linode.config.create(
|
67
|
-
:LinodeID => @linodeid,
|
68
|
-
:KernelID => @attributes[:kernelid],
|
69
|
-
:Label => "#{@attributes[:distribution_label]} Profile",
|
70
|
-
:DiskList => [ @root_diskid, @swap_diskid ].join(',')
|
71
|
-
)
|
72
|
-
@config_id = result.configid
|
73
|
-
|
74
|
-
# Add a private IP
|
75
|
-
say "Adding a private IP..."
|
76
|
-
result = @api.linode.ip.list(:LinodeID => @linodeid)
|
77
|
-
@public_ip = result.first.ipaddress
|
78
|
-
result = @api.linode.ip.addprivate(:LinodeID => @linodeid)
|
79
|
-
result = @api.linode.ip.list(:LinodeID => @linodeid).find{|i| i.ispublic == 0 }
|
80
|
-
@private_ip = result.ipaddress
|
81
|
-
|
82
|
-
@instance = {
|
83
|
-
:linode_id => @linodeid,
|
84
|
-
:env => @env,
|
85
|
-
:host => @host,
|
86
|
-
:fqdn => @fqdn,
|
87
|
-
:label => @name,
|
88
|
-
:group => @group,
|
89
|
-
:plan_id => @attributes[:planid],
|
90
|
-
:datacenter_id => @attributes[:datacenterid],
|
91
|
-
:datacenter_location => @attributes[:datacenter_location],
|
92
|
-
:distribution_id => @attributes[:distributionid],
|
93
|
-
:distribution_label => @attributes[:distribution_label],
|
94
|
-
:kernel_id => @attributes[:kernelid],
|
95
|
-
:kernel_label => @attributes[:kernel_label],
|
96
|
-
:swap_size => @swap_size,
|
97
|
-
:totalhd => @totalhd,
|
98
|
-
:root_diskid => @root_diskid,
|
99
|
-
:swap_diskid => @swap_diskid,
|
100
|
-
:config_id => @config_id,
|
101
|
-
:public_ip => @public_ip,
|
102
|
-
:private_ip => @private_ip,
|
103
|
-
}
|
104
|
-
|
105
|
-
# Boot
|
106
|
-
say 'Done. Booting...'
|
107
|
-
@api.linode.boot(:LinodeID => @linodeid)
|
108
|
-
end
|
109
|
-
|
110
|
-
def choose(key, result, options = {})
|
111
|
-
label_method = options[:label_method] || :label
|
112
|
-
id = :"#{key}id"
|
113
|
-
label = :"#{key}_#{label_method}"
|
114
|
-
|
115
|
-
# Filters
|
116
|
-
if options[:filter] and @config[options[:filter]]
|
117
|
-
result = result.select{|i| i.label.match Regexp.new(@config[options[:filter]], Regexp::IGNORECASE) }
|
118
|
-
end
|
119
|
-
|
120
|
-
result.each{|i| say "#{i.send(id)}: #{i.send(label_method)}" }
|
121
|
-
@attributes[id] = ask("which #{key}?: ", Integer) {|q| q.in = result.map(&id); q.default = result.first.send(id) }
|
122
|
-
@attributes[label] = result.find{|i| i.send(id) == @attributes[id] }.send(label_method)
|
123
|
-
end
|
124
|
-
|
125
|
-
def do_teardown
|
126
|
-
@linode_id_hash = { :LinodeID => @instance[:linode_id] }
|
127
|
-
|
128
|
-
# Shutdown first or disk deletion will fail
|
129
|
-
say 'shutting down...'
|
130
|
-
@api.linode.shutdown(@linode_id_hash)
|
131
|
-
# Wait until linode.shutdown has completed
|
132
|
-
wait_for('linode.shutdown')
|
133
|
-
|
134
|
-
# Delete the instance
|
135
|
-
say 'deleting linode...'
|
136
|
-
@api.linode.delete(@linode_id_hash.merge(:skipChecks => 1))
|
137
|
-
end
|
138
|
-
|
139
|
-
def assign_api
|
140
|
-
@api = ::Linode.new(:api_key => @config['api_key'])
|
141
|
-
end
|
142
|
-
|
143
|
-
def ip_key
|
144
|
-
:public_ip
|
145
|
-
end
|
146
|
-
|
147
|
-
def wait_for(action)
|
148
|
-
begin
|
149
|
-
sleep 3
|
150
|
-
end until @api.linode.job.list(@linode_id_hash).find{|i| i.action == action }.host_success == 1
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
data/lib/sunzi/dns.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Sunzi
|
2
|
-
class DNS
|
3
|
-
include Sunzi::Utility
|
4
|
-
|
5
|
-
def initialize(config, cloud)
|
6
|
-
dns = config['dns']
|
7
|
-
@subject = case dns
|
8
|
-
when 'linode'
|
9
|
-
Sunzi::DNS::Linode.new(config, cloud)
|
10
|
-
when 'route53'
|
11
|
-
Sunzi::DNS::Route53.new(config, cloud)
|
12
|
-
else
|
13
|
-
abort_with "DNS #{dns} is not valid!"
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def method_missing(sym, *args, &block)
|
18
|
-
@subject.send sym, *args, &block
|
19
|
-
end
|
20
|
-
|
21
|
-
def respond_to?(method)
|
22
|
-
@subject.respond_to?(sym) || super
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/sunzi/dns/base.rb
DELETED
data/lib/sunzi/dns/linode.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
Sunzi::Dependency.load('linode')
|
2
|
-
|
3
|
-
module Sunzi
|
4
|
-
class DNS
|
5
|
-
class Linode < Base
|
6
|
-
def initialize(config, cloud)
|
7
|
-
@api = ::Linode.new(:api_key => (cloud == 'linode') ? config['api_key'] : config['linode']['api_key'])
|
8
|
-
zone = config['fqdn']['zone']
|
9
|
-
@domain = @api.domain.list.find{|i| i.domain == zone }
|
10
|
-
abort_with "zone for #{zone} was not found on Linode DNS!" unless @domain
|
11
|
-
end
|
12
|
-
|
13
|
-
def add(fqdn, ip)
|
14
|
-
say 'adding the public IP to Linode DNS Manager...'
|
15
|
-
@api.domain.resource.create(:DomainID => @domain.domainid, :Type => 'A', :Name => fqdn, :Target => ip)
|
16
|
-
end
|
17
|
-
|
18
|
-
def delete(ip)
|
19
|
-
say 'deleting the public IP from Linode DNS Manager...'
|
20
|
-
resource = @api.domain.resource.list(:DomainID => @domain.domainid).find{|i| i.target == ip }
|
21
|
-
abort_with "ip address #{ip} was not found on Linode DNS!" unless resource
|
22
|
-
@api.domain.resource.delete(:DomainID => @domain.domainid, :ResourceID => resource.resourceid)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/sunzi/dns/route53.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
Sunzi::Dependency.load('route53')
|
2
|
-
|
3
|
-
module Sunzi
|
4
|
-
class DNS
|
5
|
-
class Route53 < Base
|
6
|
-
def initialize(config, cloud)
|
7
|
-
@api = ::Route53::Connection.new(config['route53']['key'], config['route53']['secret'])
|
8
|
-
zone = config['fqdn']['zone']
|
9
|
-
@route53_zone = @api.get_zones.find{|i| i.name.sub(/\.$/,'') == zone }
|
10
|
-
abort_with "zone for #{zone} was not found on Route 53!" unless @route53_zone
|
11
|
-
end
|
12
|
-
|
13
|
-
def add(fqdn, ip)
|
14
|
-
say 'adding the public IP to Route 53...'
|
15
|
-
::Route53::DNSRecord.new(fqdn, "A", "300", [ip], @route53_zone).create
|
16
|
-
end
|
17
|
-
|
18
|
-
def delete(ip)
|
19
|
-
say 'deleting the public IP from Route 53...'
|
20
|
-
record = @route53_zone.get_records.find{|i| i.values.first == ip }
|
21
|
-
record.delete if record
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/sunzi/logger.rb
DELETED
data/lib/sunzi/utility.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
---
|
2
|
-
# Dynamic variables here will be compiled to individual files in compiled/attributes.
|
3
|
-
attributes:
|
4
|
-
environment: production
|
5
|
-
ruby_version: 2.0.0
|
6
|
-
|
7
|
-
# Remote recipes here will be downloaded to compiled/recipes.
|
8
|
-
recipes:
|
9
|
-
rvm: https://raw.github.com/kenn/sunzi-recipes/master/ruby/rvm.sh
|
10
|
-
# dotdeb: https://raw.github.com/kenn/sunzi-recipes/master/debian/dotdeb-wheezy.sh
|
11
|
-
# backports: https://raw.github.com/kenn/sunzi-recipes/master/debian/backports-wheezy.sh
|
12
|
-
# mongodb-10gen: https://raw.github.com/kenn/sunzi-recipes/master/debian/mongodb-10gen.sh
|
13
|
-
|
14
|
-
# Files specified here will be copied to compiled/files.
|
15
|
-
# files:
|
16
|
-
# - ~/.ssh/id_rsa.pub
|
17
|
-
|
18
|
-
# Fine tune how Sunzi should work.
|
19
|
-
preferences:
|
20
|
-
# Erase the generated folder on the server after deploy.
|
21
|
-
# Turn on when you are done with testing and ready for production use.
|
22
|
-
erase_remote_folder: true
|
23
|
-
|
24
|
-
# Skip retrieving remote recipes when local copies already exist. This setting helps
|
25
|
-
# iterative deploy testing considerably faster, when you have a lot of remote recipes.
|
26
|
-
cache_remote_recipes: false
|
27
|
-
|
28
|
-
# Evaluate files as ERB templates. When enabled, you can pass dynamic values in the form
|
29
|
-
# of <%= @attributes.environment %> in recipes, roles, files and install.sh.
|
30
|
-
eval_erb: true
|
@@ -1,28 +0,0 @@
|
|
1
|
-
---
|
2
|
-
api_key: your_api_key
|
3
|
-
client_id: your_client_id
|
4
|
-
|
5
|
-
# add / remove environments
|
6
|
-
environments:
|
7
|
-
- production
|
8
|
-
- staging
|
9
|
-
fqdn:
|
10
|
-
zone: example.com
|
11
|
-
production: '%{host}.example.com'
|
12
|
-
staging: '%{host}.staging.example.com'
|
13
|
-
name:
|
14
|
-
production: 'example-%{host}'
|
15
|
-
staging: 'example-staging-%{host}'
|
16
|
-
|
17
|
-
# filter out large lists by keyword
|
18
|
-
distributions_filter: debian
|
19
|
-
|
20
|
-
# DNS takes "route53" or "linode"
|
21
|
-
# dns: route53
|
22
|
-
|
23
|
-
# Credentials for DNS
|
24
|
-
route53:
|
25
|
-
key: your_aws_key
|
26
|
-
secret: your_aws_secret
|
27
|
-
linode:
|
28
|
-
api_key: your_linode_api_key
|
@@ -1,42 +0,0 @@
|
|
1
|
-
---
|
2
|
-
api_key: your_api_key
|
3
|
-
root_pass: your_root_password
|
4
|
-
root_sshkey_path: ~/.ssh/id_rsa.pub
|
5
|
-
|
6
|
-
# payment_term must be 1, 12 or 24
|
7
|
-
payment_term: 1
|
8
|
-
|
9
|
-
# add / remove environments
|
10
|
-
environments:
|
11
|
-
- production
|
12
|
-
- staging
|
13
|
-
fqdn:
|
14
|
-
zone: example.com
|
15
|
-
production: '%{host}.example.com'
|
16
|
-
staging: '%{host}.staging.example.com'
|
17
|
-
name:
|
18
|
-
production: 'example-%{host}'
|
19
|
-
staging: 'example-staging-%{host}'
|
20
|
-
group:
|
21
|
-
production: example
|
22
|
-
staging: example-staging
|
23
|
-
|
24
|
-
# filter out large lists by keyword
|
25
|
-
distributions_filter: debian
|
26
|
-
kernels_filter: latest
|
27
|
-
|
28
|
-
# dns takes either "linode" or "route53"
|
29
|
-
dns: linode
|
30
|
-
|
31
|
-
# only used when route53 is chosen for DNS
|
32
|
-
route53:
|
33
|
-
key: your_aws_key
|
34
|
-
secret: your_aws_secret
|
35
|
-
|
36
|
-
# other parameters for settings.
|
37
|
-
# settings:
|
38
|
-
# alert_cpu_threshold: 90
|
39
|
-
# alert_diskio_threshold: 1000
|
40
|
-
# alert_bwin_threshold: 5
|
41
|
-
# alert_bwout_threshold: 5
|
42
|
-
# alert_bwquota_threshold: 80
|