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,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