ghost 0.2.8 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ghost.rb CHANGED
@@ -1,8 +1,22 @@
1
1
  $: << File.dirname(__FILE__)
2
2
 
3
- case RUBY_PLATFORM
3
+ module Ghost
4
+ class RecordExists < StandardError
5
+ end
6
+ end
7
+
8
+ require 'rbconfig'
9
+
10
+ case RbConfig::CONFIG['host_os']
4
11
  when /darwin/
5
- require 'ghost/mac-host'
12
+ productVersion = `/usr/bin/sw_vers -productVersion`.strip
13
+ if productVersion =~ /^10\.7\.[2-9]{1}$/
14
+ require 'ghost/linux-host'
15
+ else
16
+ require 'ghost/mac-host'
17
+ end
6
18
  when /linux/
7
19
  require 'ghost/linux-host'
8
20
  end
21
+
22
+ require 'ghost/ssh_config'
@@ -1,92 +1,158 @@
1
1
  require 'socket'
2
2
 
3
- class Host
4
- attr_reader :host, :ip
3
+ module Ghost
4
+ class Host
5
5
 
6
- def initialize(host, ip)
7
- @host = host
8
- @ip = ip
9
- end
10
-
11
- def ==(other)
12
- @host == other.host && @ip = other.ip
13
- end
14
-
15
- alias :to_s :host
16
- alias :name :host
17
- alias :hostname :host
18
-
19
- @@hosts_file = '/etc/hosts'
20
- @@permanent_hosts = [Host.new("localhost", "127.0.0.1"),
21
- Host.new(`hostname`.chomp, "127.0.0.1")]
22
- class << self
23
- protected :new
24
-
25
- def list
26
- entries = []
27
- File.open(@@hosts_file).each do |line|
28
- next if line =~ /^#/
29
- if line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(.*)$/
30
- ip = $1
31
- hosts = $2.split(/\s+/)
32
- hosts.each { |host| entries << Host.new(host, ip) }
6
+ attr_reader :host, :ip
7
+
8
+ def initialize(host, ip)
9
+ @host = host
10
+ @ip = ip
11
+ end
12
+
13
+ def ==(other)
14
+ @host == other.host && @ip = other.ip
15
+ end
16
+
17
+ alias :to_s :host
18
+ alias :name :host
19
+ alias :hostname :host
20
+
21
+ @@hosts_file = '/etc/hosts'
22
+ @@start_token, @@end_token = '# ghost start', '# ghost end'
23
+
24
+ class << self
25
+ protected :new
26
+
27
+ def list
28
+ with_exclusive_file_access(true) do |file|
29
+ entries = []
30
+ in_ghost_area = false
31
+ file.pos = 0
32
+
33
+ file.each do |line|
34
+ if !in_ghost_area and line =~ /^#{@@start_token}/
35
+ in_ghost_area = true
36
+ elsif in_ghost_area
37
+ if line =~ /^#{@@end_token}/o
38
+ in_ghost_area = false
39
+ elsif line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(.*)$/
40
+ ip = $1
41
+ hosts = $2.split(/\s+/)
42
+ hosts.each { |host| entries << Host.new(host, ip) }
43
+ end
44
+ end
45
+ end
46
+
47
+ entries
33
48
  end
34
49
  end
35
- entries.delete_if { |host| @@permanent_hosts.include? host }
36
- entries
37
- end
38
50
 
39
- def add(host, ip = "127.0.0.1", force = false)
40
- if find_by_host(host).nil? || force
41
- delete(host)
42
-
43
- unless ip[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/]
44
- ip = Socket.gethostbyname(ip)[3].bytes.to_a.join('.')
51
+ def add(host, ip = "127.0.0.1", force = false)
52
+ with_exclusive_file_access do
53
+ if find_by_host(host).nil? || force
54
+ hosts = list
55
+ hosts = hosts.delete_if { |h| h.name == host }
56
+
57
+ unless ip[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/]
58
+ ip = Socket.gethostbyname(ip)[3].bytes.to_a.join('.')
59
+ end
60
+
61
+ new_host = Host.new(host, ip)
62
+
63
+ hosts << new_host
64
+ write_out!(hosts)
65
+
66
+ new_host
67
+ else
68
+ raise Ghost::RecordExists, "Can not overwrite existing record"
69
+ end
45
70
  end
46
-
47
- new_host = Host.new(host, ip)
48
-
49
- hosts = list
50
- hosts << new_host
51
- write_out!(hosts)
52
-
53
- new_host
54
- else
55
- raise "Can not overwrite existing record"
56
- end
57
- end
58
-
59
- def find_by_host(hostname)
60
- list.find{ |host| host.hostname == hostname }
61
- end
62
-
63
- def find_by_ip(ip)
64
- list.find_all{ |host| host.ip == ip }
65
- end
66
-
67
- def empty!
68
- write_out!([])
69
- end
70
-
71
- def delete(name)
72
- hosts = list
73
- hosts = hosts.delete_if { |host| host.name == name }
74
- write_out!(hosts)
75
- end
76
-
77
- def delete_matching(pattern)
78
- pattern = Regexp.escape(pattern)
79
- hosts = list.select { |host| host.name.match(/#{pattern}/) }
80
- hosts.each { |host| delete(host.name) }
81
- hosts
82
- end
71
+ end
83
72
 
84
- protected
73
+ def find_by_host(hostname)
74
+ list.find { |host| host.hostname == hostname }
75
+ end
85
76
 
86
- def write_out!(hosts)
87
- hosts += @@permanent_hosts
88
- output = hosts.inject("") {|s, h| s + "#{h.ip} #{h.hostname}\n" }
89
- File.open(@@hosts_file, 'w') {|f| f.print output }
77
+ def find_by_ip(ip)
78
+ list.find_all{ |host| host.ip == ip }
79
+ end
80
+
81
+ def empty!
82
+ write_out!([])
83
+ end
84
+
85
+ def delete(name)
86
+ with_exclusive_file_access do
87
+ hosts = list
88
+ hosts = hosts.delete_if { |host| host.name == name }
89
+ write_out!(hosts)
90
+ end
91
+ end
92
+
93
+ def delete_matching(pattern)
94
+ with_exclusive_file_access do
95
+ pattern = Regexp.escape(pattern)
96
+ hosts = list.select { |host| host.name.match(/#{pattern}/) }
97
+ hosts.each { |host| delete(host.name) }
98
+ hosts
99
+ end
100
+ end
101
+
102
+ protected
103
+
104
+ def with_exclusive_file_access(read_only = false)
105
+ return_val = nil
106
+ flag = read_only ? 'r' : 'r+'
107
+
108
+ if @_file
109
+ return_val = yield @_file
110
+ else
111
+ File.open(@@hosts_file, flag) do |f|
112
+ f.flock File::LOCK_EX
113
+ begin
114
+ @_file = f
115
+ return_val = yield f
116
+ ensure
117
+ @_file = nil
118
+ end
119
+ end
120
+ end
121
+
122
+ return_val
123
+ end
124
+
125
+ def write_out!(hosts)
126
+ with_exclusive_file_access do |f|
127
+ new_ghosts = hosts.inject("") {|s, h| s + "#{h.ip} #{h.hostname}\n" }
128
+
129
+ output = ""
130
+ in_ghost_area, seen_tokens = false,false
131
+ f.pos = 0
132
+
133
+ f.each do |line|
134
+ if line =~ /^#{@@start_token}/o
135
+ in_ghost_area, seen_tokens = true,true
136
+ output << line << new_ghosts
137
+ elsif line =~ /^#{@@end_token}/o
138
+ in_ghost_area = false
139
+ end
140
+ output << line unless in_ghost_area
141
+ end
142
+ if !seen_tokens
143
+ output << surround_with_tokens( new_ghosts )
144
+ end
145
+
146
+ f.pos = 0
147
+ f.print output
148
+ f.truncate(f.pos)
149
+ end
150
+ end
151
+
152
+
153
+ def surround_with_tokens(str)
154
+ "\n#{@@start_token}\n#{str}#{@@end_token}\n"
155
+ end
90
156
  end
91
157
  end
92
158
  end
@@ -1,114 +1,116 @@
1
1
  require 'socket'
2
2
 
3
- class Host
4
- ListCmd = "dscl localhost -list /Local/Default/Hosts 2>&1"
5
- ReadCmd = "dscl localhost -read /Local/Default/Hosts/%s 2>&1"
6
- CreateCmd = "sudo dscl localhost -create /Local/Default/Hosts/%s IPAddress %s 2>&1"
7
- DeleteCmd = "sudo dscl localhost -delete /Local/Default/Hosts/%s 2>&1"
8
-
9
- class << self
10
- protected :new
11
-
12
- def list
13
- list = `#{ListCmd}`
14
- list = list.split("\n")
15
- list.collect { |host| Host.new(host.chomp) }
16
- end
3
+ module Ghost
4
+ class Host
5
+ ListCmd = "dscl localhost -list /Local/Default/Hosts 2>&1"
6
+ ReadCmd = "dscl localhost -read /Local/Default/Hosts/%s 2>&1"
7
+ CreateCmd = "dscl localhost -create /Local/Default/Hosts/%s IPAddress %s 2>&1"
8
+ DeleteCmd = "dscl localhost -delete /Local/Default/Hosts/%s 2>&1"
9
+
10
+ class << self
11
+ protected :new
12
+
13
+ def list
14
+ list = `#{ListCmd}`
15
+ list = list.split("\n")
16
+ list.collect { |host| Host.new(host.chomp) }
17
+ end
18
+
19
+ def add(host, ip = "127.0.0.1", force = false)
20
+ if find_by_host(host).nil? || force
21
+ unless ip[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/]
22
+ ip = Socket.gethostbyname(ip)[3].bytes.to_a.join('.')
23
+ end
24
+
25
+ `#{CreateCmd % [host, ip]}`
26
+ flush!
27
+ find_by_host(host)
28
+ else
29
+ raise Ghost::RecordExists, "Can not overwrite existing record"
30
+ end
31
+ end
32
+
33
+ def find_by_host(host)
34
+ @hosts ||= {}
35
+ @hosts[host] ||= begin
36
+ output = `#{ReadCmd % host}`
17
37
 
18
- def add(host, ip = "127.0.0.1", force = false)
19
- if find_by_host(host).nil? || force
20
- unless ip[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/]
21
- ip = Socket.gethostbyname(ip)[3].bytes.to_a.join('.')
38
+ if output =~ /eDSRecordNotFound/
39
+ nil
40
+ else
41
+ host = parse_host(output)
42
+ ip = parse_ip(output)
43
+
44
+ Host.new(host, ip)
45
+ end
22
46
  end
23
-
24
- `#{CreateCmd % [host, ip]}`
47
+ end
48
+
49
+ def find_by_ip(ip)
50
+ nil
51
+ end
52
+
53
+ def empty!
54
+ list.each { |h| delete(h) }
55
+ nil
56
+ end
57
+
58
+ def delete(host)
59
+ `#{DeleteCmd % host.to_s}`
25
60
  flush!
26
- find_by_host(host)
27
- else
28
- raise "Can not overwrite existing record"
29
- end
30
- end
31
-
32
- def find_by_host(host)
33
- @hosts ||= {}
34
- @hosts[host] ||= begin
35
- output = `#{ReadCmd % host}`
36
-
37
- if output =~ /eDSRecordNotFound/
38
- nil
39
- else
40
- host = parse_host(output)
41
- ip = parse_ip(output)
42
-
43
- Host.new(host, ip)
61
+ end
62
+
63
+ def delete_matching(pattern)
64
+ pattern = Regexp.escape(pattern)
65
+ hosts = list.select { |h| h.to_s.match(/#{pattern}/) }
66
+ hosts.each do |h|
67
+ delete(h)
44
68
  end
69
+ flush! unless hosts.empty?
70
+ hosts
45
71
  end
46
- end
47
-
48
- def find_by_ip(ip)
49
- nil
50
- end
51
-
52
- def empty!
53
- list.each { |h| delete(h) }
54
- nil
55
- end
56
-
57
- def delete(host)
58
- `#{DeleteCmd % host.to_s}`
59
- flush!
60
- end
61
-
62
- def delete_matching(pattern)
63
- pattern = Regexp.escape(pattern)
64
- hosts = list.select { |h| h.to_s.match(/#{pattern}/) }
65
- hosts.each do |h|
66
- delete(h)
72
+
73
+ # Flushes the DNS Cache
74
+ def flush!
75
+ `dscacheutil -flushcache`
76
+ @hosts = {}
77
+ true
78
+ end
79
+
80
+ protected
81
+ def parse_host(output)
82
+ parse_value(output, 'RecordName')
83
+ end
84
+
85
+ def parse_ip(output)
86
+ parse_value(output, 'IPAddress')
87
+ end
88
+
89
+ def parse_value(output, key)
90
+ match = output.match(Regexp.new("^#{key}: (.*)$"))
91
+ match[1] unless match.nil?
67
92
  end
68
- flush! unless hosts.empty?
69
- hosts
70
93
  end
71
-
72
- # Flushes the DNS Cache
73
- def flush!
74
- `dscacheutil -flushcache`
75
- @hosts = {}
76
- true
94
+
95
+ def initialize(host, ip=nil)
96
+ @host = host
97
+ @ip = ip
77
98
  end
78
-
79
- protected
80
- def parse_host(output)
81
- parse_value(output, 'RecordName')
99
+
100
+ def hostname
101
+ @host
82
102
  end
83
-
84
- def parse_ip(output)
85
- parse_value(output, 'IPAddress')
103
+ alias :to_s :hostname
104
+ alias :host :hostname
105
+ alias :name :hostname
106
+
107
+ def ip
108
+ @ip ||= self.class.send(:parse_ip, dump)
86
109
  end
87
-
88
- def parse_value(output, key)
89
- match = output.match(Regexp.new("^#{key}: (.*)$"))
90
- match[1] unless match.nil?
110
+
111
+ private
112
+ def dump
113
+ @dump ||= `#{ReadCmd % hostname}`
91
114
  end
92
115
  end
93
-
94
- def initialize(host, ip=nil)
95
- @host = host
96
- @ip = ip
97
- end
98
-
99
- def hostname
100
- @host
101
- end
102
- alias :to_s :hostname
103
- alias :host :hostname
104
- alias :name :hostname
105
-
106
- def ip
107
- @ip ||= self.class.send(:parse_ip, dump)
108
- end
109
-
110
- private
111
- def dump
112
- @dump ||= `#{ReadCmd % hostname}`
113
- end
114
116
  end