server_settings 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,16 @@
1
+ class ServerSettings
2
+
3
+ class Host
4
+ attr_accessor :host, :port
5
+ def initialize(host,port)
6
+ @host = host
7
+ @port = port
8
+ end
9
+
10
+ def self.parse(host_line)
11
+ host, port = host_line.split(/:/)
12
+ self.new(host,port)
13
+ end
14
+ end
15
+
16
+ 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,10 @@
1
+ class ServerSettings
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load "server_settings/tasks/db.rake"
5
+ end
6
+ config.before_configuration do
7
+ ServerSettings.load_config_dir("#{Rails.root}/config/servers/#{Rails.env}/*.yml")
8
+ end
9
+ end
10
+ 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,9 @@
1
+ class ServerSettings
2
+ module Task
3
+ def self.load_rake
4
+ spec = Gem::Specification.find_by_name "server_settings"
5
+ load "#{spec.gem_dir}/lib/server_settings/tasks/db.rake"
6
+ end
7
+ end
8
+ end
9
+ ServerSettings::Task.load_rake
@@ -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,3 @@
1
+ class ServerSettings
2
+ VERSION = "0.1.0"
3
+ 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