Class: Dory::Dnsmasq

Inherits:
Object
  • Object
show all
Extended by:
DockerService
Defined in:
lib/dory/dnsmasq.rb

Constant Summary collapse

@@first_attempt_failed =
false

Class Method Summary collapse

Methods included from DockerService

container_exists?, delete, docker_installed?, handle_error, has_docker_client?, ps, run_preconditions, running?, start, start_cmd, stop

Class Method Details

.address(addr) ⇒ Object



76
77
78
# File 'lib/dory/dnsmasq.rb', line 76

def self.address(addr)
  Dory::Dinghy.match?(addr) ? Dory::Dinghy.ip : addr
end

.check_port(port_num) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/dory/dnsmasq.rb', line 97

def self.check_port(port_num)
  puts "Requesting sudo to check if something is bound to port #{self.port}".green
  ret = Sh.run_command("sudo lsof -i :#{self.port}")
  return [] unless ret.success?

  list = ret.stdout.split("\n")
  list.shift  # get rid of the column headers
  list.map! do |process|
    command, pid, user, fd, type, device, size, node, name = process.split(/\s+/)
    OpenStruct.new({
      command: command,
      pid: pid,
      user: user,
      fd: fd,
      type: type,
      device: device,
      size: size,
      node: node,
      name: name
    })
  end
end

.container_nameObject



60
61
62
# File 'lib/dory/dnsmasq.rb', line 60

def self.container_name
  Dory::Config.settings[:dory][:dnsmasq][:container_name]
end

.dnsmasq_image_nameObject



9
10
11
# File 'lib/dory/dnsmasq.rb', line 9

def self.dnsmasq_image_name
  'freedomben/dory-dnsmasq:1.1.0'
end

.domain_addr_arg_stringObject



80
81
82
83
84
85
86
87
88
# File 'lib/dory/dnsmasq.rb', line 80

def self.domain_addr_arg_string
  if self.old_domain
    "#{Shellwords.escape(self.old_domain)} #{Shellwords.escape(self.address(self.old_address))}"
  else
    self.domains.map do |domain|
      "#{Shellwords.escape(domain[:domain])} #{Shellwords.escape(self.address(domain[:address]))}"
    end.join(" ")
  end
end

.domainsObject



64
65
66
# File 'lib/dory/dnsmasq.rb', line 64

def self.domains
  Dory::Config.settings[:dory][:dnsmasq][:domains]
end

.handle_error(command_output) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/dory/dnsmasq.rb', line 30

def self.handle_error(command_output)
  puts "[DEBUG] handling dnsmasq start error" if Dory::Config.debug?
  # If we've already tried to handle failure, prevent infinite recursion
  if @@first_attempt_failed || !Dory::Dinghy.installed?
    if Dory::Config.debug?
      puts "[DEBUG] Attempt to kill conflicting service failed" if Dory
    end
    return false
  else
    puts "[DEBUG] First attempt to start dnsmasq failed. There is probably a conflicting service present" if Dory::Config.debug?
    @@first_attempt_failed = true
    self.start(handle_error: false)
  end
end

.ip_from_dinghy?Boolean

Returns:

  • (Boolean)


45
46
47
48
# File 'lib/dory/dnsmasq.rb', line 45

def self.ip_from_dinghy?
  Dory::Dinghy.match?(self.address(self.old_address)) || 
    self.domains.any?{ |domain| Dory::Dinghy.match?(self.address(domain[:address])) }
end

.offer_to_kill(listener_list, answer: nil) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/dory/dnsmasq.rb', line 120

def self.offer_to_kill(listener_list, answer: nil)
  listener_list.each do |process|
    puts "Process '#{process.command}' with PID '#{process.pid}' is listening on #{process.node} port #{self.port}."
  end
  pids = listener_list.uniq(&:pid).map(&:pid)
  pidstr = pids.join(' and ')
  print "This interferes with Dory's dnsmasq container.  Would you like me to kill PID #{pidstr}? (Y/N): "
  conf = answer ? answer : ENV['DORY_KILL_DNSMASQ']
  conf = STDIN.gets.chomp unless conf
  if conf =~ /y/i
    puts "Requesting sudo to kill PID #{pidstr}"
    return Sh.run_command("sudo kill #{pids.join(' ')}").success?
  else
    puts "OK, not killing PID #{pidstr}.  Please kill manually and try starting dory again.".red
    return false
  end
end

.old_addressObject



72
73
74
# File 'lib/dory/dnsmasq.rb', line 72

def self.old_address
  Dory::Config.settings[:dory][:dnsmasq][:address]
end

.old_domainObject



68
69
70
# File 'lib/dory/dnsmasq.rb', line 68

def self.old_domain
  Dory::Config.settings[:dory][:dnsmasq][:domain]
end

.portObject



50
51
52
53
54
# File 'lib/dory/dnsmasq.rb', line 50

def self.port
  return 53 unless Os.macos?
  p = Dory::Config.settings[:dory][:dnsmasq][:port]
  p.nil? || p == 0 ? 19323 : self.sanitize_port(p)
end

.run_command(domains = self.domains) ⇒ Object



90
91
92
93
94
95
# File 'lib/dory/dnsmasq.rb', line 90

def self.run_command(domains = self.domains)
  "docker run -d -p #{self.port}:#{self.port}/tcp -p #{self.port}:#{self.port}/udp " \
  "--name=#{Shellwords.escape(self.container_name)} " \
  "--cap-add=NET_ADMIN #{Shellwords.escape(self.dnsmasq_image_name)} " \
  "#{self.domain_addr_arg_string}"
end

.run_preconditionsObject



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/dory/dnsmasq.rb', line 13

def self.run_preconditions
  puts "[DEBUG] dnsmasq service running preconditions" if Dory::Config.debug?

  # we don't want to hassle the user with checking the port unless necessary
  if @@first_attempt_failed
    puts "[DEBUG] First attempt failed.  Checking port #{self.port}" if Dory::Config.debug?
    listener_list = self.check_port(self.port)
    unless listener_list.empty?
      return self.offer_to_kill(listener_list)
    end
    return false
  else
    puts "[DEBUG] Skipping preconditions on first run" if Dory::Config.debug?
    return true
  end
end

.sanitize_port(port) ⇒ Object



56
57
58
# File 'lib/dory/dnsmasq.rb', line 56

def self.sanitize_port(port)
  port.to_s.gsub(/\D/, '').to_i
end