testlab 0.0.3 → 0.0.4

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.
@@ -0,0 +1,30 @@
1
+ class TestLab
2
+ class Network
3
+
4
+ module Status
5
+
6
+ # Network status
7
+ def status
8
+ interface = "#{bridge}:#{ip}"
9
+ {
10
+ :id => self.id,
11
+ :node_id => self.node.id,
12
+ :state => self.state,
13
+ :interface => interface
14
+ }
15
+ end
16
+
17
+ # Network Bridge State
18
+ def state
19
+ output = self.node.ssh.exec(%(sudo ifconfig #{self.bridge} | grep 'MTU'), :silence => true, :ignore_exit_status => true).output.strip
20
+ if ((output =~ /UP/) && (output =~ /RUNNING/))
21
+ :running
22
+ else
23
+ :stopped
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -13,115 +13,25 @@ class TestLab
13
13
 
14
14
  attribute :bridge
15
15
 
16
- attribute :cidr
16
+ attribute :ip
17
17
  attribute :config
18
18
 
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
+
19
29
  def initialize(*args)
20
30
  super(*args)
21
31
 
22
32
  @ui = TestLab.ui
23
33
  end
24
34
 
25
- # Network status
26
- def status
27
- interface = "#{bridge}:#{cidr}"
28
- {
29
- :id => self.id,
30
- :node_id => self.node.id,
31
- :state => self.state,
32
- :interface => interface
33
- }
34
- end
35
-
36
- ################################################################################
37
-
38
- # Create the network
39
- def create
40
- @ui.logger.debug { "Network Create: #{self.id} " }
41
-
42
- self.node.ssh.exec(%(sudo brctl addbr #{self.bridge}), :silence => true, :ignore_exit_status => true)
43
- self.node.ssh.exec(%(sudo ifconfig #{self.bridge} #{self.cidr} down), :silence => true, :ignore_exit_status => true)
44
- end
45
-
46
- # Destroy the network
47
- def destroy
48
- @ui.logger.debug { "Network Destroy: #{self.id} " }
49
-
50
- self.node.ssh.exec(%(sudo brctl delbr #{self.bridge}), :silence => true, :ignore_exit_status => true)
51
- end
52
-
53
- # Start the network
54
- def up
55
- @ui.logger.debug { "Network Up: #{self.id} " }
56
-
57
- self.node.ssh.exec(%(sudo ifconfig #{self.bridge} up), :silence => true, :ignore_exit_status => true)
58
- end
59
-
60
- # Stop the network
61
- def down
62
- @ui.logger.debug { "Network Down: #{self.id} " }
63
-
64
- self.node.ssh.exec(%(sudo ifconfig #{self.bridge} down), :silence => true, :ignore_exit_status => true)
65
- end
66
-
67
- ################################################################################
68
-
69
- # Reload the network
70
- def reload
71
- @ui.logger.debug { "Network Reload: #{self.id} " }
72
-
73
- self.down
74
- self.up
75
- end
76
-
77
- ################################################################################
78
-
79
- # State of the network
80
- def state
81
- output = self.node.ssh.exec(%(sudo ifconfig #{self.bridge} | grep 'MTU'), :silence => true, :ignore_exit_status => true).output.strip
82
- if ((output =~ /UP/) && (output =~ /RUNNING/))
83
- :running
84
- else
85
- :stopped
86
- end
87
- end
88
-
89
- ################################################################################
90
-
91
- # Network Callback: after_create
92
- def after_create
93
- @ui.logger.debug { "Network Callback: After Create: #{self.id} " }
94
- end
95
-
96
- # Network Callback: after_up
97
- def after_up
98
- @ui.logger.debug { "Network Callback: After Up: #{self.id} " }
99
-
100
- self.create
101
- self.up
102
- end
103
-
104
- # Network Callback: before_down
105
- def before_down
106
- @ui.logger.debug { "Network Callback: Before Down: #{self.id} " }
107
-
108
- self.down
109
- self.destroy
110
- end
111
-
112
- # Network Callback: before_destroy
113
- def before_destroy
114
- @ui.logger.debug { "Network Callback: Before Destroy: #{self.id} " }
115
- end
116
-
117
- ################################################################################
118
-
119
- # Method missing handler
120
- def method_missing(method_name, *method_args)
121
- @ui.logger.debug { "NETWORK METHOD MISSING: #{method_name.inspect}(#{method_args.inspect})" }
122
- super(method_name, *method_args)
123
- end
124
-
125
35
  end
126
36
 
127
37
  end
@@ -0,0 +1,95 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module Bind
5
+ require 'tempfile'
6
+
7
+ # Builds the main bind configuration sections
8
+ def build_bind_main_partial(file)
9
+ bind_conf_template = File.join(self.class.template_dir, "bind.erb")
10
+
11
+ file.puts(ZTK::Template.do_not_edit_notice(:message => "TestLab v#{TestLab::VERSION} BIND Configuration", :char => '//'))
12
+ file.puts(ZTK::Template.render(bind_conf_template, {}))
13
+ end
14
+
15
+ def build_bind_records
16
+ forward_records = Hash.new
17
+ reverse_records = Hash.new
18
+
19
+ TestLab::Container.all.each do |container|
20
+ interface = container.primary_interface
21
+ domain = (container.domain || container.node.labfile.config[:domain])
22
+
23
+ forward_records[domain] ||= Array.new
24
+ forward_records[domain] << %(#{container.id} IN A #{container.ip})
25
+
26
+ reverse_records[interface.first] ||= Array.new
27
+ reverse_records[interface.first] << %(#{container.ptr} IN PTR #{container.id}.#{domain}.)
28
+ end
29
+ { :forward => forward_records, :reverse => reverse_records }
30
+ end
31
+
32
+ # Builds the bind configuration sections for our zones
33
+ def build_bind_zone_partial(file)
34
+ bind_zone_template = File.join(self.class.template_dir, 'bind-zone.erb')
35
+
36
+ bind_records = build_bind_records
37
+ forward_records = bind_records[:forward]
38
+ reverse_records = bind_records[:reverse]
39
+
40
+ TestLab::Network.all.each do |network|
41
+ context = {
42
+ :zone => network.arpa
43
+ }
44
+
45
+ file.puts
46
+ file.puts(ZTK::Template.render(bind_zone_template, context))
47
+
48
+ build_bind_db(network.arpa, reverse_records[network.id])
49
+ end
50
+
51
+ domains = ([self.labfile.config[:domain]] + TestLab::Container.domains).flatten
52
+ domains.each do |domain|
53
+ context = {
54
+ :zone => domain
55
+ }
56
+
57
+ file.puts
58
+ file.puts(ZTK::Template.render(bind_zone_template, context))
59
+
60
+ build_bind_db(domain, forward_records[domain])
61
+ end
62
+ end
63
+
64
+ def build_bind_db(zone, records)
65
+ bind_db_template = File.join(self.class.template_dir, 'bind-db.erb')
66
+
67
+ self.ssh.file(:target => "/etc/bind/db.#{zone}", :chown => "bind:bind") do |file|
68
+ file.puts(ZTK::Template.do_not_edit_notice(:message => "TestLab v#{TestLab::VERSION} BIND DB: #{zone}", :char => ';'))
69
+ file.puts(ZTK::Template.render(bind_db_template, { :zone => zone, :records => records }))
70
+ end
71
+
72
+ # self.ssh.exec(%(sudo rm -fv /etc/bind/db.#{zone}.jnl))
73
+ end
74
+
75
+ # Builds the BIND configuration
76
+ def build_bind_conf
77
+ self.ssh.file(:target => File.join("/etc/bind/named.conf"), :chown => "bind:bind") do |file|
78
+ build_bind_main_partial(file)
79
+ build_bind_zone_partial(file)
80
+ end
81
+ end
82
+
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))
86
+
87
+ build_bind_conf
88
+
89
+ self.ssh.exec(%(sudo /bin/bash -c 'service bind9 restart || service bind9 start'))
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,43 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module Lifecycle
5
+
6
+ # Bootstrap the node
7
+ def node_setup
8
+ node_setup_template = File.join(self.class.template_dir, 'node-setup.erb')
9
+ self.ssh.bootstrap(ZTK::Template.render(node_setup_template))
10
+ end
11
+
12
+ # Setup the node.
13
+ def setup
14
+ @ui.logger.debug { "Node Setup: #{self.id} " }
15
+
16
+ node_setup
17
+
18
+ if self.components.include?('resolv')
19
+ build_resolv_conf
20
+ end
21
+
22
+ if self.components.include?('bind')
23
+ bind_setup
24
+ end
25
+
26
+ call_collections([self.networks, self.routers, self.containers], :setup)
27
+
28
+ true
29
+ end
30
+
31
+ # Teardown the node.
32
+ def teardown
33
+ @ui.logger.debug { "Node Teardown: #{self.id} " }
34
+
35
+ call_collections([self.containers, self.routers, self.networks], :teardown)
36
+
37
+ true
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module LXC
5
+ require 'lxc'
6
+
7
+ # Returns the LXC object for this Node
8
+ #
9
+ # This object is used to control containers on the node via it's provider
10
+ #
11
+ # @return [LXC] An instance of LXC configured for this node.
12
+ def lxc(options={})
13
+ if (!defined?(@lxc) || @lxc.nil?)
14
+ @lxc ||= ::LXC.new
15
+ @lxc.use_sudo = true
16
+ @lxc.use_ssh = self.ssh
17
+ end
18
+ @lxc
19
+ end
20
+
21
+ # Returns the machine type of the node.
22
+ #
23
+ # @return [String] The output of 'uname -m'.
24
+ def arch
25
+ @arch ||= self.ssh.exec(%(uname -m)).output.strip
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module Resolv
5
+ require 'tempfile'
6
+
7
+ # Builds the main resolv configuration sections
8
+ def build_resolv_main_conf(file)
9
+ resolv_conf_template = File.join(self.class.template_dir, "resolv.erb")
10
+
11
+ domains = ([self.labfile.config[:domain]] + TestLab::Container.domains).flatten
12
+ context = {
13
+ :servers => [TestLab::Network.all.map(&:clean_ip), "8.8.8.8", "8.8.4.4" ].flatten,
14
+ :search => domains.join(' ')
15
+ }
16
+
17
+ file.puts(ZTK::Template.do_not_edit_notice(:message => "TestLab v#{TestLab::VERSION} RESOLVER Configuration"))
18
+ file.puts(ZTK::Template.render(resolv_conf_template, context))
19
+ end
20
+
21
+ def build_resolv_conf
22
+ self.ssh.file(:target => File.join("/etc/resolv.conf"), :chown => "root:root") do |file|
23
+ build_resolv_main_conf(file)
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module SSH
5
+
6
+ # SSH to the Node
7
+ def ssh(options={})
8
+ if (!defined?(@ssh) || @ssh.nil?)
9
+ @ssh ||= ZTK::SSH.new({:ui => @ui, :timeout => 1200, :silence => true}.merge(options))
10
+ @ssh.config do |c|
11
+ c.host_name = @provider.ip
12
+ c.port = @provider.port
13
+ c.user = @provider.user
14
+ c.keys = @provider.identity
15
+ end
16
+ end
17
+ @ssh
18
+ end
19
+
20
+ # SSH to a container running on the Node
21
+ def container_ssh(container, options={})
22
+ name = container.id
23
+ @container_ssh ||= Hash.new
24
+ if @container_ssh[name].nil?
25
+ @container_ssh[name] ||= ZTK::SSH.new({:ui => @ui, :timeout => 1200, :silence => true}.merge(options))
26
+ @container_ssh[name].config do |c|
27
+ c.proxy_host_name = @provider.ip
28
+ c.proxy_port = @provider.port
29
+ c.proxy_user = @provider.user
30
+ c.proxy_keys = @provider.identity
31
+
32
+ c.host_name = container.ip
33
+ c.user = (container.user || "ubuntu")
34
+ c.keys = container.keys
35
+ end
36
+ end
37
+ @container_ssh[name]
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,26 @@
1
+ class TestLab
2
+ class Node
3
+
4
+ module Status
5
+
6
+ # Node Status
7
+ #
8
+ # @return [Hash] A hash detailing the status of the node.
9
+ def status
10
+ {
11
+ :instance_id => @provider.instance_id,
12
+ :state => @provider.state,
13
+ :user => @provider.user,
14
+ :ip => @provider.ip,
15
+ :port => @provider.port,
16
+ :provider => @provider.class,
17
+ :con => self.containers.count,
18
+ :net => self.networks.count,
19
+ :rtr => self.routers.count
20
+ }
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ $TTL 1d
2
+ @ IN SOA localhost. root.localhost. (
3
+ 0 ; Serial
4
+ 1w ; Refresh
5
+ 1d ; Retry
6
+ 4w ; Expire
7
+ 1d ) ; Negative Cache TTL
8
+ ;
9
+ @ IN NS localhost.
10
+ <% @records.each do |record| -%>
11
+ <%= record %>
12
+ <% end -%>
@@ -0,0 +1,6 @@
1
+ set -x
2
+
3
+ apt-get -y install bind9
4
+ service bind9 restart || service bind9 start
5
+
6
+ exit 0
@@ -0,0 +1,4 @@
1
+ zone "<%= @zone %>" {
2
+ type master;
3
+ file "/etc/bind/db.<%= @zone %>";
4
+ };
@@ -0,0 +1,60 @@
1
+ options {
2
+ directory "/var/cache/bind";
3
+
4
+ // If there is a firewall between you and nameservers you want
5
+ // to talk to, you may need to fix the firewall to allow multiple
6
+ // ports to talk. See http://www.kb.cert.org/vuls/id/800113
7
+
8
+ // If your ISP provided one or more IP addresses for stable
9
+ // nameservers, you probably want to use them as forwarders.
10
+ // Uncomment the following block, and insert the addresses replacing
11
+ // the all-0's placeholder.
12
+
13
+ // forwarders {
14
+ // 0.0.0.0;
15
+ // };
16
+
17
+ //========================================================================
18
+ // If BIND logs error messages about the root key being expired,
19
+ // you will need to update your keys. See https://www.isc.org/bind-keys
20
+ //========================================================================
21
+ dnssec-validation auto;
22
+
23
+ auth-nxdomain no; # conform to RFC1035
24
+ listen-on-v6 { any; };
25
+ };
26
+
27
+ include "/etc/bind/rndc.key";
28
+
29
+ controls {
30
+ inet 127.0.0.1 allow { 127.0.0.1; } keys { "rndc-key"; };
31
+ };
32
+
33
+ // prime the server with knowledge of the root servers
34
+ zone "." {
35
+ type hint;
36
+ file "/etc/bind/db.root";
37
+ };
38
+
39
+ // be authoritative for the localhost forward and reverse zones, and for
40
+ // broadcast zones as per RFC 1912
41
+
42
+ zone "localhost" {
43
+ type master;
44
+ file "/etc/bind/db.local";
45
+ };
46
+
47
+ zone "127.in-addr.arpa" {
48
+ type master;
49
+ file "/etc/bind/db.127";
50
+ };
51
+
52
+ zone "0.in-addr.arpa" {
53
+ type master;
54
+ file "/etc/bind/db.0";
55
+ };
56
+
57
+ zone "255.in-addr.arpa" {
58
+ type master;
59
+ file "/etc/bind/db.255";
60
+ };
@@ -0,0 +1,18 @@
1
+ set -x
2
+
3
+ # Update APT and ensure our required packages are installed
4
+ apt-get -y update
5
+ apt-get -y install lxc bridge-utils debootstrap yum iptables ntpdate ntp
6
+
7
+ # Ensure the default lxc networking services are off
8
+ service lxc-net stop
9
+
10
+ # Ensure NTP services are enabled and running
11
+ service ntp restart || service ntp start
12
+
13
+ # Enable ipv4 forwarding
14
+ sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1" || sysctl -w net.ipv4.ip_forward=1
15
+
16
+ # Install an iptable NAT rule
17
+ iptables -t nat --list -v | grep "MASQUERADE all -- any eth0 anywhere anywhere" || iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
18
+
@@ -0,0 +1,4 @@
1
+ search <%= @search %>
2
+ <% @servers.each do |server| -%>
3
+ nameserver <%= server %>
4
+ <% end -%>