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
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
|