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
@@ -7,7 +7,9 @@ module Pvcglue
7
7
  desc "bootstrap", "bootstrap"
8
8
 
9
9
  def bootstrap
10
- Pvcglue::Packages.apply('bootstrap-manager'.to_sym, :manager, self.class.manager_node, 'root', 'manager')
10
+ # Pvcglue.cloud.set_manager_as_project
11
+ Pvcglue::Stack.build({'pvcglue-manager' => Pvcglue.cloud.manager_minion}, 'manager')
12
+ # Pvcglue::Packages.apply('bootstrap-manager'.to_sym, :manager, self.class.manager_node, 'root', 'manager')
11
13
  end
12
14
 
13
15
  desc "push", "push"
@@ -19,15 +21,16 @@ module Pvcglue
19
21
  desc "pull", "pull"
20
22
 
21
23
  def pull
22
- Pvcglue::Packages.apply('manager-pull'.to_sym, :manager, self.class.manager_node, 'pvcglue', 'manager')
23
- self.class.clear_cloud_data_cache
24
+ Pvcglue::Manager.pull_configuration
25
+ # Pvcglue::Packages.apply('manager-pull'.to_sym, :manager, self.class.manager_node, 'pvcglue', 'manager')
26
+ # self.class.clear_cloud_data_cache
24
27
  end
25
28
 
26
29
  desc "show", "show manager data"
27
30
 
28
31
  def show
29
32
  self.class.initialize_cloud_data
30
- pp Pvcglue.cloud.data
33
+ ap Pvcglue.cloud.data
31
34
  end
32
35
 
33
36
  desc "info", "show manager data"
@@ -100,21 +103,23 @@ module Pvcglue
100
103
  end
101
104
 
102
105
  def self.initialize_cloud_data
103
- # return if get_local_cloud_data
104
- unless read_cached_cloud_data
105
- Pvcglue::Packages.apply('manager-get-config'.to_sym, :manager, manager_node, 'pvcglue', 'manager')
106
- # Pvcglue::Packages.apply('manager-get-config'.to_sym, :manager, manager_node, 'pvcglue') # Can not use package as it causes infinite recursion, we'll just do it manually
107
- data = `ssh pvcglue@#{manager_node[:manager][:public_ip]} "cat #{Pvcglue::Manager.manager_file_name}"`
108
- # puts "*"*80
109
- # puts data
110
- # puts "*"*80
111
- if data.empty?
112
- raise(Thor::Error, "Remote manager file not found (or empty): #{::Pvcglue::Manager.manager_file_name}")
113
- else
114
- ::Pvcglue.cloud.data = TOML.parse(data)
115
- end
116
- write_cloud_data_cache
117
- end
106
+ Pvcglue::Packages::Manager.get_configuration
107
+
108
+ # # return if get_local_cloud_data
109
+ # unless read_cached_cloud_data
110
+ # Pvcglue::Packages.apply('manager-get-config'.to_sym, :manager, manager_node, 'pvcglue', 'manager')
111
+ # # Pvcglue::Packages.apply('manager-get-config'.to_sym, :manager, manager_node, 'pvcglue') # Can not use package as it causes infinite recursion, we'll just do it manually
112
+ # data = `ssh pvcglue@#{manager_node[:manager][:public_ip]} "cat #{Pvcglue::Manager.manager_file_name}"`
113
+ # # puts "*"*80
114
+ # # puts data
115
+ # # puts "*"*80
116
+ # if data.empty?
117
+ # raise(Thor::Error, "Remote manager file not found (or empty): #{::Pvcglue::Manager.manager_file_name}")
118
+ # else
119
+ # ::Pvcglue.cloud.data = TOML.parse(data)
120
+ # end
121
+ # write_cloud_data_cache
122
+ # end
118
123
  end
119
124
 
120
125
  # def self.get_local_cloud_data
@@ -127,7 +132,7 @@ module Pvcglue
127
132
  # end
128
133
 
129
134
  def self.write_cloud_data_cache
130
- File.write(Pvcglue.configuration.cloud_cache_file_name, TOML.dump(Pvcglue.cloud.data))
135
+ # File.write(Pvcglue.configuration.cloud_cache_file_name, TOML.dump(Pvcglue.cloud.data))
131
136
  end
132
137
 
133
138
  def self.read_cached_cloud_data
@@ -163,11 +168,13 @@ module Pvcglue
163
168
  end
164
169
 
165
170
  def self.user_name
166
- 'pvcglue'
171
+ raise('Old username should not be used')
172
+ # 'pvcglue'
167
173
  end
168
174
 
169
175
  def self.home_dir
170
- File.join('/home', user_name)
176
+ # File.join('/home', user_name)
177
+ '~'
171
178
  end
172
179
 
173
180
  def self.authorized_keys_file_name
@@ -179,12 +186,18 @@ module Pvcglue
179
186
  end
180
187
 
181
188
  def self.manager_dir
182
- File.join(home_dir, '.pvc_manager')
189
+ File.join(home_dir, 'manager')
183
190
  end
184
191
 
185
192
  def self.push_configuration
186
- Pvcglue::Packages.apply('manager-push'.to_sym, :manager, manager_node, 'pvcglue', 'manager')
187
- clear_cloud_data_cache
193
+ Pvcglue::Packages::Manager.push_configuration
194
+ # Pvcglue::Packages.apply('manager-push'.to_sym, :manager, manager_node, 'pvcglue', 'manager')
195
+ # clear_cloud_data_cache
196
+ end
197
+
198
+ def self.pull_configuration
199
+ Pvcglue::Packages::Manager.pull_configuration
200
+ # clear_cloud_data_cache
188
201
  end
189
202
 
190
203
  def self.local_mode?
@@ -0,0 +1,182 @@
1
+ module Pvcglue
2
+ class Minion < SafeMash
3
+ include Hashie::Extensions::Mash::SafeAssignment
4
+
5
+ def build!
6
+ # puts '*'*175
7
+ Pvcglue.logger.info('BUILD') { "Building #{machine_name}" }
8
+
9
+ minion = self # for readability
10
+ Pvcglue::Packages::SshKeyCheck.apply(minion)
11
+ Pvcglue::Packages::AptRepos.apply(minion)
12
+ Pvcglue::Packages::AptUpdate.apply(minion)
13
+ Pvcglue::Packages::AptUpgrade.apply(minion)
14
+ Pvcglue::Packages::Swap.apply(minion)
15
+ Pvcglue::Packages::Apt.apply(minion)
16
+ Pvcglue::Packages::Firewall.apply(minion)
17
+ Pvcglue::Packages::UnattendedUpgrades.apply(minion)
18
+ Pvcglue::Packages::Users.apply(minion)
19
+ Pvcglue::Packages::AuthorizedKeys.apply(minion)
20
+ Pvcglue::Packages::Roles.apply(minion)
21
+
22
+
23
+ # puts '='*175
24
+ end
25
+
26
+ # def build_manager!
27
+ # Pvcglue.logger.info('MANAGER') { "Building #{machine_name}" }
28
+ # Pvcglue.cloud.set_manager_as_project
29
+ # build!
30
+ # end
31
+
32
+ def provision!
33
+ create! unless provisioned?
34
+ end
35
+
36
+ def provisioned?
37
+ public_ip.present?
38
+ end
39
+
40
+ def create!
41
+ raise(Thor::Error, "#{cloud_provider.name} unknown") unless cloud_provider.name == 'digital-ocean'
42
+ Pvcglue.logger.warn("Provisioning a machine for #{machine_name} on #{cloud_provider.name}...")
43
+
44
+ # TODO: Tags. production, staging, load-balancer, web, worker, database, postgress, cache, memcache...
45
+ name = machine_name
46
+ size = capacity || cloud_provider.default_capacity
47
+ image = cloud_provider.image
48
+ region = cloud_provider.region
49
+ # ap cloud_provider.initial_users
50
+ # ap cloud_provider
51
+ ssh_keys = cloud_provider.initial_users.map { |description, ssh_key| ssh_key }
52
+ backups = cloud_provider.backups.nil? ? true : cloud_provider.backups # default to true -- safety first!
53
+ tags = cloud_provider.tags
54
+
55
+ # client.droplets.all.each do |droplet|
56
+ # ap droplet
57
+ # end
58
+ droplet = DropletKit::Droplet.new(
59
+ name: name,
60
+ region: region,
61
+ image: image,
62
+ size: size,
63
+ ssh_keys: ssh_keys,
64
+ backups: backups,
65
+ ipv6: false,
66
+ private_networking: true,
67
+ user_data: '',
68
+ monitoring: true,
69
+ tags: tags
70
+ )
71
+ droplet = Pvcglue::DigitalOcean.client.droplets.create(droplet)
72
+ self.droplet = droplet
73
+ Pvcglue.logger.debug("Droplet ID: #{droplet.id}")
74
+ true
75
+ end
76
+
77
+ def has_role?(roles)
78
+ return true if roles == 'all'
79
+ !(Array(roles).map(&:to_sym) & roles_to_sym).empty?
80
+ end
81
+
82
+ def has_roles?(roles)
83
+ has_role?(roles)
84
+ end
85
+
86
+ def roles_to_sym
87
+ roles.map(&:to_sym)
88
+ end
89
+
90
+ def minion_manager?
91
+ has_role?('manager')
92
+ end
93
+
94
+ def get_user(user_name)
95
+ Pvcglue.cloud.data.users.detect { |user| user.name == user_name }
96
+ end
97
+
98
+ def get_users_from_group(names)
99
+ names = Array(names)
100
+ users = []
101
+ names.each do |name|
102
+ if name =~ /\A==.*==\z/
103
+ group = Pvcglue.cloud.data.groups[name[2..-3]]
104
+ # ap group
105
+ users.concat(get_users_from_group(group))
106
+ else
107
+ users << get_user(name)
108
+ end
109
+ end
110
+ users
111
+ end
112
+
113
+ def get_root_users
114
+ if minion_manager?
115
+ get_users_from_group('==manager_root_users==')
116
+ else
117
+ get_users_from_group('==lead_developers==')
118
+ end
119
+ end
120
+
121
+ def get_users
122
+ if minion_manager?
123
+ get_users_from_group('==manager_users==')
124
+ else
125
+ get_users_from_group('==developers==')
126
+ end
127
+ end
128
+
129
+ def get_root_authorized_keys_data
130
+ get_authorized_keys_data(get_root_users)
131
+ end
132
+
133
+ def get_users_authorized_keys_data
134
+ get_authorized_keys_data(get_users)
135
+ end
136
+
137
+ # def get_root_authorized_keys
138
+ # get_authorized_keys(get_root_users)
139
+ # end
140
+ #
141
+ # def get_users_authorized_keys
142
+ # get_authorized_keys(get_users)
143
+ # end
144
+ #
145
+ # def get_authorized_keys(users)
146
+ # keys = []
147
+ # users.each do |user|
148
+ # user.public_keys.each do |id, public_key|
149
+ # keys << public_key
150
+ # end
151
+ # end
152
+ # keys
153
+ # end
154
+
155
+ def get_github_authorized_keys(user)
156
+ return [] unless user.github_user_name.present?
157
+ uri = URI("https://github.com/#{user.github_user_name}.keys")
158
+ Net::HTTP.get(uri).split("\n")
159
+ end
160
+
161
+ def get_authorized_keys_data(users)
162
+ data = []
163
+ users.each do |user|
164
+ keys = []
165
+ keys += user.public_keys.values if user.public_keys
166
+ keys += get_github_authorized_keys(user)
167
+ keys.each do |public_key|
168
+ line = %Q(environment="PVCGLUE_USER=#{user.name}" #{public_key})
169
+ # line = %Q(command="export PVCGLUE_USER=#{id}" #{public_key})
170
+ data << line
171
+ end
172
+ end
173
+ data
174
+ end
175
+
176
+ # def update_from(another_minion)
177
+ # self.private_ip = another_minion.private_ip
178
+ # self.public_ip = another_minion.public_ip
179
+ # self.cloud_id = another_minion.cloud_id
180
+ # end
181
+ end
182
+ end
data/lib/pvcglue/nodes.rb CHANGED
@@ -17,7 +17,7 @@ module Pvcglue
17
17
 
18
18
  %w(lb db web caching redis).each do |role|
19
19
  if apply_role?(role)
20
- Pvcglue::Packages.apply(role.to_sym, :build, Pvcglue.cloud.nodes_in_stage(role))
20
+ Pvcglue::Packages.apply(role.to_sym, :build, Pvcglue.cloud.minions_filtered(role))
21
21
  end
22
22
  end
23
23
 
@@ -1,20 +1,20 @@
1
1
  #=======================================================================================================================
2
2
  package 'bootstrap' do
3
3
  #=======================================================================================================================
4
- depends_on 'time-zone'
5
- depends_on 'hostname'
6
- depends_on 'htop'
7
- depends_on 'ufw'
8
- depends_on 'applications_dir'
9
- depends_on 'authorized_keys_root'
10
- depends_on 'authorized_keys'
11
- depends_on 'sshd-config'
12
- depends_on 'firewall-config'
13
- depends_on 'firewall-enabled'
14
- depends_on 'unattended-security-upgrades'
4
+ depends_on 'time-zone' # Later, if needed
5
+ depends_on 'hostname' # Later, if needed
6
+ depends_on 'htop' # DONE
7
+ depends_on 'ufw' # DONE
8
+ depends_on 'applications_dir' # DONE
9
+ depends_on 'authorized_keys_root' # DONE
10
+ depends_on 'authorized_keys' # DONE
11
+ depends_on 'sshd-config' # Later, if needed
12
+ depends_on 'firewall-config' # DONE
13
+ depends_on 'firewall-enabled' # DONE
14
+ depends_on 'unattended-security-upgrades' # DONE
15
15
  end
16
16
 
17
- package 'applications_dir' do
17
+ package 'applications_dir' do # DONE
18
18
  depends_on 'deploy-user'
19
19
  validate do
20
20
  stat = run("stat --format=%U:%G:%a #{Pvcglue.configuration.web_app_base_dir}").strip
@@ -28,7 +28,7 @@ package 'applications_dir' do
28
28
  end
29
29
  end
30
30
 
31
- package 'deploy-user' do
31
+ package 'deploy-user' do # DONE
32
32
  apply do
33
33
  run "mkdir -p ~/.pvc && chmod 600 ~/.pvc"
34
34
  #run 'adduser --disabled-password --gecos "" deploy'
@@ -52,7 +52,7 @@ package 'deploy-user' do
52
52
 
53
53
  end
54
54
 
55
- package 'authorized_keys' do
55
+ package 'authorized_keys' do # DONE
56
56
 
57
57
  file({
58
58
  :template => ::Pvcglue.template_file_name('authorized_keys.erb'),
@@ -64,7 +64,7 @@ package 'authorized_keys' do
64
64
  })
65
65
  end
66
66
 
67
- package 'authorized_keys_root' do
67
+ package 'authorized_keys_root' do # DONE
68
68
 
69
69
  file({
70
70
  :template => ::Pvcglue.template_file_name('authorized_keys.erb'),
@@ -1,10 +1,10 @@
1
- package 'env-initialized' do
1
+ package 'env-initialized' do # DONE
2
2
  apply do
3
3
  ::Pvcglue::Env.initialize_stage_env
4
4
  end
5
5
  end
6
6
 
7
- package 'env-get-stage' do
7
+ package 'env-get-stage' do # DONE
8
8
  apply do
9
9
  data = run("cat #{::Pvcglue::Env.stage_env_file_name}")
10
10
  ::Pvcglue.cloud.stage_env = TOML.parse(data)
@@ -12,7 +12,7 @@ package 'env-get-stage' do
12
12
 
13
13
  end
14
14
 
15
- package 'env-set-stage' do
15
+ package 'env-set-stage' do # DONE
16
16
  apply do
17
17
  data = TOML.dump(Pvcglue.cloud.stage_env)
18
18
  run(%Q[echo '#{data}' | tee #{::Pvcglue::Env.stage_env_file_name} && chmod 600 #{::Pvcglue::Env.stage_env_file_name}])
@@ -20,7 +20,7 @@ package 'env-set-stage' do
20
20
 
21
21
  end
22
22
 
23
- package 'deploy-to-base' do
23
+ package 'deploy-to-base' do # DONE
24
24
  validate do
25
25
  stat = run("stat --format=%U:%G:%a #{Pvcglue.cloud.deploy_to_app_shared_dir}").strip
26
26
  stat == 'deploy:deploy:2775'
@@ -35,11 +35,11 @@ package 'deploy-to-base' do
35
35
  end
36
36
 
37
37
  package 'app-env' do
38
- depends_on 'deploy-to-base'
38
+ depends_on 'deploy-to-base' # DONE
39
39
  depends_on 'app-env-file'
40
40
  end
41
41
 
42
- package 'app-env-file' do
42
+ package 'app-env-file' do # DONE
43
43
  depends_on 'env-initialized'
44
44
 
45
45
  file({
@@ -54,7 +54,7 @@ package 'app-env-file' do
54
54
  end
55
55
 
56
56
 
57
- package 'env-push' do
57
+ package 'env-push' do # LATER
58
58
  apply do
59
59
  if File.exists?(::Pvcglue.cloud.env_local_file_name)
60
60
  data = File.read(::Pvcglue.cloud.env_local_file_name)
@@ -66,7 +66,7 @@ package 'env-push' do
66
66
  end
67
67
  end
68
68
 
69
- package 'env-pull' do
69
+ package 'env-pull' do # LATER
70
70
  apply do
71
71
  data = run("cat #{::Pvcglue::Env.stage_env_file_name}")
72
72
  if data.empty?
@@ -0,0 +1,48 @@
1
+ # Reference: http://manpages.ubuntu.com/manpages/precise/en/man8/ufw-framework.8.html
2
+ package 'firewall-config' do
3
+
4
+ file({
5
+ :template => Pvcglue.template_file_name('ufw.rules6.erb'),
6
+ :destination => '/lib/ufw/user6.rules',
7
+ :create_dirs => false,
8
+ :permissions => 0640,
9
+ :user => 'root',
10
+ :group => 'root'
11
+ }) { }
12
+
13
+ file({
14
+ :template => Pvcglue.template_file_name('ufw.rules.erb'),
15
+ :destination => '/lib/ufw/user.rules',
16
+ :create_dirs => false,
17
+ :permissions => 0640,
18
+ :user => 'root',
19
+ :group => 'root'
20
+ }) { sudo('service ufw restart') }
21
+
22
+ end
23
+
24
+ package 'firewall-enabled' do
25
+ validate do
26
+ result = sudo('ufw status verbose')
27
+ result =~ /Status: active/ && result =~ /Default: deny \(incoming\), allow \(outgoing\)/
28
+ end
29
+
30
+ apply do
31
+ sudo('ufw --force enable')
32
+ end
33
+ end
34
+
35
+ # TODO: add command line command for this
36
+ package 'update-firewall' do
37
+ # quick update of firewall settings only. Full bootstrap must be performed first.
38
+ depends_on 'firewall-config'
39
+ depends_on 'firewall-enabled'
40
+ end
41
+
42
+
43
+ # TODO: add command line command for this
44
+ package 'firewall-status' do
45
+ apply do
46
+ run "ufw status verbose"
47
+ end
48
+ end