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,52 @@
|
|
1
|
+
require "houcho/element"
|
2
|
+
require "houcho/attribute"
|
3
|
+
|
4
|
+
module Houcho
|
5
|
+
class OuterRoleExistenceException < Exception; end
|
6
|
+
|
7
|
+
class OuterRole < Element
|
8
|
+
include Houcho::Attribute
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super("outerrole")
|
12
|
+
@type_id = 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def details(outer_role)
|
16
|
+
outer_role = outer_role.is_a?(Array) ? outer_role : [outer_role]
|
17
|
+
result = {}
|
18
|
+
outer_role.each do |role|
|
19
|
+
hosts = hostlist(role)
|
20
|
+
if !hosts.empty?
|
21
|
+
result[role] = {}
|
22
|
+
result[role]["host"] = hosts
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
def hostlist(outer_role)
|
30
|
+
outer_role = outer_role.is_a?(Array) ? outer_role : [outer_role]
|
31
|
+
hosts = []
|
32
|
+
|
33
|
+
outer_role.each do |role|
|
34
|
+
id = id(role)
|
35
|
+
hosts << @db.execute("
|
36
|
+
SELECT host.name
|
37
|
+
FROM host
|
38
|
+
JOIN outerrole_host ORHOST
|
39
|
+
ON host.id = ORHOST.host_id
|
40
|
+
WHERE ORHOST.outerrole_id = ?
|
41
|
+
", id)
|
42
|
+
end
|
43
|
+
|
44
|
+
hosts.flatten.uniq.sort
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def raise_target_does_not_exist(target)
|
49
|
+
raise OuterRoleExistenceException, "outer role does not exist - #{target}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "houcho/config"
|
2
|
+
require "houcho/database"
|
3
|
+
|
4
|
+
module Houcho
|
5
|
+
class Repository
|
6
|
+
def self.init
|
7
|
+
[
|
8
|
+
Houcho::Config::APPROOT,
|
9
|
+
Houcho::Config::SPECDIR,
|
10
|
+
Houcho::Config::SCRIPTDIR,
|
11
|
+
Houcho::Config::OUTERROLESOURCEDIR,
|
12
|
+
Houcho::Config::CFYAMLDIR,
|
13
|
+
Houcho::Config::LOGDIR
|
14
|
+
].each do |d|
|
15
|
+
Dir.mkdir(d) unless Dir.exist?(d)
|
16
|
+
end
|
17
|
+
|
18
|
+
File.write("#{Houcho::Config::FILE}", {
|
19
|
+
"ukigumo" => { "host" => "", "port" => "" },
|
20
|
+
"ikachan" => { "host" => "", "port" => "", "channel" => [] },
|
21
|
+
"git" => { "uri" => "" },
|
22
|
+
"rspec" => [],
|
23
|
+
}.to_yaml) unless File.exist?("#{Houcho::Config::FILE}")
|
24
|
+
|
25
|
+
File.write("#{Houcho::Config::SPECDIR}/spec_helper.rb", <<EOD
|
26
|
+
require "serverspec"
|
27
|
+
require 'pathname'
|
28
|
+
require 'net/ssh'
|
29
|
+
require "json"
|
30
|
+
|
31
|
+
include Serverspec::Helper::Ssh
|
32
|
+
include Serverspec::Helper::DetectOS
|
33
|
+
include Serverspec::Helper::Attributes
|
34
|
+
|
35
|
+
RSpec.configure do |c|
|
36
|
+
if ENV['ASK_SUDO_PASSWORD']
|
37
|
+
require 'highline/import'
|
38
|
+
c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
|
39
|
+
else
|
40
|
+
c.sudo_password = ENV['SUDO_PASSWORD']
|
41
|
+
end
|
42
|
+
|
43
|
+
c.ssh.close if c.ssh
|
44
|
+
c.host = ENV['TARGET_HOST']
|
45
|
+
options = Net::SSH::Config.for(c.host)
|
46
|
+
user = options[:user] || Etc.getlogin
|
47
|
+
c.ssh = Net::SSH.start(c.host, user, options)
|
48
|
+
|
49
|
+
if ENV['TARGET_HOST_ATTR']
|
50
|
+
attr_set JSON.parse(ENV['TARGET_HOST_ATTR'], { :symbolize_names => true })
|
51
|
+
end
|
52
|
+
end
|
53
|
+
EOD
|
54
|
+
) unless File.exist?("#{Houcho::Config::SPECDIR}/spec_helper.rb")
|
55
|
+
|
56
|
+
Houcho::Database.new.create_tables
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/houcho/role.rb
CHANGED
@@ -1,128 +1,115 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require "houcho/database"
|
2
|
+
require "houcho/host"
|
3
|
+
require "houcho/spec"
|
4
|
+
require "houcho/outerrole"
|
5
|
+
require "houcho/attribute"
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
target = role.shift
|
7
|
+
module Houcho
|
8
|
+
class RoleExistenceException < Exception; end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
else
|
14
|
-
@roles.data[(@roles.data.keys.max||0) + 1] = target
|
15
|
-
end
|
10
|
+
class Role
|
11
|
+
include Houcho::Attribute
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
self.create(role, exists)
|
22
|
-
end
|
13
|
+
def initialize
|
14
|
+
@db = Houcho::Database.new.handle
|
15
|
+
@type = "role"
|
16
|
+
@type_id = 0
|
23
17
|
end
|
24
18
|
|
25
19
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
if ! index
|
33
|
-
errors[:exists] << target; del = false
|
34
|
-
end
|
35
|
-
if Host.has_data?(index)
|
36
|
-
errors[:hosts] << target if Host.has_data?(index); del = false
|
37
|
-
end
|
38
|
-
if Spec.has_data?(index)
|
39
|
-
errors[:specs] << target if Spec.has_data?(index); del = false
|
40
|
-
end
|
41
|
-
if CloudForecast::Role.has_data?(index)
|
42
|
-
errors[:cf] << target if CloudForecast::Role.has_data?(index); del = false
|
43
|
-
end
|
44
|
-
|
45
|
-
@roles.data.delete(index) if del
|
46
|
-
|
47
|
-
if role.size.zero?
|
48
|
-
@roles.save_to_file
|
49
|
-
e = []
|
50
|
-
e << "role(#{errors[:exists].join(',')}) does not exist" if ! errors[:exists].size.zero?
|
51
|
-
e << "detach host from #{errors[:hosts].join(',')} before delete" if ! errors[:hosts].size.zero?
|
52
|
-
e << "detach spec from #{errors[:specs].join(',')} before delete" if ! errors[:specs].size.zero?
|
53
|
-
e << "detach cloudforecast's role from #{errors[:cf].join(',')} before delete" if ! errors[:cf].size.zero?
|
54
|
-
raise("#{e.join(', ')}.") if ! e.size.zero?
|
20
|
+
def id(role)
|
21
|
+
if role.is_a?(Regexp)
|
22
|
+
@db.execute("SELECT id, name FROM role").map do |record|
|
23
|
+
record[0] if record[1] =~ role
|
24
|
+
end
|
55
25
|
else
|
56
|
-
|
26
|
+
@db.execute("SELECT id FROM role WHERE name = ?", role).flatten.first
|
57
27
|
end
|
58
28
|
end
|
59
29
|
|
60
30
|
|
61
|
-
def
|
62
|
-
|
63
|
-
raise("#{role} does not exist") if ! index
|
64
|
-
raise("#{name} already exist") if self.index(name)
|
65
|
-
|
66
|
-
@roles.data[index] = name
|
67
|
-
@roles.save_to_file
|
31
|
+
def name(id)
|
32
|
+
@db.execute("SELECT name FROM role WHERE id = ?", id).flatten.first
|
68
33
|
end
|
69
34
|
|
70
35
|
|
71
|
-
def
|
72
|
-
|
36
|
+
def exist?(role)
|
37
|
+
!id(role).nil?
|
73
38
|
end
|
74
39
|
|
75
40
|
|
76
|
-
def
|
77
|
-
|
41
|
+
def create(role)
|
42
|
+
role = [role] unless role.is_a?(Array)
|
78
43
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
44
|
+
@db.transaction do
|
45
|
+
role.each do |r|
|
46
|
+
begin
|
47
|
+
@db.execute("INSERT INTO role(name) VALUES(?)", r)
|
48
|
+
rescue SQLite3::ConstraintException, "column name is not unique"
|
49
|
+
raise RoleExistenceException, "role already exist - #{r}"
|
50
|
+
end
|
85
51
|
end
|
86
|
-
end
|
87
|
-
|
88
|
-
roles.each do |role|
|
89
|
-
index = self.index(role)
|
90
|
-
next if ! index
|
52
|
+
end
|
53
|
+
end
|
91
54
|
|
92
|
-
hosts = Host.elements(index)
|
93
|
-
specs = Spec.elements(index)
|
94
|
-
cfroles = CloudForecast::Role.elements(index)
|
95
|
-
cfhosts = CloudForecast::Role.details(cfroles)
|
96
55
|
|
97
|
-
|
98
|
-
|
99
|
-
r['spec'] = specs if ! specs.empty?
|
100
|
-
r['cf'] = cfhosts if ! cfhosts.empty?
|
56
|
+
def delete(role)
|
57
|
+
role = [role] unless role.is_a?(Array)
|
101
58
|
|
102
|
-
|
59
|
+
@db.transaction do
|
60
|
+
role.each do |r|
|
61
|
+
raise RoleExistenceException, "role does not exist - #{r}" unless exist?(r)
|
62
|
+
@db.execute("DELETE FROM role WHERE name = ?", r)
|
63
|
+
end
|
103
64
|
end
|
104
|
-
|
105
|
-
result
|
106
65
|
end
|
107
66
|
|
108
67
|
|
109
|
-
def
|
110
|
-
|
68
|
+
def rename(exist_role, name)
|
69
|
+
raise RoleExistenceException, "role does not exist - #{exist_role}" unless exist?(exist_role)
|
70
|
+
raise RoleExistenceException, "role already exist - #{name}" if exist?(name)
|
71
|
+
@db.execute("UPDATE role SET name = '#{name}' WHERE name = '#{exist_role}'")
|
111
72
|
end
|
112
73
|
|
113
74
|
|
114
|
-
def
|
115
|
-
@
|
75
|
+
def list
|
76
|
+
@db.execute("SELECT name FROM role").flatten
|
116
77
|
end
|
117
78
|
|
118
79
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
80
|
+
def details(role)
|
81
|
+
role = role.is_a?(Array) ? role : [role]
|
82
|
+
result = {}
|
83
|
+
hostobj = Host.new
|
84
|
+
specobj = Spec.new
|
85
|
+
orobj = OuterRole.new
|
86
|
+
|
87
|
+
role.each do |r|
|
88
|
+
id = id(r)
|
89
|
+
next if ! id
|
90
|
+
id = id.is_a?(Array) ? id : [id]
|
91
|
+
|
92
|
+
id.each do |i|
|
93
|
+
hosts = hostobj.list(i)
|
94
|
+
specs = specobj.list(i)
|
95
|
+
outerroles = orobj.list(i)
|
96
|
+
outerhosts = orobj.details(outerroles)
|
97
|
+
|
98
|
+
tmp = {}
|
99
|
+
tmp["host"] = hosts unless hosts.empty?
|
100
|
+
tmp["spec"] = specs unless specs.empty?
|
101
|
+
tmp["outer role"] = outerhosts unless outerhosts.empty?
|
102
|
+
|
103
|
+
result[r] = tmp
|
104
|
+
end
|
105
|
+
end
|
122
106
|
|
107
|
+
result
|
108
|
+
end
|
123
109
|
|
124
|
-
|
125
|
-
|
110
|
+
private
|
111
|
+
def raise_target_does_not_exist(target)
|
112
|
+
raise RoleExistenceException, "role does not exist - #{target}"
|
126
113
|
end
|
127
114
|
end
|
128
115
|
end
|
data/lib/houcho/spec/runner.rb
CHANGED
@@ -1,125 +1,196 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "systemu"
|
3
|
+
require "json"
|
4
|
+
require "logger"
|
5
|
+
require "parallel"
|
6
|
+
require "houcho/role"
|
7
|
+
require "houcho/spec"
|
8
|
+
require "houcho/ci"
|
9
|
+
require "houcho/config"
|
10
|
+
|
1
11
|
module Houcho
|
2
|
-
module Spec::Runner
|
3
|
-
module_function
|
4
12
|
|
5
|
-
|
6
|
-
|
7
|
-
|
13
|
+
class Spec
|
14
|
+
class Runner
|
15
|
+
def initialize
|
16
|
+
@role = Houcho::Role.new
|
17
|
+
@host = Houcho::Host.new
|
18
|
+
@spec = Houcho::Spec.new
|
19
|
+
@outerrole = Houcho::OuterRole.new
|
20
|
+
@specdir = Houcho::Config::SPECDIR
|
21
|
+
@logger = Logger.new(Houcho::Config::SPECLOG, 10)
|
22
|
+
end
|
8
23
|
|
9
|
-
spec_check = Proc.new do |specs|
|
10
|
-
p = specs.map {|spec|'spec/' + spec + '_spec.rb'}.partition {|spes|File.exist?(spes)}
|
11
|
-
spec_not_exist += p[1].map {|e|e.sub(/^spec\//,'').sub(/_spec.rb$/,'')}
|
12
|
-
p[0]
|
13
|
-
end
|
14
24
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
def check(spec, host_count, dry_run = false, console_output = false) #dry_run for test
|
26
|
+
spec = spec.is_a?(Array) ? spec : [spec]
|
27
|
+
role = spec.map { |s| @spec.details(s)[s]["role"] }.flatten
|
28
|
+
host = []
|
19
29
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
r['host'] -= ex_hosts
|
30
|
+
@role.details(role).each do |rolename, value|
|
31
|
+
host.concat(value["host"]).uniq if value["host"]
|
24
32
|
|
25
|
-
|
33
|
+
if value["outer role"]
|
34
|
+
value["outer role"].each do |outerrolename, v|
|
35
|
+
host.concat(v["host"]).uniq if v["host"]
|
36
|
+
end
|
37
|
+
end
|
26
38
|
end
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
|
40
|
+
execute_manually(host.sample(host_count), spec, dry_run, console_output)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def execute_manually(host, spec, dryrun = false, console_output = false)
|
45
|
+
host = host.is_a?(Array) ? host : [host]
|
46
|
+
spec = spec.is_a?(Array) ? spec : [spec]
|
47
|
+
|
48
|
+
run(
|
49
|
+
{ rand(36**50).to_s(36) => { "host" => host, "spec" => spec } },
|
50
|
+
dryrun,
|
51
|
+
false,
|
52
|
+
console_output
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def execute_role(role, ex_host = [], dryrun = false, console_output = false)
|
58
|
+
role = role.is_a?(Array) ? role : [role]
|
59
|
+
ex_host = ex_host.is_a?(Array) ? ex_host : [ex_host]
|
60
|
+
|
61
|
+
role_valiables = {}
|
31
62
|
|
32
|
-
|
63
|
+
@role.details(role).each do |rolename, value|
|
64
|
+
next unless value["spec"]
|
33
65
|
|
34
|
-
|
35
|
-
|
66
|
+
rv = {}
|
67
|
+
rv["host"] = []
|
68
|
+
rv["spec"] = []
|
69
|
+
rv["outer role"] = []
|
70
|
+
|
71
|
+
rv["spec"].concat(value["spec"]).uniq
|
72
|
+
rv["host"].concat(value["host"]).uniq if value["host"]
|
73
|
+
|
74
|
+
if value["outer role"]
|
75
|
+
rv["outer role"].concat(value["outer role"].keys).uniq
|
76
|
+
value["outer role"].each do |outerrolename, v|
|
77
|
+
rv["host"].concat(v["host"]).uniq if v["host"]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
rv["host"] = rv["host"] - ex_host
|
82
|
+
role_valiables[rolename] = rv
|
36
83
|
end
|
37
|
-
|
84
|
+
|
85
|
+
run(role_valiables, dryrun, true, console_output)
|
38
86
|
end
|
39
87
|
|
40
88
|
|
41
|
-
def
|
89
|
+
def run(target, dryrun, ci = false, console_output = false)
|
42
90
|
messages = []
|
43
|
-
|
44
|
-
|
45
|
-
|
91
|
+
failure = false
|
92
|
+
|
93
|
+
target.each do |role, v|
|
94
|
+
@spec.check_existence(v["spec"])
|
95
|
+
spec = v["spec"].map { |spec| "#{@specdir}/#{spec}_spec.rb" }
|
96
|
+
command = "rspec --format documentation #{spec.sort.uniq.join(" ")}"
|
46
97
|
|
47
98
|
if dryrun
|
48
|
-
v[
|
49
|
-
|
99
|
+
v["host"].each do |host|
|
100
|
+
drymsg = "TARGET_HOST=#{host} #{command}"
|
101
|
+
puts drymsg if console_output
|
102
|
+
messages << drymsg
|
50
103
|
end
|
51
104
|
next
|
52
105
|
end
|
53
106
|
|
54
|
-
v[
|
55
|
-
|
56
|
-
|
57
|
-
|
107
|
+
Parallel.each(v["host"], :in_threads => Parallel.processor_count) do |host|
|
108
|
+
attr_role = @role.get_attr(role)
|
109
|
+
attr_host = @host.get_attr(host)
|
110
|
+
attr_outerrole = {}
|
58
111
|
|
59
|
-
|
60
|
-
|
112
|
+
if v["outer role"]
|
113
|
+
v["outer role"].each do |o|
|
114
|
+
attr_outerrole.merge!(@outerrole.get_attr(o))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
attr = attr_role.merge(attr_outerrole)
|
119
|
+
attr = attr.merge(attr_host)
|
120
|
+
|
121
|
+
logmesg = ""
|
122
|
+
if attr != {} && attr_host == {} && v["outer role"].size > 1
|
123
|
+
logmsg = "might not be given the appropriate attribute value, because #{host} have no attributes and belongs to more than one outer role - #{v["outer role"].join(", ")}"
|
124
|
+
@logger.warn(host) { message }
|
125
|
+
logmsg += "\n"
|
126
|
+
end
|
127
|
+
|
128
|
+
result = systemu(
|
129
|
+
command,
|
130
|
+
:env => {
|
131
|
+
"TARGET_HOST" => host,
|
132
|
+
"TARGET_HOST_ATTR" => JSON.generate(attr)
|
133
|
+
},
|
134
|
+
:cwd => File.join(@specdir, "..")
|
135
|
+
)
|
136
|
+
|
137
|
+
@logger.info(host) { "#{result[1]}\n#{result[2]}" }
|
138
|
+
failure = true if result[0] != 0
|
139
|
+
|
140
|
+
msg = result[1].scan(/\d* examples?, \d* failures?\n/).first
|
141
|
+
msg = msg ? msg.chomp : "error"
|
142
|
+
msg += "\t#{host} => #{v["spec"].join(", ")}\n"
|
143
|
+
puts msg if console_output
|
144
|
+
|
145
|
+
if ci
|
146
|
+
begin
|
147
|
+
post_result(result, role, host, v["spec"], command, logmsg)
|
148
|
+
rescue
|
149
|
+
ci = false
|
150
|
+
end
|
151
|
+
end
|
61
152
|
end
|
62
153
|
end
|
63
|
-
|
154
|
+
|
155
|
+
failure ? false : messages
|
64
156
|
end
|
65
157
|
|
66
158
|
|
67
|
-
|
68
|
-
|
159
|
+
private
|
160
|
+
def post_result(result, role, host, spec, command, message)
|
69
161
|
result_status = result[0] == 0 ? 1 : 2
|
70
162
|
|
71
|
-
|
72
|
-
|
163
|
+
ukigumo = Houcho::Config::UKIGUMO
|
164
|
+
ikachan = Houcho::Config::IKACHAN
|
165
|
+
git = Houcho::Config::GIT
|
166
|
+
|
167
|
+
if ukigumo["host"] != "" && ukigumo["port"] != "" && git["uri"]
|
168
|
+
u = CI::UkigumoClient.new(ukigumo["host"], ukigumo["port"])
|
169
|
+
ukigumo_report = u.post({
|
73
170
|
:status => result_status,
|
74
|
-
:project =>
|
75
|
-
:branch =>
|
76
|
-
:repo =>
|
77
|
-
:revision =>
|
171
|
+
:project => host.gsub(/\./, "-"),
|
172
|
+
:branch => role,
|
173
|
+
:repo => git["uri"],
|
174
|
+
:revision => spec.join(", "),
|
78
175
|
:vc_log => command,
|
79
|
-
:body => result[1],
|
176
|
+
:body => ( message || "" ) + result[1],
|
80
177
|
})
|
81
178
|
end
|
82
179
|
|
83
|
-
if
|
84
|
-
message
|
85
|
-
message += JSON.parse(ukigumo_report)[
|
86
|
-
CI::IkachanClient.new(
|
87
|
-
conf['ikachan']['channel'],
|
88
|
-
conf['ikachan']['host'],
|
89
|
-
conf['ikachan']['port']
|
90
|
-
).post(message)
|
91
|
-
end
|
92
|
-
end
|
180
|
+
if ikachan["host"] != "" && ikachan["port"] != "" && result_status != 1
|
181
|
+
message = "[serverspec fail] #{host} => #{spec.join(", ")}"
|
182
|
+
message += " (#{JSON.parse(ukigumo_report)["report"]["url"]})" if ukigumo_report
|
93
183
|
|
184
|
+
i = CI::IkachanClient.new(
|
185
|
+
ikachan["channel"],
|
186
|
+
ikachan["host"],
|
187
|
+
ikachan["port"]
|
188
|
+
)
|
94
189
|
|
95
|
-
|
96
|
-
specs = specs.flatten
|
97
|
-
error = []
|
98
|
-
messages = []
|
99
|
-
|
100
|
-
specs.each do |spec|
|
101
|
-
hosts = []
|
102
|
-
indexes = Spec.indexes(spec)
|
103
|
-
|
104
|
-
if indexes.empty?
|
105
|
-
error << spec
|
106
|
-
next
|
107
|
-
end
|
108
|
-
|
109
|
-
indexes.each do |index|
|
110
|
-
hosts += Host.elements(index)
|
111
|
-
CloudForecast::Role.elements(index).each do |cfrole|
|
112
|
-
hosts += CloudForecast::Host.new.hosts(cfrole)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
hosts.sample(host_count).each {|host| messages += exec([], [], [host], [spec], {}, dryrun)}
|
116
|
-
end
|
117
|
-
|
118
|
-
if error.empty?
|
119
|
-
messages
|
120
|
-
else
|
121
|
-
raise("role(#{error.join(',')}) has not attached to any roles")
|
190
|
+
i.post(message)
|
122
191
|
end
|
123
192
|
end
|
124
193
|
end
|
125
194
|
end
|
195
|
+
|
196
|
+
end
|
data/lib/houcho/spec.rb
CHANGED
@@ -1,6 +1,75 @@
|
|
1
|
+
require "houcho/role"
|
2
|
+
require "houcho/element"
|
3
|
+
require "houcho/config"
|
4
|
+
|
1
5
|
module Houcho
|
2
|
-
class
|
3
|
-
|
4
|
-
|
6
|
+
class SpecFileException < Exception; end
|
7
|
+
|
8
|
+
class Spec < Element
|
9
|
+
def initialize
|
10
|
+
super("serverspec")
|
11
|
+
@specdir = Houcho::Config::SPECDIR
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def check_existence(specs)
|
16
|
+
specs = [specs] unless specs.is_a?(Array)
|
17
|
+
files = specs.partition { |spec| File.exist?("#{@specdir}/#{spec}_spec.rb") }
|
18
|
+
raise SpecFileException, "No such spec file - #{files[1].join(",")}" unless files[1].empty?
|
19
|
+
|
20
|
+
files[0]
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def attach(specs, roles)
|
25
|
+
specs = [specs] unless specs.is_a?(Array)
|
26
|
+
roles = [roles] unless roles.is_a?(Array)
|
27
|
+
files = check_existence(specs)
|
28
|
+
|
29
|
+
super(files, roles)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def rename(from, to)
|
34
|
+
if File.exist?("#{@specdir}/#{to}_spec.rb")
|
35
|
+
raise SpecFileException, "spec file already exist - #{to}"
|
36
|
+
end
|
37
|
+
|
38
|
+
check_existence(from)
|
39
|
+
File.rename("#{@specdir}/#{from}_spec.rb", "#{@specdir}/#{to}_spec.rb")
|
40
|
+
@db.execute("UPDATE #{@type} SET name = ? WHERE name = ?", to, from)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def delete(specs, force = false)
|
45
|
+
specs = [specs] unless specs.is_a?(Array)
|
46
|
+
|
47
|
+
detach_from_all(specs) if force
|
48
|
+
|
49
|
+
@db.transaction do
|
50
|
+
|
51
|
+
specs.each do |spec|
|
52
|
+
begin
|
53
|
+
@db.execute("DELETE FROM #{@type} WHERE name = ?", spec)
|
54
|
+
rescue SQLite3::ConstraintException, "foreign key constraint failed"
|
55
|
+
raise SpecFileException, "spec file has been attached to role - #{spec}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end #end of transaction
|
60
|
+
|
61
|
+
begin
|
62
|
+
check_existence(specs).each do |spec|
|
63
|
+
File.delete("#{@specdir}/#{spec}_spec.rb")
|
64
|
+
end
|
65
|
+
rescue => e
|
66
|
+
raise e.class, "#{e.message}" unless force
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def delete!(specs, force = true)
|
72
|
+
delete(specs, true)
|
73
|
+
end
|
5
74
|
end
|
6
75
|
end
|
data/lib/houcho/version.rb
CHANGED