testlab 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/Gemfile +0 -2
- data/bin/tl +28 -41
- data/lib/testlab/container/actions.rb +35 -0
- data/lib/testlab/container/class_methods.rb +7 -1
- data/lib/testlab/container/generators.rb +11 -0
- data/lib/testlab/container/interface.rb +10 -17
- data/lib/testlab/container/lifecycle.rb +14 -2
- data/lib/testlab/container/lxc.rb +24 -10
- data/lib/testlab/container/method_missing.rb +3 -1
- data/lib/testlab/container/status.rb +46 -2
- data/lib/testlab/container.rb +52 -2
- data/lib/testlab/interface.rb +45 -0
- data/lib/testlab/monkeys.rb +4 -0
- data/lib/testlab/network/actions.rb +1 -1
- data/lib/testlab/network/bind.rb +2 -2
- data/lib/testlab/network/class_methods.rb +1 -1
- data/lib/testlab/network/status.rb +12 -4
- data/lib/testlab/network.rb +2 -1
- data/lib/testlab/node/actions.rb +45 -0
- data/lib/testlab/node/bind.rb +7 -5
- data/lib/testlab/node/lifecycle.rb +3 -5
- data/lib/testlab/node/status.rb +1 -2
- data/lib/testlab/node.rb +1 -2
- data/lib/testlab/providers/vagrant.rb +1 -1
- data/lib/testlab/provisioners/shell.rb +8 -4
- data/lib/testlab/utility/misc.rb +49 -0
- data/lib/testlab/version.rb +1 -1
- data/lib/testlab.rb +123 -31
- data/spec/support/Labfile +8 -9
- data/testlab.gemspec +1 -0
- metadata +24 -5
- data/lib/testlab/router.rb +0 -66
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/bin/tl
CHANGED
@@ -3,39 +3,15 @@ require 'gli'
|
|
3
3
|
require 'testlab'
|
4
4
|
|
5
5
|
include GLI::App
|
6
|
+
include TestLab::Utility::Misc
|
6
7
|
|
7
|
-
|
8
|
+
version TestLab::VERSION
|
8
9
|
|
9
|
-
|
10
|
+
program_desc %(A framework for building lightweight virtual infrastructure using LXC)
|
11
|
+
program_long_desc %(Program Long Description)
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
# desc 'Describe some flag here'
|
15
|
-
# default_value 'the default'
|
16
|
-
# arg_name 'The name of the argument'
|
17
|
-
# flag [:f,:flagname]
|
18
|
-
|
19
|
-
# desc 'Manage the test lab'
|
20
|
-
# arg_name 'Describe arguments to lab here'
|
21
|
-
# command :lab do |c|
|
22
|
-
|
23
|
-
# # c.desc 'Describe a switch to lab'
|
24
|
-
# # c.switch :s
|
25
|
-
|
26
|
-
# # c.desc 'Describe a flag to lab'
|
27
|
-
# # c.default_value 'default'
|
28
|
-
# # c.flag :f
|
29
|
-
# # c.action do |global_options,options,args|
|
30
|
-
|
31
|
-
# # # Your command logic here
|
32
|
-
|
33
|
-
# # # If you have any errors, just raise them
|
34
|
-
# # # raise "that command made no sense"
|
35
|
-
|
36
|
-
# # puts "lab command ran"
|
37
|
-
# # end
|
38
|
-
# end
|
13
|
+
sort_help :manually
|
14
|
+
default_command :help
|
39
15
|
|
40
16
|
desc 'Create the test lab'
|
41
17
|
command :create do |create|
|
@@ -90,7 +66,8 @@ desc 'Manage nodes'
|
|
90
66
|
arg_name 'Describe arguments to node here'
|
91
67
|
command :node do |c|
|
92
68
|
|
93
|
-
c.desc 'Node ID'
|
69
|
+
c.desc 'Node ID or Name'
|
70
|
+
c.arg_name 'node'
|
94
71
|
c.flag [:i, :id]
|
95
72
|
|
96
73
|
c.desc 'Open an SSH console to a node'
|
@@ -117,7 +94,8 @@ desc 'Manage containers'
|
|
117
94
|
arg_name 'Describe arguments to container here'
|
118
95
|
command :container do |c|
|
119
96
|
|
120
|
-
c.desc 'Container ID'
|
97
|
+
c.desc 'Container ID or Name'
|
98
|
+
c.arg_name 'container'
|
121
99
|
c.flag [:i, :id]
|
122
100
|
|
123
101
|
c.desc 'Open an SSH console to a container'
|
@@ -170,7 +148,7 @@ pre do |global,command,options,args|
|
|
170
148
|
@ui = ZTK::UI.new(:logger => @logger)
|
171
149
|
@testlab = TestLab.new(:ui => @ui)
|
172
150
|
|
173
|
-
message =
|
151
|
+
message = format_message("TestLab v#{TestLab::VERSION} Loaded".black.bold)
|
174
152
|
@testlab.ui.stdout.puts(message)
|
175
153
|
|
176
154
|
true
|
@@ -183,16 +161,25 @@ post do |global,command,options,args|
|
|
183
161
|
end
|
184
162
|
|
185
163
|
on_error do |exception|
|
186
|
-
|
187
|
-
|
188
|
-
@ui.stderr.puts(["EXCEPTION:".red.bold, exception.inspect.red].join(' '))
|
164
|
+
@ui.stderr.puts
|
165
|
+
@ui.stderr.puts(format_message(["ERROR:".red, exception.message.red.bold].join(' ')))
|
189
166
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
167
|
+
case exception
|
168
|
+
when GLI::BadCommandLine, GLI::UnknownCommand, GLI::UnknownCommandArgument, GLI::UnknownGlobalArgument then
|
169
|
+
command_regex = /Command '([\w]+)' /
|
170
|
+
command = exception.message.scan(command_regex).flatten.first
|
171
|
+
|
172
|
+
commands[:help] and commands[:help].execute({}, {}, (command.nil? ? [] : [command.to_s]))
|
194
173
|
|
195
|
-
|
174
|
+
false
|
175
|
+
else
|
176
|
+
@logger.fatal { exception.inspect }
|
177
|
+
exception.backtrace.each do |line|
|
178
|
+
@logger.logdev.write("#{line}\n")
|
179
|
+
end
|
180
|
+
|
181
|
+
false
|
182
|
+
end
|
196
183
|
end
|
197
184
|
|
198
185
|
exit run(ARGV)
|
@@ -4,6 +4,11 @@ class TestLab
|
|
4
4
|
module Actions
|
5
5
|
|
6
6
|
# Create the container
|
7
|
+
#
|
8
|
+
# Builds the configuration for the container and sends a request to the
|
9
|
+
# LXC sub-system to create the container.
|
10
|
+
#
|
11
|
+
# @return [Boolean] True if successful.
|
7
12
|
def create
|
8
13
|
@ui.logger.debug { "Container Create: #{self.id} " }
|
9
14
|
|
@@ -22,33 +27,63 @@ class TestLab
|
|
22
27
|
|
23
28
|
self.lxc.create(*create_args)
|
24
29
|
end
|
30
|
+
|
31
|
+
true
|
25
32
|
end
|
26
33
|
|
27
34
|
# Destroy the container
|
35
|
+
#
|
36
|
+
# Sends a request to the LXC sub-system to destroy the container.
|
37
|
+
#
|
38
|
+
# @return [Boolean] True if successful.
|
28
39
|
def destroy
|
29
40
|
@ui.logger.debug { "Container Destroy: #{self.id} " }
|
30
41
|
|
31
42
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Destroy', :red)) do
|
32
43
|
self.lxc.destroy
|
33
44
|
end
|
45
|
+
|
46
|
+
true
|
34
47
|
end
|
35
48
|
|
36
49
|
# Start the container
|
50
|
+
#
|
51
|
+
# Sends a request to the LXC sub-system to bring the container online.
|
52
|
+
#
|
53
|
+
# @return [Boolean] True if successful.
|
37
54
|
def up
|
38
55
|
@ui.logger.debug { "Container Up: #{self.id} " }
|
39
56
|
|
57
|
+
(self.lxc.state == :not_created) and raise ContainerError, "We can not online a non-existant container!"
|
58
|
+
|
40
59
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Up', :green)) do
|
41
60
|
self.lxc.start
|
61
|
+
self.lxc.wait(:running)
|
62
|
+
|
63
|
+
(self.lxc.state != :running) and raise ContainerError, "The container failed to online!"
|
42
64
|
end
|
65
|
+
|
66
|
+
true
|
43
67
|
end
|
44
68
|
|
45
69
|
# Stop the container
|
70
|
+
#
|
71
|
+
# Sends a request to the LXC sub-system to take the container offline.
|
72
|
+
#
|
73
|
+
# @return [Boolean] True if successful.
|
46
74
|
def down
|
47
75
|
@ui.logger.debug { "Container Down: #{self.id} " }
|
48
76
|
|
77
|
+
(self.lxc.state == :not_created) and raise ContainerError, "We can not offline a non-existant container!"
|
78
|
+
|
49
79
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Down', :red)) do
|
50
80
|
self.lxc.stop
|
81
|
+
self.lxc.wait(:stopped)
|
82
|
+
|
83
|
+
(self.lxc.state != :stopped) and raise ContainerError, "The container failed to offline!"
|
51
84
|
end
|
85
|
+
|
86
|
+
true
|
52
87
|
end
|
53
88
|
|
54
89
|
end
|
@@ -3,11 +3,17 @@ class TestLab
|
|
3
3
|
|
4
4
|
module ClassMethods
|
5
5
|
|
6
|
+
# Container domain list
|
7
|
+
#
|
8
|
+
# Returns an array of strings containing all the unique domains defined
|
9
|
+
# across all containers
|
10
|
+
#
|
11
|
+
# @return [Array<String>] A unique array of all defined domain names.
|
6
12
|
def domains
|
7
13
|
self.all.map do |container|
|
8
14
|
container.domain ||= container.node.labfile.config[:domain]
|
9
15
|
container.domain
|
10
|
-
end.compact
|
16
|
+
end.compact.uniq
|
11
17
|
end
|
12
18
|
|
13
19
|
end
|
@@ -3,6 +3,12 @@ class TestLab
|
|
3
3
|
|
4
4
|
module Generators
|
5
5
|
|
6
|
+
# Generate IP address
|
7
|
+
#
|
8
|
+
# Generates an RFC compliant private IP address.
|
9
|
+
#
|
10
|
+
# @return [String] A random, private IP address in the 192.168.0.1/24
|
11
|
+
# range.
|
6
12
|
def generate_ip
|
7
13
|
octets = [ 192..192,
|
8
14
|
168..168,
|
@@ -15,6 +21,11 @@ class TestLab
|
|
15
21
|
ip.join(".")
|
16
22
|
end
|
17
23
|
|
24
|
+
# Generate MAC address
|
25
|
+
#
|
26
|
+
# Generates an RFC compliant private MAC address.
|
27
|
+
#
|
28
|
+
# @return [String] A random, private MAC address.
|
18
29
|
def generate_mac
|
19
30
|
digits = [ %w(0),
|
20
31
|
%w(0),
|
@@ -3,24 +3,17 @@ class TestLab
|
|
3
3
|
|
4
4
|
module Interface
|
5
5
|
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
# Returns a BIND PTR record
|
17
|
-
def ptr
|
18
|
-
TestLab::Utility.ptr(self.primary_interface.last[:ip])
|
19
|
-
end
|
20
|
-
|
6
|
+
# Container primary interface
|
7
|
+
#
|
8
|
+
# Returns the primary interface for the container. If the container has
|
9
|
+
# multiple interfaces, this is based on which ever interface is marked
|
10
|
+
# with the primary flag. If the container only has one interface, then
|
11
|
+
# it is returned.
|
12
|
+
#
|
13
|
+
# @return [TestLab::Interface] The primary interface for the container.
|
21
14
|
def primary_interface
|
22
|
-
if self.interfaces.any?{ |i
|
23
|
-
self.interfaces.find{ |i
|
15
|
+
if self.interfaces.any?{ |i| i.primary == true }
|
16
|
+
self.interfaces.find{ |i| i.primary == true }
|
24
17
|
else
|
25
18
|
self.interfaces.first
|
26
19
|
end
|
@@ -3,7 +3,13 @@ class TestLab
|
|
3
3
|
|
4
4
|
module Lifecycle
|
5
5
|
|
6
|
-
#
|
6
|
+
# Setup the container
|
7
|
+
#
|
8
|
+
# Attempts to setup the container. We first create the container, then
|
9
|
+
# attempt to bring it online. Afterwards the containers provisioner is
|
10
|
+
# called.
|
11
|
+
#
|
12
|
+
# @return [Boolean] True if successful.
|
7
13
|
def setup
|
8
14
|
@ui.logger.debug { "Container Setup: #{self.id} " }
|
9
15
|
|
@@ -19,7 +25,13 @@ class TestLab
|
|
19
25
|
true
|
20
26
|
end
|
21
27
|
|
22
|
-
#
|
28
|
+
# Teardown the container
|
29
|
+
#
|
30
|
+
# Attempts to teardown the container. We first call the provisioner
|
31
|
+
# teardown method defined for the container, if any. Next we attempt to
|
32
|
+
# offline the container. Afterwards the container is destroy.
|
33
|
+
#
|
34
|
+
# @return [Boolean] True if successful.
|
23
35
|
def teardown
|
24
36
|
@ui.logger.debug { "Container Teardown: #{self.id} " }
|
25
37
|
|
@@ -3,7 +3,9 @@ class TestLab
|
|
3
3
|
|
4
4
|
module LXC
|
5
5
|
|
6
|
-
#
|
6
|
+
# LXC::Container object
|
7
|
+
#
|
8
|
+
# Returns a *LXC::Container* class instance configured for this container.
|
7
9
|
#
|
8
10
|
# @return [LXC] An instance of LXC::Container configured for this
|
9
11
|
# container.
|
@@ -11,12 +13,19 @@ class TestLab
|
|
11
13
|
@lxc ||= self.node.lxc.container(self.id)
|
12
14
|
end
|
13
15
|
|
14
|
-
# SSH
|
16
|
+
# ZTK:SSH object
|
17
|
+
#
|
18
|
+
# Returns a *ZTK:SSH* class instance configured for this container.
|
19
|
+
#
|
20
|
+
# @return [ZTK::SSH] An instance of ZTK::SSH configured for this
|
21
|
+
# container.
|
15
22
|
def ssh(options={})
|
16
23
|
self.node.container_ssh(self, options)
|
17
24
|
end
|
18
25
|
|
19
26
|
# Does the container exist?
|
27
|
+
#
|
28
|
+
# @return [Boolean] True if the containers exists, false otherwise.
|
20
29
|
def exists?
|
21
30
|
@ui.logger.debug { "Container Exists?: #{self.id} " }
|
22
31
|
|
@@ -25,7 +34,7 @@ class TestLab
|
|
25
34
|
|
26
35
|
# Returns arguments for lxc-create based on our distro
|
27
36
|
#
|
28
|
-
# @return [Array] An array of arguments for lxc-create
|
37
|
+
# @return [Array<String>] An array of arguments for lxc-create
|
29
38
|
def create_args
|
30
39
|
case self.distro.downcase
|
31
40
|
when "ubuntu" then
|
@@ -49,21 +58,26 @@ class TestLab
|
|
49
58
|
end
|
50
59
|
end
|
51
60
|
|
61
|
+
# LXC Network Configuration
|
62
|
+
#
|
52
63
|
# Builds an array of hashes containing the lxc configuration options for
|
53
|
-
# our
|
64
|
+
# our network interfaces.
|
65
|
+
#
|
66
|
+
# @return [Array<Hash>] An array of hashes defining the containers
|
67
|
+
# interfaces for use in configuring LXC.
|
54
68
|
def build_lxc_network_conf(interfaces)
|
55
69
|
networks = Array.new
|
56
70
|
|
57
|
-
interfaces.each do |
|
71
|
+
interfaces.each do |interface|
|
58
72
|
networks << Hash[
|
59
73
|
'lxc.network.type' => :veth,
|
60
74
|
'lxc.network.flags' => :up,
|
61
|
-
'lxc.network.link' =>
|
62
|
-
'lxc.network.name' =>
|
63
|
-
'lxc.network.hwaddr' =>
|
64
|
-
'lxc.network.ipv4' =>
|
75
|
+
'lxc.network.link' => interface.network.bridge,
|
76
|
+
'lxc.network.name' => interface.name,
|
77
|
+
'lxc.network.hwaddr' => interface.mac,
|
78
|
+
'lxc.network.ipv4' => "#{interface.ip}/#{interface.cidr} #{interface.netmask}"
|
65
79
|
]
|
66
|
-
if (
|
80
|
+
if (interface.primary == true) || (interfaces.count == 1)
|
67
81
|
networks.last.merge!('lxc.network.ipv4.gateway' => :auto)
|
68
82
|
end
|
69
83
|
end
|
@@ -3,7 +3,9 @@ class TestLab
|
|
3
3
|
|
4
4
|
module MethodMissing
|
5
5
|
|
6
|
-
#
|
6
|
+
# Provisioner method handler
|
7
|
+
#
|
8
|
+
# Proxies missing methods to the containers defined provisioner, if any.
|
7
9
|
def method_missing(method_name, *method_args)
|
8
10
|
@ui.logger.debug { "CONTAINER METHOD MISSING: #{method_name.inspect}(#{method_args.inspect})" }
|
9
11
|
|
@@ -3,14 +3,54 @@ class TestLab
|
|
3
3
|
|
4
4
|
module Status
|
5
5
|
|
6
|
+
# Container IP
|
7
|
+
#
|
8
|
+
# Returns the IP of the container.
|
9
|
+
#
|
10
|
+
# @return [String] The containers IP address.
|
11
|
+
def ip
|
12
|
+
TestLab::Utility.ip(self.primary_interface.address)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Container CIDR
|
16
|
+
#
|
17
|
+
# Returns the CIDR of the container
|
18
|
+
#
|
19
|
+
# @return [Integer] The containers CIDR address.
|
20
|
+
def cidr
|
21
|
+
TestLab::Utility.cidr(self.primary_interface.address).to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
# Container BIND PTR Record
|
25
|
+
#
|
26
|
+
# Returns a BIND reverse-DNS PTR record.
|
27
|
+
#
|
28
|
+
# @return [String] The containers ARPA PTR record.
|
29
|
+
def ptr
|
30
|
+
TestLab::Utility.ptr(self.primary_interface.address)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Container FQDN
|
34
|
+
#
|
35
|
+
# Returns the FQDN for the container.
|
36
|
+
#
|
37
|
+
# @return [String] The containers FQDN.
|
6
38
|
def fqdn
|
7
39
|
self.domain ||= self.node.labfile.config[:domain]
|
8
40
|
|
9
41
|
[self.id, self.domain].join('.')
|
10
42
|
end
|
11
43
|
|
44
|
+
# Container Status
|
45
|
+
#
|
46
|
+
# Returns a hash of status information for the container.
|
47
|
+
#
|
48
|
+
# @return [Hash] A hash of status information for the container.
|
12
49
|
def status
|
13
|
-
interfaces = self.interfaces.collect
|
50
|
+
interfaces = self.interfaces.collect do |interface|
|
51
|
+
"#{interface.network_id}:#{interface.name}:#{interface.ip}/#{interface.cidr}"
|
52
|
+
end.join(', ')
|
53
|
+
|
14
54
|
{
|
15
55
|
:id => self.id,
|
16
56
|
:fqdn => self.fqdn,
|
@@ -23,7 +63,11 @@ class TestLab
|
|
23
63
|
}
|
24
64
|
end
|
25
65
|
|
26
|
-
# State
|
66
|
+
# Container State
|
67
|
+
#
|
68
|
+
# What state the container is in.
|
69
|
+
#
|
70
|
+
# @return [Symbol] A symbol indicating the state of the container.
|
27
71
|
def state
|
28
72
|
self.lxc.state
|
29
73
|
end
|
data/lib/testlab/container.rb
CHANGED
@@ -5,8 +5,59 @@ class TestLab
|
|
5
5
|
|
6
6
|
# Container Class
|
7
7
|
#
|
8
|
+
# This class represents the TestLab Container DSL object.
|
9
|
+
#
|
10
|
+
# @example A simple container definition with a single interface:
|
11
|
+
# container "server-west-1" do
|
12
|
+
# domain "west.zone"
|
13
|
+
#
|
14
|
+
# distro "ubuntu"
|
15
|
+
# release "precise"
|
16
|
+
#
|
17
|
+
# interface do
|
18
|
+
# network_id :west
|
19
|
+
# name :eth0
|
20
|
+
# address '10.11.0.254/16'
|
21
|
+
# mac '00:00:5e:48:e9:6f'
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @example Multiple interfaces can be defined as well:
|
26
|
+
# container "dual-nic" do
|
27
|
+
# distro "ubuntu"
|
28
|
+
# release "precise"
|
29
|
+
#
|
30
|
+
# interface do
|
31
|
+
# network_id :east
|
32
|
+
# name :eth0
|
33
|
+
# address '10.10.0.200/16'
|
34
|
+
# mac '00:00:5e:63:b5:9f'
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# interface do
|
38
|
+
# network_id :west
|
39
|
+
# primary true
|
40
|
+
# name :eth1
|
41
|
+
# address '10.11.0.200/16'
|
42
|
+
# mac '00:00:5e:08:63:df'
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# The operating system is determined by the *distro* and *release* attributes.
|
47
|
+
# The hostname (container ID) is passed as a parameter to the container call.
|
48
|
+
# A *domain* may additionally be specified (overriding the global domain, if
|
49
|
+
# set). If the *domain* attributes is omited, then the global domain is use,
|
50
|
+
# again only if it is set. The hostname (container ID) and the domain will be
|
51
|
+
# joined together to form the FQDN of the container.
|
52
|
+
#
|
53
|
+
# @see TestLab::Interface
|
54
|
+
#
|
8
55
|
# @author Zachary Patten <zachary@jovelabs.net>
|
9
56
|
class Container < ZTK::DSL::Base
|
57
|
+
|
58
|
+
# An array of symbols of the various keys in our status hash.
|
59
|
+
#
|
60
|
+
# @see TestLab::Container::Status
|
10
61
|
STATUS_KEYS = %w(node_id id fqdn state distro release interfaces provisioner).map(&:to_sym)
|
11
62
|
|
12
63
|
# Sub-Modules
|
@@ -33,6 +84,7 @@ class TestLab
|
|
33
84
|
|
34
85
|
# Associations and Attributes
|
35
86
|
belongs_to :node, :class_name => 'TestLab::Node'
|
87
|
+
has_many :interfaces, :class_name => 'TestLab::Interface'
|
36
88
|
|
37
89
|
attribute :provisioner
|
38
90
|
attribute :config
|
@@ -43,8 +95,6 @@ class TestLab
|
|
43
95
|
attribute :passwd
|
44
96
|
attribute :keys
|
45
97
|
|
46
|
-
attribute :interfaces
|
47
|
-
|
48
98
|
attribute :distro
|
49
99
|
attribute :release
|
50
100
|
attribute :arch
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class TestLab
|
2
|
+
|
3
|
+
# Interface Error Class
|
4
|
+
class InterfaceError < TestLabError; end
|
5
|
+
|
6
|
+
# Interface Class
|
7
|
+
#
|
8
|
+
# @author Zachary Patten <zachary@jovelabs.net>
|
9
|
+
class Interface < ZTK::DSL::Base
|
10
|
+
|
11
|
+
# Associations and Attributes
|
12
|
+
belongs_to :container, :class_name => 'TestLab::Container'
|
13
|
+
belongs_to :network, :class_name => 'TestLab::Network'
|
14
|
+
|
15
|
+
attribute :address
|
16
|
+
attribute :mac
|
17
|
+
attribute :name
|
18
|
+
|
19
|
+
attribute :primary
|
20
|
+
|
21
|
+
def initialize(*args)
|
22
|
+
super(*args)
|
23
|
+
|
24
|
+
@ui = TestLab.ui
|
25
|
+
end
|
26
|
+
|
27
|
+
def ip
|
28
|
+
TestLab::Utility.ip(self.address)
|
29
|
+
end
|
30
|
+
|
31
|
+
def cidr
|
32
|
+
TestLab::Utility.cidr(self.address)
|
33
|
+
end
|
34
|
+
|
35
|
+
def netmask
|
36
|
+
TestLab::Utility.netmask(self.address)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ptr
|
40
|
+
TestLab::Utility.ptr(self.address)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -26,7 +26,7 @@ class TestLab
|
|
26
26
|
@ui.logger.debug { "Network Up: #{self.id} " }
|
27
27
|
|
28
28
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Up', :green)) do
|
29
|
-
self.node.ssh.exec(%(sudo ifconfig #{self.bridge} #{self.ip} up), :silence => true, :ignore_exit_status => true)
|
29
|
+
self.node.ssh.exec(%(sudo ifconfig #{self.bridge} #{self.ip} netmask #{self.netmask} up), :silence => true, :ignore_exit_status => true)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
data/lib/testlab/network/bind.rb
CHANGED
@@ -5,12 +5,12 @@ class TestLab
|
|
5
5
|
|
6
6
|
# BIND PTR Record
|
7
7
|
def ptr
|
8
|
-
TestLab::Utility.ptr(self.
|
8
|
+
TestLab::Utility.ptr(self.address)
|
9
9
|
end
|
10
10
|
|
11
11
|
# Returns the ARPA network
|
12
12
|
def arpa
|
13
|
-
TestLab::Utility.arpa(self.
|
13
|
+
TestLab::Utility.arpa(self.address)
|
14
14
|
end
|
15
15
|
|
16
16
|
end
|
@@ -5,7 +5,7 @@ class TestLab
|
|
5
5
|
|
6
6
|
# Network status
|
7
7
|
def status
|
8
|
-
interface = "#{bridge}:#{
|
8
|
+
interface = "#{bridge}:#{self.address}"
|
9
9
|
{
|
10
10
|
:id => self.id,
|
11
11
|
:node_id => self.node.id,
|
@@ -17,19 +17,27 @@ class TestLab
|
|
17
17
|
}
|
18
18
|
end
|
19
19
|
|
20
|
+
def ip
|
21
|
+
TestLab::Utility.ip(self.address)
|
22
|
+
end
|
23
|
+
|
24
|
+
def cidr
|
25
|
+
TestLab::Utility.cidr(self.address)
|
26
|
+
end
|
27
|
+
|
20
28
|
# Returns the network mask
|
21
29
|
def netmask
|
22
|
-
TestLab::Utility.netmask(self.
|
30
|
+
TestLab::Utility.netmask(self.address)
|
23
31
|
end
|
24
32
|
|
25
33
|
# Returns the network address
|
26
34
|
def network
|
27
|
-
TestLab::Utility.network(self.
|
35
|
+
TestLab::Utility.network(self.address)
|
28
36
|
end
|
29
37
|
|
30
38
|
# Returns the broadcast address
|
31
39
|
def broadcast
|
32
|
-
TestLab::Utility.broadcast(self.
|
40
|
+
TestLab::Utility.broadcast(self.address)
|
33
41
|
end
|
34
42
|
|
35
43
|
# Network Bridge State
|
data/lib/testlab/network.rb
CHANGED
@@ -27,10 +27,11 @@ class TestLab
|
|
27
27
|
|
28
28
|
# Associations and Attributes
|
29
29
|
belongs_to :node, :class_name => 'TestLab::Node'
|
30
|
+
has_many :interfaces, :class_name => 'TestLab::Interface'
|
30
31
|
|
32
|
+
attribute :address
|
31
33
|
attribute :bridge
|
32
34
|
|
33
|
-
attribute :ip
|
34
35
|
attribute :config
|
35
36
|
|
36
37
|
|