mkit 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb997b1bc61151dde6209eeaefdf4f669df9255b7e69735eb0c5c56e346222f1
4
- data.tar.gz: 3819a29d9335a2d4831051d133d9e0056b93d54803701a27ed596a750f907d7b
3
+ metadata.gz: fc469f170acb4204c99a3c5d5b42d474e68d3541dca30920068b5b7d1c56c526
4
+ data.tar.gz: 97bd822d57128df2a7e3ae584af116aa09a250b41fed9f1dd362aa29bd3d49fb
5
5
  SHA512:
6
- metadata.gz: c95a967e4a016554700b9e844de87481fd8f4b1f71e2cb4cdae16509104b177485f6cdcc3aa114f3d4ab8680e8d39fb05c125fca4dd81edbb089800d08ec275e
7
- data.tar.gz: f62ac16133370c7bc41f901fe148b708c046f4598331848daefd4bb108419f7b2fc510a9176bff771fbff3afa4e38d5ce000d70d8cad1feeb41b8f339956d802
6
+ metadata.gz: d03fa8ceeb3668ef280fa558ce5e5002110f98cdc8bb30fef4ab299e55b532ed6faee2ddb1203925567bec8657daddcbe7eaa9cc63440350b11aca321b8c3fec
7
+ data.tar.gz: 26087de2da9a6c65a3c42c92714a83419f91c7832549b04b39f5900d47d6a574e8cb180d42d62d09e5263b56eba3ea7858e2b8b0fcf6788609be30a7e8e62ddb
data/README.md CHANGED
@@ -49,13 +49,13 @@ or after the `gem install mkit-<version>.gem`. The server and client will be ins
49
49
  0.65s info: MKIt is up and running! [ec=0xbe0] [pid=45804] [2023-12-29 15:46:04 +0000]
50
50
  ```
51
51
 
52
- There's also samples on the samples dir, for daemontools and systemd.
52
+ There's also samples on the samples dir, for `daemontools` and `systemd`.
53
53
 
54
54
  ### Accessing the API
55
55
 
56
- A client is provided to interact with mkit server.
56
+ A client is provided to interact with `mkit server`.
57
57
 
58
- Run `mkitc help` to list current supported commands.
58
+ Run `mkitc help` for a list of current supported commands.
59
59
 
60
60
  ```
61
61
  Usage: mkitc <command> [options]
@@ -75,6 +75,7 @@ update update service
75
75
  rm remove service
76
76
  version prints mkit server version
77
77
  proxy haproxy status and control
78
+ profile mkit client configuration profile
78
79
 
79
80
  Run 'mkitc help <command>' for specific command information.
80
81
  ```
@@ -93,7 +94,40 @@ The service `postgres` is available on IP `10.210.198.10:5432`
93
94
 
94
95
  ## Configuration
95
96
 
96
- On startup, configuration files on `config` directory will be copied to `/etc/mkit`. HAProxy config directory and control commands are defined on `mkit_config.yml`
97
+ ### Server configuration
98
+
99
+ On startup, configuration files on `config` directory will be copied to `/etc/mkit`.
100
+
101
+ The server is available by default on `http://localhost:4567` but you can configure server startup parameters on `/etc/mkit/mkitd_config.sh`
102
+
103
+ Please check `samples/systemd` or `samples/daemontools` directories for more details.
104
+
105
+ ```
106
+ # /etc/mkit/mkitd_config.sh
107
+ #
108
+ # mkitd server options (for systemd unit | daemontools)
109
+ #
110
+ OPTIONS=""
111
+ # e.g. OPTIONS="-b 0.0.0.0"
112
+ ```
113
+ HAProxy config directory and control commands are defined on `mkit_config.yml`
114
+
115
+ ```
116
+ # /etc/mkit/mkit_config.yml - mkit server configuration file.
117
+ mkit:
118
+ my_network:
119
+ ip: 10.210.198.1
120
+ haproxy:
121
+ config_dir: /etc/haproxy/haproxy.d
122
+ ctrl:
123
+ start: systemctl start haproxy
124
+ stop: systemctl stop haproxy
125
+ reload: systemctl reload haproxy
126
+ restart: systemctl restart haproxy
127
+ status: systemctl status haproxy
128
+ database:
129
+ env: development
130
+ ```
97
131
 
98
132
  You must configure `haproxy` to use config directory. e.g. on Ubuntu
99
133
 
@@ -111,6 +145,20 @@ CONFIG="/etc/haproxy/haproxy.d"
111
145
  # Add extra flags here, see haproxy(1) for a few options
112
146
  #EXTRAOPTS="-de -m 16"
113
147
  ```
148
+ ### Client configuration
149
+
150
+ On `mkitc` first call, default configuration will be copied to `$HOME/.mkit` with `local`default profile set.
151
+
152
+ You can add more servers and change active profile with `$mkitc profile set <profile_name>`, e.g. `$mkitc profile set server_2`
153
+
154
+ ```
155
+ # ~/.mkit/mkitc_config.yml
156
+ mkit:
157
+ local:
158
+ server.uri: http://localhost:4567
159
+ server_2: # you can add more servers. change the client active profile with mkitc profile command
160
+ server.uri: http://192.168.29.232:4567
161
+ ```
114
162
 
115
163
  ### Service
116
164
 
data/bin/mkitc CHANGED
@@ -9,25 +9,24 @@ require 'json'
9
9
  require 'net_http_unix'
10
10
  require 'securerandom'
11
11
  require 'erb'
12
+ require 'uri'
13
+ require 'fileutils'
12
14
 
13
- class InvalidParametersException < RuntimeError
15
+ class InvalidParametersException < Exception
14
16
  attr_reader :command
17
+
15
18
  def initialize(cause, command = nil)
16
19
  super(cause)
17
20
  @command = command
18
21
  end
19
22
  end
20
23
 
21
- class MKItClient
22
- def initialize
23
- @client = NetX::HTTPUnix.new('localhost', 4567)
24
- end
25
-
26
- def dict
24
+ class CommandPalette
25
+ def schema
27
26
  global_args = [
28
27
  { short: '-v', long: '--verbose', help: 'verbose', mandatory: false, value: nil }
29
28
  ]
30
- command_dict = [
29
+ [
31
30
  {
32
31
  cmd: 'ps',
33
32
  args: [
@@ -140,69 +139,89 @@ class MKItClient
140
139
  ],
141
140
  help: 'haproxy status and control',
142
141
  usage: ['<start|stop|restart|status>']
142
+ },
143
+ {
144
+ cmd: 'profile',
145
+ options: [
146
+ {
147
+ cmd: 'set',
148
+ request: { verb: 'set' },
149
+ args: [
150
+ { name: 'profile_name', mandatory: true }
151
+ ],
152
+ help: 'set mkit client configuration profile'
153
+ },
154
+ {
155
+ cmd: 'show',
156
+ request: { verb: 'show' },
157
+ help: 'show mkit client current profile'
158
+ }
159
+ ],
160
+ help: 'mkit client configuration profile',
161
+ usage: ['<[set <profile_name>]|[show]>']
143
162
  }
144
163
  ]
145
- command_dict
146
164
  end
165
+ end
147
166
 
148
- def help(cause: nil, cmd: nil)
149
- msg = ''
150
- if cause.nil?
151
- my_cmd = cmd
152
- else
153
- msg += "MKItc: #{cause.message}\n"
154
- my_cmd = cause.command
155
- end
156
- if my_cmd.nil?
157
- msg += "\nUsage: mkitc <command> [options]\n\n"
158
- msg += "Micro k8s on Ruby - a simple tool to mimic a (very) minimalistic k8 cluster\n\n"
159
- msg += "Commands:\n\n"
160
- dict.each do |c|
161
- msg += format("%-10s %s\n", c[:cmd], c[:help])
162
- end
163
- msg += "\n"
164
- msg += "Run 'mkitc help <command>' for specific command information.\n\n"
165
- else
166
- msg += format("\nUsage: mkitc %s %s\n\n", my_cmd[:cmd], my_cmd[:usage].nil? ? '' : my_cmd[:usage].join(' '))
167
- msg += format("%s\n", my_cmd[:help])
168
- unless my_cmd[:options].nil?
169
- msg += "\nOptions:\n"
170
- my_cmd[:options].each do |c|
171
- msg += format("%-10s %s\n", c[:cmd], c[:help])
172
- end
173
- end
174
- msg += "\n"
175
- end
176
- puts msg
177
- exit 1
167
+ class MKItClient
168
+ def initialize
169
+ @root = File.expand_path('..', __dir__)
170
+ @config_dir = "#{ENV['HOME']}/.mkit"
171
+ @profile_file = "#{@config_dir}/current"
172
+ @commands = CommandPalette.new
173
+ create_default_config
178
174
  end
179
175
 
180
- def create(request, request_hash = nil)
181
- unless File.file?(request_hash[:file])
182
- raise InvalidParametersException.new('File not found.', c = dict.select { |k| k[:cmd] == 'create' }.first)
176
+ def create_default_config
177
+ unless File.exist?(@config_dir)
178
+ puts "Creating config directory on '#{@config_dir}'..."
179
+ FileUtils.mkdir_p(@config_dir)
183
180
  end
181
+ FileUtils.cp("#{@root}/config/mkitc_config.yml", @config_dir) unless File.exist?("#{@config_dir}/mkitc_config.yml")
182
+ profile({ verb: 'set' }, { profile_name: 'local' }) unless File.exist?(@profile_file)
183
+ end
184
184
 
185
- yaml = YAML.load_file(request_hash[:file])
186
- if yaml['service'].nil?
187
- raise InvalidParametersException.new('Invalid configuration file', c = dict.select { |k| k[:cmd] == 'create' }.first)
188
- else
189
- request(request, request_hash)
185
+ def read_configuration
186
+ current_profile = File.read(@profile_file)
187
+ if current_profile.nil? || current_profile.empty?
188
+ # force set default
189
+ profile({ verb: 'set' }, { profile_name: 'local' })
190
+ current_profile = 'local'
190
191
  end
191
- end
192
+ cfg = YAML.load_file("#{@config_dir}/mkitc_config.yml")
192
193
 
193
- def update(request, request_hash = nil)
194
- unless File.file?(request_hash[:file])
195
- raise InvalidParametersException.new('File not found.', c = dict.select { |k| k[:cmd] == 'update' }.first)
194
+ if cfg['mkit'].nil? || cfg['mkit'][current_profile.lstrip].nil?
195
+ raise InvalidParametersException, "invalid configuration found on '~/.mkit' or profile not found"
196
196
  end
197
197
 
198
- yaml = YAML.load_file(request_hash[:file])
199
- if yaml['service'].nil?
200
- raise InvalidParametersException.new('Invalid configuration file', c = dict.select { |k| k[:cmd] == 'update' }.first)
198
+ @configuration = cfg['mkit'][current_profile.lstrip]
199
+ end
200
+
201
+ def client
202
+ read_configuration
203
+ uri = URI(@configuration['server.uri'])
204
+ case uri.scheme
205
+ when 'https'
206
+ @client = NetX::HTTPUnix.new(uri.host, uri.port)
207
+ @client.use_ssl = true
208
+ @client.verify_mode = OpenSSL::SSL::VERIFY_NONE
209
+ when 'http'
210
+ @client = NetX::HTTPUnix.new(uri.host, uri.port)
211
+ when 'sock'
212
+ @client = NetX::HTTPUnix.new("unix://#{uri.path}")
201
213
  else
202
- id = yaml['service']['name']
203
- request_hash[:id] = id
204
- request(request, request_hash)
214
+ raise InvalidParametersException, 'Invalid mkit server uri. Please check configuration'
205
215
  end
216
+ @client
217
+ end
218
+
219
+ def dict
220
+ @commands.schema
221
+ end
222
+
223
+ def find_command(cmd)
224
+ dict.select { |k| k[:cmd] == cmd }.first
206
225
  end
207
226
 
208
227
  def parse_args(args)
@@ -211,55 +230,35 @@ class MKItClient
211
230
  # short circuit for help
212
231
  if cmd == 'help' || args.empty?
213
232
  if args.size > 1
214
- c = dict.select { |k| k[:cmd] == args[1] }.first
233
+ c = find_command(args[1])
215
234
  raise InvalidParametersException, "'#{args[1]}' is not a valid help topic." if c.nil?
216
235
  end
217
236
  return help(cmd: c)
218
237
  else
219
- c = dict.select { |k| k[:cmd] == cmd }.first
238
+ c = find_command(cmd)
220
239
  end
221
240
  raise InvalidParametersException, 'Command not found' if c.nil?
222
241
 
242
+ command = c
223
243
  myargs = args.dup
224
244
  myargs.delete(cmd)
225
245
 
226
- max_args_size = c[:args].nil? ? 0 : c[:args].size
227
- max_options_size = c[:options].nil? ? 0 : 1
228
- max_args_size += max_options_size
229
-
230
- min_args_size = c[:args].nil? ? 0 : c[:args].select { |a| a[:mandatory] == true }.size
231
- min_options_size = c[:options].nil? ? 0 : 1
232
- min_args_size += min_options_size
233
-
234
- if myargs.size > max_args_size || myargs.size < min_args_size
235
- raise InvalidParametersException.new('Invalid parameters found.', c)
236
- end
237
-
238
246
  request_hash = {}
239
- request = c[:request]
247
+ request = command[:request]
240
248
  unless myargs.empty?
241
- unless c[:args].nil?
242
- idx = 0
243
- c[:args].each do |a|
244
- request_hash[a[:name].to_sym] = myargs[idx]
245
- request[:uri] = request[:uri] + a[:uri] unless a[:uri].nil?
246
- idx += 1
247
- end
248
- end
249
249
  # options
250
250
  unless c[:options].nil?
251
- option = nil
252
- myargs.each do |s|
253
- option = c[:options].select { |o| o[:cmd] == s }.first
254
- raise InvalidParametersException.new('Invalid parameters found.', c) if option.nil? || option.empty?
255
- end
256
- raise InvalidParametersException.new('Invalid parameters found.', c) if option.nil? || option.empty?
251
+ command = c[:options].select { |o| o[:cmd] == myargs[0] }.first
252
+ raise InvalidParametersException.new('Invalid parameters found.', c) if command.nil? || command.empty?
257
253
 
258
- request = option[:request]
254
+ myargs.delete_at(0)
255
+ request = command[:request]
259
256
  end
257
+ fill_cmd_args(command[:args], myargs, request, request_hash)
260
258
  end
261
- raise InvalidParametersException, "Can't find request." if request.nil?
259
+ raise InvalidParametersException.new('Invalid command or parameters.', c) if request.nil?
262
260
 
261
+ validate_command(command, request_hash)
263
262
  if respond_to? c[:cmd]
264
263
  send(c[:cmd], request, request_hash)
265
264
  else
@@ -267,11 +266,25 @@ class MKItClient
267
266
  end
268
267
  end
269
268
 
270
- def doIt(args)
271
- result = parse_args(args)
272
- puts result
273
- rescue InvalidParametersException => e
274
- help(cause: e)
269
+ def fill_cmd_args(args, myargs, request, request_hash)
270
+ return if args.nil?
271
+
272
+ idx = 0
273
+ args.each do |a|
274
+ request_hash[a[:name].to_sym] = myargs[idx]
275
+ request[:uri] = request[:uri] + a[:uri] unless a[:uri].nil?
276
+ idx += 1
277
+ end
278
+ end
279
+
280
+ def validate_command(command, request_hash)
281
+ return if command[:args].nil?
282
+
283
+ command[:args].select { |a| a[:mandatory] == true }.each do |a|
284
+ if request_hash[a[:name].to_sym].nil?
285
+ raise InvalidParametersException.new("Missing mandatory parameter: #{a[:name]}", command)
286
+ end
287
+ end
275
288
  end
276
289
 
277
290
  def request(request, request_args = nil)
@@ -304,7 +317,7 @@ class MKItClient
304
317
  when :delete
305
318
  req = Net::HTTP::Delete.new(uri)
306
319
  end
307
- @client.request(req).body
320
+ client.request(req).body
308
321
  end
309
322
 
310
323
  def attach(file)
@@ -318,6 +331,106 @@ class MKItClient
318
331
  body << "\r\n--#{boundary}--\r\n"
319
332
  [body.join, boundary]
320
333
  end
334
+
335
+ def doIt(args)
336
+ result = parse_args(args)
337
+ puts result
338
+ rescue InvalidParametersException => e
339
+ help(cause: e)
340
+ end
341
+
342
+ def help(cause: nil, cmd: nil)
343
+ msg = ''
344
+ if cause.nil?
345
+ my_cmd = cmd
346
+ else
347
+ msg += "MKItc: #{cause.message}\n"
348
+ my_cmd = cause.command
349
+ end
350
+ if my_cmd.nil?
351
+ msg += "\nUsage: mkitc <command> [options]\n\n"
352
+ msg += "Micro k8s on Ruby - a simple tool to mimic a (very) minimalistic k8 cluster\n\n"
353
+ msg += "Commands:\n\n"
354
+ dict.each do |c|
355
+ msg += format("%-10s %s\n", c[:cmd], c[:help])
356
+ end
357
+ msg += "\n"
358
+ msg += "Run 'mkitc help <command>' for specific command information.\n\n"
359
+ else
360
+ msg += format("\nUsage: mkitc %s %s\n\n", my_cmd[:cmd], my_cmd[:usage].nil? ? '' : my_cmd[:usage].join(' '))
361
+ msg += format("%s\n", my_cmd[:help])
362
+ unless my_cmd[:options].nil?
363
+ msg += "\nOptions:\n"
364
+ my_cmd[:options].each do |c|
365
+ msg += format("%-10s %s\n", c[:cmd], c[:help])
366
+ end
367
+ end
368
+ msg += "\n"
369
+ end
370
+ puts msg
371
+ exit 1
372
+ end
373
+
374
+ def create(request, request_hash = nil)
375
+ unless File.file?(request_hash[:file])
376
+ raise InvalidParametersException.new('File not found.', find_command('create'))
377
+ end
378
+
379
+ yaml = YAML.load_file(request_hash[:file])
380
+ if yaml['service'].nil?
381
+ raise InvalidParametersException.new('Invalid configuration file', find_command('create'))
382
+ else
383
+ request(request, request_hash)
384
+ end
385
+ end
386
+
387
+ def update(request, request_hash = nil)
388
+ unless File.file?(request_hash[:file])
389
+ raise InvalidParametersException.new('File not found.', find_command('update'))
390
+ end
391
+
392
+ yaml = YAML.load_file(request_hash[:file])
393
+ if yaml['service'].nil?
394
+ raise InvalidParametersException.new('Invalid configuration file', find_command('update'))
395
+ else
396
+ id = yaml['service']['name']
397
+ request_hash[:id] = id
398
+ request(request, request_hash)
399
+ end
400
+ end
401
+
402
+ def profile(request, request_hash = {})
403
+ cfg = YAML.load_file("#{@config_dir}/mkitc_config.yml")
404
+ cmd = find_command('profile')
405
+ if cfg['mkit'].nil?
406
+ raise InvalidParametersException.new(
407
+ "Invalid configuration on '~/.mkit'\nPlease fix or clean up for defaults apply", cmd
408
+ )
409
+ end
410
+
411
+ case request[:verb]
412
+ when 'set'
413
+ profile = request_hash[:profile_name]
414
+ if cfg['mkit'][profile.lstrip].nil?
415
+ raise InvalidParametersException.new("Profile not found on '~/.mkit' configuration", cmd)
416
+ end
417
+
418
+ puts "Setting current profile to #{profile}."
419
+ File.write(@profile_file, request_hash[:profile_name])
420
+ ''
421
+ when 'show'
422
+ active = File.read("#{@config_dir}/current")
423
+ cfg['mkit'].map do |k, _v|
424
+ if k == active
425
+ "*#{k}"
426
+ else
427
+ k
428
+ end
429
+ end.join(' ')
430
+ else
431
+ raise InvalidParametersException.new("Invalid 'profile' operation", cmd)
432
+ end
433
+ end
321
434
  end
322
435
 
323
436
  #
@@ -0,0 +1,3 @@
1
+ mkit:
2
+ local:
3
+ server.uri: http://localhost:4567
@@ -1,5 +1,5 @@
1
1
  #
2
- # kidsd server options (for systemd unit | daemontools)
2
+ # mkitd server options (for systemd unit | daemontools)
3
3
  #
4
4
  OPTIONS=""
5
5
 
data/lib/mkit/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module MKIt
2
- VERSION = "0.4.3"
2
+ VERSION = "0.5.0"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vasco Santos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-12 00:00:00.000000000 Z
11
+ date: 2024-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-dns
@@ -311,6 +311,7 @@ files:
311
311
  - bin/mkitd
312
312
  - config/database.yml
313
313
  - config/mkit_config.yml
314
+ - config/mkitc_config.yml
314
315
  - config/mkitd_config.sh
315
316
  - db/migrate/001_setup.rb
316
317
  - db/migrate/002_mkit_jobs.rb