houcho 0.0.6 → 0.0.8
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.
- 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
|