server_settings 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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