cyclid 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +174 -0
- data/README.md +54 -0
- data/app/cyclid.rb +61 -0
- data/app/cyclid/config.rb +38 -0
- data/app/cyclid/controllers.rb +123 -0
- data/app/cyclid/controllers/auth.rb +34 -0
- data/app/cyclid/controllers/auth/token.rb +78 -0
- data/app/cyclid/controllers/health.rb +96 -0
- data/app/cyclid/controllers/organizations.rb +104 -0
- data/app/cyclid/controllers/organizations/collection.rb +134 -0
- data/app/cyclid/controllers/organizations/config.rb +128 -0
- data/app/cyclid/controllers/organizations/document.rb +135 -0
- data/app/cyclid/controllers/organizations/job.rb +266 -0
- data/app/cyclid/controllers/organizations/members.rb +145 -0
- data/app/cyclid/controllers/organizations/stages.rb +251 -0
- data/app/cyclid/controllers/users.rb +47 -0
- data/app/cyclid/controllers/users/collection.rb +131 -0
- data/app/cyclid/controllers/users/document.rb +133 -0
- data/app/cyclid/health_helpers.rb +40 -0
- data/app/cyclid/job.rb +3 -0
- data/app/cyclid/job/helpers.rb +67 -0
- data/app/cyclid/job/job.rb +164 -0
- data/app/cyclid/job/runner.rb +275 -0
- data/app/cyclid/job/stage.rb +67 -0
- data/app/cyclid/log_buffer.rb +104 -0
- data/app/cyclid/models.rb +3 -0
- data/app/cyclid/models/job_record.rb +25 -0
- data/app/cyclid/models/organization.rb +64 -0
- data/app/cyclid/models/plugin_config.rb +25 -0
- data/app/cyclid/models/stage.rb +42 -0
- data/app/cyclid/models/step.rb +29 -0
- data/app/cyclid/models/user.rb +60 -0
- data/app/cyclid/models/user_permissions.rb +28 -0
- data/app/cyclid/monkey_patches.rb +37 -0
- data/app/cyclid/plugin_registry.rb +75 -0
- data/app/cyclid/plugins.rb +125 -0
- data/app/cyclid/plugins/action.rb +48 -0
- data/app/cyclid/plugins/action/command.rb +89 -0
- data/app/cyclid/plugins/action/email.rb +207 -0
- data/app/cyclid/plugins/action/email/html.erb +58 -0
- data/app/cyclid/plugins/action/email/text.erb +13 -0
- data/app/cyclid/plugins/action/script.rb +90 -0
- data/app/cyclid/plugins/action/slack.rb +129 -0
- data/app/cyclid/plugins/action/slack/note.erb +5 -0
- data/app/cyclid/plugins/api.rb +195 -0
- data/app/cyclid/plugins/api/github.rb +111 -0
- data/app/cyclid/plugins/api/github/callback.rb +66 -0
- data/app/cyclid/plugins/api/github/methods.rb +201 -0
- data/app/cyclid/plugins/api/github/status.rb +67 -0
- data/app/cyclid/plugins/builder.rb +80 -0
- data/app/cyclid/plugins/builder/mist.rb +107 -0
- data/app/cyclid/plugins/dispatcher.rb +89 -0
- data/app/cyclid/plugins/dispatcher/local.rb +167 -0
- data/app/cyclid/plugins/provisioner.rb +40 -0
- data/app/cyclid/plugins/provisioner/debian.rb +90 -0
- data/app/cyclid/plugins/provisioner/ubuntu.rb +98 -0
- data/app/cyclid/plugins/source.rb +39 -0
- data/app/cyclid/plugins/source/git.rb +64 -0
- data/app/cyclid/plugins/transport.rb +63 -0
- data/app/cyclid/plugins/transport/ssh.rb +155 -0
- data/app/cyclid/sinatra/api_helpers.rb +66 -0
- data/app/cyclid/sinatra/auth_helpers.rb +127 -0
- data/app/cyclid/sinatra/warden/strategies/api_token.rb +62 -0
- data/app/cyclid/sinatra/warden/strategies/basic.rb +58 -0
- data/app/cyclid/sinatra/warden/strategies/hmac.rb +76 -0
- data/app/db.rb +51 -0
- data/bin/cyclid-db-init +107 -0
- data/db/schema.rb +92 -0
- data/lib/cyclid/app.rb +4 -0
- metadata +407 -0
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Plugins
|
21
|
+
module Plugins
|
22
|
+
# Ubuntu provisioner
|
23
|
+
class Ubuntu < Provisioner
|
24
|
+
# Prepare an Ubuntu based build host
|
25
|
+
def prepare(transport, buildhost, env = {})
|
26
|
+
transport.export_env('DEBIAN_FRONTEND' => 'noninteractive')
|
27
|
+
|
28
|
+
if env.key? :repos
|
29
|
+
env[:repos].each do |repo|
|
30
|
+
next unless repo.key? :url
|
31
|
+
|
32
|
+
# Check if it's a PPA, or a traditional repository
|
33
|
+
url = repo[:url]
|
34
|
+
match = url.match(/\A(ppa|http|https):.*\Z/)
|
35
|
+
next unless match
|
36
|
+
|
37
|
+
case match[1]
|
38
|
+
when 'ppa'
|
39
|
+
add_ppa_repository(transport, url)
|
40
|
+
when 'http', 'https'
|
41
|
+
add_http_repository(transport, url, repo, buildhost)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
success = transport.exec 'sudo apt-get update'
|
46
|
+
raise 'failed to update repositories' unless success
|
47
|
+
end
|
48
|
+
|
49
|
+
env[:packages].each do |package|
|
50
|
+
success = transport.exec \
|
51
|
+
"sudo -E apt-get install -y #{package}"
|
52
|
+
raise "failed to install package #{package}" unless success
|
53
|
+
end if env.key? :packages
|
54
|
+
rescue StandardError => ex
|
55
|
+
Cyclid.logger.error "failed to provision #{buildhost[:name]}: #{ex}"
|
56
|
+
raise
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def add_ppa_repository(transport, url)
|
62
|
+
success = transport.exec "sudo apt-add-repository -y #{url}"
|
63
|
+
raise "failed to add repository #{url}" unless success
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_http_repository(transport, url, repo, buildhost)
|
67
|
+
raise 'an HTTP repository must provide a list of components' \
|
68
|
+
unless repo.key? :components
|
69
|
+
|
70
|
+
# Create a sources.list.d fragment
|
71
|
+
release = buildhost[:release]
|
72
|
+
components = repo[:components]
|
73
|
+
fragment = "deb #{url} #{release} #{components}"
|
74
|
+
|
75
|
+
success = transport.exec \
|
76
|
+
"echo '#{fragment}' | sudo tee -a /etc/apt/sources.list.d/cyclid.list"
|
77
|
+
raise "failed to add repository #{url}" unless success
|
78
|
+
|
79
|
+
if repo.key? :key_id
|
80
|
+
# Import the signing key
|
81
|
+
key_id = repo[:key_id]
|
82
|
+
|
83
|
+
success = transport.exec \
|
84
|
+
"gpg --keyserver keyserver.ubuntu.com --recv-keys #{key_id}"
|
85
|
+
raise "failed to import key #{key_id}" unless success
|
86
|
+
|
87
|
+
success = transport.exec \
|
88
|
+
"gpg -a --export #{key_id} | sudo apt-key add -"
|
89
|
+
raise "failed to add repository key #{key_id}" unless success
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Register this plugin
|
94
|
+
register_plugin 'ubuntu'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Plugins
|
21
|
+
module Plugins
|
22
|
+
# Base class for Source plugins
|
23
|
+
class Source < Base
|
24
|
+
# Return the 'human' name for the plugin type
|
25
|
+
def self.human_name
|
26
|
+
'source'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Process the source to produce a copy of the remote code in a
|
30
|
+
# directory in the working directory
|
31
|
+
def checkout(_transport, _ctx, _source = {})
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require_rel 'source/*.rb'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Plugins
|
21
|
+
module Plugins
|
22
|
+
# Git source plugin
|
23
|
+
class Git < Source
|
24
|
+
# Run commands via. the transport to check out a given Git remote
|
25
|
+
# repository
|
26
|
+
def checkout(transport, ctx, source = {})
|
27
|
+
source.symbolize_keys!
|
28
|
+
|
29
|
+
raise 'invalid git source definition' \
|
30
|
+
unless source.key? :url
|
31
|
+
|
32
|
+
# Add any context data (which could include secrets)
|
33
|
+
source = source.interpolate(ctx)
|
34
|
+
|
35
|
+
url = URI(source[:url])
|
36
|
+
|
37
|
+
# If the source includes an OAuth token, add it to the URL as the
|
38
|
+
# username
|
39
|
+
url.user = source[:token] if source.key? :token
|
40
|
+
|
41
|
+
success = transport.exec "git clone #{url}"
|
42
|
+
return false unless success
|
43
|
+
|
44
|
+
# If a branch was given, check it out
|
45
|
+
if source.key? :branch
|
46
|
+
branch = source[:branch]
|
47
|
+
|
48
|
+
match = url.path.match(%r{^.*\/(\w*)})
|
49
|
+
source_dir = "#{ctx[:workspace]}/#{match[1]}"
|
50
|
+
|
51
|
+
success = transport.exec("git fetch origin #{branch}:#{branch}", source_dir)
|
52
|
+
success = transport.exec("git checkout #{branch}", source_dir) \
|
53
|
+
unless success == false
|
54
|
+
end
|
55
|
+
|
56
|
+
return success
|
57
|
+
end
|
58
|
+
|
59
|
+
# Register this plugin
|
60
|
+
register_plugin 'git'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Plugins
|
21
|
+
module Plugins
|
22
|
+
# Base class for Transport plugins
|
23
|
+
class Transport < Base
|
24
|
+
def initialize(args = {})
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return the 'human' name for the plugin type
|
28
|
+
def self.human_name
|
29
|
+
'transport'
|
30
|
+
end
|
31
|
+
|
32
|
+
# If possible, export each of the variables in env as a shell
|
33
|
+
# environment variables. The default is simply to remember the
|
34
|
+
# environment variables, which will be exported each time when a
|
35
|
+
# command is run.
|
36
|
+
def export_env(env = {})
|
37
|
+
@env = env
|
38
|
+
end
|
39
|
+
|
40
|
+
# Run a command on the remote host.
|
41
|
+
def exec(_cmd, _path = nil)
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
# Copy data from a local IO object to a remote file.
|
46
|
+
def upload(_io, _path)
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Copy a data from remote file to a local IO object
|
51
|
+
def download(_io, _path)
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
# Disconnect the transport
|
56
|
+
def close
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
require_rel 'transport/*.rb'
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'net/ssh'
|
17
|
+
require 'net/scp'
|
18
|
+
require 'cyclid/log_buffer'
|
19
|
+
|
20
|
+
# Top level module for the core Cyclid code.
|
21
|
+
module Cyclid
|
22
|
+
# Module for the Cyclid API
|
23
|
+
module API
|
24
|
+
# Module for Cyclid Plugins
|
25
|
+
module Plugins
|
26
|
+
# SSH based transport
|
27
|
+
class Ssh < Transport
|
28
|
+
attr_reader :exit_code, :exit_signal
|
29
|
+
|
30
|
+
def initialize(args = {})
|
31
|
+
args.symbolize_keys!
|
32
|
+
|
33
|
+
# Hostname, username & a log target are required
|
34
|
+
return false unless args.include? :host and \
|
35
|
+
args.include? :user and \
|
36
|
+
args.include? :log
|
37
|
+
|
38
|
+
password = args[:password] if args.include? :password
|
39
|
+
keys = [args[:key]] if args.include? :key
|
40
|
+
|
41
|
+
@log = args[:log]
|
42
|
+
|
43
|
+
# Create an SSH channel
|
44
|
+
Cyclid.logger.debug 'waiting for SSH...'
|
45
|
+
|
46
|
+
start = Time.now
|
47
|
+
loop do
|
48
|
+
begin
|
49
|
+
@session = Net::SSH.start(args[:host],
|
50
|
+
args[:user],
|
51
|
+
password: password,
|
52
|
+
keys: keys,
|
53
|
+
timeout: 5)
|
54
|
+
break unless @session.nil?
|
55
|
+
rescue Net::SSH::AuthenticationFailed
|
56
|
+
Cyclid.logger.debug 'SSH authentication failed'
|
57
|
+
end
|
58
|
+
|
59
|
+
sleep 5
|
60
|
+
|
61
|
+
raise 'timed out waiting for SSH' \
|
62
|
+
if (Time.now - start) >= 30
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Execute a command via. SSH
|
67
|
+
def exec(cmd, path = nil)
|
68
|
+
command = build_command(cmd, path, @env)
|
69
|
+
Cyclid.logger.debug "command=#{command}"
|
70
|
+
|
71
|
+
@session.open_channel do |channel|
|
72
|
+
channel.on_open_failed do |_ch, _code, desc|
|
73
|
+
# XXX raise
|
74
|
+
abort "failed to open channel: #{desc}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# STDOUT
|
78
|
+
channel.on_data do |_ch, data|
|
79
|
+
# Send to Log Buffer
|
80
|
+
@log.write data
|
81
|
+
end
|
82
|
+
|
83
|
+
# STDERR
|
84
|
+
channel.on_extended_data do |_ch, _type, data|
|
85
|
+
# Send to Log Buffer
|
86
|
+
@log.write data
|
87
|
+
end
|
88
|
+
|
89
|
+
# Capture return value from commands
|
90
|
+
channel.on_request 'exit-status' do |_ch, data|
|
91
|
+
@exit_code = data.read_long
|
92
|
+
end
|
93
|
+
|
94
|
+
# Capture a command exiting with a signal
|
95
|
+
channel.on_request 'exit-signal' do |_ch, data|
|
96
|
+
@exit_signal = data.read_long
|
97
|
+
end
|
98
|
+
|
99
|
+
channel.exec command do |_ch, _success|
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Run the SSH even loop; this blocks until the command has completed
|
104
|
+
@session.loop
|
105
|
+
|
106
|
+
@exit_code.zero? && @exit_signal.nil? ? true : false
|
107
|
+
end
|
108
|
+
|
109
|
+
# Copy data from a local IO object to a remote file via. SCP
|
110
|
+
def upload(io, path)
|
111
|
+
channel = @session.scp.upload io, path
|
112
|
+
channel.wait
|
113
|
+
end
|
114
|
+
|
115
|
+
# Copy a data from remote file to a local IO object
|
116
|
+
def download(io, path)
|
117
|
+
channel = @session.scp.download path, io
|
118
|
+
channel.wait
|
119
|
+
end
|
120
|
+
|
121
|
+
# Close the SSH connection
|
122
|
+
def close
|
123
|
+
logout
|
124
|
+
|
125
|
+
@session.close
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def logout
|
131
|
+
exec 'exit'
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_command(cmd, path = nil, env = {})
|
135
|
+
command = []
|
136
|
+
if env
|
137
|
+
vars = env.map do |k, value|
|
138
|
+
key = k.upcase
|
139
|
+
key.gsub!(/\s/, '_')
|
140
|
+
"export #{key}=\"#{value}\""
|
141
|
+
end
|
142
|
+
command << vars.join(';')
|
143
|
+
end
|
144
|
+
|
145
|
+
command << "cd #{path}" if path
|
146
|
+
command << cmd
|
147
|
+
command.join(';')
|
148
|
+
end
|
149
|
+
|
150
|
+
# Register this plugin
|
151
|
+
register_plugin 'ssh'
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'oj'
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
# Top level module for the core Cyclid code.
|
20
|
+
module Cyclid
|
21
|
+
# Module for the Cyclid API
|
22
|
+
module API
|
23
|
+
# Sinatra helpers
|
24
|
+
module APIHelpers
|
25
|
+
# Safely parse & validate the request body
|
26
|
+
def parse_request_body
|
27
|
+
# Parse the the request
|
28
|
+
begin
|
29
|
+
request.body.rewind
|
30
|
+
|
31
|
+
if request.content_type == 'application/json' or \
|
32
|
+
request.content_type == 'text/json'
|
33
|
+
|
34
|
+
data = Oj.load request.body.read
|
35
|
+
elsif request.content_type == 'application/x-yaml' or \
|
36
|
+
request.content_type == 'text/x-yaml'
|
37
|
+
|
38
|
+
data = YAML.load request.body.read
|
39
|
+
else
|
40
|
+
halt_with_json_response(415, \
|
41
|
+
Errors::HTTPErrors::INVALID_JSON, \
|
42
|
+
"unsupported content type #{request.content_type}")
|
43
|
+
end
|
44
|
+
rescue Oj::ParseError, YAML::Exception => ex
|
45
|
+
Cyclid.logger.debug ex.message
|
46
|
+
halt_with_json_response(400, Errors::HTTPErrors::INVALID_JSON, ex.message)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sanity check the request
|
50
|
+
halt_with_json_response(400, \
|
51
|
+
Errors::HTTPErrors::INVALID_JSON, \
|
52
|
+
'request body can not be empty') if data.nil?
|
53
|
+
halt_with_json_response(400, \
|
54
|
+
Errors::HTTPErrors::INVALID_JSON, \
|
55
|
+
'request body is invalid') unless data.is_a?(Hash)
|
56
|
+
|
57
|
+
return data
|
58
|
+
end
|
59
|
+
|
60
|
+
# Return a RESTful JSON response
|
61
|
+
def json_response(id, description)
|
62
|
+
Oj.dump('id' => id, 'description' => description)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|