testlab 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 -%>