subspace 2.5.10 → 3.0.0.rc1
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 +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +12 -5
- data/README.md +57 -24
- data/UPGRADING.md +10 -0
- data/ansible/roles/common/defaults/main.yml +0 -1
- data/ansible/roles/common/files/sudoers-service +1 -1
- data/ansible/roles/common/tasks/main.yml +18 -7
- data/ansible/roles/common/tasks/no_swap.yml +26 -0
- data/ansible/roles/common/templates/motd +1 -1
- data/ansible/roles/common/templates/motd2 +1 -1
- data/ansible/roles/delayed_job/tasks/main.yml +1 -1
- data/ansible/roles/memcache/defaults/main.yml +2 -0
- data/ansible/roles/memcache/tasks/main.yml +16 -1
- data/ansible/roles/newrelic-infra/tasks/main.yml +3 -3
- data/ansible/roles/nginx/tasks/main.yml +12 -3
- data/ansible/roles/puma/tasks/main.yml +32 -20
- data/ansible/roles/puma/templates/puma-systemd.service +36 -0
- data/ansible/roles/puma/templates/puma-systemd.socket +14 -0
- data/ansible/roles/puma/templates/puma.rb +4 -2
- data/ansible/roles/rails/defaults/main.yml +0 -7
- data/ansible/roles/redis/tasks/main.yml +7 -0
- data/ansible/roles/resque/tasks/main.yml +11 -12
- data/ansible/roles/resque/templates/resque-systemd.service +10 -3
- data/ansible/roles/ruby-common/README.md +1 -1
- data/ansible/roles/ruby-common/tasks/main.yml +2 -17
- data/ansible/roles/sidekiq/defaults/main.yml +1 -1
- data/ansible/roles/sidekiq/tasks/main.yml +11 -15
- data/ansible/roles/sidekiq/templates/sidekiq-monit-rc +1 -1
- data/ansible/roles/sidekiq/templates/sidekiq-systemd.service +62 -0
- data/ansible/roles/tailscale/defaults/main.yml +2 -0
- data/ansible/roles/tailscale/tasks/main.yml +22 -0
- data/exe/subspace +1 -2
- data/lib/subspace/cli.rb +50 -14
- data/lib/subspace/commands/ansible.rb +11 -2
- data/lib/subspace/commands/base.rb +20 -5
- data/lib/subspace/commands/bootstrap.rb +16 -21
- data/lib/subspace/commands/configure.rb +2 -2
- data/lib/subspace/commands/exec.rb +20 -0
- data/lib/subspace/commands/init.rb +94 -45
- data/lib/subspace/commands/inventory.rb +45 -0
- data/lib/subspace/commands/maintain.rb +1 -1
- data/lib/subspace/commands/provision.rb +1 -3
- data/lib/subspace/commands/{vars.rb → secrets.rb} +6 -5
- data/lib/subspace/commands/ssh.rb +10 -8
- data/lib/subspace/commands/terraform.rb +83 -0
- data/lib/subspace/inventory.rb +144 -0
- data/lib/subspace/version.rb +1 -1
- data/subspace.gemspec +8 -2
- data/template/{provision → subspace}/.gitignore +3 -0
- data/template/{provision → subspace}/ansible.cfg.erb +2 -2
- data/template/subspace/group_vars/all.erb +28 -0
- data/template/subspace/group_vars/template.erb +26 -0
- data/template/subspace/inventory.yml.erb +11 -0
- data/template/{provision → subspace}/playbook.yml.erb +2 -5
- data/template/subspace/templates/authorized_keys.erb +1 -0
- data/template/subspace/terraform/.gitignore +2 -0
- data/template/subspace/terraform/template/main-oxenwagen.tf.erb +116 -0
- data/template/subspace/terraform/template/main-workhorse.tf.erb +41 -0
- data/template/subspace/terraformrc.erb +9 -0
- data/terraform/modules/s3_backend/README +2 -0
- data/terraform/modules/s3_backend/dynamodb.tf +1 -0
- data/terraform/modules/s3_backend/iam_user.tf +38 -0
- data/terraform/modules/s3_backend/main.tf +39 -0
- data/terraform/modules/s3_backend/state_bucket.tf +14 -0
- metadata +42 -53
- data/ansible/roles/monit/files/monit-http.conf +0 -3
- data/ansible/roles/monit/files/sudoers-monit +0 -1
- data/ansible/roles/monit/handlers/main.yml +0 -14
- data/ansible/roles/monit/tasks/main.yml +0 -34
- data/ansible/roles/mtpereira.passenger/.bumpversion.cfg +0 -7
- data/ansible/roles/mtpereira.passenger/.gitignore +0 -2
- data/ansible/roles/mtpereira.passenger/LICENSE +0 -20
- data/ansible/roles/mtpereira.passenger/README.md +0 -31
- data/ansible/roles/mtpereira.passenger/defaults/main.yml +0 -5
- data/ansible/roles/mtpereira.passenger/handlers/main.yml +0 -8
- data/ansible/roles/mtpereira.passenger/meta/.galaxy_install_info +0 -1
- data/ansible/roles/mtpereira.passenger/meta/main.yml +0 -21
- data/ansible/roles/mtpereira.passenger/tasks/apt.yml +0 -13
- data/ansible/roles/mtpereira.passenger/tasks/main.yml +0 -8
- data/ansible/roles/mtpereira.passenger/tasks/pkg.yml +0 -35
- data/ansible/roles/mtpereira.passenger/tasks/service.yml +0 -8
- data/ansible/roles/passenger/files/sudoers-passenger +0 -1
- data/ansible/roles/passenger/meta/main.yml +0 -6
- data/ansible/roles/passenger/tasks/main.yml +0 -5
- data/ansible/roles/postgis/defaults/main.yml +0 -2
- data/ansible/roles/puma/defaults/main.yml +0 -5
- data/ansible/roles/puma/meta/main.yml +0 -5
- data/ansible/roles/sidekiq/meta/main.yml +0 -5
- data/template/provision/group_vars/all.erb +0 -17
- data/template/provision/group_vars/template.erb +0 -11
- data/template/provision/host_vars/template.erb +0 -4
- /data/template/{provision → subspace}/hosts.erb +0 -0
- /data/template/{provision/vars → subspace/secrets}/template.erb +0 -0
- /data/template/{provision → subspace}/templates/application.yml.template +0 -0
|
@@ -15,11 +15,13 @@ After=syslog.target network.target
|
|
|
15
15
|
#
|
|
16
16
|
# !!!! !!!! !!!!
|
|
17
17
|
#
|
|
18
|
-
Type=
|
|
18
|
+
Type=forking
|
|
19
19
|
|
|
20
20
|
WorkingDirectory=/u/apps/{{project_name}}/current
|
|
21
21
|
|
|
22
|
-
ExecStart
|
|
22
|
+
ExecStart=/usr/local/bin/bundle exec rake resque:work
|
|
23
|
+
ExecStop=/bin/kill -s QUIT $MAINPID
|
|
24
|
+
PIDFile=/u/apps/{{project_name}}/shared/tmp/pids/resque.pid
|
|
23
25
|
|
|
24
26
|
# Uncomment this if you are going to use this as a system service
|
|
25
27
|
# if using as a user service then leave commented out, or you will get an error trying to start the service
|
|
@@ -31,6 +33,11 @@ UMask=0002
|
|
|
31
33
|
# Greatly reduce Ruby memory fragmentation and heap usage
|
|
32
34
|
# https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/
|
|
33
35
|
Environment=MALLOC_ARENA_MAX=2
|
|
36
|
+
Environment=RAILS_ENV={{rails_env}}
|
|
37
|
+
Environment=COUNT=1
|
|
38
|
+
Environment=QUEUES={{ job_queues | join(',') }}
|
|
39
|
+
Environment=BACKGROUND=yes
|
|
40
|
+
Environment=PIDFILE=/u/apps/{{project_name}}/shared/tmp/pids/resque.pid
|
|
34
41
|
|
|
35
42
|
# if we crash, restart
|
|
36
43
|
RestartSec=1
|
|
@@ -44,4 +51,4 @@ StandardError=syslog
|
|
|
44
51
|
SyslogIdentifier=resque
|
|
45
52
|
|
|
46
53
|
[Install]
|
|
47
|
-
WantedBy=multi-user.target
|
|
54
|
+
WantedBy=multi-user.target
|
|
@@ -23,7 +23,7 @@ Role Variables
|
|
|
23
23
|
|
|
24
24
|
> ruby_version: This variable controls the version of Ruby that will be compiled and installed. It should correspond with the tarball filename excluding the ".tar.gz" extension (e.g. "ruby-1.9.3-p484").
|
|
25
25
|
|
|
26
|
-
> ruby_checksum: The checksum of the gzipped tarball that will be downloaded and compiled.
|
|
26
|
+
> ruby_checksum: The SHA256 checksum of the gzipped tarball that will be downloaded and compiled.
|
|
27
27
|
|
|
28
28
|
> ruby_download_location: The URL that the tarball should be retrieved from. Using the ruby_version variable within this variable is a good practice (e.g. "http://cache.ruby-lang.org/pub/ruby/1.9/{{ ruby_version }}.tar.gz").
|
|
29
29
|
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
- name: Download the Ruby source code
|
|
41
41
|
get_url: url={{ ruby_download_location }}
|
|
42
42
|
dest=/usr/local/src/
|
|
43
|
-
|
|
43
|
+
sha256sum={{ ruby_checksum }}
|
|
44
44
|
become: true
|
|
45
45
|
|
|
46
46
|
- name: Generate the Ruby installation script
|
|
@@ -71,22 +71,7 @@
|
|
|
71
71
|
command: "{{ ruby_location }}/bin/gem update --system"
|
|
72
72
|
become: true
|
|
73
73
|
|
|
74
|
-
- name:
|
|
75
|
-
file:
|
|
76
|
-
path: "{{ ruby_location }}/bin/bundle"
|
|
77
|
-
state: absent
|
|
78
|
-
become: true
|
|
79
|
-
|
|
80
|
-
- name: Uninstall Bundler
|
|
81
|
-
gem:
|
|
82
|
-
name: bundler
|
|
83
|
-
state: absent
|
|
84
|
-
user_install: no
|
|
85
|
-
executable: "{{ ruby_location }}/bin/gem"
|
|
86
|
-
become: true
|
|
87
|
-
ignore_errors: yes
|
|
88
|
-
|
|
89
|
-
- name: Install Bundler
|
|
74
|
+
- name: Install/update Bundler
|
|
90
75
|
shell: "{{ ruby_location }}/bin/gem install bundler -v {{ bundler_version }}"
|
|
91
76
|
become: true
|
|
92
77
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
sidekiq_workers: 1
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
- name: Install sidekiq
|
|
3
|
-
template:
|
|
4
|
-
src: sidekiq-monit-rc
|
|
5
|
-
dest: /etc/monit/conf-available/sidekiq_{{project_name}}_{{rails_env}}
|
|
2
|
+
- name: Install systemd sidekiq script
|
|
6
3
|
become: true
|
|
4
|
+
template:
|
|
5
|
+
src: sidekiq-systemd.service
|
|
6
|
+
dest: /etc/systemd/system/sidekiq.service
|
|
7
7
|
|
|
8
|
-
- name:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
dest: /etc/monit/conf-enabled/sidekiq_{{project_name}}_{{rails_env}}
|
|
15
|
-
state: link
|
|
16
|
-
notify:
|
|
17
|
-
- reload_monit
|
|
18
|
-
- restart_monit
|
|
8
|
+
- name: Enable systemd sidekiq service
|
|
9
|
+
become: true
|
|
10
|
+
systemd:
|
|
11
|
+
name: sidekiq
|
|
12
|
+
enabled: yes
|
|
13
|
+
daemon_reload: true
|
|
19
14
|
|
|
15
|
+
# TODO Read the gemfile and make sure they have sidekiq 6????
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
check process sidekiq
|
|
2
2
|
with pidfile /u/apps/{{project_name}}/shared/tmp/pids/sidekiq.pid
|
|
3
|
-
start program = "/bin/su - deploy -c 'cd /u/apps/{{project_name}}/current && bundle exec sidekiq --queue {{hostname}} {{ job_queues | map('regex_replace', '^(.*)$', '--queue \\1') | join(' ') }} -c {{
|
|
3
|
+
start program = "/bin/su - deploy -c 'cd /u/apps/{{project_name}}/current && bundle exec sidekiq --queue {{hostname}} {{ job_queues | map('regex_replace', '^(.*)$', '--queue \\1') | join(' ') }} -c {{sidekiq_workers}} --pidfile /u/apps/{{project_name}}/shared/tmp/pids/sidekiq.pid --environment {{rails_env}} --logfile /u/apps/{{project_name}}/shared/log/sidekiq.log --daemon'" with timeout 30 seconds
|
|
4
4
|
stop program = "/bin/su - deploy -c 'kill -s TERM `cat /u/apps/{{project_name}}/shared/tmp/pids/sidekiq.pid`'" with timeout 30 seconds
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file tells systemd how to run Sidekiq as a 24/7 long-running daemon.
|
|
3
|
+
#
|
|
4
|
+
# Use `journalctl -u sidekiq -rn 100` to view the last 100 lines of log output.
|
|
5
|
+
#
|
|
6
|
+
[Unit]
|
|
7
|
+
Description=sidekiq
|
|
8
|
+
# start us only once the network and logging subsystems are available,
|
|
9
|
+
# consider adding redis-server.service if Redis is local and systemd-managed.
|
|
10
|
+
After=syslog.target network.target
|
|
11
|
+
|
|
12
|
+
# See these pages for lots of options:
|
|
13
|
+
#
|
|
14
|
+
# https://www.freedesktop.org/software/systemd/man/systemd.service.html
|
|
15
|
+
# https://www.freedesktop.org/software/systemd/man/systemd.exec.html
|
|
16
|
+
#
|
|
17
|
+
# THOSE PAGES ARE CRITICAL FOR ANY LINUX DEVOPS WORK; read them multiple
|
|
18
|
+
# times! systemd is a critical tool for all developers to know and understand.
|
|
19
|
+
#
|
|
20
|
+
[Service]
|
|
21
|
+
#
|
|
22
|
+
# !!!! !!!! !!!!
|
|
23
|
+
#
|
|
24
|
+
# As of v6.0.6, Sidekiq automatically supports systemd's `Type=notify` and watchdog service
|
|
25
|
+
# monitoring. If you are using an earlier version of Sidekiq, change this to `Type=simple`
|
|
26
|
+
# and remove the `WatchdogSec` line.
|
|
27
|
+
#
|
|
28
|
+
# !!!! !!!! !!!!
|
|
29
|
+
#
|
|
30
|
+
Type=notify
|
|
31
|
+
# If your Sidekiq process locks up, systemd's watchdog will restart it within seconds.
|
|
32
|
+
WatchdogSec=10
|
|
33
|
+
|
|
34
|
+
WorkingDirectory=/u/apps/{{project_name}}/current
|
|
35
|
+
ExecStart=/usr/local/bin/bundle exec sidekiq -e {{rails_env}} --queue {{hostname}} {{ job_queues | map('regex_replace', '^(.*)$', '--queue \\1') | join(' ') }}
|
|
36
|
+
|
|
37
|
+
# Use `systemctl kill -s TSTP sidekiq` to quiet the Sidekiq process
|
|
38
|
+
|
|
39
|
+
# Uncomment this if you are going to use this as a system service
|
|
40
|
+
# if using as a user service then leave commented out, or you will get an error trying to start the service
|
|
41
|
+
# !!! Change this to your deploy user account if you are using this as a system service !!!
|
|
42
|
+
User=deploy
|
|
43
|
+
Group=deploy
|
|
44
|
+
UMask=0002
|
|
45
|
+
|
|
46
|
+
# Greatly reduce Ruby memory fragmentation and heap usage
|
|
47
|
+
# https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/
|
|
48
|
+
Environment=MALLOC_ARENA_MAX=2
|
|
49
|
+
|
|
50
|
+
# if we crash, restart
|
|
51
|
+
RestartSec=1
|
|
52
|
+
Restart=on-failure
|
|
53
|
+
|
|
54
|
+
# output goes to /var/log/syslog (Ubuntu) or /var/log/messages (CentOS)
|
|
55
|
+
StandardOutput=syslog
|
|
56
|
+
StandardError=syslog
|
|
57
|
+
|
|
58
|
+
# This will default to "bundler" if we don't specify it
|
|
59
|
+
SyslogIdentifier=sidekiq
|
|
60
|
+
|
|
61
|
+
[Install]
|
|
62
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
- name: "Add Tailscale apt key"
|
|
3
|
+
become: true
|
|
4
|
+
apt_key:
|
|
5
|
+
url: https://pkgs.tailscale.com/stable/ubuntu/{{ansible_distribution_release}}.gpg
|
|
6
|
+
state: present
|
|
7
|
+
|
|
8
|
+
- name: "Add Tailscale apt repos"
|
|
9
|
+
become: true
|
|
10
|
+
apt_repository:
|
|
11
|
+
repo: "deb https://pkgs.tailscale.com/stable/ubuntu {{ansible_distribution_release}} main"
|
|
12
|
+
state: present
|
|
13
|
+
|
|
14
|
+
- name: "Install tailscale from api"
|
|
15
|
+
apt:
|
|
16
|
+
name: tailscale
|
|
17
|
+
state: latest
|
|
18
|
+
update_cache: yes
|
|
19
|
+
|
|
20
|
+
- name: "Join the tailnet"
|
|
21
|
+
become: true
|
|
22
|
+
command: tailscale up --auth-key {{tailscale_auth_key}} {{tailscale_options}}
|
data/exe/subspace
CHANGED
data/lib/subspace/cli.rb
CHANGED
|
@@ -7,11 +7,14 @@ require 'subspace'
|
|
|
7
7
|
require 'subspace/commands/base'
|
|
8
8
|
require 'subspace/commands/bootstrap'
|
|
9
9
|
require 'subspace/commands/configure'
|
|
10
|
+
require 'subspace/commands/exec'
|
|
10
11
|
require 'subspace/commands/init'
|
|
12
|
+
require 'subspace/commands/inventory'
|
|
11
13
|
require 'subspace/commands/override'
|
|
12
14
|
require 'subspace/commands/provision'
|
|
13
15
|
require 'subspace/commands/ssh'
|
|
14
|
-
require 'subspace/commands/
|
|
16
|
+
require 'subspace/commands/secrets'
|
|
17
|
+
require 'subspace/commands/terraform'
|
|
15
18
|
require 'subspace/commands/maintain'
|
|
16
19
|
require 'subspace/commands/maintenance_mode.rb'
|
|
17
20
|
|
|
@@ -30,11 +33,15 @@ class Subspace::Cli
|
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
command :init do |c|
|
|
33
|
-
c.syntax = 'subspace init
|
|
36
|
+
c.syntax = 'subspace init'
|
|
34
37
|
c.summary = 'Run without options to initialize subspace.'
|
|
35
38
|
c.description = 'Some initialization routines can be run indiviaully, useful for upgrading'
|
|
36
|
-
c.example 'init a new project', 'subspace init'
|
|
37
|
-
c.example 'create
|
|
39
|
+
c.example 'init a new project with one default environment (default staging)', 'subspace init'
|
|
40
|
+
c.example 'create a new fully automated production environment configuration', 'subspace init --terraform --env production'
|
|
41
|
+
c.option '--ansible', 'initialize ansible for managing individual servers'
|
|
42
|
+
c.option '--terraform', 'Initialize terraform for managing infrastructure'
|
|
43
|
+
c.option '--env STRING', 'Initialize configuration for a new environment'
|
|
44
|
+
c.option '--template [staging|production]', 'Use non-default template for this environment (default=staging)'
|
|
38
45
|
c.when_called Subspace::Commands::Init
|
|
39
46
|
end
|
|
40
47
|
|
|
@@ -47,9 +54,6 @@ class Subspace::Cli
|
|
|
47
54
|
c.option '--password', "Ask for a password instead of using ssh keys"
|
|
48
55
|
c.option '--yum', "Use yum instead of apt to install python"
|
|
49
56
|
c.option "-i", "--private-key PRIVATE-KEY", "Alias for private-key"
|
|
50
|
-
Subspace::Commands::Bootstrap::PASS_THROUGH_PARAMS.each do |param_name|
|
|
51
|
-
c.option "--#{param_name} #{param_name.upcase}", "Passed directly through to ansible-playbook command"
|
|
52
|
-
end
|
|
53
57
|
c.when_called Subspace::Commands::Bootstrap
|
|
54
58
|
end
|
|
55
59
|
|
|
@@ -64,17 +68,34 @@ class Subspace::Cli
|
|
|
64
68
|
c.when_called Subspace::Commands::Provision
|
|
65
69
|
end
|
|
66
70
|
|
|
71
|
+
command :tf do |c|
|
|
72
|
+
c.syntax = 'subspace tf [environment]'
|
|
73
|
+
c.summary = "Execute a terraform plan with the option to apply the plan after review"
|
|
74
|
+
c.when_called Subspace::Commands::Terraform
|
|
75
|
+
end
|
|
76
|
+
|
|
67
77
|
command :ssh do |c|
|
|
68
78
|
c.syntax = 'subspace ssh [options]'
|
|
69
79
|
c.summary = 'ssh to the remote server as the administrative user'
|
|
70
80
|
c.description = ''
|
|
71
|
-
c.option '--user USER', "Use a different user (eg deploy). Default is the
|
|
81
|
+
c.option '--user USER', "Use a different user (eg deploy). Default is the ansible_user"
|
|
72
82
|
Subspace::Commands::Ssh::PASS_THROUGH_PARAMS.each do |param_name|
|
|
73
83
|
c.option "-#{param_name} #{param_name.upcase}", "Passed directly through to ssh command"
|
|
74
84
|
end
|
|
75
85
|
c.when_called Subspace::Commands::Ssh
|
|
76
86
|
end
|
|
77
87
|
|
|
88
|
+
command :exec do |c|
|
|
89
|
+
c.syntax = 'subspace exec <host-spec> "<statement>" [options]'
|
|
90
|
+
c.summary = 'execute <statement> on all hosts matching <host-spec>'
|
|
91
|
+
c.description = ''
|
|
92
|
+
c.option '--user USER', "Use a different user (eg deploy). Default is the ansible_user"
|
|
93
|
+
Subspace::Commands::Exec::PASS_THROUGH_PARAMS.each do |param_name|
|
|
94
|
+
c.option "-#{param_name} #{param_name.upcase}", "Passed directly through to ssh command"
|
|
95
|
+
end
|
|
96
|
+
c.when_called Subspace::Commands::Exec
|
|
97
|
+
end
|
|
98
|
+
|
|
78
99
|
command :configure do |c, args|
|
|
79
100
|
c.syntax = 'subspace configure'
|
|
80
101
|
c.summary = "Regenerate all of the ansible configuration files. You don't normally need to run this."
|
|
@@ -89,15 +110,17 @@ class Subspace::Cli
|
|
|
89
110
|
c.when_called Subspace::Commands::Override
|
|
90
111
|
end
|
|
91
112
|
|
|
92
|
-
command :
|
|
93
|
-
c.syntax = 'subspace
|
|
113
|
+
command :secrets do |c, args|
|
|
114
|
+
c.syntax = 'subspace secrets [environment]'
|
|
94
115
|
c.summary = 'View or edit the encrypted variables for an environment'
|
|
95
|
-
c.description =
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
c.description = <<~EOS
|
|
117
|
+
By default, this will simply show the variables for a specific environemnt.
|
|
118
|
+
You can also edit variables, and we expect the functionality here to grow in the future.
|
|
119
|
+
Running `subspace secrets development --create` is usually a great way to bootstrap a new development environment.
|
|
120
|
+
EOS
|
|
98
121
|
c.option '--edit', "Edit the variables instead of view"
|
|
99
122
|
c.option '--create', "Create config/application.yml with the variables from the specified environment"
|
|
100
|
-
c.when_called Subspace::Commands::
|
|
123
|
+
c.when_called Subspace::Commands::Secrets
|
|
101
124
|
end
|
|
102
125
|
|
|
103
126
|
command :maintain do |c, args|
|
|
@@ -124,6 +147,19 @@ class Subspace::Cli
|
|
|
124
147
|
c.when_called Subspace::Commands::MaintenanceMode
|
|
125
148
|
end
|
|
126
149
|
|
|
150
|
+
command :inventory do |c, args|
|
|
151
|
+
c.syntax = 'subspace inventory <command>'
|
|
152
|
+
c.summary = 'Manage, manipulate, and other useful inventory-related functions'
|
|
153
|
+
c.description = <<~EOS
|
|
154
|
+
Available inventory commands:
|
|
155
|
+
|
|
156
|
+
capistrano - generate config/deploy/[env].rb. Requires the --env option.
|
|
157
|
+
list - list the current inventory as understood by subspace.
|
|
158
|
+
EOS
|
|
159
|
+
c.option "--env ENVIRONMENT", "Optional: Limit function to a specific environment (aka group)"
|
|
160
|
+
c.when_called Subspace::Commands::Inventory
|
|
161
|
+
end
|
|
162
|
+
|
|
127
163
|
run!
|
|
128
164
|
end
|
|
129
165
|
end
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
module Subspace
|
|
2
2
|
module Commands
|
|
3
3
|
module Ansible
|
|
4
|
+
def ansible_playbook(*args)
|
|
5
|
+
args.push "--diff"
|
|
6
|
+
args.push "--private-key"
|
|
7
|
+
args.push "subspace.pem"
|
|
8
|
+
ansible_command("ansible-playbook", *args)
|
|
9
|
+
end
|
|
10
|
+
|
|
4
11
|
def ansible_command(command, *args)
|
|
5
12
|
update_ansible_cfg
|
|
6
|
-
Dir.chdir "config/
|
|
13
|
+
Dir.chdir "config/subspace" do
|
|
7
14
|
say ">> Running #{command} #{args.join(' ')}"
|
|
8
15
|
system(command, *args, out: $stdout, err: $stderr)
|
|
9
16
|
say "<< Done"
|
|
@@ -13,7 +20,9 @@ module Subspace
|
|
|
13
20
|
private
|
|
14
21
|
|
|
15
22
|
def update_ansible_cfg
|
|
16
|
-
if
|
|
23
|
+
if ENV["DISABLE_MITOGEN"]
|
|
24
|
+
puts "Mitogen explicitly disabled. Skipping detection. "
|
|
25
|
+
elsif `pip show mitogen 2>&1` =~ /^Location: (.*?)$/m
|
|
17
26
|
@mitogen_path = $1
|
|
18
27
|
puts "🏎🚀🚅Mitogen found at #{@mitogen_path}. WARP 9!....ENGAGE!🚀"
|
|
19
28
|
else
|
|
@@ -13,7 +13,7 @@ module Subspace
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def template_dir
|
|
16
|
-
File.join(gem_path, 'template', '
|
|
16
|
+
File.join(gem_path, 'template', 'subspace')
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def gem_path
|
|
@@ -21,23 +21,34 @@ module Subspace
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def project_path
|
|
24
|
+
unless File.exist?(File.join(Dir.pwd, "config", "subspace"))
|
|
25
|
+
say "Subspace must be run from the project root"
|
|
26
|
+
exit
|
|
27
|
+
end
|
|
24
28
|
Dir.pwd # TODO make sure this is correct if they for whatever reason aren't running subspace from the project root??
|
|
25
29
|
end
|
|
26
30
|
|
|
31
|
+
def project_name
|
|
32
|
+
File.basename(project_path) # TODO see above, this should probably be in a configuration somewhere
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
def dest_dir
|
|
28
|
-
"config/
|
|
36
|
+
"config/subspace"
|
|
29
37
|
end
|
|
30
38
|
|
|
31
39
|
def template(src, dest = nil, render_binding = nil)
|
|
32
40
|
return unless confirm_overwrite File.join(dest_dir, dest || src)
|
|
33
41
|
template! src, dest, render_binding
|
|
34
|
-
say "Wrote #{dest}"
|
|
42
|
+
say "Wrote #{dest || src}"
|
|
35
43
|
end
|
|
36
44
|
|
|
37
45
|
def template!(src, dest = nil, render_binding = nil)
|
|
38
46
|
dest ||= src
|
|
39
|
-
template = ERB.new File.read(File.join(template_dir, "#{src}.erb")),
|
|
40
|
-
|
|
47
|
+
template = ERB.new File.read(File.join(template_dir, "#{src}.erb")), trim_mode: '-'
|
|
48
|
+
result = template.result(render_binding || binding)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
File.write File.join(dest_dir, dest), result
|
|
41
52
|
end
|
|
42
53
|
|
|
43
54
|
def copy(src, dest = nil)
|
|
@@ -74,6 +85,10 @@ module Subspace
|
|
|
74
85
|
def set_subspace_version
|
|
75
86
|
ENV['SUBSPACE_VERSION'] = Subspace::VERSION
|
|
76
87
|
end
|
|
88
|
+
|
|
89
|
+
def inventory
|
|
90
|
+
@inventory ||= Subspace::Inventory.read("config/subspace/inventory.yml")
|
|
91
|
+
end
|
|
77
92
|
end
|
|
78
93
|
end
|
|
79
94
|
end
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
class Subspace::Commands::Bootstrap < Subspace::Commands::Base
|
|
2
|
-
PASS_THROUGH_PARAMS = ["private-key"]
|
|
3
2
|
|
|
4
3
|
def initialize(args, options)
|
|
5
4
|
@host_spec = args.first
|
|
@@ -11,37 +10,33 @@ class Subspace::Commands::Bootstrap < Subspace::Commands::Base
|
|
|
11
10
|
|
|
12
11
|
def run
|
|
13
12
|
# ansible atlanta -m copy -a "src=/etc/hosts dest=/tmp/hosts"
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
hosts = inventory.find_hosts!(@host_spec)
|
|
14
|
+
update_ansible_cfg
|
|
15
|
+
hosts.each do |host|
|
|
16
|
+
say "Bootstapping #{host.vars["hostname"]}..."
|
|
17
|
+
learn_host(host)
|
|
18
|
+
install_python(host)
|
|
19
|
+
end
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
private
|
|
19
23
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"-m",
|
|
24
|
-
"file",
|
|
25
|
-
"-a",
|
|
26
|
-
"path=/home/{{ansible_ssh_user}}/.ssh state=directory mode=0700",
|
|
27
|
-
"-vvvv"
|
|
28
|
-
]
|
|
29
|
-
cmd = cmd | pass_through_params
|
|
30
|
-
bootstrap_command cmd
|
|
24
|
+
def learn_host(host)
|
|
25
|
+
system "ssh-keygen -R #{host.vars["ansible_host"]}"
|
|
26
|
+
system "ssh-keyscan -H #{host.vars["ansible_host"]} >> ~/.ssh/known_hosts"
|
|
31
27
|
end
|
|
32
28
|
|
|
33
|
-
def install_python
|
|
34
|
-
update_ansible_cfg
|
|
29
|
+
def install_python(host)
|
|
35
30
|
cmd = ["ansible",
|
|
36
|
-
|
|
31
|
+
host.name,
|
|
32
|
+
"--private-key",
|
|
33
|
+
"config/subspace/subspace.pem",
|
|
37
34
|
"-m",
|
|
38
35
|
"raw",
|
|
39
36
|
"-a",
|
|
40
|
-
"test -e /usr/bin/
|
|
41
|
-
"--become"
|
|
42
|
-
"-vvvv"
|
|
37
|
+
"test -e /usr/bin/python3 || (apt -y update && apt install -y python3)",
|
|
38
|
+
"--become"
|
|
43
39
|
]
|
|
44
|
-
cmd = cmd | pass_through_params
|
|
45
40
|
bootstrap_command cmd
|
|
46
41
|
end
|
|
47
42
|
|
|
@@ -16,12 +16,12 @@ class Subspace::Commands::Configure < Subspace::Commands::Base
|
|
|
16
16
|
private
|
|
17
17
|
|
|
18
18
|
def update_host_configuration(host)
|
|
19
|
-
say "Generating config/
|
|
19
|
+
say "Generating config/subspace/host_vars/#{host}"
|
|
20
20
|
template "host_vars/template", "host_vars/#{host}", Subspace.config.binding_for(host: host)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def update_group_configuration(group)
|
|
24
|
-
say "Generating config/
|
|
24
|
+
say "Generating config/subspace/group_vars/#{group}"
|
|
25
25
|
template "group_vars/template", "group_vars/#{group}", Subspace.config.binding_for(group: group)
|
|
26
26
|
end
|
|
27
27
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'subspace/inventory'
|
|
3
|
+
class Subspace::Commands::Exec < Subspace::Commands::Base
|
|
4
|
+
PASS_THROUGH_PARAMS = ["i"]
|
|
5
|
+
|
|
6
|
+
def initialize(args, options)
|
|
7
|
+
@host_spec = args[0]
|
|
8
|
+
@command = args[1]
|
|
9
|
+
@user = options.user
|
|
10
|
+
@options = options
|
|
11
|
+
run
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
hosts = inventory.find_hosts!(@host_spec)
|
|
16
|
+
|
|
17
|
+
say "> Running `#{@command}` on #{hosts.join ','}"
|
|
18
|
+
ansible_command "ansible", @host_spec, "-m", "command", "-a", @command
|
|
19
|
+
end
|
|
20
|
+
end
|