consist 0.1.2 → 0.1.3

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: effa6a127c653d11567c095935c5ad02c06ffeed759344a114a4792c40b12e50
4
- data.tar.gz: 66207f1f0943ff8ffd5569ae4aa253c5f0594f003bf6c375f189c2c2ab08b9f8
3
+ metadata.gz: ce1770d8755d16d374ad05d69e36645c67b819926bd7a163e497714ca6400a20
4
+ data.tar.gz: '09ce200d04369a78c1d66bd4b389df1ff402951be094189d3d13c7042a18ff83'
5
5
  SHA512:
6
- metadata.gz: a96b06f251cd58a88683c6f7cd4c954b393013a115e5ab79927fed782fc395a3afb6aac3c6e2f3b9d90d9b7479669850a80f8301005e38ddab06250c4cb2a073
7
- data.tar.gz: f55c41e49e972b5e7d4f4f475e2ba7029a63589c383d312798f7d09b3ce075337e8a5cb1249114b8d96c559a545c14762a2efff55d1683457098e8d0c60f8e33
6
+ metadata.gz: b487a6385b295f593cd3477afe5be8031f1cee5de7742c6fe99892da0f28eba0a855f91fbb7cc84750538826e5bd763164a49c4ac172d448dec477c09bdc4847
7
+ data.tar.gz: 65cb3135f0ea5afc548b321282f289b7fe66e4642b80eecfa530174235f173616781d60cb976ec362d05f1496f9b8fc2ca3a025a7c96c6435129c941e375c5b8
data/README.md CHANGED
@@ -23,6 +23,7 @@ server, such as firewalls, general hardening, enabling swapfile etc.
23
23
  - Procedural declaration execution - no converging, orchestration or
24
24
  event driven operation
25
25
  - If you can shell script it, you can `consist` it directly
26
+ - Encouraging sharing of portable `Consistfiles` across the community
26
27
 
27
28
  ---
28
29
 
@@ -30,6 +31,13 @@ server, such as firewalls, general hardening, enabling swapfile etc.
30
31
  - [Support](#support)
31
32
  - [Rationale](#rationale)
32
33
  - [Key Concepts](#key-concepts)
34
+ - [Recipes](#recipes)
35
+ - [Steps](#steps)
36
+ - [Files](#files)
37
+ - [Consistfile](#consistfile)
38
+ - [Artifacts](#artifacts)
39
+ - [.consist directory](#.consist-directory)
40
+ - [Comunity Consistfiles](#community-consistfiles)
33
41
  - [Is It Good?](#is-it-good%3F)
34
42
  - [License](#license)
35
43
  - [Code of conduct](#code-of-conduct)
@@ -41,26 +49,32 @@ server, such as firewalls, general hardening, enabling swapfile etc.
41
49
  gem install consist
42
50
  ```
43
51
 
44
- You must be already auth'd with the server you want to scaffold. `consist` will use
45
- your SSH id to perform actions.
52
+ You must be already authenticated with the server you want to scaffold.
53
+ `consist` will use your account's SSH id to perform actions.
46
54
 
47
- Then, you have two ways of interacting with Consist. First is the `scaffold` command:
55
+ The main way of using `consist` is to go with a `Consistfile` in
56
+ your project root that describes the recipe and steps. Then you can say:
48
57
 
49
58
  ```sh
50
- consist scaffold <recipe_name> root <ip_address>
59
+ consist up <ip_address> [--consistfile=/path/to/consistfile] [--consistdir=/path/to/.consistdir]
51
60
  ```
52
61
 
53
- Will kick off the scaffolding of that given server with the given
54
- recipe, using the `root` user.
62
+ And `consist` will do it's thing with that given IP address.
55
63
 
56
- The other way of using `consist` is to go with a `Consistfile` in
57
- your project root that describes the recipe and steps. Then you can say:
64
+ To create a blank `Consistfile` in your project, execute:
58
65
 
59
- ```sh
60
- consist up <ip_address>
66
+ ```ruby
67
+ consist init
61
68
  ```
62
69
 
63
- And `consist` will do it's thing with that given IP address.
70
+ ## Commands
71
+
72
+ Other commands available:
73
+
74
+ - `consist init [account/repo]` - initialize your project with a new Consist file. Optionally,
75
+ you can specify a Github `account/repo` path and that location will be used to clone down a
76
+ Consistfile, and any associated artifacts needed by the Consistfile.
77
+ - `consist ping <ip_address>` - checks you can connect and authenticate with the given IP
64
78
 
65
79
  ## Features
66
80
 
@@ -160,9 +174,10 @@ end
160
174
 
161
175
  A `Consistfile` is a portable giant file of a recipe and all its
162
176
  steps. Something like (this is a _full_ example, in practice you
163
- would reference some of Consist's built in steps):
177
+ would reference some of Consists' built in steps):
164
178
 
165
179
  ```ruby
180
+ # This is a shortened non-complete example.
166
181
  consist do
167
182
  config :hostname, "testexample.com"
168
183
  config :site_fqdn, "textexample.com"
@@ -191,171 +206,6 @@ consist do
191
206
  EOS
192
207
  end
193
208
 
194
- file :fail2ban_config do
195
- <<~EOS
196
- # Fail2Ban configuration file.
197
- #
198
-
199
- # to view current bans, run one of the following:
200
- # fail2ban-client status ssh
201
- # iptables --list -n | fgrep DROP
202
-
203
- # The DEFAULT allows a global definition of the options. They can be overridden
204
- # in each jail afterwards.
205
-
206
- [DEFAULT]
207
-
208
- ignoreip = 127.0.0.1
209
- bantime = 600
210
- maxretry = 3
211
- backend = auto
212
- usedns = warn
213
- destemail = <%= admin_email %>
214
-
215
- #
216
- # ACTIONS
217
- #
218
-
219
- banaction = iptables-multiport
220
- mta = sendmail
221
- protocol = tcp
222
- chain = INPUT
223
-
224
- #
225
- # Action shortcuts. To be used to define action parameter
226
-
227
- # The simplest action to take: ban only
228
- action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
229
-
230
- # ban & send an e-mail with whois report to the destemail.
231
- action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
232
- %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"]
233
-
234
- # ban & send an e-mail with whois report and relevant log lines
235
- # to the destemail.
236
- action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
237
- %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
238
-
239
- # default action
240
- action = %(action_mw)s
241
-
242
- [ssh]
243
-
244
- enabled = true
245
- port = 987
246
- filter = sshd
247
- logpath = /var/log/auth.log
248
- maxretry = 6
249
-
250
- [ssh-ddos]
251
-
252
- enabled = true
253
- port = 987
254
- filter = sshd-ddos
255
- logpath = /var/log/auth.log
256
- maxretry = 6
257
- EOS
258
- end
259
-
260
- file :logwatch_config do
261
- <<~EOS
262
- Output = mail
263
- MailTo = <%= admin_email %>
264
- MailFrom = logwatch@host1.mydomain.org
265
- Detail = Low
266
- Service = All
267
- EOS
268
- end
269
-
270
- file :sysctl_config do
271
- <<~EOS
272
- # Do not accept ICMP redirects (prevent MITM attacks)
273
- net.ipv4.conf.all.accept_redirects = 0
274
- net.ipv6.conf.all.accept_redirects = 0
275
- # Do not send ICMP redirects (we are not a router)
276
- net.ipv4.conf.all.send_redirects = 0
277
- # Log Martian Packets
278
- net.ipv4.conf.all.log_martians = 1
279
- # Controls IP packet forwarding
280
- net.ipv4.ip_forward = 0
281
- # Controls source route verification
282
- net.ipv4.conf.default.rp_filter = 1
283
- # Do not accept source routing
284
- net.ipv4.conf.default.accept_source_route = 0
285
- # Controls the System Request debugging functionality of the kernel
286
- kernel.sysrq = 0
287
- # Controls whether core dumps will append the PID to the core filename
288
- # Useful for debugging multi-threaded applications
289
- kernel.core_uses_pid = 1
290
- # Controls the use of TCP syncookies
291
- net.ipv4.tcp_synack_retries = 2
292
- ######## IPv4 networking start ###########
293
- # Send redirects, if router, but this is just server
294
- net.ipv4.conf.all.send_redirects = 0
295
- net.ipv4.conf.default.send_redirects = 0
296
- # Accept packets with SRR option? No
297
- net.ipv4.conf.all.accept_source_route = 0
298
- # Accept Redirects? No, this is not router
299
- net.ipv4.conf.all.accept_redirects = 0
300
- net.ipv4.conf.all.secure_redirects = 0
301
- # Log packets with impossible addresses to kernel log? Yes
302
- net.ipv4.conf.all.log_martians = 1
303
- net.ipv4.conf.default.accept_source_route = 0
304
- net.ipv4.conf.default.accept_redirects = 0
305
- net.ipv4.conf.default.secure_redirects = 0
306
- # Ignore all ICMP ECHO and TIMESTAMP requests sent to it via broadcast/multicast
307
- net.ipv4.icmp_echo_ignore_broadcasts = 1
308
- # Prevent against the common 'syn flood attack'
309
- net.ipv4.tcp_syncookies = 1
310
- # Enable source validation by reversed path, as specified in RFC1812
311
- net.ipv4.conf.all.rp_filter = 1
312
- net.ipv4.conf.default.rp_filter = 1
313
- ######## IPv6 networking start ###########
314
- # Number of Router Solicitations to send until assuming no routers are present.
315
- # This is host and not router
316
- net.ipv6.conf.default.router_solicitations = 0
317
- # Accept Router Preference in RA?
318
- net.ipv6.conf.default.accept_ra_rtr_pref = 0
319
- # Learn Prefix Information in Router Advertisement
320
- net.ipv6.conf.default.accept_ra_pinfo = 0
321
- # Setting controls whether the system will accept Hop Limit settings from a router advertisement
322
- net.ipv6.conf.default.accept_ra_defrtr = 0
323
- #router advertisements can cause the system to assign a global unicast address to an interface
324
- net.ipv6.conf.default.autoconf = 0
325
- #how many neighbor solicitations to send out per address?
326
- net.ipv6.conf.default.dad_transmits = 0
327
- # How many global unicast IPv6 addresses can be assigned to each interface?
328
- net.ipv6.conf.default.max_addresses = 1
329
- ######## IPv6 networking ends ###########
330
- # Disabled, not used anymore
331
- #Enable ExecShield protection |
332
- #kernel.exec-shield = 1
333
- #kernel.randomize_va_space = 1
334
- # TCP and memory optimization
335
- # increase TCP max buffer size setable using setsockopt()
336
- #net.ipv4.tcp_rmem = 4096 87380 8388608
337
- #net.ipv4.tcp_wmem = 4096 87380 8388608
338
- # increase Linux auto tuning TCP buffer limits
339
- #net.core.rmem_max = 8388608
340
- #net.core.wmem_max = 8388608
341
- #net.core.netdev_max_backlog = 5000
342
- #net.ipv4.tcp_window_scaling = 1
343
- # increase system file descriptor limit
344
- fs.file-max = 65535
345
- #Allow for more PIDs
346
- kernel.pid_max = 65536
347
- #Increase system IP port limits
348
- net.ipv4.ip_local_port_range = 2000 65000
349
- # Disable IPv6 autoconf
350
- #net.ipv6.conf.all.autoconf = 0
351
- #net.ipv6.conf.default.autoconf = 0
352
- #net.ipv6.conf.eth0.autoconf = 0
353
- #net.ipv6.conf.all.accept_ra = 0
354
- #net.ipv6.conf.default.accept_ra = 0
355
- #net.ipv6.conf.eth0.accept_ra = 0
356
- EOS
357
- end
358
-
359
209
  recipe :kamal_single_server do
360
210
  name "Kamal Single Server Scaffold"
361
211
 
@@ -395,233 +245,50 @@ consist do
395
245
  EOS
396
246
  end
397
247
  end
248
+ end
249
+ end
250
+ end
398
251
 
399
- step :update_apt_packages do
400
- name "Updating APT packages"
401
- required_user :root
402
-
403
- upload_file message: "Uploading APT config...",
404
- local_file: :apt_auto_upgrade,
405
- remote_path: "/etc/apt/apt.conf.d/20auto-upgrades"
406
-
407
- shell do
408
- <<~EOS
409
- apt-get update && apt-get upgrade -y
410
- apt-get autoremove
411
- apt-get autoclean
412
- EOS
413
- end
414
- end
415
-
416
- step :install_apt_packages do
417
- name "Installing essential APT packages"
418
- required_user :root
419
-
420
- shell "Installing essential packages" do
421
- <<~EOS
422
- apt-get -y install build-essential curl git vim
423
- EOS
424
- end
425
- end
426
-
427
- step :setup_ntp do
428
- name "Installing NTP daemon"
429
- required_user :root
430
-
431
- shell "Configuring NTP daemon", params: {raise_on_non_zero_exit: false} do
432
- <<~EOS
433
- apt-get -y remove systemd-timesyncd
434
- timedatectl set-ntp no 2>1
435
- apt-get -y install ntp
436
- EOS
437
- end
438
-
439
- shell "Start NTP and Fail2Ban" do
440
- <<~EOS
441
- service ntp restart
442
- EOS
443
- end
444
- end
445
-
446
- step :install_fail2ban do
447
- name "Installing fail2ban"
448
- required_user :root
449
-
450
- shell "Installing essential packages" do
451
- <<~EOS
452
- apt-get -y install fail2ban
453
- EOS
454
- end
455
-
456
- upload_file message: "Uploading fail2ban confing", local_file: :fail2ban_config,
457
- remote_path: "/etc/fail2ban/jail.local"
458
-
459
- shell "Start Fail2Ban" do
460
- <<~EOS
461
- service fail2ban restart
462
- systemctl enable fail2ban.service
463
- EOS
464
- end
465
- end
466
-
467
- step :setup_swap do
468
- name "Configure and enable the swapfile"
469
- required_user :root
470
-
471
- check status: :nonexistant, file: "/swapfile" do
472
- shell do
473
- <<~EOS
474
- fallocate -l <%= swap_size %> /swapfile
475
- chmod 600 /swapfile
476
- mkswap /swapfile
477
- swapon /swapfile
478
- echo "\n/swapfile swap swap defaults 0 0\n" >> /etc/fstab
479
- sysctl vm.swappiness=<%=swap_swappiness%>
480
- echo "\nvm.swappiness=<%=swap_swappiness%>\n" >> /etc/sysctl.conf
481
- EOS
482
- end
483
- end
484
- end
485
-
486
- step :harden_ssh do
487
- name "Harden the SSH config"
488
-
489
- mutate_file mode: :replace, target_file: "/etc/ssh/sshd_config", match: "^#PasswordAuthentication yes$",
490
- target_string: "PasswordAuthentication no"
491
- mutate_file mode: :replace, target_file: "/etc/ssh/sshd_config", match: "^#PubkeyAuthentication yes$",
492
- target_string: "PubkeyAuthentication yes"
493
-
494
- shell do
495
- <<~EOS
496
- service ssh restart
497
- EOS
498
- end
499
- end
500
-
501
- step :harden_system do
502
- name "Harden the SYSCTL settings"
503
-
504
- upload_file message: "Uploading sysctl config...",
505
- local_file: :sysctl_config,
506
- remote_path: "/tmp/sysctl_config"
507
-
508
- shell do
509
- <<~EOS
510
- cat /etc/sysctl.conf /tmp/sysctl_config > /etc/sysctl.conf
511
- rm /tmp/sysctl_config
512
- sysctl -p
513
- EOS
514
- end
515
- end
516
-
517
- step :setup_ufw do
518
- name "Setup UFW"
519
-
520
- shell do
521
- <<~EOS
522
- ufw logging on
523
- ufw default deny incoming
524
- ufw default allow outgoing
525
- ufw allow 22
526
- ufw allow 80
527
- ufw allow 443
528
- ufw --force enable
529
- service ufw restart
530
- EOS
531
- end
532
- end
533
-
534
- step :setup_postfix do
535
- name "Install Postfix for admin emails"
252
+ # vim: filetype=ruby
253
+ ```
536
254
 
537
- shell do
538
- <<~EOS
539
- echo "postfix postfix/mailname string <%= site_fqdn %>" | debconf-set-selections
540
- EOS
541
- end
255
+ Given a `Consistfile` you could then say `consist up <ip_address>` and
256
+ it would just work.
542
257
 
543
- shell do
544
- <<~EOS
545
- echo "postfix postfix/main_mailer_type string 'Internet Site'" | debconf-set-selections
546
- EOS
547
- end
258
+ ### Artifacts
548
259
 
549
- shell do
550
- <<~EOS
551
- DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes postfix
552
- EOS
553
- end
554
- end
260
+ Artifacts allow you to split out your `Consistfile` into separate files.
555
261
 
556
- step :setup_logwatch do
557
- name "Setup Logwatch to automate log reporting"
262
+ You can create blocks in the `Consistfile` as shown above, but you can also only
263
+ specify an `id`, and that `id` will be used to try and attempt to load a file of that
264
+ name in the `.consist/<type>/<id>` directory. For example, referencing a file:
558
265
 
559
- shell do
560
- <<~EOS
561
- DEBIAN_FRONTEND=noninteractive apt-get install --assume-yes logwatch
562
- EOS
563
- end
266
+ ```ruby
267
+ file :apt_auto_upgrade
268
+ ```
564
269
 
565
- mutate_file mode: :replace, target_file: "/etc/cron.daily/00logwatch", match: "^/usr/sbin/logwatch --output mail$",
566
- target_string: "/usr/sbin/logwatch --output mail --mailto <%= admin_email %> --detail high", delim: "#"
270
+ Will attempt to load a file in `.consist/files/apt_auto_upgrade`. The same is
271
+ possible for any of the main types: `files`, `steps`, and `recipes`
567
272
 
568
- upload_file message: "Uploading Logwatch confing", local_file: :logwatch_config,
569
- remote_path: "/etc/logwatch/conf"
570
- end
273
+ ### `.consist` directory
571
274
 
572
- step :setup_docker do
573
- name "Setup Docker"
275
+ The `.consist` directory is assumed to be in the root of your project, and should
276
+ contain three subdirectories for each of the types: `files`, `steps`, `recipes`.
574
277
 
575
- shell do
576
- <<~EOS
577
- # Add Docker's official GPG key:
578
- apt-get update
579
- apt-get install ca-certificates curl gnupg -y
580
- install -m 0755 -d /etc/apt/keyrings
581
- rm /etc/apt/keyrings/docker.gpg
582
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --batch --no-tty --dearmor -o /etc/apt/keyrings/docker.gpg
583
- chmod a+r /etc/apt/keyrings/docker.gpg
584
-
585
- # Add the repository to Apt sources:
586
- echo \
587
- "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
588
- $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
589
- tee /etc/apt/sources.list.d/docker.list > /dev/null
590
- apt-get update
591
-
592
- # Install Docker
593
- apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
594
-
595
- # Make Docker start on boot
596
- sudo systemctl enable docker.service
597
- sudo systemctl enable containerd.service
598
- EOS
599
- end
278
+ You can specify an alternate directory location by passing the `--consistdir` switch
279
+ to the `up` command.
600
280
 
601
- shell "Create docker group", params: {raise_on_non_zero_exit: false} do
602
- <<~EOS
603
- # Create group
604
- sudo groupadd docker
605
- sudo usermod -aG docker $USER
606
- EOS
607
- end
281
+ ## Community Consistfiles
608
282
 
609
- shell "Create default private network", params: {raise_on_non_zero_exit: false} do
610
- <<~EOS
611
- # Create default private network
612
- docker network create private
613
- EOS
614
- end
615
- end
616
- end
617
- end
618
- end
283
+ If you create a Github repo, and all it contains is a `Consistfile` and any associated
284
+ artifacts under a `.consist` directory, other people will be able to use it by
285
+ executing `consist init <gh_repo_path>` in their project root.
619
286
 
620
- # vim: filetype=ruby
621
- ```
287
+ If you create one, please open a PR to include it here:
622
288
 
623
- Given a `Consistfile` you could then say `consist up <ip_address>` and
624
- it would just work.
289
+ | Name | Repo | Description |
290
+ | ------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------- |
291
+ | Kamal Single Server Setup | [consist-sh/kamal-single-server](https://github.com/consist-sh/kamal-single-server) | Setup a single server with good defaults ready to run Kamal |
625
292
 
626
293
  ## Is it good?
627
294
 
data/lib/consist/cli.rb CHANGED
@@ -1,9 +1,12 @@
1
+ require "fileutils"
2
+
1
3
  require "thor"
2
4
  require "sshkit"
3
5
  require "sshkit/dsl"
4
6
 
7
+ require "consist/utils"
8
+ require "consist/resolver"
5
9
  require "consist/recipe"
6
- require "consist/recipes"
7
10
  require "consist/step"
8
11
  require "consist/consistfile"
9
12
  require "consist/commands/includes/stream_logger"
@@ -16,16 +19,22 @@ require "consist/commands/check"
16
19
  module Consist
17
20
  class CLI < Thor
18
21
  extend ThorExt::Start
22
+ include Thor::Actions
23
+ include SSHKit::DSL
19
24
 
20
25
  map %w[-v --version] => "version"
21
26
 
27
+ def self.source_root
28
+ File.dirname(__FILE__)
29
+ end
30
+
22
31
  desc "version", "Display consist version"
23
32
  def version
24
33
  say "consist/#{VERSION} #{RUBY_DESCRIPTION}"
25
34
  end
26
35
 
27
- desc "lightup", "Attempt to connect to a server and execute an idempotent statement."
28
- def lightup(user, server)
36
+ desc "ping", "Attempt to connect to a server and execute an idempotent statement."
37
+ def ping(user, server)
29
38
  puts "---> Attempting to connect to #{server} as #{user}"
30
39
  on("#{user}@#{server}") do
31
40
  as user do
@@ -34,18 +43,28 @@ module Consist
34
43
  end
35
44
  end
36
45
 
37
- desc "scaffold", "Apply a given recipe to (a) server(s)"
38
- def scaffold(_recipe, server_ip)
39
- Consist::Recipes.new(server_ip)
40
- end
41
-
42
46
  option :step, type: :string
43
47
  option :consistfile, type: :string
48
+ option :consistdir, type: :string
44
49
  desc "up", "Run a Consistfile against a server"
45
50
  def up(server_ip)
46
51
  specified_step = options[:step]
47
52
  consistfile = options[:consistfile]
48
- Consist::Consistfile.new(server_ip, consistfile:, specified_step:)
53
+ consist_dir = options[:consistdir]
54
+ Consist::Consistfile.new(server_ip, consist_dir:, consistfile:, specified_step:)
55
+ end
56
+
57
+ desc "init", "Initialize a project with Consist, optionally specifying a GH path to a Consistfile"
58
+ def init(gh_path = nil)
59
+ if gh_path
60
+ full_url = "https://github.com/#{gh_path}"
61
+ Consist::Utils.clone_repo_contents(full_url, Dir.pwd)
62
+ else
63
+ puts "Creating new Consistfile..."
64
+ directory "templates/.consist", File.join(Dir.pwd, ".consist")
65
+ template "templates/Consistfile.tt", File.join(Dir.pwd, "Consistfile")
66
+ puts "...done"
67
+ end
49
68
  end
50
69
  end
51
70
  end
@@ -2,18 +2,21 @@
2
2
 
3
3
  module Consist
4
4
  class << self
5
- attr_accessor :files, :config
5
+ attr_accessor :files, :config, :consist_dir
6
6
  end
7
7
 
8
8
  @files = []
9
9
  @config = {}
10
+ @consist_dir = ""
10
11
 
11
12
  class Consistfile
12
13
  include SSHKit::DSL
13
14
 
14
- def initialize(server_ip, specified_step:, consistfile:)
15
+ def initialize(server_ip, specified_step:, consist_dir:, consistfile:)
15
16
  @server_ip = server_ip
16
17
  @specified_step = specified_step
18
+ Consist.consist_dir = consist_dir || ".consist"
19
+
17
20
  consistfile_path = if consistfile
18
21
  File.expand_path(consistfile, Dir.pwd)
19
22
  else
@@ -30,7 +33,6 @@ module Consist
30
33
 
31
34
  def recipe(id, &definition)
32
35
  recipe = Consist::Recipe.new(id, &definition)
33
-
34
36
  puts "Executing Recipe: #{recipe.name}"
35
37
 
36
38
  if @specified_step.nil?
@@ -47,9 +49,12 @@ module Consist
47
49
  end
48
50
 
49
51
  def file(id, &definition)
50
- return unless definition
51
-
52
- contents = yield
52
+ if definition
53
+ contents = yield
54
+ else
55
+ file_contents = Consist::Resolver.new(pwd: Dir.pwd).resolve_artifact(type: :file, id:)
56
+ contents = file_contents
57
+ end
53
58
 
54
59
  Consist.files << {id:, contents:}
55
60
  end
@@ -2,9 +2,16 @@
2
2
 
3
3
  module Consist
4
4
  class Recipe
5
- def initialize(_id = nil, &definition)
5
+ def initialize(id = nil, &definition)
6
6
  @steps = []
7
- instance_eval(&definition)
7
+ @id = id
8
+
9
+ if definition
10
+ instance_eval(&definition)
11
+ else
12
+ contents = Consist::Resolver.new(pwd: Dir.pwd).resolve_artifact(type: :recipe, id:)
13
+ instance_eval(contents)
14
+ end
8
15
  end
9
16
 
10
17
  def name(name = nil)
@@ -22,21 +29,13 @@ module Consist
22
29
  @user
23
30
  end
24
31
 
25
- def steps(&block)
26
- instance_eval(&block) if block
32
+ def steps(&definition)
33
+ instance_eval(&definition) if definition
27
34
  @steps
28
35
  end
29
36
 
30
- def step(step_name, &block)
31
- if block
32
- @steps << Step.new(id: step_name, &block)
33
- return
34
- end
35
-
36
- target_path = File.join("../../", "steps", step_name.to_s, "step.rb")
37
- step_path = File.expand_path(target_path, __FILE__)
38
- step_content = File.read(step_path)
39
- @steps << Step.new(id: step_name) { instance_eval(step_content) }
37
+ def step(id, &definition)
38
+ @steps << Step.new(id:, &definition)
40
39
  end
41
40
  end
42
41
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Consist
4
+ class Resolver
5
+ def initialize(pwd:)
6
+ @pwd = pwd
7
+ end
8
+
9
+ def resolve_artifact(type:, id:)
10
+ file_name = %i[recipe step].include?(type) ? "#{id}.rb" : id.to_s
11
+ target_path = File.join(Consist.consist_dir, "#{type}s", file_name)
12
+ artifact_path = File.expand_path(target_path, @pwd)
13
+ File.read(artifact_path)
14
+ end
15
+ end
16
+ end
data/lib/consist/step.rb CHANGED
@@ -6,11 +6,17 @@ module Consist
6
6
  class Step
7
7
  include SSHKit::DSL
8
8
 
9
- def initialize(id:, &block)
9
+ def initialize(id:, &definition)
10
10
  @commands = []
11
11
  @id = id
12
12
  @required_user = :root
13
- instance_eval(&block)
13
+
14
+ if definition
15
+ instance_eval(&definition)
16
+ else
17
+ contents = Consist::Resolver.new(pwd: Dir.pwd).resolve_artifact(type: :step, id:)
18
+ instance_eval(contents)
19
+ end
14
20
  end
15
21
 
16
22
  def id(id = nil)
@@ -0,0 +1,19 @@
1
+ consist do
2
+ config :example, "example"
3
+
4
+ # Define a recipe block:
5
+ #
6
+ # recipe :my_recipe do
7
+ # name "My recipe"
8
+ #
9
+ # steps do
10
+ # step do
11
+ # shell do
12
+ # <<~EOS
13
+ # echo 'hello'
14
+ # EOS
15
+ # end
16
+ # end
17
+ # end
18
+ # end
19
+ end
@@ -0,0 +1,28 @@
1
+ require "fileutils"
2
+ require "tmpdir"
3
+
4
+ module Consist
5
+ module Utils
6
+ extend self
7
+
8
+ def clone_repo_contents(source_repo, target_dir)
9
+ temp_dir = Dir.mktmpdir
10
+
11
+ puts "Using #{source_repo} as template to initialize Consistfile..."
12
+ system("git clone --depth=1 #{source_repo} #{temp_dir} >/dev/null 2>&1")
13
+
14
+ Dir.foreach(temp_dir) do |item|
15
+ next if [".", "..", ".git"].include?(item)
16
+ next unless ["Consistfile", ".consist"].include?(item)
17
+
18
+ source_path = File.join(temp_dir, item)
19
+ target_path = File.join(target_dir, item)
20
+ FileUtils.cp_r(source_path, target_path)
21
+ end
22
+
23
+ FileUtils.remove_entry_secure(temp_dir)
24
+
25
+ puts "...done"
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module Consist
2
- VERSION = "0.1.2".freeze
2
+ VERSION = '0.1.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: consist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - John McDowall
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-30 00:00:00.000000000 Z
11
+ date: 2023-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-ssh
@@ -73,14 +73,12 @@ files:
73
73
  - lib/consist/commands/upload.rb
74
74
  - lib/consist/consistfile.rb
75
75
  - lib/consist/recipe.rb
76
- - lib/consist/recipes.rb
76
+ - lib/consist/resolver.rb
77
77
  - lib/consist/step.rb
78
+ - lib/consist/templates/Consistfile.tt
78
79
  - lib/consist/thor_ext.rb
80
+ - lib/consist/utils.rb
79
81
  - lib/consist/version.rb
80
- - lib/recipes/kamal_single_server.rb
81
- - lib/steps/install_apt_packages/step.rb
82
- - lib/steps/update_apt_packages/apt_auto_upgrades
83
- - lib/steps/update_apt_packages/step.rb
84
82
  homepage: https://github.com/consist-sh/consist
85
83
  licenses:
86
84
  - LGPL-3.0
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Consist
4
- class Recipes
5
- include SSHKit::DSL
6
-
7
- def initialize(server_ip)
8
- recipe_directory = File.expand_path("../recipes", __dir__)
9
- recipes = Dir[File.join(recipe_directory, "*.rb")]
10
-
11
- recipes.each do |recipe_file|
12
- recipe_content = File.read(recipe_file)
13
- recipe = Recipe.new { instance_eval(recipe_content) }
14
-
15
- puts "Executing Recipe: #{recipe.name}"
16
- recipe.steps.each do |step|
17
- puts "Executing Step: #{step.name}"
18
-
19
- on("#{step.required_user}@#{server_ip}") do
20
- step.perform(self)
21
- end
22
- end
23
-
24
- puts "Execution of #{recipe.name} has completed."
25
- end
26
- end
27
- end
28
- end
@@ -1,8 +0,0 @@
1
- name "Kamal Single Server"
2
- description "Sets up a single server to run Kamal"
3
- user :root
4
-
5
- steps do
6
- step :update_apt_packages
7
- step :install_apt_packages
8
- end
@@ -1,19 +0,0 @@
1
- name "Install APT packages"
2
- required_user :root
3
-
4
- shell "Installing essential packages" do
5
- <<~EOS
6
- apt-get -y remove systemd-timesyncd
7
- timedatectl set-ntp no
8
- apt-get -y install build-essential curl fail2ban git ntp vim
9
- apt-get autoremove
10
- apt-get autoclean
11
- EOS
12
- end
13
-
14
- shell "Start NTP and Fail2Ban" do
15
- <<~EOS
16
- service ntp restart
17
- service fail2ban restart
18
- EOS
19
- end
@@ -1,3 +0,0 @@
1
- APT::Periodic::AutocleanInterval "7";
2
- APT::Periodic::Update-Package-Lists "1";
3
- APT::Periodic::Unattended-Upgrade "1";
@@ -1,11 +0,0 @@
1
- name "Update the APT packages"
2
- required_user :root
3
-
4
- upload_file message: "Uploading APT config...", local_file: "apt_auto_upgrades",
5
- remote_path: "/etc/apt/apt.conf.d/20auto-upgrades"
6
-
7
- shell do
8
- <<~EOS
9
- apt-get update && apt-get upgrade -y
10
- EOS
11
- end