server_settings 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +77 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +202 -0
- data/Rakefile +2 -0
- data/example/sample.rb +53 -0
- data/lib/capistrano/server_settings.rb +8 -0
- data/lib/server_settings.rb +113 -0
- data/lib/server_settings/capistrano.rb +23 -0
- data/lib/server_settings/database.rb +29 -0
- data/lib/server_settings/database_config.rb +46 -0
- data/lib/server_settings/host.rb +16 -0
- data/lib/server_settings/host_collection.rb +31 -0
- data/lib/server_settings/railtie.rb +10 -0
- data/lib/server_settings/role.rb +42 -0
- data/lib/server_settings/role_db.rb +59 -0
- data/lib/server_settings/tasks.rb +9 -0
- data/lib/server_settings/tasks/db.rake +98 -0
- data/lib/server_settings/version.rb +3 -0
- data/server_settings.gemspec +25 -0
- data/spec/lib/server_settings/database_config_spec.rb +97 -0
- data/spec/lib/servers_config_spec.rb +300 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/test-yaml/role1.yml +3 -0
- data/spec/test-yaml/role2.yml +3 -0
- metadata +133 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'server_settings'
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module ServersGroup
|
5
|
+
def self.extend(configuration)
|
6
|
+
configuration.load do
|
7
|
+
Capistrano::Configuration.instance.load do
|
8
|
+
def load_servers(pattern)
|
9
|
+
ServerSettings.load_config_dir(pattern)
|
10
|
+
ServerSettings.each_role do |role, hosts|
|
11
|
+
role role.to_sym, *hosts.map(&:host)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
if Capistrano::Configuration.instance
|
21
|
+
Capistrano::ServersGroup.extend(Capistrano::Configuration.instance)
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class ServerSettings
|
2
|
+
class Database
|
3
|
+
attr_accessor :name, :group, :master, :backup, :slaves, :settings
|
4
|
+
def initialize(name, group)
|
5
|
+
@name = name
|
6
|
+
@group = group
|
7
|
+
end
|
8
|
+
|
9
|
+
def config(role)
|
10
|
+
host = send(role)
|
11
|
+
case host
|
12
|
+
when Array
|
13
|
+
host.map { |h| settings.merge(:host => h) }
|
14
|
+
when String
|
15
|
+
settings.merge(:host => host)
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def host
|
22
|
+
@master
|
23
|
+
end
|
24
|
+
|
25
|
+
def has_slave?
|
26
|
+
!! @slaves and not @slaves.empty?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class ServerSettings
|
2
|
+
class DatabaseConfig
|
3
|
+
def self.slave_name(name, idx)
|
4
|
+
name + "_slave#{idx}"
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.generate_database_config(db_role, with_slave:true)
|
8
|
+
configuration = {}
|
9
|
+
return configuration unless ServerSettings.databases
|
10
|
+
|
11
|
+
ServerSettings.databases.each do |db|
|
12
|
+
next unless db.config(db_role)
|
13
|
+
|
14
|
+
role_db_config = db.config(db_role)
|
15
|
+
stringify_keys!(role_db_config) if defined? Rails
|
16
|
+
|
17
|
+
if db.name == "default"
|
18
|
+
if defined? Rails
|
19
|
+
configuration[Rails.env] = role_db_config
|
20
|
+
else
|
21
|
+
configuration.merge!(role_db_config)
|
22
|
+
end
|
23
|
+
elsif db.group
|
24
|
+
configuration[db.group] ||= {}
|
25
|
+
configuration[db.group][db.name] = role_db_config
|
26
|
+
else
|
27
|
+
configuration[db.name] = role_db_config
|
28
|
+
end
|
29
|
+
|
30
|
+
if with_slave && db.has_slave?
|
31
|
+
db.config(:slaves).each.with_index(1) do |config, idx|
|
32
|
+
# スレーブのバックアップホストは、マスターのバックアップホストと同じにする
|
33
|
+
config[:host] = db.backup if db_role == :backup
|
34
|
+
stringify_keys!(config) if defined? Rails
|
35
|
+
configuration[slave_name(db.name, idx)] = config
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
configuration
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.stringify_keys!(config)
|
43
|
+
config.keys.each { |key| config[key.to_s] = config.delete(key) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class ServerSettings
|
2
|
+
|
3
|
+
class HostCollection < Array
|
4
|
+
def initialize(hosts, role_config)
|
5
|
+
@role_config = role_config
|
6
|
+
unless hosts.kind_of?(Array)
|
7
|
+
raise InvalidHosts, "hosts: #{hosts} is not array"
|
8
|
+
end
|
9
|
+
|
10
|
+
hosts.each do |host_exp|
|
11
|
+
self.push Host.parse(host_exp)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_format(format)
|
16
|
+
self.map do |host|
|
17
|
+
replacemap = @role_config
|
18
|
+
replacemap['%host'] = host.host
|
19
|
+
replacemap['%port'] = host.port if host.port
|
20
|
+
replacemap.inject(format) do |string, mapping|
|
21
|
+
string.gsub(*mapping)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Errors
|
27
|
+
class InvalidHosts < StandardError ; end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class ServerSettings
|
2
|
+
|
3
|
+
class Role
|
4
|
+
attr_reader :name, :config
|
5
|
+
|
6
|
+
def initialize(role, config)
|
7
|
+
@name = role
|
8
|
+
@config = load(config)
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(config)
|
12
|
+
role_options = config.keys.select{|s| s != "hosts"}
|
13
|
+
@settings = Hash[*role_options.map do |option_name|
|
14
|
+
[ "%#{option_name}", config[option_name].to_s]
|
15
|
+
end.flatten]
|
16
|
+
if config.has_key?("hosts")
|
17
|
+
config["hosts"]= HostCollection.new(config["hosts"], @settings)
|
18
|
+
end
|
19
|
+
config
|
20
|
+
end
|
21
|
+
|
22
|
+
def hosts
|
23
|
+
@config["hosts"] if @config.has_key?("hosts")
|
24
|
+
end
|
25
|
+
|
26
|
+
def host
|
27
|
+
hosts.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(name, *args, &block)
|
31
|
+
key = name.to_s
|
32
|
+
return nil unless @config.has_key? key
|
33
|
+
@config[key]
|
34
|
+
end
|
35
|
+
|
36
|
+
def with_format(format)
|
37
|
+
hosts.with_format(format)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class ServerSettings
|
2
|
+
|
3
|
+
class RoleDB < Role
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def databases
|
7
|
+
@config.keys.select { |a| a.kind_of?(String) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def build_db(name, config, group = nil)
|
11
|
+
db = Database.new(name, group)
|
12
|
+
db.master = config[:master]
|
13
|
+
db.backup = config[:backup]
|
14
|
+
db.slaves = config[:slaves]
|
15
|
+
db.settings = config_params(config)
|
16
|
+
return db
|
17
|
+
end
|
18
|
+
|
19
|
+
def find(db_name)
|
20
|
+
select { |s| s.name == db_name }.first
|
21
|
+
end
|
22
|
+
|
23
|
+
def each
|
24
|
+
default_db = build_db("default", @config)
|
25
|
+
yield default_db
|
26
|
+
|
27
|
+
databases.each do |db_name|
|
28
|
+
config = @config[db_name]
|
29
|
+
|
30
|
+
if config && config.has_key?(:master)
|
31
|
+
db = build_db(db_name, config)
|
32
|
+
db.settings = default_db.settings.merge(db.settings)
|
33
|
+
yield db
|
34
|
+
|
35
|
+
else # this is group section
|
36
|
+
group_name = db_name
|
37
|
+
config.map do |nest_db_name, nest_config|
|
38
|
+
db = build_db(nest_db_name, nest_config, group_name)
|
39
|
+
db.settings = default_db.settings.merge(db.settings)
|
40
|
+
yield db
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def hosts
|
47
|
+
find_all
|
48
|
+
end
|
49
|
+
|
50
|
+
def config_params(config)
|
51
|
+
exclude_settings = [ :master, :backup, :slaves ]
|
52
|
+
config_keys = config.keys.select do |s|
|
53
|
+
s.is_a?(Symbol) and not exclude_settings.include?(s)
|
54
|
+
end
|
55
|
+
Hash[*config_keys.map {|s| [s, config[s]] }.flatten]
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
namespace :server_settings do
|
2
|
+
namespace :db do
|
3
|
+
namespace :create do
|
4
|
+
require "colorize"
|
5
|
+
|
6
|
+
def build_new_db_configs
|
7
|
+
ServerSettings::DatabaseConfig.generate_database_config(:master).each_with_object([]) do |(_, config), new_db_configs|
|
8
|
+
client = Mysql2::Client.new(username: config["username"], password: config["password"], host: config["host"])
|
9
|
+
if client.query("SHOW DATABASES LIKE '#{ config['database'] }'").to_a.blank?
|
10
|
+
new_db_configs << [config, client]
|
11
|
+
else
|
12
|
+
client.close
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def show_new_databases(new_db_configs)
|
18
|
+
if new_db_configs.blank?
|
19
|
+
puts "There is no new databases."
|
20
|
+
else
|
21
|
+
new_db_configs.each do |config, _|
|
22
|
+
puts format("* %-15s: new database '%s'", config["host"], config["database"]).colorize(:green)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def close_connections(new_db_configs)
|
28
|
+
new_db_configs.each { |_, client| client.close }
|
29
|
+
end
|
30
|
+
|
31
|
+
def confirm_and_execute(prompt, &block)
|
32
|
+
print "#{ prompt } (yes/N): "
|
33
|
+
if $stdin.gets.strip == "yes"
|
34
|
+
block.call
|
35
|
+
else
|
36
|
+
puts "Operation canceled."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def perform_show_status(new_db_configs)
|
41
|
+
show_new_databases(new_db_configs)
|
42
|
+
close_connections(new_db_configs)
|
43
|
+
end
|
44
|
+
|
45
|
+
def perform_create_databases(new_db_configs)
|
46
|
+
show_new_databases(new_db_configs)
|
47
|
+
confirm_and_execute "Are you sure you want to execute above?" do
|
48
|
+
new_db_configs.each do |config, client|
|
49
|
+
command = "CREATE DATABASE IF NOT EXISTS #{ config['database'] }"
|
50
|
+
puts "Executing '#{ command }' on #{ config['host'] }"
|
51
|
+
client.query(command)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
ensure
|
55
|
+
close_connections(new_db_configs)
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "Show status of new databases not created yet"
|
59
|
+
task :status => :environment do
|
60
|
+
new_db_configs = build_new_db_configs
|
61
|
+
perform_show_status(new_db_configs)
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "Confirm and execute CREATE DATABASE for each new database"
|
65
|
+
task :execute => :environment do
|
66
|
+
new_db_configs = build_new_db_configs
|
67
|
+
next if new_db_configs.blank?
|
68
|
+
perform_create_databases(new_db_configs)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "Confirm and execute Drop DATABASE for all database"
|
73
|
+
task :drop => :environment do
|
74
|
+
all_db_configs = build_all_db_configs
|
75
|
+
next if all_db_configs.blank?
|
76
|
+
perform_drop_databases(all_db_configs)
|
77
|
+
end
|
78
|
+
|
79
|
+
def build_all_db_configs
|
80
|
+
ServerSettings::DatabaseConfig.generate_database_config(:master).each_with_object([]) do |(_, config), all_db_configs|
|
81
|
+
client = Mysql2::Client.new(username: config["username"], password: config["password"], host: config["host"])
|
82
|
+
all_db_configs << [config, client]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def perform_drop_databases(all_db_configs)
|
87
|
+
confirm_and_execute "Are you sure you want to execute above?" do
|
88
|
+
all_db_configs.each do |config, client|
|
89
|
+
command = "DROP DATABASE IF EXISTS #{ config['database'] }"
|
90
|
+
puts "Executing '#{ command }' on #{ config['host'] }"
|
91
|
+
client.query(command)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
ensure
|
95
|
+
close_connections(all_db_configs)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'server_settings/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "server_settings"
|
8
|
+
spec.version = ServerSettings::VERSION
|
9
|
+
spec.authors = ["Osamu MATSUMOTO", "Contributers"]
|
10
|
+
spec.email = ["osamu.matsumoto@gmail.com"]
|
11
|
+
spec.summary = %q{Server Configuration logic}
|
12
|
+
spec.description = %q{Server Configuration logic for any where}
|
13
|
+
spec.homepage = "https://github.com/monsterstrike/server_settings"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "colorize"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'server_settings'
|
3
|
+
|
4
|
+
describe "ServerSettings::DatabaseConfig" do
|
5
|
+
let (:config1) do
|
6
|
+
yaml_text = <<-EOF
|
7
|
+
---
|
8
|
+
databases: &default
|
9
|
+
:adapter: mysql2
|
10
|
+
:encoding: utf8
|
11
|
+
:reconnect: true
|
12
|
+
:database: server_settings
|
13
|
+
:pool: 5
|
14
|
+
:username: monsterstrike
|
15
|
+
:password: monsterstrike
|
16
|
+
:master: localhost
|
17
|
+
user:
|
18
|
+
<<: *default
|
19
|
+
:database: server_settings_user
|
20
|
+
has_slave:
|
21
|
+
<<: *default
|
22
|
+
:database: server_settings_has_slave
|
23
|
+
:slaves: [ localhost ]
|
24
|
+
archive:
|
25
|
+
archive_me:
|
26
|
+
<<: *default
|
27
|
+
has_backup:
|
28
|
+
<<: *default
|
29
|
+
:backup: 'backup.com'
|
30
|
+
no_backup:
|
31
|
+
<<: *default
|
32
|
+
EOF
|
33
|
+
end
|
34
|
+
before do
|
35
|
+
filepath = "config.yml"
|
36
|
+
allow(IO).to receive(:read).with(filepath).and_return(config1)
|
37
|
+
allow(File).to receive(:mtime).with(filepath).and_return(Time.now)
|
38
|
+
ServerSettings.load_config("config.yml")
|
39
|
+
end
|
40
|
+
after do
|
41
|
+
ServerSettings.destroy
|
42
|
+
end
|
43
|
+
describe ".slave_name" do
|
44
|
+
it { expect(ServerSettings::DatabaseConfig.slave_name("hoge", 1)).to eq "hoge_slave1" }
|
45
|
+
end
|
46
|
+
describe ".generate_database_config" do
|
47
|
+
context "check configuration" do
|
48
|
+
let(:database_config) { database_config = ServerSettings::DatabaseConfig.generate_database_config(:master) }
|
49
|
+
it "contain `user` key" do
|
50
|
+
expect(database_config["user"].class).to eq Hash
|
51
|
+
end
|
52
|
+
context "when has slave" do
|
53
|
+
it "contain slave key" do
|
54
|
+
expect(database_config["has_slave_slave1"].class).to eq Hash
|
55
|
+
end
|
56
|
+
end
|
57
|
+
context "when has group" do
|
58
|
+
it "create nest configuration" do
|
59
|
+
expect(database_config["archive"]["archive_me"].class).to eq Hash
|
60
|
+
end
|
61
|
+
end
|
62
|
+
context "when no slaves options" do
|
63
|
+
it "does not exist slave key" do
|
64
|
+
no_slave_config = ServerSettings::DatabaseConfig.generate_database_config(:master, with_slave: false)
|
65
|
+
expect(no_slave_config.has_key? "has_slave_slave1").to be false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
context "when use backup role" do
|
69
|
+
let(:backup_config) { ServerSettings::DatabaseConfig.generate_database_config :backup }
|
70
|
+
it "change host to backup" do
|
71
|
+
expect(backup_config["has_backup"][:host]).to eq "backup.com"
|
72
|
+
end
|
73
|
+
it "does not set key, when not set backup" do
|
74
|
+
expect(backup_config.has_key? "no_backup").to eq false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
context "when use rails" do
|
79
|
+
before do
|
80
|
+
module Rails
|
81
|
+
def self.env
|
82
|
+
end
|
83
|
+
end
|
84
|
+
allow(Rails).to receive(:env).and_return("test")
|
85
|
+
end
|
86
|
+
it "contain environment key" do
|
87
|
+
database_config = ServerSettings::DatabaseConfig.generate_database_config(:master)
|
88
|
+
expect(database_config["test"]).not_to eq nil
|
89
|
+
end
|
90
|
+
it "returns configs with string keys" do
|
91
|
+
database_config = ServerSettings::DatabaseConfig.generate_database_config(:master)
|
92
|
+
expect(database_config["user"].keys.all? { |k| k.is_a? String }).to be true
|
93
|
+
expect(database_config["has_slave_slave1"].keys.all? { |k| k.is_a? String }).to be true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|