dev-lxc 0.1.2
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/README.md +275 -0
- data/Rakefile +1 -0
- data/bin/dev-lxc +6 -0
- data/dev-lxc.gemspec +25 -0
- data/files/configs/ha.yaml +31 -0
- data/files/configs/open-source.yaml +10 -0
- data/files/configs/standalone.yaml +13 -0
- data/files/configs/tier.yaml +21 -0
- data/files/create_users/create_users.rb +53 -0
- data/files/create_users/default.rb +261 -0
- data/files/create_users/knife.rb.erb +15 -0
- data/lib/dev-lxc/chef-cluster.rb +127 -0
- data/lib/dev-lxc/chef-server.rb +234 -0
- data/lib/dev-lxc/cli.rb +137 -0
- data/lib/dev-lxc/container.rb +62 -0
- data/lib/dev-lxc/version.rb +3 -0
- data/lib/dev-lxc.rb +79 -0
- metadata +132 -0
data/lib/dev-lxc/cli.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require 'dev-lxc'
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module DevLXC::CLI
|
6
|
+
class Cluster < Thor
|
7
|
+
no_commands{
|
8
|
+
def get_cluster(config_option)
|
9
|
+
config = "dev-lxc.yaml" if File.exists?("dev-lxc.yaml")
|
10
|
+
config = config_option unless config_option.nil?
|
11
|
+
raise "A cluster config file must be provided" if config.nil?
|
12
|
+
::DevLXC::ChefCluster.new(YAML.load(IO.read(config)))
|
13
|
+
end
|
14
|
+
}
|
15
|
+
|
16
|
+
desc "init [TOPOLOGY]", "Provide a cluster config file"
|
17
|
+
def init(topology=nil)
|
18
|
+
topologies = %w(open-source standalone tier)
|
19
|
+
if topology.nil? || ! topologies.include?(topology)
|
20
|
+
topologies_with_index = topologies.map.with_index{ |a, i| [i+1, *a]}
|
21
|
+
print_table topologies_with_index
|
22
|
+
selection = ask("Which cluster topology do you want to use?", :limited_to => topologies_with_index.map{|c| c[0].to_s})
|
23
|
+
topology = topologies[selection.to_i - 1]
|
24
|
+
end
|
25
|
+
puts IO.read("#{File.dirname(__FILE__)}/../../files/configs/#{topology}.yaml")
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "status", "Show status of a cluster's Chef servers"
|
29
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
30
|
+
def status
|
31
|
+
get_cluster(options[:config]).status
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "abspath [ROOTFS_PATH]", "Returns the absolute path to a file for each Chef server in a cluster"
|
35
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
36
|
+
def abspath(rootfs_path)
|
37
|
+
puts get_cluster(options[:config]).abspath(rootfs_path).join(" ")
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "run_command [COMMAND]", "Runs a command in each Chef server in a cluster"
|
41
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
42
|
+
def run_command(command)
|
43
|
+
get_cluster(options[:config]).run_command(command)
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "start", "Start a cluster's Chef servers"
|
47
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
48
|
+
def start
|
49
|
+
get_cluster(options[:config]).start
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "stop", "Stop a cluster's Chef servers"
|
53
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
54
|
+
def stop
|
55
|
+
get_cluster(options[:config]).stop
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "destroy", "Destroy a cluster's Chef servers"
|
59
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
60
|
+
option :base, :aliases => "-b", :type => :boolean, :desc => "Destroy the cluster's base containers also"
|
61
|
+
def destroy
|
62
|
+
cluster = get_cluster(options[:config])
|
63
|
+
cluster.destroy
|
64
|
+
cluster.destroy_base_containers if options[:base]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Server < Thor
|
69
|
+
no_commands{
|
70
|
+
def get_server(name, config_option)
|
71
|
+
config = "dev-lxc.yaml" if File.exists?("dev-lxc.yaml")
|
72
|
+
config = config_option unless config_option.nil?
|
73
|
+
raise "A cluster config file must be provided" if config.nil?
|
74
|
+
::DevLXC::ChefServer.new(name, YAML.load(IO.read(config)))
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
desc "status [NAME]", "Show status of a cluster's Chef server"
|
79
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
80
|
+
def status(name)
|
81
|
+
get_server(name, options[:config]).status
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "abspath [NAME] [ROOTFS_PATH]", "Returns the absolute path to a file in a cluster's Chef server"
|
85
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
86
|
+
def abspath(name, rootfs_path)
|
87
|
+
puts get_server(name, options[:config]).abspath(rootfs_path)
|
88
|
+
end
|
89
|
+
|
90
|
+
desc "run_command [NAME] [COMMAND]", "Runs a command in a cluster's Chef server"
|
91
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
92
|
+
def run_command(name, command)
|
93
|
+
get_server(name, options[:config]).run_command(command)
|
94
|
+
end
|
95
|
+
|
96
|
+
desc "start [NAME]", "Start a cluster's Chef server"
|
97
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
98
|
+
def start(name)
|
99
|
+
get_server(name, options[:config]).start
|
100
|
+
end
|
101
|
+
|
102
|
+
desc "stop [NAME]", "Stop a cluster's Chef server"
|
103
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
104
|
+
def stop(name)
|
105
|
+
get_server(name, options[:config]).stop
|
106
|
+
end
|
107
|
+
|
108
|
+
desc "destroy [NAME]", "Destroy a cluster's Chef server"
|
109
|
+
option :config, :aliases => "-c", :desc => "Specify a cluster's YAML config file. ./dev-lxc.yaml will be used by default"
|
110
|
+
option :base, :aliases => "-b", :type => :boolean, :desc => "Destroy the server's base containers also"
|
111
|
+
def destroy(name)
|
112
|
+
server = get_server(name, options[:config])
|
113
|
+
server.destroy
|
114
|
+
server.destroy_base_containers if options[:base]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class DevLXC < Thor
|
119
|
+
desc "create [BASE_PLATFORM]", "Create a base platform"
|
120
|
+
def create(base_platform=nil)
|
121
|
+
base_platforms = %w(b-ubuntu-1004 b-ubuntu-1204 b-centos-5 b-centos-6)
|
122
|
+
if base_platform.nil? || ! base_platforms.include?(base_platform)
|
123
|
+
base_platforms_with_index = base_platforms.map.with_index{ |a, i| [i+1, *a]}
|
124
|
+
print_table base_platforms_with_index
|
125
|
+
selection = ask("Which base platform do you want to create?", :limited_to => base_platforms_with_index.map{|c| c[0].to_s})
|
126
|
+
base_platform = base_platforms[selection.to_i - 1]
|
127
|
+
end
|
128
|
+
::DevLXC.create_base_platform(base_platform)
|
129
|
+
end
|
130
|
+
|
131
|
+
desc "cluster SUBCOMMAND ...ARGS", "manage Chef cluster"
|
132
|
+
subcommand "cluster", Cluster
|
133
|
+
|
134
|
+
desc "server SUBCOMMAND ...ARGS", "manage Chef server"
|
135
|
+
subcommand "server", Server
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module DevLXC
|
2
|
+
class Container < LXC::Container
|
3
|
+
def start
|
4
|
+
raise "Container #{self.name} does not exist." unless self.defined?
|
5
|
+
puts "Starting container #{self.name}"
|
6
|
+
super
|
7
|
+
wait(:running, 3)
|
8
|
+
puts "Waiting for #{self.name} container's network"
|
9
|
+
ips = nil
|
10
|
+
30.times do
|
11
|
+
ips = self.ip_addresses
|
12
|
+
break unless ips.empty?
|
13
|
+
sleep 1
|
14
|
+
end
|
15
|
+
raise "Container #{self.name} network is not available." if ips.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop
|
19
|
+
puts "Stopping container #{self.name}"
|
20
|
+
super
|
21
|
+
wait("STOPPED", 3)
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
return unless self.defined?
|
26
|
+
stop if running?
|
27
|
+
puts "Destroying container #{self.name}"
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def sync_mounts(mounts)
|
32
|
+
preserved_mounts = self.config_item("lxc.mount.entry").delete_if { |m| m.end_with?("## dev-lxc ##") }
|
33
|
+
self.clear_config_item('lxc.mount.entries')
|
34
|
+
self.set_config_item("lxc.mount.entry", preserved_mounts)
|
35
|
+
mounts.each do |mount|
|
36
|
+
raise "Mount source #{mount.split.first} does not exist." unless File.exists?(mount.split.first)
|
37
|
+
puts "Adding mount entry #{mount}"
|
38
|
+
self.set_config_item("lxc.mount.entry", "#{mount} none bind,optional,create=dir 0 0 ## dev-lxc ##")
|
39
|
+
end
|
40
|
+
self.save_config
|
41
|
+
end
|
42
|
+
|
43
|
+
def run_command(command)
|
44
|
+
raise "Container #{self.name} must be running first" unless running?
|
45
|
+
attach({:wait => true, :stdin => STDIN, :stdout => STDOUT, :stderr => STDERR}) do
|
46
|
+
LXC.run_command(command)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def install_package(package_path)
|
51
|
+
raise "File #{package_path} does not exist in container #{self.name}" unless run_command("test -e #{package_path}")
|
52
|
+
puts "Installing #{package_path} in container #{self.name}"
|
53
|
+
case File.extname(package_path)
|
54
|
+
when ".deb"
|
55
|
+
install_command = "dpkg -D10 -i #{package_path}"
|
56
|
+
when ".rpm"
|
57
|
+
install_command = "rpm -Uvh #{package_path}"
|
58
|
+
end
|
59
|
+
run_command(install_command)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/dev-lxc.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "digest/sha1"
|
3
|
+
require "lxc"
|
4
|
+
require "dev-lxc/container"
|
5
|
+
require "dev-lxc/chef-server"
|
6
|
+
require "dev-lxc/chef-cluster"
|
7
|
+
|
8
|
+
module DevLXC
|
9
|
+
def self.create_base_platform(base_platform_name)
|
10
|
+
base_platform = DevLXC::Container.new(base_platform_name)
|
11
|
+
if base_platform.defined?
|
12
|
+
puts "Using existing container #{base_platform.name}"
|
13
|
+
return base_platform
|
14
|
+
end
|
15
|
+
puts "Creating container #{base_platform.name}"
|
16
|
+
case base_platform.name
|
17
|
+
when "b-ubuntu-1004"
|
18
|
+
base_platform.create("download", "btrfs", 0, ["-d", "ubuntu", "-r", "lucid", "-a", "amd64"])
|
19
|
+
when "b-ubuntu-1204"
|
20
|
+
base_platform.create("download", "btrfs", 0, ["-d", "ubuntu", "-r", "precise", "-a", "amd64"])
|
21
|
+
when "b-centos-5"
|
22
|
+
base_platform.create("centos", "btrfs", 0, ["-R", "5"])
|
23
|
+
when "b-centos-6"
|
24
|
+
base_platform.create("download", "btrfs", 0, ["-d", "centos", "-r", "6", "-a", "amd64"])
|
25
|
+
end
|
26
|
+
hwaddr = '00:16:3e:' + Digest::SHA1.hexdigest(Time.now.to_s).slice(0..5).unpack('a2a2a2').join(':')
|
27
|
+
puts "Setting #{base_platform.name} container's lxc.network.0.hwaddr to #{hwaddr}"
|
28
|
+
base_platform.set_config_item("lxc.network.0.hwaddr", hwaddr)
|
29
|
+
base_platform.save_config
|
30
|
+
base_platform.start
|
31
|
+
puts "Installing packages in container #{base_platform.name}"
|
32
|
+
case base_platform.name
|
33
|
+
when "b-ubuntu-1004"
|
34
|
+
base_platform.run_command("apt-get update")
|
35
|
+
base_platform.run_command("apt-get install -y standard^ server^ vim-nox emacs23-nox curl tree")
|
36
|
+
when "b-ubuntu-1204"
|
37
|
+
base_platform.run_command("apt-get update")
|
38
|
+
base_platform.run_command("apt-get install -y standard^ server^ vim-nox emacs23-nox tree")
|
39
|
+
when "b-centos-5", "b-centos-6"
|
40
|
+
base_platform.run_command("yum install -y @base @core vim-enhanced emacs-nox tree")
|
41
|
+
end
|
42
|
+
base_platform.stop
|
43
|
+
return base_platform
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.assign_ip_address(ipaddress, container_name, hwaddr)
|
47
|
+
puts "Assigning IP address #{ipaddress} to #{container_name} container's lxc.network.hwaddr #{hwaddr}"
|
48
|
+
search_file_delete_line("/etc/lxc/dhcp-hosts.conf", /(^#{hwaddr}|,#{ipaddress}$)/)
|
49
|
+
append_line_to_file("/etc/lxc/dhcp-hosts.conf", "#{hwaddr},#{ipaddress}\n")
|
50
|
+
reload_dnsmasq
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.create_dns_record(api_fqdn, container_name, ipaddress)
|
54
|
+
dns_record = "#{ipaddress} #{container_name} #{api_fqdn}\n"
|
55
|
+
puts "Creating DNS record: #{dns_record}"
|
56
|
+
search_file_delete_line("/etc/lxc/addn-hosts.conf", /^#{ipaddress}\s/)
|
57
|
+
append_line_to_file("/etc/lxc/addn-hosts.conf", dns_record)
|
58
|
+
reload_dnsmasq
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.reload_dnsmasq
|
62
|
+
system("pkill -HUP dnsmasq")
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.search_file_delete_line(file_name, regex)
|
66
|
+
IO.write(file_name, IO.readlines(file_name).delete_if {|line| line.match(Regexp.new(regex))}.join)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.append_line_to_file(file_name, line)
|
70
|
+
content = IO.readlines(file_name)
|
71
|
+
content[-1] = content[-1].chomp + "\n"
|
72
|
+
content << line
|
73
|
+
IO.write(file_name, content.join)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.search_file_replace(file_name, regex, replace)
|
77
|
+
IO.write(file_name, IO.readlines(file_name).map {|line| line.gsub(Regexp.new(regex), replace)}.join)
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dev-lxc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jeremiah Snapp
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-03-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: thor
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: ruby-lxc
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.0.1
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.0.1
|
78
|
+
description: A tool for creating Chef server clusters using LXC containers
|
79
|
+
email:
|
80
|
+
- jeremiah@getchef.com
|
81
|
+
executables:
|
82
|
+
- dev-lxc
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- LICENSE
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- bin/dev-lxc
|
92
|
+
- dev-lxc.gemspec
|
93
|
+
- files/configs/ha.yaml
|
94
|
+
- files/configs/open-source.yaml
|
95
|
+
- files/configs/standalone.yaml
|
96
|
+
- files/configs/tier.yaml
|
97
|
+
- files/create_users/create_users.rb
|
98
|
+
- files/create_users/default.rb
|
99
|
+
- files/create_users/knife.rb.erb
|
100
|
+
- lib/dev-lxc.rb
|
101
|
+
- lib/dev-lxc/chef-cluster.rb
|
102
|
+
- lib/dev-lxc/chef-server.rb
|
103
|
+
- lib/dev-lxc/cli.rb
|
104
|
+
- lib/dev-lxc/container.rb
|
105
|
+
- lib/dev-lxc/version.rb
|
106
|
+
homepage: https://github.com/jeremiahsnapp/dev-lxc
|
107
|
+
licenses:
|
108
|
+
- Apache2
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 1.8.23
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: A tool for creating Chef server clusters using LXC containers
|
131
|
+
test_files: []
|
132
|
+
has_rdoc:
|