buildserver 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4755cb02e6340c1620396a9b1a0b76e202c49209
4
+ data.tar.gz: c3fcfd6c6e90e216b88ef5760760a248249ec4e6
5
+ SHA512:
6
+ metadata.gz: 894790ca78703a31dd210e299b4c64732caaf6f997c982f6fdaddca3fde692fb58e2d8977b26b3a4351ce8037baa40ad5c36ed598bd64f14d387b73bc58c942c
7
+ data.tar.gz: 39527a7d1a5231db090127673fa1e28405729b2745f379a319878b40dcdad0cdec250a60727e1066f53daff90199d57bc8a6267c50650118f27f5bd9396c6c3e
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.1
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ # gem "rails"
5
+ gemspec
6
+
7
+ gem 'subexec'
8
+ gem 'pry'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Pidrock
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # Buildserver
2
+
3
+ Lets you easily compile bash scripts from Ruby to build server instances on your favorite Linux distro.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'buildserver'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install buildserver
18
+
19
+ ## Usage
20
+
21
+ Init a directory like this:
22
+
23
+ ```bash
24
+ mkdir -p buildingblocks
25
+ touch buildingblocks/build.rb
26
+ cat > buildingblocks/build.rb << EOF
27
+ require 'buildserver'
28
+ require_relative 'blocks/base/builder'
29
+
30
+ buildserver = Buildserver::Buildserver.new
31
+ buildserver.add_instance('wilmut.example.com', '80.0.0.10', :jumphost)
32
+
33
+ buildserver.add_build_block(:base, Blocks::Base::Builder.new)
34
+
35
+ buildserver.build!
36
+ EOF
37
+
38
+ mkdir -p buildingblocks/blocks
39
+ mkdir -p buildingblocks/blocks/base
40
+ touch buildingblocks/blocks/base/builder.rb
41
+ cat > buildingblocks/blocks/base/builder.rb << EOF
42
+ require 'buildserver'
43
+
44
+ module Blocks
45
+ module Base
46
+
47
+ class Builder < Buildserver::BuildingBlock
48
+ def build(instance, instances)
49
+ run_command("apt-get update")
50
+ run_command("apt-get -y install aptitude")
51
+ run_command("aptitude -y full-upgrade")
52
+
53
+ # Set hostname
54
+ run_command("echo \"#{instance.hostname}\" > /etc/hostname")
55
+ run_command("echo -e \"\\n127.0.0.1 #{instance.hostname} #{instance.hostname}.local\\n\" >> /etc/hosts")
56
+ run_command("hostname -F /etc/hostname")
57
+
58
+ # Set ssh to only allow keys
59
+ run_command("sed -i \"/#PasswordAuthentication yes/PasswordAuthentication no/g\" /etc/ssh/sshd_config")
60
+ run_command("service ssh restart", :after)
61
+ end
62
+
63
+ def external_ports
64
+ [22]
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+
71
+ EOF
72
+ ```
73
+
74
+ ### Adding servers with roles:
75
+
76
+ ```ruby
77
+ buildserver.add_instance('m1.example.com', '80.0.0.1', :loadbalancer)
78
+ buildserver.add_instance('m2.example.com', '80.0.0.2', :utility)
79
+ buildserver.add_instance('m3.example.com', '80.0.0.3', :application)
80
+ ```
81
+
82
+ ### Built-in Builder methods:
83
+
84
+ #### Templating
85
+
86
+ To install a template the following is possible:
87
+
88
+ ```ruby
89
+ template = template('haproxy.cfg.erb' {port: 80})
90
+ install_template(template, "/etc/haproxy/haproxy.cfg")
91
+ ```
92
+
93
+ To append a template to a file use `append_template`
94
+
95
+ ```ruby
96
+ template = template('pg_hostfile.erb', {username: user.username})
97
+ append_template(template, user.username, '/etc/postgresql/9.3/main/pg_hba.conf')
98
+ ```
99
+
100
+ #### User existence
101
+
102
+ To only do something if a user exists on the system:
103
+
104
+ ```ruby
105
+ if_user_exists?(@username) do
106
+ # Do stuff
107
+ end
108
+ ```
109
+
110
+ And if the user don't exists:
111
+
112
+ ```ruby
113
+ if_user_dont_exists?(@username) do
114
+ run_command("adduser #{@username} --disabled-password --gecos \"\"")
115
+ end
116
+ ```
117
+
118
+ #### Directory existence
119
+
120
+ Use `if_directory_exists?(path)` or `if_directory_dont_exists?(path)`
121
+
122
+ ```ruby
123
+ if_directory_exists?("/etc/serf_handlers") do
124
+ template = template('serf_haproxy.rb')
125
+ install_template(template, "/etc/serf_handlers/serf_haproxy.rb")
126
+ end
127
+
128
+ # Installing RBENV
129
+ if_directory_dont_exists?("#{@home_dir}/.rbenv") do
130
+ run_command("su #{@username} -c \"cd #{@home_dir} && git clone https://github.com/sstephenson/rbenv.git #{@home_dir}/.rbenv\"")
131
+ end
132
+ ```
133
+
134
+ #### File existence
135
+
136
+ Use `if_file_exists?(path)` or `if_file_dont_exists?(path)`
137
+
138
+ ```ruby
139
+ if_file_exists?("/etc/nginx/sites-enabled/default") do
140
+ run_command("rm /etc/nginx/sites-enabled/default")
141
+ end
142
+
143
+ if_file_dont_exists?("/sbin/serf") do
144
+ run_command("cd /root")
145
+ run_command("wget https://dl.bintray.com/mitchellh/serf/0.6.2_linux_amd64.zip -O serf.zip")
146
+ run_command("unzip serf.zip")
147
+ run_command("mv serf /sbin/serf")
148
+ end
149
+ ```
150
+
151
+ ### Example of a user builder with login through public-key from Github:
152
+
153
+ This takes advantage of the fact that Github exposes public-keys for users, you can see mine here: https://github.com/kaspergrubbe.keys
154
+
155
+ You use this builder like this:
156
+
157
+ ```ruby
158
+ require_relative 'blocks/user/builder'
159
+ buildserver.add_build_block(:base, Blocks::User::Builder.new('root', {home_dir: '/root', github_users: ['kaspergrubbe']}))
160
+ buildserver.add_build_block(:base, Blocks::User::Builder.new('kasper', {github_users: ['kaspergrubbe']}))
161
+ ```
162
+
163
+ This is the code:
164
+
165
+ ```ruby
166
+ require 'buildserver'
167
+
168
+ module Blocks
169
+ module User
170
+
171
+ class Builder < Buildserver::BuildingBlock
172
+ def initialize(username, options = {})
173
+ @username = username
174
+ @home_dir = options.fetch(:home_dir, "/home/#{@username}")
175
+ @github_users = options.fetch(:github_users, [])
176
+ end
177
+
178
+ def build(instance, instances)
179
+ if_user_dont_exists?(@username) do
180
+ run_command(" adduser #{@username} --disabled-password --gecos \"\"")
181
+ end
182
+
183
+ if !@github_users.nil?
184
+ run_command("touch #{@home_dir}/combined_keys")
185
+ @github_users.each do |github_user|
186
+ run_command("wget https://github.com/#{github_user}.keys -O - >> #{@home_dir}/combined_keys")
187
+ run_command("echo \"\" >> #{@home_dir}/combined_keys")
188
+ end
189
+ run_command("mv #{@home_dir}/combined_keys #{@home_dir}/.ssh/authorized_keys")
190
+ run_command("chown #{@username} #{@home_dir}/.ssh/authorized_keys")
191
+ run_command("chmod 644 #{@home_dir}/.ssh/authorized_keys")
192
+ end
193
+
194
+ # Enable color
195
+ run_command("sed -i \"s/#force_color_prompt=yes/force_color_prompt=yes/g\" #{@home_dir}/.bashrc")
196
+ end
197
+ end
198
+
199
+ end
200
+ end
201
+ ```
202
+
203
+ ## Contributing
204
+
205
+ 1. Fork it ( https://github.com/Pidrock/buildserver/fork )
206
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
207
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
208
+ 4. Push to the branch (`git push origin my-new-feature`)
209
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "buildserver"
7
+ spec.version = '0.0.1'
8
+ spec.authors = ["Kasper Grubbe"]
9
+ spec.email = ["kawsper@gmail.com"]
10
+ spec.summary = %q{Lets you easily compile bash scripts from Ruby to build server instances on your favorite Linux distro.}
11
+ spec.description = %q{Build bash scripts from Ruby}
12
+ spec.homepage = "https://github.com/Pidrock/buildserver"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_development_dependency "rake", "~> 10.3"
22
+ end
@@ -0,0 +1,134 @@
1
+ require 'erb'
2
+
3
+ module Buildserver
4
+ class BuildingBlock
5
+
6
+ def build!(config, instance, other_instances)
7
+ reset!
8
+ @config = config
9
+
10
+ build(instance, other_instances)
11
+
12
+ [@build_commands, @after_build_commands]
13
+ end
14
+
15
+ def exposes_services
16
+ []
17
+ end
18
+
19
+ def external_ports
20
+ []
21
+ end
22
+
23
+ def internal_ports
24
+ []
25
+ end
26
+
27
+ private
28
+
29
+ def reset!
30
+ @config = []
31
+ @build_commands = []
32
+ @after_build_commands = []
33
+ end
34
+
35
+ def run_command(command, direction = :now)
36
+ case direction
37
+ when :after
38
+ @after_build_commands << " #{command}"
39
+ else
40
+ @build_commands << " #{command}"
41
+ end
42
+ end
43
+
44
+ ## CONFIG
45
+ ###############################################
46
+
47
+ def config(option)
48
+ @config[option]
49
+ end
50
+
51
+ ## TEMPLATING
52
+ ###############################################
53
+
54
+ def template(filename, vars = {})
55
+ # This is fucking awful :(
56
+ template_path = self.class.to_s.split("::").map(&:downcase).map {|t| t.gsub("builder","templates")}
57
+ pwd = File.join(File.join(Dir.pwd),File.join('buildingblocks'),File.join(template_path),File.join(filename))
58
+
59
+ template_file = File.open(pwd)
60
+ rendered_file = ErbTemplate.new.parse(template_file, vars)
61
+ rendered_file
62
+ end
63
+
64
+ def install_template(template, location, options = {})
65
+ run_command("touch #{location}")
66
+ run_command("chown #{options.fetch(:owners)} #{location}") if options.include?(:owners)
67
+ run_command("chmod #{options.fetch(:permission)} #{location}") if options.include?(:permission)
68
+
69
+ run_command("cat > #{location} << EOF
70
+ #{template}
71
+ EOF")
72
+ end
73
+
74
+ def append_template(template, splitter, location)
75
+ # Remove old template from file
76
+ run_command("sed -i \"/#---#{splitter.upcase}-START/,/#---#{splitter.upcase}-END/d\" #{location}")
77
+
78
+ # Put splitter in beginning and end of template
79
+ new_template = "#---#{splitter.upcase}-START\n"
80
+ new_template << template
81
+ new_template << "#---#{splitter.upcase}-END\n"
82
+
83
+ run_command("cat >> #{location} << EOF
84
+ #{new_template}
85
+ EOF")
86
+ end
87
+
88
+ ## USER
89
+ ###############################################
90
+
91
+ def if_user_exists?(username)
92
+ run_command("if id -u #{username} >/dev/null 2>&1; then")
93
+ yield if block_given?
94
+ run_command("fi")
95
+ end
96
+
97
+ def if_user_dont_exists?(username)
98
+ run_command("if ! id -u #{username} >/dev/null 2>&1; then")
99
+ yield if block_given?
100
+ run_command("fi")
101
+ end
102
+
103
+ ## DIRECTORY
104
+ ###############################################
105
+
106
+ def if_directory_exists?(path)
107
+ run_command("if [ -d \"#{path}\" ]; then")
108
+ yield if block_given?
109
+ run_command("fi")
110
+ end
111
+
112
+ def if_directory_dont_exists?(path)
113
+ run_command("if [ ! -d \"#{path}\" ]; then")
114
+ yield if block_given?
115
+ run_command("fi")
116
+ end
117
+
118
+ ## FILES
119
+ ###############################################
120
+
121
+ def if_file_exists?(path)
122
+ run_command("if [ -f #{path} ]; then")
123
+ yield if block_given?
124
+ run_command("fi")
125
+ end
126
+
127
+ def if_file_dont_exists?(path)
128
+ run_command("if [ ! -f #{path} ]; then")
129
+ yield if block_given?
130
+ run_command("fi")
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,21 @@
1
+ require 'erb'
2
+
3
+ module Buildserver
4
+
5
+ class ErbTemplate
6
+ def initialize
7
+ end
8
+
9
+ def parse(template_file, vars)
10
+ template_file.rewind
11
+ template = template_file.read
12
+
13
+ vars.each_pair do |key, value|
14
+ instance_variable_set('@' + key.to_s, value)
15
+ end
16
+
17
+ ERB.new(template).result(binding)
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,61 @@
1
+ require 'json'
2
+
3
+ module Buildserver
4
+
5
+ class Instance
6
+ attr_reader :hostname, :ip_address, :role
7
+
8
+ def initialize(hostname, ip_address, role)
9
+ @hostname = hostname
10
+ @ip_address = ip_address
11
+ @role = role.to_s
12
+ @build_blocks = []
13
+ end
14
+
15
+ def add_build_block(block)
16
+ @build_blocks << block
17
+ end
18
+
19
+ def to_s
20
+ "#{@hostname}/#{@ip_address} - #{@role}"
21
+ end
22
+
23
+ def services
24
+ @build_blocks.map{|bb| bb.exposes_services}.flatten
25
+ end
26
+
27
+ def external_ports
28
+ @build_blocks.map{|bb| bb.external_ports}.flatten
29
+ end
30
+
31
+ def internal_ports
32
+ @build_blocks.map{|bb| bb.internal_ports}.flatten
33
+ end
34
+
35
+ def has_role?(role)
36
+ @role == role.to_s
37
+ end
38
+
39
+ def build(config, instances)
40
+ @commands = []
41
+ @after_commands = []
42
+
43
+ @build_blocks.each do |build_block|
44
+ @commands << "# ! #{build_block.to_s} -------------------------------------"
45
+
46
+ commands, after_commands = build_block.build!(config, self, instances)
47
+
48
+ @commands << commands
49
+ @commands << "# / #{build_block.to_s} -------------------------------------"
50
+
51
+ @after_commands << after_commands
52
+ end
53
+
54
+ @commands << @after_commands
55
+
56
+ @commands.flatten
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,49 @@
1
+ require 'fileutils'
2
+
3
+ require_relative 'buildserver/instance'
4
+ require_relative 'buildserver/building_block'
5
+ require_relative 'buildserver/erb_template'
6
+
7
+ module Buildserver
8
+
9
+ class Buildserver
10
+ def initialize(config = {})
11
+ @instances = []
12
+
13
+ @config = config
14
+ end
15
+
16
+ def add_instance(hostname, ip_address, role)
17
+ @instances << Instance.new(hostname, ip_address, role)
18
+ end
19
+
20
+ def add_build_block(for_role, build_block)
21
+ if for_role == :base
22
+ instances = @instances
23
+ else
24
+ instances = @instances.select{|instance| instance.has_role?(for_role.to_s)}
25
+ end
26
+
27
+ instances.each do |instance|
28
+ instance.add_build_block(build_block)
29
+ end
30
+ end
31
+
32
+ def build!
33
+ FileUtils.mkdir_p("builds")
34
+ FileUtils.rm( Dir.glob("builds/*") )
35
+
36
+ @instances.each do |instance|
37
+ puts "Writing to builds/#{instance.hostname}.sh..."
38
+ commands = instance.build(@config, @instances - [instance])
39
+
40
+ file = File.new("builds/#{instance.hostname}.sh", "w")
41
+ commands.each do |command|
42
+ file.puts(command)
43
+ end
44
+ file.close
45
+ end
46
+ end
47
+
48
+ end
49
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: buildserver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kasper Grubbe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.3'
41
+ description: Build bash scripts from Ruby
42
+ email:
43
+ - kawsper@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".ruby-version"
50
+ - Gemfile
51
+ - LICENSE
52
+ - README.md
53
+ - Rakefile
54
+ - buildserver.gemspec
55
+ - lib/buildserver.rb
56
+ - lib/buildserver/building_block.rb
57
+ - lib/buildserver/erb_template.rb
58
+ - lib/buildserver/instance.rb
59
+ homepage: https://github.com/Pidrock/buildserver
60
+ licenses:
61
+ - MIT
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubyforge_project:
79
+ rubygems_version: 2.2.2
80
+ signing_key:
81
+ specification_version: 4
82
+ summary: Lets you easily compile bash scripts from Ruby to build server instances
83
+ on your favorite Linux distro.
84
+ test_files: []