Class: OsCtld::EtcHosts

Inherits:
Object
  • Object
show all
Includes:
OsCtl::Lib::Utils::File
Defined in:
lib/osctld/etc_hosts.rb

Overview

Manipulate localhost hostnames in `/etc/hosts` like files

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ EtcHosts

Returns a new instance of EtcHosts

Parameters:

  • path (String)

    path to the hosts file



12
13
14
# File 'lib/osctld/etc_hosts.rb', line 12

def initialize(path)
  @path = path
end

Instance Attribute Details

#pathString (readonly)

Returns:

  • (String)


9
10
11
# File 'lib/osctld/etc_hosts.rb', line 9

def path
  @path
end

Instance Method Details

#add_name(line, name, after: nil) ⇒ Object (protected)

Add hostname to `line` from `/etc/hosts`

The hostname is put into the first position.

Parameters:

  • line (String)
  • name (String)
  • after (String, nil)


121
122
123
124
125
126
127
128
129
130
# File 'lib/osctld/etc_hosts.rb', line 121

def add_name(line, name, after: nil)
  if after
    replace_name(line, after, "#{after} #{name}")
  else
    return if line !~ /^([^\s]+)(\s+)/

    i = $~.end(2)
    "#{$1}#{$2}#{name} #{line[i..-1]}"
  end
end

#all_names(hostname) ⇒ Object (protected)

Return all names in the order that should be set for a hostname

Parameters:

  • hostname (OsCtl::Lib::Hostname)


95
96
97
98
99
100
101
102
103
104
105
# File 'lib/osctld/etc_hosts.rb', line 95

def all_names(hostname)
  ret = []

  if hostname.local == hostname.fqdn
    ret << hostname.fqdn
  else
    ret << hostname.fqdn << hostname.local
  end

  ret
end

#do_edit(names) ⇒ Object (protected)

Edit the hosts file and let the caller transform it

If the target file exists, it is read and each line is yielded to the caller. The caller returns the new value that is written to the target file instead of the original line.

If the target file does not exist, it is created and populated with `names`. Nothing is yielded to the caller in that case.

Parameters:

  • names (Array<String>)

    list of hostnames to set



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/osctld/etc_hosts.rb', line 76

def do_edit(names)
  regenerate_file(path, 0644) do |new, old|
    if old
      old.each_line do |line|
        new.write(yield(line))
      end

    else
      new.write(<<END
127.0.0.1       #{(names + %w(localhost)).join(' ')}
::1             #{(names + %w(localhost ip6-localhost ip6-loopback)).join(' ')}
END
      )
    end
  end
end

#includes_name?(line, name) ⇒ Boolean (protected)

Check if a line of string contains specific hostname

Parameters:

  • line (String)
  • name (String)

Returns:

  • (Boolean)


110
111
112
# File 'lib/osctld/etc_hosts.rb', line 110

def includes_name?(line, name)
  /\s#{Regexp.escape(name)}(\s|$)/ =~ line
end

#replace(old_hostname, new_hostname) ⇒ Object

Parameters:

  • old_hostname (OsCtl::Lib::Hostname)
  • new_hostname (OsCtl::Lib::Hostname)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/osctld/etc_hosts.rb', line 40

def replace(old_hostname, new_hostname)
  old_names = all_names(old_hostname)
  new_names = all_names(new_hostname)

  do_edit(new_names) do |line|
    next(line) if (/^127\.0\.0\.1\s/ !~ line && /^::1\s/ !~ line)

    new_line = line.strip
    last = nil

    zip_all(new_names, old_names).each do |new_name, old_name|
      if old_name && includes_name?(new_line, old_name)
        new_line = replace_name(new_line, old_name, new_name || '')
      elsif new_name
        new_line = add_name(new_line, new_name, after: last)
      end

      last = new_name
    end

    new_line << "\n"
    new_line
  end
end

#replace_name(line, old_name, new_name) ⇒ Object (protected)

Replace hostname in `line` read from `/etc/hosts`

Parameters:

  • line (String)
  • old_name (String)
  • new_name (String)


137
138
139
140
141
142
# File 'lib/osctld/etc_hosts.rb', line 137

def replace_name(line, old_name, new_name)
  line.sub(
    /(\s)#{Regexp.escape(old_name)}(\s|$)/,
    "\\1#{new_name}\\2"
  )
end

#set(hostname) ⇒ Object

Parameters:

  • hostname (OsCtl::Lib::Hostname)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/osctld/etc_hosts.rb', line 17

def set(hostname)
  names = all_names(hostname)

  do_edit(names) do |line|
    next(line) if (/^127\.0\.0\.1\s/ !~ line && /^::1\s/ !~ line)

    new_line = line.strip
    last = nil

    names.each do |name|
      next if includes_name?(new_line, name)

      new_line = add_name(new_line, name, after: last)
      last = name
    end

    new_line << "\n"
    new_line
  end
end

#zip_all(a, b) ⇒ Object (protected)



144
145
146
# File 'lib/osctld/etc_hosts.rb', line 144

def zip_all(a, b)
  [a.size, b.size].max.times.map { |i| [a[i], b[i]] }
end