murakumo 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.
data/README ADDED
@@ -0,0 +1,57 @@
1
+ = Murakumo
2
+
3
+ == Description
4
+
5
+ Murakumo is the internal DNS server which manages name information using a gossip protocol.
6
+
7
+ == Source Code
8
+
9
+ https://bitbucket.org/winebarrel/murakumo
10
+
11
+ == Dependency
12
+
13
+ * RubyDNS
14
+ * SQLite
15
+ * MessagePack
16
+
17
+ == Install
18
+
19
+ gem install murakumo
20
+ cp /usr/local/lib/ruby/gems/1.8/gems/murakumo-*/etc/murakumo.server /etc/init.d/murakumo
21
+ chmod 755 /etc/init.d/murakumo
22
+ /etc/init.d/murakumo start
23
+
24
+ == Example
25
+ === display of a list of a record
26
+
27
+ shell> mrkmctl -L
28
+ IP address TTL Priority Activity Hostname
29
+ --------------- ------ -------- -------- ----------
30
+ 10.11.12.13 60 Origin Active my-host
31
+
32
+ === addition of a record
33
+
34
+ shell> mrkmctl -A foo.bar,300,master
35
+ shell> mrkmctl -L
36
+ IP address TTL Priority Activity Hostname
37
+ --------------- ------ -------- -------- ----------
38
+ 10.11.12.13 60 Origin Active dev-01
39
+ 10.11.12.13 300 Master Active foo.bar
40
+
41
+ === deletion of a record
42
+
43
+ shell> mrkmctl -D foo.bar
44
+ shell> mrkmctl -L
45
+ IP address TTL Priority Activity Hostname
46
+ --------------- ------ -------- -------- ----------
47
+ 10.11.12.13 60 Origin Active my-host
48
+
49
+ === addition of a node
50
+
51
+ shell> mrkmctl -a 10.11.12.14
52
+ shell> mrkmctl -L
53
+ IP address TTL Priority Activity Hostname
54
+ --------------- ------ -------- -------- ----------
55
+ 10.11.12.13 60 Origin Active my-host
56
+ 10.11.12.14 60 Origin Active other-host
57
+
data/bin/mrkmctl ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rubygems'
5
+ require 'cli/mrkmctl'
data/bin/murakumo ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rubygems'
5
+ require 'cli/murakumo'
@@ -0,0 +1,95 @@
1
+ #!/bin/sh
2
+ # chkconfig: 345 64 36
3
+ # description: The internal DNS server which manages name information using a gossip protocol.
4
+ # processname: /usr/local/bin/murakumo
5
+ # config: /etc/murakumo.yml
6
+
7
+ prog=/usr/local/bin/murakumo
8
+ ctlprog=/usr/local/bin/mrkmctl
9
+ conf=/etc/murakumo.yml
10
+
11
+ if [ "$1" != "configure" -a ! -e "$conf" ]; then
12
+ echo "configuration file is not found: $conf"
13
+ exit 1
14
+ fi
15
+
16
+ case "$1" in
17
+ start)
18
+ $prog -c $conf -d start
19
+ ;;
20
+ stop)
21
+ $prog -c $conf -d stop
22
+ ;;
23
+ status)
24
+ $prog -c $conf -d status
25
+ ;;
26
+ restart)
27
+ $prog -c $conf -d restart
28
+ ;;
29
+ save)
30
+ $ctlprog -y > ${conf}.new
31
+
32
+ if [ $? -eq 0 ]; then
33
+ cp ${conf}.new $conf
34
+ echo "configuration file was updated: $conf"
35
+ fi
36
+
37
+ rm -f ${conf}.new
38
+ ;;
39
+ configure)
40
+ if [ -e "$conf" ]; then
41
+ echo "configuration file already exists."
42
+ exit 1
43
+ fi
44
+
45
+ bind_addr=0.0.0.0
46
+ ip_addr=`/sbin/ifconfig eth0 | awk -F'[: ]+' '/inet/{print $4}'`
47
+ hostname=`hostname`
48
+ resolver=`grep nameserver /etc/resolv.conf | fgrep -v 127.0.0.1 | head -n 1 | awk '{print $2}'`
49
+
50
+ if [ -n "$resolver" ]; then
51
+ resolver="$resolver, 8.8.8.8"
52
+ else
53
+ resolver="8.8.8.8"
54
+ fi
55
+
56
+ cat <<EOF > $conf
57
+ ---
58
+ address: $bind_addr
59
+ port: 53
60
+
61
+ auth-key: onion
62
+ log-level: info
63
+ resolver: $resolver
64
+ max-ip-number: 8
65
+
66
+ host: $ip_addr, $hostname, 60
67
+
68
+ #alias:
69
+ # - foo,60,master
70
+ # - bar,60,backup
71
+
72
+ #health-check:
73
+ # foo:
74
+ # interval: 5
75
+ # timeout: 5
76
+ # healthy: 2
77
+ # unhealthy: 2
78
+ # script: |
79
+ # tcp_check 80
80
+ # bar:
81
+ # interval: 5
82
+ # timeout: 5
83
+ # healthy: 2
84
+ # unhealthy: 2
85
+ # script: |
86
+ # http_get '/index.html'
87
+ EOF
88
+
89
+ echo "configuration file was created: $conf"
90
+ echo -e "\033[0;31mPlease set 127.0.0.1 to resolv.conf.\033[0;39m"
91
+ ;;
92
+ *)
93
+ echo $"Usage: $0 {start|stop|restart|status|save|configureh}"
94
+ exit 1
95
+ esac
@@ -0,0 +1,33 @@
1
+ ---
2
+ # configuration of dns
3
+ address: 0.0.0.0
4
+ port: 53
5
+
6
+ auth-key: onion
7
+ log-level: info
8
+ resolver: 8.8.8.8
9
+ max-ip-num: 8
10
+
11
+ # Ip address, hostname, ttl
12
+ host: 10.11.12.13, my-host, 60
13
+
14
+ # alias hostname, ttl, master/backup
15
+ alias:
16
+ - foo,60,master
17
+ - bar,60,master
18
+
19
+ health-check:
20
+ foo:
21
+ interval: 5
22
+ timeout: 5
23
+ healthy: 10
24
+ unhealthy: 2
25
+ script: |
26
+ tcp_check 80
27
+ bar:
28
+ interval: 5
29
+ timeout: 5
30
+ healthy: 10
31
+ unhealthy: 2
32
+ script: |
33
+ http_get '/index.html'
@@ -0,0 +1,74 @@
1
+ require 'drb/drb'
2
+ require 'yaml'
3
+
4
+ require 'cli/mrkmctl_options'
5
+ require 'misc/murakumo_const'
6
+
7
+ # オプションをパース
8
+ options = mrkmctl_parse_args
9
+
10
+ # リモートオブジェクトを生成
11
+ there = DRbObject.new_with_uri("drbunix:#{options[:socket]}")
12
+
13
+ cmd, arg = options[:command]
14
+
15
+ # 各コマンドの処理
16
+ begin
17
+ case cmd
18
+ # 一覧表示
19
+ when :list
20
+ records = if arg.kind_of?(String)
21
+ # 引数がある場合はフィルタリング
22
+ there.list_records.select {|r| r[0..1].any?{|i| i.start_with?(arg) } }
23
+ else
24
+ there.list_records
25
+ end
26
+
27
+ puts <<-EOF
28
+ IP address TTL Priority Activity Hostname
29
+ --------------- ------ -------- -------- ----------
30
+ EOF
31
+ records.each do |r|
32
+ r[3] = (r[3] == Murakumo::ORIGIN ? 'Origin' : r[3] == Murakumo::MASTER ? 'Master' : 'Backup')
33
+ r[4] = (r[4] == Murakumo::ACTIVE ? 'Active' : 'Inactive')
34
+ puts '%-15s %6d %-8s %-8s %s' % r.values_at(0, 2, 3, 4, 1)
35
+ end
36
+
37
+ # レコードの追加・更新
38
+ when :add
39
+ is_success, errmsg = there.add_or_rplace_records(arg)
40
+ is_success or raise(errmsg)
41
+
42
+ # レコードの削除
43
+ when :delete
44
+ is_success, errmsg = there.delete_records(arg)
45
+ is_success or raise(errmsg)
46
+
47
+ # ノードの追加
48
+ when :add_node
49
+ is_success, errmsg = there.add_nodes(arg)
50
+ is_success or raise(errmsg)
51
+
52
+ # ノードの削除
53
+ when :delete_node
54
+ is_success, errmsg = there.delete_nodes(arg)
55
+ is_success or raise(errmsg)
56
+
57
+ # 属性の取得
58
+ when :get
59
+ puts "#{arg}=#{there.get_attr(arg)}"
60
+
61
+ # 属性の設定
62
+ when :set
63
+ is_success, errmsg = there.set_attr(*arg)
64
+ is_success or raise(errmsg)
65
+
66
+ # 設定の出力
67
+ when :yaml
68
+ puts there.to_hash.to_yaml
69
+
70
+ end
71
+ rescue => e
72
+ $stderr.puts "error: #{e.message}"
73
+ exit 1
74
+ end
@@ -0,0 +1,122 @@
1
+ require 'optopus'
2
+
3
+ require 'misc/murakumo_const'
4
+
5
+ Version = '0.1.0'
6
+
7
+ def mrkmctl_parse_args
8
+ optopus do
9
+ desc 'displays a list of a record'
10
+ option :list, '-L', '--list [NAME]'
11
+
12
+ desc 'adds or updates a record: <hostname>[,<TTL>[,{master|backup}]]'
13
+ option :add, '-A', '--add RECORD', :type => Array, :multiple => true do |value|
14
+ (1 <= value.length and value.length <= 3) or invalid_argument
15
+
16
+ hostname, ttl, master_backup = value
17
+
18
+ # hostname
19
+ /\A[0-9a-z\.\-]+\Z/i =~ hostname or invalid_argument
20
+
21
+ # TTL
22
+ unless ttl.nil? or (/\A\d+\Z/ =~ ttl and ttl.to_i > 0)
23
+ invalid_argument
24
+ end
25
+
26
+ # MASTER or BACKUP
27
+ master_backup.nil? or /\A(master|backup)\Z/i =~ master_backup or invalid_argument
28
+ end
29
+
30
+ desc 'deletes a record'
31
+ option :delete, '-D', '--delete NAME', :multiple => true do |value|
32
+ /\A[0-9a-z\.\-]+\Z/i =~ value or invalid_argument
33
+ end
34
+
35
+ desc 'adds a node'
36
+ option :add_node, '-a', '--add-node HOST', :multiple => true do |value|
37
+ unless [/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z/, /\A[0-9a-z\.\-]+\Z/i].any? {|i| i =~ value }
38
+ invalid_argument
39
+ end
40
+ end
41
+
42
+ desc 'deletes a node'
43
+ option :delete_node, '-d', '--delete-node HOST', :multiple => true do |value|
44
+ unless [/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z/, /\A[0-9a-z\.\-]+\Z/i].any? {|i| i =~ value }
45
+ invalid_argument
46
+ end
47
+ end
48
+
49
+ desc "gets an attribute: #{Murakumo::ATTRIBUTES.keys.join(',')}"
50
+ option :get, '-g', '--get ATTR' do |value|
51
+ Murakumo::ATTRIBUTES.keys.include?(value.to_sym) or invalid_argument
52
+ end
53
+
54
+ desc "sets an attribute (name=value): #{Murakumo::ATTRIBUTES.keys.join(',')}"
55
+ option :set, '-s', '--set ATTR' do |value|
56
+ /\A.+=.+\Z/ =~ value or invalid_argument
57
+ name, val = value.split('=', 2)
58
+ Murakumo::ATTRIBUTES.keys.include?(name.to_sym) or invalid_argument
59
+
60
+ if name == 'log_level'
61
+ %w(debug info warn error fatal).include?(val) or invalid_argument
62
+ end
63
+ end
64
+
65
+ desc ' configuration file is outputted by yaml'
66
+ option :yaml, '-y', '--yaml'
67
+
68
+ desc 'path of a socket file'
69
+ option :socket, '-S', '--socket PATH', :default => '/var/tmp/murakumo.sock'
70
+
71
+ after do |options|
72
+ # add
73
+ if options[:add]
74
+ options[:add] = options[:add].map do |r|
75
+ r = r.map {|i| i ? i.to_s.strip : i }
76
+ [nil, 60, 'master'].each_with_index {|v, i| r[i] ||= v }
77
+
78
+ [
79
+ r[0], # name
80
+ r[1].to_i, # TTL
81
+ ((/master/i =~ r[2].to_s) ? Murakumo::MASTER : Murakumo::BACKUP),
82
+ ]
83
+ end
84
+ end
85
+
86
+ # 一応、uniq
87
+ [:delete, :add_node, :delete_node].each do |key|
88
+ if options[key]
89
+ options[key] = options[key].uniq
90
+ end
91
+ end
92
+
93
+ if options[:get]
94
+ options[:get] = options[:get].to_sym
95
+ end
96
+
97
+ if options[:set]
98
+ options[:set] = options[:set].split('=', 2)
99
+ options[:set][0] = options[:set][0].to_sym
100
+ end
101
+
102
+ # command
103
+ commands = [:list, :add, :delete, :add_node, :delete_node, :get, :set, :yaml].map {|k|
104
+ [k, options[k]]
105
+ }.select {|i| not i[1].nil? }
106
+
107
+ opt_keys = %w(-L -A -D --add-node --delete-node --get --set --yaml)
108
+
109
+ if commands.length < 1
110
+ parse_error('command is not specified', *opt_keys)
111
+ elsif commands.length > 1
112
+ parse_error('cannot use together', *opt_keys)
113
+ end
114
+
115
+ options[:command] = commands.first
116
+ end
117
+
118
+ error do |e|
119
+ abort(e.message)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,20 @@
1
+ require 'cli/murakumo_options'
2
+ require 'srv/murakumo_server'
3
+
4
+ # オプションをパース
5
+ options = murakumo_parse_args
6
+
7
+ # サーバの初期化
8
+ Murakumo::Server.init(options)
9
+
10
+ if options[:daemon]
11
+ # デーモン化する場合
12
+ # RExecに処理を委譲するのでARGVの先頭にdaemonizeのコマンドを格納
13
+ ARGV.unshift options[:daemon].to_s
14
+
15
+ Murakumo::Server.pid_directory = options[:pid_dir]
16
+ Murakumo::Server.daemonize
17
+ else
18
+ # デーモン化しない場合
19
+ Murakumo::Server.run
20
+ end
@@ -0,0 +1,158 @@
1
+ require 'logger'
2
+ require 'optopus'
3
+ require 'resolv'
4
+ require 'socket'
5
+
6
+ require 'misc/murakumo_const'
7
+
8
+ Version = '0.1.0'
9
+
10
+ def murakumo_parse_args
11
+ optopus do
12
+ desc 'key for authentication (required)'
13
+ option :auth_key, '-K', '--auth-key STRING', :required => true
14
+
15
+ desc 'ip address to bind'
16
+ option :dns_address, '-a', '--address IP', :default => '0.0.0.0' do |value|
17
+ /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z/ =~ value or invalid_argument
18
+ end
19
+
20
+ desc 'port number of a name service'
21
+ option :dns_port, '-p', '--port NUM', :type => Integer, :default => 53
22
+
23
+ desc 'initial node list of gossip protocols'
24
+ option :initial_nodes, '-i', '--initial-nodes IP_LIST', :type => Array, :default => [] do |value|
25
+ value.all? {|i| /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z/ =~ i } or invalid_argument
26
+ end
27
+
28
+ desc "host's resource record : <ip_addr>[,<hostname>[,<TTL>]] (required)"
29
+ option :host, '-H', '--host RECORD', :type => Array, :required => true do |value|
30
+ (1 <= value.length and value.length <= 3) or invalid_argument
31
+
32
+ ip_addr, hostname, ttl = value
33
+
34
+ # ip address
35
+ /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z/ =~ ip_addr or invalid_argument
36
+
37
+ # hostname
38
+ /\A[0-9a-z\.\-]+\Z/i =~ hostname or invalid_argument
39
+
40
+ # TTL
41
+ unless ttl.nil? or (/\A\d+\Z/ =~ ttl and ttl.to_i > 0)
42
+ invalid_argument
43
+ end
44
+ end # :host
45
+
46
+ desc 'resource record of an alias: <hostname>[,<TTL>[,{master|backup}]]'
47
+ option :aliases, '-A', '--alias RECORD', :type => Array, :multiple => true do |value|
48
+ (1 <= value.length and value.length <= 3) or invalid_argument
49
+
50
+ hostname, ttl, master_backup = value
51
+
52
+ # hostname
53
+ /\A[0-9a-z\.\-]+\Z/ =~ hostname or invalid_argument
54
+
55
+ # TTL
56
+ unless ttl.nil? or (/\A\d+\Z/ =~ ttl and ttl.to_i > 0)
57
+ invalid_argument
58
+ end
59
+
60
+ # MASTER or BACKUP
61
+ master_backup.nil? or /\A(master|backup)\Z/i =~ master_backup or invalid_argument
62
+ end # :aliases
63
+
64
+ desc 'ip address of a default resolver'
65
+ option :resolver, '-r', '--resolver IP_LIST', :type => Array do |value|
66
+ unless value.all? {|i| /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\Z/ =~ i }
67
+ invalid_argument
68
+ end
69
+ end
70
+
71
+ desc 'path of a socket file'
72
+ option :socket, '-S', '--socket PATH', :default => '/var/tmp/murakumo.sock'
73
+
74
+ desc 'maximum number of the IP address returned as a response'
75
+ option :max_ip_num, '-n', '--max-ip-num NUM', :type => Integer, :default => 8 do |value|
76
+ invalid_argument if value < 1
77
+ end
78
+
79
+ desc 'command of daemonize: {start|stop|restart|status}'
80
+ option :daemon, '-d', '--daemon CMD', :type => [:start, :stop, :restart, :status]
81
+
82
+ desc 'directory of a pid file'
83
+ option :pid_dir, '-f', '--pid-dir PATH'
84
+
85
+ desc 'output path of a log'
86
+ option :log_path, '-l', '--log-path PATH'
87
+
88
+ desc 'output level of a log'
89
+ option :log_level, '-L', '--log-level LEVEL', :type => [:debug, :info, :warn, :error, :fatal], :default => :info
90
+
91
+ desc 'path of a configuration file'
92
+ config_file '-c', '--config PATH'
93
+
94
+ desc 'port number of a gossip service'
95
+ option :gossip_port, '-P', '--gossip-port NUM', :type => Integer, :default => 10870
96
+
97
+ desc 'lifetime of the node of a gossip protocol'
98
+ option :gossip_node_lifetime, '-T', '--gossip-node-lifetime NUM', :type => Integer, :default => 10
99
+
100
+ desc 'transmitting interval of a gossip protocol'
101
+ option :gossip_send_interval, '-I', '--gossip-send-interval NUM', :type => Float, :default => 0.3
102
+
103
+ desc 'reception timeout of a gossip protocol'
104
+ option :gossip_receive_timeout, '-O', '--gossip-receive-timeout NUM', :type => Integer, :default => 3
105
+
106
+ after do |options|
107
+ # resolver
108
+ if options[:resolver]
109
+ options[:resolver] = options[:resolver].map {|i| i.strip }
110
+ options[:resolver] = Resolv::DNS.new(:nameserver => options[:resolver])
111
+ end
112
+
113
+ # initial nodes
114
+ if options[:initial_nodes]
115
+ options[:initial_nodes] = options[:initial_nodes].map {|i| i.strip }
116
+ end
117
+
118
+ # host
119
+ options[:host] = options[:host].map {|i| i.strip }
120
+ options[:host][1] ||= Socket.gethostname
121
+ options[:host][2] = (options[:host][2] || 60).to_i # TTL
122
+
123
+ # aliases
124
+ config_file_aliases = options.config_file ? options.config_file['alias'] : nil
125
+
126
+ if config_file_aliases
127
+ if config_file_aliases.kind_of?(Array)
128
+ options[:aliases] = config_file_aliases.map {|i| i.split(',') }
129
+ else
130
+ options[:aliases] = [options[:aliases]]
131
+ end
132
+ end
133
+
134
+ options[:aliases] = (options[:aliases] || []).map do |r|
135
+ r = r.map {|i| i.to_s.strip }
136
+ [nil, 60, 'master'].each_with_index {|v, i| r[i] ||= v }
137
+
138
+ [
139
+ r[0], # name
140
+ r[1].to_i, # TTL
141
+ ((/master/i =~ r[2].to_s) ? Murakumo::MASTER : Murakumo::BACKUP),
142
+ ]
143
+ end
144
+
145
+ # logger
146
+ if not options[:log_path] and options[:daemon]
147
+ options[:log_path] = '/var/log/murakumo.log'
148
+ end
149
+
150
+ options[:logger] = Logger.new(options[:log_path] || $stderr)
151
+ options[:logger].level = Logger.const_get(options[:log_level].to_s.upcase)
152
+ end
153
+
154
+ error do |e|
155
+ abort(e.message)
156
+ end
157
+ end
158
+ end