mkit 0.4.3 → 0.5.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 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