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.
Files changed (40) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +7 -0
  4. data/README.md +14 -37
  5. data/bin/console +14 -0
  6. data/bin/setup +8 -0
  7. data/{bin → exe}/sunzi +0 -0
  8. data/lib/sunzi.rb +18 -22
  9. data/lib/sunzi/actions.rb +35 -0
  10. data/lib/sunzi/cli.rb +6 -139
  11. data/lib/sunzi/command.rb +113 -0
  12. data/lib/sunzi/core_ext.rb +10 -0
  13. data/lib/sunzi/dependency.rb +26 -29
  14. data/lib/sunzi/endpoint.rb +17 -0
  15. data/lib/sunzi/plugin.rb +17 -0
  16. data/sunzi.gemspec +9 -9
  17. data/{lib/templates → templates}/create/.gitignore +0 -0
  18. data/{lib/templates → templates}/create/files/.gitkeep +0 -0
  19. data/{lib/templates → templates}/create/install.sh +13 -7
  20. data/{lib/templates → templates}/create/recipes/sunzi.sh +0 -0
  21. data/{lib/templates → templates}/create/roles/db.sh +0 -0
  22. data/{lib/templates → templates}/create/roles/web.sh +0 -0
  23. data/templates/create/sunzi.yml +27 -0
  24. data/templates/dependency/gemfile.erb +6 -0
  25. data/templates/dependency/install.erb +6 -0
  26. metadata +45 -36
  27. data/lib/sunzi/cloud.rb +0 -24
  28. data/lib/sunzi/cloud/base.rb +0 -98
  29. data/lib/sunzi/cloud/digital_ocean.rb +0 -78
  30. data/lib/sunzi/cloud/linode.rb +0 -154
  31. data/lib/sunzi/dns.rb +0 -25
  32. data/lib/sunzi/dns/base.rb +0 -7
  33. data/lib/sunzi/dns/linode.rb +0 -26
  34. data/lib/sunzi/dns/route53.rb +0 -25
  35. data/lib/sunzi/logger.rb +0 -17
  36. data/lib/sunzi/utility.rb +0 -17
  37. data/lib/templates/create/sunzi.yml +0 -30
  38. data/lib/templates/setup/digital_ocean/digital_ocean.yml +0 -28
  39. data/lib/templates/setup/linode/linode.yml +0 -42
  40. 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
@@ -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
@@ -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
@@ -1,7 +0,0 @@
1
- module Sunzi
2
- class DNS
3
- class Base
4
- include Sunzi::Utility
5
- end
6
- end
7
- end
@@ -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
@@ -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
@@ -1,17 +0,0 @@
1
- module Sunzi
2
- module Logger
3
- class << self
4
- def info(text)
5
- puts text.bright
6
- end
7
-
8
- def success(text)
9
- puts text.color(:green).bright
10
- end
11
-
12
- def error(text)
13
- puts text.color(:red).bright
14
- end
15
- end
16
- end
17
- end
@@ -1,17 +0,0 @@
1
- module Sunzi
2
- module Utility
3
- def abort_with(text)
4
- Logger.error text
5
- abort
6
- end
7
-
8
- def exit_with(text)
9
- Logger.success text
10
- exit
11
- end
12
-
13
- def say(text)
14
- Logger.info text
15
- end
16
- end
17
- end
@@ -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