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 +7 -0
- data/lib/interface/interface.rb +50 -0
- data/lib/proto/plugin_pb.rb +42 -0
- data/lib/proto/plugin_services_pb.rb +33 -0
- data/lib/rubysdk.rb +169 -0
- metadata +89 -0
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: []
|