nex_client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ require 'colorize'
3
+
4
+ module NexClient
5
+ module Commands
6
+ autoload :Addons, 'nex_client/commands/addons'
7
+ autoload :Apps, 'nex_client/commands/apps'
8
+ autoload :CubeInstances, 'nex_client/commands/cube_instances'
9
+ autoload :CubeTemplates, 'nex_client/commands/cube_templates'
10
+ autoload :Domains, 'nex_client/commands/domains'
11
+ autoload :Helpers, 'nex_client/commands/helpers'
12
+ autoload :Organizations, 'nex_client/commands/organizations'
13
+ autoload :Racks, 'nex_client/commands/racks'
14
+ autoload :SslCertificates, 'nex_client/commands/ssl_certificates'
15
+ autoload :Users, 'nex_client/commands/users'
16
+ end
17
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+ module NexClient
3
+ module Commands
4
+ module Addons
5
+ extend Helpers
6
+
7
+ ADDONS_TITLE = "Addons".colorize(:red)
8
+ ADDONS_HEADERS = ['id','name','status','service','app'].map(&:upcase)
9
+
10
+ def self.list(args,opts)
11
+ filters = {}
12
+ filters[:status] = opts.status || 'active'
13
+ filters[:service] = opts.service if opts.service.present?
14
+
15
+ # All option
16
+ filters = {} if opts.all
17
+
18
+ # Scope to specific app
19
+ filters[:'app.name'] = args.first if args.first.present?
20
+
21
+ # Create table
22
+ list = NexClient::Addon.includes(:app).where(filters).order('status')
23
+ self.display_addons(list)
24
+ end
25
+
26
+ def self.create(args,opts)
27
+ svc_name,app_name = args
28
+ app = NexClient::App.find(name: app_name).first
29
+
30
+ # Display error
31
+ unless app
32
+ error("Error! Could not find app: #{app_name}")
33
+ return false
34
+ end
35
+
36
+ addon = NexClient::Addon.new(service: svc_name)
37
+ addon.relationships.attributes = { app: { data: { type: 'apps', id: app.id } } }
38
+ addon.save
39
+
40
+ # Display errors if any
41
+ if addon.errors.any?
42
+ display_record_errors(addon)
43
+ return false
44
+ end
45
+
46
+ # Display app
47
+ self.display_addons(NexClient::Addon.includes(:app).find(addon.id).first)
48
+ end
49
+
50
+ def self.destroy(args,opts)
51
+ name = args.first
52
+ e = NexClient::Addon.find(name: name).first
53
+
54
+ # Display error
55
+ unless e
56
+ error("Error! Could not find addon: #{name}")
57
+ return false
58
+ end
59
+
60
+ # Ask confirmation
61
+ answer = ask("Enter the name of this addon to confirm: ")
62
+ unless answer == e.name
63
+ error("Aborting deletion...")
64
+ return false
65
+ end
66
+
67
+ e.destroy
68
+ success("Successfully destroyed addon: #{name}")
69
+ end
70
+
71
+ def self.display_addons(list)
72
+ table = Terminal::Table.new title: ADDONS_TITLE, headings: ADDONS_HEADERS do |t|
73
+ [list].flatten.compact.each do |e|
74
+ t.add_row(self.format_record(e))
75
+ end
76
+ end
77
+ puts table
78
+ puts "\n"
79
+ end
80
+
81
+ def self.format_record(record)
82
+ app = self.format_app(record)
83
+ [
84
+ record.id,
85
+ record.name,
86
+ record.status,
87
+ record.service,
88
+ app
89
+ ]
90
+ end
91
+
92
+ def self.format_app(record)
93
+ return '-' unless a = record.app
94
+ a.name
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,301 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NexClient
4
+ module Commands
5
+ module Apps
6
+ extend Helpers
7
+
8
+ SCALING_DIRECTIONS = [:up,:down]
9
+ APPS_TITLE = "App Details".colorize(:green)
10
+ APPS_HEADERS = ['id','name','status','image','ssl','storage','preferred region','nodes','owner'].map(&:upcase)
11
+
12
+ VARS_TITLE = "Environment Variables".colorize(:blue)
13
+ VARS_HEADERS = ['key','value'].map(&:upcase)
14
+
15
+ SCM_TITLE = "Source Control Management".colorize(:yellow)
16
+ SCM_HEADERS = ['provider','repo','branch','last commit'].map(&:upcase)
17
+
18
+ def self.list(args,opts)
19
+ filters = {}
20
+ filters[:status] = [opts.status || 'active']
21
+ filters[:ssl_enabled] = opts.ssl if opts.ssl.present?
22
+ filters[:persistent_storage] = opts.storage if opts.storage.present?
23
+ filters[:'owner.handle'] = opts.owner if opts.owner.present?
24
+
25
+ # All option
26
+ filters = {} if opts.all
27
+
28
+ # Display
29
+ list = NexClient::App.includes(:owner).where(filters).order('status')
30
+ self.display_apps(list)
31
+ end
32
+
33
+ def self.info(args,opts)
34
+ name = args.first
35
+ e = NexClient::App.includes(:addons,:owner).find(name: name).first
36
+
37
+ # Display error
38
+ unless e
39
+ error("Error! Could not find app: #{name}")
40
+ return false
41
+ end
42
+
43
+ # Display app details
44
+ self.display_apps(e)
45
+
46
+ # Display all vars
47
+ self.display_vars(e.all_vars)
48
+
49
+ # Display all vars
50
+ self.display_scm(e.scm)
51
+
52
+ # Display all addons
53
+ Addons.display_addons(e.addons.select { |a| a.status == 'active'})
54
+ end
55
+
56
+ def self.create(args,opts)
57
+ image_info = args.first.split(':')
58
+ attrs = { image: image_info[0], image_tag: image_info[1] }
59
+
60
+ # Meta attributes
61
+ attrs[:ssl_enabled] = !opts.no_ssl if opts.no_ssl.present?
62
+ attrs[:persistent_storage] = opts.storage if opts.storage.present?
63
+
64
+ # Env variables via command line
65
+ if opts.env.present?
66
+ attrs[:vars] ||= {}
67
+ opts.env.each do |e|
68
+ key,val = e.split('=',2)
69
+ attrs[:vars][key] = val
70
+ end
71
+ end
72
+
73
+ # Env variables from file
74
+ if opts.env_file.present?
75
+ f = File.read(opts.env_file)
76
+ attrs[:vars] ||= {}
77
+ f.split('\n').each do |e|
78
+ key,val = e.split('=',2)
79
+ attrs[:vars][key] = val
80
+ end
81
+ end
82
+
83
+ # Create the app
84
+ e = NexClient::App.new(attrs)
85
+
86
+ # Add owner if specified
87
+ if opts.owner.present?
88
+ o = NexClient::Organization.find(handle:opts.owner).first
89
+ unless o
90
+ error("Error! Could not find organization: #{opts.owner}")
91
+ return false
92
+ end
93
+ e.relationships.attributes = { owner: { data: { type: 'organizations', id: o.id } } }
94
+ end
95
+
96
+ # Save the resource
97
+ e.save
98
+
99
+ # Display errors if any
100
+ if e.errors.any?
101
+ self.display_record_errors(e)
102
+ return false
103
+ end
104
+
105
+ # Display app
106
+ self.display_apps(NexClient::App.includes(:owner).find(e.id).first)
107
+ end
108
+
109
+ def self.destroy(args,opts)
110
+ name = args.first
111
+ e = NexClient::App.find(name: name).first
112
+
113
+ # Display error
114
+ unless e
115
+ error("Error! Could not find app: #{name}")
116
+ return false
117
+ end
118
+
119
+ # Ask confirmation
120
+ answer = ask("Enter the name of this app to confirm: ")
121
+ unless answer == e.name
122
+ error("Aborting deletion...")
123
+ return false
124
+ end
125
+
126
+ e.destroy
127
+ success("Successfully destroyed app: #{name}")
128
+ end
129
+
130
+ def self.restart(args,opts)
131
+ name = args.first
132
+ e = NexClient::App.find(name: name).first
133
+
134
+ # Display error
135
+ unless e
136
+ error("Error! Could not find app: #{name}")
137
+ return false
138
+ end
139
+
140
+ # Perform
141
+ e.restart
142
+
143
+ # Display errors if any
144
+ if e.errors.any?
145
+ display_record_errors(e)
146
+ return false
147
+ end
148
+
149
+ success("Initiated phased restart for app: #{name}...")
150
+ end
151
+
152
+ def self.scale(direction,args,opts)
153
+ return false unless SCALING_DIRECTIONS.include?(direction.to_sym)
154
+ name = args.first
155
+ e = NexClient::App.find(name: name).first
156
+
157
+ # Display error
158
+ unless e
159
+ error("Error! Could not find app: #{name}")
160
+ return false
161
+ end
162
+
163
+ # Scaling attributes
164
+ attrs = {}
165
+ count = opts.count || 1
166
+ attrs[:count] = count
167
+ attrs[:preferred_region] = opts.region if opts.region.present?
168
+
169
+ # Perform
170
+ e.send("scale_#{direction}",{data: { attributes: attrs } })
171
+
172
+ # Display errors if any
173
+ if e.errors.any?
174
+ display_record_errors(e)
175
+ return false
176
+ end
177
+
178
+ success("Successfully requested to scale #{name} #{direction} by #{count} #{'node'.pluralize(count)}...")
179
+ end
180
+
181
+ def self.manage_vars(args,opts)
182
+ name = args.first
183
+ e = NexClient::App.find(name: name).first
184
+
185
+ # Display error
186
+ unless e
187
+ error("Error! Could not find app: #{name}")
188
+ return false
189
+ end
190
+
191
+ # Add/Delete vars
192
+ if opts.add.present? || opts.delete.present?
193
+ vars = (e.vars || {}).dup
194
+
195
+ # Add vars
196
+ (opts.add || []).each do |v|
197
+ key,val = v.split('=',2)
198
+ vars[key] = val
199
+ end
200
+
201
+ # Delete vars
202
+ (opts.delete || []).each { |k| vars.delete(k) }
203
+
204
+ # Update and reload the resource
205
+ e.update_attributes(vars: vars)
206
+ e = NexClient::App.find(e.id).first
207
+ end
208
+
209
+ # Display all vars
210
+ self.display_vars(e.all_vars)
211
+ end
212
+
213
+ def self.manage_scm(args,opts)
214
+ name = args.first
215
+ e = NexClient::App.find(name: name).first
216
+
217
+ # Display error
218
+ unless e
219
+ error("Error! Could not find app: #{name}")
220
+ return false
221
+ end
222
+
223
+ # Link SCM
224
+ if opts.link
225
+ provider,repo,branch = opts.link.split(':')
226
+ attrs = { provider: provider, config: { repo: repo, branch: branch } }
227
+
228
+ # Update and reload the resource
229
+ e.link_scm({data: { attributes: attrs } })
230
+ e = NexClient::App.find(e.id).first
231
+ end
232
+
233
+ # Unlink SCM
234
+ if !opts.link && opts.unlink
235
+ # Update and reload the resource
236
+ e.unlink_scm
237
+ e = NexClient::App.find(e.id).first
238
+ end
239
+
240
+ # Display all vars
241
+ self.display_scm(e.scm)
242
+ end
243
+
244
+ def self.display_apps(list)
245
+ table = Terminal::Table.new title: APPS_TITLE, headings: APPS_HEADERS do |t|
246
+ [list].flatten.compact.each do |e|
247
+ t.add_row(self.format_record(e))
248
+ end
249
+ end
250
+ puts table
251
+ puts "\n"
252
+ end
253
+
254
+ def self.display_vars(list)
255
+ table = Terminal::Table.new title: VARS_TITLE, headings: VARS_HEADERS do |t|
256
+ [list].flatten.compact.each do |e|
257
+ e.each { |k,v| t.add_row([k,v]) }
258
+ end
259
+ end
260
+ puts table
261
+ puts "\n"
262
+ end
263
+
264
+ def self.display_scm(list)
265
+ table = Terminal::Table.new title: SCM_TITLE, headings: SCM_HEADERS do |t|
266
+ [list].flatten.compact.each do |e|
267
+ t.add_row([e['provider'],e['repo'],e['branch'],e['last_commit'] || '- nothing pushed yet -'])
268
+ end
269
+ end
270
+ puts table
271
+ puts "\n"
272
+ end
273
+
274
+ def self.format_record(record)
275
+ owner = self.format_owner(record)
276
+ node_count = self.format_node_count(record)
277
+ [
278
+ record.id,
279
+ record.name,
280
+ record.status,
281
+ record.image,
282
+ record.ssl_enabled,
283
+ record.persistent_storage,
284
+ record.preferred_region,
285
+ node_count,
286
+ owner
287
+ ]
288
+ end
289
+
290
+ def self.format_owner(record)
291
+ return '-' unless o = record.owner
292
+ "#{o.type[0]}:#{o.handle}"
293
+ end
294
+
295
+ def self.format_node_count(record)
296
+ return '-' unless record.node_count && record.max_node_count
297
+ "#{record.node_count}/#{record.max_node_count}"
298
+ end
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+ module NexClient
3
+ module Commands
4
+ module CubeInstances
5
+ extend Helpers
6
+
7
+ CUBES_TITLE = "Cube Instances".colorize(:blue)
8
+ CUBES_HEADERS = ['id','status','region','ssl','storage','SOA','ip','port','dns','cluster'].map(&:upcase)
9
+
10
+ def self.list(args,opts)
11
+ filters = {}
12
+ filters[:status] = opts.status || 'running'
13
+ filters[:soa_enabled] = opts.soa if opts.soa.present?
14
+ filters[:ssl_enabled] = opts.ssl if opts.ssl.present?
15
+ filters[:persistent_storage] = opts.storage if opts.storage.present?
16
+
17
+ # All option
18
+ filters = {} if opts.all
19
+
20
+ # Identification options
21
+ filters[:dns] = opts.dns if opts.dns.present?
22
+ filters[:'app.name'] = opts.app if opts.app.present?
23
+ filters[:'addon.name'] = opts.addon if opts.addon.present?
24
+
25
+ # Create table
26
+ list = NexClient::CubeInstance.includes(:cluster).where(filters).order('status')
27
+ self.display_cubes(list)
28
+ end
29
+
30
+ def self.trigger_action(action,args,opts)
31
+ name = args.first
32
+ e = NexClient::CubeInstance.find(name: name).first
33
+
34
+ # Display error
35
+ unless e
36
+ error("Error! Could not find cube: #{name}")
37
+ return false
38
+ end
39
+
40
+ # Perform
41
+ e.send(action)
42
+
43
+ # Display errors if any
44
+ if e.errors.any?
45
+ display_record_errors(e)
46
+ return false
47
+ end
48
+
49
+ success("Initiated #{action} for cube #{name}...")
50
+ end
51
+
52
+ def self.display_cubes(list)
53
+ table = Terminal::Table.new title: CUBES_TITLE, headings: CUBES_HEADERS do |t|
54
+ [list].flatten.compact.each do |e|
55
+ t.add_row(self.format_record(e))
56
+ end
57
+ end
58
+ puts table
59
+ puts "\n"
60
+ end
61
+
62
+ def self.format_record(record)
63
+ dns = self.format_dns(record)
64
+ cluster = self.format_cluster(record)
65
+ [
66
+ record.id,
67
+ record.status,
68
+ record.region,
69
+ record.ssl_enabled,
70
+ record.persistent_storage,
71
+ record.soa_enabled,
72
+ record.ip_address || '-',
73
+ record.port || '-',
74
+ dns,
75
+ cluster
76
+ ]
77
+ end
78
+
79
+ def self.format_dns(record)
80
+ record.dns || '-'
81
+ end
82
+
83
+ def self.format_cluster(record)
84
+ return '-' unless o = record.cluster
85
+ "#{o.type.singularize}:#{o.name}"
86
+ end
87
+ end
88
+ end
89
+ end