larrow-runner 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -5
- data/larrow-runner.gemspec +0 -3
- data/lib/active_support/core_ext/hash.rb +7 -0
- data/lib/active_support/core_ext/hash/compact.rb +20 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +38 -0
- data/lib/active_support/core_ext/hash/except.rb +15 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +23 -0
- data/lib/active_support/core_ext/hash/keys.rb +162 -0
- data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -0
- data/lib/active_support/core_ext/hash/slice.rb +42 -0
- data/lib/active_support/hash_with_indifferent_access.rb +272 -0
- data/lib/larrow/runner.rb +3 -3
- data/lib/larrow/runner/cli/tools.rb +5 -1
- data/lib/larrow/runner/errors.rb +2 -1
- data/lib/larrow/runner/logger.rb +2 -2
- data/lib/larrow/runner/manager.rb +10 -3
- data/lib/larrow/runner/manifest.rb +15 -4
- data/lib/larrow/runner/manifest/adapter/larrow.rb +28 -26
- data/lib/larrow/runner/manifest/adapter/travis.rb +53 -52
- data/lib/larrow/runner/manifest/base_loader.rb +18 -16
- data/lib/larrow/runner/manifest/configuration.rb +118 -116
- data/lib/larrow/runner/model/app.rb +4 -4
- data/lib/larrow/runner/model/node.rb +56 -56
- data/lib/larrow/runner/service/cloud.rb +10 -4
- data/lib/larrow/runner/session.rb +14 -11
- data/lib/larrow/runner/vcs/base.rb +14 -12
- data/lib/larrow/runner/vcs/github.rb +40 -38
- data/lib/larrow/runner/version.rb +1 -1
- metadata +11 -50
data/lib/larrow/runner.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'active_support/deprecation'
|
2
1
|
require 'active_support/core_ext/hash'
|
2
|
+
require 'active_support/core_ext/string'
|
3
3
|
|
4
4
|
require "larrow/runner/version"
|
5
5
|
require 'larrow/runner/logger'
|
@@ -18,8 +18,8 @@ module Larrow
|
|
18
18
|
end
|
19
19
|
# global options
|
20
20
|
RunOption = {}.with_indifferent_access
|
21
|
-
#
|
22
|
-
|
21
|
+
# default resource file path
|
22
|
+
ResourcePath = '.larrow.resource'
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -8,7 +8,11 @@ You can save it as .larrow.yml on the project root folder.
|
|
8
8
|
EOF
|
9
9
|
def dump url
|
10
10
|
vcs = Vcs.detect url
|
11
|
-
configuration =
|
11
|
+
configuration = Manifest.configuration(
|
12
|
+
vcs,
|
13
|
+
ignore_base_scripts: true,
|
14
|
+
ignore_larrow: true
|
15
|
+
)
|
12
16
|
puts configuration.dump
|
13
17
|
end
|
14
18
|
|
data/lib/larrow/runner/errors.rb
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
ExecutionError
|
1
|
+
ExecutionError = Class.new StandardError
|
2
|
+
InvalidConfigFile = Class.new StandardError
|
data/lib/larrow/runner/logger.rb
CHANGED
@@ -7,7 +7,7 @@ module Larrow::Runner
|
|
7
7
|
# logger.level(3).title 'hello'
|
8
8
|
# logger.level(3).detail 'hello'
|
9
9
|
class Logger
|
10
|
-
def initialize logger, level:nil, color:'
|
10
|
+
def initialize logger, level:nil, color:'green'
|
11
11
|
@inner_logger = if logger.is_a? ::Logger
|
12
12
|
logger
|
13
13
|
else
|
@@ -44,7 +44,7 @@ module Larrow::Runner
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def detail msg
|
47
|
-
color('
|
47
|
+
color('magenta').info msg
|
48
48
|
end
|
49
49
|
|
50
50
|
def err msg
|
@@ -45,6 +45,11 @@ module Larrow::Runner
|
|
45
45
|
|
46
46
|
def handle_exception
|
47
47
|
yield
|
48
|
+
rescue InvalidConfigFile => e
|
49
|
+
data = eval(e.message)
|
50
|
+
url = "https://github.com/fsword/larrow-runner/wiki/#{data[:wiki]}"
|
51
|
+
RunLogger.err "invalid config file: #{data[:file]}"
|
52
|
+
RunLogger.level(1).err "see: #{url}"
|
48
53
|
rescue => e
|
49
54
|
RunOption[:keep] = true if e.is_a?(ExecutionError)
|
50
55
|
if e.is_a?(ExecutionError) && !debug?
|
@@ -88,7 +93,7 @@ module Larrow::Runner
|
|
88
93
|
|
89
94
|
def self.resource
|
90
95
|
resource_iterator do |clazz, array|
|
91
|
-
RunLogger.
|
96
|
+
RunLogger.info clazz.name.split("::").last
|
92
97
|
clazz.show array, 1
|
93
98
|
end
|
94
99
|
end
|
@@ -101,14 +106,16 @@ module Larrow::Runner
|
|
101
106
|
end
|
102
107
|
|
103
108
|
def self.resource_iterator
|
104
|
-
|
105
|
-
|
109
|
+
RunLogger.title "load resource from #{ResourcePath}"
|
110
|
+
resource = YAML.load(File.read ResourcePath) rescue {}
|
111
|
+
|
106
112
|
resource.each_pair do |k,array|
|
107
113
|
case k
|
108
114
|
when :nodes
|
109
115
|
yield Model::Node, array
|
110
116
|
end
|
111
117
|
end
|
118
|
+
RunLogger.detail "no resource on the file" if resource.empty?
|
112
119
|
end
|
113
120
|
end
|
114
121
|
end
|
@@ -13,11 +13,22 @@ module Larrow
|
|
13
13
|
|
14
14
|
extend self
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
# options:
|
17
|
+
# :ignore_larrow : do not try to use larrow adapter
|
18
|
+
# :ignore_base_scripts : do not merge base scripts
|
19
|
+
def configuration source_accessor, options={}
|
20
|
+
adapters = [Travis, Blank]
|
21
|
+
adapters.unshift Larrow unless options[:ignore_larrow]
|
22
|
+
|
23
|
+
configuration = adapters.each do |clazz|
|
24
|
+
c = clazz.new(source_accessor).load
|
25
|
+
break c if c
|
26
|
+
end
|
27
|
+
|
28
|
+
unless options[:ignore_base_scripts]
|
29
|
+
add_base_scripts(configuration, source_accessor)
|
20
30
|
end
|
31
|
+
configuration
|
21
32
|
end
|
22
33
|
|
23
34
|
def add_base_scripts configuration,source_accessor
|
@@ -1,31 +1,33 @@
|
|
1
|
-
module Larrow::Runner
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
module Larrow::Runner
|
2
|
+
module Manifest
|
3
|
+
class Larrow < BaseLoader
|
4
|
+
def config_file
|
5
|
+
source_accessor.larrow_file || '.larrow.yml'
|
6
|
+
end
|
7
|
+
|
8
|
+
# TODO manifest validation
|
9
|
+
def parse content
|
10
|
+
data = YAML.load(content).with_indifferent_access
|
11
|
+
if data.is_a? Array # stages as a Array
|
12
|
+
# TODO
|
13
|
+
elsif data.is_a? Hash # steps as a Hash
|
14
|
+
configuration.image = data[:image]
|
15
|
+
Configuration::DEFINED_GROUPS[:custom].each do |title|
|
16
|
+
v = data[title]
|
17
|
+
build_step title,v if v
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
|
22
|
+
def build_step title, lines
|
23
|
+
source_dir = if title == :init
|
24
|
+
nil
|
25
|
+
else
|
26
|
+
configuration.source_dir
|
27
|
+
end
|
28
|
+
scripts = lines.map{|s| Script.new s, base_dir: source_dir}
|
29
|
+
configuration.put_to_step title, scripts
|
30
|
+
end
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
@@ -1,43 +1,44 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
|
-
module Larrow::Runner
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
3
|
+
module Larrow::Runner
|
4
|
+
module Manifest
|
5
|
+
class Travis < BaseLoader
|
6
|
+
CONFIG_FILE='.travis.yml'
|
7
|
+
attr_accessor :data
|
8
|
+
|
9
|
+
def parse content
|
10
|
+
self.data = YAML.load(content).with_indifferent_access
|
11
|
+
build_language
|
12
|
+
map_step :prepare, :before_script
|
13
|
+
map_step :functional_test, :script
|
14
|
+
end
|
15
|
+
|
16
|
+
def map_step title, travis_title
|
17
|
+
source_dir = configuration.source_dir
|
18
|
+
scripts = (data[travis_title] || []).map do |cmd|
|
19
|
+
Script.new cmd, base_dir: source_dir
|
20
|
+
end
|
21
|
+
return nil if scripts.empty?
|
22
|
+
|
23
|
+
configuration.put_to_step title, scripts
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_language
|
27
|
+
return if data[:language].nil?
|
28
|
+
clazz = eval data[:language].camelize
|
29
|
+
clazz.fulfill(data,configuration)
|
19
30
|
end
|
20
|
-
return nil if scripts.empty?
|
21
|
-
|
22
|
-
configuration.put_to_step title, scripts
|
23
|
-
end
|
24
|
-
|
25
|
-
def build_language
|
26
|
-
return if data[:language].nil?
|
27
|
-
clazz = eval data[:language].camelize
|
28
|
-
clazz.fulfill(data,configuration)
|
29
31
|
end
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
lines = <<-EOF
|
32
|
+
class Erlang
|
33
|
+
TEMPLATE_PATH='/opt/install/erlang/%s'
|
34
|
+
def self.fulfill data, configuration
|
35
|
+
revision = case data[:otp_release].last
|
36
|
+
when /R15/ then 'R15B03'
|
37
|
+
when /R16/ then 'R16B03'
|
38
|
+
when /17/ then '17.1'
|
39
|
+
end rescue '17'
|
40
|
+
install_dir = sprintf(TEMPLATE_PATH,revision.downcase)
|
41
|
+
lines = <<-EOF
|
41
42
|
echo '-s' >> .curlrc
|
42
43
|
curl https://raw.githubusercontent.com/spawngrid/kerl/master/kerl -o /usr/local/bin/kerl
|
43
44
|
chmod a+x /usr/local/bin/kerl
|
@@ -45,29 +46,29 @@ kerl update releases
|
|
45
46
|
kerl build #{revision} #{revision}
|
46
47
|
kerl install #{revision} #{install_dir}
|
47
48
|
echo 'source #{install_dir}/activate' >> $HOME/.bashrc
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
EOF
|
50
|
+
lines.split(/\n/).each do |line|
|
51
|
+
s = Script.new line
|
52
|
+
configuration.put_to_step :init, s
|
53
|
+
end
|
52
54
|
end
|
53
55
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
lines = <<-EOF
|
56
|
+
|
57
|
+
class Ruby
|
58
|
+
def self.fulfill data, configuration
|
59
|
+
return unless data[:rvm] # only rvm is supported for ruby
|
60
|
+
version = data[:rvm].last
|
61
|
+
lines = <<-EOF
|
61
62
|
echo '-s' >> .curlrc
|
62
63
|
curl -sSL https://get.rvm.io | bash -s stable
|
63
64
|
echo 'source /etc/profile.d/rvm.sh' >> .bashrc
|
64
65
|
rvm install #{version}
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
EOF
|
67
|
+
lines.split(/\n/).each do |line|
|
68
|
+
s = Script.new line
|
69
|
+
configuration.put_to_step :init, s
|
70
|
+
end
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
72
74
|
end
|
73
|
-
|
@@ -1,21 +1,23 @@
|
|
1
|
-
module Larrow::Runner
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module Larrow::Runner
|
2
|
+
module Manifest
|
3
|
+
class BaseLoader
|
4
|
+
attr_accessor :source_accessor,:configuration
|
5
|
+
def initialize source_accessor
|
6
|
+
self.source_accessor = source_accessor
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def load
|
10
|
+
content = source_accessor.get config_file
|
11
|
+
return nil if content.nil?
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
self.configuration = Configuration.new
|
14
|
+
parse content
|
15
|
+
self.configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
def config_file
|
19
|
+
self.class.const_get('CONFIG_FILE')
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
end
|
@@ -1,126 +1,128 @@
|
|
1
|
-
module Larrow::Runner
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
:
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
:
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
def put_to_step title, *scripts
|
39
|
-
steps[title] ||= CmdStep.new(nil, title)
|
40
|
-
steps[title].scripts += scripts.flatten
|
41
|
-
self
|
42
|
-
end
|
43
|
-
|
44
|
-
def insert_to_step title, *scripts
|
45
|
-
steps[title] ||= CmdStep.new(nil, title)
|
46
|
-
steps[title].scripts.unshift *scripts.flatten
|
47
|
-
self
|
48
|
-
end
|
49
|
-
|
50
|
-
def add_source_sync source_accessor
|
51
|
-
steps[:source_sync] = FunctionStep.new(:source_sync) do |node|
|
52
|
-
source_accessor.update_source node,source_dir
|
1
|
+
module Larrow::Runner
|
2
|
+
module Manifest
|
3
|
+
# The top of manifest model which store Steps information
|
4
|
+
class Configuration
|
5
|
+
DEFINED_GROUPS = {
|
6
|
+
all:[
|
7
|
+
:init,
|
8
|
+
:source_sync, #inner step
|
9
|
+
:prepare,
|
10
|
+
:compile, :unit_test,
|
11
|
+
:before_install, #inner_step
|
12
|
+
:install, :functional_test,
|
13
|
+
:before_start, #inner_step
|
14
|
+
:start, :integration_test,
|
15
|
+
:after_start, :complete #inner_step
|
16
|
+
],
|
17
|
+
custom: [
|
18
|
+
:init,
|
19
|
+
:prepare,
|
20
|
+
:compile, :unit_test,
|
21
|
+
:install, :functional_test,
|
22
|
+
:start, :integration_test,
|
23
|
+
],
|
24
|
+
deploy: [
|
25
|
+
:init,:source_sync,:prepare,
|
26
|
+
:compile,:before_install,:install,
|
27
|
+
:before_start,:start,:after_start,
|
28
|
+
:complete
|
29
|
+
],
|
30
|
+
image: [:init]
|
31
|
+
}
|
32
|
+
|
33
|
+
attr_accessor :steps, :image, :source_dir
|
34
|
+
def initialize
|
35
|
+
self.steps = {}
|
36
|
+
self.source_dir = '$HOME/source'
|
53
37
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
groups = groups - [:init] if image
|
60
|
-
groups.each do |title|
|
61
|
-
yield steps[title] if steps[title]
|
38
|
+
|
39
|
+
def put_to_step title, *scripts
|
40
|
+
steps[title] ||= CmdStep.new(nil, title)
|
41
|
+
steps[title].scripts += scripts.flatten
|
42
|
+
self
|
62
43
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
scripts_data = steps[title].scripts.map(&:dump).compact
|
69
|
-
sum.update title.to_s => scripts_data
|
44
|
+
|
45
|
+
def insert_to_step title, *scripts
|
46
|
+
steps[title] ||= CmdStep.new(nil, title)
|
47
|
+
steps[title].scripts.unshift *scripts.flatten
|
48
|
+
self
|
70
49
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
50
|
+
|
51
|
+
def add_source_sync source_accessor
|
52
|
+
steps[:source_sync] = FunctionStep.new(:source_sync) do |node|
|
53
|
+
source_accessor.update_source node,source_dir
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def steps_for type
|
58
|
+
groups = DEFINED_GROUPS[type]
|
59
|
+
# ignore init when image id is specified
|
60
|
+
groups = groups - [:init] if image
|
61
|
+
groups.each do |title|
|
62
|
+
yield steps[title] if steps[title]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def dump
|
67
|
+
data = DEFINED_GROUPS[:all].reduce({}) do |sum,title|
|
68
|
+
next sum if steps[title].nil?
|
69
|
+
scripts_data = steps[title].scripts.map(&:dump).compact
|
70
|
+
sum.update title.to_s => scripts_data
|
71
|
+
end
|
72
|
+
YAML.dump data
|
86
73
|
end
|
87
74
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
block.call node
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# store the real command line
|
107
|
-
# :cannt_fail used to declare `non-zero retcode of current script will be fail`
|
108
|
-
class Script
|
109
|
-
attr_accessor :cmd, :base_dir, :args, :cannt_fail
|
110
|
-
def initialize cmd, base_dir:nil, args:{}, cannt_fail: true
|
111
|
-
self.cmd = cmd
|
112
|
-
self.args = args
|
113
|
-
self.cannt_fail = cannt_fail
|
114
|
-
self.base_dir = base_dir
|
75
|
+
|
76
|
+
# Describe a set of scripts to accomplish a specific goal
|
77
|
+
class CmdStep
|
78
|
+
attr_accessor :scripts, :title
|
79
|
+
def initialize scripts, title
|
80
|
+
self.scripts = scripts || []
|
81
|
+
self.title = title
|
82
|
+
end
|
83
|
+
|
84
|
+
def run_on node
|
85
|
+
scripts.each do |script|
|
86
|
+
node.execute script.actual_command, base_dir: script.base_dir
|
87
|
+
end
|
88
|
+
end
|
115
89
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
90
|
+
|
91
|
+
# An abstract step which bind business logic with block
|
92
|
+
# This class designed for some typically service,eg:
|
93
|
+
# * local file folder sync
|
94
|
+
# * some service invoke
|
95
|
+
class FunctionStep
|
96
|
+
attr_accessor :block, :title
|
97
|
+
def initialize title, &block
|
98
|
+
self.title = title
|
99
|
+
self.block = block
|
100
|
+
end
|
101
|
+
|
102
|
+
def run_on node
|
103
|
+
block.call node
|
104
|
+
end
|
119
105
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
106
|
+
|
107
|
+
# store the real command line
|
108
|
+
# :cannt_fail used to declare `non-zero retcode of current script will be fail`
|
109
|
+
class Script
|
110
|
+
attr_accessor :cmd, :base_dir, :args, :cannt_fail
|
111
|
+
def initialize cmd, base_dir:nil, args:{}, cannt_fail: true
|
112
|
+
self.cmd = cmd
|
113
|
+
self.args = args
|
114
|
+
self.cannt_fail = cannt_fail
|
115
|
+
self.base_dir = base_dir
|
116
|
+
end
|
117
|
+
|
118
|
+
def actual_command
|
119
|
+
sprintf(cmd, args)
|
120
|
+
end
|
121
|
+
|
122
|
+
def dump
|
123
|
+
return nil if cmd.empty?
|
124
|
+
cmd
|
125
|
+
end
|
124
126
|
end
|
125
127
|
end
|
126
128
|
end
|