testlab 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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