cyclid-client 0.3.0
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/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
data/bin/cyclid
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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
|
+
$LOAD_PATH.push File.expand_path('../../lib', __FILE__)
|
17
|
+
|
18
|
+
require 'cyclid/cli'
|
19
|
+
|
20
|
+
Cyclid::Cli::Command.start(ARGV)
|
@@ -0,0 +1,25 @@
|
|
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
|
+
module Client
|
17
|
+
# Possible authentication methods
|
18
|
+
module AuthMethods
|
19
|
+
AUTH_NONE = 0,
|
20
|
+
AUTH_HMAC = 1,
|
21
|
+
AUTH_BASIC = 2,
|
22
|
+
AUTH_TOKEN = 3
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/cyclid/cli.rb
ADDED
@@ -0,0 +1,90 @@
|
|
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 'thor'
|
16
|
+
require 'require_all'
|
17
|
+
|
18
|
+
require_rel 'cli/*.rb'
|
19
|
+
require 'cyclid/client'
|
20
|
+
|
21
|
+
# Add some helpers to the Thor base class
|
22
|
+
class Thor
|
23
|
+
private
|
24
|
+
|
25
|
+
def client
|
26
|
+
@client ||= Cyclid::Client::Tilapia.new(path: options[:config], log_level: debug?)
|
27
|
+
end
|
28
|
+
|
29
|
+
def debug?
|
30
|
+
options[:debug] ? Logger::DEBUG : Logger::FATAL
|
31
|
+
end
|
32
|
+
|
33
|
+
# Open a text editor against a temporary file with the data rendered to
|
34
|
+
# JSON, and then re-parse the file after the user has completed editing.
|
35
|
+
def invoke_editor(data)
|
36
|
+
# Sanity check that EDITOR is set in the environment before we try to run
|
37
|
+
# it
|
38
|
+
abort('ERROR: '.colorize(:red) + 'You must set your EDITOR environment variable') \
|
39
|
+
if ENV['EDITOR'].nil?
|
40
|
+
|
41
|
+
# Write the data to a temporary file
|
42
|
+
tmpfile = Tempfile.new('cyclid')
|
43
|
+
tmpfile.write(JSON.pretty_generate(data))
|
44
|
+
tmpfile.flush
|
45
|
+
|
46
|
+
# Run the editor
|
47
|
+
system("#{ENV['EDITOR']} #{tmpfile.path}")
|
48
|
+
|
49
|
+
# Re-open and read it back in now that the user has finished editing it
|
50
|
+
tmpfile.open
|
51
|
+
data = JSON.parse(tmpfile.read)
|
52
|
+
|
53
|
+
tmpfile.close
|
54
|
+
tmpfile.unlink
|
55
|
+
|
56
|
+
return data
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module Cyclid
|
61
|
+
module Cli
|
62
|
+
CYCLID_CONFIG_DIR = File.join(ENV['HOME'], '.cyclid')
|
63
|
+
CYCLID_CONFIG_PATH = File.join(CYCLID_CONFIG_DIR, 'config')
|
64
|
+
|
65
|
+
# Top level Thor-based CLI
|
66
|
+
class Command < Thor
|
67
|
+
class_option :config, aliases: '-c', type: :string, default: CYCLID_CONFIG_PATH
|
68
|
+
class_option :debug, aliases: '-d', type: :boolean, default: false
|
69
|
+
|
70
|
+
desc 'admin', 'Administrator commands'
|
71
|
+
subcommand 'admin', Admin
|
72
|
+
|
73
|
+
desc 'user', 'Manage users'
|
74
|
+
subcommand 'user', User
|
75
|
+
|
76
|
+
desc 'organization', 'Manage organizations'
|
77
|
+
subcommand 'organization', Organization
|
78
|
+
map 'org' => :organization
|
79
|
+
|
80
|
+
desc 'job', 'Manage jobs'
|
81
|
+
subcommand 'job', Job
|
82
|
+
|
83
|
+
desc 'secret', 'Manage secrets'
|
84
|
+
subcommand 'secret', Secret
|
85
|
+
|
86
|
+
desc 'stage', 'Manage stages'
|
87
|
+
subcommand 'stage', Stage
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,32 @@
|
|
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 'base64'
|
16
|
+
require 'openssl'
|
17
|
+
|
18
|
+
require_rel 'admin/*.rb'
|
19
|
+
|
20
|
+
module Cyclid
|
21
|
+
module Cli
|
22
|
+
# 'admin' sub-command
|
23
|
+
class Admin < Thor
|
24
|
+
desc 'user', 'Manage users'
|
25
|
+
subcommand 'user', AdminUser
|
26
|
+
|
27
|
+
desc 'organization', 'Manage organizations'
|
28
|
+
subcommand 'organization', AdminOrganization
|
29
|
+
map 'org' => :organization
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,122 @@
|
|
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
|
+
module Cli
|
17
|
+
# 'admin organization' sub-commands
|
18
|
+
class AdminOrganization < Thor
|
19
|
+
desc 'list', 'List all of the organizations'
|
20
|
+
def list
|
21
|
+
orgs = client.org_list
|
22
|
+
orgs.each do |org|
|
23
|
+
puts org
|
24
|
+
end
|
25
|
+
rescue StandardError => ex
|
26
|
+
abort "Failed to retrieve list of organizations: #{ex}"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'show NAME', 'Show details of the organization NAME'
|
30
|
+
def show(name)
|
31
|
+
org = client.org_get(name)
|
32
|
+
|
33
|
+
# Convert the public key to PEM
|
34
|
+
der_key = Base64.decode64(org['public_key'])
|
35
|
+
public_key = OpenSSL::PKey::RSA.new(der_key)
|
36
|
+
|
37
|
+
# Pretty print the organization details
|
38
|
+
puts 'Name: '.colorize(:cyan) + org['name']
|
39
|
+
puts 'Owner Email: '.colorize(:cyan) + org['owner_email']
|
40
|
+
puts 'Public Key: '.colorize(:cyan) + public_key.to_pem
|
41
|
+
puts 'Members:'.colorize(:cyan)
|
42
|
+
if org['users'].any?
|
43
|
+
org['users'].each do |user|
|
44
|
+
puts "\t#{user}"
|
45
|
+
end
|
46
|
+
else
|
47
|
+
puts "\tNone"
|
48
|
+
end
|
49
|
+
rescue StandardError => ex
|
50
|
+
abort "Failed to get organization: #{ex}"
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'create NAME OWNER-EMAIL', 'Create a new organization NAME'
|
54
|
+
long_desc <<-LONGDESC
|
55
|
+
Create an organization NAME with the owner email address EMAIL.
|
56
|
+
|
57
|
+
The --admin option adds a user as the initial organization administrator.
|
58
|
+
LONGDESC
|
59
|
+
option :admin, aliases: '-a'
|
60
|
+
def create(name, email)
|
61
|
+
client.org_add(name, email)
|
62
|
+
|
63
|
+
if options[:admin]
|
64
|
+
# Add the user to the organization and create the appropriate admin
|
65
|
+
# permissions for them.
|
66
|
+
client.org_modify(name,
|
67
|
+
members: options[:admin])
|
68
|
+
|
69
|
+
perms = { 'admin' => true, 'write' => true, 'read' => true }
|
70
|
+
client.org_user_permissions(name,
|
71
|
+
options[:admin],
|
72
|
+
perms)
|
73
|
+
end
|
74
|
+
rescue StandardError => ex
|
75
|
+
abort "Failed to create new organization: #{ex}"
|
76
|
+
end
|
77
|
+
|
78
|
+
desc 'modify NAME', 'Modify the organization NAME'
|
79
|
+
long_desc <<-LONGDESC
|
80
|
+
Modify the organization NAME.
|
81
|
+
|
82
|
+
The --email option sets the owners email address.
|
83
|
+
|
84
|
+
The --members options sets the list of organization members.
|
85
|
+
|
86
|
+
*WARNING* --members will overwrite the existing list of members, so use with care!
|
87
|
+
LONGDESC
|
88
|
+
option :email, aliases: '-e'
|
89
|
+
option :members, aliases: '-m', type: :array
|
90
|
+
def modify(name)
|
91
|
+
client.org_modify(name,
|
92
|
+
owner_email: options[:email],
|
93
|
+
members: options[:members])
|
94
|
+
rescue StandardError => ex
|
95
|
+
abort "Failed to modify organization: #{ex}"
|
96
|
+
end
|
97
|
+
|
98
|
+
desc 'delete NAME', 'Delete the organization NAME'
|
99
|
+
long_desc <<-LONGDESC
|
100
|
+
Delete the organization NAME from the server.
|
101
|
+
|
102
|
+
The --force option will delete the organization without asking for confirmation.
|
103
|
+
LONGDESC
|
104
|
+
option :force, aliases: '-f', type: :boolean
|
105
|
+
def delete(name)
|
106
|
+
if options[:force]
|
107
|
+
delete = true
|
108
|
+
else
|
109
|
+
print "Delete organization #{name}: are you sure? (Y/n): ".colorize(:red)
|
110
|
+
delete = STDIN.getc.chr.casecmp('y') == 0
|
111
|
+
end
|
112
|
+
abort unless delete
|
113
|
+
|
114
|
+
begin
|
115
|
+
client.org_delete(name)
|
116
|
+
rescue StandardError => ex
|
117
|
+
abort "Failed to delete organization: #{ex}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,142 @@
|
|
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
|
+
module Cli
|
17
|
+
# 'admin user' sub-commands
|
18
|
+
class AdminUser < Thor
|
19
|
+
desc 'list', 'List all of the users'
|
20
|
+
def list
|
21
|
+
users = client.user_list
|
22
|
+
users.each do |user|
|
23
|
+
puts user
|
24
|
+
end
|
25
|
+
rescue StandardError => ex
|
26
|
+
abort "Failed to retrieve list of users: #{ex}"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'show USERNAME', 'Show details of the user USERNAME'
|
30
|
+
def show(username)
|
31
|
+
user = client.user_get(username)
|
32
|
+
|
33
|
+
# Pretty print the user details
|
34
|
+
puts 'Username: '.colorize(:cyan) + user['username']
|
35
|
+
puts 'Name: '.colorize(:cyan) + (user['name'] || '')
|
36
|
+
puts 'Email: '.colorize(:cyan) + user['email']
|
37
|
+
puts 'Organizations:'.colorize(:cyan)
|
38
|
+
if user['organizations'].any?
|
39
|
+
user['organizations'].each do |org|
|
40
|
+
puts "\t#{org}"
|
41
|
+
end
|
42
|
+
else
|
43
|
+
puts "\tNone"
|
44
|
+
end
|
45
|
+
rescue StandardError => ex
|
46
|
+
abort "Failed to get user: #{ex}"
|
47
|
+
end
|
48
|
+
|
49
|
+
desc 'create USERNAME EMAIL', 'Create a new user USERNAME'
|
50
|
+
long_desc <<-LONGDESC
|
51
|
+
Create a user USERNAME with the email address EMAIL. The new user will not be a member of
|
52
|
+
any organization.
|
53
|
+
|
54
|
+
The --name option sets the users real name.
|
55
|
+
|
56
|
+
The --password option sets an encrypted password for HTTP Basic authentication and Cyclid
|
57
|
+
UI console logins.
|
58
|
+
|
59
|
+
The --secret option sets a shared secret which is used for signing Cyclid API requests.
|
60
|
+
|
61
|
+
One of either --password or --secret should be used if you want the user to be able to
|
62
|
+
authenticate with the server.
|
63
|
+
LONGDESC
|
64
|
+
option :name, aliases: '-n'
|
65
|
+
option :password, aliases: '-p'
|
66
|
+
option :secret, aliases: '-s'
|
67
|
+
def create(username, email)
|
68
|
+
client.user_add(username, email, options[:name], options[:password], options[:secret])
|
69
|
+
rescue StandardError => ex
|
70
|
+
abort "Failed to create new user: #{ex}"
|
71
|
+
end
|
72
|
+
|
73
|
+
desc 'modify USERNAME', 'Modify the user USERNAME'
|
74
|
+
long_desc <<-LONGDESC
|
75
|
+
Modify the user USERNAME.
|
76
|
+
|
77
|
+
The --name option sets the users real name.
|
78
|
+
|
79
|
+
The --email option sets the users email address.
|
80
|
+
|
81
|
+
The --password option sets an encrypted password for HTTP Basic authentication and Cyclid
|
82
|
+
UI console logins.
|
83
|
+
|
84
|
+
The --secret option sets a shared secret which is used for signing Cyclid API requests.
|
85
|
+
LONGDESC
|
86
|
+
option :name, aliases: '-n'
|
87
|
+
option :email, aliases: '-e'
|
88
|
+
option :password, aliases: '-p'
|
89
|
+
option :secret, aliases: '-s'
|
90
|
+
def modify(username)
|
91
|
+
client.user_modify(username,
|
92
|
+
name: options[:name],
|
93
|
+
email: options[:email],
|
94
|
+
password: options[:password],
|
95
|
+
secret: options[:secret])
|
96
|
+
rescue StandardError => ex
|
97
|
+
abort "Failed to modify user: #{ex}"
|
98
|
+
end
|
99
|
+
|
100
|
+
desc 'passwd USERNAME', 'Change the password of the user USERNAME'
|
101
|
+
def passwd(username)
|
102
|
+
# Get the new password
|
103
|
+
print 'Password: '
|
104
|
+
password = STDIN.noecho(&:gets).chomp
|
105
|
+
print "\nConfirm password: "
|
106
|
+
confirm = STDIN.noecho(&:gets).chomp
|
107
|
+
print "\n"
|
108
|
+
abort 'Passwords do not match' unless password == confirm
|
109
|
+
|
110
|
+
# Modify the user with the new password
|
111
|
+
begin
|
112
|
+
client.user_modify(username, password: password)
|
113
|
+
rescue StandardError => ex
|
114
|
+
abort "Failed to modify user: #{ex}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
desc 'delete USERNAME', 'Delete the user USERNAME'
|
119
|
+
long_desc <<-LONGDESC
|
120
|
+
Delete the user USERNAME from the server.
|
121
|
+
|
122
|
+
The --force option will delete the user without asking for confirmation.
|
123
|
+
LONGDESC
|
124
|
+
option :force, aliases: '-f', type: :boolean
|
125
|
+
def delete(username)
|
126
|
+
if options[:force]
|
127
|
+
delete = true
|
128
|
+
else
|
129
|
+
print "Delete user #{username}: are you sure? (Y/n): ".colorize(:red)
|
130
|
+
delete = STDIN.getc.chr.casecmp('y') == 0
|
131
|
+
end
|
132
|
+
abort unless delete
|
133
|
+
|
134
|
+
begin
|
135
|
+
client.user_delete(username)
|
136
|
+
rescue StandardError => ex
|
137
|
+
abort "Failed to delete user: #{ex}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
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 'yaml'
|
16
|
+
require 'json'
|
17
|
+
require 'cyclid/constants'
|
18
|
+
|
19
|
+
module Cyclid
|
20
|
+
module Cli
|
21
|
+
# 'job' sub-command
|
22
|
+
class Job < Thor
|
23
|
+
desc 'submit FILENAME', 'Submit a job to be run'
|
24
|
+
long_desc <<-LONGDESC
|
25
|
+
Submit a job to be run by the server. FILENAME should be the path to a valid Cyclid job
|
26
|
+
file, in either YAML or JSON format.
|
27
|
+
|
28
|
+
Cyclid will attempt to detect the format of the job file automatically. You can force the
|
29
|
+
parsing format using either the --yaml or --json options.
|
30
|
+
|
31
|
+
The --yaml option causes the job file to be parsed as YAML.
|
32
|
+
|
33
|
+
The --json option causes the job file to be parsed as JSON.
|
34
|
+
LONGDESC
|
35
|
+
option :yaml, aliases: '-y'
|
36
|
+
option :json, aliases: '-j'
|
37
|
+
def submit(filename)
|
38
|
+
job_file = File.expand_path(filename)
|
39
|
+
raise 'Cannot open file' unless File.exist?(job_file)
|
40
|
+
|
41
|
+
job_type = if options[:yaml]
|
42
|
+
'yaml'
|
43
|
+
elsif options[:json]
|
44
|
+
'json'
|
45
|
+
else
|
46
|
+
# Detect format
|
47
|
+
match = job_file.match(/\A.*\.(json|yml|yaml)\z/)
|
48
|
+
match[1]
|
49
|
+
end
|
50
|
+
job_type = 'yaml' if job_type == 'yml'
|
51
|
+
|
52
|
+
# Do a client-side sanity check by attempting to parse the file; we
|
53
|
+
# don't do anything with the data but it fails-fast if the file has a
|
54
|
+
# syntax error
|
55
|
+
job = File.read(job_file)
|
56
|
+
if job_type == 'yaml'
|
57
|
+
YAML.load(job)
|
58
|
+
elsif job_type == 'json'
|
59
|
+
JSON.parse(job)
|
60
|
+
else
|
61
|
+
raise 'Unknown or unsupported file type'
|
62
|
+
end
|
63
|
+
|
64
|
+
job_info = client.job_submit(client.config.organization, job, job_type)
|
65
|
+
puts 'Job: '.colorize(:cyan) + job_info['job_id'].to_s
|
66
|
+
rescue StandardError => ex
|
67
|
+
abort "Failed to submit job: #{ex}"
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'show JOBID', 'Show details of a job'
|
71
|
+
def show(jobid)
|
72
|
+
job = client.job_get(client.config.organization, jobid)
|
73
|
+
|
74
|
+
status_id = job['status']
|
75
|
+
status = Cyclid::API::Constants::JOB_STATUSES[status_id]
|
76
|
+
|
77
|
+
started = job['started'].nil? ? nil : Time.parse(job['started'])
|
78
|
+
ended = job['ended'].nil? ? nil : Time.parse(job['ended'])
|
79
|
+
|
80
|
+
# Pretty-print the job details (without the log)
|
81
|
+
puts 'Job: '.colorize(:cyan) + job['id'].to_s
|
82
|
+
puts 'Name: '.colorize(:cyan) + (job['job_name'] || '')
|
83
|
+
puts 'Version: '.colorize(:cyan) + (job['job_version'] || '')
|
84
|
+
puts 'Started: '.colorize(:cyan) + (started ? started.asctime : '')
|
85
|
+
puts 'Ended: '.colorize(:cyan) + (ended ? ended.asctime : '')
|
86
|
+
puts 'Status: '.colorize(:cyan) + status
|
87
|
+
rescue StandardError => ex
|
88
|
+
abort "Failed to get job status: #{ex}"
|
89
|
+
end
|
90
|
+
|
91
|
+
desc 'status JOBID', 'Show the status of a job'
|
92
|
+
def status(jobid)
|
93
|
+
job_status = client.job_status(client.config.organization, jobid)
|
94
|
+
|
95
|
+
status_id = job_status['status']
|
96
|
+
status = Cyclid::API::Constants::JOB_STATUSES[status_id]
|
97
|
+
|
98
|
+
# Pretty-print the job status
|
99
|
+
puts 'Status: '.colorize(:cyan) + status
|
100
|
+
rescue StandardError => ex
|
101
|
+
abort "Failed to get job status: #{ex}"
|
102
|
+
end
|
103
|
+
|
104
|
+
desc 'log JOBID', 'Show the job log'
|
105
|
+
def log(jobid)
|
106
|
+
job_log = client.job_log(client.config.organization, jobid)
|
107
|
+
|
108
|
+
puts job_log['log']
|
109
|
+
rescue StandardError => ex
|
110
|
+
abort "Failed to get job log: #{ex}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|