factor 0.6.3 → 0.6.4
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/bin/factor +1 -1
- data/lib/{factor.rb → commands.rb} +8 -8
- data/lib/commands/base.rb +6 -64
- data/lib/commands/{registry.rb → registry_command.rb} +1 -1
- data/lib/commands/{workflows.rb → workflow_command.rb} +25 -34
- data/lib/common/deep_struct.rb +48 -0
- data/lib/factor/version.rb +1 -1
- data/lib/logger/basic.rb +68 -0
- data/lib/logger/logger.rb +28 -0
- data/lib/runtime/exec_handler.rb +16 -0
- data/lib/runtime/service_address.rb +46 -0
- data/lib/runtime/service_caller.rb +105 -0
- data/lib/runtime/workflow.rb +170 -0
- data/lib/websocket_manager.rb +2 -1
- data/spec/spec_helper.rb +0 -7
- metadata +14 -17
- data/lib/listener.rb +0 -26
- data/lib/runtime.rb +0 -232
- data/spec/base_spec.rb +0 -102
- data/spec/listener_spec.rb +0 -9
- data/spec/registry_spec.rb +0 -0
- data/spec/workflow_spec.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26eb148636a08597d3d15057a3536d5b1780f9c8
|
4
|
+
data.tar.gz: 87b420da894fa98fd2f9e151982a63008ea452cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90c063260db5e9fc933991d4bedfb17b52c52e1908f5fbb0a1ab53fd5acfbf03eca4027947b99c854aea968fbfd732f7db69d3d1096c2fe6783be2a37e665d37
|
7
|
+
data.tar.gz: fb996d555b5542c5dda46e198e2fb84cf8a642308843a4d4edaa2946f4985e3ff68b5058b4fa495c952fc18a832acddc47f04406b469415bce1536002278bb58
|
data/bin/factor
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
require 'commander/import'
|
4
4
|
|
5
5
|
require 'factor/version'
|
6
|
-
require 'commands/
|
7
|
-
require 'commands/
|
6
|
+
require 'commands/workflow_command'
|
7
|
+
require 'commands/registry_command'
|
8
8
|
|
9
9
|
program :name, 'Factor.io Server'
|
10
10
|
program :version, Factor::VERSION
|
@@ -17,20 +17,20 @@ command 'server' do |c|
|
|
17
17
|
c.option '--credentials FILE', String, 'credentials.yml file path.'
|
18
18
|
c.option '--connectors FILE', String, 'connectors.yml file path'
|
19
19
|
c.option '--path FILE', String, 'Path to workflows'
|
20
|
-
c.when_called Factor::Commands::
|
20
|
+
c.when_called Factor::Commands::WorkflowCommand, :server
|
21
21
|
end
|
22
22
|
|
23
23
|
command 'cloud' do |c|
|
24
24
|
c.syntax = 'factor host <account id> <workflow id> <api key>'
|
25
25
|
c.description = 'Start the Factor.io Server using your workflows and credentials from Factor.io Cloud'
|
26
26
|
c.option '--host URL', String, 'Use non-default Cloud service provider (e.g. pro server)'
|
27
|
-
c.when_called Factor::Commands::
|
27
|
+
c.when_called Factor::Commands::WorkflowCommand, :cloud
|
28
28
|
end
|
29
29
|
|
30
30
|
command 'registry workflows' do |c|
|
31
31
|
c.syntax = 'factor registry workflows'
|
32
32
|
c.description = 'Get list of available workflow jumpstarts'
|
33
|
-
c.when_called Factor::Commands::
|
33
|
+
c.when_called Factor::Commands::RegistryCommand, :workflows
|
34
34
|
end
|
35
35
|
|
36
36
|
command 'registry workflows add' do |c|
|
@@ -39,13 +39,13 @@ command 'registry workflows add' do |c|
|
|
39
39
|
c.option '--credentials FILE', String, 'credentials.yml file path.'
|
40
40
|
c.option '--connectors FILE', String, 'connectors.yml file path'
|
41
41
|
c.option '--values \'{"api_key":"foo"}\'', String, "{}"
|
42
|
-
c.when_called Factor::Commands::
|
42
|
+
c.when_called Factor::Commands::RegistryCommand, :add_workflow
|
43
43
|
end
|
44
44
|
|
45
45
|
command 'registry connectors' do |c|
|
46
46
|
c.syntax = 'factor registry connectors'
|
47
47
|
c.description = 'Get list of available connectors'
|
48
|
-
c.when_called Factor::Commands::
|
48
|
+
c.when_called Factor::Commands::RegistryCommand, :connectors
|
49
49
|
end
|
50
50
|
|
51
51
|
command 'registry connector add' do |c|
|
@@ -54,7 +54,7 @@ command 'registry connector add' do |c|
|
|
54
54
|
c.option '--credentials FILE', String, 'credentials.yml file path.'
|
55
55
|
c.option '--connectors FILE', String, 'connectors.yml file path'
|
56
56
|
c.option '--values \'{"api_key":"foo"}\'', String, "{}"
|
57
|
-
c.when_called Factor::Commands::
|
57
|
+
c.when_called Factor::Commands::RegistryCommand, :add_connector
|
58
58
|
end
|
59
59
|
|
60
60
|
alias_command 's', 'server'
|
data/lib/commands/base.rb
CHANGED
@@ -4,40 +4,21 @@ require 'colored'
|
|
4
4
|
require 'configatron'
|
5
5
|
require 'yaml'
|
6
6
|
require 'fileutils'
|
7
|
+
require 'logger/basic'
|
7
8
|
|
8
9
|
module Factor
|
9
10
|
module Commands
|
10
11
|
# Base command with common methods used by all commands
|
11
12
|
class Command
|
13
|
+
attr_accessor :logger
|
14
|
+
|
12
15
|
DEFAULT_FILENAME = {
|
13
16
|
connectors: File.expand_path('./connectors.yml'),
|
14
17
|
credentials: File.expand_path('./credentials.yml')
|
15
18
|
}
|
16
19
|
|
17
|
-
|
18
|
-
|
19
|
-
def info(options = {})
|
20
|
-
log_line :info, options
|
21
|
-
end
|
22
|
-
|
23
|
-
def error(options = {})
|
24
|
-
log_line :error, options
|
25
|
-
end
|
26
|
-
|
27
|
-
def warn(options = {})
|
28
|
-
log_line :warn, options
|
29
|
-
end
|
30
|
-
|
31
|
-
def success(options = {})
|
32
|
-
log_line :success, options
|
33
|
-
end
|
34
|
-
|
35
|
-
def exception(message, exception)
|
36
|
-
error 'message' => message
|
37
|
-
error 'message' => " #{exception.message}"
|
38
|
-
exception.backtrace.each do |line|
|
39
|
-
error 'message' => " #{line}"
|
40
|
-
end
|
20
|
+
def initialize
|
21
|
+
@logger = Factor::Log::BasicLogger.new
|
41
22
|
end
|
42
23
|
|
43
24
|
def load_config(options = {})
|
@@ -77,46 +58,7 @@ module Factor
|
|
77
58
|
end
|
78
59
|
configatron[config_type].configure_from_hash(data)
|
79
60
|
rescue => ex
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
def log_line(section, options = {})
|
84
|
-
options = { message: options } if options.is_a?(String)
|
85
|
-
tag = tag(options)
|
86
|
-
message = options['message'] || options[:message]
|
87
|
-
section_text = format_section(section)
|
88
|
-
write "[ #{section_text} ] [#{time}]#{tag} #{message}" if message
|
89
|
-
end
|
90
|
-
|
91
|
-
def format_section(section)
|
92
|
-
formated_section = section.to_s.upcase.center(10)
|
93
|
-
case section
|
94
|
-
when :error then formated_section.red
|
95
|
-
when :info then formated_section.bold
|
96
|
-
when :warn then formated_section.yellow
|
97
|
-
when :success then formated_section.green
|
98
|
-
else formated_section
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def tag(options)
|
103
|
-
primary = options['service_id'] || options['instance_id']
|
104
|
-
secondary = if options['service_id'] && options['instance_id']
|
105
|
-
":#{options['instane_id']}"
|
106
|
-
else
|
107
|
-
''
|
108
|
-
end
|
109
|
-
primary ? "[#{primary}#{secondary}]" : ''
|
110
|
-
end
|
111
|
-
|
112
|
-
def time
|
113
|
-
Time.now.localtime.strftime('%m/%d/%y %T.%L')
|
114
|
-
end
|
115
|
-
|
116
|
-
def write(message)
|
117
|
-
stream = @destination_stream || $stdout
|
118
|
-
stream.puts(message)
|
119
|
-
stream.flush
|
61
|
+
logger.error "Couldn't load #{config_type} from #{absolute_path}", exception:ex
|
120
62
|
end
|
121
63
|
end
|
122
64
|
end
|
@@ -10,7 +10,7 @@ require 'commands/base'
|
|
10
10
|
module Factor
|
11
11
|
module Commands
|
12
12
|
# Workflow is a Command to start the factor runtime from the CLI
|
13
|
-
class
|
13
|
+
class RegistryCommand < Factor::Commands::Command
|
14
14
|
|
15
15
|
def workflows(args, options)
|
16
16
|
list = get_yaml_data 'https://raw.githubusercontent.com/factor-io/index/master/workflows.yml'
|
@@ -3,14 +3,15 @@
|
|
3
3
|
require 'configatron'
|
4
4
|
|
5
5
|
require 'commands/base'
|
6
|
-
require 'runtime'
|
6
|
+
require 'runtime/workflow'
|
7
7
|
|
8
8
|
module Factor
|
9
9
|
module Commands
|
10
10
|
# Workflow is a Command to start the factor runtime from the CLI
|
11
|
-
class
|
11
|
+
class WorkflowCommand < Factor::Commands::Command
|
12
12
|
def initialize
|
13
13
|
@workflows = {}
|
14
|
+
super
|
14
15
|
end
|
15
16
|
|
16
17
|
def server(_args, options)
|
@@ -23,7 +24,7 @@ module Factor
|
|
23
24
|
load_config(config_settings)
|
24
25
|
load_all_workflows(workflow_filename)
|
25
26
|
block_until_interupt
|
26
|
-
info 'Good bye!'
|
27
|
+
logger.info 'Good bye!'
|
27
28
|
end
|
28
29
|
|
29
30
|
def cloud(args, options)
|
@@ -31,35 +32,35 @@ module Factor
|
|
31
32
|
host = (options.host || "https://factor.io").sub(/(\/)+$/,'')
|
32
33
|
|
33
34
|
if !api_key || !workflow_id || !account_id
|
34
|
-
error "API Key, Worklfow ID and Acount ID are all required"
|
35
|
+
logger.error "API Key, Worklfow ID and Acount ID are all required"
|
35
36
|
exit
|
36
37
|
end
|
37
38
|
|
38
|
-
info "Getting workflow (#{workflow_id}) from Factor.io Cloud"
|
39
|
+
logger.info "Getting workflow (#{workflow_id}) from Factor.io Cloud"
|
39
40
|
begin
|
40
41
|
workflow_url = "#{host}/#{account_id}/workflows/#{workflow_id}.json?auth_token=#{api_key}"
|
41
42
|
raw_content = RestClient.get(workflow_url)
|
42
43
|
workflow_info = JSON.parse(raw_content)
|
43
44
|
rescue => ex
|
44
|
-
error "Couldn't retreive workflow: #{ex.message}"
|
45
|
+
logger.error "Couldn't retreive workflow: #{ex.message}"
|
45
46
|
exit
|
46
47
|
end
|
47
48
|
|
48
49
|
workflow_definition = workflow_info["definition"]
|
49
50
|
|
50
|
-
info "Getting credentials from Factor.io Cloud"
|
51
|
+
logger.info "Getting credentials from Factor.io Cloud"
|
51
52
|
begin
|
52
53
|
credential_url = "#{host}/#{account_id}/credentials.json?auth_token=#{api_key}"
|
53
54
|
raw_content = RestClient.get(credential_url)
|
54
55
|
credentials = JSON.parse(raw_content)
|
55
56
|
rescue => ex
|
56
|
-
error "Couldn't retreive workflow: #{ex.message}"
|
57
|
+
logger.error "Couldn't retreive workflow: #{ex.message}"
|
57
58
|
exit
|
58
59
|
end
|
59
60
|
|
60
61
|
configatron[:credentials].configure_from_hash(credentials)
|
61
62
|
|
62
|
-
info "Getting connectors from Factor.io Cloud"
|
63
|
+
logger.info "Getting connectors from Factor.io Cloud"
|
63
64
|
connectors = {}
|
64
65
|
begin
|
65
66
|
connectors_url = "#{host}/#{account_id}/connectors.json?auth_token=#{api_key}"
|
@@ -70,7 +71,7 @@ module Factor
|
|
70
71
|
connectors[connector_id] = connector_info['connectors'].values.first
|
71
72
|
end
|
72
73
|
rescue => ex
|
73
|
-
error "Couldn't retreive workflow: #{ex.message}"
|
74
|
+
logger.error "Couldn't retreive workflow: #{ex.message}"
|
74
75
|
exit
|
75
76
|
end
|
76
77
|
|
@@ -80,7 +81,7 @@ module Factor
|
|
80
81
|
|
81
82
|
block_until_interupt
|
82
83
|
|
83
|
-
info 'Good bye!'
|
84
|
+
logger.info 'Good bye!'
|
84
85
|
end
|
85
86
|
|
86
87
|
private
|
@@ -90,22 +91,22 @@ module Factor
|
|
90
91
|
glob = "#{workflow_filename}#{glob_ending}*.rb"
|
91
92
|
file_list = Dir.glob(glob)
|
92
93
|
if !file_list.all? { |file| File.file?(file) }
|
93
|
-
error "#{workflow_filename} is neither a file or directory"
|
94
|
+
logger.error "#{workflow_filename} is neither a file or directory"
|
94
95
|
elsif file_list.count == 0
|
95
|
-
error 'No workflows in this directory to run'
|
96
|
+
logger.error 'No workflows in this directory to run'
|
96
97
|
else
|
97
98
|
file_list.each { |filename| load_workflow(File.expand_path(filename)) }
|
98
99
|
end
|
99
100
|
end
|
100
101
|
|
101
102
|
def block_until_interupt
|
102
|
-
info 'Ctrl-c to exit'
|
103
|
+
logger.info 'Ctrl-c to exit'
|
103
104
|
begin
|
104
105
|
loop do
|
105
106
|
sleep 1
|
106
107
|
end
|
107
108
|
rescue Interrupt
|
108
|
-
info 'Exiting app...'
|
109
|
+
logger.info 'Exiting app...'
|
109
110
|
ensure
|
110
111
|
@workflows.keys.each { |workflow_id| unload_workflow(workflow_id) }
|
111
112
|
end
|
@@ -113,11 +114,11 @@ module Factor
|
|
113
114
|
|
114
115
|
def load_workflow(workflow_filename)
|
115
116
|
# workflow_filename = File.expand_path(filename)
|
116
|
-
info "Loading workflow from #{workflow_filename}"
|
117
|
+
logger.info "Loading workflow from #{workflow_filename}"
|
117
118
|
begin
|
118
119
|
workflow_definition = File.read(workflow_filename)
|
119
120
|
rescue => ex
|
120
|
-
|
121
|
+
logger.error "Couldn't read file #{workflow_filename}", exception:ex
|
121
122
|
return
|
122
123
|
end
|
123
124
|
|
@@ -125,23 +126,22 @@ module Factor
|
|
125
126
|
end
|
126
127
|
|
127
128
|
def load_workflow_from_definition(workflow_definition)
|
128
|
-
info "Setting up workflow processor"
|
129
|
+
logger.info "Setting up workflow processor"
|
129
130
|
begin
|
130
131
|
connector_settings = configatron.connectors.to_hash
|
131
132
|
credential_settings = configatron.credentials.to_hash
|
132
|
-
runtime = Runtime.new(connector_settings, credential_settings)
|
133
|
-
runtime.logger = method(:log_message)
|
133
|
+
runtime = Factor::Runtime::Workflow.new(connector_settings, credential_settings, logger: logger)
|
134
134
|
rescue => ex
|
135
|
-
message = "Couldn't setup workflow process
|
136
|
-
|
135
|
+
message = "Couldn't setup workflow process"
|
136
|
+
logger.error message:message, exception:ex
|
137
137
|
end
|
138
138
|
|
139
139
|
workflow_thread = fork do
|
140
140
|
begin
|
141
|
-
info "Starting workflow"
|
141
|
+
logger.info "Starting workflow"
|
142
142
|
runtime.load(workflow_definition)
|
143
143
|
rescue => ex
|
144
|
-
|
144
|
+
logger.error message: "Couldn't workflow", exception: ex
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
@@ -149,18 +149,9 @@ module Factor
|
|
149
149
|
end
|
150
150
|
|
151
151
|
def unload_workflow(workflow_id)
|
152
|
-
info "Stopping #{workflow_id}"
|
152
|
+
logger.info "Stopping #{workflow_id}"
|
153
153
|
Process.kill('SIGINT', @workflows[workflow_id])
|
154
154
|
end
|
155
|
-
|
156
|
-
def log_message(message_info)
|
157
|
-
case message_info['status']
|
158
|
-
when 'info' then info message_info
|
159
|
-
when 'success' then success message_info
|
160
|
-
when 'warn' then warn message_info
|
161
|
-
else error message_info
|
162
|
-
end
|
163
|
-
end
|
164
155
|
end
|
165
156
|
end
|
166
157
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Factor
|
4
|
+
module Common
|
5
|
+
class DeepStruct < OpenStruct
|
6
|
+
def initialize(hash=nil)
|
7
|
+
@table = {}
|
8
|
+
@hash_table = {}
|
9
|
+
|
10
|
+
if hash
|
11
|
+
hash.each do |k,v|
|
12
|
+
@table[k.to_sym] = (v.is_a?(Hash) ? self.class.new(v) : v)
|
13
|
+
@hash_table[k.to_sym] = v
|
14
|
+
|
15
|
+
new_ostruct_member(k)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_h
|
21
|
+
@hash_table
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](idx)
|
25
|
+
hash = marshal_dump
|
26
|
+
hash[idx.to_sym]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.flat_hash(h,f=[],g={})
|
31
|
+
return g.update({ f=>h }) unless h.is_a? Hash
|
32
|
+
h.each { |k,r| flat_hash(r,f+[k],g) }
|
33
|
+
g
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.simple_object_convert(item)
|
37
|
+
if item.is_a?(Hash)
|
38
|
+
Factor::Common::DeepStruct.new(item)
|
39
|
+
elsif item.is_a?(Array)
|
40
|
+
item.map do |i|
|
41
|
+
simple_object_convert(i)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
item
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/factor/version.rb
CHANGED
data/lib/logger/basic.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative './logger.rb'
|
2
|
+
|
3
|
+
module Factor
|
4
|
+
module Log
|
5
|
+
class BasicLogger < Factor::Log::Logger
|
6
|
+
|
7
|
+
attr_accessor :destination_stream
|
8
|
+
|
9
|
+
def log(section, options={})
|
10
|
+
options = { message: options } if options.is_a?(String)
|
11
|
+
tag = tag(options)
|
12
|
+
message = options['message'] || options[:message]
|
13
|
+
section_text = format_section(section)
|
14
|
+
write "[ #{section_text} ] [#{time}]#{tag} #{message}" if message
|
15
|
+
exception options[:exception] if options[:exception]
|
16
|
+
end
|
17
|
+
|
18
|
+
def info(options = {})
|
19
|
+
log :info, options
|
20
|
+
end
|
21
|
+
|
22
|
+
def warn(options = {})
|
23
|
+
log :warn, options
|
24
|
+
end
|
25
|
+
|
26
|
+
def error(options = {})
|
27
|
+
log :error, options
|
28
|
+
end
|
29
|
+
|
30
|
+
def success(options = {})
|
31
|
+
log :success, options
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def exception(exception)
|
37
|
+
error message: " #{exception.message}"
|
38
|
+
exception.backtrace.each do |line|
|
39
|
+
error message: " #{line}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def format_section(section)
|
44
|
+
formated_section = section.to_s.upcase.center(10)
|
45
|
+
case section.to_sym
|
46
|
+
when :error then formated_section.red
|
47
|
+
when :info then formated_section.bold
|
48
|
+
when :warn then formated_section.yellow
|
49
|
+
when :success then formated_section.green
|
50
|
+
else formated_section
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def tag(options)
|
55
|
+
primary = options['service_id'] || options['instance_id']
|
56
|
+
secondary = ":#{options['instane_id']}" if options['service_id'] && options['instance_id']
|
57
|
+
primary ? "[#{primary}#{secondary || ''}]" : ''
|
58
|
+
end
|
59
|
+
|
60
|
+
def write(message)
|
61
|
+
stream = @destination_stream || $stdout
|
62
|
+
stream.puts(message)
|
63
|
+
stream.flush
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|