-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize hosts read #454
Optimize hosts read #454
Changes from 1 commit
a76777f
671bc1c
183af41
69fb68e
2814e51
0fea43b
c9b506e
9cc559f
2891ea7
329459d
8f87a1d
1fc89e6
10a186a
ce70f39
447cc1b
8d9d6b8
b5fd998
daa9755
c460b5b
43ebe40
5d4bfaa
8eb9bfa
72281b1
9bdd9af
b508d83
e6b65e0
ed6a634
63ed52c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
require "yast" | ||
require "yast2/target_file" | ||
|
||
require "cfa/base_model" | ||
require "cfa/matcher" | ||
require "cfa/augeas_parser" | ||
|
||
module CFA | ||
class Hosts < BaseModel | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the people that did not design CFA::BaseModel, a comment with the full URL of its API docs will be useful: http://www.rubydoc.info/github/config-files-api/config_files_api/CFA/BaseModel There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||
PARSER = AugeasParser.new("hosts.lns") | ||
PATH = "/etc/hosts".freeze | ||
include Yast::Logger | ||
|
||
def initialize(file_handler: nil) | ||
super(PARSER, PATH, file_handler: file_handler) | ||
end | ||
|
||
def hosts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this and some other methods miss documentation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
matcher = Matcher.new { |k,v| k =~ /^\d*$/ } | ||
data.select(matcher).each_with_object({}) do |host, result| | ||
entry = host[:value] | ||
result[entry["ipaddr"]] ||= [] | ||
result[entry["ipaddr"]] << single_host_entry(entry) | ||
end | ||
end | ||
|
||
def host(ip) | ||
hosts = data.select(ip_matcher(ip)) | ||
|
||
hosts.map do |host| | ||
single_host_entry(host[:value]) | ||
end | ||
end | ||
|
||
def delete_host(ip) | ||
entries = data.select(ip_matcher(ip)) | ||
if entries.empty? | ||
log.info "no entry to delete for ip #{ip}" | ||
return | ||
end | ||
|
||
if entries.size > 1 | ||
log.info "delete host with ip '#{ip}' removes more then one entry" | ||
end | ||
|
||
entries.each do |e| | ||
log.info "deleting record #{e.inspect}" | ||
data.delete(e[:key]) | ||
end | ||
end | ||
|
||
# replaces or adds new host entry. If more then one entry with given ip exists | ||
# then replaces the last instance | ||
def set_host(ip, canonical, aliases = []) | ||
entries = data.select(ip_matcher(ip)) | ||
if entries.empty? | ||
log.info "adding new entry for ip #{ip}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahem, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, that cause another search thrue tree searching for ip There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What? The body of this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, right, add_entry do not search for existing ips, so I will adapt |
||
entry_line = AugeasTree.new | ||
entry_line["ipaddr"] = ip | ||
entry_line["canonical"] = canonical | ||
aliases_col = entry_line.collection("alias") | ||
aliases.each do |a| | ||
aliases_col.add(a) | ||
end | ||
data.add(unique_id, entry_line) | ||
return | ||
end | ||
|
||
if entries.size > 1 | ||
log.info "more then one entry with ip '#{ip}'. Replacing last one." | ||
end | ||
|
||
entry = entries.last[:value] | ||
entry["ipaddr"] = ip | ||
entry["canonical"] = canonical | ||
# clear previous aliases | ||
entry.delete("alias") | ||
entry.delete("alias[]") | ||
aliases_col = entry.collection("alias") | ||
aliases.each do |a| | ||
aliases_col.add(a) | ||
end | ||
end | ||
|
||
# adds new entry, even if it exists | ||
def add_host(ip, canonical, aliases = []) | ||
log.info "adding new entry for ip #{ip}" | ||
entry_line = AugeasTree.new | ||
entry_line["ipaddr"] = ip | ||
entry_line["canonical"] = canonical | ||
aliases_col = entry_line.collection("alias") | ||
aliases.each do |a| | ||
aliases_col.add(a) | ||
end | ||
data.add(unique_id, entry_line) | ||
end | ||
|
||
def remove_hostname(hostname) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename this to |
||
entries = data.select(hostname_matcher(hostname)) | ||
entries.each do |entry| | ||
entry = entry[:value] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. overwriting variable used for iterating in loop is usually not considered to be a good idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not? in ruby it is just variable assigned to some value, but I can create new one if you are more comfortable with it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
if entry["canonical"] == hostname | ||
aliases = aliases_for(entry) | ||
if aliases.empty? | ||
delete_host(entry["ipaddr"]) | ||
else | ||
set_host(entry["ipaddr"], aliases.first, aliases[1..-1]) | ||
end | ||
else | ||
reduced_aliases = aliases_for(entry) | ||
reduced_aliases.delete(hostname) | ||
set_host(entry["ipaddr"], entry["canonical"], reduced_aliases) | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def ip_matcher(ip) | ||
Matcher.new { |k, v| v["ipaddr"] == ip } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
end | ||
|
||
def hostname_matcher(hostname) | ||
Matcher.new do |k, v| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
v["canonical"] == hostname || aliases_for(v).include?(hostname) | ||
end | ||
end | ||
|
||
def aliases_for(entry) | ||
entry["alias[]"] ? entry.collection("alias").map{ |a| a } : [entry["alias"]].compact | ||
end | ||
|
||
def single_host_entry(entry) | ||
result = [entry["canonical"]] | ||
result.concat(aliases_for(entry)) | ||
result.join(" ") | ||
end | ||
|
||
def unique_id | ||
id = 1 | ||
loop do | ||
return id.to_s unless data[id.to_s] | ||
id += 1 | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't check that in details yet so it is more less note for me. Here you change semantics (list of ips -> single ip)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I change API because it is used only as single parameter. I think it do not make much sense to change hostname for more ips, it means you have one hostname for more ips which looks bogus for me.