pvcglue 0.1.39 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/README.md +12 -3
  5. data/bin/pvc +4 -2
  6. data/lib/pvcglue.rb +106 -21
  7. data/lib/pvcglue/bootstrap.rb +1 -1
  8. data/lib/pvcglue/cli.rb +28 -17
  9. data/lib/pvcglue/cloud.rb +243 -56
  10. data/lib/pvcglue/configuration.rb +43 -5
  11. data/lib/pvcglue/connection.rb +236 -0
  12. data/lib/pvcglue/custom_hashie.rb +3 -0
  13. data/lib/pvcglue/db.rb +19 -13
  14. data/lib/pvcglue/digital_ocean.rb +21 -0
  15. data/lib/pvcglue/env.rb +52 -28
  16. data/lib/pvcglue/manager.rb +38 -25
  17. data/lib/pvcglue/minion.rb +182 -0
  18. data/lib/pvcglue/nodes.rb +1 -1
  19. data/lib/pvcglue/{packages → old_packages}/bootstrap.rb +15 -15
  20. data/lib/pvcglue/{packages → old_packages}/env.rb +8 -8
  21. data/lib/pvcglue/old_packages/firewall.rb +48 -0
  22. data/lib/pvcglue/old_packages/manager.rb +116 -0
  23. data/lib/pvcglue/{packages → old_packages}/monit-bootstrap.rb +0 -0
  24. data/lib/pvcglue/{packages → old_packages}/monit-web.rb +0 -0
  25. data/lib/pvcglue/{packages → old_packages}/nginx.rb +0 -0
  26. data/lib/pvcglue/{packages → old_packages}/nodejs.rb +0 -0
  27. data/lib/pvcglue/{packages → old_packages}/passenger.rb +0 -0
  28. data/lib/pvcglue/old_packages/postgresql.rb +10 -0
  29. data/lib/pvcglue/{packages → old_packages}/role_db.rb +9 -9
  30. data/lib/pvcglue/{packages → old_packages}/role_lb.rb +6 -6
  31. data/lib/pvcglue/{packages → old_packages}/role_memcached.rb +0 -0
  32. data/lib/pvcglue/{packages → old_packages}/role_redis.rb +0 -0
  33. data/lib/pvcglue/{packages → old_packages}/role_web.rb +9 -9
  34. data/lib/pvcglue/old_packages/rvm.rb +78 -0
  35. data/lib/pvcglue/{packages → old_packages}/timezone.rb +0 -0
  36. data/lib/pvcglue/{packages → old_packages}/ubuntu.rb +0 -0
  37. data/lib/pvcglue/packages.rb +192 -71
  38. data/lib/pvcglue/packages/apt.rb +74 -0
  39. data/lib/pvcglue/packages/apt_repos.rb +48 -0
  40. data/lib/pvcglue/packages/apt_update.rb +18 -0
  41. data/lib/pvcglue/packages/apt_upgrade.rb +20 -0
  42. data/lib/pvcglue/packages/authorized_keys.rb +33 -0
  43. data/lib/pvcglue/packages/bundler.rb +14 -0
  44. data/lib/pvcglue/packages/dir_base.rb +16 -0
  45. data/lib/pvcglue/packages/dir_shared.rb +16 -0
  46. data/lib/pvcglue/packages/firewall.rb +30 -46
  47. data/lib/pvcglue/packages/load_balancer.rb +71 -0
  48. data/lib/pvcglue/packages/maintenance_mode.rb +28 -0
  49. data/lib/pvcglue/packages/manager.rb +101 -99
  50. data/lib/pvcglue/packages/postgresql.rb +36 -8
  51. data/lib/pvcglue/packages/roles.rb +23 -0
  52. data/lib/pvcglue/packages/ruby.rb +13 -0
  53. data/lib/pvcglue/packages/rvm.rb +18 -71
  54. data/lib/pvcglue/packages/secrets.rb +36 -0
  55. data/lib/pvcglue/packages/ssh_key_check.rb +11 -0
  56. data/lib/pvcglue/packages/ssl.rb +45 -0
  57. data/lib/pvcglue/packages/ssl_acme.rb +29 -0
  58. data/lib/pvcglue/packages/swap.rb +14 -0
  59. data/lib/pvcglue/packages/unattended_upgrades.rb +20 -0
  60. data/lib/pvcglue/packages/users.rb +20 -0
  61. data/lib/pvcglue/packages/web.rb +50 -0
  62. data/lib/pvcglue/stack.rb +166 -0
  63. data/lib/pvcglue/templates/50unattended-upgrades.erb +63 -0
  64. data/lib/pvcglue/templates/capfile.erb +4 -1
  65. data/lib/pvcglue/templates/deploy.rb.erb +3 -2
  66. data/lib/pvcglue/templates/lb.sites-enabled.erb +15 -9
  67. data/lib/pvcglue/templates/letsencrypt-webroot.erb +3 -0
  68. data/lib/pvcglue/templates/pg_hba.conf.erb +1 -2
  69. data/lib/pvcglue/templates/postgresql.conf.erb +376 -291
  70. data/lib/pvcglue/templates/stage-deploy.rb.erb +2 -2
  71. data/lib/pvcglue/templates/web.bashrc.erb +16 -5
  72. data/lib/pvcglue/templates/web.nginx.conf.erb +1 -1
  73. data/lib/pvcglue/templates/web.sites-enabled.erb +1 -1
  74. data/lib/pvcglue/version.rb +1 -1
  75. data/pvcglue.gemspec +17 -12
  76. metadata +125 -22
@@ -1,10 +1,38 @@
1
- apt_package 'postgresql' do
2
- action('start') { sudo 'service postgresql start' }
3
- action('stop') { sudo 'service postgresql stop' }
4
- action('restart') { sudo('service postgresql restart') }
5
- end
1
+ module Pvcglue
2
+ class Packages
3
+ class Postgresql < Pvcglue::Packages
6
4
 
7
- package 'postgres' do
8
- depends_on 'postgresql', 'libpq-dev'
9
- end
5
+ def installed?
6
+ get_minion_state(:postgresql_updated_at)
7
+ end
8
+
9
+ def install!
10
+ Pvcglue::Env.initialize_stage_env
11
+ connection.write_to_file_from_template(:root, 'postgresql.conf.erb', '/etc/postgresql/9.6/main/postgresql.conf', 'postgres', 'postgres', '0644')
12
+ connection.write_to_file_from_template(:root, 'pg_hba.conf.erb', '/etc/postgresql/9.6/main/pg_hba.conf', 'postgres', 'postgres', '0644')
13
+
14
+ # connection.run_get_stdout(:root, '', 'service postgresql restart')
15
+ # unless $?.exitstatus == 0
16
+ # Pvcglue.logger.error { 'Unable to (re)start postgresql. Getting status...' }
17
+ # result = connection.run_get_stdout(:root, '', 'systemctl status postgresql.service')
18
+ # puts result
19
+ # raise('There was a problem restarting PostgreSQL.')
20
+ # end
21
+
22
+ username = Pvcglue.cloud.stage_env['DB_USER_POSTGRES_USERNAME']
23
+ password = Pvcglue.cloud.stage_env['DB_USER_POSTGRES_PASSWORD']
24
+ db_name = username # just for clarity in later statements. This also must match database.yml.
25
+ # TODO: Instead of ssh? below, use ssh!, but allow for the user having been already created. It's only an issue for when the minion state has been reset
26
+ connection.ssh?(:root, '', %Q[cd /var/lib/postgresql && sudo -u postgres psql -c "CREATE ROLE #{username} LOGIN CREATEDB PASSWORD '#{password}';"])
27
+ connection.ssh!(:root, '', %Q[cd /var/lib/postgresql && sudo -u postgres psql -c "ALTER ROLE #{username} PASSWORD '#{password}' CREATEDB LOGIN"])
28
+ connection.ssh?(:root, '', %Q[cd /var/lib/postgresql && sudo -u postgres psql -c "CREATE DATABASE #{db_name} WITH OWNER #{username}"])
29
+ connection.ssh!(:root, '', %Q[cd /var/lib/postgresql && sudo -u postgres psql #{db_name} -c "ALTER SCHEMA public OWNER TO #{username}"])
10
30
 
31
+
32
+ set_minion_state(:postgresql_updated_at, Time.now.utc)
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class Roles < Pvcglue::Packages
4
+ def installed?
5
+ false
6
+ end
7
+
8
+ def post_install_check?
9
+ true
10
+ end
11
+
12
+ def install!
13
+ Pvcglue::Packages::Manager.apply(minion) if has_role?(:manager)
14
+ Pvcglue::Packages::LoadBalancer.apply(minion) if has_role?(:lb)
15
+ Pvcglue::Packages::Web.apply(minion) if has_role?(:web)
16
+ Pvcglue::Packages::Worker.apply(minion) if has_role?(:worker)
17
+ Pvcglue::Packages::Postgresql.apply(minion) if has_role?(:pg)
18
+ Pvcglue::Packages::Memcache.apply(minion) if has_role?(:mc)
19
+ Pvcglue::Packages::Redis.apply(minion) if has_role?(:redis)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class Ruby < Pvcglue::Packages
4
+ def installed?
5
+ connection.run_get_stdout!(user_name, '', 'rvm list strings') =~ /#{Pvcglue.configuration.ruby_version.gsub('.', '\.')}/
6
+ end
7
+
8
+ def install!
9
+ connection.run!(user_name, '', "rvm install #{Pvcglue.configuration.ruby_version}")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,78 +1,25 @@
1
- package 'rvm' do
2
- depends_on 'curl'
3
- depends_on 'rvm-bashrc'
1
+ module Pvcglue
2
+ class Packages
3
+ class Rvm < Pvcglue::Packages
4
+ def installed?
5
+ connection.run_get_stdout!(user_name, '', 'type rvm | head -n 1') =~ /rvm is a function/
6
+ end
4
7
 
5
- validate do
6
- run('type rvm | head -n 1') =~ /rvm is a function/
7
- end
8
+ def install!
9
+ connection.write_to_file_from_template(user_name, 'gemrc.erb', "/home/#{user_name}/.gemrc") # sets: gem: --no-ri --no-rdoc
10
+ connection.write_to_file_from_template(user_name, 'web.bashrc.erb', "/home/#{user_name}/.bashrc")
8
11
 
9
- apply do
10
- run 'gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3'
11
- run 'gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3' # Do it again, the first time only sets things up, and does not import the keys
12
- # run 'curl -sSL https://rvm.io/mpapis.asc | gpg --import -'
13
- run '\curl -sSL https://get.rvm.io | bash -s stable --with-default-gems="bundler"'
14
- run "rvm requirements"
15
- end
12
+ connection.run_get_stdout!(user_name, '', 'gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3')
13
+ # Do it again, the first time only sets things up, and does not import the keys
14
+ connection.run!(user_name, '', '\curl -sSL https://get.rvm.io | bash -s stable --with-default-gems=bundler')
16
15
 
17
- remove do
18
- run 'yes "yes" | rvm implode'
19
- end
20
- end
16
+ # TODO: set autolibs mode so there are not installed automatically, as the user won't have sudo permissions later.
17
+ # OR create a 'install' user that can sudo...might be easier...
18
+ # Installing required packages: libreadline6-dev, libyaml-dev, libsqlite3-dev, sqlite3, autoconf, libgmp-dev, libgdbm-dev, libncurses5-dev, automake, libtool, bison, pkg-config, libffi-dev...............
21
19
 
22
- package 'rvm-bashrc' do
23
- file({
24
- :template => Pvcglue.template_file_name('web.bashrc.erb'),
25
- :destination => '/home/deploy/.bashrc',
26
- :create_dirs => false,
27
- :permissions => 0644,
28
- :user => 'deploy',
29
- :group => 'deploy'
30
- })
31
- end
20
+ connection.run_get_stdout!(user_name, '', 'rvm requirements')
32
21
 
33
- package 'gem' do
34
- depends_on 'rvm-ruby'
35
- action 'exists' do |gem_name|
36
- run("gem list -i #{gem_name}") =~ /true/
37
- end
38
- action 'install' do |gem_name|
39
- sudo "gem install #{gem_name} --no-ri --no-rdoc"
22
+ end
23
+ end
40
24
  end
41
- action 'uninstall' do |gem_name|
42
- sudo "gem uninstall #{gem_name} -x -a"
43
- end
44
- end
45
-
46
- package 'bundler' do
47
- depends_on 'gem'
48
- apply { trigger 'gem:install', 'bundler' }
49
- remove { trigger 'gem:remove', 'bundler' }
50
- validate { trigger 'gem:exists', 'bundler' }
51
25
  end
52
-
53
- package 'rvm-ruby' do
54
- depends_on 'rvm'
55
-
56
- validate do
57
- run('rvm list strings') =~ /#{Pvcglue.configuration.ruby_version.gsub('.', '\.')}/
58
- end
59
-
60
- apply do
61
- run "rvm install #{Pvcglue.configuration.ruby_version}"
62
- # run "rvm --default use 2.0.0"
63
- end
64
-
65
- remove do
66
- run "rvm remove --archive --gems #{Pvcglue.configuration.ruby_version}"
67
- end
68
-
69
- end
70
-
71
- package 'no-rdoc' do
72
- file({
73
- :template => Pvcglue.template_file_name('gemrc.erb'),
74
- :destination => '/home/deploy/.gemrc',
75
- :create_dirs => false
76
- })
77
- end
78
-
@@ -0,0 +1,36 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class Secrets < Pvcglue::Packages
4
+ def installed?
5
+ false
6
+ end
7
+
8
+ def install!
9
+ Pvcglue::Env.initialize_stage_env
10
+ connection.write_to_file_from_template(user_name, 'web.env.erb', Pvcglue.cloud.env_file_name, nil, nil, '0640') # TODO: Double check permissions
11
+ restart_web_app!
12
+ end
13
+
14
+ def post_install_check?
15
+ true
16
+ end
17
+
18
+ def restart_web_app!
19
+ if connection.file_exists?(user_name, Pvcglue.cloud.deploy_to_app_current_temp_dir)
20
+ connection.ssh!(user_name, '', "touch #{Pvcglue.cloud.restart_txt_file_name}")
21
+ end
22
+ end
23
+
24
+ def self.load_for_stage
25
+ data = Pvcglue::Packages::Manager.new.load_secrets
26
+ data = '' if data.nil?
27
+ Pvcglue.cloud.stage_env = TOML.parse(data)
28
+ end
29
+
30
+ def self.save_for_stage
31
+ data = TOML.dump(Pvcglue.cloud.stage_env)
32
+ Pvcglue::Packages::Manager.new.save_secrets(data)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class SshKeyCheck < Pvcglue::Packages
4
+ def installed?
5
+ # This has the side effect of adding the server to known_hosts file, to prevent needing interactive prompt
6
+ connection.ssh_retry_wait(:root, '-o strictHostKeyChecking=no', 'echo', 30, 1)
7
+ true
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class Ssl < Pvcglue::Packages
4
+ def installed?
5
+ return true if Pvcglue.cloud.ssl_mode == :none
6
+ false
7
+ end
8
+
9
+ def install!
10
+ # TODO: Support using already created certs
11
+ return true unless Pvcglue.cloud.ssl_mode == :acme
12
+
13
+ Pvcglue::Packages::SslAcme.apply(minion)
14
+
15
+ # Issue Certificate
16
+ first_domain = Pvcglue.cloud.domains.first
17
+ domains = Pvcglue.cloud.domains.map { |domain| "-d #{domain}" }
18
+ first_domain_option = domains.first
19
+ domain_options = domains.join(' ')
20
+ staging_option = Pvcglue.command_line_options[:create_test_cert] ? '--staging ' : ''
21
+ force_option = Pvcglue.command_line_options[:force_cert] ? '--force ' : ''
22
+ debug_option = Pvcglue.logger.level == 0 ? '--debug ' : ''
23
+
24
+ unless Net::HTTP.get(first_domain, '/.well-known/acme-challenge/test.html') =~ /shiny/
25
+ Pvcglue.logger.error("Unable to connect to #{first_domain} at #{minion.public_ip}")
26
+ raise(Thor::Error, 'Please fix and then restart.')
27
+ end
28
+
29
+ result = connection.ssh?(:root, '', "/root/.acme.sh/acme.sh #{debug_option}#{staging_option}#{force_option}--issue #{domain_options} -w #{Pvcglue.cloud.letsencrypt_root}")
30
+ raise result.inspect unless result.exitstatus == 0 || result.exitstatus == 2
31
+
32
+ # Install Certificate
33
+ connection.mkdir_p(:root, Pvcglue.cloud.nginx_config_ssl_path)
34
+ # acme.sh --installcert -d theos.in --keypath /etc/nginx/ssl/theos.in/theos.in.key --fullchainpath /etc/nginx/ssl/theos.in/theos.in.cer --reloadcmd 'systemctl reload nginx'
35
+
36
+ connection.ssh!(:root, '', "/root/.acme.sh/acme.sh --installcert #{first_domain_option} --keypath #{Pvcglue.cloud.nginx_ssl_key_file_name} --fullchainpath #{Pvcglue.cloud.nginx_ssl_crt_file_name} --reloadcmd 'systemctl reload nginx'")
37
+ end
38
+
39
+ def post_install_check?
40
+ true
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class SslAcme < Pvcglue::Packages
4
+ def installed?
5
+ return true if Pvcglue.cloud.ssl_mode == :none
6
+ get_minion_state(:acme_sh_updated_at)
7
+ end
8
+
9
+ def install!
10
+ # Thanks to https://www.rmedgar.com/blog/using-acme-sh-with-nginx
11
+
12
+ connection.ssh!(:root, '', 'curl https://get.acme.sh | sh')
13
+
14
+ # mkdir -p /var/www/le_root/.well-known/acme-challenge
15
+ connection.mkdir_p(:root, Pvcglue.cloud.letsencrypt_full)
16
+ #chown -R root:www-data /var/www/le_root
17
+ connection.chown(:root, Pvcglue.cloud.letsencrypt_root, 'root', 'www-data', '-R')
18
+
19
+ # Test with http://www.example.com/.well-known/acme-challenge/test.html
20
+ connection.write_to_file(:root, "Everything's shiny, Cap'n. Not to fret.", File.join(Pvcglue.cloud.letsencrypt_full, 'test.html'), 'root', 'www-data', '660')
21
+
22
+ connection.ssh!(:root, '', 'systemctl reload nginx.service')
23
+
24
+ set_minion_state(:acme_sh_updated_at, Time.now.utc)
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class Swap < Pvcglue::Packages
4
+ def installed?
5
+
6
+ # sudo("cat /etc/fstab") =~ /\/swapfile/
7
+ true
8
+ end
9
+
10
+ def install!
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class UnattendedUpgrades < Pvcglue::Packages
4
+ def installed?
5
+ get_minion_state(:installed_unattended_upgrades_at)
6
+ end
7
+
8
+ def install!
9
+ connection.write_to_file_from_template(:root, '20auto-upgrades.erb', '/etc/apt/apt.conf.d/20auto-upgrades')
10
+ connection.write_to_file_from_template(:root, '50unattended-upgrades.erb', '/etc/apt/apt.conf.d/50unattended-upgrades')
11
+ end
12
+
13
+ def post_install_check?
14
+ connection.run!(:root, '', 'service unattended-upgrades restart')
15
+ set_minion_state(:installed_unattended_upgrades_at, Time.now.utc)
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class Users < Pvcglue::Packages
4
+ def installed?
5
+ result = connection.run_get_stdout(:root, '', "getent passwd #{user_name} && groups #{user_name}")
6
+ result =~ /^#{user_name}:/ && result =~ /#{user_name} sudo/
7
+ end
8
+
9
+ def install!
10
+ # connection.run!(:root, '', 'mkdir -p ~/.pvc && chmod 600 ~/.pvc') # TODO: Still needed?
11
+ # connection.run!(:root, '', "useradd -d /home/#{user_name} -G sudo -m -U #{user_name} && usermod -s /bin/bash #{user_name}")
12
+
13
+ connection.run!(:root, '', "useradd -d /home/#{user_name} -G sudo -m -U #{user_name}")
14
+ connection.run!(:root, '', "usermod -s /bin/bash #{user_name}")
15
+ # TODO: Lock down the sudo permissions to just let the user deploy
16
+ connection.run!(:root, '', "echo '#{user_name} ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+ module Pvcglue
2
+ class Packages
3
+ class Web < Pvcglue::Packages
4
+
5
+ def installed?
6
+ false
7
+ end
8
+
9
+ def install!
10
+ Pvcglue::Packages::DirBase.apply(minion)
11
+ Pvcglue::Packages::DirShared.apply(minion)
12
+ Pvcglue::Packages::Rvm.apply(minion)
13
+ Pvcglue::Packages::Ruby.apply(minion)
14
+ Pvcglue::Packages::Bundler.apply(minion)
15
+ Pvcglue::Packages::Secrets.apply(minion)
16
+ connection.write_to_file_from_template(:root, 'web.nginx.conf.erb', '/etc/nginx/nginx.conf')
17
+
18
+ set_passenger_ruby # needs to be set before rendering 'web.sites-enabled.erb'
19
+ connection.write_to_file_from_template(:root, 'web.sites-enabled.erb', "/etc/nginx/sites-enabled/#{Pvcglue.cloud.app_and_stage_name}")
20
+
21
+
22
+ end
23
+
24
+ def post_install_check?
25
+ result = connection.run_get_stdout(:root, '', 'service nginx restart')
26
+ if $?.exitstatus == 0
27
+ # Pvcglue.logger.debug { result }
28
+ true
29
+ else
30
+ Pvcglue.logger.error { 'Unable to (re)start nginx. Getting status...' }
31
+ result = connection.run_get_stdout(:root, '', 'systemctl status nginx.service')
32
+ puts result
33
+ false
34
+ end
35
+
36
+ # TODO: Ping the server as a double check.
37
+ end
38
+
39
+ def set_passenger_ruby
40
+ info = connection.run_get_stdout!(user_name, '', "rvm use #{Pvcglue.configuration.ruby_version} && $(which passenger-config) --ruby-command")
41
+ if info =~ /passenger_ruby (.*)/
42
+ Pvcglue.cloud.passenger_ruby = $1
43
+ else
44
+ raise "'passenger_ruby' not found." unless Pvcglue.cloud.passenger_ruby
45
+ end
46
+
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,166 @@
1
+ module Pvcglue
2
+ class Stack
3
+ def self.build(minions, roles_filter)
4
+ Pvcglue::Stack.new(roles_filter).run(minions)
5
+ end
6
+
7
+ def initialize(roles_filter)
8
+ @roles_filter = roles_filter
9
+ end
10
+
11
+ def apply_role?(role)
12
+ @roles_filter == 'all' || role == @roles_filter
13
+ end
14
+
15
+ def run(minions)
16
+ # puts "Configuring nodes for #{@roles_filter}."
17
+
18
+ # ap Pvcglue.configuration
19
+ # ap Pvcglue.cloud.data
20
+ # ap Pvcglue.cloud.app_name
21
+ # ap Pvcglue.cloud.project
22
+ # ap Pvcglue.cloud.project.name
23
+ # ap Pvcglue.cloud.project.stages.map { |stage| stage.to_dot.stage }
24
+ # ap Pvcglue.cloud.project.stages.map { |stage| stage.name }
25
+ # ap Pvcglue.cloud.stage
26
+ # ap Pvcglue.cloud.minions
27
+ # ap Pvcglue.cloud.minions.map { |key, value| value.roles }
28
+ # minions.each do |minion_name, minion|
29
+ # ap minion_name
30
+ # ap minion.first
31
+ # end
32
+ # ap minions['staging-pg'].private_ip
33
+ # minions['staging-pg'].private_ip = '127.0.0.1'
34
+ # ap minions['staging-pg'].private_ip
35
+ new_minions = []
36
+ minions.each do |minion_name, minion|
37
+ Pvcglue.logger_current_minion = minion
38
+ # droplet = Pvcglue::DigitalOcean.client.droplets.find(id: 38371925)
39
+ # minion.droplet = droplet
40
+ # new_minions << minion if true || minion.provision!
41
+ unless minion.provisioned?
42
+ if droplets.detect { |droplet| droplet.name == minion_name }
43
+ raise(Thor::Error, "Machine with the name of '#{minion_name}' already exists!")
44
+ end
45
+ minion.provision!
46
+ new_minions << minion
47
+ end
48
+ end
49
+ Pvcglue.logger_current_minion = nil
50
+
51
+ if new_minions.size > 0
52
+ # ap new_minions
53
+ Pvcglue.logger.info("Checking status of new minions (#{new_minions.size})...")
54
+ time = Benchmark.realtime do
55
+ begin
56
+ lazy_minions = get_lazy_minions(minions)
57
+ unless lazy_minions.size == 0
58
+ # puts '*'*175
59
+ # ap waiting_for
60
+ Pvcglue.logger.info("Waiting for #{lazy_minions.map { |key, value| key }.join(', ')}...")
61
+ sleep(1.5)
62
+ end
63
+ end until lazy_minions.size == 0
64
+ updated_minions = write_config(new_minions)
65
+ updated_minions.each do |updated_minion|
66
+ minions[updated_minion.machine_name].private_ip = updated_minion.private_ip
67
+ minions[updated_minion.machine_name].public_ip = updated_minion.public_ip
68
+ minions[updated_minion.machine_name].cloud_id = updated_minion.cloud_id
69
+ minions[updated_minion.machine_name].connection = Pvcglue::Connection.new(minions[updated_minion.machine_name])
70
+ end
71
+ end
72
+ Pvcglue.logger.info("Minions (finally) ready after #{time.round(2)} seconds!")
73
+ # Pvcglue.cloud.reload_minions!
74
+ end
75
+
76
+ minions.each do |minion_name, minion|
77
+ next unless minion.has_role?(@roles_filter)
78
+ Pvcglue.logger_current_minion = minion
79
+ minion.build!
80
+ end
81
+ Pvcglue.logger_current_minion = nil
82
+
83
+ # raise(Thor::Error, 'STOP!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
84
+ #
85
+ # %w(lb db web caching redis).each do |role|
86
+ # if apply_role?(role)
87
+ # Pvcglue::Packages.apply(role.to_sym, :build, Pvcglue.cloud.minions_filtered(role))
88
+ # end
89
+ # end
90
+
91
+ Pvcglue::Pvcify.run unless minions.values.first.minion_manager?
92
+
93
+ end
94
+
95
+ def write_config(minions)
96
+ # TODO: Just read and write the configuration from manager without writing to `minion.cloud.local_file_name`
97
+ Pvcglue::Manager.pull_configuration
98
+ data = File.read(Pvcglue.cloud.local_file_name)
99
+ updated_minions = minions.map do |minion|
100
+ # puts '-'*175
101
+ # ap minion.droplet
102
+ # Refresh droplet (didn't find a reload method)
103
+ droplet_id = minion.droplet.id.to_s
104
+ # ap droplet_id
105
+ minion.droplet = Pvcglue::DigitalOcean.client.droplets.find(id: droplet_id)
106
+ # puts '='*175
107
+ # ap minion.droplet
108
+ ip_addresses = Pvcglue::DigitalOcean.get_ip_addresses(minion.droplet)
109
+ data = update_minion_data(minion, ip_addresses, droplet_id, data)
110
+ minion.public_ip = ip_addresses.public
111
+ minion.private_ip = ip_addresses.private
112
+ minion.cloud_id = droplet_id
113
+ minion
114
+ end
115
+ File.write(Pvcglue.cloud.local_file_name, data)
116
+ Pvcglue::Manager.push_configuration
117
+ updated_minions
118
+ end
119
+
120
+ def update_minion_data(minion, ip_addresses, cloud_id, data)
121
+ unless minion.public_ip_address.nil? && minion.private_id_address.nil? && minion.cloud_id.nil?
122
+ raise(Thor::Error, "#{minion.machine_name} has previously defined ip address(es) or cloud_id, can not change.")
123
+ end
124
+ if ip_addresses.public.nil? || ip_addresses.private.nil? || cloud_id.nil?
125
+ raise(Thor::Error, "New IP addresses (#{ip_addresses}) or cloud_id (#{cloud_id}) are not valid.")
126
+ end
127
+
128
+
129
+ replacement = "\\1\\2\n\\1public_ip = '#{ip_addresses.public}'\n\\1private_ip = '#{ip_addresses.private}'\n\\1cloud_id = '#{cloud_id}'"
130
+ new_data = data.sub(/( *)(name\s*=\s*['"]#{Regexp.quote(minion.machine_name)}['"])/, replacement)
131
+ raise "Unable to update minion data for #{minion.machine_name}." if data == new_data
132
+
133
+ # replacement = "$1$2\n$1public_ip = '#{ip_addresses.public}'\n$1private_ip = '#{ip_addresses.private}'"
134
+ # new_data = data.sub(/( *)(name\s*=\s*['"]staging-lb['"])/) do |match|
135
+ # "#{$1}#{$2}\n#{$1}public_ip = '#{ip_addresses.public}'\n#{$1}private_ip = '#{ip_addresses.private}'"
136
+ # end
137
+ # puts new_data
138
+
139
+
140
+ Pvcglue.logger.debug("Updated configuration for machine named #{minion.machine_name}.")
141
+ new_data
142
+ end
143
+
144
+ def droplets
145
+ @droplets ||= Pvcglue::DigitalOcean.client.droplets.all
146
+ end
147
+
148
+ def get_lazy_minions(minions)
149
+ droplets = Pvcglue::DigitalOcean.client.droplets.all
150
+
151
+ minions.select do |minion_name, minion|
152
+ Pvcglue.logger_current_minion = minion
153
+ # next unless minion.machine_name == 'staging-lb'
154
+ # ap minion_name
155
+ found = droplets.detect do |droplet|
156
+ droplet[:name] == minion.machine_name
157
+ end
158
+ # ap found
159
+ # ap found[:status]
160
+ !found || found[:status] != 'active'
161
+ end
162
+ # ap minions
163
+ end
164
+
165
+ end
166
+ end