consist 0.1.2 → 0.1.3

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