cyclid-client 0.3.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 +587 -0
- data/bin/cyclid +20 -0
- data/lib/cyclid/auth_methods.rb +25 -0
- data/lib/cyclid/cli.rb +90 -0
- data/lib/cyclid/cli/admin.rb +32 -0
- data/lib/cyclid/cli/admin/organization.rb +122 -0
- data/lib/cyclid/cli/admin/user.rb +142 -0
- data/lib/cyclid/cli/job.rb +114 -0
- data/lib/cyclid/cli/organization.rb +129 -0
- data/lib/cyclid/cli/organization/config.rb +90 -0
- data/lib/cyclid/cli/organization/member.rb +126 -0
- data/lib/cyclid/cli/secret.rb +42 -0
- data/lib/cyclid/cli/stage.rb +121 -0
- data/lib/cyclid/cli/user.rb +84 -0
- data/lib/cyclid/client.rb +98 -0
- data/lib/cyclid/client/api.rb +114 -0
- data/lib/cyclid/client/api/basic.rb +30 -0
- data/lib/cyclid/client/api/hmac.rb +59 -0
- data/lib/cyclid/client/api/none.rb +29 -0
- data/lib/cyclid/client/api/token.rb +30 -0
- data/lib/cyclid/client/auth.rb +36 -0
- data/lib/cyclid/client/health.rb +34 -0
- data/lib/cyclid/client/job.rb +88 -0
- data/lib/cyclid/client/organization.rb +187 -0
- data/lib/cyclid/client/stage.rb +79 -0
- data/lib/cyclid/client/user.rb +134 -0
- data/lib/cyclid/config.rb +92 -0
- metadata +157 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
# Copyright 2016 Liqwyd Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'colorize'
|
16
|
+
|
17
|
+
# Cyclid top level module
|
18
|
+
module Cyclid
|
19
|
+
module Cli
|
20
|
+
# 'user' sub-command
|
21
|
+
class User < Thor
|
22
|
+
desc 'show', 'Show your user details'
|
23
|
+
def show
|
24
|
+
user = client.user_get(client.config.username)
|
25
|
+
|
26
|
+
# Pretty print the user details
|
27
|
+
puts 'Username: '.colorize(:cyan) + user['username']
|
28
|
+
puts 'Name: '.colorize(:cyan) + (user['name'] || '')
|
29
|
+
puts 'Email: '.colorize(:cyan) + user['email']
|
30
|
+
puts 'Organizations'.colorize(:cyan)
|
31
|
+
if user['organizations'].any?
|
32
|
+
user['organizations'].each do |org|
|
33
|
+
puts "\t#{org}"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
puts "\tNone"
|
37
|
+
end
|
38
|
+
rescue StandardError => ex
|
39
|
+
abort "Failed to get user: #{ex}"
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'modify', 'Modify your user'
|
43
|
+
long_desc <<-LONGDESC
|
44
|
+
Modify your user details.
|
45
|
+
|
46
|
+
The --email option sets your email address.
|
47
|
+
|
48
|
+
The --password option sets an encrypted password for HTTP Basic authentication and Cyclid
|
49
|
+
UI console logins.
|
50
|
+
|
51
|
+
The --secret option sets a shared secret which is used for signing Cyclid API requests.
|
52
|
+
LONGDESC
|
53
|
+
option :email, aliases: '-e'
|
54
|
+
option :password, aliases: '-p'
|
55
|
+
option :secret, aliases: '-s'
|
56
|
+
def modify
|
57
|
+
client.user_modify(client.config.username,
|
58
|
+
email: options[:email],
|
59
|
+
password: options[:password],
|
60
|
+
secret: options[:secret])
|
61
|
+
rescue StandardError => ex
|
62
|
+
abort "Failed to modify user: #{ex}"
|
63
|
+
end
|
64
|
+
|
65
|
+
desc 'passwd', 'Change your password'
|
66
|
+
def passwd
|
67
|
+
# Get the new password
|
68
|
+
print 'Password: '
|
69
|
+
password = STDIN.noecho(&:gets).chomp
|
70
|
+
print "\nConfirm password: "
|
71
|
+
confirm = STDIN.noecho(&:gets).chomp
|
72
|
+
print "\n"
|
73
|
+
abort 'Passwords do not match' unless password == confirm
|
74
|
+
|
75
|
+
# Modify the user with the new password
|
76
|
+
begin
|
77
|
+
client.user_modify(client.config.username, password: password)
|
78
|
+
rescue StandardError => ex
|
79
|
+
abort "Failed to modify user: #{ex}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# Copyright 2016 Liqwyd Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'securerandom'
|
16
|
+
require 'oj'
|
17
|
+
require 'yaml'
|
18
|
+
require 'logger'
|
19
|
+
|
20
|
+
require 'cyclid/config'
|
21
|
+
require 'cyclid/auth_methods'
|
22
|
+
|
23
|
+
require 'cyclid/client/api'
|
24
|
+
require 'cyclid/client/user'
|
25
|
+
require 'cyclid/client/organization'
|
26
|
+
require 'cyclid/client/job'
|
27
|
+
require 'cyclid/client/stage'
|
28
|
+
require 'cyclid/client/auth'
|
29
|
+
require 'cyclid/client/health'
|
30
|
+
|
31
|
+
module Cyclid
|
32
|
+
# Cyclid client methods
|
33
|
+
module Client
|
34
|
+
# Tilapia is the standard Cyclid Ruby client. It provides an inteligent
|
35
|
+
# programmable API on top of the standard Cyclid REST API, complete with
|
36
|
+
# automatic signing of HTTP requests and HTTP error handling.
|
37
|
+
#
|
38
|
+
# The client provides interfaces for managing Users, Organizations, Stages
|
39
|
+
# & Jobs. Refer to the documentation for those modules for more information.
|
40
|
+
#
|
41
|
+
# In case you're wondering, this class required a name: it couldn't be
|
42
|
+
# 'Cyclid' and it couldn't be 'Client'. Tilapia are a common type of
|
43
|
+
# Cichlid...
|
44
|
+
class Tilapia
|
45
|
+
attr_reader :config, :logger
|
46
|
+
# @!attribute [r] config
|
47
|
+
# @return [Config] Client configuration object
|
48
|
+
# @!attribute [r] logger
|
49
|
+
# @return [Logger] Client logger object
|
50
|
+
|
51
|
+
# @param [Hash] options
|
52
|
+
# @option options [String] :config_path Fully qualified path to the configuration file
|
53
|
+
# @option options [FixNum] :log_level Logger output level
|
54
|
+
def initialize(options)
|
55
|
+
@config = Config.new(options)
|
56
|
+
|
57
|
+
# Create a logger
|
58
|
+
log_level = options[:log_level] || Logger::FATAL
|
59
|
+
@logger = Logger.new(STDERR)
|
60
|
+
@logger.level = log_level
|
61
|
+
|
62
|
+
# Select the API methods to use
|
63
|
+
@api = case @config.auth
|
64
|
+
when AuthMethods::AUTH_NONE
|
65
|
+
Api::None.new(@config, @logger)
|
66
|
+
when AuthMethods::AUTH_HMAC
|
67
|
+
Api::Hmac.new(@config, @logger)
|
68
|
+
when AuthMethods::AUTH_BASIC
|
69
|
+
Api::Basic.new(@config, @logger)
|
70
|
+
when AuthMethods::AUTH_TOKEN
|
71
|
+
Api::Token.new(@config, @logger)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
include User
|
76
|
+
include Organization
|
77
|
+
include Job
|
78
|
+
include Stage
|
79
|
+
include Auth
|
80
|
+
include Health
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# Build a URI for the configured server & required resource
|
85
|
+
def server_uri(path)
|
86
|
+
URI::HTTP.build(host: @config.server,
|
87
|
+
port: @config.port,
|
88
|
+
path: path)
|
89
|
+
end
|
90
|
+
|
91
|
+
def method_missing(method, *args, &block)
|
92
|
+
@api.send(method, *args, &block)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
include AuthMethods
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Copyright 2016 Liqwyd Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'uri'
|
16
|
+
require 'net/http'
|
17
|
+
|
18
|
+
module Cyclid
|
19
|
+
# Cyclid client methods
|
20
|
+
module Client
|
21
|
+
# Client API request methods
|
22
|
+
module Api
|
23
|
+
# Base class for API request implementations
|
24
|
+
class Base
|
25
|
+
def initialize(config, logger)
|
26
|
+
@config = config
|
27
|
+
@logger = logger
|
28
|
+
end
|
29
|
+
|
30
|
+
# Add authentication details & perform a GET request
|
31
|
+
def api_get(uri)
|
32
|
+
req = authenticate_request(Net::HTTP::Get.new(uri), uri)
|
33
|
+
|
34
|
+
api_request(uri, req)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Add authentication details perform a POST request with a pre-formatted body
|
38
|
+
def api_raw_post(uri, data, content_type)
|
39
|
+
unsigned = Net::HTTP::Post.new(uri)
|
40
|
+
unsigned.content_type = content_type
|
41
|
+
unsigned.body = data
|
42
|
+
|
43
|
+
req = authenticate_request(unsigned, uri)
|
44
|
+
|
45
|
+
api_request(uri, req)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add authentication details perform a POST request with a JSON body
|
49
|
+
def api_json_post(uri, data)
|
50
|
+
json = Oj.dump(data)
|
51
|
+
api_raw_post(uri, json, 'application/json')
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add authentication details perform a POST request with a YAML body
|
55
|
+
def api_yaml_post(uri, data)
|
56
|
+
yaml = YAML.dump(data)
|
57
|
+
api_raw_post(uri, yaml, 'application/x-yaml')
|
58
|
+
end
|
59
|
+
|
60
|
+
# Add authentication details perform a PUT request with a JSON body
|
61
|
+
def api_json_put(uri, data)
|
62
|
+
unsigned = Net::HTTP::Put.new(uri)
|
63
|
+
unsigned.content_type = 'application/json'
|
64
|
+
unsigned.body = Oj.dump(data)
|
65
|
+
|
66
|
+
req = authenticate_request(unsigned, uri)
|
67
|
+
|
68
|
+
api_request(uri, req)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Add authentication details perform a DELETE request
|
72
|
+
def api_delete(uri)
|
73
|
+
req = authenticate_request(Net::HTTP::Delete.new(uri), uri)
|
74
|
+
|
75
|
+
api_request(uri, req)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Perform an API HTTP request & return the parsed response body
|
79
|
+
def api_request(uri, req)
|
80
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
81
|
+
res = http.request(req)
|
82
|
+
|
83
|
+
parse_response(res)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Parse, validate & handle response data
|
87
|
+
def parse_response(res)
|
88
|
+
response_data = Oj.load(res.body)
|
89
|
+
|
90
|
+
# Return immediately if the response was an HTTP 200 OK
|
91
|
+
return response_data if res.code == '200'
|
92
|
+
|
93
|
+
@logger.info "server request failed with error ##{res.code}: \
|
94
|
+
#{response_data['description']}"
|
95
|
+
raise response_data['description']
|
96
|
+
rescue Oj::ParseError => ex
|
97
|
+
@logger.debug "body: #{res.body}\n#{ex}"
|
98
|
+
raise 'failed to decode server response body'
|
99
|
+
end
|
100
|
+
|
101
|
+
# The API does not support non-authenticated requests, so this method
|
102
|
+
# must be implemented.
|
103
|
+
def authenticate_request(_request, _uri)
|
104
|
+
raise NotImplementedError
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
require 'cyclid/client/api/none'
|
112
|
+
require 'cyclid/client/api/hmac'
|
113
|
+
require 'cyclid/client/api/basic'
|
114
|
+
require 'cyclid/client/api/token'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright 2016 Liqwyd Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Cyclid
|
16
|
+
# Cyclid client methods
|
17
|
+
module Client
|
18
|
+
# Client API HTTP methods
|
19
|
+
module Api
|
20
|
+
# HTTP Basic auth HTTP methods
|
21
|
+
class Basic < Base
|
22
|
+
# Add the username & password to the request
|
23
|
+
def authenticate_request(request, _uri)
|
24
|
+
request.basic_auth(@config.username, @config.password)
|
25
|
+
return request
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright 2016 Liqwyd Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'cyclid/hmac'
|
16
|
+
|
17
|
+
module Cyclid
|
18
|
+
# Cyclid client methods
|
19
|
+
module Client
|
20
|
+
# Client API HTTP methods
|
21
|
+
module Api
|
22
|
+
# HMAC signed HTTP methods
|
23
|
+
class Hmac < Base
|
24
|
+
# Sign the request with HMAC
|
25
|
+
def authenticate_request(request, uri)
|
26
|
+
algorithm = 'sha256'
|
27
|
+
signer = Cyclid::HMAC::Signer.new(algorithm)
|
28
|
+
|
29
|
+
method = if request.is_a? Net::HTTP::Get
|
30
|
+
'GET'
|
31
|
+
elsif request.is_a? Net::HTTP::Post
|
32
|
+
'POST'
|
33
|
+
elsif request.is_a? Net::HTTP::Put
|
34
|
+
'PUT'
|
35
|
+
elsif request.is_a? Net::HTTP::Delete
|
36
|
+
'DELETE'
|
37
|
+
else
|
38
|
+
raise "invalid request method #{request.inspect}"
|
39
|
+
end
|
40
|
+
|
41
|
+
nonce = SecureRandom.hex
|
42
|
+
headers = signer.sign_request(uri.path,
|
43
|
+
@config.secret,
|
44
|
+
auth_header_format: '%{auth_scheme} %{username}:%{signature}', # rubocop:disable Metrics/LineLength
|
45
|
+
username: @config.username,
|
46
|
+
nonce: nonce,
|
47
|
+
method: method)
|
48
|
+
|
49
|
+
headers[0].each do |k, v|
|
50
|
+
request[k] = v
|
51
|
+
end
|
52
|
+
request['X-HMAC-Algorithm'] = algorithm
|
53
|
+
|
54
|
+
return request
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright 2016 Liqwyd Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Cyclid
|
16
|
+
# Cyclid client methods
|
17
|
+
module Client
|
18
|
+
# Client API HTTP methods
|
19
|
+
module Api
|
20
|
+
# Only works for non-authenticated request (E.g. healthchecks)
|
21
|
+
class None < Base
|
22
|
+
# Do nothing
|
23
|
+
def authenticate_request(request, _uri)
|
24
|
+
request
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright 2016 Liqwyd Ltd.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Cyclid
|
16
|
+
# Cyclid client methods
|
17
|
+
module Client
|
18
|
+
# Client API HTTP methods
|
19
|
+
module Api
|
20
|
+
# JWT token based HTTP methods
|
21
|
+
class Token < Base
|
22
|
+
# Add the token to the request
|
23
|
+
def authenticate_request(request, _uri)
|
24
|
+
request.add_field('Authorization', "Token #{@config.username}:#{@config.token}")
|
25
|
+
return request
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|