rubysdk 0.0.1.pre1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b68c1b1d1dd1f48ea982f1f78a1a2f9faf9bf4757cdd8b6e0abba92b1b408ca4
4
+ data.tar.gz: 24c597c5ce8ccc0e2c4fc8993e2644f0e730e1bc64559bb36dbb9c4f704bec71
5
+ SHA512:
6
+ metadata.gz: 3d06348ec15a34af4294e5697a26980a42aaa2bd5a939d7a9f3286bfa7e3b44bed6172cdf7bb445082ea41aa4e11d08e936f05c782045113d066d8519ec841de
7
+ data.tar.gz: 06750cacb7b562dc4b03195442928a8bde0b365bb43e8f733b4ad8a158d0e7782e433c6eafcb527bee14c7af6f56687a50ef6936ea19a7a250f37ff919363ed5
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Interface
4
+ class Job
5
+ attr_accessor :handler, :title, :desc, :dependson, :args, :interaction
6
+
7
+ def initialize(handler=nil, title="", desc="", dependson=[], args=[], interaction=nil)
8
+ @handler = handler
9
+ @title = title
10
+ @desc = desc
11
+ @dependson = dependson
12
+ @args = args
13
+ @interaction = interaction
14
+ end
15
+ end
16
+
17
+ class Argument
18
+ attr_accessor :desc, :type, :key, :value
19
+
20
+ def initialize(desc="", type=nil, key="", value="")
21
+ @desc = desc
22
+ @type = type
23
+ @key = key
24
+ @value = value
25
+ end
26
+ end
27
+
28
+ class ManualInteraction
29
+ attr_accessor :desc, :type, :value
30
+
31
+ def initialize(desc="", type=nil, value="")
32
+ @desc = desc
33
+ @type = type
34
+ @value = value
35
+ end
36
+ end
37
+
38
+ class JobsWrapper
39
+ attr_accessor :handler, :job
40
+
41
+ def initialize(handler=nil, job=nil)
42
+ @handler = handler
43
+ @job = job
44
+ end
45
+ end
46
+
47
+ class ErrorExitPipeline < StandardError
48
+ end
49
+ end
50
+
@@ -0,0 +1,42 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: plugin.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_message "proto.Job" do
8
+ optional :unique_id, :uint32, 1
9
+ optional :title, :string, 2
10
+ optional :description, :string, 3
11
+ repeated :dependson, :uint32, 4
12
+ repeated :args, :message, 5, "proto.Argument"
13
+ optional :interaction, :message, 6, "proto.ManualInteraction"
14
+ end
15
+ add_message "proto.Argument" do
16
+ optional :description, :string, 1
17
+ optional :type, :string, 2
18
+ optional :key, :string, 3
19
+ optional :value, :string, 4
20
+ end
21
+ add_message "proto.ManualInteraction" do
22
+ optional :description, :string, 1
23
+ optional :type, :string, 2
24
+ optional :value, :string, 3
25
+ end
26
+ add_message "proto.JobResult" do
27
+ optional :unique_id, :uint32, 1
28
+ optional :failed, :bool, 2
29
+ optional :exit_pipeline, :bool, 3
30
+ optional :message, :string, 4
31
+ end
32
+ add_message "proto.Empty" do
33
+ end
34
+ end
35
+
36
+ module Proto
37
+ Job = Google::Protobuf::DescriptorPool.generated_pool.lookup("proto.Job").msgclass
38
+ Argument = Google::Protobuf::DescriptorPool.generated_pool.lookup("proto.Argument").msgclass
39
+ ManualInteraction = Google::Protobuf::DescriptorPool.generated_pool.lookup("proto.ManualInteraction").msgclass
40
+ JobResult = Google::Protobuf::DescriptorPool.generated_pool.lookup("proto.JobResult").msgclass
41
+ Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("proto.Empty").msgclass
42
+ end
@@ -0,0 +1,33 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: plugin.proto for package 'proto'
3
+ # Original file comments:
4
+ # plugin.proto
5
+ # Defines the gRPC interface between gaia and the user defined
6
+ # pipelines (plugins). All rpc Methods are called from Gaia and
7
+ # executed in the plugin.
8
+ #
9
+
10
+ require 'grpc'
11
+ require 'plugin_pb'
12
+
13
+ module Proto
14
+ module Plugin
15
+ class Service
16
+
17
+ include GRPC::GenericService
18
+
19
+ self.marshal_class_method = :encode
20
+ self.unmarshal_class_method = :decode
21
+ self.service_name = 'proto.Plugin'
22
+
23
+ # GetJobs returns a stream of Job objects.
24
+ # Used to expose jobs to gaia.
25
+ rpc :GetJobs, Empty, stream(Job)
26
+ # ExecuteJob signals the plugin to execute the given job.
27
+ # Used to execute one job from a pipeline.
28
+ rpc :ExecuteJob, Job, JobResult
29
+ end
30
+
31
+ Stub = Service.rpc_stub_class
32
+ end
33
+ end
data/lib/rubysdk.rb ADDED
@@ -0,0 +1,169 @@
1
+ this_dir = File.expand_path(File.dirname(__FILE__))
2
+ proto_dir = File.join(this_dir, 'proto')
3
+ interface_dir = File.join(this_dir, 'interface')
4
+ $LOAD_PATH.unshift(proto_dir) unless $LOAD_PATH.include?(proto_dir)
5
+ $LOAD_PATH.unshift(interface_dir) unless $LOAD_PATH.include?(interface_dir)
6
+
7
+ require 'grpc'
8
+ require 'fnv'
9
+ require 'plugin_services_pb'
10
+ require 'interface'
11
+
12
+ module RubySDK
13
+ # GRPCServer provides an implementation of the Plugin service.
14
+ class GRPCServer < Proto::Plugin::Service
15
+ def initialize(cached_jobs)
16
+ @cached_jobs = cached_jobs
17
+ end
18
+
19
+ # GetJobs returns all registered jobs.
20
+ def GetJobs(empty)
21
+ @cached_jobs.each { |job| yield job.job }
22
+ end
23
+
24
+ # ExecuteJob executes the given job and returns a result.
25
+ def ExecuteJob(job)
26
+ cjob = nil
27
+ @cached_jobs.each do |cached_job|
28
+ cjob = cached_job unless cached_job.unique_id == job.unique_id
29
+ end
30
+ if cjob == nil
31
+ JobResult.new(failed: true,
32
+ exit_pipeline: true,
33
+ message: "job not found in plugin " + job.title)
34
+ return
35
+ end
36
+
37
+ # Transform arguments
38
+ args = []
39
+ job.args.each do |arg|
40
+ new_arg = Proto::Argument.new(key: arg.key,
41
+ value: arg.value)
42
+ args.push new_arg
43
+ end
44
+
45
+ # Execute job
46
+ job_result = JobResult.new
47
+ begin
48
+ job.handler.call(args)
49
+ rescue => e
50
+ # Check if job wants to force exit pipeline.
51
+ # We will exit the pipeline but not mark it as 'failed'.
52
+ job_result.failed = true unless e == ErrorExitPipeline
53
+
54
+ # Set log message and job id
55
+ job_result.exit_pipeline = true
56
+ job_result.message = e.message
57
+ job_result.unique_id = job.job.unique_id
58
+ end
59
+ end
60
+ end
61
+
62
+ # Serve caches the given jobs and starts the gRPC server.
63
+ # This function should be last called in the plugin main function.
64
+ def Serve(jobs)
65
+ include Interface
66
+
67
+ # Cache the jobs for later processing.
68
+ # We have to transform given jobs into suitable proto models.
69
+ cached_jobs = []
70
+ jobs.each do |job|
71
+ # Transform manual interaction
72
+ manual_interaction = nil
73
+ if job.interaction != nil
74
+ manual_interaction = ManualInteraction.new(description: job.interaction.desc,
75
+ type: job.interaction.type,
76
+ value: job.interaction.value)
77
+ end
78
+
79
+ # Transform arguments
80
+ args = []
81
+ if job.args != nil
82
+ job.args.each do |arg|
83
+ trans_arg = Proto::Argument.new(description: arg.desc,
84
+ type: arg.type,
85
+ key: arg.key,
86
+ value: arg.value)
87
+
88
+ args.push trans_arg
89
+ end
90
+ end
91
+
92
+ # Create proto job object
93
+ proto_job = Proto::Job.new(unique_id: FNV.new.fnv1a_32(job.title),
94
+ title: job.title,
95
+ description: job.title,
96
+ args: args,
97
+ interaction: manual_interaction)
98
+
99
+ # Resolve job dependencies
100
+ if job.dependson != nil
101
+ proto_job.dependson = Google::Protobuf::RepeatedField.new(:uint32, [])
102
+ job.dependson.each do |dep_job|
103
+ dep_found = false
104
+ jobs.each do |curr_job|
105
+ if curr_job.title.casecmp(dep_job) == 0
106
+ proto_job.dependson += FNV.new.fnv1a_32(curr_job.title)
107
+ dep_found = true
108
+ break
109
+ end
110
+ end
111
+
112
+ raise "job #{job.title} has dependency #{dep_job} which is not declared" unless dep_found == true
113
+ end
114
+ end
115
+
116
+ # Create wrapper object
117
+ wrapper_job = JobsWrapper.new(handler: job.handler,
118
+ job: proto_job)
119
+ cached_jobs.push wrapper_job
120
+ end
121
+
122
+ # Check if two jobs have the same title which is restricted.
123
+ #dup_map = {}
124
+ cached_jobs.each do |job|
125
+ #dup_map[job.job.unique_id] = (map[job.job.unique_id] || 0) + 1
126
+
127
+ #if dup_map[job.job.unique_id] > 1
128
+ # raise "duplicate job with the title #{job.title} found which is not allowed"
129
+ #end
130
+ end
131
+
132
+ # Get certificates path from env variables.
133
+ cert_path = ENV["GAIA_PLUGIN_CERT"]
134
+ key_path = ENV["GAIA_PLUGIN_KEY"]
135
+ root_ca_path = ENV["GAIA_PLUGIN_CA_CERT"]
136
+
137
+ # Check if all certs are available.
138
+ raise "cannot find path to certificate" unless File.file?(cert_path)
139
+ raise "cannot find path to key" unless File.file?(key_path)
140
+ raise "cannot find path to root CA certificate" unless File.file?(root_ca_path)
141
+
142
+ # Implement health service.
143
+ #health_svc = GRPC::Health::Checker.new
144
+ #health_svc.add_status("plugin", GRPC::Core::StatusCodes::SERVING)
145
+
146
+ # Load certificates and create credentials.
147
+ credentials = GRPC::Core::ServerCredentials.new(
148
+ File.read(root_ca_path),
149
+ [{
150
+ private_key: File.read(key_path),
151
+ cert_chain: File.read(cert_path)
152
+ }],
153
+ true # force client authentication.
154
+ )
155
+
156
+ # Register gRPC server and handle.
157
+ host = 'localhost'
158
+ s = GRPC::RpcServer.new
159
+ port = s.add_http2_port(host+':0', credentials)
160
+ s.handle(GRPCServer.new(cached_jobs))
161
+
162
+ # Output the address and service name to stdout.
163
+ # hashicorp go-plugin will use that to establish a connection.
164
+ puts "1|2|tcp|#{host}:#{port}|grpc"
165
+ STDOUT.sync = true
166
+
167
+ s.run_till_terminated
168
+ end
169
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubysdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.pre1
5
+ platform: ruby
6
+ authors:
7
+ - Michel Vocks
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: grpc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fnv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: grpc-tools
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.17'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.17'
55
+ description:
56
+ email: michelvocks@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/interface/interface.rb
62
+ - lib/proto/plugin_pb.rb
63
+ - lib/proto/plugin_services_pb.rb
64
+ - lib/rubysdk.rb
65
+ homepage: https://gaia-pipeline.io
66
+ licenses:
67
+ - Apache-2.0
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.3.1
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.7.6
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: Ruby SDK for Gaia pipelines (https://gaia-pipeline.io).
89
+ test_files: []