Class: Chef::Provisioning::LXCDriver::LXCTransport

Inherits:
Transport
  • Object
show all
Includes:
Mixin::ShellOut
Defined in:
lib/chef/provisioning/lxc_driver/lxc_transport.rb

Defined Under Namespace

Classes: LXCExecuteResult

Constant Summary collapse

@@active_transports =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, lxc_path, options = {}) ⇒ LXCTransport

Returns a new instance of LXCTransport.



26
27
28
29
30
31
32
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 26

def initialize(name, lxc_path, options={})
  @options = options
  @name = name
  @lxc_path = lxc_path
  @port_forwards = {}
  @@active_transports << self
end

Instance Attribute Details

#lxc_pathObject (readonly)

Returns the value of attribute lxc_path.



22
23
24
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 22

def lxc_path
  @lxc_path
end

#nameObject (readonly)

Returns the value of attribute name.



22
23
24
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 22

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



22
23
24
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 22

def options
  @options
end

Class Method Details

.disconnect_active_transportsObject



151
152
153
154
155
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 151

def self.disconnect_active_transports
  @@active_transports.to_a.dup.each do |transport|
    transport.disconnect
  end
end

Instance Method Details

#available?Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 147

def available?
  container.running?
end

#containerObject



34
35
36
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 34

def container
  @container ||= LXC::Container.new(name, lxc_path)
end

#container_path(path) ⇒ Object



42
43
44
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 42

def container_path(path)
  File.join(rootfs, path)
end

#disconnectObject



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 130

def disconnect
  @port_forwards.each_pair do |port, (pid, thread, channel)|
    Chef::Log.debug("stopping port forward #{port} for container #{name}")
    begin
      Chef::Log.debug("Killing PID #{pid}")
      Process.kill('KILL', pid)
    rescue
    end
    begin
      thread.kill
    rescue
    end
  end
  @port_forwards = {}
  @@active_transports.delete(self)
end

#download_file(path, local_path) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 110

def download_file(path, local_path)
  Chef::Log.debug("Copying file #{path} from #{name} to local #{local_path}")
  data = read_file(path)
  File.open(local_path, 'w') do |f|
    f.write(data)
  end
end

#execute(command, options = {}) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 46

def execute(command, options = {})
  timeout = options[:timeout] || 3600
  Chef::Log.info("Executing #{command} on #{name}")
  container.execute(timeout: timeout) do
    cmd = Mixlib::ShellOut.new(command)
    cmd.timeout = timeout
    begin
      cmd.run_command
      LXCExecuteResult.new(command, {}, cmd.stdout, cmd.stderr, cmd.exitstatus)
    rescue Errno::ENOENT => e
      LXCExecuteResult.new(command, {} , '', e.message, 2)
    end
  end
end

#make_url_available_to_remote(local_url) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 61

def make_url_available_to_remote(local_url)
  uri = URI(local_url)
  uri_scheme = uri.scheme
  uri_scheme = nil if uri.scheme == 'chefzero'
  host = Socket.getaddrinfo(uri.host, uri_scheme, nil, :STREAM)[0][3]
  if host == '127.0.0.1' || host == '::1'
    unless @port_forwards[uri.port]

      Chef::Log.debug("Forwarding container port #{uri.port} to local port #{uri.port}")
      # Create the channel that will let the container and the host talk to each other
      channel = LXC::Extra::Channel.new

      # Start the container side of the proxy, listening for client connections
      pid = container.attach do
        begin
          server = TCPServer.new(host, uri.port)
          proxy = LXC::Extra::ProxyClientSide.new(channel, server)
          proxy.start
        rescue
          Chef::Log.error("ERROR in proxy (container side): #{$!}\n#{$!.backtrace.join("\n")}")
          raise
        end
      end

      # Start the host side of the proxy, which contacts the real server
      thread = Thread.new do
        proxy = LXC::Extra::ProxyServerSide.new(channel) do
          TCPSocket.new(host, uri.port)
        end
        proxy.start
      end

      Chef::Log.debug("Forwarded #{uri.port} on container #{name} to local port #{uri.port}.  Container listener id PID #{pid}")

      @port_forwards[uri.port] = [ pid, thread, channel ]
    end

  end
  local_url
end

#read_file(path) ⇒ Object



102
103
104
105
106
107
108
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 102

def read_file(path)
  container.execute(wait: true) do
    if File.exists?(container_path(path))
      File.read(container_path(path))
    end
  end
end

#rootfsObject



38
39
40
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 38

def rootfs
  container.config_item('lxc.rootfs')
end

#upload_file(local_path, path) ⇒ Object



126
127
128
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 126

def upload_file(local_path, path)
  write_file(path, File.read(local_path))
end

#write_file(path, content) ⇒ Object



118
119
120
121
122
123
124
# File 'lib/chef/provisioning/lxc_driver/lxc_transport.rb', line 118

def write_file(path, content)
  container.execute(wait: true) do
    File.open(path, 'w') do |f|
      f.write(content)
    end
  end
end