testlab 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,8 +7,10 @@ class TestLab
7
7
  def create
8
8
  @ui.logger.debug { "Container Create: #{self.id} " }
9
9
 
10
+ self.domain ||= self.node.labfile.config[:domain]
10
11
  self.distro ||= "ubuntu"
11
12
  self.release ||= "precise"
13
+
12
14
  self.arch ||= detect_arch
13
15
 
14
16
  self.lxc.config.clear
@@ -0,0 +1,16 @@
1
+ class TestLab
2
+ class Container
3
+
4
+ module ClassMethods
5
+
6
+ def domains
7
+ self.all.map do |container|
8
+ container.domain ||= container.node.labfile.config[:domain]
9
+ container.domain
10
+ end.compact
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ class TestLab
2
+ class Container
3
+
4
+ module Interface
5
+
6
+ def ip
7
+ TestLab::Utility.ip(self.primary_interface.last[:ip])
8
+ end
9
+
10
+ # Returns the CIDR of the container
11
+ def cidr
12
+ TestLab::Utility.cidr(self.primary_interface.last[:ip]).to_i
13
+ end
14
+
15
+ def ptr
16
+ octets = self.ip.split('.')
17
+
18
+ result = case self.cidr
19
+ when 0..7 then
20
+ octets[-4,4]
21
+ when 8..15 then
22
+ octets[-3,3]
23
+ when 16..23 then
24
+ octets[-2,2]
25
+ when 24..31 then
26
+ octets[-1,1]
27
+ end
28
+
29
+ result.reverse.join('.')
30
+ end
31
+
32
+ def primary_interface
33
+ if self.interfaces.any?{ |i,c| c[:primary] == true }
34
+ self.interfaces.find{ |i,c| c[:primary] == true }
35
+ else
36
+ self.interfaces.first
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
@@ -11,6 +11,18 @@ class TestLab
11
11
  @lxc ||= self.node.lxc.container(self.id)
12
12
  end
13
13
 
14
+ # SSH to the container
15
+ def ssh(options={})
16
+ self.node.container_ssh(self, options)
17
+ end
18
+
19
+ # Does the container exist?
20
+ def exists?
21
+ @ui.logger.debug { "Container Exists?: #{self.id} " }
22
+
23
+ self.lxc.exists?
24
+ end
25
+
14
26
  # Returns arguments for lxc-create based on our distro
15
27
  #
16
28
  # @return [Array] An array of arguments for lxc-create
@@ -37,6 +49,28 @@ class TestLab
37
49
  end
38
50
  end
39
51
 
52
+ # Builds an array of hashes containing the lxc configuration options for
53
+ # our networks
54
+ def build_lxc_network_conf(interfaces)
55
+ networks = Array.new
56
+
57
+ interfaces.each do |network, network_config|
58
+ networks << Hash[
59
+ 'lxc.network.type' => :veth,
60
+ 'lxc.network.flags' => :up,
61
+ 'lxc.network.link' => TestLab::Network.first(network).bridge,
62
+ 'lxc.network.name' => network_config[:name],
63
+ 'lxc.network.hwaddr' => network_config[:mac],
64
+ 'lxc.network.ipv4' => network_config[:ip]
65
+ ]
66
+ if (network_config[:primary] == true) || (interfaces.count == 1)
67
+ networks.last.merge!('lxc.network.ipv4.gateway' => :auto)
68
+ end
69
+ end
70
+
71
+ networks
72
+ end
73
+
40
74
  end
41
75
 
42
76
  end
@@ -0,0 +1,20 @@
1
+ class TestLab
2
+ class Container
3
+
4
+ module MethodMissing
5
+
6
+ # Method missing handler
7
+ def method_missing(method_name, *method_args)
8
+ @ui.logger.debug { "CONTAINER METHOD MISSING: #{method_name.inspect}(#{method_args.inspect})" }
9
+
10
+ if (defined?(@provisioner) && @provisioner.respond_to?(method_name))
11
+ @provisioner.send(method_name, [self, *method_args].flatten)
12
+ else
13
+ super(method_name, *method_args)
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -3,11 +3,17 @@ class TestLab
3
3
 
4
4
  module Status
5
5
 
6
+ def fqdn
7
+ self.domain ||= self.node.labfile.config[:domain]
8
+
9
+ [self.id, self.domain].join('.')
10
+ end
11
+
6
12
  def status
7
13
  interfaces = self.interfaces.collect{ |network, network_config| "#{network}:#{network_config[:name]}:#{network_config[:ip]}" }.join(', ')
8
-
9
14
  {
10
15
  :id => self.id,
16
+ :fqdn => self.fqdn,
11
17
  :state => self.state,
12
18
  :distro => self.distro,
13
19
  :release => self.release,
@@ -7,8 +7,29 @@ class TestLab
7
7
  #
8
8
  # @author Zachary Patten <zachary@jovelabs.net>
9
9
  class Container < ZTK::DSL::Base
10
- STATUS_KEYS = %w(node_id id state distro release interfaces provisioner).map(&:to_sym)
10
+ STATUS_KEYS = %w(node_id id fqdn state distro release interfaces provisioner).map(&:to_sym)
11
+
12
+ # Sub-Modules
13
+ autoload :Actions, 'testlab/container/actions'
14
+ autoload :ClassMethods, 'testlab/container/class_methods'
15
+ autoload :Generators, 'testlab/container/generators'
16
+ autoload :Interface, 'testlab/container/interface'
17
+ autoload :Lifecycle, 'testlab/container/lifecycle'
18
+ autoload :LXC, 'testlab/container/lxc'
19
+ autoload :MethodMissing, 'testlab/container/method_missing'
20
+ autoload :Status, 'testlab/container/status'
11
21
 
22
+ include TestLab::Container::Actions
23
+ include TestLab::Container::Generators
24
+ include TestLab::Container::Interface
25
+ include TestLab::Container::Lifecycle
26
+ include TestLab::Container::LXC
27
+ include TestLab::Container::MethodMissing
28
+ include TestLab::Container::Status
29
+
30
+ extend TestLab::Container::ClassMethods
31
+
32
+ # Associations and Attributes
12
33
  belongs_to :node, :class_name => 'TestLab::Node'
13
34
 
14
35
  attribute :provisioner
@@ -28,21 +49,6 @@ class TestLab
28
49
  attribute :persist
29
50
 
30
51
 
31
- autoload :Actions, 'testlab/container/actions'
32
- autoload :Generators, 'testlab/container/generators'
33
- autoload :Lifecycle, 'testlab/container/lifecycle'
34
- autoload :LXC, 'testlab/container/lxc'
35
- autoload :Network, 'testlab/container/network'
36
- autoload :Status, 'testlab/container/status'
37
-
38
- include TestLab::Container::Actions
39
- include TestLab::Container::Generators
40
- include TestLab::Container::Lifecycle
41
- include TestLab::Container::LXC
42
- include TestLab::Container::Network
43
- include TestLab::Container::Status
44
-
45
-
46
52
  def initialize(*args)
47
53
  super(*args)
48
54
 
@@ -50,77 +56,6 @@ class TestLab
50
56
  @provisioner = self.provisioner.new(self.config) if !self.provisioner.nil?
51
57
  end
52
58
 
53
- ################################################################################
54
-
55
- # Does the container exist?
56
- def exists?
57
- @ui.logger.debug { "Container Exists?: #{self.id} " }
58
-
59
- self.lxc.exists?
60
- end
61
-
62
- ################################################################################
63
-
64
- # SSH to the container
65
- def ssh(options={})
66
- self.node.container_ssh(self, options)
67
- end
68
-
69
- def ip
70
- self.primary_interface.last[:ip].split('/').first
71
- end
72
-
73
- # Returns the CIDR of the container
74
- def cidr
75
- self.primary_interface.last[:ip].split('/').last.to_i
76
- end
77
-
78
- def ptr
79
- octets = self.ip.split('.')
80
-
81
- result = case self.cidr
82
- when 0..7 then
83
- octets[-4,4]
84
- when 8..15 then
85
- octets[-3,3]
86
- when 16..23 then
87
- octets[-2,2]
88
- when 24..31 then
89
- octets[-1,1]
90
- end
91
-
92
- result.reverse.join('.')
93
- end
94
-
95
- def primary_interface
96
- if self.interfaces.any?{ |i,c| c[:primary] == true }
97
- self.interfaces.find{ |i,c| c[:primary] == true }
98
- else
99
- self.interfaces.first
100
- end
101
- end
102
-
103
- class << self
104
-
105
- def domains
106
- self.all.map(&:domain).compact
107
- end
108
-
109
- end
110
-
111
- ################################################################################
112
-
113
- # Method missing handler
114
- def method_missing(method_name, *method_args)
115
- @ui.logger.debug { "CONTAINER METHOD MISSING: #{method_name.inspect}(#{method_args.inspect})" }
116
-
117
- if (defined?(@provisioner) && @provisioner.respond_to?(method_name))
118
- @provisioner.send(method_name, [self, *method_args].flatten)
119
- else
120
- super(method_name, *method_args)
121
- end
122
- end
123
-
124
59
  end
125
60
 
126
61
  end
@@ -0,0 +1,19 @@
1
+ class TestLab
2
+ class Network
3
+
4
+ module Bind
5
+
6
+ # BIND PTR Record
7
+ def ptr
8
+ TestLab::Utility.ptr(self.ip)
9
+ end
10
+
11
+ # Returns the ARPA network
12
+ def arpa
13
+ TestLab::Utility.arpa(self.ip)
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ class TestLab
2
+ class Network
3
+
4
+ module ClassMethods
5
+
6
+ def ips
7
+ self.all.map(&:ip).collect{ |ip| TestLab::Utility.ip(ip) }.compact
8
+ end
9
+
10
+ end
11
+
12
+ end
13
+ end
@@ -10,10 +10,28 @@ class TestLab
10
10
  :id => self.id,
11
11
  :node_id => self.node.id,
12
12
  :state => self.state,
13
- :interface => interface
13
+ :interface => interface,
14
+ :broadcast => self.broadcast,
15
+ :network => self.network,
16
+ :netmask => self.netmask
14
17
  }
15
18
  end
16
19
 
20
+ # Returns the network mask
21
+ def netmask
22
+ TestLab::Utility.netmask(self.ip)
23
+ end
24
+
25
+ # Returns the network address
26
+ def network
27
+ TestLab::Utility.network(self.ip)
28
+ end
29
+
30
+ # Returns the broadcast address
31
+ def broadcast
32
+ TestLab::Utility.broadcast(self.ip)
33
+ end
34
+
17
35
  # Network Bridge State
18
36
  def state
19
37
  output = self.node.ssh.exec(%(sudo ifconfig #{self.bridge} | grep 'MTU'), :silence => true, :ignore_exit_status => true).output.strip
@@ -7,8 +7,23 @@ class TestLab
7
7
  #
8
8
  # @author Zachary Patten <zachary@jovelabs.net>
9
9
  class Network < ZTK::DSL::Base
10
- STATUS_KEYS = %w(node_id id state interface).map(&:to_sym)
10
+ STATUS_KEYS = %w(node_id id state interface network netmask broadcast).map(&:to_sym)
11
11
 
12
+ # Sub-Modules
13
+ autoload :Actions, 'testlab/network/actions'
14
+ autoload :Bind, 'testlab/network/bind'
15
+ autoload :ClassMethods, 'testlab/network/class_methods'
16
+ autoload :Lifecycle, 'testlab/network/lifecycle'
17
+ autoload :Status, 'testlab/network/status'
18
+
19
+ include TestLab::Network::Actions
20
+ include TestLab::Network::Bind
21
+ include TestLab::Network::Lifecycle
22
+ include TestLab::Network::Status
23
+
24
+ extend TestLab::Network::ClassMethods
25
+
26
+ # Associations and Attributes
12
27
  belongs_to :node, :class_name => 'TestLab::Node'
13
28
 
14
29
  attribute :bridge
@@ -16,15 +31,6 @@ class TestLab
16
31
  attribute :ip
17
32
  attribute :config
18
33
 
19
- autoload :Actions, 'testlab/network/actions'
20
- autoload :CIDR, 'testlab/network/cidr'
21
- autoload :Lifecycle, 'testlab/network/lifecycle'
22
- autoload :Status, 'testlab/network/status'
23
-
24
- include TestLab::Network::Actions
25
- include TestLab::Network::CIDR
26
- include TestLab::Network::Lifecycle
27
- include TestLab::Network::Status
28
34
 
29
35
  def initialize(*args)
30
36
  super(*args)
@@ -17,14 +17,14 @@ class TestLab
17
17
  reverse_records = Hash.new
18
18
 
19
19
  TestLab::Container.all.each do |container|
20
- interface = container.primary_interface
21
- domain = (container.domain || container.node.labfile.config[:domain])
20
+ interface = container.primary_interface
21
+ container.domain ||= container.node.labfile.config[:domain]
22
22
 
23
- forward_records[domain] ||= Array.new
24
- forward_records[domain] << %(#{container.id} IN A #{container.ip})
23
+ forward_records[container.domain] ||= Array.new
24
+ forward_records[container.domain] << %(#{container.id} IN A #{container.ip})
25
25
 
26
26
  reverse_records[interface.first] ||= Array.new
27
- reverse_records[interface.first] << %(#{container.ptr} IN PTR #{container.id}.#{domain}.)
27
+ reverse_records[interface.first] << %(#{container.ptr} IN PTR #{container.id}.#{container.domain}.)
28
28
  end
29
29
  { :forward => forward_records, :reverse => reverse_records }
30
30
  end
@@ -48,8 +48,7 @@ class TestLab
48
48
  build_bind_db(network.arpa, reverse_records[network.id])
49
49
  end
50
50
 
51
- domains = ([self.labfile.config[:domain]] + TestLab::Container.domains).flatten
52
- domains.each do |domain|
51
+ TestLab::Container.domains.each do |domain|
53
52
  context = {
54
53
  :zone => domain
55
54
  }
@@ -68,8 +67,6 @@ class TestLab
68
67
  file.puts(ZTK::Template.do_not_edit_notice(:message => "TestLab v#{TestLab::VERSION} BIND DB: #{zone}", :char => ';'))
69
68
  file.puts(ZTK::Template.render(bind_db_template, { :zone => zone, :records => records }))
70
69
  end
71
-
72
- # self.ssh.exec(%(sudo rm -fv /etc/bind/db.#{zone}.jnl))
73
70
  end
74
71
 
75
72
  # Builds the BIND configuration
@@ -80,13 +77,18 @@ class TestLab
80
77
  end
81
78
  end
82
79
 
83
- def bind_setup
84
- bind_setup_template = File.join(self.class.template_dir, 'bind-setup.erb')
85
- self.ssh.bootstrap(ZTK::Template.render(bind_setup_template))
80
+ def bind_install
81
+ self.ssh.exec(%(sudo apt-get -y install bind9))
82
+ end
86
83
 
87
- build_bind_conf
84
+ def bind_reload
85
+ self.ssh.exec(%(sudo rndc reload))
86
+ end
88
87
 
89
- self.ssh.exec(%(sudo /bin/bash -c 'service bind9 restart || service bind9 start'))
88
+ def bind_setup
89
+ bind_install
90
+ build_bind_conf
91
+ bind_reload
90
92
  end
91
93
 
92
94
  end
@@ -0,0 +1,14 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module ClassMethods
5
+
6
+ # Returns the path to the node templates
7
+ def template_dir
8
+ File.join(TestLab.gem_dir, "lib", "testlab", "node", "templates")
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -3,6 +3,23 @@ class TestLab
3
3
 
4
4
  module Lifecycle
5
5
 
6
+ # Iterates an array of arrays calling the specified method on all the
7
+ # collections of objects
8
+ def call_collections(collections, method_name)
9
+ collections.each do |collection|
10
+ call_methods(collection, method_name)
11
+ end
12
+ end
13
+
14
+ # Calls the specified method on all the objects supplied
15
+ def call_methods(objects, method_name)
16
+ objects.each do |object|
17
+ if object.respond_to?(method_name)
18
+ object.send(method_name)
19
+ end
20
+ end
21
+ end
22
+
6
23
  # Bootstrap the node
7
24
  def node_setup
8
25
  node_setup_template = File.join(self.class.template_dir, 'node-setup.erb')
@@ -25,6 +42,10 @@ class TestLab
25
42
 
26
43
  call_collections([self.networks, self.routers, self.containers], :setup)
27
44
 
45
+ if self.components.include?('bind')
46
+ bind_reload
47
+ end
48
+
28
49
  true
29
50
  end
30
51
 
@@ -0,0 +1,29 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module MethodMissing
5
+
6
+ # Node Method Missing Handler
7
+ def method_missing(method_name, *method_args)
8
+ @ui.logger.debug { "NODE METHOD MISSING: #{method_name.inspect}(#{method_args.inspect})" }
9
+
10
+ if TestLab::Provider::PROXY_METHODS.include?(method_name)
11
+ result = nil
12
+
13
+ if @provider.respond_to?(method_name)
14
+ @ui.logger.debug { "@provider.send(#{method_name.inspect}, #{method_args.inspect})" }
15
+ result = @provider.send(method_name, *method_args)
16
+ else
17
+ raise TestLab::ProviderError, "Your provider does not respond to the method '#{method_name}'!"
18
+ end
19
+
20
+ result
21
+ else
22
+ super(method_name, *method_args)
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -8,10 +8,9 @@ class TestLab
8
8
  def build_resolv_main_conf(file)
9
9
  resolv_conf_template = File.join(self.class.template_dir, "resolv.erb")
10
10
 
11
- domains = ([self.labfile.config[:domain]] + TestLab::Container.domains).flatten
12
11
  context = {
13
- :servers => [TestLab::Network.all.map(&:clean_ip), "8.8.8.8", "8.8.4.4" ].flatten,
14
- :search => domains.join(' ')
12
+ :servers => [TestLab::Network.ips, "8.8.8.8", "8.8.4.4" ].flatten,
13
+ :search => TestLab::Container.domains.join(' ')
15
14
  }
16
15
 
17
16
  file.puts(ZTK::Template.do_not_edit_notice(:message => "TestLab v#{TestLab::VERSION} RESOLVER Configuration"))
@@ -8,6 +8,7 @@ class TestLab
8
8
  # @return [Hash] A hash detailing the status of the node.
9
9
  def status
10
10
  {
11
+ :id => self.id,
11
12
  :instance_id => @provider.instance_id,
12
13
  :state => @provider.state,
13
14
  :user => @provider.user,
@@ -1,6 +1,6 @@
1
1
  $TTL 1d
2
2
  @ IN SOA localhost. root.localhost. (
3
- 0 ; Serial
3
+ <%= Time.now.to_i %> ; Serial
4
4
  1w ; Refresh
5
5
  1d ; Retry
6
6
  4w ; Expire
@@ -10,9 +10,10 @@ options {
10
10
  // Uncomment the following block, and insert the addresses replacing
11
11
  // the all-0's placeholder.
12
12
 
13
- // forwarders {
14
- // 0.0.0.0;
15
- // };
13
+ forwarders {
14
+ 8.8.8.8;
15
+ 8.8.4.4;
16
+ };
16
17
 
17
18
  //========================================================================
18
19
  // If BIND logs error messages about the root key being expired,
data/lib/testlab/node.rb CHANGED
@@ -9,6 +9,27 @@ class TestLab
9
9
  class Node < ZTK::DSL::Base
10
10
  STATUS_KEYS = %w(id instance_id state user ip port provider con net rtr).map(&:to_sym)
11
11
 
12
+ # Sub-Modules
13
+ autoload :Bind, 'testlab/node/bind'
14
+ autoload :ClassMethods, 'testlab/node/class_methods'
15
+ autoload :Lifecycle, 'testlab/node/lifecycle'
16
+ autoload :LXC, 'testlab/node/lxc'
17
+ autoload :MethodMissing, 'testlab/node/method_missing'
18
+ autoload :Resolv, 'testlab/node/resolv'
19
+ autoload :SSH, 'testlab/node/ssh'
20
+ autoload :Status, 'testlab/node/status'
21
+
22
+ include TestLab::Node::Bind
23
+ include TestLab::Node::Lifecycle
24
+ include TestLab::Node::LXC
25
+ include TestLab::Node::MethodMissing
26
+ include TestLab::Node::Resolv
27
+ include TestLab::Node::SSH
28
+ include TestLab::Node::Status
29
+
30
+ extend TestLab::Node::ClassMethods
31
+
32
+ # Associations and Attributes
12
33
  belongs_to :labfile, :class_name => 'TestLab::Lab'
13
34
 
14
35
  has_many :routers, :class_name => 'TestLab::Router'
@@ -20,21 +41,6 @@ class TestLab
20
41
  attribute :components
21
42
 
22
43
 
23
- autoload :Bind, 'testlab/node/bind'
24
- autoload :Lifecycle, 'testlab/node/lifecycle'
25
- autoload :LXC, 'testlab/node/lxc'
26
- autoload :Resolv, 'testlab/node/resolv'
27
- autoload :SSH, 'testlab/node/ssh'
28
- autoload :Status, 'testlab/node/status'
29
-
30
- include TestLab::Node::Bind
31
- include TestLab::Node::Lifecycle
32
- include TestLab::Node::LXC
33
- include TestLab::Node::Resolv
34
- include TestLab::Node::SSH
35
- include TestLab::Node::Status
36
-
37
-
38
44
  def initialize(*args)
39
45
  super(*args)
40
46
 
@@ -42,54 +48,6 @@ class TestLab
42
48
  @provider = self.provider.new(self.config)
43
49
  end
44
50
 
45
- ################################################################################
46
-
47
- # Iterates an array of arrays calling the specified method on all the
48
- # collections of objects
49
- def call_collections(collections, method_name)
50
- collections.each do |collection|
51
- call_methods(collection, method_name)
52
- end
53
- end
54
-
55
- # Calls the specified method on all the objects supplied
56
- def call_methods(objects, method_name)
57
- objects.each do |object|
58
- if object.respond_to?(method_name)
59
- object.send(method_name)
60
- end
61
- end
62
- end
63
-
64
- # Method missing handler
65
- def method_missing(method_name, *method_args)
66
- @ui.logger.debug { "NODE METHOD MISSING: #{method_name.inspect}(#{method_args.inspect})" }
67
-
68
- if TestLab::Provider::PROXY_METHODS.include?(method_name)
69
- result = nil
70
-
71
- if @provider.respond_to?(method_name)
72
- @ui.logger.debug { "@provider.send(#{method_name.inspect}, #{method_args.inspect})" }
73
- result = @provider.send(method_name, *method_args)
74
- else
75
- raise TestLab::ProviderError, "Your provider does not respond to the method '#{method_name}'!"
76
- end
77
-
78
- result
79
- else
80
- super(method_name, *method_args)
81
- end
82
- end
83
-
84
- class << self
85
-
86
- # Returns the path to the gems provider templates
87
- def template_dir
88
- File.join(TestLab.gem_dir, "lib", "testlab", "node", "templates")
89
- end
90
-
91
- end
92
-
93
51
  end
94
52
 
95
53
  end
@@ -1,6 +1,12 @@
1
1
  class TestLab
2
- class Network
2
+ module Utility
3
3
 
4
+ # CIDR Error Class
5
+ class CIDRError < UtilityError; end
6
+
7
+ # CIDR Module
8
+ #
9
+ # @author Zachary Patten <zachary@jovelabs.net>
4
10
  module CIDR
5
11
 
6
12
  CIDR_MATRIX = {
@@ -39,61 +45,81 @@ class TestLab
39
45
  0 => { :netmask => '0.0.0.0', :broadcast => '255.255.255.255', :network => '0.0.0.0' }
40
46
  }
41
47
 
42
- # Returns the CIDR of the network
43
- def cidr
44
- self.ip.split('/').last.to_i
48
+ def ip(ip)
49
+ ip.split('/').first
50
+ end
51
+
52
+ def cidr(ip)
53
+ ip.split('/').last.to_i
45
54
  end
46
55
 
47
- # Returns the IP with the CIDR notation stripped away
48
- def clean_ip
49
- self.ip.split('/').first
56
+ def octets(ip)
57
+ ip.split('.')
50
58
  end
51
59
 
52
- # Returns the entry from the CIDR_MATRIX constant based on our CIDR
53
- def cidr_matrix
54
- CIDR_MATRIX[self.cidr]
60
+ def cidr_matrix(cidr)
61
+ CIDR_MATRIX[cidr.to_i]
55
62
  end
56
63
 
57
- # Returns the network mask
58
- def netmask
59
- cidr_matrix[:netmask]
64
+ def netmask(ip)
65
+ ip, cidr = ip.split('/')
66
+ cidr_matrix(cidr)[:netmask]
60
67
  end
61
68
 
62
69
  # Returns the network address
63
- def network
64
- cidr_matrix[:network] % clean_ip.split('.')
70
+ def network(ip)
71
+ ip, cidr = ip.split('/')
72
+ cidr_matrix(cidr)[:network] % ip.split('.')
65
73
  end
66
74
 
67
75
  # Returns the broadcast address
68
- def broadcast
69
- cidr_matrix[:broadcast] % clean_ip.split('.')
76
+ def broadcast(ip)
77
+ ip, cidr = ip.split('/')
78
+ cidr_matrix(cidr)[:broadcast] % ip.split('.')
70
79
  end
71
80
 
72
- def cidr_octets(fill=nil)
73
- octets = self.clean_ip.split('.')
81
+ def cidr_octets(ip, fill=nil)
82
+ ip, cidr = ip.split('/')
83
+ oct = octets(ip)
74
84
 
75
- result = case self.cidr
85
+ result = case cidr.to_i
76
86
  when 0..7 then
77
- octets[-4,4]
87
+ oct[-4,4]
78
88
  when 8..15 then
79
- [octets[-3,3], fill]
89
+ [fill, oct[-3,3]]
80
90
  when 16..23 then
81
- [octets[-2,2], fill, fill]
91
+ [fill, fill, oct[-2,2]]
82
92
  when 24..31 then
83
- [octets[-1,1], fill, fill, fill]
93
+ [fill, fill, fill, oct[-1,1]]
84
94
  end
85
95
 
86
96
  result.flatten.compact
87
97
  end
88
98
 
89
- def ptr
90
- cidr_octets.reverse.join('.')
99
+ def arpa_octets(ip, fill=nil)
100
+ ip, cidr = ip.split('/')
101
+ oct = octets(ip)
102
+
103
+ result = case cidr.to_i
104
+ when 0..7 then
105
+ [fill, fill, fill, fill]
106
+ when 8..15 then
107
+ [oct[0,1], fill, fill, fill]
108
+ when 16..23 then
109
+ [oct[0,2], fill, fill]
110
+ when 24..31 then
111
+ [oct[0,3], fill]
112
+ end
113
+
114
+ result.flatten.compact.reverse
115
+ end
116
+
117
+ def ptr(ip)
118
+ cidr_octets(ip).reverse.join('.')
91
119
  end
92
120
 
93
- # Returns the ARPA address
94
- def arpa
95
- result = self.network.split('.').delete_if{ |ip| ip == '0' }.reverse.join('.')
96
- "#{result}.in-addr.arpa"
121
+ def arpa(ip)
122
+ [arpa_octets(ip), 'in-addr', 'arpa'].flatten.join('.')
97
123
  end
98
124
 
99
125
  end
@@ -0,0 +1,16 @@
1
+ class TestLab
2
+
3
+ # Utility Error Class
4
+ class UtilityError < TestLabError; end
5
+
6
+ # Utility Module
7
+ #
8
+ # @author Zachary Patten <zachary@jovelabs.net>
9
+ module Utility
10
+ autoload :CIDR, 'testlab/utility/cidr'
11
+
12
+ extend TestLab::Utility::CIDR
13
+
14
+ end
15
+
16
+ end
@@ -1,6 +1,6 @@
1
1
  class TestLab
2
2
  unless const_defined?(:VERSION)
3
3
  # TestLab Gem Version
4
- VERSION = "0.0.4"
4
+ VERSION = "0.1.0"
5
5
  end
6
6
  end
data/lib/testlab.rb CHANGED
@@ -10,15 +10,15 @@ class TestLab
10
10
  # Top-Level Error Class
11
11
  class TestLabError < StandardError; end
12
12
 
13
- autoload :Provider, 'testlab/provider'
13
+ # Main Classes
14
+ autoload :Container, 'testlab/container'
15
+ autoload :Labfile, 'testlab/labfile'
16
+ autoload :Network, 'testlab/network'
17
+ autoload :Node, 'testlab/node'
18
+ autoload :Provider, 'testlab/provider'
14
19
  autoload :Provisioner, 'testlab/provisioner'
15
-
16
- autoload :Labfile, 'testlab/labfile'
17
- autoload :Node, 'testlab/node'
18
- autoload :Router, 'testlab/router'
19
- autoload :Container, 'testlab/container'
20
- autoload :Network, 'testlab/network'
21
- autoload :Link, 'testlab/link'
20
+ autoload :Router, 'testlab/router'
21
+ autoload :Utility, 'testlab/utility'
22
22
 
23
23
  @@ui ||= nil
24
24
 
@@ -63,17 +63,17 @@ class TestLab
63
63
  if alive?
64
64
  @@ui.stdout.puts("NODES:")
65
65
  ZTK::Report.new(:ui => @@ui).spreadsheet(TestLab::Node.all, TestLab::Node::STATUS_KEYS) do |node|
66
- OpenStruct.new(node.status.merge(:id => node.id))
66
+ OpenStruct.new(node.status)
67
67
  end
68
68
  @@ui.stdout.puts
69
69
  @@ui.stdout.puts("NETWORKS:")
70
70
  ZTK::Report.new(:ui => @@ui).spreadsheet(TestLab::Network.all, TestLab::Network::STATUS_KEYS) do |network|
71
- OpenStruct.new(network.status.merge(:id => network.id))
71
+ OpenStruct.new(network.status)
72
72
  end
73
73
  @@ui.stdout.puts
74
74
  @@ui.stdout.puts("CONTAINERS:")
75
75
  ZTK::Report.new(:ui => @@ui).spreadsheet(TestLab::Container.all, TestLab::Container::STATUS_KEYS) do |container|
76
- OpenStruct.new(container.status.merge(:id => container.id))
76
+ OpenStruct.new(container.status)
77
77
  end
78
78
 
79
79
  true
data/spec/support/Labfile CHANGED
@@ -18,7 +18,7 @@ node :localhost do
18
18
  ]
19
19
 
20
20
  network :testnet do
21
- cidr "192.168.255.254/16"
21
+ ip "192.168.255.254/16"
22
22
  bridge :br0
23
23
  end
24
24
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testlab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -161,26 +161,30 @@ files:
161
161
  - lib/testlab.rb
162
162
  - lib/testlab/container.rb
163
163
  - lib/testlab/container/actions.rb
164
+ - lib/testlab/container/class_methods.rb
164
165
  - lib/testlab/container/generators.rb
166
+ - lib/testlab/container/interface.rb
165
167
  - lib/testlab/container/lifecycle.rb
166
168
  - lib/testlab/container/lxc.rb
167
- - lib/testlab/container/network.rb
169
+ - lib/testlab/container/method_missing.rb
168
170
  - lib/testlab/container/status.rb
169
171
  - lib/testlab/labfile.rb
170
172
  - lib/testlab/network.rb
171
173
  - lib/testlab/network/actions.rb
172
- - lib/testlab/network/cidr.rb
174
+ - lib/testlab/network/bind.rb
175
+ - lib/testlab/network/class_methods.rb
173
176
  - lib/testlab/network/lifecycle.rb
174
177
  - lib/testlab/network/status.rb
175
178
  - lib/testlab/node.rb
176
179
  - lib/testlab/node/bind.rb
180
+ - lib/testlab/node/class_methods.rb
177
181
  - lib/testlab/node/lifecycle.rb
178
182
  - lib/testlab/node/lxc.rb
183
+ - lib/testlab/node/method_missing.rb
179
184
  - lib/testlab/node/resolv.rb
180
185
  - lib/testlab/node/ssh.rb
181
186
  - lib/testlab/node/status.rb
182
187
  - lib/testlab/node/templates/bind-db.erb
183
- - lib/testlab/node/templates/bind-setup.erb
184
188
  - lib/testlab/node/templates/bind-zone.erb
185
189
  - lib/testlab/node/templates/bind.erb
186
190
  - lib/testlab/node/templates/node-setup.erb
@@ -195,6 +199,8 @@ files:
195
199
  - lib/testlab/provisioners/shell.rb
196
200
  - lib/testlab/provisioners/templates/chef/bootstrap.erb
197
201
  - lib/testlab/router.rb
202
+ - lib/testlab/utility.rb
203
+ - lib/testlab/utility/cidr.rb
198
204
  - lib/testlab/version.rb
199
205
  - spec/provider_spec.rb
200
206
  - spec/provisioner_spec.rb
@@ -217,7 +223,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
217
223
  version: '0'
218
224
  segments:
219
225
  - 0
220
- hash: -3944268925164045043
226
+ hash: 4469350422868766283
221
227
  required_rubygems_version: !ruby/object:Gem::Requirement
222
228
  none: false
223
229
  requirements:
@@ -226,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
232
  version: '0'
227
233
  segments:
228
234
  - 0
229
- hash: -3944268925164045043
235
+ hash: 4469350422868766283
230
236
  requirements: []
231
237
  rubyforge_project:
232
238
  rubygems_version: 1.8.25
@@ -1,31 +0,0 @@
1
- class TestLab
2
- class Container
3
-
4
- module Network
5
-
6
- # Builds an array of hashes containing the lxc configuration options for
7
- # our networks
8
- def build_lxc_network_conf(interfaces)
9
- networks = Array.new
10
-
11
- interfaces.each do |network, network_config|
12
- networks << Hash[
13
- 'lxc.network.type' => :veth,
14
- 'lxc.network.flags' => :up,
15
- 'lxc.network.link' => TestLab::Network.first(network).bridge,
16
- 'lxc.network.name' => network_config[:name],
17
- 'lxc.network.hwaddr' => network_config[:mac],
18
- 'lxc.network.ipv4' => network_config[:ip]
19
- ]
20
- if (network_config[:primary] == true) || (interfaces.count == 1)
21
- networks.last.merge!('lxc.network.ipv4.gateway' => :auto)
22
- end
23
- end
24
-
25
- networks
26
- end
27
-
28
- end
29
-
30
- end
31
- end
@@ -1,6 +0,0 @@
1
- set -x
2
-
3
- apt-get -y install bind9
4
- service bind9 restart || service bind9 start
5
-
6
- exit 0