houcho 0.0.6 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/Gemfile.lock +32 -0
- data/bin/houcho +3 -262
- data/houcho.gemspec +2 -1
- data/lib/houcho/attribute.rb +99 -0
- data/lib/houcho/ci.rb +18 -13
- data/lib/houcho/cli/attribute.rb +70 -0
- data/lib/houcho/cli/host.rb +46 -0
- data/lib/houcho/cli/outerrole.rb +53 -0
- data/lib/houcho/cli/role.rb +69 -0
- data/lib/houcho/cli/spec.rb +103 -0
- data/lib/houcho/cli.rb +52 -0
- data/lib/houcho/config.rb +28 -0
- data/lib/houcho/database.rb +99 -0
- data/lib/houcho/element.rb +79 -50
- data/lib/houcho/host.rb +30 -9
- data/lib/houcho/outerrole/cloudforecast.rb +94 -0
- data/{templates/role/cf_roles.yaml → lib/houcho/outerrole/yabitz.rb} +0 -0
- data/lib/houcho/outerrole.rb +52 -0
- data/lib/houcho/repository.rb +59 -0
- data/lib/houcho/role.rb +78 -91
- data/lib/houcho/spec/runner.rb +156 -85
- data/lib/houcho/spec.rb +72 -3
- data/lib/houcho/version.rb +1 -1
- data/lib/houcho.rb +10 -52
- data/spec/houcho_spec.rb +334 -91
- metadata +31 -22
- data/lib/houcho/cloudforecast/host.rb +0 -25
- data/lib/houcho/cloudforecast/role.rb +0 -25
- data/lib/houcho/cloudforecast.rb +0 -59
- data/lib/houcho/yamlhandle.rb +0 -31
- data/spec/spec_helper.rb +0 -15
- data/templates/conf/houcho.conf +0 -10
- data/templates/conf/kk.rb +0 -14
- data/templates/conf/rspec.conf +0 -1
- data/templates/master +0 -94
- data/templates/role/cloudforecast/.gitkeep +0 -0
- data/templates/role/cloudforecast.yaml +0 -0
- data/templates/role/hosts.yaml +0 -0
- data/templates/role/hosts_ignored.yaml +0 -0
- data/templates/role/roles.yaml +0 -0
- data/templates/role/specs.yaml +0 -0
- data/templates/spec/sample_spec.rb +0 -13
- data/templates/spec/spec_helper.rb +0 -29
@@ -0,0 +1,69 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "houcho/role"
|
3
|
+
|
4
|
+
module Houcho
|
5
|
+
module CLI
|
6
|
+
class Role < Thor
|
7
|
+
namespace :role
|
8
|
+
|
9
|
+
@@r = Houcho::Role.new
|
10
|
+
|
11
|
+
desc 'create [role1 role2 role3...]', 'cretate role'
|
12
|
+
def create(*args)
|
13
|
+
Houcho::CLI::Main.empty_args(self, shell, __method__) if args.empty?
|
14
|
+
@@r.create(args)
|
15
|
+
rescue Houcho::RoleExistenceException => e
|
16
|
+
puts e.message
|
17
|
+
exit!
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'delete [role1 role2 role3...]', 'delete a role'
|
21
|
+
def delete(*args)
|
22
|
+
Houcho::CLI::Main.empty_args(self, shell, __method__) if args.empty?
|
23
|
+
@@r.delete(args)
|
24
|
+
rescue SQLite3::ConstraintException => e
|
25
|
+
puts e.message
|
26
|
+
exit!
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'rename [exist role] [name]', 'rename a role'
|
30
|
+
def rename(exist_role, name)
|
31
|
+
@@r.rename(exist_role, name)
|
32
|
+
rescue SQLite3::ConstraintException, SQLite3::SQLException => e
|
33
|
+
puts e.message
|
34
|
+
exit!
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'details [role1 role2...]', 'show details about role'
|
38
|
+
def details(*args)
|
39
|
+
Houcho::CLI::Main.empty_args(self, shell, __method__) if args.empty?
|
40
|
+
Houcho::CLI::Main.puts_details(@@r.details(args))
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'list', 'show all of roles'
|
44
|
+
def list
|
45
|
+
puts @@r.list.join("\n")
|
46
|
+
end
|
47
|
+
|
48
|
+
desc 'exec (role1 role2..) [options]', 'run role'
|
49
|
+
option :exclude_hosts, :type => :array, :desc => '--exclude-hosts host1 host2 host3...'
|
50
|
+
option :dry_run, :type => :boolean, :default => false, :desc => 'show commands that may exexute'
|
51
|
+
def exec(*args)
|
52
|
+
Houcho::CLI::Main.empty_args(self, shell, __method__) if args.empty?
|
53
|
+
runner = Houcho::Spec::Runner.new
|
54
|
+
|
55
|
+
begin
|
56
|
+
exit! unless runner.execute_role(
|
57
|
+
args,
|
58
|
+
(options[:exclude_hosts] || []),
|
59
|
+
options[:dry_run],
|
60
|
+
true #output to console
|
61
|
+
)
|
62
|
+
rescue Houcho::SpecFileException => e
|
63
|
+
puts e.message
|
64
|
+
exit!
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'houcho/spec'
|
3
|
+
require 'houcho/spec/runner'
|
4
|
+
|
5
|
+
module Houcho
|
6
|
+
module CLI
|
7
|
+
class Spec < Thor
|
8
|
+
namespace :spec
|
9
|
+
|
10
|
+
@@s = Houcho::Spec.new
|
11
|
+
|
12
|
+
desc 'list', 'show all of spec list'
|
13
|
+
def list
|
14
|
+
puts @@s.list.sort.join("\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
desc 'attach [spec1 spec2 spec3...] --roles [role1 role2...]', 'attach spec to role'
|
19
|
+
option :roles, :type => :array, :required => true, :desc => 'specify the roles separated by spaces.'
|
20
|
+
def attach(*args)
|
21
|
+
@@s.attach(args, options[:roles])
|
22
|
+
rescue RoleExistenceException, SpecFileException, SQLite3::ConstraintException => e
|
23
|
+
puts e.message
|
24
|
+
exit!
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
desc 'detach [spec1 spec2 spec3...]', 'detach spec from spec'
|
29
|
+
option :roles, :type => :array, :required => true, :desc => 'specify the roles separated by spaces.'
|
30
|
+
def detach(*args)
|
31
|
+
@@s.detach(args, options[:roles])
|
32
|
+
rescue RoleExistenceException, SQLite3::ConstraintException => e
|
33
|
+
puts e.message
|
34
|
+
exit!
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
desc "rename [from] [to]", "rename spec file"
|
39
|
+
def rename(from, to)
|
40
|
+
@@s.rename(from, to)
|
41
|
+
rescue SpecFileException => e
|
42
|
+
puts e.message
|
43
|
+
exit!
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
desc "delete [spec1 spec2 spec3...]", "delete spec file from houcho repository."
|
48
|
+
option :force, :aliases => "-f", :type => :boolean, :desc => "delete spec force together with attachment."
|
49
|
+
def delete(*args)
|
50
|
+
if options[:force]
|
51
|
+
@@s.delete_file!(args)
|
52
|
+
else
|
53
|
+
@@s.delete_file(args)
|
54
|
+
end
|
55
|
+
rescue SpecFileException => e
|
56
|
+
puts e.message
|
57
|
+
exit!
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
desc 'details [spec1 spec2 spec3...]', 'show details about spec'
|
62
|
+
def details(*args)
|
63
|
+
Houcho::CLI::Main.puts_details(@@s.details(args))
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
desc 'check [spec1 spec2...]', 'run the spec sampled appropriately to the associated host'
|
68
|
+
option :samples, :type => :numeric, :default => 5, :desc => 'number of sample hosts'
|
69
|
+
def check(*args)
|
70
|
+
Houcho::CLI::Main.empty_args(self, shell, __method__) if args.empty?
|
71
|
+
runner = Houcho::Spec::Runner.new
|
72
|
+
|
73
|
+
begin
|
74
|
+
exit! unless runner.check(args, options[:samples], false, true)
|
75
|
+
rescue SpecFileException => e
|
76
|
+
puts e.message
|
77
|
+
exit!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
desc 'exec [spec1 spec2..]', 'run spec'
|
83
|
+
option :hosts, :type => :array, :desc => '--hosts host1 host2 host3...', :required => true
|
84
|
+
option :dry_run, :type => :boolean, :default => false, :desc => 'show commands that may exexute'
|
85
|
+
def exec(*args)
|
86
|
+
Houcho::CLI::Main.empty_args(self, shell, __method__) if args.empty?
|
87
|
+
runner = Houcho::Spec::Runner.new
|
88
|
+
|
89
|
+
begin
|
90
|
+
exit! unless runner.execute_manually(
|
91
|
+
options[:hosts],
|
92
|
+
args,
|
93
|
+
options[:dry_run],
|
94
|
+
true #output to console
|
95
|
+
)
|
96
|
+
rescue Houcho::SpecFileException => e
|
97
|
+
puts e.message
|
98
|
+
exit!
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/houcho/cli.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "rainbow"
|
3
|
+
require "houcho/repository"
|
4
|
+
|
5
|
+
module Houcho::CLI
|
6
|
+
class Main < Thor
|
7
|
+
if File.exist?("#{Houcho::Config::APPROOT}/houcho.db")
|
8
|
+
require "houcho/cli/role"
|
9
|
+
require "houcho/cli/spec"
|
10
|
+
require "houcho/cli/host"
|
11
|
+
require "houcho/cli/outerrole"
|
12
|
+
require "houcho/cli/attribute"
|
13
|
+
register(Houcho::CLI::Role, "role", "role [create|delete|rename|list|details|exec]", "operation of roles")
|
14
|
+
register(Houcho::CLI::Host, "host", "host [attach|detach|list|details]", "operation of hosts")
|
15
|
+
register(Houcho::CLI::Spec, "spec", "spec [attach|detach|list|details|rename|delete|exec|check]", "operation of specs")
|
16
|
+
register(Houcho::CLI::OuterRole, "outerrole", "outerrole [attach|detach|list|details|load]", "operation of outer roles")
|
17
|
+
register(Houcho::CLI::Attribute, "attr", "attr [set|get|delete]", "operation of attribute")
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "init","set houcho repository on directory set environment variable HOUCHO_ROOT"
|
21
|
+
def init
|
22
|
+
Houcho::Repository.init
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.empty_args(klass, chell, mesod)
|
26
|
+
klass.class.task_help(chell, mesod)
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.puts_details(e, indentsize = 0, cnt = 1)
|
31
|
+
case e
|
32
|
+
when Array
|
33
|
+
e.sort.each.with_index(1) do |v, i|
|
34
|
+
(indentsize-1).times {print ' '}
|
35
|
+
print i != e.size ? '├─ ' : '└─ '
|
36
|
+
puts v
|
37
|
+
end
|
38
|
+
puts ''
|
39
|
+
when Hash
|
40
|
+
e.each do |k,v|
|
41
|
+
if indentsize != 0
|
42
|
+
(indentsize).times {print ' '}
|
43
|
+
end
|
44
|
+
title = k.to_s.color(0,255,0)
|
45
|
+
title = '[' + k.to_s.color(219,112,147) + ']' if indentsize == 0
|
46
|
+
puts title
|
47
|
+
puts_details(v, indentsize+1, cnt+1)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module Houcho
|
4
|
+
module Config
|
5
|
+
APPROOT = ENV["HOUCHO_ROOT"] ? ENV["HOUCHO_ROOT"] : "/etc/houcho"
|
6
|
+
|
7
|
+
SPECDIR = "#{APPROOT}/spec"
|
8
|
+
SCRIPTDIR = "#{APPROOT}/script"
|
9
|
+
|
10
|
+
OUTERROLESOURCEDIR = "#{APPROOT}/outerrole"
|
11
|
+
CFYAMLDIR = "#{OUTERROLESOURCEDIR}/cloudforecast"
|
12
|
+
|
13
|
+
LOGDIR = "#{APPROOT}/log"
|
14
|
+
SPECLOG = "#{LOGDIR}/serverspec.log"
|
15
|
+
|
16
|
+
FILE = "#{Houcho::Config::APPROOT}/houcho.conf"
|
17
|
+
begin
|
18
|
+
conf = YAML.load_file(FILE)
|
19
|
+
rescue
|
20
|
+
end
|
21
|
+
if conf
|
22
|
+
UKIGUMO = conf["ukigumo"]
|
23
|
+
IKACHAN = conf["ikachan"]
|
24
|
+
GIT = conf["git"]
|
25
|
+
RSPEC = conf["rspec"]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "sqlite3"
|
2
|
+
require "houcho/config"
|
3
|
+
|
4
|
+
module Houcho
|
5
|
+
class Database
|
6
|
+
attr_reader :handle
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@handle = SQLite3::Database.new("#{Houcho::Config::APPROOT}/houcho.db")
|
10
|
+
@handle.execute("PRAGMA foreign_keys = ON")
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_tables
|
14
|
+
@handle.execute_batch <<-SQL
|
15
|
+
CREATE TABLE IF NOT EXISTS role (
|
16
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
17
|
+
name VARCHAR NOT NULL UNIQUE
|
18
|
+
);
|
19
|
+
|
20
|
+
CREATE TABLE IF NOT EXISTS host (
|
21
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
22
|
+
name VARCHAR NOT NULL UNIQUE
|
23
|
+
);
|
24
|
+
|
25
|
+
CREATE TABLE IF NOT EXISTS role_host (
|
26
|
+
role_id INTEGER NOT NULL,
|
27
|
+
host_id INTEGER NOT NULL,
|
28
|
+
UNIQUE(role_id, host_id),
|
29
|
+
FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE RESTRICT,
|
30
|
+
FOREIGN KEY (host_id) REFERENCES host (id) ON DELETE RESTRICT
|
31
|
+
);
|
32
|
+
|
33
|
+
CREATE TABLE IF NOT EXISTS serverspec (
|
34
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
35
|
+
name VARCHAR NOT NULL UNIQUE
|
36
|
+
);
|
37
|
+
|
38
|
+
CREATE TABLE IF NOT EXISTS role_serverspec (
|
39
|
+
role_id INTEGER NOT NULL,
|
40
|
+
serverspec_id INTEGER NOT NULL,
|
41
|
+
UNIQUE(role_id, serverspec_id),
|
42
|
+
FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE RESTRICT,
|
43
|
+
FOREIGN KEY (serverspec_id) REFERENCES serverspec (id) ON DELETE RESTRICT
|
44
|
+
);
|
45
|
+
|
46
|
+
CREATE TABLE IF NOT EXISTS script (
|
47
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
48
|
+
name VARCHAR NOT NULL UNIQUE
|
49
|
+
);
|
50
|
+
|
51
|
+
CREATE TABLE IF NOT EXISTS role_script (
|
52
|
+
role_id INTEGER NOT NULL,
|
53
|
+
script_id INTEGER NOT NULL,
|
54
|
+
UNIQUE(role_id, script_id),
|
55
|
+
FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE RESTRICT,
|
56
|
+
FOREIGN KEY (script_id) REFERENCES script (id) ON DELETE RESTRICT
|
57
|
+
);
|
58
|
+
|
59
|
+
CREATE TABLE IF NOT EXISTS outerrole (
|
60
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
61
|
+
name VARCHAR NOT NULL UNIQUE,
|
62
|
+
data_source VARCHAR NOT NULL
|
63
|
+
);
|
64
|
+
|
65
|
+
CREATE TABLE IF NOT EXISTS outerrole_host (
|
66
|
+
outerrole_id INTEGER NOT NULL,
|
67
|
+
host_id INTEGER NOT NULL,
|
68
|
+
UNIQUE(outerrole_id, host_id),
|
69
|
+
FOREIGN KEY (outerrole_id) REFERENCES outerrole (id) ON DELETE RESTRICT,
|
70
|
+
FOREIGN KEY (host_id) REFERENCES host (id) ON DELETE RESTRICT
|
71
|
+
);
|
72
|
+
|
73
|
+
CREATE TABLE IF NOT EXISTS role_outerrole (
|
74
|
+
role_id INTEGER NOT NULL,
|
75
|
+
outerrole_id INTEGER NOT NULL,
|
76
|
+
UNIQUE(role_id, outerrole_id),
|
77
|
+
FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE RESTRICT,
|
78
|
+
FOREIGN KEY (outerrole_id) REFERENCES outerrole (id) ON DELETE RESTRICT
|
79
|
+
);
|
80
|
+
|
81
|
+
CREATE TABLE IF NOT EXISTS attribute (
|
82
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
83
|
+
name VARCHAR NOT NULL UNIQUE
|
84
|
+
);
|
85
|
+
|
86
|
+
CREATE TABLE IF NOT EXISTS attribute_value (
|
87
|
+
id INTEGER NOT NULL PRIMARY KEY,
|
88
|
+
attr_id INTEGER NOT NULL,
|
89
|
+
element_type INTEGER NOT NULL,
|
90
|
+
element_id INTEGER NOT NULL,
|
91
|
+
value VARCHAR NOT NULL,
|
92
|
+
COMMENT "element_type => {0:role, 1:outerrole, 2:host}",
|
93
|
+
UNIQUE(attr_id, element_type, element_id),
|
94
|
+
FOREIGN KEY (attr_id) REFERENCES attribute (id) ON DELETE RESTRICT
|
95
|
+
);
|
96
|
+
SQL
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/houcho/element.rb
CHANGED
@@ -1,80 +1,109 @@
|
|
1
|
+
require 'houcho/role'
|
2
|
+
require "houcho/database"
|
3
|
+
|
1
4
|
module Houcho
|
2
|
-
|
5
|
+
class Element
|
6
|
+
def initialize(type)
|
7
|
+
@db = Houcho::Database.new.handle
|
8
|
+
@role = Houcho::Role.new
|
9
|
+
@type = type
|
10
|
+
end
|
3
11
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
else
|
8
|
-
@elements.data.values.flatten.uniq
|
9
|
-
end
|
12
|
+
|
13
|
+
def id(name)
|
14
|
+
@db.execute("SELECT id FROM #{@type} WHERE name = '#{name}'").flatten.first
|
10
15
|
end
|
11
16
|
|
12
17
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
18
|
+
def list(role_id = nil)
|
19
|
+
sql = "SELECT T1.name FROM #{@type} T1"
|
20
|
+
sql += " JOIN role_#{@type} T2 ON T1.id = T2.#{@type}_id WHERE T2.role_id = #{role_id}" if role_id
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
index = Role.index(role)
|
20
|
-
if ! index
|
21
|
-
invalid_roles << role
|
22
|
-
next
|
23
|
-
end
|
22
|
+
@db.execute(sql).flatten
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
|
26
|
+
def details(elements)
|
27
|
+
elements = elements.is_a?(Array) ? elements : [elements]
|
28
|
+
result = {}
|
29
|
+
|
30
|
+
elements.each do |element|
|
31
|
+
roles = @db.execute("
|
32
|
+
SELECT role.name
|
33
|
+
FROM role, #{@type}, role_#{@type}
|
34
|
+
WHERE role_#{@type}.#{@type}_id = #{@type}.id
|
35
|
+
AND role_#{@type}.role_id = role.id
|
36
|
+
AND #{@type}.name = ?
|
37
|
+
", element).flatten.sort.uniq
|
38
|
+
|
39
|
+
result[element] = { "role" => roles }
|
27
40
|
end
|
28
41
|
|
29
|
-
|
30
|
-
raise("role(#{invalid_roles.join(',')}) does not exist") if ! invalid_roles.size.zero?
|
42
|
+
result
|
31
43
|
end
|
32
44
|
|
33
45
|
|
34
|
-
def
|
35
|
-
elements = [elements]
|
36
|
-
roles
|
46
|
+
def attach(elements, roles)
|
47
|
+
elements = [elements] unless elements.is_a?(Array)
|
48
|
+
roles = [roles] unless roles.is_a?(Array)
|
37
49
|
|
38
|
-
invalid_roles = []
|
39
50
|
roles.each do |role|
|
40
|
-
|
41
|
-
|
42
|
-
invalid_roles << role
|
43
|
-
next
|
44
|
-
end
|
51
|
+
role_id = @role.id(role)
|
52
|
+
raise RoleExistenceException, "role does not exist - #{role}" unless role_id
|
45
53
|
|
46
|
-
@
|
47
|
-
end
|
54
|
+
@db.transaction do
|
48
55
|
|
49
|
-
|
50
|
-
|
51
|
-
end
|
56
|
+
elements.each do |element|
|
57
|
+
@db.execute("INSERT INTO #{@type}(name) VALUES(?)", element) unless id(element)
|
52
58
|
|
59
|
+
begin
|
60
|
+
@db.execute("INSERT INTO role_#{@type} VALUES(?,?)", role_id, id(element))
|
61
|
+
rescue SQLite3::ConstraintException
|
62
|
+
next
|
63
|
+
end
|
64
|
+
end
|
53
65
|
|
54
|
-
|
55
|
-
|
56
|
-
@elements.data[index].include?(element)
|
66
|
+
end #end of transaction
|
67
|
+
end
|
57
68
|
end
|
58
69
|
|
59
70
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
71
|
+
def detach_from_all(elements)
|
72
|
+
roles = []
|
73
|
+
details(elements).each do |e, r|
|
74
|
+
roles = roles.concat(r["role"]||[]).uniq
|
75
|
+
end
|
76
|
+
|
77
|
+
detach(elements, roles)
|
63
78
|
end
|
64
79
|
|
65
80
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
end
|
81
|
+
def detach(elements, roles)
|
82
|
+
elements = [elements] unless elements.is_a?(Array)
|
83
|
+
roles = [roles] unless roles.is_a?(Array)
|
70
84
|
|
85
|
+
roles.each do |role|
|
86
|
+
role_id = @role.id(role)
|
87
|
+
raise RoleExistenceException, "role does not exist - #{role}" if role_id.nil?
|
88
|
+
|
89
|
+
@db.transaction do
|
90
|
+
|
91
|
+
elements.each do |element|
|
92
|
+
@db.execute(
|
93
|
+
"DELETE FROM role_#{@type} WHERE role_id = ? AND #{@type}_id = ?",
|
94
|
+
role_id,
|
95
|
+
id(element)
|
96
|
+
)
|
97
|
+
|
98
|
+
begin
|
99
|
+
@db.execute("DELETE FROM #{@type} WHERE name = ?", element)
|
100
|
+
rescue SQLite3::ConstraintException, "foreign key constraint failed"
|
101
|
+
next
|
102
|
+
end
|
103
|
+
end
|
71
104
|
|
72
|
-
|
73
|
-
result = {}
|
74
|
-
elements.each do |element|
|
75
|
-
result[element] = { 'role' => self.indexes(element).map {|index|Role.name(index)} }
|
105
|
+
end #end of transaction
|
76
106
|
end
|
77
|
-
result
|
78
107
|
end
|
79
108
|
end
|
80
109
|
end
|
data/lib/houcho/host.rb
CHANGED
@@ -1,22 +1,43 @@
|
|
1
|
+
require "houcho/element"
|
2
|
+
require "houcho/attribute"
|
3
|
+
|
1
4
|
module Houcho
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
+
class HostExistenceException < Exception; end
|
6
|
+
|
7
|
+
class Host < Element
|
8
|
+
include Houcho::Attribute
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super("host")
|
12
|
+
@type_id = 2
|
13
|
+
end
|
5
14
|
|
6
|
-
def
|
15
|
+
def details(hosts)
|
16
|
+
hosts = hosts.is_a?(Array) ? hosts : [hosts]
|
7
17
|
result = {}
|
8
18
|
|
9
19
|
hosts.each do |host|
|
10
|
-
roles =
|
11
|
-
|
20
|
+
roles = super(host)[host]["role"]
|
21
|
+
outerroles = @db.execute("
|
22
|
+
SELECT role.name
|
23
|
+
FROM outerrole role, outerrole_host oh
|
24
|
+
WHERE role.id = oh.outerrole_id
|
25
|
+
AND oh.host_id = ?
|
26
|
+
", id(host)).flatten.sort.uniq
|
12
27
|
|
13
|
-
result[host]
|
14
|
-
result[host][
|
15
|
-
result[host][
|
28
|
+
result[host] = {}
|
29
|
+
result[host]["role"] = roles if ! roles.empty?
|
30
|
+
result[host]["outer role"] = outerroles if ! outerroles.empty?
|
16
31
|
|
17
32
|
result.delete(host) if result[host].keys.empty?
|
18
33
|
end
|
34
|
+
|
19
35
|
result
|
20
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def raise_target_does_not_exist(target)
|
40
|
+
raise HostExistenceException, "host does not exist - #{target}"
|
41
|
+
end
|
21
42
|
end
|
22
43
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "houcho/config"
|
2
|
+
require "houcho/database"
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module Houcho
|
6
|
+
|
7
|
+
class OuterRole
|
8
|
+
class CloudForecast; end
|
9
|
+
class << CloudForecast
|
10
|
+
def load
|
11
|
+
cfdir = Houcho::Config::CFYAMLDIR
|
12
|
+
|
13
|
+
Dir::entries(cfdir).each do |file|
|
14
|
+
next if file !~ /\.yaml$/
|
15
|
+
yaml = "#{cfdir}/#{file}"
|
16
|
+
group = load_group(yaml)
|
17
|
+
cfrole = create_cf_role(yaml, group)
|
18
|
+
|
19
|
+
save_cf_role(cfrole)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
def load_group(yaml)
|
26
|
+
group = []
|
27
|
+
|
28
|
+
File.open(yaml).each_line do |line|
|
29
|
+
next unless line =~ /^---/
|
30
|
+
if line =~ /^---\s+#(?<group>.+)\n/
|
31
|
+
group << $~[:group].gsub(/\s+/, "_")
|
32
|
+
else
|
33
|
+
group << "NOGROUP"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
group
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def create_cf_role(yaml, group)
|
42
|
+
cfrole = {}
|
43
|
+
|
44
|
+
YAML.load_stream(File.open(yaml)).each_with_index do |doc, i|
|
45
|
+
label = "NOLABEL"
|
46
|
+
|
47
|
+
doc["servers"].each do |servers|
|
48
|
+
label = servers["label"].gsub(/\s+/, '_') if servers["label"]
|
49
|
+
outerrole = "#{group[i]}::#{label}::#{servers["config"].sub(/\.yaml$/, "")}"
|
50
|
+
hosts = servers["hosts"].map { |host| host.split(/\s+/)[1] }
|
51
|
+
|
52
|
+
cfrole[outerrole] = hosts
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
cfrole
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def save_cf_role(cfrole)
|
61
|
+
db = Houcho::Database.new.handle
|
62
|
+
db.transaction do
|
63
|
+
|
64
|
+
cfrole.each do |outerrole, hosts|
|
65
|
+
begin
|
66
|
+
db.execute("INSERT INTO outerrole(name, data_source) VALUES(?,?)", outerrole, "CloudForecast")
|
67
|
+
rescue SQLite3::ConstraintException, "column name is not unique"
|
68
|
+
ensure
|
69
|
+
outerrole_id = db.execute("SELECT id FROM outerrole WHERE name = ?", outerrole).flatten.first
|
70
|
+
end
|
71
|
+
|
72
|
+
hosts.each do |host|
|
73
|
+
begin
|
74
|
+
db.execute("INSERT INTO host(name) VALUES(?)", host)
|
75
|
+
rescue SQLite3::ConstraintException, "column name is not unique"
|
76
|
+
ensure
|
77
|
+
begin
|
78
|
+
db.execute(
|
79
|
+
"INSERT INTO outerrole_host(outerrole_id, host_id) VALUES(?,?)",
|
80
|
+
outerrole_id,
|
81
|
+
db.execute("SELECT id FROM host WHERE name = ?", host).flatten.first
|
82
|
+
)
|
83
|
+
rescue SQLite3::ConstraintException, "column name is not unique"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end #end of transaction
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
File without changes
|