Skip to content

Commit 9e41819

Browse files
committed
first commit
0 parents  commit 9e41819

File tree

12 files changed

+308
-0
lines changed

12 files changed

+308
-0
lines changed

LICENSE

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Copyright (c) 2012 Andrew Kent
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Whitespace-only changes.

bin/hull

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env ruby
2+
3+
arg_command = ARGV.shift
4+
arg_package = ARGV.shift
5+
arg_node = ARGV.shift
6+
7+
8+
require_relative "../lib/hull"
9+
include Hull::DSL
10+
11+
require Dir.pwd + '/config/hull'
12+
13+
14+
if arg_command == 'apply'
15+
apply(arg_node, arg_package, :install)
16+
else
17+
demonstrate(arg_node, arg_package, :install)
18+
end

config/hull.rb

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
load_package 'apt'
2+
3+
4+
package 'ubuntu-dev' do
5+
depends_on 'build-essential'
6+
depends_on 'git'
7+
end
8+
9+
package 'build-essential' do
10+
depends_on 'apt'
11+
12+
install do
13+
trigger 'apt:install', 'build-essential'
14+
end
15+
16+
remove do
17+
trigger 'apt:remove', 'build-essential'
18+
end
19+
end
20+
21+
22+
package 'git' do
23+
install do
24+
trigger 'apt:install', 'git-core'
25+
end
26+
27+
remove do
28+
trigger 'apt:remove', 'git-core'
29+
end
30+
end
31+
32+
33+
node 'kent-web-1', '198.211.122.159'
34+
35+
36+
37+
# apply 'kent-web-1', 'ubuntu-dev', :install
38+
# demonstrate '198.211.122.159', 'ubuntu-dev', :install

hull.gemspec

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Gem::Specification.new do |gem|
2+
gem.authors = ["Andy Kent"]
3+
gem.email = ["[email protected]"]
4+
gem.description = %q{Simplified Machine Building}
5+
gem.summary = %q{Simplified Machine Building}
6+
gem.homepage = ""
7+
8+
gem.files = `git ls-files`.split($\)
9+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
10+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
11+
gem.name = "hull"
12+
gem.require_paths = ["lib"]
13+
gem.version = '0.1.0'
14+
gem.add_dependency('colored')
15+
gem.add_dependency('net-ssh')
16+
end

lib/hull.rb

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require 'colored'
2+
3+
module Hull; end
4+
5+
require_relative "./hull/package"
6+
require_relative "./hull/package_index"
7+
require_relative "./hull/node"
8+
require_relative "./hull/runner"
9+
require_relative "./hull/dsl"

lib/hull/dsl.rb

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module Hull
2+
module DSL
3+
module_function
4+
def package(name, &definition)
5+
pkg = Hull::Package.new(name)
6+
pkg.instance_eval(&definition)
7+
Hull::PackageIndex.default.add(pkg)
8+
end
9+
10+
def apply(node_name, pkg_name, command)
11+
node = Hull::Node.find(node_name)
12+
pkg = Hull::PackageIndex.default.get(pkg_name)
13+
Hull::Runner.new(node, pkg).apply(command)
14+
end
15+
16+
def demonstrate(node_name, pkg_name, command)
17+
node = Hull::Node.find(node_name)
18+
pkg = Hull::PackageIndex.default.get(pkg_name)
19+
Hull::Runner.new(node, pkg).demonstrate(command)
20+
end
21+
22+
def load_package(name)
23+
require_relative("./packages/#{name}")
24+
end
25+
26+
def node(name, host)
27+
Hull::Node.new(name, host)
28+
end
29+
end
30+
end

lib/hull/node.rb

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
require 'net/ssh'
2+
3+
class Hull::Node
4+
attr_reader :name
5+
6+
def self.find(name)
7+
@nodes[name]
8+
end
9+
10+
def self.register(node)
11+
@nodes ||= {}
12+
@nodes[node.name] = node
13+
end
14+
15+
def initialize(name, host)
16+
@name = name
17+
@host = host
18+
@connection = nil
19+
Hull::Node.register(self)
20+
end
21+
22+
def execute(cmd)
23+
log('execute', cmd.cyan)
24+
connection.exec! cmd do |channel, stream, data|
25+
data.split("\n").each do |line|
26+
msg = stream == :stdout ? line.green : line.red
27+
log(stream, msg)
28+
end
29+
end
30+
end
31+
32+
def log(context, msg)
33+
puts "#{@host} [#{context.to_s.bold}] #{msg}"
34+
end
35+
36+
def connection
37+
return @connection if @connection
38+
@connetion = Net::SSH.start(@host, 'root')
39+
end
40+
end
41+
42+
43+
class Hull::MockNode
44+
def execute(cmd)
45+
log('execute', cmd)
46+
end
47+
end

lib/hull/package.rb

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
class Hull::Package
2+
attr_reader :name, :dependancies, :actions
3+
4+
def initialize(name)
5+
@name = name
6+
@dependancies = []
7+
@actions = {}
8+
@commands = {}
9+
@remove = nil
10+
end
11+
12+
def depends_on(pkg_name)
13+
@dependancies << pkg_name
14+
end
15+
16+
def install(&definition)
17+
@commands[:install] = definition
18+
end
19+
20+
def remove(&definition)
21+
@commands[:remove] = definition
22+
end
23+
24+
def action(name, &definition)
25+
@actions[name] = definition
26+
end
27+
28+
def command(name)
29+
@commands[name.to_sym]
30+
end
31+
32+
def provides_command?(name)
33+
!command(name).nil?
34+
end
35+
end

lib/hull/package_index.rb

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
class Hull::PackageIndex
2+
attr_reader :index_name
3+
4+
def initialize(index_name)
5+
@index_name = index_name
6+
@packages = {}
7+
end
8+
9+
def self.default
10+
@default ||= new('default')
11+
end
12+
13+
def add(pkg)
14+
@packages[pkg.name] = pkg
15+
end
16+
17+
def get(pkg_name)
18+
pkg = @packages[pkg_name]
19+
raise "Missing Package #{pkg_name}" if pkg.nil?
20+
pkg
21+
end
22+
end

lib/hull/packages/apt.rb

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Hull::DSL
2+
package 'apt' do
3+
action 'install' do |package_name|
4+
run "DEBIAN_FRONTEND=noninteractive apt-get install -y -q #{package_name}"
5+
end
6+
7+
action 'remove' do |package_name|
8+
run "DEBIAN_FRONTEND=noninteractive apt-get remove -y -q #{package_name}"
9+
end
10+
end
11+
end

lib/hull/runner.rb

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
class Hull::Runner
2+
def initialize(node, package)
3+
@node = node
4+
@package = package
5+
@perform = true
6+
end
7+
8+
def packages
9+
resolver = Hull::Resolver.new(@package)
10+
resolver.resolve
11+
resolver.packages
12+
end
13+
14+
def apply(command_name)
15+
packages.each do |pkg|
16+
next unless pkg.provides_command?(command_name)
17+
@node.log pkg.name, command_name.to_s.yellow
18+
context = @perform ? Hull::ExecutionContext.new(@node) : Hull::MockExecutionContext.new(@node)
19+
cmd = pkg.command(command_name)
20+
context.apply(cmd)
21+
end
22+
end
23+
24+
def demonstrate(command_name)
25+
@perform = false
26+
apply(command_name)
27+
@perform = true
28+
end
29+
end
30+
31+
32+
class Hull::ExecutionContext
33+
def initialize(node)
34+
@node = node
35+
end
36+
37+
def apply(blk)
38+
instance_eval(&blk)
39+
end
40+
41+
def run(cmd)
42+
@node.execute(cmd)
43+
end
44+
45+
def trigger(action, *args)
46+
pkg_name, action_name = *action.split(':', 2)
47+
pkg = Hull::PackageIndex.default.get(pkg_name)
48+
action = pkg.actions[action_name]
49+
instance_exec(*args, &action)
50+
end
51+
end
52+
53+
class Hull::MockExecutionContext < Hull::ExecutionContext
54+
def run(cmd)
55+
@node.log 'mock-execute', cmd
56+
end
57+
end
58+
59+
60+
class Hull::Resolver
61+
attr_reader :packages
62+
def initialize(package)
63+
@package = package
64+
@packages = [@package]
65+
end
66+
67+
def resolve
68+
dependancies = @package.dependancies.map { |d| Hull::PackageIndex.default.get(d) }
69+
@packages += dependancies.map {|d| Hull::Resolver.new(d).resolve.packages }
70+
@packages.flatten!
71+
@packages.reverse!
72+
@packages.uniq!
73+
self
74+
end
75+
end

0 commit comments

Comments
 (0)