taperole 1.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 +7 -0
- data/.gitignore +5 -0
- data/.tape/ansible.cfg +4 -0
- data/CONTRIBUTING.md +22 -0
- data/README.md +100 -0
- data/Vagrantfile +26 -0
- data/ansible.cfg +2 -0
- data/bin/tape +81 -0
- data/id_rsa_sb_basebox +27 -0
- data/lib/tape/ansible_runner.rb +84 -0
- data/lib/tape/installer.rb +154 -0
- data/lib/tape/qemu_provisioner.rb +167 -0
- data/lib/tape/vagrant_provisioner.rb +42 -0
- data/lib/tape.rb +76 -0
- data/requirements.yml +16 -0
- data/roles/after_deploy/tasks/main.yml +1 -0
- data/roles/backend_checkout/tasks/main.yml +21 -0
- data/roles/backend_config/defaults/main.yml +1 -0
- data/roles/backend_config/tasks/main.yml +49 -0
- data/roles/backend_config/templates/database.yml.j2 +8 -0
- data/roles/backend_config/templates/env_config.yml.j2 +2 -0
- data/roles/backend_install_essentials/meta/main.yml +5 -0
- data/roles/backend_install_essentials/tasks/main.yml +24 -0
- data/roles/backend_install_essentials/templates/memcached.j2 +7 -0
- data/roles/database_load/defaults/main.yml +3 -0
- data/roles/database_load/meta/main.yml +3 -0
- data/roles/database_load/tasks/db_reset.yml +14 -0
- data/roles/database_load/tasks/main.yml +21 -0
- data/roles/delayed_job/defaults/main.yml +2 -0
- data/roles/delayed_job/library/sudo_upstart +101 -0
- data/roles/delayed_job/tasks/main.yml +35 -0
- data/roles/delayed_job/templates/dj_runner_upstart.j2 +17 -0
- data/roles/deployer_user/files/id_rsa_digital_ocean.pub +1 -0
- data/roles/deployer_user/tasks/keys.yml +19 -0
- data/roles/deployer_user/tasks/main.yml +18 -0
- data/roles/frontend_deploy/handlers/main.yml +2 -0
- data/roles/frontend_deploy/tasks/main.yml +8 -0
- data/roles/general/meta/main.yml +3 -0
- data/roles/general/tasks/basic_packages.yml +3 -0
- data/roles/general/tasks/main.yml +6 -0
- data/roles/general/tasks/swapfile.yml +21 -0
- data/roles/monit_activate/tasks/main.yml +2 -0
- data/roles/monit_install/tasks/main.yml +19 -0
- data/roles/monit_install/templates/web_interface.j2 +2 -0
- data/roles/nginx/handlers/main.yml +2 -0
- data/roles/nginx/tasks/main.yml +30 -0
- data/roles/nginx/templates/nginx_monit.j2 +3 -0
- data/roles/nginx/templates/nginx_unicorn.j2 +55 -0
- data/roles/postgres/meta/main.yml +15 -0
- data/roles/redis/tasks/main.yml +15 -0
- data/roles/redis/templates/redis.j2 +10 -0
- data/roles/sidekiq/defaults/main.yml +2 -0
- data/roles/sidekiq/meta/main.yml +3 -0
- data/roles/sidekiq/tasks/main.yml +19 -0
- data/roles/sidekiq/templates/sidekiq.j2 +4 -0
- data/roles/unicorn_activate/defaults/main.yml +3 -0
- data/roles/unicorn_activate/tasks/main.yml +25 -0
- data/roles/unicorn_install/tasks/main.yml +24 -0
- data/roles/unicorn_install/templates/unicorn.rb.j2 +47 -0
- data/roles/unicorn_install/templates/unicorn_init.j2 +70 -0
- data/roles/unicorn_install/templates/unicorn_monit.j2 +5 -0
- data/taperole.gemspec +11 -0
- data/templates/base/deploy.example.yml +17 -0
- data/templates/base/hosts.example +7 -0
- data/templates/base/omnibox.example.yml +25 -0
- data/templates/base/tape_vars.example.yml +13 -0
- data/templates/static_html/deploy.example.yml +12 -0
- data/templates/static_html/omnibox.example.yml +15 -0
- data/templates/static_html/tape_vars.example.yml +7 -0
- data/vars/defaults.yml +31 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 62490a5daeb6150d42dc9e9739557f820e0ae934
|
4
|
+
data.tar.gz: a93676ee597a4c57cb5cc3fe4097fb0023cb0a37
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 097f949627f97b9e2a6e6fd33c0526f7157db46717f46e92fba432f53c920ee2ac9e1de67699fba2b55ef6515b1c6c752b282bf8a0e95e575d710ccd5b8c7aef
|
7
|
+
data.tar.gz: 1c90655f1b208db25fdfcd3fbdb6c695e4e0e61967be845d94b527db959c738739872b8e7117cc07541f012273dc7b6d06df3c6ad1ab39dbe23f1c36ec5b1de1
|
data/.gitignore
ADDED
data/.tape/ansible.cfg
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#Contributor Guidelines
|
2
|
+
|
3
|
+
##Submitting a Pull Request
|
4
|
+
|
5
|
+
###Workflow
|
6
|
+
We use [Waffle.io](https://waffle.io/smashingboxes/tape) to manage our workflow for this project. Please respect the workflow and move PRs that are ready to be mereged into the 'Ready' column.
|
7
|
+
|
8
|
+
###PR Structure
|
9
|
+
|
10
|
+
Please give details regarding your PR in the following format. It really helps with review and quickens the speed at which your changes are merged in
|
11
|
+
|
12
|
+

|
13
|
+
|
14
|
+
##Opening Issues
|
15
|
+
|
16
|
+
###Basic details
|
17
|
+
|
18
|
+
Please include the following in the Issues you open
|
19
|
+
|
20
|
+
* OS Version
|
21
|
+
* ansible version
|
22
|
+
* tape version
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
[](https://waffle.io/smashingboxes/tape)
|
2
|
+
# Infrastructure Management
|
3
|
+
|
4
|
+
## Deploying & provisioning with tape
|
5
|
+
**Use Unbuntu precise64 (12.04 x64)**
|
6
|
+
|
7
|
+
**Enable ssh access via root user**
|
8
|
+
|
9
|
+
### Basics
|
10
|
+
|
11
|
+
**Install**
|
12
|
+
|
13
|
+
* Add the following to your gemfile.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'tape', github: 'smashingboxes/tape', group: :development, tag: <DESIRED_VERSION>
|
17
|
+
```
|
18
|
+
|
19
|
+
* `bundle install`
|
20
|
+
* `tape installer install`
|
21
|
+
* Updated the hosts file with the IP address of your server
|
22
|
+
|
23
|
+
```
|
24
|
+
[omnibox]
|
25
|
+
0.0.0.0
|
26
|
+
```
|
27
|
+
|
28
|
+
* Fill in missing values in `tape_vars.yml`
|
29
|
+
* Copy all developers public keys into some dir and specify that dir inside `tape_vars.yml` (dev_key_files)
|
30
|
+
* `tape ansible everything`
|
31
|
+
|
32
|
+
**Upgrade**
|
33
|
+
|
34
|
+
```
|
35
|
+
bundle upgrade tape
|
36
|
+
tape installer install
|
37
|
+
```
|
38
|
+
|
39
|
+
### Custom roles
|
40
|
+
You can write app specific roles in the roles files storred in the `roles` directory
|
41
|
+
|
42
|
+
You must then specify the roles you want to use in `omnibox.yml` or `deploy.yml`
|
43
|
+
|
44
|
+
[Read the Ansible docs on playbook roles here](http://docs.ansible.com/playbooks_roles.html)
|
45
|
+
|
46
|
+
### Multistage
|
47
|
+
You can setup multistage by defining your hosts file as follows
|
48
|
+
|
49
|
+
```
|
50
|
+
[production]
|
51
|
+
0.0.0.0 be_app_env=SOME_ENV be_app_branch=SOME_BRANCH
|
52
|
+
[staging]
|
53
|
+
0.0.0.0 be_app_env=SOME_ENV be_app_branch=SOME_BRANCH
|
54
|
+
[omnibox:children]
|
55
|
+
production
|
56
|
+
staging
|
57
|
+
```
|
58
|
+
|
59
|
+
then use the `-l` option to specify the staging
|
60
|
+
|
61
|
+
```sh
|
62
|
+
tape ansible deploy -l staging
|
63
|
+
```
|
64
|
+
|
65
|
+
## Testing
|
66
|
+
### With vagrant
|
67
|
+
|
68
|
+
|
69
|
+
1. `vagrant up` or `tape vagrant create`
|
70
|
+
2. Put the following into your [hosts inventory file](http://docs.ansible.com/intro_inventory.html):
|
71
|
+
|
72
|
+
```
|
73
|
+
[vagrant]
|
74
|
+
<192.168.13.37> ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key
|
75
|
+
```
|
76
|
+
|
77
|
+
The port number might be different if other vagrant machines are running, run `vagrant ssh-config` to find the correct configuration.
|
78
|
+
You can speicfy a port using the `ansible_ssh_port` in your hosts inventory file.
|
79
|
+
|
80
|
+
3. Update `tape_vars.yml` with information to a [rails app you want to deploy](https://github.com/BrandonMathis/vanilla-rails-app)
|
81
|
+
4. `tape ansible everything -l vagrant`
|
82
|
+
|
83
|
+
|
84
|
+
### With QEMU
|
85
|
+
|
86
|
+
1. `tape qemu create --name fe_test`
|
87
|
+
2. `tape qemu start --name fe_test -p2255`
|
88
|
+
3. `ssh-add ./id_rsa_sb_basebox`
|
89
|
+
4. `echo 'localhost:2255' >test_hosts`
|
90
|
+
5. `tape ansible everything`
|
91
|
+
|
92
|
+
Run `tape -h` for a quick rundown of the tool's modules and options.
|
93
|
+
|
94
|
+
## Development
|
95
|
+
|
96
|
+
```sh
|
97
|
+
git clone git@github.com:smashingboxes/tape.git
|
98
|
+
cd tape
|
99
|
+
ansible-galaxy install -r requirements.yml --force
|
100
|
+
```
|
data/Vagrantfile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure 2 do |config|
|
5
|
+
config.vm.box = 'hashicorp/precise64'
|
6
|
+
|
7
|
+
name = %x[basename `git rev-parse --show-toplevel`].chomp
|
8
|
+
config.vm.define "#{name}_vagrant_box"
|
9
|
+
|
10
|
+
# private_ip = "192.168.13.37"
|
11
|
+
# config.vm.network(:private_network, :ip => private_ip)
|
12
|
+
|
13
|
+
# TODO free me from the bonds of this ip
|
14
|
+
config.vm.network 'forwarded_port', guest: 80, host: 8080
|
15
|
+
config.vm.network 'private_network', type: 'dhcp'
|
16
|
+
|
17
|
+
config.ssh.insert_key = false
|
18
|
+
config.ssh.shell = 'bash -c "BASH_ENV=/etc/profile exec bash"'
|
19
|
+
|
20
|
+
config.vm.provision :shell, inline: <<-SCRIPT
|
21
|
+
sudo su
|
22
|
+
mkdir ~/.ssh/
|
23
|
+
cp /home/vagrant/.ssh/authorized_keys ~/.ssh/
|
24
|
+
chmod 600 ~/.ssh/authorized_keys
|
25
|
+
SCRIPT
|
26
|
+
end
|
data/ansible.cfg
ADDED
data/bin/tape
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << File.join(__dir__, '..', 'lib')
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'ostruct'
|
7
|
+
require 'tape'
|
8
|
+
|
9
|
+
options = OpenStruct.new
|
10
|
+
opt_parser = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: tape <module> <action> [options]"
|
12
|
+
|
13
|
+
opts.on("-v", "--[no-]verbose", "Be loud") {|v| options.verbose = v}
|
14
|
+
|
15
|
+
opts.on("-i", "--inventory [INVENTORY_FILE]",
|
16
|
+
String, "Do actions with the given inventory file") do |i|
|
17
|
+
options.inventory_file = i
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on('-n', "--name [NAME]",
|
21
|
+
String, "The name of the machine to operate on") do |n|
|
22
|
+
options.name = n
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('-p', "--port [PORT]",
|
26
|
+
Integer, "The port that the machine is listening on for SSH connections") do |p|
|
27
|
+
options.port = p
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-h", "--help", "Show this help") do
|
31
|
+
STDERR.puts opts
|
32
|
+
exit 0
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-l", "--limit [PATTERN]",
|
36
|
+
String, "Limits ansible runs to hosts matching PATTERN") do |p|
|
37
|
+
options.host_pattern = p
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on("-t", "--tags [TAGS]",
|
41
|
+
String, "only run plays and tasks tagged with these values") do |t|
|
42
|
+
options.tags = t
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.separator ''
|
46
|
+
opts.separator "MODULES"
|
47
|
+
TapeBoxer.registered_modules.values.each do |exec_module|
|
48
|
+
opts.separator " #{exec_module.name.to_s.upcase}"
|
49
|
+
exec_module.klass.actions.values.each do |action|
|
50
|
+
opts.separator " #{action.name}: #{action.description}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
opt_parser.parse!(ARGV)
|
57
|
+
|
58
|
+
fail_without = ->(&block){
|
59
|
+
val = block.call
|
60
|
+
|
61
|
+
if val
|
62
|
+
return val
|
63
|
+
else
|
64
|
+
STDERR.puts(opt_parser.help)
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
}
|
68
|
+
|
69
|
+
module_name = fail_without.call{ ARGV.shift }.to_sym
|
70
|
+
action_name = fail_without.call{ ARGV.shift }.to_sym
|
71
|
+
|
72
|
+
exec_module = fail_without.call{TapeBoxer.registered_modules[module_name]}
|
73
|
+
|
74
|
+
begin
|
75
|
+
exec_module.klass.new(options).execute_action(action_name)
|
76
|
+
rescue TapeBoxer::InvalidAction,
|
77
|
+
TapeBoxer::ActionError, TapeBoxer::UnspecifiedOption => e
|
78
|
+
|
79
|
+
STDERR.puts(e.message)
|
80
|
+
exit 2
|
81
|
+
end
|
data/id_rsa_sb_basebox
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIIEowIBAAKCAQEAzdGlX5Ostx5Tuq8s3ZlImcs3lw5SmDbRi4SCdbnKKeTQJ/M6
|
3
|
+
Tjfluj3SVy1ZwzL0gQWLLS9aGBX8/6XRCyddBuBDkkK7Tl+7Xvaz4IuXbl6JOgYr
|
4
|
+
zYa4i8SM+mKxUwjfNTgK7df//K4Htzs9dW19CpYvzAnRDE1ghT5RBkLinfuTb3+z
|
5
|
+
IjvYWKsovJTiv624OWeRZxWSvIyalfsRKlGBvbjJC5PlAxOzrVbnyEeNh5JAGtiP
|
6
|
+
lG/sikqtz0Vd08jXRlwsG/pz65hzWKN8XwTZvKIjXJgdwXyY8VJOjHnsdWOV9JSN
|
7
|
+
m5+/nHVpZLBh8u1Ms3As4FngCvsO9Z8dU+f+4QIDAQABAoIBAEjAuJJGYyD/qV0u
|
8
|
+
Gs/iJRWoDehpeaywg/WrS2pN2DZi2WmlwpBvldb1j2qdb0Neuar5yK6aNGCbNSkw
|
9
|
+
9enZajrJ/1iuGgOkN1lkH0VaUpcC98L493bZDlbpjWPciw3s7umi+8oDNkudQMD2
|
10
|
+
Qc1GfJLHb/HR7oFIwLuYwY9TCUQKTU8KP77HSwKto1MMEBrA+wHd5G6eLKLC+Gvh
|
11
|
+
XXkiG2nafs/xgKX6aq4YKcKBJJO7f4tAIeqQZL1x9dJQqhtopj31P8Hv7xNh1zxc
|
12
|
+
V61O7gCNM/kP7Mur3XYUFPvLnQOUfPaZCUzxWoJphh5UzBkJyCq4pquA6Q6cx/Im
|
13
|
+
NLha5oECgYEA6cCTUCmC7yiKcgUUcw1RFYE91bgxlSo6dliGev9eXbP84N3IReCV
|
14
|
+
8+0TZqTjLKVVANYOBGf3uYC8o0CO6c9Q4t/7bYt0/TuZD/PciCCSNt2GLsr/LVHB
|
15
|
+
Qoum6kytm4ZRJDWUPUVv+89xYhXgwogdrZXZc5yR/K0sJUnl+S8St8kCgYEA4Wh4
|
16
|
+
Gkp8YKsSCdUaKR46AWRpOh6P4YllcfBj7eeW5+Dp78yLw6bjfxOqNgfMtP3oyKR4
|
17
|
+
tic0u0tBIvn3GFFwca+PpYhejdXNivmXGq6bADu+qOQJXtCpOVWhA6rqslJEuAnb
|
18
|
+
yAmvwoWEecti4Rqx52z3wV/PWiqfkMTUI7IWSlkCgYBSU7sOnrA430RziAp9wxDt
|
19
|
+
zAklPqxn5umUSPWEWHC5++xynmotAj6OHM+adTR1wv0/QCTLtHpxYUAPF2u+OYA5
|
20
|
+
h72cBWP81ILCNZdUcnRM0pSx4lkhcwvoDhuJpdv3TMVDRYOiWNRqEdPTQfVZTmt1
|
21
|
+
ebOOnnRkU/GaaH6Q1t120QKBgQCF8M0FWmOEEcNbQl0UN9jiAOeiWIzIyRsV1HGc
|
22
|
+
6bO7P+Pi0ZnvfdjLJ0VKa+IRXpuXtlvgaXWlIben7/8LXUFC3L6v71O4VmaYAW3v
|
23
|
+
tfd28Ql/VFnZFIaqAh72jfZ+VfJtpbYKrO7a2Pn6YYf1GSbDzPV/283b114P6VXh
|
24
|
+
jC5AqQKBgEF8TyZNb5ERgfsbzS9TerP+MbJ4jC7lVrOUZlQeF8URbq81aERIM4Or
|
25
|
+
18RwSXyAywObJWCXYdPdEFjYYaSBw7rSub87/bNiQHZoyTC08R8ZEAIub58HTNav
|
26
|
+
taWNCo22rsYcaJysHeIqKhl6iFOYhdOucLFZJZO4Vi/PkGQ9v5V7
|
27
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Executes ansible commands
|
2
|
+
module TapeBoxer
|
3
|
+
class AnsibleRunner < ExecutionModule
|
4
|
+
TapeBoxer.register_module :ansible, self
|
5
|
+
|
6
|
+
action :configure_dj_runner,
|
7
|
+
proc {ansible '-t configure_dj_runner -e force_dj_runner_restart=true'},
|
8
|
+
"Configures and restarts the delayed job runner"
|
9
|
+
action :restart_unicorn,
|
10
|
+
proc {ansible '-t unicorn_restart'},
|
11
|
+
"Restarts the unicorns running on the app servers"
|
12
|
+
action :stop_unicorn,
|
13
|
+
proc {ansible '-t unicorn_stop -e kill_unicorn=true'},
|
14
|
+
"Stops the unicorns running on the app servers"
|
15
|
+
action :force_stop_unicorn,
|
16
|
+
proc {ansible '-t unicorn_force_stop -e kill_unicorn=true'},
|
17
|
+
"Stops the unicorns running on the app servers"
|
18
|
+
action :start_unicorn,
|
19
|
+
proc {ansible '-t unicorn_start'},
|
20
|
+
"Starts the unicorns running on the app servers"
|
21
|
+
action :restart_nginx,
|
22
|
+
proc {ansible '-t restart_nginx'},
|
23
|
+
"Restarts Nginx"
|
24
|
+
action :configure_deployer_user,
|
25
|
+
proc {ansible '-t deployer'},
|
26
|
+
"Ensures the deployer user is present and configures his SSH keys"
|
27
|
+
action :reset_db,
|
28
|
+
proc {ansible '-t db_reset -e force_db_reset=true'},
|
29
|
+
"wipes and re-seeds the DB"
|
30
|
+
action :bundle,
|
31
|
+
proc {ansible '-t bundle -e force_bundle=true'},
|
32
|
+
"Bundles the gems running on the app servers"
|
33
|
+
action :fe_deploy,
|
34
|
+
proc {ansible_deploy '-t fe_deploy'},
|
35
|
+
"Re-deploys fe code"
|
36
|
+
action :deploy,
|
37
|
+
proc {ansible_deploy '-t be_deploy'},
|
38
|
+
"Checks out app code, installs dependencies and restarts unicorns for "\
|
39
|
+
"both FE and BE code."
|
40
|
+
action :everything, proc {ansible}, "This does it all."
|
41
|
+
|
42
|
+
def initialize(*args)
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
attr_reader :opts
|
48
|
+
|
49
|
+
def ansible(cmd_str = '')
|
50
|
+
exec_ansible('omnibox.yml', cmd_str)
|
51
|
+
end
|
52
|
+
|
53
|
+
def ansible_deploy(cmd_str = '')
|
54
|
+
exec_ansible('deploy.yml', cmd_str)
|
55
|
+
end
|
56
|
+
|
57
|
+
def exec_ansible(playbook, args)
|
58
|
+
enforce_roles_path!
|
59
|
+
cmd = "ANSIBLE_CONFIG=#{local_dir}/.tape/ansible.cfg ansible-playbook -i #{inventory_file} #{playbook} #{args} #{hosts_flag} -e tape_dir=#{tape_dir}"
|
60
|
+
cmd += ' -vvvv' if opts.verbose
|
61
|
+
cmd += " -t #{opts.tags}" if opts.tags
|
62
|
+
STDERR.puts "Executing: #{cmd}" if opts.verbose
|
63
|
+
Kernel.exec(cmd)
|
64
|
+
end
|
65
|
+
|
66
|
+
def enforce_roles_path!
|
67
|
+
Dir.mkdir('.tape') unless Dir.exists?('.tape')
|
68
|
+
File.open('.tape/ansible.cfg', 'w') do |f|
|
69
|
+
f.puts '[defaults]'
|
70
|
+
f.puts "roles_path=./roles:#{tape_dir}/roles:#{tape_dir}/vendor"
|
71
|
+
f.puts '[ssh_connection]'
|
72
|
+
f.puts 'ssh_args = -o ForwardAgent=yes'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def hosts_flag
|
77
|
+
"-l #{opts.host_pattern}" if opts.host_pattern
|
78
|
+
end
|
79
|
+
|
80
|
+
def inventory_file
|
81
|
+
opts.inventory_file || "#{local_dir}/hosts"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module TapeBoxer
|
2
|
+
class Installer < ExecutionModule
|
3
|
+
TapeBoxer.register_module :installer, self
|
4
|
+
|
5
|
+
action :dependencies,
|
6
|
+
proc { dependencies },
|
7
|
+
'Install dependencies'
|
8
|
+
action :install,
|
9
|
+
proc {install},
|
10
|
+
'Creates all nessisary hosts and config files'
|
11
|
+
action :uninstall,
|
12
|
+
proc {uninstall},
|
13
|
+
'Cleans up files generated by the installer'
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def dependencies
|
22
|
+
puts 'Dependencies:'
|
23
|
+
|
24
|
+
if system "ansible-galaxy install -r #{tape_dir}/requirements.yml -p #{tape_dir}/vendor --force"
|
25
|
+
print 'Installing/updating dependencies: '
|
26
|
+
puts '✔'.green
|
27
|
+
else
|
28
|
+
puts '✘'.red
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def install
|
33
|
+
dependencies
|
34
|
+
File.open('.gitignore', 'r+') { |f| f.puts '.tape' unless f.read =~/^\.tape$/ }
|
35
|
+
mkdir 'roles'
|
36
|
+
if fe_app? && !rails_app?
|
37
|
+
puts '🔎 JS/HTML app detected'.pink
|
38
|
+
copy_static_app_examples
|
39
|
+
else rails_app?
|
40
|
+
puts '🔎 Rails app detected'.pink
|
41
|
+
copy_basic_examples
|
42
|
+
end
|
43
|
+
copy_example 'templates/base/hosts.example', 'hosts'
|
44
|
+
mkdir 'dev_keys'
|
45
|
+
print 'Are you going to use vagrant? (y/n): '
|
46
|
+
if gets.chomp == 'y'
|
47
|
+
copy_example 'Vagrantfile', 'Vagrantfile'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def fe_app?
|
52
|
+
!Dir["#{local_dir}/gulpfile.*"].empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def rails_app?
|
56
|
+
!Dir["#{local_dir}/config.ru"].empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
def copy_static_app_examples
|
60
|
+
copy_example 'templates/static_html/omnibox.example.yml', 'omnibox.yml'
|
61
|
+
copy_example 'templates/static_html/deploy.example.yml', 'deploy.yml'
|
62
|
+
copy_example 'templates/static_html/tape_vars.example.yml', 'tape_vars.yml'
|
63
|
+
end
|
64
|
+
|
65
|
+
def copy_basic_examples
|
66
|
+
copy_example 'templates/base/omnibox.example.yml', 'omnibox.yml'
|
67
|
+
copy_example 'templates/base/deploy.example.yml', 'deploy.yml'
|
68
|
+
copy_example 'templates/base/tape_vars.example.yml', 'tape_vars.yml'
|
69
|
+
end
|
70
|
+
|
71
|
+
def uninstall
|
72
|
+
rm 'omnibox.yml'
|
73
|
+
rm 'deploy.yml'
|
74
|
+
rm 'tape_vars.yml'
|
75
|
+
rm 'roles'
|
76
|
+
rm 'hosts'
|
77
|
+
rm 'dev_keys'
|
78
|
+
rm 'Vagrantfile'
|
79
|
+
end
|
80
|
+
|
81
|
+
def rm(file)
|
82
|
+
print 'Deleting '.red
|
83
|
+
FileUtils.rm_r "#{local_dir}/#{file}"
|
84
|
+
puts file
|
85
|
+
end
|
86
|
+
|
87
|
+
def mkdir(name)
|
88
|
+
print "#{name}: "
|
89
|
+
begin
|
90
|
+
FileUtils.mkdir name
|
91
|
+
success
|
92
|
+
rescue Errno::EEXIST
|
93
|
+
exists
|
94
|
+
rescue Exception => e
|
95
|
+
error
|
96
|
+
raise e
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def touch(file)
|
101
|
+
File.new "#{local_dir}/#{file}", 'w'
|
102
|
+
end
|
103
|
+
|
104
|
+
def copy_example(file, cp_file)
|
105
|
+
print "#{cp_file}: "
|
106
|
+
begin
|
107
|
+
if File.exists?("#{local_dir}/#{cp_file}")
|
108
|
+
exists
|
109
|
+
else
|
110
|
+
FileUtils.cp("#{tape_dir}/#{file}", "#{local_dir}/#{cp_file}")
|
111
|
+
success
|
112
|
+
end
|
113
|
+
rescue Exception => e
|
114
|
+
error
|
115
|
+
raise e
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def success
|
120
|
+
puts '✔'.green
|
121
|
+
end
|
122
|
+
|
123
|
+
def error
|
124
|
+
puts '✘'.red
|
125
|
+
end
|
126
|
+
|
127
|
+
def exists
|
128
|
+
puts '✘ (Exists)'.yellow
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class String
|
134
|
+
# colorization
|
135
|
+
def colorize(color_code)
|
136
|
+
"\e[#{color_code}m#{self}\e[0m"
|
137
|
+
end
|
138
|
+
|
139
|
+
def red
|
140
|
+
colorize(31)
|
141
|
+
end
|
142
|
+
|
143
|
+
def green
|
144
|
+
colorize(32)
|
145
|
+
end
|
146
|
+
|
147
|
+
def yellow
|
148
|
+
colorize(33)
|
149
|
+
end
|
150
|
+
|
151
|
+
def pink
|
152
|
+
colorize(35)
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
module TapeBoxer
|
3
|
+
class QemuProvisioner < ExecutionModule
|
4
|
+
BASE_IMG = File.realpath(File.join(__dir__, ''))
|
5
|
+
HOSTED_IMG_PATH = 'http://d.pr/f/17cOG/434tIaDx+'
|
6
|
+
PIDFILE_DIR = "/tmp/tape"
|
7
|
+
BOXIMG_DIR = File.join(ENV['HOME'], '.tape', 'boxes')
|
8
|
+
BOXLOG_DIR = '/tmp/tape'
|
9
|
+
DEFAULT_PORT = 2255
|
10
|
+
|
11
|
+
TapeBoxer.register_module :qemu, self
|
12
|
+
|
13
|
+
action :create,
|
14
|
+
proc {create_img},
|
15
|
+
'Creates a new qemu box with the given name'
|
16
|
+
action :start,
|
17
|
+
proc {start_box},
|
18
|
+
'Ensures the qemu box by the given name is running'
|
19
|
+
action :ssh,
|
20
|
+
proc {ssh_to_box},
|
21
|
+
'SSHes to the box by the given name. Requires id_rsa_sb_basebox
|
22
|
+
key to be added to the current SSH agent'
|
23
|
+
action :reset,
|
24
|
+
proc {reset_box},
|
25
|
+
'Destroys and re-creates the box by the given name'
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def ssh_to_box
|
30
|
+
require_opt :name
|
31
|
+
ensure_box_running
|
32
|
+
Kernel.exec("ssh root@127.0.0.1 -p #{port}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_img
|
36
|
+
require_opt :name
|
37
|
+
img_name = opts[:name] + '.img'
|
38
|
+
|
39
|
+
if File.exists?(image_path)
|
40
|
+
STDERR.puts "That image already exists!"
|
41
|
+
exit 1
|
42
|
+
else
|
43
|
+
Kernel.exec "qemu-img create -b '#{base_image_path}' -fqcow2 '#{image_path}'"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_box
|
48
|
+
require_opt :name
|
49
|
+
ensure_box_created
|
50
|
+
ensure_box_not_running
|
51
|
+
|
52
|
+
cmd = "qemu-system-x86_64 -m 512 "\
|
53
|
+
"-netdev user,hostfwd=tcp:127.0.0.1:#{qemu_port}-:22,id=net.0 "\
|
54
|
+
"-device e1000,netdev=net.0 "\
|
55
|
+
"-nographic -enable-kvm #{image_path}"
|
56
|
+
|
57
|
+
pid = Process.spawn(cmd, out: boxlog_path)
|
58
|
+
|
59
|
+
write_pidfile(pid)
|
60
|
+
Process.detach(pid)
|
61
|
+
end
|
62
|
+
|
63
|
+
def qemu_port
|
64
|
+
opts.port || DEFAULT_PORT
|
65
|
+
end
|
66
|
+
|
67
|
+
def reset_box
|
68
|
+
require_opt :name
|
69
|
+
ensure_box_created
|
70
|
+
|
71
|
+
File.delete(image_path)
|
72
|
+
create_img
|
73
|
+
end
|
74
|
+
|
75
|
+
def ensure_box_created
|
76
|
+
unless File.exists?(image_path)
|
77
|
+
raise ActionError, "The machine (#{opts.name}) has not yet been created!"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def ensure_box_running
|
82
|
+
unless pidfile_present? and process_alive?(read_pidfile)
|
83
|
+
raise ActionError, "The machine(#{opts.name}) needs to be "\
|
84
|
+
"running before you can do this!"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def port
|
89
|
+
opts.port or 2255
|
90
|
+
end
|
91
|
+
|
92
|
+
def ensure_box_not_running
|
93
|
+
if pidfile_present? and process_alive?(read_pidfile)
|
94
|
+
raise ActionError, "The machine (#{opts.name}) is already running!"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def process_alive?(pid)
|
99
|
+
Process.kill(0, pid)
|
100
|
+
rescue Errno::ESRCH
|
101
|
+
return false
|
102
|
+
end
|
103
|
+
|
104
|
+
def base_image_path
|
105
|
+
img = "sb_ubuntu_12.04_x64_base.img"
|
106
|
+
path = File.join(image_dir, img)
|
107
|
+
unless File.exists?(path)
|
108
|
+
print 'base image #{path} not found. Dow you want to download (y/n) '
|
109
|
+
if STDOUT.flush and gets.chomp.downcase == 'y'
|
110
|
+
%x[curl -0L #{HOSTED_IMG_PATH} > #{image_dir}/#{img}]
|
111
|
+
path = File.join(image_dir, img)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
return path
|
116
|
+
end
|
117
|
+
|
118
|
+
def pidfile_present?
|
119
|
+
File.exists? pidfile_path
|
120
|
+
end
|
121
|
+
|
122
|
+
def image_path
|
123
|
+
File.expand_path(File.join(image_dir, "qemu-#{opts.name}.img"))
|
124
|
+
end
|
125
|
+
|
126
|
+
def delete_pidfile
|
127
|
+
File.delete(pidfile_path)
|
128
|
+
end
|
129
|
+
|
130
|
+
def write_pidfile(pid)
|
131
|
+
File.open(pidfile_path, 'w').write(pid.to_s)
|
132
|
+
end
|
133
|
+
|
134
|
+
def read_pidfile
|
135
|
+
STDERR.puts "Reading pidfile #{pidfile_path}" if opts.verbose
|
136
|
+
pid = File.open(pidfile_path, 'r').read.to_i
|
137
|
+
|
138
|
+
unless pid > 0
|
139
|
+
raise ActionError, "Pidfile (#{pidfile_path}) does not appear to be numeric!"
|
140
|
+
end
|
141
|
+
|
142
|
+
return pid
|
143
|
+
end
|
144
|
+
|
145
|
+
def boxlog_path
|
146
|
+
@boxlog_path ||=
|
147
|
+
File.expand_path(File.join(boxlog_dir, "qemu-#{opts.name}.log"))
|
148
|
+
end
|
149
|
+
|
150
|
+
def pidfile_path
|
151
|
+
@pidfile_path ||=
|
152
|
+
File.expand_path(File.join(pidfile_dir, "qemu-#{opts[:name]}.pid"))
|
153
|
+
end
|
154
|
+
|
155
|
+
def boxlog_dir
|
156
|
+
FileUtils.mkdir_p(PIDFILE_DIR) && PIDFILE_DIR
|
157
|
+
end
|
158
|
+
|
159
|
+
def pidfile_dir
|
160
|
+
FileUtils.mkdir_p(PIDFILE_DIR) && PIDFILE_DIR
|
161
|
+
end
|
162
|
+
|
163
|
+
def image_dir
|
164
|
+
FileUtils.mkdir_p(BOXIMG_DIR) && BOXIMG_DIR
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|