danarchy_deploy 0.1.6 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/Gemfile.lock +9 -20
  4. data/README.md +10 -9
  5. data/Rakefile +0 -4
  6. data/bin/danarchy_deploy +23 -9
  7. data/danarchy_deploy.gemspec +4 -3
  8. data/lib/danarchy_deploy.rb +186 -55
  9. data/lib/danarchy_deploy/applicator.rb +39 -0
  10. data/lib/danarchy_deploy/applicator/nginx.rb +86 -0
  11. data/lib/danarchy_deploy/applicator/phpfpm.rb +84 -0
  12. data/lib/danarchy_deploy/applicator/redmine.rb +40 -0
  13. data/lib/danarchy_deploy/applicator/ssl.rb +14 -0
  14. data/lib/danarchy_deploy/applicator/wordpress.rb +146 -0
  15. data/lib/danarchy_deploy/applicator/wordpress/wpcli.rb +67 -0
  16. data/lib/danarchy_deploy/applicator/wordpress/wpcli_install.sh +36 -0
  17. data/lib/danarchy_deploy/applicator/wordpress/wpconfig.rb +49 -0
  18. data/lib/danarchy_deploy/archiver.rb +9 -7
  19. data/lib/danarchy_deploy/archiver/svn.rb +17 -0
  20. data/lib/danarchy_deploy/groups.rb +2 -2
  21. data/lib/danarchy_deploy/hash_deep_merge.rb +9 -0
  22. data/lib/danarchy_deploy/helpers.rb +42 -10
  23. data/lib/danarchy_deploy/services.rb +12 -25
  24. data/lib/danarchy_deploy/services/init.rb +52 -0
  25. data/lib/danarchy_deploy/services/init/openrc.rb +72 -0
  26. data/lib/danarchy_deploy/services/init/systemd.rb +69 -0
  27. data/lib/danarchy_deploy/services/mongodb.rb +162 -0
  28. data/lib/danarchy_deploy/services/mysql.rb +58 -0
  29. data/lib/danarchy_deploy/services/mysql/new_server.rb +72 -0
  30. data/lib/danarchy_deploy/services/mysql/privileges.rb +35 -0
  31. data/lib/danarchy_deploy/system.rb +86 -0
  32. data/lib/danarchy_deploy/system/centos.rb +17 -0
  33. data/lib/danarchy_deploy/system/debian.rb +61 -0
  34. data/lib/danarchy_deploy/system/gentoo.rb +66 -0
  35. data/lib/danarchy_deploy/system/opensuse.rb +22 -0
  36. data/lib/danarchy_deploy/templater.rb +53 -13
  37. data/lib/danarchy_deploy/users.rb +31 -21
  38. data/lib/danarchy_deploy/version.rb +1 -1
  39. metadata +34 -12
@@ -0,0 +1,162 @@
1
+ require 'mongo'
2
+
3
+ module DanarchyDeploy
4
+ module Services
5
+ class MongoDB
6
+ def self.new(os, mongodb, options)
7
+ @mongodb = mongodb
8
+ @options = options
9
+ puts "\n" + self.name
10
+ puts "\n > Configuring MongoDB service."
11
+
12
+ DanarchyDeploy::Services::Init.init_manager(os, 'mongodb', 'start', options) if ! options[:pretend]
13
+ Mongo::Logger.logger.level = Logger::FATAL
14
+ mongodb_conf, updated_conf = self.load_mongodb_conf
15
+ host_port = mongodb_conf['net']['bindIp'].split(',').first + ':' + mongodb_conf['net']['port'].to_s
16
+ admin_user, new_admin = self.load_admin_user
17
+
18
+ if new_admin == true
19
+ client = Mongo::Client.new(['127.0.0.1'], database: 'admin')
20
+ self.ensure_user(client.database, admin_user)
21
+ end
22
+
23
+ if ! options[:pretend] && updated_conf == true || new_admin == true
24
+ puts 'Stopping MongoDB'
25
+ DanarchyDeploy::Services::Init.init_manager(os, 'mongodb', 'stop', options)
26
+ self.save_mongodb_conf(mongodb_conf)
27
+ puts 'Starting MongoDB'
28
+ DanarchyDeploy::Services::Init.init_manager(os, 'mongodb', 'start', options)
29
+ end
30
+
31
+ client = Mongo::Client.new([host_port], database: 'admin',
32
+ user: admin_user[:user], password: Base64.decode64(admin_user[:password]))
33
+ self.ensure_user(client.database, admin_user)
34
+
35
+ if databases = @mongodb[:databases]
36
+ databases.each do |database, params|
37
+ print "\n |+ Fake Run: " if options[:pretend]
38
+ puts "\n Reviewing database: #{database}"
39
+ db = client.use(database).database
40
+ params[:users].each do |user|
41
+ puts " > Checking user: #{user[:user]}"
42
+ self.ensure_user(db, user)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+ def self.load_mongodb_conf
50
+ updated_conf = false
51
+ @mongodb[:mongodb_conf] = @mongodb[:mongodb_conf] ?
52
+ @mongodb[:mongodb_conf] :
53
+ '/etc/mongodb.conf'
54
+ mongodb_conf = File.exist?(@mongodb[:mongodb_conf]) ? YAML.load_file(@mongodb[:mongodb_conf]) : Hash.new
55
+
56
+ generated_mongodb_conf = self.generate_mongodb_conf
57
+ updated_conf = mongodb_conf != generated_mongodb_conf
58
+ [generated_mongodb_conf, updated_conf]
59
+ end
60
+
61
+ def self.generate_mongodb_conf
62
+ if ! File.readlines('/etc/security/limits.conf').grep(/mongodb/)
63
+ entry = 'mongodb soft nofile 32000'
64
+ entry += 'mongodb hard nofile 64000'
65
+ File.open('/etc/security/limits.conf', 'a+') do |f|
66
+ f.write entry
67
+ end
68
+ end
69
+
70
+ mongodb_conf = {
71
+ 'net' => { 'port' => 27017, 'bindIp' => '127.0.0.1' },
72
+ 'storage' => { 'dbPath' => '/var/lib/mongodb' },
73
+ 'systemLog' => { 'destination' => 'file',
74
+ 'path' => '/var/log/mongodb/mongodb.log',
75
+ 'quiet' => true,
76
+ 'logAppend' => true }
77
+ }
78
+
79
+ if @mongodb[:config]
80
+ mdb_conf = DanarchyDeploy::Helpers.hash_symbols_to_strings(@mongodb[:config])
81
+ mongodb_conf = mongodb_conf.deep_merge(mdb_conf)
82
+ end
83
+
84
+ mongodb_conf
85
+ end
86
+
87
+ def self.save_mongodb_conf(mongodb_conf)
88
+ if @options[:pretend]
89
+ puts "\n |+ Fake run: Saving MongoDB Configuration"
90
+ else
91
+ puts 'Saving MongoDB Configuration'
92
+ File.write(@mongodb[:mongodb_conf], mongodb_conf.to_yaml)
93
+ end
94
+ end
95
+
96
+ # def self.ensure_admin_user(host_port, admin_user)
97
+ # begin
98
+ # client = Mongo::Client.new([host_port], database: 'admin',
99
+ # username: admin_user[:user], password: admin_user[:password])
100
+ # database = client.database
101
+ # database.users.info(admin_user[:user])
102
+ # rescue Mongo::Auth::Unauthorized, Mongo::Error => e
103
+ # puts e.message
104
+
105
+ # if @options[:pretend]
106
+ # puts " |+ Fake Run: Creating admin user #{admin_user[:user]}"
107
+ # else
108
+ # client = Mongo::Client.new([host_port], database: 'admin')
109
+ # db = client.database
110
+ # self.ensure_user(db, admin_user)
111
+ # end
112
+ # end
113
+ # end
114
+
115
+ def self.generate_admin_user
116
+ password = @mongodb[:admin_password] ?
117
+ @mongodb[:admin_password].chomp :
118
+ Base64.encode64(SecureRandom.base64(14)).chomp
119
+
120
+ { user: "admin",
121
+ password: password,
122
+ roles: [{ role: "root", db: "admin" },
123
+ { role: "userAdminAnyDatabase", db: "admin" },
124
+ { role: "dbAdminAnyDatabase", db: "admin" },
125
+ { role: "readWriteAnyDatabase", db: "admin" }] }
126
+ end
127
+
128
+ def self.load_admin_user
129
+ admin_user = nil
130
+ new_user = false
131
+
132
+ if File.exist?('/root/.mdb_admin_user.json')
133
+ admin_user = JSON.parse(File.read('/root/.mdb_admin_user.json'), symbolize_names: true)
134
+ else
135
+ admin_user = self.generate_admin_user
136
+ self.save_admin_user(admin_user) if ! @options[:pretend]
137
+ new_user = true
138
+ end
139
+
140
+ [admin_user, new_user]
141
+ end
142
+
143
+ def self.save_admin_user(admin_user)
144
+ File.write('/root/.mdb_admin_user.json', JSON.pretty_generate(admin_user))
145
+ end
146
+
147
+ def self.ensure_user(db, user)
148
+ puts user if @options[:vars_verbose]
149
+ password = Base64.decode64(user[:password]).chomp
150
+ if @options[:pretend]
151
+ puts "\n |+ Fake Run: Creating/Updating user: #{user[:user]}"
152
+ elsif db.users.info(user[:user]).empty?
153
+ puts "\n |+ Creating user: #{user[:user]}"
154
+ db.users.create(user[:user], password: password, roles: user[:roles])
155
+ else
156
+ puts "\n |+ Updating user: #{user[:user]}"
157
+ db.users.update(user[:user], password: password, roles: user[:roles])
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'mysql/new_server'
2
+ require_relative 'mysql/privileges'
3
+
4
+ module DanarchyDeploy
5
+ module Services
6
+ class MySQL
7
+ def self.new(os, mysql, options)
8
+ puts "\n" + self.name
9
+ puts "\n > Configuring MySQL service."
10
+
11
+ mysql = self.set_parameters(mysql)
12
+ self.generate_my_cnf(mysql, options)
13
+
14
+ if File.exist?(mysql[:my_cnf]) && Dir.exist?(mysql[:datadir] + '/mysql')
15
+ puts " |+ Using existing MySQL service."
16
+ else
17
+ MySQL::NewServer.new(os, mysql, options)
18
+ end
19
+
20
+ if mysql[:privileges]
21
+ puts "\n > Configuring MySQL Privileges"
22
+ MySQL::Privileges.new(mysql, options)
23
+ end
24
+ end
25
+
26
+ def self.set_parameters(mysql)
27
+ mysql[:default_file] = mysql[:default_file] ?
28
+ mysql[:default_file] :
29
+ '/root/.my.cnf'
30
+ mysql[:my_cnf] = mysql[:my_cnf] ?
31
+ mysql[:my_cnf] :
32
+ '/etc/mysql/my.cnf'
33
+ mysql[:datadir] = mysql[:datadir] ?
34
+ mysql[:datadir] :
35
+ '/var/lib/mysql'
36
+ mysql[:bind_address] = mysql[:bind_address] ?
37
+ mysql[:bind_address] :
38
+ '127.0.0.1'
39
+
40
+ mysql
41
+ end
42
+
43
+ def self.generate_my_cnf(mysql, options)
44
+ source = options[:deploy_dir] +
45
+ '/templates/services/mysql/my.cnf.erb'
46
+
47
+ templates = [{ target: mysql[:my_cnf],
48
+ source: source,
49
+ variables: {
50
+ datadir: mysql[:datadir],
51
+ bind_address: mysql[:bind_address] }
52
+ }]
53
+
54
+ DanarchyDeploy::Templater.new(templates, options)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,72 @@
1
+
2
+ module DanarchyDeploy
3
+ module Services
4
+ class MySQL
5
+ class NewServer
6
+ def self.new(os, mysql, options)
7
+ self.generate_root_mycnf(mysql, options)
8
+
9
+ if os == 'gentoo'
10
+ self.gentoo_new_mysql(mysql, options)
11
+ elsif os == 'opensuse'
12
+ self.opensuse_new_mysql(mysql, options)
13
+ elsif %w[debian ubuntu].include?(os)
14
+ self.debian_new_mysql(mysql, options)
15
+ elsif %w[centos redhat].include?(os)
16
+ self.centos_new_mysql(mysql, options)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def self.gentoo_new_mysql(mysql, options)
23
+ puts "\n > Performing first time MySQL configuration."
24
+ cmd = 'emerge --config mariadb'
25
+ config_result = DanarchyDeploy::Helpers.run_command(cmd, options)
26
+
27
+ if config_result[:stderr]
28
+ abort(' |! ERROR: Failed to configure MySQL')
29
+ else config_result[:stdout]
30
+ puts " |+ MySQL configured successfully"
31
+ puts config_result[:stdout]
32
+ end
33
+
34
+ puts "\n > Starting MySQL."
35
+ DanarchyDeploy::Services::Init.init_manager('gentoo', 'mysql', 'start', options)
36
+ end
37
+
38
+ def self.debian_new_mysql(mysql, options)
39
+ puts " ! Debian/Ubuntu MySQL configuration not yet implemented!"
40
+ end
41
+
42
+ def self.centos_new_mysql(mysql, options)
43
+ puts " ! CentOS/Redhat MySQL configuration not yet implemented!"
44
+
45
+ end
46
+
47
+ def self.opensuse_new_mysql(mysql, options)
48
+ puts " ! OpenSUSE MySQL configuration not yet implemented!"
49
+ end
50
+
51
+ def self.generate_root_mycnf(mysql, options)
52
+ return if File.exist?(mysql[:default_file])
53
+ puts " |+ Generating #{mysql[:default_file]} file."
54
+ password = SecureRandom.base64(14)
55
+ source = options[:deploy_dir] +
56
+ '/templates/services/mysql/root_my.cnf.erb'
57
+
58
+ templates = [{ target: mysql[:default_file],
59
+ source: source,
60
+ variables: {
61
+ host: 'localhost',
62
+ user: 'root',
63
+ pass: password,
64
+ port: '3306' }
65
+ }]
66
+
67
+ DanarchyDeploy::Templater.new(templates, options)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,35 @@
1
+ # require 'mysql2'
2
+ # Need to run with CLI rather than Ruby gem to reduce dependencies when this isn't used.
3
+
4
+ module DanarchyDeploy
5
+ module Services
6
+ class MySQL
7
+ class Privileges
8
+ def self.new(mysql, options)
9
+ sql_grants = sql_template(mysql, options)
10
+ run_sql_grants(mysql, sql_grants, options)
11
+ end
12
+
13
+ def self.sql_template(mysql, options)
14
+ sql_grants = '/root/.user_grants.sql'
15
+ source = options[:deploy_dir] +
16
+ '/templates/services/mysql/user_db_grants.sql.erb'
17
+ templates = [{ target: sql_grants,
18
+ source: source,
19
+ variables: mysql[:privileges] }]
20
+
21
+ DanarchyDeploy::Templater.new(templates, options)
22
+ sql_grants
23
+ end
24
+
25
+ def self.run_sql_grants(mysql, sql_grants, options)
26
+ # Using CLI commands for now;
27
+ # mysql2 requires mysql client be installed even if we won't be using it.
28
+ # client = Mysql2::Client.new(:default_file => default_file)
29
+ cmd = "mysql --defaults-file=#{mysql[:default_file]} -v < #{sql_grants}"
30
+ DanarchyDeploy::Helpers.run_command(cmd, options)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,86 @@
1
+ require_relative 'system/centos'
2
+ require_relative 'system/debian'
3
+ require_relative 'system/gentoo'
4
+ require_relative 'system/opensuse'
5
+
6
+ module DanarchyDeploy
7
+ module System
8
+ def self.new(deployment, options)
9
+ abort('Operating System not defined! Exiting!') if !deployment[:os]
10
+ puts "\n" + self.name
11
+
12
+ installer, updater, cleaner = prep_operating_system(deployment, options)
13
+ install_result = nil
14
+ if deployment[:packages] && !deployment[:packages].empty?
15
+ packages = deployment[:packages].join(' ')
16
+ puts "\nInstalling packages..."
17
+ install_result = DanarchyDeploy::Helpers.run_command("#{installer} #{packages}", options)
18
+ puts install_result[:stdout] if install_result[:stdout]
19
+ else
20
+ puts "\nNo packages to install."
21
+ end
22
+
23
+ if !options[:pretend]
24
+ puts "\nRunning system updates..."
25
+ updater_result = DanarchyDeploy::Helpers.run_command(updater, options)
26
+ puts updater_result[:stdout] if updater_result[:stdout]
27
+ puts "\nCleaning up unused packages..."
28
+ cleanup_result = DanarchyDeploy::Helpers.run_command(cleaner, options)
29
+ puts cleanup_result[:stdout] if cleanup_result[:stdout]
30
+ end
31
+
32
+ deployment
33
+ end
34
+
35
+ private
36
+ def self.prep_operating_system(deployment, options)
37
+ (installer, updater, cleaner) = nil
38
+ os = deployment[:os]
39
+
40
+ if deployment[:system]
41
+ if deployment[:system][:archives]
42
+ puts " > Deploying system archives"
43
+ DanarchyDeploy::Archiver.new(deployment[:system][:archives], options)
44
+ end
45
+
46
+ if deployment[:system][:templates]
47
+ puts "\n > Configuring system templates for #{deployment[:os]}"
48
+ DanarchyDeploy::Templater.new(deployment[:system][:templates], options)
49
+
50
+ # Add deployment[:system][:dmcrypt], deployment[:system][:lvm], and deployment[:system][:fstab] here
51
+ deployment[:system][:templates].each do |t|
52
+ if t[:target] == '/etc/fstab'
53
+ t[:variables].each do |v|
54
+ if !Dir.exist?(v[:mountpoint])
55
+ puts "Creating mountpoint: #{v[:mountpoint]}"
56
+ FileUtils.mkdir_p(v[:mountpoint]) if !options[:pretend]
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+
65
+ puts "\n > Mounting Filesystems"
66
+ if !options[:pretend]
67
+ mount_result = DanarchyDeploy::Helpers.run_command('mount -a', options)
68
+ abort(' |! Failed to mount filesystems!') if mount_result[:stderr]
69
+ end
70
+
71
+ if os.downcase == 'gentoo'
72
+ (installer, updater, cleaner) = DanarchyDeploy::System::Gentoo.new(deployment, options)
73
+ elsif %w[debian ubuntu].include?(os.downcase)
74
+ (installer, updater, cleaner) = DanarchyDeploy::System::Debian.new(deployment, options)
75
+ elsif os.downcase == 'opensuse'
76
+ puts 'OpenSUSE is not fully supported yet!'
77
+ (installer, updater, cleaner) = DanarchyDeploy::System::OpenSUSE.new(deployment, options)
78
+ elsif %w[centos redhat].include?(os.downcase)
79
+ puts 'CentOS/RedHat is not fully supported yet!'
80
+ (installer, updater, cleaner) = DanarchyDeploy::System::CentOS.new(deployment, options)
81
+ end
82
+
83
+ [installer, updater, cleaner]
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module DanarchyDeploy
3
+ module System
4
+ class CentOS
5
+ def self.new(deployment, options)
6
+ puts "\n" + self.name
7
+ puts "#{deployment[:os].capitalize} detected! Using yum."
8
+ # needs more testing
9
+ installer = 'yum install -y '
10
+ updater = 'yum upgrade -y'
11
+ cleaner = 'yum clean all'
12
+
13
+ [installer, updater, cleaner]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ require 'net/http'
2
+
3
+ module DanarchyDeploy
4
+ module System
5
+ class Debian
6
+ def self.new(deployment, options)
7
+ puts "\n" + self.name
8
+ puts "#{deployment[:os].capitalize} detected! Using apt."
9
+
10
+ if deployment[:apt]
11
+ if deployment[:apt][:templates]
12
+ puts "\nChecking Apt configs."
13
+ DanarchyDeploy::Templater.new(deployment[:apt][:templates], options)
14
+ end
15
+
16
+ if deployment[:apt][:gpgkeys]
17
+ puts "\nInstalling Apt GPG Keys."
18
+ install_gpgkeys(deployment[:apt][:gpgkeys], options)
19
+ end
20
+ end
21
+
22
+ nonint = 'export DEBIAN_FRONTEND=noninteractive ; '
23
+ installer = nonint + 'apt-get install -y '
24
+ installer += '--dry-run ' if options[:pretend]
25
+ updater = nonint + 'apt-get upgrade -y '
26
+ cleaner = nonint + 'apt-get autoclean -y '
27
+
28
+ puts "\nUpdating Apt repos..."
29
+ DanarchyDeploy::Helpers.run_command(nonint + 'apt-get update', options)
30
+
31
+ [installer, updater, cleaner]
32
+ end
33
+
34
+ private
35
+ def self.install_gpgkeys(gpgkeys, options)
36
+ gpgkeys.each do |url|
37
+ puts "\n > Acquiring GPG key from: #{url}"
38
+ tmpfile = '/var/tmp/' + `date +%s`.chomp + '.gpgkey.tmp'
39
+ gpgkey = Net::HTTP.get(URI(url))
40
+ if ! gpgkey
41
+ abort(' ! GPG key download failed!')
42
+ else
43
+ puts " |+ GPG key successfully downloaded!"
44
+ File.write(tmpfile, gpgkey)
45
+ abort(" ! Failed to write tmpfile for url: #{url} => #{tmpfile}") if ! File.exist?(tmpfile)
46
+
47
+ # Silence noise about non-TTY terminal thanks to apt-key
48
+ gpgcmd = "export APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=false; apt-key add -qq #{tmpfile}"
49
+ gpg_result = DanarchyDeploy::Helpers.run_command(gpgcmd, { quiet: true })
50
+
51
+ if gpg_result[:stderr]
52
+ abort(" ! Failed to write key for: #{url}")
53
+ elsif gpg_result[:stdout]
54
+ puts " |+ GPG Key saved!"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end