dev-lxc 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,123 +1,128 @@
1
- module DevLXC
2
- class Container < LXC::Container
3
- def status
4
- if self.defined?
5
- state = self.state
6
- ip_addresses = self.ip_addresses.join(" ") if self.state == :running
7
- else
8
- state = "not_created"
9
- end
10
- { 'name' => self.name, 'state' => state, 'ip_addresses' => ip_addresses }
11
- end
12
-
13
- def start
14
- unless self.defined?
15
- puts "ERROR: Container '#{self.name}' does not exist."
16
- exit 1
17
- end
18
- puts "Starting container '#{self.name}'"
19
- super
20
- wait(:running, 3)
21
- puts "Waiting for '#{self.name}' container's network"
22
- ips = nil
23
- 30.times do
24
- ips = self.ip_addresses
25
- break unless ips.empty?
26
- sleep 1
27
- end
28
- if ips.empty?
29
- puts "ERROR: Container '#{self.name}' network is not available."
30
- exit 1
31
- end
32
- end
33
-
34
- def shutdown
35
- puts "Shutting down container '#{self.name}'"
36
- super
37
- wait(:stopped, 3)
38
- end
39
-
40
- def destroy
41
- stop if running?
42
- puts "Destroying container '#{self.name}'"
43
- super if self.defined?
44
- end
45
-
46
- def sync_mounts(mounts)
47
- existing_mounts = self.config_item("lxc.mount.entry")
48
- unless existing_mounts.nil?
49
- preserved_mounts = existing_mounts.delete_if { |m| m.end_with?("## dev-lxc ##") }
50
- self.clear_config_item('lxc.mount.entry')
51
- self.set_config_item("lxc.mount.entry", preserved_mounts)
52
- end
53
- unless mounts.nil?
54
- mounts.each do |mount|
55
- if ! preserved_mounts.nil? && preserved_mounts.any? { |m| m.start_with?("#{mount} ") }
56
- puts "Skipping mount entry #{mount}, it already exists"
57
- next
58
- else
59
- puts "Adding mount entry #{mount}"
60
- self.set_config_item("lxc.mount.entry", "#{mount} none bind,optional,create=dir 0 0 ## dev-lxc ##")
61
- end
62
- end
63
- end
64
- self.save_config
65
- end
66
-
67
- def sync_ssh_keys(ssh_keys)
68
- dot_ssh_path = "/home/dev-lxc/.ssh"
69
- unless File.exist?("#{config_item('lxc.rootfs')}#{dot_ssh_path}/authorized_keys")
70
- run_command("sudo -u dev-lxc mkdir -p #{dot_ssh_path}")
71
- run_command("sudo -u dev-lxc chmod 700 #{dot_ssh_path}")
72
- run_command("sudo -u dev-lxc touch #{dot_ssh_path}/authorized_keys")
73
- run_command("sudo -u dev-lxc chmod 600 #{dot_ssh_path}/authorized_keys")
74
- end
75
- authorized_keys = IO.read("#{config_item('lxc.rootfs')}#{dot_ssh_path}/authorized_keys").split("\n")
76
- authorized_keys.delete_if { |m| m.end_with?("## dev-lxc ##") }
77
- unless ssh_keys.nil?
78
- ssh_keys.each do |ssh_key|
79
- puts "Adding SSH key #{ssh_key} to #{dot_ssh_path}/authorized_keys"
80
- authorized_keys << IO.read(ssh_key).chomp + " ## dev-lxc ##"
81
- end
82
- end
83
- authorized_keys_content = String.new
84
- authorized_keys_content = authorized_keys.join("\n") + "\n" unless authorized_keys.empty?
85
- IO.write("#{config_item('lxc.rootfs')}#{dot_ssh_path}/authorized_keys", authorized_keys_content)
86
- end
87
-
88
- def run_command(command, output_file=nil)
89
- unless running?
90
- puts "ERROR: Container '#{self.name}' must be running first"
91
- exit 1
92
- end
93
- attach_opts = { wait: true, env_policy: LXC::LXC_ATTACH_CLEAR_ENV, extra_env_vars: ['HOME=/root'] }
94
- if output_file
95
- file = File.open(output_file, 'w+')
96
- attach_opts[:stdout] = file
97
- end
98
- begin
99
- attach(attach_opts) do
100
- LXC.run_command(command)
101
- end
102
- ensure
103
- file.close if file
104
- end
105
- end
106
-
107
- def install_package(package_path)
108
- unless run_command("test -e #{package_path}") == 0
109
- puts "ERROR: File #{package_path} does not exist in container '#{self.name}'"
110
- exit 1
111
- end
112
- puts "Installing #{package_path} in container '#{self.name}'"
113
- case File.extname(package_path)
114
- when ".deb"
115
- install_command = "dpkg -i --skip-same-version #{package_path}"
116
- when ".rpm"
117
- install_command = "rpm -Uvh #{package_path}"
118
- end
119
- run_command(install_command)
120
- end
121
-
122
- end
123
- end
1
+ module DevLXC
2
+ class Container < LXC::Container
3
+ def status
4
+ if self.defined?
5
+ state = self.state
6
+ ip_addresses = self.ip_addresses.join(" ") if self.state == :running
7
+ else
8
+ state = "not_created"
9
+ end
10
+ { 'name' => self.name, 'state' => state, 'ip_addresses' => ip_addresses }
11
+ end
12
+
13
+ def start
14
+ unless self.defined?
15
+ puts "ERROR: Container '#{self.name}' does not exist."
16
+ exit 1
17
+ end
18
+ puts "Starting container '#{self.name}'"
19
+ super
20
+ wait(:running, 3)
21
+ # sometimes after the dev-lxc-platform system has booted up it is not able to ping containers after they have been started
22
+ # it's not clear to me why this happens
23
+ # restarting systemd-resolved just once completely fixes the problem
24
+ # but to avoid more complicated code i am solving this by restarting systemd-resolved every time a container starts
25
+ system("systemctl restart systemd-resolved.service")
26
+ puts "Waiting for '#{self.name}' container's network"
27
+ ips = nil
28
+ 60.times do
29
+ ips = self.ip_addresses
30
+ break unless ips.empty?
31
+ sleep 1
32
+ end
33
+ if ips.empty?
34
+ puts "ERROR: Container '#{self.name}' network is not available."
35
+ exit 1
36
+ end
37
+ end
38
+
39
+ def shutdown
40
+ puts "Shutting down container '#{self.name}'"
41
+ super
42
+ wait(:stopped, 3)
43
+ end
44
+
45
+ def destroy
46
+ stop if running?
47
+ puts "Destroying container '#{self.name}'"
48
+ super if self.defined?
49
+ end
50
+
51
+ def sync_mounts(mounts)
52
+ existing_mounts = self.config_item("lxc.mount.entry")
53
+ unless existing_mounts.nil?
54
+ preserved_mounts = existing_mounts.delete_if { |m| m.end_with?("## dev-lxc ##") }
55
+ self.clear_config_item('lxc.mount.entry')
56
+ self.set_config_item("lxc.mount.entry", preserved_mounts)
57
+ end
58
+ unless mounts.nil?
59
+ mounts.each do |mount|
60
+ if ! preserved_mounts.nil? && preserved_mounts.any? { |m| m.start_with?("#{mount} ") }
61
+ puts "Skipping mount entry #{mount}, it already exists"
62
+ next
63
+ else
64
+ puts "Adding mount entry #{mount}"
65
+ self.set_config_item("lxc.mount.entry", "#{mount} none bind,optional,create=dir 0 0 ## dev-lxc ##")
66
+ end
67
+ end
68
+ end
69
+ self.save_config
70
+ end
71
+
72
+ def sync_ssh_keys(ssh_keys)
73
+ dot_ssh_path = "/home/dev-lxc/.ssh"
74
+ unless File.exist?("#{config_item('lxc.rootfs')}#{dot_ssh_path}/authorized_keys")
75
+ run_command("sudo -u dev-lxc mkdir -p #{dot_ssh_path}")
76
+ run_command("sudo -u dev-lxc chmod 700 #{dot_ssh_path}")
77
+ run_command("sudo -u dev-lxc touch #{dot_ssh_path}/authorized_keys")
78
+ run_command("sudo -u dev-lxc chmod 600 #{dot_ssh_path}/authorized_keys")
79
+ end
80
+ authorized_keys = IO.read("#{config_item('lxc.rootfs')}#{dot_ssh_path}/authorized_keys").split("\n")
81
+ authorized_keys.delete_if { |m| m.end_with?("## dev-lxc ##") }
82
+ unless ssh_keys.nil?
83
+ ssh_keys.each do |ssh_key|
84
+ puts "Adding SSH key #{ssh_key} to #{dot_ssh_path}/authorized_keys"
85
+ authorized_keys << IO.read(ssh_key).chomp + " ## dev-lxc ##"
86
+ end
87
+ end
88
+ authorized_keys_content = String.new
89
+ authorized_keys_content = authorized_keys.join("\n") + "\n" unless authorized_keys.empty?
90
+ IO.write("#{config_item('lxc.rootfs')}#{dot_ssh_path}/authorized_keys", authorized_keys_content)
91
+ end
92
+
93
+ def run_command(command, output_file=nil)
94
+ unless running?
95
+ puts "ERROR: Container '#{self.name}' must be running first"
96
+ exit 1
97
+ end
98
+ attach_opts = { wait: true, env_policy: LXC::LXC_ATTACH_CLEAR_ENV, extra_env_vars: ['HOME=/root'] }
99
+ if output_file
100
+ file = File.open(output_file, 'w+')
101
+ attach_opts[:stdout] = file
102
+ end
103
+ begin
104
+ attach(attach_opts) do
105
+ LXC.run_command(command)
106
+ end
107
+ ensure
108
+ file.close if file
109
+ end
110
+ end
111
+
112
+ def install_package(package_path)
113
+ unless run_command("test -e #{package_path}") == 0
114
+ puts "ERROR: File #{package_path} does not exist in container '#{self.name}'"
115
+ exit 1
116
+ end
117
+ puts "Installing #{package_path} in container '#{self.name}'"
118
+ case File.extname(package_path)
119
+ when ".deb"
120
+ install_command = "dpkg -i --skip-same-version #{package_path}"
121
+ when ".rpm"
122
+ install_command = "rpm -Uvh #{package_path}"
123
+ end
124
+ run_command(install_command)
125
+ end
126
+
127
+ end
128
+ end
@@ -1,197 +1,197 @@
1
- require "json"
2
- require "dev-lxc/container"
3
-
4
- module DevLXC
5
- class Server
6
- attr_reader :container
7
-
8
- def initialize(name, ipaddress, additional_fqdn, memory_per_server, mounts, ssh_keys)
9
- @container = DevLXC::Container.new(name)
10
- @ipaddress = ipaddress
11
- @additional_fqdn = additional_fqdn
12
- @memory_per_server = memory_per_server
13
- @mounts = mounts
14
- @ssh_keys = ssh_keys
15
- end
16
-
17
- def name
18
- @container.name
19
- end
20
-
21
- def status
22
- @container.status
23
- end
24
-
25
- def run_command(command, output_file=nil)
26
- if @container.running?
27
- puts "Running '#{command}' in '#{@container.name}'"
28
- puts "Saving output to #{output_file}" if output_file
29
- @container.run_command(command, output_file)
30
- else
31
- puts "'#{@container.name}' is not running"
32
- end
33
- end
34
-
35
- def install_package(package_path)
36
- @container.install_package(package_path)
37
- end
38
-
39
- def start
40
- return if @container.running?
41
- hwaddr = @container.config_item("lxc.network.0.hwaddr")
42
- release_lingering_dhcp_ip_addresses(hwaddr)
43
- assign_static_ip_address(hwaddr) if @ipaddress
44
- @container.sync_mounts(@mounts)
45
- @container.start
46
- @container.sync_ssh_keys(@ssh_keys)
47
- @container.set_cgroup_item('memory.limit_in_bytes', @memory_per_server) if @memory_per_server
48
- puts
49
- end
50
-
51
- def shutdown
52
- @container.shutdown if @container.running?
53
- remove_static_ip_address(@container.config_item("lxc.network.0.hwaddr")) if @container.defined?
54
- end
55
-
56
- def snapshot(comment=nil)
57
- unless @container.defined?
58
- puts "WARNING: Skipping snapshot of '#{@container.name}' because it does not exist"
59
- return
60
- end
61
- if @container.running?
62
- puts "WARNING: Skipping snapshot of '#{@container.name}' because it is running"
63
- return
64
- end
65
- puts "Creating snapshot of container '#{@container.name}'"
66
- snapname = @container.snapshot
67
- unless comment.nil?
68
- snapshot = @container.snapshot_list.select { |sn| sn.first == snapname }
69
- snapshot_comment_file = snapshot.flatten[1]
70
- IO.write(snapshot_comment_file, comment) unless snapshot_comment_file.nil?
71
- end
72
- end
73
-
74
- def snapshot_destroy(snapname=nil)
75
- unless @container.defined?
76
- puts "Skipping container '#{@container.name}' because it does not exist"
77
- return
78
- end
79
- if snapname == "ALL"
80
- if @container.snapshot_list.empty?
81
- puts "Container '#{@container.name}' does not have any snapshots"
82
- else
83
- @container.snapshot_list.each do |snapshot|
84
- puts "Destroying snapshot '#{snapshot.first}' of container '#{@container.name}'"
85
- @container.snapshot_destroy(snapshot.first)
86
- end
87
- end
88
- elsif snapname == "LAST"
89
- if @container.snapshot_list.empty?
90
- puts "Container '#{@container.name}' does not have any snapshots"
91
- else
92
- snapname = @container.snapshot_list.last.first
93
- puts "Destroying snapshot '#{snapname}' of container '#{@container.name}'"
94
- @container.snapshot_destroy(snapname)
95
- end
96
- else
97
- snapshot = @container.snapshot_list.select { |sn| sn.first == snapname }
98
- if snapshot.flatten.empty?
99
- puts "Container '#{@container.name}' does not have a '#{snapname}' snapshot"
100
- else
101
- puts "Destroying snapshot '#{snapname}' of container '#{@container.name}'"
102
- @container.snapshot_destroy(snapname)
103
- end
104
- end
105
- end
106
-
107
- def snapshot_list
108
- snapshots = Array.new
109
- return snapshots unless @container.defined?
110
- @container.snapshot_list.each do |snapshot|
111
- (snapname, snap_comment_file, snaptime) = snapshot
112
- snap_comment = IO.read(snap_comment_file).chomp if File.exist?(snap_comment_file)
113
- snapshots << [snapname, snaptime, snap_comment]
114
- end
115
- snapshots
116
- end
117
-
118
- def snapshot_restore(snapname=nil)
119
- unless @container.defined?
120
- puts "WARNING: Skipping container '#{@container.name}' because it does not exist"
121
- return
122
- end
123
- if @container.running?
124
- puts "WARNING: Skipping container '#{@container.name}' because it is running"
125
- return
126
- end
127
- if snapname == "LAST"
128
- if @container.snapshot_list.empty?
129
- puts "WARNING: Skipping container '#{@container.name}' because it does not have any snapshots"
130
- else
131
- snapname = @container.snapshot_list.last.first
132
- puts "Restoring snapshot '#{snapname}' of container '#{@container.name}'"
133
- @container.snapshot_restore(snapname)
134
- end
135
- else
136
- snapshot = @container.snapshot_list.select { |sn| sn.first == snapname }
137
- if snapshot.flatten.empty?
138
- puts "WARNING: Skipping container '#{@container.name}' because it does not have a '#{snapname}' snapshot"
139
- else
140
- puts "Restoring snapshot '#{snapname}' of container '#{@container.name}'"
141
- @container.snapshot_restore(snapname)
142
- end
143
- end
144
- end
145
-
146
- def destroy
147
- return unless @container.defined?
148
- @container.snapshot_list.each { |snapshot| @container.snapshot_destroy(snapshot.first) }
149
- hwaddr = @container.config_item("lxc.network.0.hwaddr")
150
- @container.destroy
151
- remove_static_ip_address(hwaddr)
152
- end
153
-
154
- def release_lingering_dhcp_ip_addresses(hwaddr)
155
- dhcp_leases = IO.readlines('/var/lib/misc/dnsmasq.lxcbr0.leases')
156
- leases_to_release = dhcp_leases.map do |dhcp_lease|
157
- if m = dhcp_lease.match(/ #{hwaddr} (\d+\.\d+\.\d+\.\d+) /)
158
- mac_addr = hwaddr
159
- ip_addr = m[1]
160
- elsif m = dhcp_lease.match(/ (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w) #{@ipaddress} /)
161
- mac_addr = m[1]
162
- ip_addr = @ipaddress
163
- elsif m = dhcp_lease.match(/ (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w) (\d+\.\d+\.\d+\.\d+) #{@container.name.sub(/\.lxc$/, '')} /)
164
- mac_addr = m[1]
165
- ip_addr = m[2]
166
- end
167
- if mac_addr && ip_addr
168
- { dhcp_lease: dhcp_lease, mac_addr: mac_addr, ip_addr: ip_addr }
169
- end
170
- end
171
- leases_to_release.compact!
172
- unless leases_to_release.empty?
173
- system("systemctl stop lxc-net.service")
174
- leases_to_release.each do |l|
175
- puts "Releasing lingering DHCP lease: #{l[:dhcp_lease]}"
176
- DevLXC.search_file_delete_line("/var/lib/misc/dnsmasq.lxcbr0.leases", /( #{l[:mac_addr]} #{l[:ip_addr]} )/)
177
- end
178
- system("systemctl start lxc-net.service")
179
- end
180
- end
181
-
182
- def assign_static_ip_address(hwaddr)
183
- puts "Assigning IP address #{@ipaddress} to '#{@container.name}' container's lxc.network.hwaddr #{hwaddr}"
184
- DevLXC.search_file_delete_line("/etc/lxc/dhcp-hosts.conf", /(^#{hwaddr}|,#{@ipaddress}$)/)
185
- DevLXC.append_line_to_file("/etc/lxc/dhcp-hosts.conf", "#{hwaddr},#{@ipaddress}\n")
186
- DevLXC.reload_dnsmasq
187
- end
188
-
189
- def remove_static_ip_address(hwaddr=nil)
190
- if hwaddr
191
- DevLXC.search_file_delete_line("/etc/lxc/dhcp-hosts.conf", /^#{hwaddr}/)
192
- DevLXC.reload_dnsmasq
193
- end
194
- end
195
-
196
- end
197
- end
1
+ require "json"
2
+ require "dev-lxc/container"
3
+
4
+ module DevLXC
5
+ class Server
6
+ attr_reader :container
7
+
8
+ def initialize(name, ipaddress, additional_fqdn, memory_per_server, mounts, ssh_keys)
9
+ @container = DevLXC::Container.new(name)
10
+ @ipaddress = ipaddress
11
+ @additional_fqdn = additional_fqdn
12
+ @memory_per_server = memory_per_server
13
+ @mounts = mounts
14
+ @ssh_keys = ssh_keys
15
+ end
16
+
17
+ def name
18
+ @container.name
19
+ end
20
+
21
+ def status
22
+ @container.status
23
+ end
24
+
25
+ def run_command(command, output_file=nil)
26
+ if @container.running?
27
+ puts "Running '#{command}' in '#{@container.name}'"
28
+ puts "Saving output to #{output_file}" if output_file
29
+ @container.run_command(command, output_file)
30
+ else
31
+ puts "'#{@container.name}' is not running"
32
+ end
33
+ end
34
+
35
+ def install_package(package_path)
36
+ @container.install_package(package_path)
37
+ end
38
+
39
+ def start
40
+ return if @container.running?
41
+ hwaddr = @container.config_item("lxc.network.0.hwaddr")
42
+ release_lingering_dhcp_ip_addresses(hwaddr)
43
+ assign_static_ip_address(hwaddr) if @ipaddress
44
+ @container.sync_mounts(@mounts)
45
+ @container.start
46
+ @container.sync_ssh_keys(@ssh_keys)
47
+ @container.set_cgroup_item('memory.limit_in_bytes', @memory_per_server) if @memory_per_server
48
+ puts
49
+ end
50
+
51
+ def shutdown
52
+ @container.shutdown if @container.running?
53
+ remove_static_ip_address(@container.config_item("lxc.network.0.hwaddr")) if @container.defined?
54
+ end
55
+
56
+ def snapshot(comment=nil)
57
+ unless @container.defined?
58
+ puts "WARNING: Skipping snapshot of '#{@container.name}' because it does not exist"
59
+ return
60
+ end
61
+ if @container.running?
62
+ puts "WARNING: Skipping snapshot of '#{@container.name}' because it is running"
63
+ return
64
+ end
65
+ puts "Creating snapshot of container '#{@container.name}'"
66
+ snapname = @container.snapshot
67
+ unless comment.nil?
68
+ snapshot = @container.snapshot_list.select { |sn| sn.first == snapname }
69
+ snapshot_comment_file = snapshot.flatten[1]
70
+ IO.write(snapshot_comment_file, comment) unless snapshot_comment_file.nil?
71
+ end
72
+ end
73
+
74
+ def snapshot_destroy(snapname=nil)
75
+ unless @container.defined?
76
+ puts "Skipping container '#{@container.name}' because it does not exist"
77
+ return
78
+ end
79
+ if snapname == "ALL"
80
+ if @container.snapshot_list.empty?
81
+ puts "Container '#{@container.name}' does not have any snapshots"
82
+ else
83
+ @container.snapshot_list.each do |snapshot|
84
+ puts "Destroying snapshot '#{snapshot.first}' of container '#{@container.name}'"
85
+ @container.snapshot_destroy(snapshot.first)
86
+ end
87
+ end
88
+ elsif snapname == "LAST"
89
+ if @container.snapshot_list.empty?
90
+ puts "Container '#{@container.name}' does not have any snapshots"
91
+ else
92
+ snapname = @container.snapshot_list.last.first
93
+ puts "Destroying snapshot '#{snapname}' of container '#{@container.name}'"
94
+ @container.snapshot_destroy(snapname)
95
+ end
96
+ else
97
+ snapshot = @container.snapshot_list.select { |sn| sn.first == snapname }
98
+ if snapshot.flatten.empty?
99
+ puts "Container '#{@container.name}' does not have a '#{snapname}' snapshot"
100
+ else
101
+ puts "Destroying snapshot '#{snapname}' of container '#{@container.name}'"
102
+ @container.snapshot_destroy(snapname)
103
+ end
104
+ end
105
+ end
106
+
107
+ def snapshot_list
108
+ snapshots = Array.new
109
+ return snapshots unless @container.defined?
110
+ @container.snapshot_list.each do |snapshot|
111
+ (snapname, snap_comment_file, snaptime) = snapshot
112
+ snap_comment = IO.read(snap_comment_file).chomp if File.exist?(snap_comment_file)
113
+ snapshots << [snapname, snaptime, snap_comment]
114
+ end
115
+ snapshots
116
+ end
117
+
118
+ def snapshot_restore(snapname=nil)
119
+ unless @container.defined?
120
+ puts "WARNING: Skipping container '#{@container.name}' because it does not exist"
121
+ return
122
+ end
123
+ if @container.running?
124
+ puts "WARNING: Skipping container '#{@container.name}' because it is running"
125
+ return
126
+ end
127
+ if snapname == "LAST"
128
+ if @container.snapshot_list.empty?
129
+ puts "WARNING: Skipping container '#{@container.name}' because it does not have any snapshots"
130
+ else
131
+ snapname = @container.snapshot_list.last.first
132
+ puts "Restoring snapshot '#{snapname}' of container '#{@container.name}'"
133
+ @container.snapshot_restore(snapname)
134
+ end
135
+ else
136
+ snapshot = @container.snapshot_list.select { |sn| sn.first == snapname }
137
+ if snapshot.flatten.empty?
138
+ puts "WARNING: Skipping container '#{@container.name}' because it does not have a '#{snapname}' snapshot"
139
+ else
140
+ puts "Restoring snapshot '#{snapname}' of container '#{@container.name}'"
141
+ @container.snapshot_restore(snapname)
142
+ end
143
+ end
144
+ end
145
+
146
+ def destroy
147
+ return unless @container.defined?
148
+ @container.snapshot_list.each { |snapshot| @container.snapshot_destroy(snapshot.first) }
149
+ hwaddr = @container.config_item("lxc.network.0.hwaddr")
150
+ @container.destroy
151
+ remove_static_ip_address(hwaddr)
152
+ end
153
+
154
+ def release_lingering_dhcp_ip_addresses(hwaddr)
155
+ dhcp_leases = IO.readlines('/var/lib/misc/dnsmasq.lxcbr0.leases')
156
+ leases_to_release = dhcp_leases.map do |dhcp_lease|
157
+ if m = dhcp_lease.match(/ #{hwaddr} (\d+\.\d+\.\d+\.\d+) /)
158
+ mac_addr = hwaddr
159
+ ip_addr = m[1]
160
+ elsif m = dhcp_lease.match(/ (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w) #{@ipaddress} /)
161
+ mac_addr = m[1]
162
+ ip_addr = @ipaddress
163
+ elsif m = dhcp_lease.match(/ (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w) (\d+\.\d+\.\d+\.\d+) #{@container.name.sub(/\.lxc$/, '')} /)
164
+ mac_addr = m[1]
165
+ ip_addr = m[2]
166
+ end
167
+ if mac_addr && ip_addr
168
+ { dhcp_lease: dhcp_lease, mac_addr: mac_addr, ip_addr: ip_addr }
169
+ end
170
+ end
171
+ leases_to_release.compact!
172
+ unless leases_to_release.empty?
173
+ system("systemctl stop lxc-net.service")
174
+ leases_to_release.each do |l|
175
+ puts "Releasing lingering DHCP lease: #{l[:dhcp_lease]}"
176
+ DevLXC.search_file_delete_line("/var/lib/misc/dnsmasq.lxcbr0.leases", /( #{l[:mac_addr]} #{l[:ip_addr]} )/)
177
+ end
178
+ system("systemctl start lxc-net.service")
179
+ end
180
+ end
181
+
182
+ def assign_static_ip_address(hwaddr)
183
+ puts "Assigning IP address #{@ipaddress} to '#{@container.name}' container's lxc.network.hwaddr #{hwaddr}"
184
+ DevLXC.search_file_delete_line("/etc/lxc/dhcp-hosts.conf", /(^#{hwaddr}|,#{@ipaddress}$)/)
185
+ DevLXC.append_line_to_file("/etc/lxc/dhcp-hosts.conf", "#{hwaddr},#{@ipaddress}\n")
186
+ DevLXC.reload_dnsmasq
187
+ end
188
+
189
+ def remove_static_ip_address(hwaddr=nil)
190
+ if hwaddr
191
+ DevLXC.search_file_delete_line("/etc/lxc/dhcp-hosts.conf", /^#{hwaddr}/)
192
+ DevLXC.reload_dnsmasq
193
+ end
194
+ end
195
+
196
+ end
197
+ end
@@ -1,3 +1,3 @@
1
- module DevLXC
2
- VERSION = "3.2.0"
3
- end
1
+ module DevLXC
2
+ VERSION = "3.3.0"
3
+ end